Duplicator – WordPress Migration Plugin - Version 1.3.0

Version Description

Download this release

Release Info

Developer cory@lamle.org
Plugin Icon 128x128 Duplicator – WordPress Migration Plugin
Version 1.3.0
Comparing to
See all releases

Code changes from version 1.2.52 to 1.3.0

Files changed (65) hide show
  1. assets/css/global_admin_style.css +34 -0
  2. assets/css/style.css +3 -5
  3. assets/img/hdivider.png +0 -0
  4. assets/img/logo-dpro-300x50-nosnap.png +0 -0
  5. assets/js/javascript.php +59 -3
  6. assets/js/jquery.qtip/jquery.qtip.min.js.map +1 -0
  7. assets/js/parsley.min.js.map +1 -0
  8. classes/class.archive.config.php +42 -0
  9. classes/class.db.php +30 -35
  10. classes/class.io.php +93 -0
  11. classes/class.logging.php +255 -48
  12. classes/class.password.php +4 -0
  13. classes/class.server.php +117 -81
  14. classes/class.settings.php +28 -31
  15. classes/package/class.pack.archive.filters.php +86 -84
  16. classes/package/class.pack.archive.php +661 -605
  17. classes/package/class.pack.archive.zip.php +56 -15
  18. classes/package/class.pack.database.php +226 -57
  19. classes/package/class.pack.installer.php +418 -167
  20. classes/package/class.pack.php +885 -115
  21. classes/package/duparchive/class.pack.archive.duparchive.php +368 -0
  22. classes/package/duparchive/class.pack.archive.duparchive.state.create.php +82 -0
  23. classes/package/duparchive/class.pack.archive.duparchive.state.expand.php +135 -0
  24. classes/package/duparchive/index.php +2 -0
  25. classes/ui/class.ui.dialog.php +197 -201
  26. classes/ui/class.ui.notice.php +10 -14
  27. classes/ui/class.ui.screen.base.php +77 -76
  28. classes/ui/class.ui.viewstate.php +70 -73
  29. classes/utilities/class.u.json.php +192 -152
  30. classes/utilities/class.u.multisite.php +53 -0
  31. classes/utilities/class.u.php +87 -74
  32. classes/utilities/class.u.scancheck.php +5 -8
  33. classes/utilities/class.u.shell.php +39 -0
  34. classes/utilities/class.u.string.php +98 -0
  35. classes/utilities/class.u.validator.php +228 -0
  36. classes/utilities/class.u.zip.php +155 -0
  37. ctrls/ctrl.base.php +10 -0
  38. ctrls/ctrl.package.php +423 -155
  39. ctrls/ctrl.tools.php +77 -6
  40. ctrls/ctrl.ui.php +4 -9
  41. debug/main.php +0 -191
  42. debug/tst.packages.php +0 -31
  43. debug/tst.tools.php +0 -38
  44. debug/tst.ui.php +0 -45
  45. define.php +33 -10
  46. duplicator.php +37 -25
  47. installer/build/assets/inc.css.php +0 -246
  48. installer/build/assets/inc.js.php +0 -78
  49. installer/build/assets/inc.libs.css.php +0 -48
  50. installer/build/assets/inc.libs.js.php +0 -191
  51. installer/build/classes/class.csrf.php +0 -75
  52. installer/build/classes/class.db.php +0 -215
  53. installer/build/classes/class.engine.php +0 -450
  54. installer/build/classes/class.logging.php +0 -67
  55. installer/build/classes/class.server.php +0 -183
  56. installer/build/classes/config/class.conf.srv.php +0 -113
  57. installer/build/classes/config/class.conf.wp.php +0 -246
  58. installer/build/ctrls/ctrl.step1.php +0 -148
  59. installer/build/ctrls/ctrl.step2.php +0 -499
  60. installer/build/ctrls/ctrl.step3.php +0 -390
  61. installer/build/main.installer.php +0 -418
  62. installer/build/view.step1.php +0 -798
  63. installer/build/view.step2.php +0 -441
  64. installer/build/view.step3.php +0 -340
  65. installer/dup-installer/assets/font-awesome/css/font-awesome.min.css +4 -0
assets/css/global_admin_style.css ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ================================================
2
+ * DUPLICATOR STYLE
3
+ * Included in all admin pages
4
+ * ================================================ */
5
+
6
+ .dup-updated {
7
+ margin-left: 0;
8
+ background: #fff;
9
+ border-left: 4px solid #fff;
10
+ box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
11
+ margin: 5px 15px 2px;
12
+ padding: 1px 12px;
13
+ }
14
+
15
+ .dup-updated p {
16
+ margin: 0.5em 0;
17
+ padding: 2px;
18
+ }
19
+
20
+ .dup-updated a {
21
+ padding-bottom: 2px;
22
+ }
23
+
24
+ .dup-updated {
25
+ border-left-color: #46b450;
26
+ }
27
+
28
+ .wrap .dup-updated {
29
+ margin: 5px 0 15px;
30
+ margin: 20px 0 10px 0;
31
+ padding: 5px 10px;
32
+ font-size: 14px;
33
+ line-height: 175%;
34
+ }
assets/css/style.css CHANGED
@@ -42,12 +42,12 @@ div#dup-progress-bar-area {width:500px; margin:40px auto 0px auto; padding:25px
42
  div#dup-progress-bar-area h2 {margin-bottom:15px}
43
 
44
  /*HEADER MESSAGES*/
45
- div.dup-hdr-success {color:green; font-size:22px; font-weight:bold}
46
  div.dup-hdr-error {color:#A62426; font-size:22px; font-weight:bold}
47
 
48
  /*DIALOGS: THICKBOX */
49
  #TB_title { padding-bottom: 3px!important; margin-bottom:5px!important; font-size:16px!important;}
50
- div.dup-dlg-alert-txt {padding:10px 0; font-size:16px}
51
  div.dup-dlg-alert-btns {position:absolute; bottom:20px; right:20px;}
52
  div.dup-dlg-confirm-txt {padding:10px 0; font-size:16px}
53
  div.dup-dlg-confirm-btns {position:absolute; bottom:20px; right:20px;}
@@ -68,12 +68,10 @@ input.parsley-error, textarea.parsley-error {
68
  border:1px solid #EED3D7 !important;
69
  }
70
  div.qtip-content {line-height:16px}
71
- ul.parsley-errors-list {margin:0 0 -7px 0; font-style: italic}
72
-
73
  div.notice-safemode {color: maroon;}
74
  div.cleanup-notice b.title {color: green;font-size: 20px;}
75
 
76
  /*SCREEN TABS*/
77
  div.dup-screen-hlp-info {line-height:26px; padding:10px 0 10px 0}
78
  #screen-meta-links .button { font-size:13px !important; height:auto !important;font-weight: normal; padding: 3px 6px 3px 16px !important;min-width:72px !important}
79
-
42
  div#dup-progress-bar-area h2 {margin-bottom:15px}
43
 
44
  /*HEADER MESSAGES*/
45
+ div.dup-hdr-success {color:#23282d; font-size:22px; font-weight:bold}
46
  div.dup-hdr-error {color:#A62426; font-size:22px; font-weight:bold}
47
 
48
  /*DIALOGS: THICKBOX */
49
  #TB_title { padding-bottom: 3px!important; margin-bottom:5px!important; font-size:16px!important;}
50
+ div.dup-dlg-alert-txt {padding:10px 0; font-size:16px; line-height:22px}
51
  div.dup-dlg-alert-btns {position:absolute; bottom:20px; right:20px;}
52
  div.dup-dlg-confirm-txt {padding:10px 0; font-size:16px}
53
  div.dup-dlg-confirm-btns {position:absolute; bottom:20px; right:20px;}
68
  border:1px solid #EED3D7 !important;
69
  }
70
  div.qtip-content {line-height:16px}
71
+ ul.parsley-error-list {margin:1px 0px -7px 0px}
 
72
  div.notice-safemode {color: maroon;}
73
  div.cleanup-notice b.title {color: green;font-size: 20px;}
74
 
75
  /*SCREEN TABS*/
76
  div.dup-screen-hlp-info {line-height:26px; padding:10px 0 10px 0}
77
  #screen-meta-links .button { font-size:13px !important; height:auto !important;font-weight: normal; padding: 3px 6px 3px 16px !important;min-width:72px !important}
 
assets/img/hdivider.png DELETED
Binary file
assets/img/logo-dpro-300x50-nosnap.png DELETED
Binary file
assets/js/javascript.php CHANGED
@@ -14,6 +14,49 @@ Duplicator.Debug = new Object();
14
  Duplicator.DEBUG_AJAX_RESPONSE = false;
15
  Duplicator.AJAX_TIMER = null;
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  /* ============================================================================
19
  * BASE NAMESPACE: All methods at the top of the Duplicator Namespace
@@ -66,9 +109,22 @@ Duplicator.UI.SaveViewState = function (key, value)
66
  jQuery.ajax({
67
  type: "POST",
68
  url: ajaxurl,
69
- dataType: "json",
70
- data: {action : 'DUP_CTRL_UI_SaveViewState', key: key, value: value, nonce: '<?php echo wp_create_nonce('DUP_CTRL_UI_SaveViewState'); ?>'},
71
- success: function(data) {},
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  error: function(data) {}
73
  });
74
  }
14
  Duplicator.DEBUG_AJAX_RESPONSE = false;
15
  Duplicator.AJAX_TIMER = null;
16
 
17
+ Duplicator.parseJSON = function(mixData) {
18
+ try {
19
+ var parsed = JSON.parse(mixData);
20
+ return parsed;
21
+ } catch (e) {
22
+ console.log("JSON parse failed - 1");
23
+ console.log(mixData);
24
+ }
25
+
26
+ if (mixData.indexOf('[') > -1 && mixData.indexOf('{') > -1) {
27
+ if (mixData.indexOf('{') < mixData.indexOf('[')) {
28
+ var startBracket = '{';
29
+ var endBracket = '}';
30
+ } else {
31
+ var startBracket = '[';
32
+ var endBracket = ']';
33
+ }
34
+ } else if (mixData.indexOf('[') > -1 && mixData.indexOf('{') === -1) {
35
+ var startBracket = '[';
36
+ var endBracket = ']';
37
+ } else {
38
+ var startBracket = '{';
39
+ var endBracket = '}';
40
+ }
41
+
42
+ var jsonStartPos = mixData.indexOf(startBracket);
43
+ var jsonLastPos = mixData.lastIndexOf(endBracket);
44
+ if (jsonStartPos > -1 && jsonLastPos > -1) {
45
+ var expectedJsonStr = mixData.slice(jsonStartPos, jsonLastPos + 1);
46
+ try {
47
+ var parsed = JSON.parse(expectedJsonStr);
48
+ return parsed;
49
+ } catch (e) {
50
+ console.log("JSON parse failed - 2");
51
+ console.log(mixData);
52
+ throw e;
53
+ return false;
54
+ }
55
+ }
56
+ throw "could not parse the JSON";
57
+ return false;
58
+ }
59
+
60
 
61
  /* ============================================================================
62
  * BASE NAMESPACE: All methods at the top of the Duplicator Namespace
109
  jQuery.ajax({
110
  type: "POST",
111
  url: ajaxurl,
112
+ dataType: "text",
113
+ data: {
114
+ action : 'DUP_CTRL_UI_SaveViewState',
115
+ key: key,
116
+ value: value,
117
+ nonce: '<?php echo wp_create_nonce('DUP_CTRL_UI_SaveViewState'); ?>'
118
+ },
119
+ success: function(respData) {
120
+ try {
121
+ var data = Duplicator.parseJSON(respData);
122
+ } catch(err) {
123
+ console.error(err);
124
+ console.error('JSON parse failed for response data: ' + respData);
125
+ return false;
126
+ }
127
+ },
128
  error: function(data) {}
129
  });
130
  }
assets/js/jquery.qtip/jquery.qtip.min.js.map ADDED
@@ -0,0 +1 @@
 
1
+ {"version":3,"file":"jquery.qtip.min.js","sources":["jquery.qtip.js"],"names":["window","document","undefined","factory","define","amd","jQuery","fn","qtip","$","QTip","target","options","id","attr","this","tooltip","NULL","elements","_id","NAMESPACE","timers","img","plugins","cache","event","disabled","FALSE","onTooltip","lastClass","rendered","destroyed","waiting","hiddenDuringWait","positioning","triggering","invalidOpt","a","type","invalidContent","c","isFunction","length","jquery","then","sanitizeOptions","opts","content","text","ajax","once","metadata","done","api","loading","deferred","extend","context","success","error","set","xhr","status","isPlainObject","title","button","position","my","at","show","TRUE","ready","hide","style","classes","each","PLUGINS","sanitize","convertNotation","notation","obj","i","option","levels","split","pop","setCallback","args","category","rule","match","checks","RegExp","exec","push","apply","createWidgetClass","cls","WIDGET","concat","join","delay","callback","duration","setTimeout","proxy","call","showMethod","hasClass","CLASS_DISABLED","clearTimeout","toggle","hideMethod","relatedTarget","ontoTooltip","closest","SELECTOR","ontoTarget","fixed","test","preventDefault","stopImmediatePropagation","e","inactiveMethod","inactive","repositionMethod","offsetWidth","reposition","delegate","selector","events","method","body","QTIP","ATTR_ID","arguments","init","elem","posOptions","config","docBody","newTarget","metadata5","name","html5","data","parseJSON","defaults","container","solo","viewport","eq","CORNER","overwrite","ATTR_HAS","suppress","removeAttr","oldtitle","camel","s","charAt","toUpperCase","slice","vendorCss","prop","cur","val","ucProp","props","cssPrefixes","cssProps","css","intCss","Math","ceil","parseFloat","Tip","_ns","offset","size","width","height","Modal","Ie6","PROTOTYPE","CHECKS","trackingBound","X","Y","WIDTH","HEIGHT","TOP","LEFT","BOTTOM","RIGHT","CENTER","FLIPINVERT","SHIFT","INACTIVE_EVENTS","CLASS_FIXED","CLASS_DEFAULT","CLASS_FOCUS","CLASS_HOVER","replaceSuffix","BROWSER","ie","v","createElement","innerHTML","getElementsByTagName","NaN","iOS","navigator","userAgent","replace","prototype","_when","deferreds","when","render","self","posClass","_createPosClass","class","tracking","adjust","mouse","role","aria-live","aria-atomic","aria-describedby","aria-hidden","toggleClass","appendTo","append","_createTitle","_updateTitle","_createButton","_updateContent","_setWidget","instance","initialize","_unassignEvents","_assignEvents","_trigger","destroy","immediate","process","timer","stop","find","remove","end","removeData","one","builtin","^id$","o","prev","nextid","new_id","^prerender","^content.text$","^content.attr$","^content.title$","_removeTitle","^content.button$","_updateButton","^content.title.(text|button)$","^position.(my|at)$","^position.container$","^show.ready$","^style.classes$","p","removeClass","addClass","^style.(width|height)","^style.widget|content.title","^style.def","^events.(render|show|move|hide|focus|blur)$","^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)","get","toLowerCase","result","precedance","string","rmove","rrender","value","previous","nodeType","_update","element","empty","display","visibility","html","_waitForContent","images","imagesLoaded","Deferred","resolve","promise","titlebar","widget","insertBefore","substr","abbrev","effect","pluginCalculations","adjusted","newClass","tooltipWidth","outerWidth","tooltipHeight","outerHeight","targetWidth","targetHeight","left","top","visible","isScroll","win","doc","ownerDocument","isArray","x","y","distance","origin","pageX","innerWidth","documentElement","clientWidth","pageY","scrollX","scrollLeft","scrollY","scrollTop","innerHeight","imagemap","is","svg","ownerSVGElement","adjustable","isNaN","queue","next","opacity","removeAttribute","pos","scroll","scrolled","parentOffset","overflow","quirks","compatMode","parent","getBoundingClientRect","offsetParent","C","Corner","corner","forceY","f","invert","z","center","clone","state","add","has","fix","identicalState","allow","after","contentOptions","animate","sameTarget","search","focus","bind","_storeMouse","not","Event","unbind","blur","autofocus","trigger","n","fadeTo","qtips","curIndex","parseInt","zIndex","newIndex","zindex","filter","disable","enable","isString","close","aria-label","prepend","click","on","def","_bind","targets","suffix","ns","_unbind","originalEvent","isDefaultPrevented","_bindEvents","showEvents","hideEvents","showTargets","hideTargets","similarTargets","toggleEvents","showIndex","inArray","splice","_assignInitialEvents","hoverIntent","prerender","showTarget","hideTarget","trim","onTarget","containerTarget","viewportTarget","documentTarget","windowTarget","leave","nodeName","indexOf","enabled","isAncestor","parents","inactiveEvents","limit","abs","resize","special","grep","toArray","currentTarget","newValue","command","returned","makeArray","timeStamp","keepData","elems","func","old","ui","cleanData","triggerHandler","version","move","hidden","TIP","MARGIN","BORDER","COLOR","BG_COLOR","TRANSPARENT","IMPORTANT","HASCANVAS","getContext","INVALID","PIXEL_RATIO","devicePixelRatio","BACKING_STORE_RATIO","backingStorePixelRatio","webkitBackingStorePixelRatio","mozBackingStorePixelRatio","msBackingStorePixelRatio","oBackingStorePixelRatio","SCALE","createVML","tag","tip","prependTo","lineJoin","miterLimit","save","stopPropagation","create","_swapDimensions","_resetDimensions","_useTitle","_parseCorner","_parseWidth","side","use","_parseRadius","_invalidColour","compare","_parseColours","borderSide","colorElem","color","_calculateSize","bigHyp","ratio","isCenter","base","pow","round","smallHyp","sqrt","hyp","border","reverse","_calculateTip","scale","width2","height2","tips","br","bl","tr","tl","tc","bc","rc","lc","lt","rt","lb","rb","_drawCoords","coords","beginPath","moveTo","lineTo","closePath","update","bigCoords","translate","newSize","inner","children","curSize","mimic","lineHeight","restore","clearRect","fillStyle","fill","coordsize","antialias","Number","$this","path","fillcolor","filled","stroked","opera","calculate","corners","userOffset","b","max","margin","bottom","right","shiftflip","direction","popposite","opposite","newCorner","shiftonly","xy","shift","horizontal","vertical","cornerTop","cornerLeft","user","^position.my|style.tip.(corner|mimic|border)$","^style.tip.(height|width)$","^content.title|style.(classes|widget)$","MODAL","OVERLAY","MODALCLASS","MODALSELECTOR","focusable","expr","map","mapName","isTabIndexNotNaN","parentNode","href","focusInputs","blurElems","focusableElems","first","stealFocus","targetOnTop","current","onLast","prevState","mousedown","modal","escape","keyCode","stealfocus","visibleModals","detach","overlay","modal_zindex","oEvent","last","^show.modal.(on|blur)$","elemWidth","elemHeight","otherSide","side1","side2","lengthName","targetLength","elemLength","initialPos","mySide","atSide","isShift","myLength","atLength","sideOffset","viewportScroll","viewportOffset","containerStatic","containerOffset","overflow1","overflow2","viewportWidth","viewportHeight","min","newMy","methodX","methodY","polys","polygon","baseCoords","newWidth","newHeight","compareX","compareY","realX","realY","floor","rect","ax","ay","bx","by","_angles","ellipse","cx","cy","rx","ry","rxc","cos","PI","rys","sin","circle","r","frameOffset","mtx","transformed","len","points","root","strokeWidth2","getBBox","baseVal","x1","y1","x2","y2","numberOfItems","getItem","createSVGPoint","getScreenCTM","matrixTransform","defaultView","parentWindow","frameElement","area","imageOffset","shape","image","coordsString","coordsArray","IE6","BGIFRAME","_scroll","bgiframe","adjustBGIFrame","redrawContainer","redraw","tipAdjust","dimensions","plugin","drawing","perc","ie6","^content|style$"],"mappings":"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"}
assets/js/parsley.min.js.map ADDED
@@ -0,0 +1 @@
 
1
+ {"version":3,"sources":["parsley.min.js","/source/parsley.js","/source/src/parsley/pubsub.js","/source/src/parsley/utils.js","/source/src/parsley/defaults.js","/source/src/parsley/abstract.js","/source/src/parsley/validator.js","/source/src/parsley/validator_registry.js","/source/src/parsley/ui.js","/source/src/parsley/form.js","/source/src/parsley/factory/constraint.js","/source/src/parsley/field.js","/source/src/parsley/multiple.js","/source/src/parsley/factory.js","/source/src/parsley/main.js","/source/src/parsley/remote.js","/source/src/i18n/en.js","/source/src/parsley.js"],"names":["_toConsumableArray","arr","Array","isArray","i","arr2","length","from","_slice","prototype","slice","global","factory","exports","module","require","define","amd","parsley","jQuery","this","$","adapt","fn","context","parsleyAdaptedCallback","args","call","arguments","unshift","apply","o","eventName","name","lastIndexOf","eventPrefix","substr","globalID","pastWarnings","ParsleyUtils__ParsleyUtils","attr","$element","namespace","obj","attribute","attributes","regex","RegExp","hasOwnProperty","specified","test","camelize","deserializeValue","value","checkAttr","_checkAttr","is","setAttr","setAttribute","dasherize","String","generateID","num","isNaN","Number","parseJSON","e","str","replace","match","chr","toUpperCase","toLowerCase","warn","_window$console","window","console","warnOnce","msg","_resetWarnings","trimString","string","namespaceEvents","events","split","map","evt","join","objectCreate","Object","create","Error","TypeError","result","ParsleyUtils__default","ParsleyDefaults","inputs","excluded","priorityEnabled","multiple","group","uiEnabled","validationThreshold","focus","trigger","triggerAfterFailure","errorClass","successClass","classHandler","ParsleyField","errorsContainer","errorsWrapper","errorTemplate","ParsleyAbstract","asyncSupport","actualizeOptions","options","domOptions","parent","_resetOptions","initOptions","_listeners","on","queue","push","subscribe","listenTo","off","splice","unsubscribe","unsubscribeTo","target","extraArg","reset","__class__","_resetUI","_trigger","fields","destroy","_destroyUI","removeData","asyncIsValid","force","whenValid","_findRelated","find","requirementConverters","_string","integer","parseInt","number","parseFloat","reference","boolean","object","regexp","_regexp","flags","convertArrayRequirement","m","values","convertRequirement","requirementType","converter","convertExtraOptionRequirement","requirementSpec","extraOptionReader","main","extra","key","ParsleyValidator","spec","extend","validate","requirementFirstArg","validateMultiple","validateNumber","validateString","parseRequirements","requirements","type","isPlainObject","priority","ParsleyValidatorRegistry","validators","catalog","locale","init","typeRegexes","email","digits","alphanum","url","range","decimalPlaces","Math","max","addValidator","Parsley","setLocale","addCatalog","messages","set","addMessage","message","addMessages","nameMessageObject","arg1","arg2","_setValidator","updateValidator","removeValidator","validator","getErrorMessage","constraint","typeMessages","formatMessage","defaultMessage","en","parameters","notblank","required","_ref","undefined","_ref$step","step","_ref$base","base","nb","decimals","toInt","f","round","pow","pattern","minlength","requirement","maxlength","min","mincheck","maxcheck","check","equalto","refOrValue","$reference","val","ParsleyUI","diffResults","newResult","oldResult","deep","added","kept","found","j","assert","removed","Form","_actualizeTriggers","_this","onSubmitValidate","onSubmitButton","_focusedField","validationResult","field","noFocus","Field","_reflowUI","_buildUI","_ui","diff","lastValidationResult","_manageStatusClass","_manageErrorsMessages","_failedOnce","getErrorsMessages","errorMessage","_getErrorMessage","addError","_ref2","_ref2$updateClass","updateClass","_addError","_errorClass","updateError","_ref3","_ref3$updateClass","_updateError","removeError","_ref4","_ref4$updateClass","_removeError","hasConstraints","needsValidation","_successClass","_resetClass","errorsMessagesDisabled","_insertErrorWrapper","$errorsWrapper","append","addClass","html","removeClass","remove","_ref5","_ref6","customConstraintErrorMessage","__id__","$errorClassHandler","_manageClassHandler","errorsWrapperId","validationInformationVisible","$handler","$errorsContainer","$from","after","_this2","$toBind","event","_eventValidate","getValue","children","ParsleyForm","element","ParsleyForm__statusMapping","pending","resolved","rejected","_this3","$submitSource","_$submitSource","first","prop","promise","whenValidate","state","stopImmediatePropagation","preventDefault","done","_submit","$synthetic","appendTo","Event","_arguments","_this4","_ref7","submitEvent","_refreshFields","promises","_withoutReactualizingFormOptions","promiseBasedOnValidationResult","r","Deferred","reject","resolve","when","fail","always","pipe","isValid","_arguments2","_this5","_ref8","_bindFields","_this6","oldFields","fieldsMappedById","not","each","_","fieldInstance","Factory","oldActualizeOptions","ConstraintFactory","parsleyField","isDomConstraint","validatorSpec","_validatorRegistry","_parseRequirements","capitalize","cap","instance","requirementList","_this7","parsleyFormInstance","constraints","constraintsByName","_bindConstraints","parsley_field__statusMapping","_this8","_ref9","refreshConstraints","_isInGroup","_refreshed","_isRequired","validateIfEmpty","inArray","_arguments3","_this9","_ref10","_ref10$force","groupedConstraints","_getGroupedConstraints","_validateConstraint","_this10","_handleWhitespace","addConstraint","removeConstraint","updateConstraint","_bindHtml5Constraints","hasClass","trimValue","whitespace","index","p","sort","a","b","parsley_field","ParsleyMultiple","addElement","$elements","fieldConstraints","has","data","filter","_init","ParsleyFactory","savedparsleyFormInstance","__version__","bind","isMultiple","handleMultiple","parsleyMultipleInstance","_this11","input","$previouslyRelated","get","doNotStore","parsleyInstance","ParsleyExtend","vernums","jquery","forEach","document","version","psly","instances","ParsleyConfig","ParsleyUtils","registry","i18n","method","proxy","_window$Parsley","UI","doNotUpdateClass","navigator","userAgent","autoBind","deprecated","listen","callback","unsubscribeAll","emit","_instance","instanceGiven","asyncValidators","default","xhr","status","reverse","addAsyncValidator","ajaxOptions","csr","indexOf","encodeURIComponent","remoteOptions","param","_remoteCache","ajax","handleXhr","then"],"mappings":"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","file":"parsley.min.js","sourcesContent":[null,"(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) :\n typeof define === 'function' && define.amd ? define(['jquery'], factory) :\n global.parsley = factory(global.$)\n}(this, function ($) { 'use strict';\n\n var globalID = 1;\n var pastWarnings = {};\n\n var ParsleyUtils__ParsleyUtils = {\n // Parsley DOM-API\n // returns object from dom attributes and values\n attr: function ($element, namespace, obj) {\n var i;\n var attribute;\n var attributes;\n var regex = new RegExp('^' + namespace, 'i');\n\n if ('undefined' === typeof obj)\n obj = {};\n else {\n // Clear all own properties. This won't affect prototype's values\n for (i in obj) {\n if (obj.hasOwnProperty(i))\n delete obj[i];\n }\n }\n\n if ('undefined' === typeof $element || 'undefined' === typeof $element[0])\n return obj;\n\n attributes = $element[0].attributes;\n for (i = attributes.length; i--; ) {\n attribute = attributes[i];\n\n if (attribute && attribute.specified && regex.test(attribute.name)) {\n obj[this.camelize(attribute.name.slice(namespace.length))] = this.deserializeValue(attribute.value);\n }\n }\n\n return obj;\n },\n\n checkAttr: function ($element, namespace, checkAttr) {\n return $element.is('[' + namespace + checkAttr + ']');\n },\n\n setAttr: function ($element, namespace, attr, value) {\n $element[0].setAttribute(this.dasherize(namespace + attr), String(value));\n },\n\n generateID: function () {\n return '' + globalID++;\n },\n\n /** Third party functions **/\n // Zepto deserialize function\n deserializeValue: function (value) {\n var num;\n\n try {\n return value ?\n value == \"true\" ||\n (value == \"false\" ? false :\n value == \"null\" ? null :\n !isNaN(num = Number(value)) ? num :\n /^[\\[\\{]/.test(value) ? $.parseJSON(value) :\n value)\n : value;\n } catch (e) { return value; }\n },\n\n // Zepto camelize function\n camelize: function (str) {\n return str.replace(/-+(.)?/g, function (match, chr) {\n return chr ? chr.toUpperCase() : '';\n });\n },\n\n // Zepto dasherize function\n dasherize: function (str) {\n return str.replace(/::/g, '/')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-z\\d])([A-Z])/g, '$1_$2')\n .replace(/_/g, '-')\n .toLowerCase();\n },\n\n warn: function () {\n if (window.console && 'function' === typeof window.console.warn)\n window.console.warn(...arguments);\n },\n\n warnOnce: function(msg) {\n if (!pastWarnings[msg]) {\n pastWarnings[msg] = true;\n this.warn(...arguments);\n }\n },\n\n _resetWarnings: function () {\n pastWarnings = {};\n },\n\n trimString: function(string) {\n return string.replace(/^\\s+|\\s+$/g, '');\n },\n\n namespaceEvents: function(events, namespace) {\n events = this.trimString(events || '').split(/\\s+/);\n if (!events[0])\n return '';\n return $.map(events, evt => { return `${evt}.${namespace}`; }).join(' ');\n },\n\n // Object.create polyfill, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill\n objectCreate: Object.create || (function () {\n var Object = function () {};\n return function (prototype) {\n if (arguments.length > 1) {\n throw Error('Second argument not supported');\n }\n if (typeof prototype != 'object') {\n throw TypeError('Argument must be an object');\n }\n Object.prototype = prototype;\n var result = new Object();\n Object.prototype = null;\n return result;\n };\n })()\n };\n\n var ParsleyUtils__default = ParsleyUtils__ParsleyUtils;\n\n // All these options could be overriden and specified directly in DOM using\n // `data-parsley-` default DOM-API\n // eg: `inputs` can be set in DOM using `data-parsley-inputs=\"input, textarea\"`\n // eg: `data-parsley-stop-on-first-failing-constraint=\"false\"`\n\n var ParsleyDefaults = {\n // ### General\n\n // Default data-namespace for DOM API\n namespace: 'data-parsley-',\n\n // Supported inputs by default\n inputs: 'input, textarea, select',\n\n // Excluded inputs by default\n excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',\n\n // Stop validating field on highest priority failing constraint\n priorityEnabled: true,\n\n // ### Field only\n\n // identifier used to group together inputs (e.g. radio buttons...)\n multiple: null,\n\n // identifier (or array of identifiers) used to validate only a select group of inputs\n group: null,\n\n // ### UI\n // Enable\\Disable error messages\n uiEnabled: true,\n\n // Key events threshold before validation\n validationThreshold: 3,\n\n // Focused field on form validation error. 'first'|'last'|'none'\n focus: 'first',\n\n // event(s) that will trigger validation before first failure. eg: `input`...\n trigger: false,\n\n // event(s) that will trigger validation after first failure.\n triggerAfterFailure: 'input',\n\n // Class that would be added on every failing validation Parsley field\n errorClass: 'parsley-error',\n\n // Same for success validation\n successClass: 'parsley-success',\n\n // Return the `$element` that will receive these above success or error classes\n // Could also be (and given directly from DOM) a valid selector like `'#div'`\n classHandler: function (ParsleyField) {},\n\n // Return the `$element` where errors will be appended\n // Could also be (and given directly from DOM) a valid selector like `'#div'`\n errorsContainer: function (ParsleyField) {},\n\n // ul elem that would receive errors' list\n errorsWrapper: '<ul class=\"parsley-errors-list\"></ul>',\n\n // li elem that would receive error message\n errorTemplate: '<li></li>'\n };\n\n var ParsleyAbstract = function () {};\n\n ParsleyAbstract.prototype = {\n asyncSupport: true, // Deprecated\n\n actualizeOptions: function () {\n ParsleyUtils__default.attr(this.$element, this.options.namespace, this.domOptions);\n if (this.parent && this.parent.actualizeOptions)\n this.parent.actualizeOptions();\n return this;\n },\n\n _resetOptions: function (initOptions) {\n this.domOptions = ParsleyUtils__default.objectCreate(this.parent.options);\n this.options = ParsleyUtils__default.objectCreate(this.domOptions);\n // Shallow copy of ownProperties of initOptions:\n for (var i in initOptions) {\n if (initOptions.hasOwnProperty(i))\n this.options[i] = initOptions[i];\n }\n this.actualizeOptions();\n },\n\n _listeners: null,\n\n // Register a callback for the given event name\n // Callback is called with context as the first argument and the `this`\n // The context is the current parsley instance, or window.Parsley if global\n // A return value of `false` will interrupt the calls\n on: function (name, fn) {\n this._listeners = this._listeners || {};\n var queue = this._listeners[name] = this._listeners[name] || [];\n queue.push(fn);\n\n return this;\n },\n\n // Deprecated. Use `on` instead\n subscribe: function(name, fn) {\n $.listenTo(this, name.toLowerCase(), fn);\n },\n\n // Unregister a callback (or all if none is given) for the given event name\n off: function (name, fn) {\n var queue = this._listeners && this._listeners[name];\n if (queue) {\n if (!fn) {\n delete this._listeners[name];\n } else {\n for (var i = queue.length; i--; )\n if (queue[i] === fn)\n queue.splice(i, 1);\n }\n }\n return this;\n },\n\n // Deprecated. Use `off`\n unsubscribe: function(name, fn) {\n $.unsubscribeTo(this, name.toLowerCase());\n },\n\n // Trigger an event of the given name\n // A return value of `false` interrupts the callback chain\n // Returns false if execution was interrupted\n trigger: function (name, target, extraArg) {\n target = target || this;\n var queue = this._listeners && this._listeners[name];\n var result;\n var parentResult;\n if (queue) {\n for (var i = queue.length; i--; ) {\n result = queue[i].call(target, target, extraArg);\n if (result === false) return result;\n }\n }\n if (this.parent) {\n return this.parent.trigger(name, target, extraArg);\n }\n return true;\n },\n\n // Reset UI\n reset: function () {\n // Field case: just emit a reset event for UI\n if ('ParsleyForm' !== this.__class__) {\n this._resetUI();\n return this._trigger('reset');\n }\n\n // Form case: emit a reset event for each field\n for (var i = 0; i < this.fields.length; i++)\n this.fields[i].reset();\n\n this._trigger('reset');\n },\n\n // Destroy Parsley instance (+ UI)\n destroy: function () {\n // Field case: emit destroy event to clean UI and then destroy stored instance\n this._destroyUI();\n if ('ParsleyForm' !== this.__class__) {\n this.$element.removeData('Parsley');\n this.$element.removeData('ParsleyFieldMultiple');\n this._trigger('destroy');\n\n return;\n }\n\n // Form case: destroy all its fields and then destroy stored instance\n for (var i = 0; i < this.fields.length; i++)\n this.fields[i].destroy();\n\n this.$element.removeData('Parsley');\n this._trigger('destroy');\n },\n\n asyncIsValid: function (group, force) {\n ParsleyUtils__default.warnOnce(\"asyncIsValid is deprecated; please use whenValid instead\");\n return this.whenValid({group, force});\n },\n\n _findRelated: function () {\n return this.options.multiple ?\n this.parent.$element.find(`[${this.options.namespace}multiple=\"${this.options.multiple}\"]`)\n : this.$element;\n }\n };\n\n var requirementConverters = {\n string: function(string) {\n return string;\n },\n integer: function(string) {\n if (isNaN(string))\n throw 'Requirement is not an integer: \"' + string + '\"';\n return parseInt(string, 10);\n },\n number: function(string) {\n if (isNaN(string))\n throw 'Requirement is not a number: \"' + string + '\"';\n return parseFloat(string);\n },\n reference: function(string) { // Unused for now\n var result = $(string);\n if (result.length === 0)\n throw 'No such reference: \"' + string + '\"';\n return result;\n },\n boolean: function(string) {\n return string !== 'false';\n },\n object: function(string) {\n return ParsleyUtils__default.deserializeValue(string);\n },\n regexp: function(regexp) {\n var flags = '';\n\n // Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern\n if (/^\\/.*\\/(?:[gimy]*)$/.test(regexp)) {\n // Replace the regexp literal string with the first match group: ([gimy]*)\n // If no flag is present, this will be a blank string\n flags = regexp.replace(/.*\\/([gimy]*)$/, '$1');\n // Again, replace the regexp literal string with the first match group:\n // everything excluding the opening and closing slashes and the flags\n regexp = regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');\n } else {\n // Anchor regexp:\n regexp = '^' + regexp + '$';\n }\n return new RegExp(regexp, flags);\n }\n };\n\n var convertArrayRequirement = function(string, length) {\n var m = string.match(/^\\s*\\[(.*)\\]\\s*$/);\n if (!m)\n throw 'Requirement is not an array: \"' + string + '\"';\n var values = m[1].split(',').map(ParsleyUtils__default.trimString);\n if (values.length !== length)\n throw 'Requirement has ' + values.length + ' values when ' + length + ' are needed';\n return values;\n };\n\n var convertRequirement = function(requirementType, string) {\n var converter = requirementConverters[requirementType || 'string'];\n if (!converter)\n throw 'Unknown requirement specification: \"' + requirementType + '\"';\n return converter(string);\n };\n\n var convertExtraOptionRequirement = function(requirementSpec, string, extraOptionReader) {\n var main = null;\n var extra = {};\n for (var key in requirementSpec) {\n if (key) {\n var value = extraOptionReader(key);\n if ('string' === typeof value)\n value = convertRequirement(requirementSpec[key], value);\n extra[key] = value;\n } else {\n main = convertRequirement(requirementSpec[key], string);\n }\n }\n return [main, extra];\n };\n\n // A Validator needs to implement the methods `validate` and `parseRequirements`\n\n var ParsleyValidator = function(spec) {\n $.extend(true, this, spec);\n };\n\n ParsleyValidator.prototype = {\n // Returns `true` iff the given `value` is valid according the given requirements.\n validate: function(value, requirementFirstArg) {\n if (this.fn) { // Legacy style validator\n\n if (arguments.length > 3) // If more args then value, requirement, instance...\n requirementFirstArg = [].slice.call(arguments, 1, -1); // Skip first arg (value) and last (instance), combining the rest\n return this.fn.call(this, value, requirementFirstArg);\n }\n\n if ($.isArray(value)) {\n if (!this.validateMultiple)\n throw 'Validator `' + this.name + '` does not handle multiple values';\n return this.validateMultiple(...arguments);\n } else {\n if (this.validateNumber) {\n if (isNaN(value))\n return false;\n arguments[0] = parseFloat(arguments[0]);\n return this.validateNumber(...arguments);\n }\n if (this.validateString) {\n return this.validateString(...arguments);\n }\n throw 'Validator `' + this.name + '` only handles multiple values';\n }\n },\n\n // Parses `requirements` into an array of arguments,\n // according to `this.requirementType`\n parseRequirements: function(requirements, extraOptionReader) {\n if ('string' !== typeof requirements) {\n // Assume requirement already parsed\n // but make sure we return an array\n return $.isArray(requirements) ? requirements : [requirements];\n }\n var type = this.requirementType;\n if ($.isArray(type)) {\n var values = convertArrayRequirement(requirements, type.length);\n for (var i = 0; i < values.length; i++)\n values[i] = convertRequirement(type[i], values[i]);\n return values;\n } else if ($.isPlainObject(type)) {\n return convertExtraOptionRequirement(type, requirements, extraOptionReader);\n } else {\n return [convertRequirement(type, requirements)];\n }\n },\n // Defaults:\n requirementType: 'string',\n\n priority: 2\n\n };\n\n var ParsleyValidatorRegistry = function (validators, catalog) {\n this.__class__ = 'ParsleyValidatorRegistry';\n\n // Default Parsley locale is en\n this.locale = 'en';\n\n this.init(validators || {}, catalog || {});\n };\n\n var typeRegexes = {\n email: /^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))$/i,\n\n // Follow https://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers\n number: /^-?(\\d*\\.)?\\d+(e[-+]?\\d+)?$/i,\n\n integer: /^-?\\d+$/,\n\n digits: /^\\d+$/,\n\n alphanum: /^\\w+$/i,\n\n url: new RegExp(\n \"^\" +\n // protocol identifier\n \"(?:(?:https?|ftp)://)?\" + // ** mod: make scheme optional\n // user:pass authentication\n \"(?:\\\\S+(?::\\\\S*)?@)?\" +\n \"(?:\" +\n // IP address exclusion\n // private & local networks\n // \"(?!(?:10|127)(?:\\\\.\\\\d{1,3}){3})\" + // ** mod: allow local networks\n // \"(?!(?:169\\\\.254|192\\\\.168)(?:\\\\.\\\\d{1,3}){2})\" + // ** mod: allow local networks\n // \"(?!172\\\\.(?:1[6-9]|2\\\\d|3[0-1])(?:\\\\.\\\\d{1,3}){2})\" + // ** mod: allow local networks\n // IP address dotted notation octets\n // excludes loopback network 0.0.0.0\n // excludes reserved space >= 224.0.0.0\n // excludes network & broacast addresses\n // (first & last IP address of each class)\n \"(?:[1-9]\\\\d?|1\\\\d\\\\d|2[01]\\\\d|22[0-3])\" +\n \"(?:\\\\.(?:1?\\\\d{1,2}|2[0-4]\\\\d|25[0-5])){2}\" +\n \"(?:\\\\.(?:[1-9]\\\\d?|1\\\\d\\\\d|2[0-4]\\\\d|25[0-4]))\" +\n \"|\" +\n // host name\n \"(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)\" +\n // domain name\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*\" +\n // TLD identifier\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))\" +\n \")\" +\n // port number\n \"(?::\\\\d{2,5})?\" +\n // resource path\n \"(?:/\\\\S*)?\" +\n \"$\", 'i'\n )\n };\n typeRegexes.range = typeRegexes.number;\n\n // See http://stackoverflow.com/a/10454560/8279\n var decimalPlaces = num => {\n var match = ('' + num).match(/(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/);\n if (!match) { return 0; }\n return Math.max(\n 0,\n // Number of digits right of decimal point.\n (match[1] ? match[1].length : 0) -\n // Adjust for scientific notation.\n (match[2] ? +match[2] : 0));\n };\n\n ParsleyValidatorRegistry.prototype = {\n init: function (validators, catalog) {\n this.catalog = catalog;\n // Copy prototype's validators:\n this.validators = $.extend({}, this.validators);\n\n for (var name in validators)\n this.addValidator(name, validators[name].fn, validators[name].priority);\n\n window.Parsley.trigger('parsley:validator:init');\n },\n\n // Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n\n setLocale: function (locale) {\n if ('undefined' === typeof this.catalog[locale])\n throw new Error(locale + ' is not available in the catalog');\n\n this.locale = locale;\n\n return this;\n },\n\n // Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`\n addCatalog: function (locale, messages, set) {\n if ('object' === typeof messages)\n this.catalog[locale] = messages;\n\n if (true === set)\n return this.setLocale(locale);\n\n return this;\n },\n\n // Add a specific message for a given constraint in a given locale\n addMessage: function (locale, name, message) {\n if ('undefined' === typeof this.catalog[locale])\n this.catalog[locale] = {};\n\n this.catalog[locale][name] = message;\n\n return this;\n },\n\n // Add messages for a given locale\n addMessages: function (locale, nameMessageObject) {\n for (var name in nameMessageObject)\n this.addMessage(locale, name, nameMessageObject[name]);\n\n return this;\n },\n\n // Add a new validator\n //\n // addValidator('custom', {\n // requirementType: ['integer', 'integer'],\n // validateString: function(value, from, to) {},\n // priority: 22,\n // messages: {\n // en: \"Hey, that's no good\",\n // fr: \"Aye aye, pas bon du tout\",\n // }\n // })\n //\n // Old API was addValidator(name, function, priority)\n //\n addValidator: function (name, arg1, arg2) {\n if (this.validators[name])\n ParsleyUtils__default.warn('Validator \"' + name + '\" is already defined.');\n else if (ParsleyDefaults.hasOwnProperty(name)) {\n ParsleyUtils__default.warn('\"' + name + '\" is a restricted keyword and is not a valid validator name.');\n return;\n }\n return this._setValidator(...arguments);\n },\n\n updateValidator: function (name, arg1, arg2) {\n if (!this.validators[name]) {\n ParsleyUtils__default.warn('Validator \"' + name + '\" is not already defined.');\n return this.addValidator(...arguments);\n }\n return this._setValidator(this, arguments);\n },\n\n removeValidator: function (name) {\n if (!this.validators[name])\n ParsleyUtils__default.warn('Validator \"' + name + '\" is not defined.');\n\n delete this.validators[name];\n\n return this;\n },\n\n _setValidator: function (name, validator, priority) {\n if ('object' !== typeof validator) {\n // Old style validator, with `fn` and `priority`\n validator = {\n fn: validator,\n priority: priority\n };\n }\n if (!validator.validate) {\n validator = new ParsleyValidator(validator);\n }\n this.validators[name] = validator;\n\n for (var locale in validator.messages || {})\n this.addMessage(locale, name, validator.messages[locale]);\n\n return this;\n },\n\n getErrorMessage: function (constraint) {\n var message;\n\n // Type constraints are a bit different, we have to match their requirements too to find right error message\n if ('type' === constraint.name) {\n var typeMessages = this.catalog[this.locale][constraint.name] || {};\n message = typeMessages[constraint.requirements];\n } else\n message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);\n\n return message || this.catalog[this.locale].defaultMessage || this.catalog.en.defaultMessage;\n },\n\n // Kind of light `sprintf()` implementation\n formatMessage: function (string, parameters) {\n if ('object' === typeof parameters) {\n for (var i in parameters)\n string = this.formatMessage(string, parameters[i]);\n\n return string;\n }\n\n return 'string' === typeof string ? string.replace(/%s/i, parameters) : '';\n },\n\n // Here is the Parsley default validators list.\n // A validator is an object with the following key values:\n // - priority: an integer\n // - requirement: 'string' (default), 'integer', 'number', 'regexp' or an Array of these\n // - validateString, validateMultiple, validateNumber: functions returning `true`, `false` or a promise\n // Alternatively, a validator can be a function that returns such an object\n //\n validators: {\n notblank: {\n validateString: function(value) {\n return /\\S/.test(value);\n },\n priority: 2\n },\n required: {\n validateMultiple: function(values) {\n return values.length > 0;\n },\n validateString: function(value) {\n return /\\S/.test(value);\n },\n priority: 512\n },\n type: {\n validateString: function(value, type, {step = '1', base = 0} = {}) {\n var regex = typeRegexes[type];\n if (!regex) {\n throw new Error('validator type `' + type + '` is not supported');\n }\n if (!regex.test(value))\n return false;\n if ('number' === type) {\n if (!/^any$/i.test(step || '')) {\n var nb = Number(value);\n var decimals = Math.max(decimalPlaces(step), decimalPlaces(base));\n if (decimalPlaces(nb) > decimals) // Value can't have too many decimals\n return false;\n // Be careful of rounding errors by using integers.\n var toInt = f => { return Math.round(f * Math.pow(10, decimals)); };\n if ((toInt(nb) - toInt(base)) % toInt(step) != 0)\n return false;\n }\n }\n return true;\n },\n requirementType: {\n '': 'string',\n step: 'string',\n base: 'number'\n },\n priority: 256\n },\n pattern: {\n validateString: function(value, regexp) {\n return regexp.test(value);\n },\n requirementType: 'regexp',\n priority: 64\n },\n minlength: {\n validateString: function (value, requirement) {\n return value.length >= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n maxlength: {\n validateString: function (value, requirement) {\n return value.length <= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n length: {\n validateString: function (value, min, max) {\n return value.length >= min && value.length <= max;\n },\n requirementType: ['integer', 'integer'],\n priority: 30\n },\n mincheck: {\n validateMultiple: function (values, requirement) {\n return values.length >= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n maxcheck: {\n validateMultiple: function (values, requirement) {\n return values.length <= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n check: {\n validateMultiple: function (values, min, max) {\n return values.length >= min && values.length <= max;\n },\n requirementType: ['integer', 'integer'],\n priority: 30\n },\n min: {\n validateNumber: function (value, requirement) {\n return value >= requirement;\n },\n requirementType: 'number',\n priority: 30\n },\n max: {\n validateNumber: function (value, requirement) {\n return value <= requirement;\n },\n requirementType: 'number',\n priority: 30\n },\n range: {\n validateNumber: function (value, min, max) {\n return value >= min && value <= max;\n },\n requirementType: ['number', 'number'],\n priority: 30\n },\n equalto: {\n validateString: function (value, refOrValue) {\n var $reference = $(refOrValue);\n if ($reference.length)\n return value === $reference.val();\n else\n return value === refOrValue;\n },\n priority: 256\n }\n }\n };\n\n var ParsleyUI = {};\n\n var diffResults = function (newResult, oldResult, deep) {\n var added = [];\n var kept = [];\n\n for (var i = 0; i < newResult.length; i++) {\n var found = false;\n\n for (var j = 0; j < oldResult.length; j++)\n if (newResult[i].assert.name === oldResult[j].assert.name) {\n found = true;\n break;\n }\n\n if (found)\n kept.push(newResult[i]);\n else\n added.push(newResult[i]);\n }\n\n return {\n kept: kept,\n added: added,\n removed: !deep ? diffResults(oldResult, newResult, true).added : []\n };\n };\n\n ParsleyUI.Form = {\n\n _actualizeTriggers: function () {\n this.$element.on('submit.Parsley', evt => { this.onSubmitValidate(evt); });\n this.$element.on('click.Parsley', 'input[type=\"submit\"], button[type=\"submit\"]', evt => { this.onSubmitButton(evt); });\n\n // UI could be disabled\n if (false === this.options.uiEnabled)\n return;\n\n this.$element.attr('novalidate', '');\n },\n\n focus: function () {\n this._focusedField = null;\n\n if (true === this.validationResult || 'none' === this.options.focus)\n return null;\n\n for (var i = 0; i < this.fields.length; i++) {\n var field = this.fields[i];\n if (true !== field.validationResult && field.validationResult.length > 0 && 'undefined' === typeof field.options.noFocus) {\n this._focusedField = field.$element;\n if ('first' === this.options.focus)\n break;\n }\n }\n\n if (null === this._focusedField)\n return null;\n\n return this._focusedField.focus();\n },\n\n _destroyUI: function () {\n // Reset all event listeners\n this.$element.off('.Parsley');\n }\n\n };\n\n ParsleyUI.Field = {\n\n _reflowUI: function () {\n this._buildUI();\n\n // If this field doesn't have an active UI don't bother doing something\n if (!this._ui)\n return;\n\n // Diff between two validation results\n var diff = diffResults(this.validationResult, this._ui.lastValidationResult);\n\n // Then store current validation result for next reflow\n this._ui.lastValidationResult = this.validationResult;\n\n // Handle valid / invalid / none field class\n this._manageStatusClass();\n\n // Add, remove, updated errors messages\n this._manageErrorsMessages(diff);\n\n // Triggers impl\n this._actualizeTriggers();\n\n // If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user\n if ((diff.kept.length || diff.added.length) && !this._failedOnce) {\n this._failedOnce = true;\n this._actualizeTriggers();\n }\n },\n\n // Returns an array of field's error message(s)\n getErrorsMessages: function () {\n // No error message, field is valid\n if (true === this.validationResult)\n return [];\n\n var messages = [];\n\n for (var i = 0; i < this.validationResult.length; i++)\n messages.push(this.validationResult[i].errorMessage ||\n this._getErrorMessage(this.validationResult[i].assert));\n\n return messages;\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n addError: function (name, {message, assert, updateClass = true} = {}) {\n this._buildUI();\n this._addError(name, {message, assert});\n\n if (updateClass)\n this._errorClass();\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n updateError: function (name, {message, assert, updateClass = true} = {}) {\n this._buildUI();\n this._updateError(name, {message, assert});\n\n if (updateClass)\n this._errorClass();\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n removeError: function (name, {updateClass = true} = {}) {\n this._buildUI();\n this._removeError(name);\n\n // edge case possible here: remove a standard Parsley error that is still failing in this.validationResult\n // but highly improbable cuz' manually removing a well Parsley handled error makes no sense.\n if (updateClass)\n this._manageStatusClass();\n },\n\n _manageStatusClass: function () {\n if (this.hasConstraints() && this.needsValidation() && true === this.validationResult)\n this._successClass();\n else if (this.validationResult.length > 0)\n this._errorClass();\n else\n this._resetClass();\n },\n\n _manageErrorsMessages: function (diff) {\n if ('undefined' !== typeof this.options.errorsMessagesDisabled)\n return;\n\n // Case where we have errorMessage option that configure an unique field error message, regardless failing validators\n if ('undefined' !== typeof this.options.errorMessage) {\n if ((diff.added.length || diff.kept.length)) {\n this._insertErrorWrapper();\n\n if (0 === this._ui.$errorsWrapper.find('.parsley-custom-error-message').length)\n this._ui.$errorsWrapper\n .append(\n $(this.options.errorTemplate)\n .addClass('parsley-custom-error-message')\n );\n\n return this._ui.$errorsWrapper\n .addClass('filled')\n .find('.parsley-custom-error-message')\n .html(this.options.errorMessage);\n }\n\n return this._ui.$errorsWrapper\n .removeClass('filled')\n .find('.parsley-custom-error-message')\n .remove();\n }\n\n // Show, hide, update failing constraints messages\n for (var i = 0; i < diff.removed.length; i++)\n this._removeError(diff.removed[i].assert.name);\n\n for (i = 0; i < diff.added.length; i++)\n this._addError(diff.added[i].assert.name, {message: diff.added[i].errorMessage, assert: diff.added[i].assert});\n\n for (i = 0; i < diff.kept.length; i++)\n this._updateError(diff.kept[i].assert.name, {message: diff.kept[i].errorMessage, assert: diff.kept[i].assert});\n },\n\n\n _addError: function (name, {message, assert}) {\n this._insertErrorWrapper();\n this._ui.$errorsWrapper\n .addClass('filled')\n .append(\n $(this.options.errorTemplate)\n .addClass('parsley-' + name)\n .html(message || this._getErrorMessage(assert))\n );\n },\n\n _updateError: function (name, {message, assert}) {\n this._ui.$errorsWrapper\n .addClass('filled')\n .find('.parsley-' + name)\n .html(message || this._getErrorMessage(assert));\n },\n\n _removeError: function (name) {\n this._ui.$errorsWrapper\n .removeClass('filled')\n .find('.parsley-' + name)\n .remove();\n },\n\n _getErrorMessage: function (constraint) {\n var customConstraintErrorMessage = constraint.name + 'Message';\n\n if ('undefined' !== typeof this.options[customConstraintErrorMessage])\n return window.Parsley.formatMessage(this.options[customConstraintErrorMessage], constraint.requirements);\n\n return window.Parsley.getErrorMessage(constraint);\n },\n\n _buildUI: function () {\n // UI could be already built or disabled\n if (this._ui || false === this.options.uiEnabled)\n return;\n\n var _ui = {};\n\n // Give field its Parsley id in DOM\n this.$element.attr(this.options.namespace + 'id', this.__id__);\n\n /** Generate important UI elements and store them in this **/\n // $errorClassHandler is the $element that woul have parsley-error and parsley-success classes\n _ui.$errorClassHandler = this._manageClassHandler();\n\n // $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer\n _ui.errorsWrapperId = 'parsley-id-' + (this.options.multiple ? 'multiple-' + this.options.multiple : this.__id__);\n _ui.$errorsWrapper = $(this.options.errorsWrapper).attr('id', _ui.errorsWrapperId);\n\n // ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly\n _ui.lastValidationResult = [];\n _ui.validationInformationVisible = false;\n\n // Store it in this for later\n this._ui = _ui;\n },\n\n // Determine which element will have `parsley-error` and `parsley-success` classes\n _manageClassHandler: function () {\n // An element selector could be passed through DOM with `data-parsley-class-handler=#foo`\n if ('string' === typeof this.options.classHandler && $(this.options.classHandler).length)\n return $(this.options.classHandler);\n\n // Class handled could also be determined by function given in Parsley options\n var $handler = this.options.classHandler.call(this, this);\n\n // If this function returned a valid existing DOM element, go for it\n if ('undefined' !== typeof $handler && $handler.length)\n return $handler;\n\n // Otherwise, if simple element (input, texatrea, select...) it will perfectly host the classes\n if (!this.options.multiple || this.$element.is('select'))\n return this.$element;\n\n // But if multiple element (radio, checkbox), that would be their parent\n return this.$element.parent();\n },\n\n _insertErrorWrapper: function () {\n var $errorsContainer;\n\n // Nothing to do if already inserted\n if (0 !== this._ui.$errorsWrapper.parent().length)\n return this._ui.$errorsWrapper.parent();\n\n if ('string' === typeof this.options.errorsContainer) {\n if ($(this.options.errorsContainer).length)\n return $(this.options.errorsContainer).append(this._ui.$errorsWrapper);\n else\n ParsleyUtils__default.warn('The errors container `' + this.options.errorsContainer + '` does not exist in DOM');\n } else if ('function' === typeof this.options.errorsContainer)\n $errorsContainer = this.options.errorsContainer.call(this, this);\n\n if ('undefined' !== typeof $errorsContainer && $errorsContainer.length)\n return $errorsContainer.append(this._ui.$errorsWrapper);\n\n var $from = this.$element;\n if (this.options.multiple)\n $from = $from.parent();\n return $from.after(this._ui.$errorsWrapper);\n },\n\n _actualizeTriggers: function () {\n var $toBind = this._findRelated();\n\n // Remove Parsley events already bound on this field\n $toBind.off('.Parsley');\n if (this._failedOnce)\n $toBind.on(ParsleyUtils__default.namespaceEvents(this.options.triggerAfterFailure, 'Parsley'), () => {\n this.validate();\n });\n else {\n $toBind.on(ParsleyUtils__default.namespaceEvents(this.options.trigger, 'Parsley'), event => {\n this._eventValidate(event);\n });\n }\n },\n\n _eventValidate: function (event) {\n // For keyup, keypress, keydown, input... events that could be a little bit obstrusive\n // do not validate if val length < min threshold on first validation. Once field have been validated once and info\n // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.\n if (/key|input/.test(event.type))\n if (!(this._ui && this._ui.validationInformationVisible) && this.getValue().length <= this.options.validationThreshold)\n return;\n\n this.validate();\n },\n\n _resetUI: function () {\n // Reset all event listeners\n this._failedOnce = false;\n this._actualizeTriggers();\n\n // Nothing to do if UI never initialized for this field\n if ('undefined' === typeof this._ui)\n return;\n\n // Reset all errors' li\n this._ui.$errorsWrapper\n .removeClass('filled')\n .children()\n .remove();\n\n // Reset validation class\n this._resetClass();\n\n // Reset validation flags and last validation result\n this._ui.lastValidationResult = [];\n this._ui.validationInformationVisible = false;\n },\n\n _destroyUI: function () {\n this._resetUI();\n\n if ('undefined' !== typeof this._ui)\n this._ui.$errorsWrapper.remove();\n\n delete this._ui;\n },\n\n _successClass: function () {\n this._ui.validationInformationVisible = true;\n this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass);\n },\n _errorClass: function () {\n this._ui.validationInformationVisible = true;\n this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass);\n },\n _resetClass: function () {\n this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass);\n }\n };\n\n var ParsleyForm = function (element, domOptions, options) {\n this.__class__ = 'ParsleyForm';\n this.__id__ = ParsleyUtils__default.generateID();\n\n this.$element = $(element);\n this.domOptions = domOptions;\n this.options = options;\n this.parent = window.Parsley;\n\n this.fields = [];\n this.validationResult = null;\n };\n\n var ParsleyForm__statusMapping = {pending: null, resolved: true, rejected: false};\n\n ParsleyForm.prototype = {\n onSubmitValidate: function (event) {\n // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior\n if (true === event.parsley)\n return;\n\n // If we didn't come here through a submit button, use the first one in the form\n var $submitSource = this._$submitSource || this.$element.find('input[type=\"submit\"], button[type=\"submit\"]').first();\n this._$submitSource = null;\n this.$element.find('.parsley-synthetic-submit-button').prop('disabled', true);\n if ($submitSource.is('[formnovalidate]'))\n return;\n\n var promise = this.whenValidate({event});\n\n if ('resolved' === promise.state() && false !== this._trigger('submit')) {\n // All good, let event go through. We make this distinction because browsers\n // differ in their handling of `submit` being called from inside a submit event [#1047]\n } else {\n // Rejected or pending: cancel this submit\n event.stopImmediatePropagation();\n event.preventDefault();\n if ('pending' === promise.state())\n promise.done(() => { this._submit($submitSource); });\n }\n },\n\n onSubmitButton: function(event) {\n this._$submitSource = $(event.target);\n },\n // internal\n // _submit submits the form, this time without going through the validations.\n // Care must be taken to \"fake\" the actual submit button being clicked.\n _submit: function ($submitSource) {\n if (false === this._trigger('submit'))\n return;\n // Add submit button's data\n if ($submitSource) {\n var $synthetic = this.$element.find('.parsley-synthetic-submit-button').prop('disabled', false);\n if (0 === $synthetic.length)\n $synthetic = $('<input class=\"parsley-synthetic-submit-button\" type=\"hidden\">').appendTo(this.$element);\n $synthetic.attr({\n name: $submitSource.attr('name'),\n value: $submitSource.attr('value')\n });\n }\n\n this.$element.trigger($.extend($.Event('submit'), {parsley: true}));\n },\n\n // Performs validation on fields while triggering events.\n // @returns `true` if all validations succeeds, `false`\n // if a failure is immediately detected, or `null`\n // if dependant on a promise.\n // Consider using `whenValidate` instead.\n validate: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils__default.warnOnce('Calling validate on a parsley form without passing arguments as an object is deprecated.');\n var [group, force, event] = arguments;\n options = {group, force, event};\n }\n return ParsleyForm__statusMapping[ this.whenValidate(options).state() ];\n },\n\n whenValidate: function ({group, force, event} = {}) {\n this.submitEvent = event;\n if (event) {\n this.submitEvent = $.extend({}, event, {preventDefault: () => {\n ParsleyUtils__default.warnOnce(\"Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`\");\n this.validationResult = false;\n }});\n }\n this.validationResult = true;\n\n // fire validate event to eventually modify things before very validation\n this._trigger('validate');\n\n // Refresh form DOM options and form's fields that could have changed\n this._refreshFields();\n\n var promises = this._withoutReactualizingFormOptions(() => {\n return $.map(this.fields, field => {\n return field.whenValidate({force, group});\n });\n });\n\n var promiseBasedOnValidationResult = () => {\n var r = $.Deferred();\n if (false === this.validationResult)\n r.reject();\n return r.resolve().promise();\n };\n\n return $.when(...promises)\n .done( () => { this._trigger('success'); })\n .fail( () => {\n this.validationResult = false;\n this.focus();\n this._trigger('error');\n })\n .always(() => { this._trigger('validated'); })\n .pipe( promiseBasedOnValidationResult, promiseBasedOnValidationResult);\n },\n\n // Iterate over refreshed fields, and stop on first failure.\n // Returns `true` if all fields are valid, `false` if a failure is detected\n // or `null` if the result depends on an unresolved promise.\n // Prefer using `whenValid` instead.\n isValid: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils__default.warnOnce('Calling isValid on a parsley form without passing arguments as an object is deprecated.');\n var [group, force] = arguments;\n options = {group, force};\n }\n return ParsleyForm__statusMapping[ this.whenValid(options).state() ];\n },\n\n // Iterate over refreshed fields and validate them.\n // Returns a promise.\n // A validation that immediately fails will interrupt the validations.\n whenValid: function ({group, force} = {}) {\n this._refreshFields();\n\n var promises = this._withoutReactualizingFormOptions(() => {\n return $.map(this.fields, field => {\n return field.whenValid({group, force});\n });\n });\n return $.when(...promises);\n },\n\n _refreshFields: function () {\n return this.actualizeOptions()._bindFields();\n },\n\n _bindFields: function () {\n var oldFields = this.fields;\n\n this.fields = [];\n this.fieldsMappedById = {};\n\n this._withoutReactualizingFormOptions(() => {\n this.$element\n .find(this.options.inputs)\n .not(this.options.excluded)\n .each((_, element) => {\n var fieldInstance = new window.Parsley.Factory(element, {}, this);\n\n // Only add valid and not excluded `ParsleyField` and `ParsleyFieldMultiple` children\n if (('ParsleyField' === fieldInstance.__class__ || 'ParsleyFieldMultiple' === fieldInstance.__class__) && (true !== fieldInstance.options.excluded))\n if ('undefined' === typeof this.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__]) {\n this.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__] = fieldInstance;\n this.fields.push(fieldInstance);\n }\n });\n\n $(oldFields).not(this.fields).each((_, field) => {\n field._trigger('reset');\n });\n });\n return this;\n },\n\n // Internal only.\n // Looping on a form's fields to do validation or similar\n // will trigger reactualizing options on all of them, which\n // in turn will reactualize the form's options.\n // To avoid calling actualizeOptions so many times on the form\n // for nothing, _withoutReactualizingFormOptions temporarily disables\n // the method actualizeOptions on this form while `fn` is called.\n _withoutReactualizingFormOptions: function (fn) {\n var oldActualizeOptions = this.actualizeOptions;\n this.actualizeOptions = function () { return this; };\n var result = fn();\n this.actualizeOptions = oldActualizeOptions;\n return result;\n },\n\n // Internal only.\n // Shortcut to trigger an event\n // Returns true iff event is not interrupted and default not prevented.\n _trigger: function (eventName) {\n return this.trigger('form:' + eventName);\n }\n\n };\n\n var ConstraintFactory = function (parsleyField, name, requirements, priority, isDomConstraint) {\n if (!/ParsleyField/.test(parsleyField.__class__))\n throw new Error('ParsleyField or ParsleyFieldMultiple instance expected');\n\n var validatorSpec = window.Parsley._validatorRegistry.validators[name];\n var validator = new ParsleyValidator(validatorSpec);\n\n $.extend(this, {\n validator: validator,\n name: name,\n requirements: requirements,\n priority: priority || parsleyField.options[name + 'Priority'] || validator.priority,\n isDomConstraint: true === isDomConstraint\n });\n this._parseRequirements(parsleyField.options);\n };\n\n var capitalize = function(str) {\n var cap = str[0].toUpperCase();\n return cap + str.slice(1);\n };\n\n ConstraintFactory.prototype = {\n validate: function(value, instance) {\n var args = this.requirementList.slice(0); // Make copy\n args.unshift(value);\n args.push(instance);\n return this.validator.validate.apply(this.validator, args);\n },\n\n _parseRequirements: function(options) {\n this.requirementList = this.validator.parseRequirements(this.requirements, key => {\n return options[this.name + capitalize(key)];\n });\n }\n };\n\n var ParsleyField = function (field, domOptions, options, parsleyFormInstance) {\n this.__class__ = 'ParsleyField';\n this.__id__ = ParsleyUtils__default.generateID();\n\n this.$element = $(field);\n\n // Set parent if we have one\n if ('undefined' !== typeof parsleyFormInstance) {\n this.parent = parsleyFormInstance;\n }\n\n this.options = options;\n this.domOptions = domOptions;\n\n // Initialize some properties\n this.constraints = [];\n this.constraintsByName = {};\n this.validationResult = [];\n\n // Bind constraints\n this._bindConstraints();\n };\n\n var parsley_field__statusMapping = {pending: null, resolved: true, rejected: false};\n\n ParsleyField.prototype = {\n // # Public API\n // Validate field and trigger some events for mainly `ParsleyUI`\n // @returns `true`, an array of the validators that failed, or\n // `null` if validation is not finished. Prefer using whenValidate\n validate: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils__default.warnOnce('Calling validate on a parsley field without passing arguments as an object is deprecated.');\n options = {options};\n }\n var promise = this.whenValidate(options);\n if (!promise) // If excluded with `group` option\n return true;\n switch (promise.state()) {\n case 'pending': return null;\n case 'resolved': return true;\n case 'rejected': return this.validationResult;\n }\n },\n\n // Validate field and trigger some events for mainly `ParsleyUI`\n // @returns a promise that succeeds only when all validations do\n // or `undefined` if field is not in the given `group`.\n whenValidate: function ({force, group} = {}) {\n // do not validate a field if not the same as given validation group\n this.refreshConstraints();\n if (group && !this._isInGroup(group))\n return;\n\n this.value = this.getValue();\n\n // Field Validate event. `this.value` could be altered for custom needs\n this._trigger('validate');\n\n return this.whenValid({force, value: this.value, _refreshed: true})\n .always(() => { this._reflowUI(); })\n .done(() => { this._trigger('success'); })\n .fail(() => { this._trigger('error'); })\n .always(() => { this._trigger('validated'); });\n },\n\n hasConstraints: function () {\n return 0 !== this.constraints.length;\n },\n\n // An empty optional field does not need validation\n needsValidation: function (value) {\n if ('undefined' === typeof value)\n value = this.getValue();\n\n // If a field is empty and not required, it is valid\n // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators\n if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty)\n return false;\n\n return true;\n },\n\n _isInGroup: function (group) {\n if ($.isArray(this.options.group))\n return -1 !== $.inArray(group, this.options.group);\n return this.options.group === group;\n },\n\n // Just validate field. Do not trigger any event.\n // Returns `true` iff all constraints pass, `false` if there are failures,\n // or `null` if the result can not be determined yet (depends on a promise)\n // See also `whenValid`.\n isValid: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils__default.warnOnce('Calling isValid on a parsley field without passing arguments as an object is deprecated.');\n var [force, value] = arguments;\n options = {force, value};\n }\n var promise = this.whenValid(options);\n if (!promise) // Excluded via `group`\n return true;\n return parsley_field__statusMapping[promise.state()];\n },\n\n // Just validate field. Do not trigger any event.\n // @returns a promise that succeeds only when all validations do\n // or `undefined` if the field is not in the given `group`.\n // The argument `force` will force validation of empty fields.\n // If a `value` is given, it will be validated instead of the value of the input.\n whenValid: function ({force = false, value, group, _refreshed} = {}) {\n // Recompute options and rebind constraints to have latest changes\n if (!_refreshed)\n this.refreshConstraints();\n // do not validate a field if not the same as given validation group\n if (group && !this._isInGroup(group))\n return;\n\n this.validationResult = true;\n\n // A field without constraint is valid\n if (!this.hasConstraints())\n return $.when();\n\n // Value could be passed as argument, needed to add more power to 'parsley:field:validate'\n if ('undefined' === typeof value || null === value)\n value = this.getValue();\n\n if (!this.needsValidation(value) && true !== force)\n return $.when();\n\n var groupedConstraints = this._getGroupedConstraints();\n var promises = [];\n $.each(groupedConstraints, (_, constraints) => {\n // Process one group of constraints at a time, we validate the constraints\n // and combine the promises together.\n var promise = $.when(\n ...$.map(constraints, constraint => this._validateConstraint(value, constraint))\n );\n promises.push(promise);\n if (promise.state() === 'rejected')\n return false; // Interrupt processing if a group has already failed\n });\n return $.when.apply($, promises);\n },\n\n // @returns a promise\n _validateConstraint: function(value, constraint) {\n var result = constraint.validate(value, this);\n // Map false to a failed promise\n if (false === result)\n result = $.Deferred().reject();\n // Make sure we return a promise and that we record failures\n return $.when(result).fail(errorMessage => {\n if (true === this.validationResult)\n this.validationResult = [];\n this.validationResult.push({\n assert: constraint,\n errorMessage: 'string' === typeof errorMessage && errorMessage\n });\n });\n },\n\n // @returns Parsley field computed value that could be overrided or configured in DOM\n getValue: function () {\n var value;\n\n // Value could be overriden in DOM or with explicit options\n if ('function' === typeof this.options.value)\n value = this.options.value(this);\n else if ('undefined' !== typeof this.options.value)\n value = this.options.value;\n else\n value = this.$element.val();\n\n // Handle wrong DOM or configurations\n if ('undefined' === typeof value || null === value)\n return '';\n\n return this._handleWhitespace(value);\n },\n\n // Actualize options that could have change since previous validation\n // Re-bind accordingly constraints (could be some new, removed or updated)\n refreshConstraints: function () {\n return this.actualizeOptions()._bindConstraints();\n },\n\n /**\n * Add a new constraint to a field\n *\n * @param {String} name\n * @param {Mixed} requirements optional\n * @param {Number} priority optional\n * @param {Boolean} isDomConstraint optional\n */\n addConstraint: function (name, requirements, priority, isDomConstraint) {\n\n if (window.Parsley._validatorRegistry.validators[name]) {\n var constraint = new ConstraintFactory(this, name, requirements, priority, isDomConstraint);\n\n // if constraint already exist, delete it and push new version\n if ('undefined' !== this.constraintsByName[constraint.name])\n this.removeConstraint(constraint.name);\n\n this.constraints.push(constraint);\n this.constraintsByName[constraint.name] = constraint;\n }\n\n return this;\n },\n\n // Remove a constraint\n removeConstraint: function (name) {\n for (var i = 0; i < this.constraints.length; i++)\n if (name === this.constraints[i].name) {\n this.constraints.splice(i, 1);\n break;\n }\n delete this.constraintsByName[name];\n return this;\n },\n\n // Update a constraint (Remove + re-add)\n updateConstraint: function (name, parameters, priority) {\n return this.removeConstraint(name)\n .addConstraint(name, parameters, priority);\n },\n\n // # Internals\n\n // Internal only.\n // Bind constraints from config + options + DOM\n _bindConstraints: function () {\n var constraints = [];\n var constraintsByName = {};\n\n // clean all existing DOM constraints to only keep javascript user constraints\n for (var i = 0; i < this.constraints.length; i++)\n if (false === this.constraints[i].isDomConstraint) {\n constraints.push(this.constraints[i]);\n constraintsByName[this.constraints[i].name] = this.constraints[i];\n }\n\n this.constraints = constraints;\n this.constraintsByName = constraintsByName;\n\n // then re-add Parsley DOM-API constraints\n for (var name in this.options)\n this.addConstraint(name, this.options[name], undefined, true);\n\n // finally, bind special HTML5 constraints\n return this._bindHtml5Constraints();\n },\n\n // Internal only.\n // Bind specific HTML5 constraints to be HTML5 compliant\n _bindHtml5Constraints: function () {\n // html5 required\n if (this.$element.hasClass('required') || this.$element.attr('required'))\n this.addConstraint('required', true, undefined, true);\n\n // html5 pattern\n if ('string' === typeof this.$element.attr('pattern'))\n this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);\n\n // range\n if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max'))\n this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);\n\n // HTML5 min\n else if ('undefined' !== typeof this.$element.attr('min'))\n this.addConstraint('min', this.$element.attr('min'), undefined, true);\n\n // HTML5 max\n else if ('undefined' !== typeof this.$element.attr('max'))\n this.addConstraint('max', this.$element.attr('max'), undefined, true);\n\n\n // length\n if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength'))\n this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);\n\n // HTML5 minlength\n else if ('undefined' !== typeof this.$element.attr('minlength'))\n this.addConstraint('minlength', this.$element.attr('minlength'), undefined, true);\n\n // HTML5 maxlength\n else if ('undefined' !== typeof this.$element.attr('maxlength'))\n this.addConstraint('maxlength', this.$element.attr('maxlength'), undefined, true);\n\n\n // html5 types\n var type = this.$element.attr('type');\n\n if ('undefined' === typeof type)\n return this;\n\n // Small special case here for HTML5 number: integer validator if step attribute is undefined or an integer value, number otherwise\n if ('number' === type) {\n return this.addConstraint('type', ['number', {\n step: this.$element.attr('step'),\n base: this.$element.attr('min') || this.$element.attr('value')\n }], undefined, true);\n // Regular other HTML5 supported types\n } else if (/^(email|url|range)$/i.test(type)) {\n return this.addConstraint('type', type, undefined, true);\n }\n return this;\n },\n\n // Internal only.\n // Field is required if have required constraint without `false` value\n _isRequired: function () {\n if ('undefined' === typeof this.constraintsByName.required)\n return false;\n\n return false !== this.constraintsByName.required.requirements;\n },\n\n // Internal only.\n // Shortcut to trigger an event\n _trigger: function (eventName) {\n return this.trigger('field:' + eventName);\n },\n\n // Internal only\n // Handles whitespace in a value\n // Use `data-parsley-whitespace=\"squish\"` to auto squish input value\n // Use `data-parsley-whitespace=\"trim\"` to auto trim input value\n _handleWhitespace: function (value) {\n if (true === this.options.trimValue)\n ParsleyUtils__default.warnOnce('data-parsley-trim-value=\"true\" is deprecated, please use data-parsley-whitespace=\"trim\"');\n\n if ('squish' === this.options.whitespace)\n value = value.replace(/\\s{2,}/g, ' ');\n\n if (('trim' === this.options.whitespace) || ('squish' === this.options.whitespace) || (true === this.options.trimValue))\n value = ParsleyUtils__default.trimString(value);\n\n return value;\n },\n\n // Internal only.\n // Returns the constraints, grouped by descending priority.\n // The result is thus an array of arrays of constraints.\n _getGroupedConstraints: function () {\n if (false === this.options.priorityEnabled)\n return [this.constraints];\n\n var groupedConstraints = [];\n var index = {};\n\n // Create array unique of priorities\n for (var i = 0; i < this.constraints.length; i++) {\n var p = this.constraints[i].priority;\n if (!index[p])\n groupedConstraints.push(index[p] = []);\n index[p].push(this.constraints[i]);\n }\n // Sort them by priority DESC\n groupedConstraints.sort(function (a, b) { return b[0].priority - a[0].priority; });\n\n return groupedConstraints;\n }\n\n };\n\n var parsley_field = ParsleyField;\n\n var ParsleyMultiple = function () {\n this.__class__ = 'ParsleyFieldMultiple';\n };\n\n ParsleyMultiple.prototype = {\n // Add new `$element` sibling for multiple field\n addElement: function ($element) {\n this.$elements.push($element);\n\n return this;\n },\n\n // See `ParsleyField.refreshConstraints()`\n refreshConstraints: function () {\n var fieldConstraints;\n\n this.constraints = [];\n\n // Select multiple special treatment\n if (this.$element.is('select')) {\n this.actualizeOptions()._bindConstraints();\n\n return this;\n }\n\n // Gather all constraints for each input in the multiple group\n for (var i = 0; i < this.$elements.length; i++) {\n\n // Check if element have not been dynamically removed since last binding\n if (!$('html').has(this.$elements[i]).length) {\n this.$elements.splice(i, 1);\n continue;\n }\n\n fieldConstraints = this.$elements[i].data('ParsleyFieldMultiple').refreshConstraints().constraints;\n\n for (var j = 0; j < fieldConstraints.length; j++)\n this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint);\n }\n\n return this;\n },\n\n // See `ParsleyField.getValue()`\n getValue: function () {\n // Value could be overriden in DOM\n if ('function' === typeof this.options.value)\n value = this.options.value(this);\n else if ('undefined' !== typeof this.options.value)\n return this.options.value;\n\n // Radio input case\n if (this.$element.is('input[type=radio]'))\n return this._findRelated().filter(':checked').val() || '';\n\n // checkbox input case\n if (this.$element.is('input[type=checkbox]')) {\n var values = [];\n\n this._findRelated().filter(':checked').each(function () {\n values.push($(this).val());\n });\n\n return values;\n }\n\n // Select multiple case\n if (this.$element.is('select') && null === this.$element.val())\n return [];\n\n // Default case that should never happen\n return this.$element.val();\n },\n\n _init: function () {\n this.$elements = [this.$element];\n\n return this;\n }\n };\n\n var ParsleyFactory = function (element, options, parsleyFormInstance) {\n this.$element = $(element);\n\n // If the element has already been bound, returns its saved Parsley instance\n var savedparsleyFormInstance = this.$element.data('Parsley');\n if (savedparsleyFormInstance) {\n\n // If the saved instance has been bound without a ParsleyForm parent and there is one given in this call, add it\n if ('undefined' !== typeof parsleyFormInstance && savedparsleyFormInstance.parent === window.Parsley) {\n savedparsleyFormInstance.parent = parsleyFormInstance;\n savedparsleyFormInstance._resetOptions(savedparsleyFormInstance.options);\n }\n\n return savedparsleyFormInstance;\n }\n\n // Parsley must be instantiated with a DOM element or jQuery $element\n if (!this.$element.length)\n throw new Error('You must bind Parsley on an existing element.');\n\n if ('undefined' !== typeof parsleyFormInstance && 'ParsleyForm' !== parsleyFormInstance.__class__)\n throw new Error('Parent instance must be a ParsleyForm instance');\n\n this.parent = parsleyFormInstance || window.Parsley;\n return this.init(options);\n };\n\n ParsleyFactory.prototype = {\n init: function (options) {\n this.__class__ = 'Parsley';\n this.__version__ = '2.3.5';\n this.__id__ = ParsleyUtils__default.generateID();\n\n // Pre-compute options\n this._resetOptions(options);\n\n // A ParsleyForm instance is obviously a `<form>` element but also every node that is not an input and has the `data-parsley-validate` attribute\n if (this.$element.is('form') || (ParsleyUtils__default.checkAttr(this.$element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)))\n return this.bind('parsleyForm');\n\n // Every other element is bound as a `ParsleyField` or `ParsleyFieldMultiple`\n return this.isMultiple() ? this.handleMultiple() : this.bind('parsleyField');\n },\n\n isMultiple: function () {\n return (this.$element.is('input[type=radio], input[type=checkbox]')) || (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple'));\n },\n\n // Multiples fields are a real nightmare :(\n // Maybe some refactoring would be appreciated here...\n handleMultiple: function () {\n var name;\n var multiple;\n var parsleyMultipleInstance;\n\n // Handle multiple name\n if (this.options.multiple)\n ; // We already have our 'multiple' identifier\n else if ('undefined' !== typeof this.$element.attr('name') && this.$element.attr('name').length)\n this.options.multiple = name = this.$element.attr('name');\n else if ('undefined' !== typeof this.$element.attr('id') && this.$element.attr('id').length)\n this.options.multiple = this.$element.attr('id');\n\n // Special select multiple input\n if (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple')) {\n this.options.multiple = this.options.multiple || this.__id__;\n return this.bind('parsleyFieldMultiple');\n\n // Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it\n } else if (!this.options.multiple) {\n ParsleyUtils__default.warn('To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.', this.$element);\n return this;\n }\n\n // Remove special chars\n this.options.multiple = this.options.multiple.replace(/(:|\\.|\\[|\\]|\\{|\\}|\\$)/g, '');\n\n // Add proper `data-parsley-multiple` to siblings if we have a valid multiple name\n if ('undefined' !== typeof name) {\n $('input[name=\"' + name + '\"]').each((i, input) => {\n if ($(input).is('input[type=radio], input[type=checkbox]'))\n $(input).attr(this.options.namespace + 'multiple', this.options.multiple);\n });\n }\n\n // Check here if we don't already have a related multiple instance saved\n var $previouslyRelated = this._findRelated();\n for (var i = 0; i < $previouslyRelated.length; i++) {\n parsleyMultipleInstance = $($previouslyRelated.get(i)).data('Parsley');\n if ('undefined' !== typeof parsleyMultipleInstance) {\n\n if (!this.$element.data('ParsleyFieldMultiple')) {\n parsleyMultipleInstance.addElement(this.$element);\n }\n\n break;\n }\n }\n\n // Create a secret ParsleyField instance for every multiple field. It will be stored in `data('ParsleyFieldMultiple')`\n // And will be useful later to access classic `ParsleyField` stuff while being in a `ParsleyFieldMultiple` instance\n this.bind('parsleyField', true);\n\n return parsleyMultipleInstance || this.bind('parsleyFieldMultiple');\n },\n\n // Return proper `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`\n bind: function (type, doNotStore) {\n var parsleyInstance;\n\n switch (type) {\n case 'parsleyForm':\n parsleyInstance = $.extend(\n new ParsleyForm(this.$element, this.domOptions, this.options),\n window.ParsleyExtend\n )._bindFields();\n break;\n case 'parsleyField':\n parsleyInstance = $.extend(\n new parsley_field(this.$element, this.domOptions, this.options, this.parent),\n window.ParsleyExtend\n );\n break;\n case 'parsleyFieldMultiple':\n parsleyInstance = $.extend(\n new parsley_field(this.$element, this.domOptions, this.options, this.parent),\n new ParsleyMultiple(),\n window.ParsleyExtend\n )._init();\n break;\n default:\n throw new Error(type + 'is not a supported Parsley type');\n }\n\n if (this.options.multiple)\n ParsleyUtils__default.setAttr(this.$element, this.options.namespace, 'multiple', this.options.multiple);\n\n if ('undefined' !== typeof doNotStore) {\n this.$element.data('ParsleyFieldMultiple', parsleyInstance);\n\n return parsleyInstance;\n }\n\n // Store the freshly bound instance in a DOM element for later access using jQuery `data()`\n this.$element.data('Parsley', parsleyInstance);\n\n // Tell the world we have a new ParsleyForm or ParsleyField instance!\n parsleyInstance._actualizeTriggers();\n parsleyInstance._trigger('init');\n\n return parsleyInstance;\n }\n };\n\n var vernums = $.fn.jquery.split('.');\n if (parseInt(vernums[0]) <= 1 && parseInt(vernums[1]) < 8) {\n throw \"The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.\";\n }\n if (!vernums.forEach) {\n ParsleyUtils__default.warn('Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim');\n }\n // Inherit `on`, `off` & `trigger` to Parsley:\n var Parsley = $.extend(new ParsleyAbstract(), {\n $element: $(document),\n actualizeOptions: null,\n _resetOptions: null,\n Factory: ParsleyFactory,\n version: '2.3.5'\n });\n\n // Supplement ParsleyField and Form with ParsleyAbstract\n // This way, the constructors will have access to those methods\n $.extend(parsley_field.prototype, ParsleyUI.Field, ParsleyAbstract.prototype);\n $.extend(ParsleyForm.prototype, ParsleyUI.Form, ParsleyAbstract.prototype);\n // Inherit actualizeOptions and _resetOptions:\n $.extend(ParsleyFactory.prototype, ParsleyAbstract.prototype);\n\n // ### jQuery API\n // `$('.elem').parsley(options)` or `$('.elem').psly(options)`\n $.fn.parsley = $.fn.psly = function (options) {\n if (this.length > 1) {\n var instances = [];\n\n this.each(function () {\n instances.push($(this).parsley(options));\n });\n\n return instances;\n }\n\n // Return undefined if applied to non existing DOM element\n if (!$(this).length) {\n ParsleyUtils__default.warn('You must bind Parsley on an existing element.');\n\n return;\n }\n\n return new ParsleyFactory(this, options);\n };\n\n // ### ParsleyField and ParsleyForm extension\n // Ensure the extension is now defined if it wasn't previously\n if ('undefined' === typeof window.ParsleyExtend)\n window.ParsleyExtend = {};\n\n // ### Parsley config\n // Inherit from ParsleyDefault, and copy over any existing values\n Parsley.options = $.extend(ParsleyUtils__default.objectCreate(ParsleyDefaults), window.ParsleyConfig);\n window.ParsleyConfig = Parsley.options; // Old way of accessing global options\n\n // ### Globals\n window.Parsley = window.psly = Parsley;\n window.ParsleyUtils = ParsleyUtils__default;\n\n // ### Define methods that forward to the registry, and deprecate all access except through window.Parsley\n var registry = window.Parsley._validatorRegistry = new ParsleyValidatorRegistry(window.ParsleyConfig.validators, window.ParsleyConfig.i18n);\n window.ParsleyValidator = {};\n $.each('setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator'.split(' '), function (i, method) {\n window.Parsley[method] = $.proxy(registry, method);\n window.ParsleyValidator[method] = function () {\n ParsleyUtils__default.warnOnce(`Accessing the method '${method}' through ParsleyValidator is deprecated. Simply call 'window.Parsley.${method}(...)'`);\n return window.Parsley[method](...arguments);\n };\n });\n\n // ### ParsleyUI\n // Deprecated global object\n window.Parsley.UI = ParsleyUI;\n window.ParsleyUI = {\n removeError: function (instance, name, doNotUpdateClass) {\n var updateClass = true !== doNotUpdateClass;\n ParsleyUtils__default.warnOnce(`Accessing ParsleyUI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method.`);\n return instance.removeError(name, {updateClass});\n },\n getErrorsMessages: function (instance) {\n ParsleyUtils__default.warnOnce(`Accessing ParsleyUI is deprecated. Call 'getErrorsMessages' on the instance directly.`);\n return instance.getErrorsMessages();\n }\n };\n $.each('addError updateError'.split(' '), function (i, method) {\n window.ParsleyUI[method] = function (instance, name, message, assert, doNotUpdateClass) {\n var updateClass = true !== doNotUpdateClass;\n ParsleyUtils__default.warnOnce(`Accessing ParsleyUI is deprecated. Call '${method}' on the instance directly. Please comment in issue 1073 as to your need to call this method.`);\n return instance[method](name, {message, assert, updateClass});\n };\n });\n\n // Alleviate glaring Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=1250521\n // See also https://github.com/guillaumepotier/Parsley.js/issues/1068\n if (/firefox/i.test(navigator.userAgent)) {\n $(document).on('change', 'select', evt => {\n $(evt.target).trigger('input');\n });\n }\n\n // ### PARSLEY auto-binding\n // Prevent it by setting `ParsleyConfig.autoBind` to `false`\n if (false !== window.ParsleyConfig.autoBind) {\n $(function () {\n // Works only on `data-parsley-validate`.\n if ($('[data-parsley-validate]').length)\n $('[data-parsley-validate]').parsley();\n });\n }\n\n var o = $({});\n var deprecated = function () {\n ParsleyUtils__default.warnOnce(\"Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley\");\n };\n\n // Returns an event handler that calls `fn` with the arguments it expects\n function adapt(fn, context) {\n // Store to allow unbinding\n if (!fn.parsleyAdaptedCallback) {\n fn.parsleyAdaptedCallback = function () {\n var args = Array.prototype.slice.call(arguments, 0);\n args.unshift(this);\n fn.apply(context || o, args);\n };\n }\n return fn.parsleyAdaptedCallback;\n }\n\n var eventPrefix = 'parsley:';\n // Converts 'parsley:form:validate' into 'form:validate'\n function eventName(name) {\n if (name.lastIndexOf(eventPrefix, 0) === 0)\n return name.substr(eventPrefix.length);\n return name;\n }\n\n // $.listen is deprecated. Use Parsley.on instead.\n $.listen = function (name, callback) {\n var context;\n deprecated();\n if ('object' === typeof arguments[1] && 'function' === typeof arguments[2]) {\n context = arguments[1];\n callback = arguments[2];\n }\n\n if ('function' !== typeof callback)\n throw new Error('Wrong parameters');\n\n window.Parsley.on(eventName(name), adapt(callback, context));\n };\n\n $.listenTo = function (instance, name, fn) {\n deprecated();\n if (!(instance instanceof parsley_field) && !(instance instanceof ParsleyForm))\n throw new Error('Must give Parsley instance');\n\n if ('string' !== typeof name || 'function' !== typeof fn)\n throw new Error('Wrong parameters');\n\n instance.on(eventName(name), adapt(fn));\n };\n\n $.unsubscribe = function (name, fn) {\n deprecated();\n if ('string' !== typeof name || 'function' !== typeof fn)\n throw new Error('Wrong arguments');\n window.Parsley.off(eventName(name), fn.parsleyAdaptedCallback);\n };\n\n $.unsubscribeTo = function (instance, name) {\n deprecated();\n if (!(instance instanceof parsley_field) && !(instance instanceof ParsleyForm))\n throw new Error('Must give Parsley instance');\n instance.off(eventName(name));\n };\n\n $.unsubscribeAll = function (name) {\n deprecated();\n window.Parsley.off(eventName(name));\n $('form,input,textarea,select').each(function () {\n var instance = $(this).data('Parsley');\n if (instance) {\n instance.off(eventName(name));\n }\n });\n };\n\n // $.emit is deprecated. Use jQuery events instead.\n $.emit = function (name, instance) {\n deprecated();\n var instanceGiven = (instance instanceof parsley_field) || (instance instanceof ParsleyForm);\n var args = Array.prototype.slice.call(arguments, instanceGiven ? 2 : 1);\n args.unshift(eventName(name));\n if (!instanceGiven) {\n instance = window.Parsley;\n }\n instance.trigger(...args);\n };\n\n var pubsub = {};\n\n $.extend(true, Parsley, {\n asyncValidators: {\n 'default': {\n fn: function (xhr) {\n // By default, only status 2xx are deemed successful.\n // Note: we use status instead of state() because responses with status 200\n // but invalid messages (e.g. an empty body for content type set to JSON) will\n // result in state() === 'rejected'.\n return xhr.status >= 200 && xhr.status < 300;\n },\n url: false\n },\n reverse: {\n fn: function (xhr) {\n // If reverse option is set, a failing ajax request is considered successful\n return xhr.status < 200 || xhr.status >= 300;\n },\n url: false\n }\n },\n\n addAsyncValidator: function (name, fn, url, options) {\n Parsley.asyncValidators[name] = {\n fn: fn,\n url: url || false,\n options: options || {}\n };\n\n return this;\n }\n\n });\n\n Parsley.addValidator('remote', {\n requirementType: {\n '': 'string',\n 'validator': 'string',\n 'reverse': 'boolean',\n 'options': 'object'\n },\n\n validateString: function (value, url, options, instance) {\n var data = {};\n var ajaxOptions;\n var csr;\n var validator = options.validator || (true === options.reverse ? 'reverse' : 'default');\n\n if ('undefined' === typeof Parsley.asyncValidators[validator])\n throw new Error('Calling an undefined async validator: `' + validator + '`');\n\n url = Parsley.asyncValidators[validator].url || url;\n\n // Fill current value\n if (url.indexOf('{value}') > -1) {\n url = url.replace('{value}', encodeURIComponent(value));\n } else {\n data[instance.$element.attr('name') || instance.$element.attr('id')] = value;\n }\n\n // Merge options passed in from the function with the ones in the attribute\n var remoteOptions = $.extend(true, options.options || {} , Parsley.asyncValidators[validator].options);\n\n // All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options`\n ajaxOptions = $.extend(true, {}, {\n url: url,\n data: data,\n type: 'GET'\n }, remoteOptions);\n\n // Generate store key based on ajax options\n instance.trigger('field:ajaxoptions', instance, ajaxOptions);\n\n csr = $.param(ajaxOptions);\n\n // Initialise querry cache\n if ('undefined' === typeof Parsley._remoteCache)\n Parsley._remoteCache = {};\n\n // Try to retrieve stored xhr\n var xhr = Parsley._remoteCache[csr] = Parsley._remoteCache[csr] || $.ajax(ajaxOptions);\n\n var handleXhr = function () {\n var result = Parsley.asyncValidators[validator].fn.call(instance, xhr, url, options);\n if (!result) // Map falsy results to rejected promise\n result = $.Deferred().reject();\n return $.when(result);\n };\n\n return xhr.then(handleXhr, handleXhr);\n },\n\n priority: -1\n });\n\n Parsley.on('form:submit', function () {\n Parsley._remoteCache = {};\n });\n\n window.ParsleyExtend.addAsyncValidator = function () {\n ParsleyUtils.warnOnce('Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`');\n return Parsley.addAsyncValidator(...arguments);\n };\n\n // This is included with the Parsley library itself,\n // thus there is no use in adding it to your project.\n Parsley.addMessages('en', {\n defaultMessage: \"This value seems to be invalid.\",\n type: {\n email: \"This value should be a valid email.\",\n url: \"This value should be a valid url.\",\n number: \"This value should be a valid number.\",\n integer: \"This value should be a valid integer.\",\n digits: \"This value should be digits.\",\n alphanum: \"This value should be alphanumeric.\"\n },\n notblank: \"This value should not be blank.\",\n required: \"This value is required.\",\n pattern: \"This value seems to be invalid.\",\n min: \"This value should be greater than or equal to %s.\",\n max: \"This value should be lower than or equal to %s.\",\n range: \"This value should be between %s and %s.\",\n minlength: \"This value is too short. It should have %s characters or more.\",\n maxlength: \"This value is too long. It should have %s characters or fewer.\",\n length: \"This value length is invalid. It should be between %s and %s characters long.\",\n mincheck: \"You must select at least %s choices.\",\n maxcheck: \"You must select %s choices or fewer.\",\n check: \"You must select between %s and %s choices.\",\n equalto: \"This value should be the same.\"\n });\n\n Parsley.setLocale('en');\n\n var parsley = Parsley;\n\n return parsley;\n\n}));\n","import $ from 'jquery';\nimport ParsleyField from './field';\nimport ParsleyForm from './form';\nimport ParsleyUtils from './utils';\n\nvar o = $({});\nvar deprecated = function () {\n ParsleyUtils.warnOnce(\"Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley\");\n};\n\n// Returns an event handler that calls `fn` with the arguments it expects\nfunction adapt(fn, context) {\n // Store to allow unbinding\n if (!fn.parsleyAdaptedCallback) {\n fn.parsleyAdaptedCallback = function () {\n var args = Array.prototype.slice.call(arguments, 0);\n args.unshift(this);\n fn.apply(context || o, args);\n };\n }\n return fn.parsleyAdaptedCallback;\n}\n\nvar eventPrefix = 'parsley:';\n// Converts 'parsley:form:validate' into 'form:validate'\nfunction eventName(name) {\n if (name.lastIndexOf(eventPrefix, 0) === 0)\n return name.substr(eventPrefix.length);\n return name;\n}\n\n// $.listen is deprecated. Use Parsley.on instead.\n$.listen = function (name, callback) {\n var context;\n deprecated();\n if ('object' === typeof arguments[1] && 'function' === typeof arguments[2]) {\n context = arguments[1];\n callback = arguments[2];\n }\n\n if ('function' !== typeof callback)\n throw new Error('Wrong parameters');\n\n window.Parsley.on(eventName(name), adapt(callback, context));\n};\n\n$.listenTo = function (instance, name, fn) {\n deprecated();\n if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))\n throw new Error('Must give Parsley instance');\n\n if ('string' !== typeof name || 'function' !== typeof fn)\n throw new Error('Wrong parameters');\n\n instance.on(eventName(name), adapt(fn));\n};\n\n$.unsubscribe = function (name, fn) {\n deprecated();\n if ('string' !== typeof name || 'function' !== typeof fn)\n throw new Error('Wrong arguments');\n window.Parsley.off(eventName(name), fn.parsleyAdaptedCallback);\n};\n\n$.unsubscribeTo = function (instance, name) {\n deprecated();\n if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))\n throw new Error('Must give Parsley instance');\n instance.off(eventName(name));\n};\n\n$.unsubscribeAll = function (name) {\n deprecated();\n window.Parsley.off(eventName(name));\n $('form,input,textarea,select').each(function () {\n var instance = $(this).data('Parsley');\n if (instance) {\n instance.off(eventName(name));\n }\n });\n};\n\n// $.emit is deprecated. Use jQuery events instead.\n$.emit = function (name, instance) {\n deprecated();\n var instanceGiven = (instance instanceof ParsleyField) || (instance instanceof ParsleyForm);\n var args = Array.prototype.slice.call(arguments, instanceGiven ? 2 : 1);\n args.unshift(eventName(name));\n if (!instanceGiven) {\n instance = window.Parsley;\n }\n instance.trigger(...args);\n};\n\nexport default {};\n","import $ from 'jquery';\n\nvar globalID = 1;\nvar pastWarnings = {};\n\nvar ParsleyUtils = {\n // Parsley DOM-API\n // returns object from dom attributes and values\n attr: function ($element, namespace, obj) {\n var i;\n var attribute;\n var attributes;\n var regex = new RegExp('^' + namespace, 'i');\n\n if ('undefined' === typeof obj)\n obj = {};\n else {\n // Clear all own properties. This won't affect prototype's values\n for (i in obj) {\n if (obj.hasOwnProperty(i))\n delete obj[i];\n }\n }\n\n if ('undefined' === typeof $element || 'undefined' === typeof $element[0])\n return obj;\n\n attributes = $element[0].attributes;\n for (i = attributes.length; i--; ) {\n attribute = attributes[i];\n\n if (attribute && attribute.specified && regex.test(attribute.name)) {\n obj[this.camelize(attribute.name.slice(namespace.length))] = this.deserializeValue(attribute.value);\n }\n }\n\n return obj;\n },\n\n checkAttr: function ($element, namespace, checkAttr) {\n return $element.is('[' + namespace + checkAttr + ']');\n },\n\n setAttr: function ($element, namespace, attr, value) {\n $element[0].setAttribute(this.dasherize(namespace + attr), String(value));\n },\n\n generateID: function () {\n return '' + globalID++;\n },\n\n /** Third party functions **/\n // Zepto deserialize function\n deserializeValue: function (value) {\n var num;\n\n try {\n return value ?\n value == \"true\" ||\n (value == \"false\" ? false :\n value == \"null\" ? null :\n !isNaN(num = Number(value)) ? num :\n /^[\\[\\{]/.test(value) ? $.parseJSON(value) :\n value)\n : value;\n } catch (e) { return value; }\n },\n\n // Zepto camelize function\n camelize: function (str) {\n return str.replace(/-+(.)?/g, function (match, chr) {\n return chr ? chr.toUpperCase() : '';\n });\n },\n\n // Zepto dasherize function\n dasherize: function (str) {\n return str.replace(/::/g, '/')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-z\\d])([A-Z])/g, '$1_$2')\n .replace(/_/g, '-')\n .toLowerCase();\n },\n\n warn: function () {\n if (window.console && 'function' === typeof window.console.warn)\n window.console.warn(...arguments);\n },\n\n warnOnce: function(msg) {\n if (!pastWarnings[msg]) {\n pastWarnings[msg] = true;\n this.warn(...arguments);\n }\n },\n\n _resetWarnings: function () {\n pastWarnings = {};\n },\n\n trimString: function(string) {\n return string.replace(/^\\s+|\\s+$/g, '');\n },\n\n namespaceEvents: function(events, namespace) {\n events = this.trimString(events || '').split(/\\s+/);\n if (!events[0])\n return '';\n return $.map(events, evt => { return `${evt}.${namespace}`; }).join(' ');\n },\n\n // Object.create polyfill, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill\n objectCreate: Object.create || (function () {\n var Object = function () {};\n return function (prototype) {\n if (arguments.length > 1) {\n throw Error('Second argument not supported');\n }\n if (typeof prototype != 'object') {\n throw TypeError('Argument must be an object');\n }\n Object.prototype = prototype;\n var result = new Object();\n Object.prototype = null;\n return result;\n };\n })()\n};\n\nexport default ParsleyUtils;\n","// All these options could be overriden and specified directly in DOM using\n// `data-parsley-` default DOM-API\n// eg: `inputs` can be set in DOM using `data-parsley-inputs=\"input, textarea\"`\n// eg: `data-parsley-stop-on-first-failing-constraint=\"false\"`\n\nvar ParsleyDefaults = {\n // ### General\n\n // Default data-namespace for DOM API\n namespace: 'data-parsley-',\n\n // Supported inputs by default\n inputs: 'input, textarea, select',\n\n // Excluded inputs by default\n excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',\n\n // Stop validating field on highest priority failing constraint\n priorityEnabled: true,\n\n // ### Field only\n\n // identifier used to group together inputs (e.g. radio buttons...)\n multiple: null,\n\n // identifier (or array of identifiers) used to validate only a select group of inputs\n group: null,\n\n // ### UI\n // Enable\\Disable error messages\n uiEnabled: true,\n\n // Key events threshold before validation\n validationThreshold: 3,\n\n // Focused field on form validation error. 'first'|'last'|'none'\n focus: 'first',\n\n // event(s) that will trigger validation before first failure. eg: `input`...\n trigger: false,\n\n // event(s) that will trigger validation after first failure.\n triggerAfterFailure: 'input',\n\n // Class that would be added on every failing validation Parsley field\n errorClass: 'parsley-error',\n\n // Same for success validation\n successClass: 'parsley-success',\n\n // Return the `$element` that will receive these above success or error classes\n // Could also be (and given directly from DOM) a valid selector like `'#div'`\n classHandler: function (ParsleyField) {},\n\n // Return the `$element` where errors will be appended\n // Could also be (and given directly from DOM) a valid selector like `'#div'`\n errorsContainer: function (ParsleyField) {},\n\n // ul elem that would receive errors' list\n errorsWrapper: '<ul class=\"parsley-errors-list\"></ul>',\n\n // li elem that would receive error message\n errorTemplate: '<li></li>'\n};\n\nexport default ParsleyDefaults;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\n\nvar ParsleyAbstract = function () {};\n\nParsleyAbstract.prototype = {\n asyncSupport: true, // Deprecated\n\n actualizeOptions: function () {\n ParsleyUtils.attr(this.$element, this.options.namespace, this.domOptions);\n if (this.parent && this.parent.actualizeOptions)\n this.parent.actualizeOptions();\n return this;\n },\n\n _resetOptions: function (initOptions) {\n this.domOptions = ParsleyUtils.objectCreate(this.parent.options);\n this.options = ParsleyUtils.objectCreate(this.domOptions);\n // Shallow copy of ownProperties of initOptions:\n for (var i in initOptions) {\n if (initOptions.hasOwnProperty(i))\n this.options[i] = initOptions[i];\n }\n this.actualizeOptions();\n },\n\n _listeners: null,\n\n // Register a callback for the given event name\n // Callback is called with context as the first argument and the `this`\n // The context is the current parsley instance, or window.Parsley if global\n // A return value of `false` will interrupt the calls\n on: function (name, fn) {\n this._listeners = this._listeners || {};\n var queue = this._listeners[name] = this._listeners[name] || [];\n queue.push(fn);\n\n return this;\n },\n\n // Deprecated. Use `on` instead\n subscribe: function(name, fn) {\n $.listenTo(this, name.toLowerCase(), fn);\n },\n\n // Unregister a callback (or all if none is given) for the given event name\n off: function (name, fn) {\n var queue = this._listeners && this._listeners[name];\n if (queue) {\n if (!fn) {\n delete this._listeners[name];\n } else {\n for (var i = queue.length; i--; )\n if (queue[i] === fn)\n queue.splice(i, 1);\n }\n }\n return this;\n },\n\n // Deprecated. Use `off`\n unsubscribe: function(name, fn) {\n $.unsubscribeTo(this, name.toLowerCase());\n },\n\n // Trigger an event of the given name\n // A return value of `false` interrupts the callback chain\n // Returns false if execution was interrupted\n trigger: function (name, target, extraArg) {\n target = target || this;\n var queue = this._listeners && this._listeners[name];\n var result;\n var parentResult;\n if (queue) {\n for (var i = queue.length; i--; ) {\n result = queue[i].call(target, target, extraArg);\n if (result === false) return result;\n }\n }\n if (this.parent) {\n return this.parent.trigger(name, target, extraArg);\n }\n return true;\n },\n\n // Reset UI\n reset: function () {\n // Field case: just emit a reset event for UI\n if ('ParsleyForm' !== this.__class__) {\n this._resetUI();\n return this._trigger('reset');\n }\n\n // Form case: emit a reset event for each field\n for (var i = 0; i < this.fields.length; i++)\n this.fields[i].reset();\n\n this._trigger('reset');\n },\n\n // Destroy Parsley instance (+ UI)\n destroy: function () {\n // Field case: emit destroy event to clean UI and then destroy stored instance\n this._destroyUI();\n if ('ParsleyForm' !== this.__class__) {\n this.$element.removeData('Parsley');\n this.$element.removeData('ParsleyFieldMultiple');\n this._trigger('destroy');\n\n return;\n }\n\n // Form case: destroy all its fields and then destroy stored instance\n for (var i = 0; i < this.fields.length; i++)\n this.fields[i].destroy();\n\n this.$element.removeData('Parsley');\n this._trigger('destroy');\n },\n\n asyncIsValid: function (group, force) {\n ParsleyUtils.warnOnce(\"asyncIsValid is deprecated; please use whenValid instead\");\n return this.whenValid({group, force});\n },\n\n _findRelated: function () {\n return this.options.multiple ?\n this.parent.$element.find(`[${this.options.namespace}multiple=\"${this.options.multiple}\"]`)\n : this.$element;\n }\n};\n\nexport default ParsleyAbstract;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\n\nvar requirementConverters = {\n string: function(string) {\n return string;\n },\n integer: function(string) {\n if (isNaN(string))\n throw 'Requirement is not an integer: \"' + string + '\"';\n return parseInt(string, 10);\n },\n number: function(string) {\n if (isNaN(string))\n throw 'Requirement is not a number: \"' + string + '\"';\n return parseFloat(string);\n },\n reference: function(string) { // Unused for now\n var result = $(string);\n if (result.length === 0)\n throw 'No such reference: \"' + string + '\"';\n return result;\n },\n boolean: function(string) {\n return string !== 'false';\n },\n object: function(string) {\n return ParsleyUtils.deserializeValue(string);\n },\n regexp: function(regexp) {\n var flags = '';\n\n // Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern\n if (/^\\/.*\\/(?:[gimy]*)$/.test(regexp)) {\n // Replace the regexp literal string with the first match group: ([gimy]*)\n // If no flag is present, this will be a blank string\n flags = regexp.replace(/.*\\/([gimy]*)$/, '$1');\n // Again, replace the regexp literal string with the first match group:\n // everything excluding the opening and closing slashes and the flags\n regexp = regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');\n } else {\n // Anchor regexp:\n regexp = '^' + regexp + '$';\n }\n return new RegExp(regexp, flags);\n }\n};\n\nvar convertArrayRequirement = function(string, length) {\n var m = string.match(/^\\s*\\[(.*)\\]\\s*$/);\n if (!m)\n throw 'Requirement is not an array: \"' + string + '\"';\n var values = m[1].split(',').map(ParsleyUtils.trimString);\n if (values.length !== length)\n throw 'Requirement has ' + values.length + ' values when ' + length + ' are needed';\n return values;\n};\n\nvar convertRequirement = function(requirementType, string) {\n var converter = requirementConverters[requirementType || 'string'];\n if (!converter)\n throw 'Unknown requirement specification: \"' + requirementType + '\"';\n return converter(string);\n};\n\nvar convertExtraOptionRequirement = function(requirementSpec, string, extraOptionReader) {\n var main = null;\n var extra = {};\n for (var key in requirementSpec) {\n if (key) {\n var value = extraOptionReader(key);\n if ('string' === typeof value)\n value = convertRequirement(requirementSpec[key], value);\n extra[key] = value;\n } else {\n main = convertRequirement(requirementSpec[key], string);\n }\n }\n return [main, extra];\n};\n\n// A Validator needs to implement the methods `validate` and `parseRequirements`\n\nvar ParsleyValidator = function(spec) {\n $.extend(true, this, spec);\n};\n\nParsleyValidator.prototype = {\n // Returns `true` iff the given `value` is valid according the given requirements.\n validate: function(value, requirementFirstArg) {\n if (this.fn) { // Legacy style validator\n\n if (arguments.length > 3) // If more args then value, requirement, instance...\n requirementFirstArg = [].slice.call(arguments, 1, -1); // Skip first arg (value) and last (instance), combining the rest\n return this.fn.call(this, value, requirementFirstArg);\n }\n\n if ($.isArray(value)) {\n if (!this.validateMultiple)\n throw 'Validator `' + this.name + '` does not handle multiple values';\n return this.validateMultiple(...arguments);\n } else {\n if (this.validateNumber) {\n if (isNaN(value))\n return false;\n arguments[0] = parseFloat(arguments[0]);\n return this.validateNumber(...arguments);\n }\n if (this.validateString) {\n return this.validateString(...arguments);\n }\n throw 'Validator `' + this.name + '` only handles multiple values';\n }\n },\n\n // Parses `requirements` into an array of arguments,\n // according to `this.requirementType`\n parseRequirements: function(requirements, extraOptionReader) {\n if ('string' !== typeof requirements) {\n // Assume requirement already parsed\n // but make sure we return an array\n return $.isArray(requirements) ? requirements : [requirements];\n }\n var type = this.requirementType;\n if ($.isArray(type)) {\n var values = convertArrayRequirement(requirements, type.length);\n for (var i = 0; i < values.length; i++)\n values[i] = convertRequirement(type[i], values[i]);\n return values;\n } else if ($.isPlainObject(type)) {\n return convertExtraOptionRequirement(type, requirements, extraOptionReader);\n } else {\n return [convertRequirement(type, requirements)];\n }\n },\n // Defaults:\n requirementType: 'string',\n\n priority: 2\n\n};\n\nexport default ParsleyValidator;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\nimport ParsleyDefaults from './defaults';\nimport ParsleyValidator from './validator';\n\nvar ParsleyValidatorRegistry = function (validators, catalog) {\n this.__class__ = 'ParsleyValidatorRegistry';\n\n // Default Parsley locale is en\n this.locale = 'en';\n\n this.init(validators || {}, catalog || {});\n};\n\nvar typeRegexes = {\n email: /^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))$/i,\n\n // Follow https://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers\n number: /^-?(\\d*\\.)?\\d+(e[-+]?\\d+)?$/i,\n\n integer: /^-?\\d+$/,\n\n digits: /^\\d+$/,\n\n alphanum: /^\\w+$/i,\n\n url: new RegExp(\n \"^\" +\n // protocol identifier\n \"(?:(?:https?|ftp)://)?\" + // ** mod: make scheme optional\n // user:pass authentication\n \"(?:\\\\S+(?::\\\\S*)?@)?\" +\n \"(?:\" +\n // IP address exclusion\n // private & local networks\n // \"(?!(?:10|127)(?:\\\\.\\\\d{1,3}){3})\" + // ** mod: allow local networks\n // \"(?!(?:169\\\\.254|192\\\\.168)(?:\\\\.\\\\d{1,3}){2})\" + // ** mod: allow local networks\n // \"(?!172\\\\.(?:1[6-9]|2\\\\d|3[0-1])(?:\\\\.\\\\d{1,3}){2})\" + // ** mod: allow local networks\n // IP address dotted notation octets\n // excludes loopback network 0.0.0.0\n // excludes reserved space >= 224.0.0.0\n // excludes network & broacast addresses\n // (first & last IP address of each class)\n \"(?:[1-9]\\\\d?|1\\\\d\\\\d|2[01]\\\\d|22[0-3])\" +\n \"(?:\\\\.(?:1?\\\\d{1,2}|2[0-4]\\\\d|25[0-5])){2}\" +\n \"(?:\\\\.(?:[1-9]\\\\d?|1\\\\d\\\\d|2[0-4]\\\\d|25[0-4]))\" +\n \"|\" +\n // host name\n \"(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)\" +\n // domain name\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*\" +\n // TLD identifier\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))\" +\n \")\" +\n // port number\n \"(?::\\\\d{2,5})?\" +\n // resource path\n \"(?:/\\\\S*)?\" +\n \"$\", 'i'\n )\n};\ntypeRegexes.range = typeRegexes.number;\n\n// See http://stackoverflow.com/a/10454560/8279\nvar decimalPlaces = num => {\n var match = ('' + num).match(/(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/);\n if (!match) { return 0; }\n return Math.max(\n 0,\n // Number of digits right of decimal point.\n (match[1] ? match[1].length : 0) -\n // Adjust for scientific notation.\n (match[2] ? +match[2] : 0));\n};\n\nParsleyValidatorRegistry.prototype = {\n init: function (validators, catalog) {\n this.catalog = catalog;\n // Copy prototype's validators:\n this.validators = $.extend({}, this.validators);\n\n for (var name in validators)\n this.addValidator(name, validators[name].fn, validators[name].priority);\n\n window.Parsley.trigger('parsley:validator:init');\n },\n\n // Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n\n setLocale: function (locale) {\n if ('undefined' === typeof this.catalog[locale])\n throw new Error(locale + ' is not available in the catalog');\n\n this.locale = locale;\n\n return this;\n },\n\n // Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`\n addCatalog: function (locale, messages, set) {\n if ('object' === typeof messages)\n this.catalog[locale] = messages;\n\n if (true === set)\n return this.setLocale(locale);\n\n return this;\n },\n\n // Add a specific message for a given constraint in a given locale\n addMessage: function (locale, name, message) {\n if ('undefined' === typeof this.catalog[locale])\n this.catalog[locale] = {};\n\n this.catalog[locale][name] = message;\n\n return this;\n },\n\n // Add messages for a given locale\n addMessages: function (locale, nameMessageObject) {\n for (var name in nameMessageObject)\n this.addMessage(locale, name, nameMessageObject[name]);\n\n return this;\n },\n\n // Add a new validator\n //\n // addValidator('custom', {\n // requirementType: ['integer', 'integer'],\n // validateString: function(value, from, to) {},\n // priority: 22,\n // messages: {\n // en: \"Hey, that's no good\",\n // fr: \"Aye aye, pas bon du tout\",\n // }\n // })\n //\n // Old API was addValidator(name, function, priority)\n //\n addValidator: function (name, arg1, arg2) {\n if (this.validators[name])\n ParsleyUtils.warn('Validator \"' + name + '\" is already defined.');\n else if (ParsleyDefaults.hasOwnProperty(name)) {\n ParsleyUtils.warn('\"' + name + '\" is a restricted keyword and is not a valid validator name.');\n return;\n }\n return this._setValidator(...arguments);\n },\n\n updateValidator: function (name, arg1, arg2) {\n if (!this.validators[name]) {\n ParsleyUtils.warn('Validator \"' + name + '\" is not already defined.');\n return this.addValidator(...arguments);\n }\n return this._setValidator(this, arguments);\n },\n\n removeValidator: function (name) {\n if (!this.validators[name])\n ParsleyUtils.warn('Validator \"' + name + '\" is not defined.');\n\n delete this.validators[name];\n\n return this;\n },\n\n _setValidator: function (name, validator, priority) {\n if ('object' !== typeof validator) {\n // Old style validator, with `fn` and `priority`\n validator = {\n fn: validator,\n priority: priority\n };\n }\n if (!validator.validate) {\n validator = new ParsleyValidator(validator);\n }\n this.validators[name] = validator;\n\n for (var locale in validator.messages || {})\n this.addMessage(locale, name, validator.messages[locale]);\n\n return this;\n },\n\n getErrorMessage: function (constraint) {\n var message;\n\n // Type constraints are a bit different, we have to match their requirements too to find right error message\n if ('type' === constraint.name) {\n var typeMessages = this.catalog[this.locale][constraint.name] || {};\n message = typeMessages[constraint.requirements];\n } else\n message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);\n\n return message || this.catalog[this.locale].defaultMessage || this.catalog.en.defaultMessage;\n },\n\n // Kind of light `sprintf()` implementation\n formatMessage: function (string, parameters) {\n if ('object' === typeof parameters) {\n for (var i in parameters)\n string = this.formatMessage(string, parameters[i]);\n\n return string;\n }\n\n return 'string' === typeof string ? string.replace(/%s/i, parameters) : '';\n },\n\n // Here is the Parsley default validators list.\n // A validator is an object with the following key values:\n // - priority: an integer\n // - requirement: 'string' (default), 'integer', 'number', 'regexp' or an Array of these\n // - validateString, validateMultiple, validateNumber: functions returning `true`, `false` or a promise\n // Alternatively, a validator can be a function that returns such an object\n //\n validators: {\n notblank: {\n validateString: function(value) {\n return /\\S/.test(value);\n },\n priority: 2\n },\n required: {\n validateMultiple: function(values) {\n return values.length > 0;\n },\n validateString: function(value) {\n return /\\S/.test(value);\n },\n priority: 512\n },\n type: {\n validateString: function(value, type, {step = '1', base = 0} = {}) {\n var regex = typeRegexes[type];\n if (!regex) {\n throw new Error('validator type `' + type + '` is not supported');\n }\n if (!regex.test(value))\n return false;\n if ('number' === type) {\n if (!/^any$/i.test(step || '')) {\n var nb = Number(value);\n var decimals = Math.max(decimalPlaces(step), decimalPlaces(base));\n if (decimalPlaces(nb) > decimals) // Value can't have too many decimals\n return false;\n // Be careful of rounding errors by using integers.\n var toInt = f => { return Math.round(f * Math.pow(10, decimals)); };\n if ((toInt(nb) - toInt(base)) % toInt(step) != 0)\n return false;\n }\n }\n return true;\n },\n requirementType: {\n '': 'string',\n step: 'string',\n base: 'number'\n },\n priority: 256\n },\n pattern: {\n validateString: function(value, regexp) {\n return regexp.test(value);\n },\n requirementType: 'regexp',\n priority: 64\n },\n minlength: {\n validateString: function (value, requirement) {\n return value.length >= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n maxlength: {\n validateString: function (value, requirement) {\n return value.length <= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n length: {\n validateString: function (value, min, max) {\n return value.length >= min && value.length <= max;\n },\n requirementType: ['integer', 'integer'],\n priority: 30\n },\n mincheck: {\n validateMultiple: function (values, requirement) {\n return values.length >= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n maxcheck: {\n validateMultiple: function (values, requirement) {\n return values.length <= requirement;\n },\n requirementType: 'integer',\n priority: 30\n },\n check: {\n validateMultiple: function (values, min, max) {\n return values.length >= min && values.length <= max;\n },\n requirementType: ['integer', 'integer'],\n priority: 30\n },\n min: {\n validateNumber: function (value, requirement) {\n return value >= requirement;\n },\n requirementType: 'number',\n priority: 30\n },\n max: {\n validateNumber: function (value, requirement) {\n return value <= requirement;\n },\n requirementType: 'number',\n priority: 30\n },\n range: {\n validateNumber: function (value, min, max) {\n return value >= min && value <= max;\n },\n requirementType: ['number', 'number'],\n priority: 30\n },\n equalto: {\n validateString: function (value, refOrValue) {\n var $reference = $(refOrValue);\n if ($reference.length)\n return value === $reference.val();\n else\n return value === refOrValue;\n },\n priority: 256\n }\n }\n};\n\nexport default ParsleyValidatorRegistry;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\n\nvar ParsleyUI = {};\n\nvar diffResults = function (newResult, oldResult, deep) {\n var added = [];\n var kept = [];\n\n for (var i = 0; i < newResult.length; i++) {\n var found = false;\n\n for (var j = 0; j < oldResult.length; j++)\n if (newResult[i].assert.name === oldResult[j].assert.name) {\n found = true;\n break;\n }\n\n if (found)\n kept.push(newResult[i]);\n else\n added.push(newResult[i]);\n }\n\n return {\n kept: kept,\n added: added,\n removed: !deep ? diffResults(oldResult, newResult, true).added : []\n };\n};\n\nParsleyUI.Form = {\n\n _actualizeTriggers: function () {\n this.$element.on('submit.Parsley', evt => { this.onSubmitValidate(evt); });\n this.$element.on('click.Parsley', 'input[type=\"submit\"], button[type=\"submit\"]', evt => { this.onSubmitButton(evt); });\n\n // UI could be disabled\n if (false === this.options.uiEnabled)\n return;\n\n this.$element.attr('novalidate', '');\n },\n\n focus: function () {\n this._focusedField = null;\n\n if (true === this.validationResult || 'none' === this.options.focus)\n return null;\n\n for (var i = 0; i < this.fields.length; i++) {\n var field = this.fields[i];\n if (true !== field.validationResult && field.validationResult.length > 0 && 'undefined' === typeof field.options.noFocus) {\n this._focusedField = field.$element;\n if ('first' === this.options.focus)\n break;\n }\n }\n\n if (null === this._focusedField)\n return null;\n\n return this._focusedField.focus();\n },\n\n _destroyUI: function () {\n // Reset all event listeners\n this.$element.off('.Parsley');\n }\n\n};\n\nParsleyUI.Field = {\n\n _reflowUI: function () {\n this._buildUI();\n\n // If this field doesn't have an active UI don't bother doing something\n if (!this._ui)\n return;\n\n // Diff between two validation results\n var diff = diffResults(this.validationResult, this._ui.lastValidationResult);\n\n // Then store current validation result for next reflow\n this._ui.lastValidationResult = this.validationResult;\n\n // Handle valid / invalid / none field class\n this._manageStatusClass();\n\n // Add, remove, updated errors messages\n this._manageErrorsMessages(diff);\n\n // Triggers impl\n this._actualizeTriggers();\n\n // If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user\n if ((diff.kept.length || diff.added.length) && !this._failedOnce) {\n this._failedOnce = true;\n this._actualizeTriggers();\n }\n },\n\n // Returns an array of field's error message(s)\n getErrorsMessages: function () {\n // No error message, field is valid\n if (true === this.validationResult)\n return [];\n\n var messages = [];\n\n for (var i = 0; i < this.validationResult.length; i++)\n messages.push(this.validationResult[i].errorMessage ||\n this._getErrorMessage(this.validationResult[i].assert));\n\n return messages;\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n addError: function (name, {message, assert, updateClass = true} = {}) {\n this._buildUI();\n this._addError(name, {message, assert});\n\n if (updateClass)\n this._errorClass();\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n updateError: function (name, {message, assert, updateClass = true} = {}) {\n this._buildUI();\n this._updateError(name, {message, assert});\n\n if (updateClass)\n this._errorClass();\n },\n\n // It's a goal of Parsley that this method is no longer required [#1073]\n removeError: function (name, {updateClass = true} = {}) {\n this._buildUI();\n this._removeError(name);\n\n // edge case possible here: remove a standard Parsley error that is still failing in this.validationResult\n // but highly improbable cuz' manually removing a well Parsley handled error makes no sense.\n if (updateClass)\n this._manageStatusClass();\n },\n\n _manageStatusClass: function () {\n if (this.hasConstraints() && this.needsValidation() && true === this.validationResult)\n this._successClass();\n else if (this.validationResult.length > 0)\n this._errorClass();\n else\n this._resetClass();\n },\n\n _manageErrorsMessages: function (diff) {\n if ('undefined' !== typeof this.options.errorsMessagesDisabled)\n return;\n\n // Case where we have errorMessage option that configure an unique field error message, regardless failing validators\n if ('undefined' !== typeof this.options.errorMessage) {\n if ((diff.added.length || diff.kept.length)) {\n this._insertErrorWrapper();\n\n if (0 === this._ui.$errorsWrapper.find('.parsley-custom-error-message').length)\n this._ui.$errorsWrapper\n .append(\n $(this.options.errorTemplate)\n .addClass('parsley-custom-error-message')\n );\n\n return this._ui.$errorsWrapper\n .addClass('filled')\n .find('.parsley-custom-error-message')\n .html(this.options.errorMessage);\n }\n\n return this._ui.$errorsWrapper\n .removeClass('filled')\n .find('.parsley-custom-error-message')\n .remove();\n }\n\n // Show, hide, update failing constraints messages\n for (var i = 0; i < diff.removed.length; i++)\n this._removeError(diff.removed[i].assert.name);\n\n for (i = 0; i < diff.added.length; i++)\n this._addError(diff.added[i].assert.name, {message: diff.added[i].errorMessage, assert: diff.added[i].assert});\n\n for (i = 0; i < diff.kept.length; i++)\n this._updateError(diff.kept[i].assert.name, {message: diff.kept[i].errorMessage, assert: diff.kept[i].assert});\n },\n\n\n _addError: function (name, {message, assert}) {\n this._insertErrorWrapper();\n this._ui.$errorsWrapper\n .addClass('filled')\n .append(\n $(this.options.errorTemplate)\n .addClass('parsley-' + name)\n .html(message || this._getErrorMessage(assert))\n );\n },\n\n _updateError: function (name, {message, assert}) {\n this._ui.$errorsWrapper\n .addClass('filled')\n .find('.parsley-' + name)\n .html(message || this._getErrorMessage(assert));\n },\n\n _removeError: function (name) {\n this._ui.$errorsWrapper\n .removeClass('filled')\n .find('.parsley-' + name)\n .remove();\n },\n\n _getErrorMessage: function (constraint) {\n var customConstraintErrorMessage = constraint.name + 'Message';\n\n if ('undefined' !== typeof this.options[customConstraintErrorMessage])\n return window.Parsley.formatMessage(this.options[customConstraintErrorMessage], constraint.requirements);\n\n return window.Parsley.getErrorMessage(constraint);\n },\n\n _buildUI: function () {\n // UI could be already built or disabled\n if (this._ui || false === this.options.uiEnabled)\n return;\n\n var _ui = {};\n\n // Give field its Parsley id in DOM\n this.$element.attr(this.options.namespace + 'id', this.__id__);\n\n /** Generate important UI elements and store them in this **/\n // $errorClassHandler is the $element that woul have parsley-error and parsley-success classes\n _ui.$errorClassHandler = this._manageClassHandler();\n\n // $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer\n _ui.errorsWrapperId = 'parsley-id-' + (this.options.multiple ? 'multiple-' + this.options.multiple : this.__id__);\n _ui.$errorsWrapper = $(this.options.errorsWrapper).attr('id', _ui.errorsWrapperId);\n\n // ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly\n _ui.lastValidationResult = [];\n _ui.validationInformationVisible = false;\n\n // Store it in this for later\n this._ui = _ui;\n },\n\n // Determine which element will have `parsley-error` and `parsley-success` classes\n _manageClassHandler: function () {\n // An element selector could be passed through DOM with `data-parsley-class-handler=#foo`\n if ('string' === typeof this.options.classHandler && $(this.options.classHandler).length)\n return $(this.options.classHandler);\n\n // Class handled could also be determined by function given in Parsley options\n var $handler = this.options.classHandler.call(this, this);\n\n // If this function returned a valid existing DOM element, go for it\n if ('undefined' !== typeof $handler && $handler.length)\n return $handler;\n\n // Otherwise, if simple element (input, texatrea, select...) it will perfectly host the classes\n if (!this.options.multiple || this.$element.is('select'))\n return this.$element;\n\n // But if multiple element (radio, checkbox), that would be their parent\n return this.$element.parent();\n },\n\n _insertErrorWrapper: function () {\n var $errorsContainer;\n\n // Nothing to do if already inserted\n if (0 !== this._ui.$errorsWrapper.parent().length)\n return this._ui.$errorsWrapper.parent();\n\n if ('string' === typeof this.options.errorsContainer) {\n if ($(this.options.errorsContainer).length)\n return $(this.options.errorsContainer).append(this._ui.$errorsWrapper);\n else\n ParsleyUtils.warn('The errors container `' + this.options.errorsContainer + '` does not exist in DOM');\n } else if ('function' === typeof this.options.errorsContainer)\n $errorsContainer = this.options.errorsContainer.call(this, this);\n\n if ('undefined' !== typeof $errorsContainer && $errorsContainer.length)\n return $errorsContainer.append(this._ui.$errorsWrapper);\n\n var $from = this.$element;\n if (this.options.multiple)\n $from = $from.parent();\n return $from.after(this._ui.$errorsWrapper);\n },\n\n _actualizeTriggers: function () {\n var $toBind = this._findRelated();\n\n // Remove Parsley events already bound on this field\n $toBind.off('.Parsley');\n if (this._failedOnce)\n $toBind.on(ParsleyUtils.namespaceEvents(this.options.triggerAfterFailure, 'Parsley'), () => {\n this.validate();\n });\n else {\n $toBind.on(ParsleyUtils.namespaceEvents(this.options.trigger, 'Parsley'), event => {\n this._eventValidate(event);\n });\n }\n },\n\n _eventValidate: function (event) {\n // For keyup, keypress, keydown, input... events that could be a little bit obstrusive\n // do not validate if val length < min threshold on first validation. Once field have been validated once and info\n // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.\n if (/key|input/.test(event.type))\n if (!(this._ui && this._ui.validationInformationVisible) && this.getValue().length <= this.options.validationThreshold)\n return;\n\n this.validate();\n },\n\n _resetUI: function () {\n // Reset all event listeners\n this._failedOnce = false;\n this._actualizeTriggers();\n\n // Nothing to do if UI never initialized for this field\n if ('undefined' === typeof this._ui)\n return;\n\n // Reset all errors' li\n this._ui.$errorsWrapper\n .removeClass('filled')\n .children()\n .remove();\n\n // Reset validation class\n this._resetClass();\n\n // Reset validation flags and last validation result\n this._ui.lastValidationResult = [];\n this._ui.validationInformationVisible = false;\n },\n\n _destroyUI: function () {\n this._resetUI();\n\n if ('undefined' !== typeof this._ui)\n this._ui.$errorsWrapper.remove();\n\n delete this._ui;\n },\n\n _successClass: function () {\n this._ui.validationInformationVisible = true;\n this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass);\n },\n _errorClass: function () {\n this._ui.validationInformationVisible = true;\n this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass);\n },\n _resetClass: function () {\n this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass);\n }\n};\n\nexport default ParsleyUI;\n","import $ from 'jquery';\nimport ParsleyAbstract from './abstract';\nimport ParsleyUtils from './utils';\n\nvar ParsleyForm = function (element, domOptions, options) {\n this.__class__ = 'ParsleyForm';\n this.__id__ = ParsleyUtils.generateID();\n\n this.$element = $(element);\n this.domOptions = domOptions;\n this.options = options;\n this.parent = window.Parsley;\n\n this.fields = [];\n this.validationResult = null;\n};\n\nvar statusMapping = {pending: null, resolved: true, rejected: false};\n\nParsleyForm.prototype = {\n onSubmitValidate: function (event) {\n // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior\n if (true === event.parsley)\n return;\n\n // If we didn't come here through a submit button, use the first one in the form\n var $submitSource = this._$submitSource || this.$element.find('input[type=\"submit\"], button[type=\"submit\"]').first();\n this._$submitSource = null;\n this.$element.find('.parsley-synthetic-submit-button').prop('disabled', true);\n if ($submitSource.is('[formnovalidate]'))\n return;\n\n var promise = this.whenValidate({event});\n\n if ('resolved' === promise.state() && false !== this._trigger('submit')) {\n // All good, let event go through. We make this distinction because browsers\n // differ in their handling of `submit` being called from inside a submit event [#1047]\n } else {\n // Rejected or pending: cancel this submit\n event.stopImmediatePropagation();\n event.preventDefault();\n if ('pending' === promise.state())\n promise.done(() => { this._submit($submitSource); });\n }\n },\n\n onSubmitButton: function(event) {\n this._$submitSource = $(event.target);\n },\n // internal\n // _submit submits the form, this time without going through the validations.\n // Care must be taken to \"fake\" the actual submit button being clicked.\n _submit: function ($submitSource) {\n if (false === this._trigger('submit'))\n return;\n // Add submit button's data\n if ($submitSource) {\n var $synthetic = this.$element.find('.parsley-synthetic-submit-button').prop('disabled', false);\n if (0 === $synthetic.length)\n $synthetic = $('<input class=\"parsley-synthetic-submit-button\" type=\"hidden\">').appendTo(this.$element);\n $synthetic.attr({\n name: $submitSource.attr('name'),\n value: $submitSource.attr('value')\n });\n }\n\n this.$element.trigger($.extend($.Event('submit'), {parsley: true}));\n },\n\n // Performs validation on fields while triggering events.\n // @returns `true` if all validations succeeds, `false`\n // if a failure is immediately detected, or `null`\n // if dependant on a promise.\n // Consider using `whenValidate` instead.\n validate: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils.warnOnce('Calling validate on a parsley form without passing arguments as an object is deprecated.');\n var [group, force, event] = arguments;\n options = {group, force, event};\n }\n return statusMapping[ this.whenValidate(options).state() ];\n },\n\n whenValidate: function ({group, force, event} = {}) {\n this.submitEvent = event;\n if (event) {\n this.submitEvent = $.extend({}, event, {preventDefault: () => {\n ParsleyUtils.warnOnce(\"Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`\");\n this.validationResult = false;\n }});\n }\n this.validationResult = true;\n\n // fire validate event to eventually modify things before very validation\n this._trigger('validate');\n\n // Refresh form DOM options and form's fields that could have changed\n this._refreshFields();\n\n var promises = this._withoutReactualizingFormOptions(() => {\n return $.map(this.fields, field => {\n return field.whenValidate({force, group});\n });\n });\n\n var promiseBasedOnValidationResult = () => {\n var r = $.Deferred();\n if (false === this.validationResult)\n r.reject();\n return r.resolve().promise();\n };\n\n return $.when(...promises)\n .done( () => { this._trigger('success'); })\n .fail( () => {\n this.validationResult = false;\n this.focus();\n this._trigger('error');\n })\n .always(() => { this._trigger('validated'); })\n .pipe( promiseBasedOnValidationResult, promiseBasedOnValidationResult);\n },\n\n // Iterate over refreshed fields, and stop on first failure.\n // Returns `true` if all fields are valid, `false` if a failure is detected\n // or `null` if the result depends on an unresolved promise.\n // Prefer using `whenValid` instead.\n isValid: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils.warnOnce('Calling isValid on a parsley form without passing arguments as an object is deprecated.');\n var [group, force] = arguments;\n options = {group, force};\n }\n return statusMapping[ this.whenValid(options).state() ];\n },\n\n // Iterate over refreshed fields and validate them.\n // Returns a promise.\n // A validation that immediately fails will interrupt the validations.\n whenValid: function ({group, force} = {}) {\n this._refreshFields();\n\n var promises = this._withoutReactualizingFormOptions(() => {\n return $.map(this.fields, field => {\n return field.whenValid({group, force});\n });\n });\n return $.when(...promises);\n },\n\n _refreshFields: function () {\n return this.actualizeOptions()._bindFields();\n },\n\n _bindFields: function () {\n var oldFields = this.fields;\n\n this.fields = [];\n this.fieldsMappedById = {};\n\n this._withoutReactualizingFormOptions(() => {\n this.$element\n .find(this.options.inputs)\n .not(this.options.excluded)\n .each((_, element) => {\n var fieldInstance = new window.Parsley.Factory(element, {}, this);\n\n // Only add valid and not excluded `ParsleyField` and `ParsleyFieldMultiple` children\n if (('ParsleyField' === fieldInstance.__class__ || 'ParsleyFieldMultiple' === fieldInstance.__class__) && (true !== fieldInstance.options.excluded))\n if ('undefined' === typeof this.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__]) {\n this.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__] = fieldInstance;\n this.fields.push(fieldInstance);\n }\n });\n\n $(oldFields).not(this.fields).each((_, field) => {\n field._trigger('reset');\n });\n });\n return this;\n },\n\n // Internal only.\n // Looping on a form's fields to do validation or similar\n // will trigger reactualizing options on all of them, which\n // in turn will reactualize the form's options.\n // To avoid calling actualizeOptions so many times on the form\n // for nothing, _withoutReactualizingFormOptions temporarily disables\n // the method actualizeOptions on this form while `fn` is called.\n _withoutReactualizingFormOptions: function (fn) {\n var oldActualizeOptions = this.actualizeOptions;\n this.actualizeOptions = function () { return this; };\n var result = fn();\n this.actualizeOptions = oldActualizeOptions;\n return result;\n },\n\n // Internal only.\n // Shortcut to trigger an event\n // Returns true iff event is not interrupted and default not prevented.\n _trigger: function (eventName) {\n return this.trigger('form:' + eventName);\n }\n\n};\n\nexport default ParsleyForm;\n","import $ from 'jquery';\nimport ParsleyUtils from '../utils';\nimport ParsleyValidator from '../validator';\n\n\nvar ConstraintFactory = function (parsleyField, name, requirements, priority, isDomConstraint) {\n if (!/ParsleyField/.test(parsleyField.__class__))\n throw new Error('ParsleyField or ParsleyFieldMultiple instance expected');\n\n var validatorSpec = window.Parsley._validatorRegistry.validators[name];\n var validator = new ParsleyValidator(validatorSpec);\n\n $.extend(this, {\n validator: validator,\n name: name,\n requirements: requirements,\n priority: priority || parsleyField.options[name + 'Priority'] || validator.priority,\n isDomConstraint: true === isDomConstraint\n });\n this._parseRequirements(parsleyField.options);\n};\n\nvar capitalize = function(str) {\n var cap = str[0].toUpperCase();\n return cap + str.slice(1);\n};\n\nConstraintFactory.prototype = {\n validate: function(value, instance) {\n var args = this.requirementList.slice(0); // Make copy\n args.unshift(value);\n args.push(instance);\n return this.validator.validate.apply(this.validator, args);\n },\n\n _parseRequirements: function(options) {\n this.requirementList = this.validator.parseRequirements(this.requirements, key => {\n return options[this.name + capitalize(key)];\n });\n }\n};\n\nexport default ConstraintFactory;\n\n","import $ from 'jquery';\nimport ConstraintFactory from './factory/constraint';\nimport ParsleyUI from './ui';\nimport ParsleyUtils from './utils';\n\nvar ParsleyField = function (field, domOptions, options, parsleyFormInstance) {\n this.__class__ = 'ParsleyField';\n this.__id__ = ParsleyUtils.generateID();\n\n this.$element = $(field);\n\n // Set parent if we have one\n if ('undefined' !== typeof parsleyFormInstance) {\n this.parent = parsleyFormInstance;\n }\n\n this.options = options;\n this.domOptions = domOptions;\n\n // Initialize some properties\n this.constraints = [];\n this.constraintsByName = {};\n this.validationResult = [];\n\n // Bind constraints\n this._bindConstraints();\n};\n\nvar statusMapping = {pending: null, resolved: true, rejected: false};\n\nParsleyField.prototype = {\n // # Public API\n // Validate field and trigger some events for mainly `ParsleyUI`\n // @returns `true`, an array of the validators that failed, or\n // `null` if validation is not finished. Prefer using whenValidate\n validate: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils.warnOnce('Calling validate on a parsley field without passing arguments as an object is deprecated.');\n options = {options};\n }\n var promise = this.whenValidate(options);\n if (!promise) // If excluded with `group` option\n return true;\n switch (promise.state()) {\n case 'pending': return null;\n case 'resolved': return true;\n case 'rejected': return this.validationResult;\n }\n },\n\n // Validate field and trigger some events for mainly `ParsleyUI`\n // @returns a promise that succeeds only when all validations do\n // or `undefined` if field is not in the given `group`.\n whenValidate: function ({force, group} = {}) {\n // do not validate a field if not the same as given validation group\n this.refreshConstraints();\n if (group && !this._isInGroup(group))\n return;\n\n this.value = this.getValue();\n\n // Field Validate event. `this.value` could be altered for custom needs\n this._trigger('validate');\n\n return this.whenValid({force, value: this.value, _refreshed: true})\n .always(() => { this._reflowUI(); })\n .done(() => { this._trigger('success'); })\n .fail(() => { this._trigger('error'); })\n .always(() => { this._trigger('validated'); });\n },\n\n hasConstraints: function () {\n return 0 !== this.constraints.length;\n },\n\n // An empty optional field does not need validation\n needsValidation: function (value) {\n if ('undefined' === typeof value)\n value = this.getValue();\n\n // If a field is empty and not required, it is valid\n // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators\n if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty)\n return false;\n\n return true;\n },\n\n _isInGroup: function (group) {\n if ($.isArray(this.options.group))\n return -1 !== $.inArray(group, this.options.group);\n return this.options.group === group;\n },\n\n // Just validate field. Do not trigger any event.\n // Returns `true` iff all constraints pass, `false` if there are failures,\n // or `null` if the result can not be determined yet (depends on a promise)\n // See also `whenValid`.\n isValid: function (options) {\n if (arguments.length >= 1 && !$.isPlainObject(options)) {\n ParsleyUtils.warnOnce('Calling isValid on a parsley field without passing arguments as an object is deprecated.');\n var [force, value] = arguments;\n options = {force, value};\n }\n var promise = this.whenValid(options);\n if (!promise) // Excluded via `group`\n return true;\n return statusMapping[promise.state()];\n },\n\n // Just validate field. Do not trigger any event.\n // @returns a promise that succeeds only when all validations do\n // or `undefined` if the field is not in the given `group`.\n // The argument `force` will force validation of empty fields.\n // If a `value` is given, it will be validated instead of the value of the input.\n whenValid: function ({force = false, value, group, _refreshed} = {}) {\n // Recompute options and rebind constraints to have latest changes\n if (!_refreshed)\n this.refreshConstraints();\n // do not validate a field if not the same as given validation group\n if (group && !this._isInGroup(group))\n return;\n\n this.validationResult = true;\n\n // A field without constraint is valid\n if (!this.hasConstraints())\n return $.when();\n\n // Value could be passed as argument, needed to add more power to 'parsley:field:validate'\n if ('undefined' === typeof value || null === value)\n value = this.getValue();\n\n if (!this.needsValidation(value) && true !== force)\n return $.when();\n\n var groupedConstraints = this._getGroupedConstraints();\n var promises = [];\n $.each(groupedConstraints, (_, constraints) => {\n // Process one group of constraints at a time, we validate the constraints\n // and combine the promises together.\n var promise = $.when(\n ...$.map(constraints, constraint => this._validateConstraint(value, constraint))\n );\n promises.push(promise);\n if (promise.state() === 'rejected')\n return false; // Interrupt processing if a group has already failed\n });\n return $.when.apply($, promises);\n },\n\n // @returns a promise\n _validateConstraint: function(value, constraint) {\n var result = constraint.validate(value, this);\n // Map false to a failed promise\n if (false === result)\n result = $.Deferred().reject();\n // Make sure we return a promise and that we record failures\n return $.when(result).fail(errorMessage => {\n if (true === this.validationResult)\n this.validationResult = [];\n this.validationResult.push({\n assert: constraint,\n errorMessage: 'string' === typeof errorMessage && errorMessage\n });\n });\n },\n\n // @returns Parsley field computed value that could be overrided or configured in DOM\n getValue: function () {\n var value;\n\n // Value could be overriden in DOM or with explicit options\n if ('function' === typeof this.options.value)\n value = this.options.value(this);\n else if ('undefined' !== typeof this.options.value)\n value = this.options.value;\n else\n value = this.$element.val();\n\n // Handle wrong DOM or configurations\n if ('undefined' === typeof value || null === value)\n return '';\n\n return this._handleWhitespace(value);\n },\n\n // Actualize options that could have change since previous validation\n // Re-bind accordingly constraints (could be some new, removed or updated)\n refreshConstraints: function () {\n return this.actualizeOptions()._bindConstraints();\n },\n\n /**\n * Add a new constraint to a field\n *\n * @param {String} name\n * @param {Mixed} requirements optional\n * @param {Number} priority optional\n * @param {Boolean} isDomConstraint optional\n */\n addConstraint: function (name, requirements, priority, isDomConstraint) {\n\n if (window.Parsley._validatorRegistry.validators[name]) {\n var constraint = new ConstraintFactory(this, name, requirements, priority, isDomConstraint);\n\n // if constraint already exist, delete it and push new version\n if ('undefined' !== this.constraintsByName[constraint.name])\n this.removeConstraint(constraint.name);\n\n this.constraints.push(constraint);\n this.constraintsByName[constraint.name] = constraint;\n }\n\n return this;\n },\n\n // Remove a constraint\n removeConstraint: function (name) {\n for (var i = 0; i < this.constraints.length; i++)\n if (name === this.constraints[i].name) {\n this.constraints.splice(i, 1);\n break;\n }\n delete this.constraintsByName[name];\n return this;\n },\n\n // Update a constraint (Remove + re-add)\n updateConstraint: function (name, parameters, priority) {\n return this.removeConstraint(name)\n .addConstraint(name, parameters, priority);\n },\n\n // # Internals\n\n // Internal only.\n // Bind constraints from config + options + DOM\n _bindConstraints: function () {\n var constraints = [];\n var constraintsByName = {};\n\n // clean all existing DOM constraints to only keep javascript user constraints\n for (var i = 0; i < this.constraints.length; i++)\n if (false === this.constraints[i].isDomConstraint) {\n constraints.push(this.constraints[i]);\n constraintsByName[this.constraints[i].name] = this.constraints[i];\n }\n\n this.constraints = constraints;\n this.constraintsByName = constraintsByName;\n\n // then re-add Parsley DOM-API constraints\n for (var name in this.options)\n this.addConstraint(name, this.options[name], undefined, true);\n\n // finally, bind special HTML5 constraints\n return this._bindHtml5Constraints();\n },\n\n // Internal only.\n // Bind specific HTML5 constraints to be HTML5 compliant\n _bindHtml5Constraints: function () {\n // html5 required\n if (this.$element.hasClass('required') || this.$element.attr('required'))\n this.addConstraint('required', true, undefined, true);\n\n // html5 pattern\n if ('string' === typeof this.$element.attr('pattern'))\n this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);\n\n // range\n if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max'))\n this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);\n\n // HTML5 min\n else if ('undefined' !== typeof this.$element.attr('min'))\n this.addConstraint('min', this.$element.attr('min'), undefined, true);\n\n // HTML5 max\n else if ('undefined' !== typeof this.$element.attr('max'))\n this.addConstraint('max', this.$element.attr('max'), undefined, true);\n\n\n // length\n if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength'))\n this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);\n\n // HTML5 minlength\n else if ('undefined' !== typeof this.$element.attr('minlength'))\n this.addConstraint('minlength', this.$element.attr('minlength'), undefined, true);\n\n // HTML5 maxlength\n else if ('undefined' !== typeof this.$element.attr('maxlength'))\n this.addConstraint('maxlength', this.$element.attr('maxlength'), undefined, true);\n\n\n // html5 types\n var type = this.$element.attr('type');\n\n if ('undefined' === typeof type)\n return this;\n\n // Small special case here for HTML5 number: integer validator if step attribute is undefined or an integer value, number otherwise\n if ('number' === type) {\n return this.addConstraint('type', ['number', {\n step: this.$element.attr('step'),\n base: this.$element.attr('min') || this.$element.attr('value')\n }], undefined, true);\n // Regular other HTML5 supported types\n } else if (/^(email|url|range)$/i.test(type)) {\n return this.addConstraint('type', type, undefined, true);\n }\n return this;\n },\n\n // Internal only.\n // Field is required if have required constraint without `false` value\n _isRequired: function () {\n if ('undefined' === typeof this.constraintsByName.required)\n return false;\n\n return false !== this.constraintsByName.required.requirements;\n },\n\n // Internal only.\n // Shortcut to trigger an event\n _trigger: function (eventName) {\n return this.trigger('field:' + eventName);\n },\n\n // Internal only\n // Handles whitespace in a value\n // Use `data-parsley-whitespace=\"squish\"` to auto squish input value\n // Use `data-parsley-whitespace=\"trim\"` to auto trim input value\n _handleWhitespace: function (value) {\n if (true === this.options.trimValue)\n ParsleyUtils.warnOnce('data-parsley-trim-value=\"true\" is deprecated, please use data-parsley-whitespace=\"trim\"');\n\n if ('squish' === this.options.whitespace)\n value = value.replace(/\\s{2,}/g, ' ');\n\n if (('trim' === this.options.whitespace) || ('squish' === this.options.whitespace) || (true === this.options.trimValue))\n value = ParsleyUtils.trimString(value);\n\n return value;\n },\n\n // Internal only.\n // Returns the constraints, grouped by descending priority.\n // The result is thus an array of arrays of constraints.\n _getGroupedConstraints: function () {\n if (false === this.options.priorityEnabled)\n return [this.constraints];\n\n var groupedConstraints = [];\n var index = {};\n\n // Create array unique of priorities\n for (var i = 0; i < this.constraints.length; i++) {\n var p = this.constraints[i].priority;\n if (!index[p])\n groupedConstraints.push(index[p] = []);\n index[p].push(this.constraints[i]);\n }\n // Sort them by priority DESC\n groupedConstraints.sort(function (a, b) { return b[0].priority - a[0].priority; });\n\n return groupedConstraints;\n }\n\n};\n\nexport default ParsleyField;\n","import $ from 'jquery';\n\nvar ParsleyMultiple = function () {\n this.__class__ = 'ParsleyFieldMultiple';\n};\n\nParsleyMultiple.prototype = {\n // Add new `$element` sibling for multiple field\n addElement: function ($element) {\n this.$elements.push($element);\n\n return this;\n },\n\n // See `ParsleyField.refreshConstraints()`\n refreshConstraints: function () {\n var fieldConstraints;\n\n this.constraints = [];\n\n // Select multiple special treatment\n if (this.$element.is('select')) {\n this.actualizeOptions()._bindConstraints();\n\n return this;\n }\n\n // Gather all constraints for each input in the multiple group\n for (var i = 0; i < this.$elements.length; i++) {\n\n // Check if element have not been dynamically removed since last binding\n if (!$('html').has(this.$elements[i]).length) {\n this.$elements.splice(i, 1);\n continue;\n }\n\n fieldConstraints = this.$elements[i].data('ParsleyFieldMultiple').refreshConstraints().constraints;\n\n for (var j = 0; j < fieldConstraints.length; j++)\n this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint);\n }\n\n return this;\n },\n\n // See `ParsleyField.getValue()`\n getValue: function () {\n // Value could be overriden in DOM\n if ('function' === typeof this.options.value)\n value = this.options.value(this);\n else if ('undefined' !== typeof this.options.value)\n return this.options.value;\n\n // Radio input case\n if (this.$element.is('input[type=radio]'))\n return this._findRelated().filter(':checked').val() || '';\n\n // checkbox input case\n if (this.$element.is('input[type=checkbox]')) {\n var values = [];\n\n this._findRelated().filter(':checked').each(function () {\n values.push($(this).val());\n });\n\n return values;\n }\n\n // Select multiple case\n if (this.$element.is('select') && null === this.$element.val())\n return [];\n\n // Default case that should never happen\n return this.$element.val();\n },\n\n _init: function () {\n this.$elements = [this.$element];\n\n return this;\n }\n};\n\nexport default ParsleyMultiple;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\nimport ParsleyAbstract from './abstract';\nimport ParsleyForm from './form';\nimport ParsleyField from './field';\nimport ParsleyMultiple from './multiple';\n\nvar ParsleyFactory = function (element, options, parsleyFormInstance) {\n this.$element = $(element);\n\n // If the element has already been bound, returns its saved Parsley instance\n var savedparsleyFormInstance = this.$element.data('Parsley');\n if (savedparsleyFormInstance) {\n\n // If the saved instance has been bound without a ParsleyForm parent and there is one given in this call, add it\n if ('undefined' !== typeof parsleyFormInstance && savedparsleyFormInstance.parent === window.Parsley) {\n savedparsleyFormInstance.parent = parsleyFormInstance;\n savedparsleyFormInstance._resetOptions(savedparsleyFormInstance.options);\n }\n\n return savedparsleyFormInstance;\n }\n\n // Parsley must be instantiated with a DOM element or jQuery $element\n if (!this.$element.length)\n throw new Error('You must bind Parsley on an existing element.');\n\n if ('undefined' !== typeof parsleyFormInstance && 'ParsleyForm' !== parsleyFormInstance.__class__)\n throw new Error('Parent instance must be a ParsleyForm instance');\n\n this.parent = parsleyFormInstance || window.Parsley;\n return this.init(options);\n};\n\nParsleyFactory.prototype = {\n init: function (options) {\n this.__class__ = 'Parsley';\n this.__version__ = '@@version';\n this.__id__ = ParsleyUtils.generateID();\n\n // Pre-compute options\n this._resetOptions(options);\n\n // A ParsleyForm instance is obviously a `<form>` element but also every node that is not an input and has the `data-parsley-validate` attribute\n if (this.$element.is('form') || (ParsleyUtils.checkAttr(this.$element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)))\n return this.bind('parsleyForm');\n\n // Every other element is bound as a `ParsleyField` or `ParsleyFieldMultiple`\n return this.isMultiple() ? this.handleMultiple() : this.bind('parsleyField');\n },\n\n isMultiple: function () {\n return (this.$element.is('input[type=radio], input[type=checkbox]')) || (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple'));\n },\n\n // Multiples fields are a real nightmare :(\n // Maybe some refactoring would be appreciated here...\n handleMultiple: function () {\n var name;\n var multiple;\n var parsleyMultipleInstance;\n\n // Handle multiple name\n if (this.options.multiple)\n ; // We already have our 'multiple' identifier\n else if ('undefined' !== typeof this.$element.attr('name') && this.$element.attr('name').length)\n this.options.multiple = name = this.$element.attr('name');\n else if ('undefined' !== typeof this.$element.attr('id') && this.$element.attr('id').length)\n this.options.multiple = this.$element.attr('id');\n\n // Special select multiple input\n if (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple')) {\n this.options.multiple = this.options.multiple || this.__id__;\n return this.bind('parsleyFieldMultiple');\n\n // Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it\n } else if (!this.options.multiple) {\n ParsleyUtils.warn('To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.', this.$element);\n return this;\n }\n\n // Remove special chars\n this.options.multiple = this.options.multiple.replace(/(:|\\.|\\[|\\]|\\{|\\}|\\$)/g, '');\n\n // Add proper `data-parsley-multiple` to siblings if we have a valid multiple name\n if ('undefined' !== typeof name) {\n $('input[name=\"' + name + '\"]').each((i, input) => {\n if ($(input).is('input[type=radio], input[type=checkbox]'))\n $(input).attr(this.options.namespace + 'multiple', this.options.multiple);\n });\n }\n\n // Check here if we don't already have a related multiple instance saved\n var $previouslyRelated = this._findRelated();\n for (var i = 0; i < $previouslyRelated.length; i++) {\n parsleyMultipleInstance = $($previouslyRelated.get(i)).data('Parsley');\n if ('undefined' !== typeof parsleyMultipleInstance) {\n\n if (!this.$element.data('ParsleyFieldMultiple')) {\n parsleyMultipleInstance.addElement(this.$element);\n }\n\n break;\n }\n }\n\n // Create a secret ParsleyField instance for every multiple field. It will be stored in `data('ParsleyFieldMultiple')`\n // And will be useful later to access classic `ParsleyField` stuff while being in a `ParsleyFieldMultiple` instance\n this.bind('parsleyField', true);\n\n return parsleyMultipleInstance || this.bind('parsleyFieldMultiple');\n },\n\n // Return proper `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`\n bind: function (type, doNotStore) {\n var parsleyInstance;\n\n switch (type) {\n case 'parsleyForm':\n parsleyInstance = $.extend(\n new ParsleyForm(this.$element, this.domOptions, this.options),\n window.ParsleyExtend\n )._bindFields();\n break;\n case 'parsleyField':\n parsleyInstance = $.extend(\n new ParsleyField(this.$element, this.domOptions, this.options, this.parent),\n window.ParsleyExtend\n );\n break;\n case 'parsleyFieldMultiple':\n parsleyInstance = $.extend(\n new ParsleyField(this.$element, this.domOptions, this.options, this.parent),\n new ParsleyMultiple(),\n window.ParsleyExtend\n )._init();\n break;\n default:\n throw new Error(type + 'is not a supported Parsley type');\n }\n\n if (this.options.multiple)\n ParsleyUtils.setAttr(this.$element, this.options.namespace, 'multiple', this.options.multiple);\n\n if ('undefined' !== typeof doNotStore) {\n this.$element.data('ParsleyFieldMultiple', parsleyInstance);\n\n return parsleyInstance;\n }\n\n // Store the freshly bound instance in a DOM element for later access using jQuery `data()`\n this.$element.data('Parsley', parsleyInstance);\n\n // Tell the world we have a new ParsleyForm or ParsleyField instance!\n parsleyInstance._actualizeTriggers();\n parsleyInstance._trigger('init');\n\n return parsleyInstance;\n }\n};\n\nexport default ParsleyFactory;\n","import $ from 'jquery';\nimport ParsleyUtils from './utils';\nimport ParsleyDefaults from './defaults';\nimport ParsleyAbstract from './abstract';\nimport ParsleyValidatorRegistry from './validator_registry';\nimport ParsleyUI from './ui';\nimport ParsleyForm from './form';\nimport ParsleyField from './field';\nimport ParsleyMultiple from './multiple';\nimport ParsleyFactory from './factory';\n\nvar vernums = $.fn.jquery.split('.');\nif (parseInt(vernums[0]) <= 1 && parseInt(vernums[1]) < 8) {\n throw \"The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.\";\n}\nif (!vernums.forEach) {\n ParsleyUtils.warn('Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim');\n}\n// Inherit `on`, `off` & `trigger` to Parsley:\nvar Parsley = $.extend(new ParsleyAbstract(), {\n $element: $(document),\n actualizeOptions: null,\n _resetOptions: null,\n Factory: ParsleyFactory,\n version: '@@version'\n });\n\n// Supplement ParsleyField and Form with ParsleyAbstract\n// This way, the constructors will have access to those methods\n$.extend(ParsleyField.prototype, ParsleyUI.Field, ParsleyAbstract.prototype);\n$.extend(ParsleyForm.prototype, ParsleyUI.Form, ParsleyAbstract.prototype);\n// Inherit actualizeOptions and _resetOptions:\n$.extend(ParsleyFactory.prototype, ParsleyAbstract.prototype);\n\n// ### jQuery API\n// `$('.elem').parsley(options)` or `$('.elem').psly(options)`\n$.fn.parsley = $.fn.psly = function (options) {\n if (this.length > 1) {\n var instances = [];\n\n this.each(function () {\n instances.push($(this).parsley(options));\n });\n\n return instances;\n }\n\n // Return undefined if applied to non existing DOM element\n if (!$(this).length) {\n ParsleyUtils.warn('You must bind Parsley on an existing element.');\n\n return;\n }\n\n return new ParsleyFactory(this, options);\n};\n\n// ### ParsleyField and ParsleyForm extension\n// Ensure the extension is now defined if it wasn't previously\nif ('undefined' === typeof window.ParsleyExtend)\n window.ParsleyExtend = {};\n\n// ### Parsley config\n// Inherit from ParsleyDefault, and copy over any existing values\nParsley.options = $.extend(ParsleyUtils.objectCreate(ParsleyDefaults), window.ParsleyConfig);\nwindow.ParsleyConfig = Parsley.options; // Old way of accessing global options\n\n// ### Globals\nwindow.Parsley = window.psly = Parsley;\nwindow.ParsleyUtils = ParsleyUtils;\n\n// ### Define methods that forward to the registry, and deprecate all access except through window.Parsley\nvar registry = window.Parsley._validatorRegistry = new ParsleyValidatorRegistry(window.ParsleyConfig.validators, window.ParsleyConfig.i18n);\nwindow.ParsleyValidator = {};\n$.each('setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator'.split(' '), function (i, method) {\n window.Parsley[method] = $.proxy(registry, method);\n window.ParsleyValidator[method] = function () {\n ParsleyUtils.warnOnce(`Accessing the method '${method}' through ParsleyValidator is deprecated. Simply call 'window.Parsley.${method}(...)'`);\n return window.Parsley[method](...arguments);\n };\n});\n\n// ### ParsleyUI\n// Deprecated global object\nwindow.Parsley.UI = ParsleyUI;\nwindow.ParsleyUI = {\n removeError: function (instance, name, doNotUpdateClass) {\n var updateClass = true !== doNotUpdateClass;\n ParsleyUtils.warnOnce(`Accessing ParsleyUI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method.`);\n return instance.removeError(name, {updateClass});\n },\n getErrorsMessages: function (instance) {\n ParsleyUtils.warnOnce(`Accessing ParsleyUI is deprecated. Call 'getErrorsMessages' on the instance directly.`);\n return instance.getErrorsMessages();\n }\n};\n$.each('addError updateError'.split(' '), function (i, method) {\n window.ParsleyUI[method] = function (instance, name, message, assert, doNotUpdateClass) {\n var updateClass = true !== doNotUpdateClass;\n ParsleyUtils.warnOnce(`Accessing ParsleyUI is deprecated. Call '${method}' on the instance directly. Please comment in issue 1073 as to your need to call this method.`);\n return instance[method](name, {message, assert, updateClass});\n };\n});\n\n// Alleviate glaring Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=1250521\n// See also https://github.com/guillaumepotier/Parsley.js/issues/1068\nif (/firefox/i.test(navigator.userAgent)) {\n $(document).on('change', 'select', evt => {\n $(evt.target).trigger('input');\n });\n}\n\n// ### PARSLEY auto-binding\n// Prevent it by setting `ParsleyConfig.autoBind` to `false`\nif (false !== window.ParsleyConfig.autoBind) {\n $(function () {\n // Works only on `data-parsley-validate`.\n if ($('[data-parsley-validate]').length)\n $('[data-parsley-validate]').parsley();\n });\n}\n\nexport default Parsley;\n","import $ from 'jquery';\n\nimport Parsley from './main';\n\n$.extend(true, Parsley, {\n asyncValidators: {\n 'default': {\n fn: function (xhr) {\n // By default, only status 2xx are deemed successful.\n // Note: we use status instead of state() because responses with status 200\n // but invalid messages (e.g. an empty body for content type set to JSON) will\n // result in state() === 'rejected'.\n return xhr.status >= 200 && xhr.status < 300;\n },\n url: false\n },\n reverse: {\n fn: function (xhr) {\n // If reverse option is set, a failing ajax request is considered successful\n return xhr.status < 200 || xhr.status >= 300;\n },\n url: false\n }\n },\n\n addAsyncValidator: function (name, fn, url, options) {\n Parsley.asyncValidators[name] = {\n fn: fn,\n url: url || false,\n options: options || {}\n };\n\n return this;\n }\n\n});\n\nParsley.addValidator('remote', {\n requirementType: {\n '': 'string',\n 'validator': 'string',\n 'reverse': 'boolean',\n 'options': 'object'\n },\n\n validateString: function (value, url, options, instance) {\n var data = {};\n var ajaxOptions;\n var csr;\n var validator = options.validator || (true === options.reverse ? 'reverse' : 'default');\n\n if ('undefined' === typeof Parsley.asyncValidators[validator])\n throw new Error('Calling an undefined async validator: `' + validator + '`');\n\n url = Parsley.asyncValidators[validator].url || url;\n\n // Fill current value\n if (url.indexOf('{value}') > -1) {\n url = url.replace('{value}', encodeURIComponent(value));\n } else {\n data[instance.$element.attr('name') || instance.$element.attr('id')] = value;\n }\n\n // Merge options passed in from the function with the ones in the attribute\n var remoteOptions = $.extend(true, options.options || {} , Parsley.asyncValidators[validator].options);\n\n // All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options`\n ajaxOptions = $.extend(true, {}, {\n url: url,\n data: data,\n type: 'GET'\n }, remoteOptions);\n\n // Generate store key based on ajax options\n instance.trigger('field:ajaxoptions', instance, ajaxOptions);\n\n csr = $.param(ajaxOptions);\n\n // Initialise querry cache\n if ('undefined' === typeof Parsley._remoteCache)\n Parsley._remoteCache = {};\n\n // Try to retrieve stored xhr\n var xhr = Parsley._remoteCache[csr] = Parsley._remoteCache[csr] || $.ajax(ajaxOptions);\n\n var handleXhr = function () {\n var result = Parsley.asyncValidators[validator].fn.call(instance, xhr, url, options);\n if (!result) // Map falsy results to rejected promise\n result = $.Deferred().reject();\n return $.when(result);\n };\n\n return xhr.then(handleXhr, handleXhr);\n },\n\n priority: -1\n});\n\nParsley.on('form:submit', function () {\n Parsley._remoteCache = {};\n});\n\nwindow.ParsleyExtend.addAsyncValidator = function () {\n ParsleyUtils.warnOnce('Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`');\n return Parsley.addAsyncValidator(...arguments);\n};\n","// This is included with the Parsley library itself,\n// thus there is no use in adding it to your project.\nimport Parsley from '../parsley/main';\n\nParsley.addMessages('en', {\n defaultMessage: \"This value seems to be invalid.\",\n type: {\n email: \"This value should be a valid email.\",\n url: \"This value should be a valid url.\",\n number: \"This value should be a valid number.\",\n integer: \"This value should be a valid integer.\",\n digits: \"This value should be digits.\",\n alphanum: \"This value should be alphanumeric.\"\n },\n notblank: \"This value should not be blank.\",\n required: \"This value is required.\",\n pattern: \"This value seems to be invalid.\",\n min: \"This value should be greater than or equal to %s.\",\n max: \"This value should be lower than or equal to %s.\",\n range: \"This value should be between %s and %s.\",\n minlength: \"This value is too short. It should have %s characters or more.\",\n maxlength: \"This value is too long. It should have %s characters or fewer.\",\n length: \"This value length is invalid. It should be between %s and %s characters long.\",\n mincheck: \"You must select at least %s choices.\",\n maxcheck: \"You must select %s choices or fewer.\",\n check: \"You must select between %s and %s choices.\",\n equalto: \"This value should be the same.\"\n});\n\nParsley.setLocale('en');\n","import $ from 'jquery';\nimport Parsley from './parsley/main';\nimport './parsley/pubsub';\nimport './parsley/remote';\nimport './i18n/en';\n\nexport default Parsley;\n"],"sourceRoot":"/source/"}
classes/class.archive.config.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @copyright 2016 Snap Creek LLC
4
+ */
5
+
6
+ // Exit if accessed directly
7
+ if (! defined('DUPLICATOR_VERSION')) exit;
8
+
9
+ class DUP_Archive_Config
10
+ {
11
+ //READ-ONLY: COMPARE VALUES
12
+ public $created;
13
+ public $version_dup;
14
+ public $version_wp;
15
+ public $version_db;
16
+ public $version_php;
17
+ public $version_os;
18
+ public $dbInfo;
19
+ //READ-ONLY: GENERAL
20
+ public $url_old;
21
+ public $opts_delete;
22
+ public $blogname;
23
+ public $wproot;
24
+ public $wplogin_url;
25
+ public $relative_content_dir;
26
+ public $exportOnlyDB;
27
+ public $installSiteOverwriteOn;
28
+
29
+ //PRE-FILLED: GENERAL
30
+ public $secure_on;
31
+ public $secure_pass;
32
+ public $skipscan;
33
+ public $dbhost;
34
+ public $dbname;
35
+ public $dbuser;
36
+ public $dbpass;
37
+
38
+ // MULTISITE
39
+ public $mu_mode;
40
+
41
+ public $wp_tableprefix;
42
+ }
classes/class.db.php CHANGED
@@ -8,14 +8,11 @@
8
  * @package Duplicator
9
  * @subpackage classes/utilities
10
  * @copyright (c) 2017, Snapcreek LLC
11
- * @since 1.1.32
12
  *
13
  */
14
 
15
  // Exit if accessed directly
16
- if (!defined('DUPLICATOR_VERSION')) {
17
- exit;
18
- }
19
 
20
  class DUP_DB extends wpdb
21
  {
@@ -78,44 +75,43 @@ class DUP_DB extends wpdb
78
  *
79
  * @return boolean|string
80
  */
81
- public static function getWindowsMySqlDumpRealPath()
82
- {
83
- try {
84
- if (function_exists('php_ini_loaded_file')) {
85
- $get_php_ini_path = php_ini_loaded_file();
86
- if (@file_exists($get_php_ini_path)) {
87
- $search = array(
88
- dirname(dirname($get_php_ini_path)).'/mysql/bin/mysqldump.exe',
89
- dirname(dirname(dirname($get_php_ini_path))).'/mysql/bin/mysqldump.exe',
90
- dirname(dirname($get_php_ini_path)).'/mysql/bin/mysqldump',
91
- dirname(dirname(dirname($get_php_ini_path))).'/mysql/bin/mysqldump',
92
- );
93
-
94
- foreach ($search as $mysqldump) {
95
- if (@file_exists($mysqldump)) {
96
- return str_replace("\\", "/", $mysqldump);
97
- }
 
98
  }
99
  }
100
  }
 
101
 
102
- unset($search);
103
- unset($get_php_ini_path);
104
 
105
- return false;
106
-
107
- } catch(Exception $ex) {
108
- return false;
109
- }
110
  }
111
 
112
- /**
113
  * Returns the mysqldump path if the server is enabled to execute it otherwise false
114
  *
115
  * @return boolean|string
116
  */
117
  public static function getMySqlDumpPath()
118
  {
 
119
  //Is shell_exec possible
120
  if (!DUP_Util::hasShellExec()) {
121
  return false;
@@ -124,20 +120,19 @@ class DUP_DB extends wpdb
124
  $custom_mysqldump_path = DUP_Settings::Get('package_mysqldump_path');
125
  $custom_mysqldump_path = (strlen($custom_mysqldump_path)) ? $custom_mysqldump_path : '';
126
 
127
- //COMMON WINDOWS PATHS
128
  if (DUP_Util::isWindows()) {
129
  $paths = array(
130
  $custom_mysqldump_path,
131
- self::getWindowsMySqlDumpRealPath(),
132
  'C:/xampp/mysql/bin/mysqldump.exe',
133
  'C:/Program Files/xampp/mysql/bin/mysqldump',
134
  'C:/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
135
  'C:/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
136
- 'C:/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump',
137
- 'C:/wamp64/bin/mysql/mysql5.7.21/bin',
138
  );
139
 
140
- //COMMON LINUX PATHS
141
  } else {
142
  $path1 = '';
143
  $path2 = '';
@@ -160,7 +155,7 @@ class DUP_DB extends wpdb
160
  '/usr/mysql/bin/mysqldump',
161
  '/usr/bin/mysqldump',
162
  '/opt/local/lib/mysql6/bin/mysqldump',
163
- '/opt/local/lib/mysql5/bin/mysqldump',
164
  );
165
  }
166
 
8
  * @package Duplicator
9
  * @subpackage classes/utilities
10
  * @copyright (c) 2017, Snapcreek LLC
 
11
  *
12
  */
13
 
14
  // Exit if accessed directly
15
+ if (! defined('DUPLICATOR_VERSION')) exit;
 
 
16
 
17
  class DUP_DB extends wpdb
18
  {
75
  *
76
  * @return boolean|string
77
  */
78
+ public static function getWindowsMySqlDumpRealPath() {
79
+ if(function_exists('php_ini_loaded_file'))
80
+ {
81
+ $get_php_ini_path = php_ini_loaded_file();
82
+ if(file_exists($get_php_ini_path))
83
+ {
84
+ $search = array(
85
+ dirname(dirname($get_php_ini_path)).'/mysql/bin/mysqldump.exe',
86
+ dirname(dirname(dirname($get_php_ini_path))).'/mysql/bin/mysqldump.exe',
87
+ dirname(dirname($get_php_ini_path)).'/mysql/bin/mysqldump',
88
+ dirname(dirname(dirname($get_php_ini_path))).'/mysql/bin/mysqldump',
89
+ );
90
+
91
+ foreach($search as $mysqldump)
92
+ {
93
+ if(file_exists($mysqldump))
94
+ {
95
+ return str_replace("\\","/",$mysqldump);
96
  }
97
  }
98
  }
99
+ }
100
 
101
+ unset($search);
102
+ unset($get_php_ini_path);
103
 
104
+ return false;
 
 
 
 
105
  }
106
 
107
+ /**
108
  * Returns the mysqldump path if the server is enabled to execute it otherwise false
109
  *
110
  * @return boolean|string
111
  */
112
  public static function getMySqlDumpPath()
113
  {
114
+
115
  //Is shell_exec possible
116
  if (!DUP_Util::hasShellExec()) {
117
  return false;
120
  $custom_mysqldump_path = DUP_Settings::Get('package_mysqldump_path');
121
  $custom_mysqldump_path = (strlen($custom_mysqldump_path)) ? $custom_mysqldump_path : '';
122
 
123
+ //Common Windows Paths
124
  if (DUP_Util::isWindows()) {
125
  $paths = array(
126
  $custom_mysqldump_path,
127
+ self::getWindowsMySqlDumpRealPath(),
128
  'C:/xampp/mysql/bin/mysqldump.exe',
129
  'C:/Program Files/xampp/mysql/bin/mysqldump',
130
  'C:/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
131
  'C:/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
132
+ 'C:/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump'
 
133
  );
134
 
135
+ //Common Linux Paths
136
  } else {
137
  $path1 = '';
138
  $path2 = '';
155
  '/usr/mysql/bin/mysqldump',
156
  '/usr/bin/mysqldump',
157
  '/opt/local/lib/mysql6/bin/mysqldump',
158
+ '/opt/local/lib/mysql5/bin/mysqldump'
159
  );
160
  }
161
 
classes/class.io.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @copyright 2018 Snap Creek LLC
4
+ * Class for all IO operations
5
+ */
6
+
7
+ // Exit if accessed directly
8
+ if (! defined('DUPLICATOR_VERSION')) exit;
9
+
10
+ class DUP_IO
11
+ {
12
+ /**
13
+ * Safely deletes a file
14
+ *
15
+ * @param string $file The full filepath to the file
16
+ *
17
+ * @return TRUE on success or if file does not exist. FALSE on failure
18
+ */
19
+ public static function deleteFile($file)
20
+ {
21
+ if (file_exists($file)) {
22
+ if (@unlink($file) === false) {
23
+ DUP_Log::Info("Could not delete file: {$file}");
24
+ return false;
25
+ }
26
+ }
27
+ return true;
28
+ }
29
+
30
+ /**
31
+ * Removes a directory recursively except for the root of a WP Site
32
+ *
33
+ * @param string $directory The full filepath to the directory to remove
34
+ *
35
+ * @return TRUE on success FALSE on failure
36
+ */
37
+ public static function deleteTree($directory)
38
+ {
39
+ $success = true;
40
+
41
+ if(!file_exists("{$directory}/wp-config.php")) {
42
+ $filenames = array_diff(scandir($directory), array('.', '..'));
43
+
44
+ foreach ($filenames as $filename) {
45
+ if (is_dir("$directory/$filename")) {
46
+ $success = self::deleteTree("$directory/$filename");
47
+ } else {
48
+ $success = @unlink("$directory/$filename");
49
+ }
50
+
51
+ if ($success === false) {
52
+ break;
53
+ }
54
+ }
55
+ } else {
56
+ return false;
57
+ }
58
+
59
+ return $success && @rmdir($directory);
60
+ }
61
+
62
+ /**
63
+ * Safely copies a file to a directory
64
+ *
65
+ * @param string $source_file The full filepath to the file to copy
66
+ * @param string $dest_dir The full path to the destination directory were the file will be copied
67
+ * @param string $delete_first Delete file before copying the new one
68
+ *
69
+ * @return TRUE on success or if file does not exist. FALSE on failure
70
+ */
71
+ public static function copyFile($source_file, $dest_dir, $delete_first = false)
72
+ {
73
+ //Create directory
74
+ if (file_exists($dest_dir) == false)
75
+ {
76
+ if (self::createDir($dest_dir, 0755, true) === false)
77
+ {
78
+ DUP_PRO_LOG::traceError("Error creating $dest_dir.");
79
+ return false;
80
+ }
81
+ }
82
+
83
+ //Remove file with same name before copy
84
+ $filename = basename($source_file);
85
+ $dest_filepath = $dest_dir . "/$filename";
86
+ if($delete_first)
87
+ {
88
+ self::deleteFile($dest_filepath);
89
+ }
90
+
91
+ return copy($source_file, $dest_filepath);
92
+ }
93
+ }
classes/class.logging.php CHANGED
@@ -1,58 +1,223 @@
1
  <?php
2
- if ( ! defined('DUPLICATOR_VERSION') ) exit; // Exit if accessed directly
 
3
 
4
  /**
5
  * Helper Class for logging
6
- * @package Dupicator\classes
7
  */
8
- class DUP_Log {
9
-
 
 
 
 
 
 
 
 
 
 
 
10
  /**
11
  * The file handle used to write to the log file
12
- * @var file resource
13
  */
14
- private static $logFileHandle;
15
-
 
 
 
 
 
 
 
 
16
  /**
17
  * Open a log file connection for writing
18
  * @param string $name Name of the log file to create
19
  */
20
- static public function Open($name) {
21
- if (! isset($name)) throw new Exception("A name value is required to open a file log.");
22
- self::$logFileHandle = @fopen(DUPLICATOR_SSDIR_PATH . "/{$name}.log", "c+");
 
 
23
  }
24
-
25
  /**
26
  * Close the log file connection
27
  */
28
- static public function Close() {
29
- @fclose(self::$logFileHandle);
 
30
  }
31
-
32
  /**
33
  * General information logging
34
  * @param string $msg The message to log
35
- *
36
- * REPLACE TO DEBUG: Memory consuption as script runs
37
- * $results = DUP_Util::byteSize(memory_get_peak_usage(true)) . "\t" . $msg;
38
- * @fwrite(self::$logFileHandle, "{$results} \n");
39
  */
40
- static public function Info($msg) {
41
- @fwrite(self::$logFileHandle, "{$msg} \n");
42
- //$results = DUP_Util::byteSize(memory_get_usage(true)) . "\t" . $msg;
43
- //@fwrite(self::$logFileHandle, "{$results} \n");
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  }
45
-
46
  /**
47
- * Called when an error is detected and no further processing should occur
48
- * @param string $msg The message to log
49
- * @param string $details Additional details to help resolve the issue if possible
50
- */
51
- static public function Error($msg, $detail) {
52
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  $source = self::getStack(debug_backtrace());
54
-
55
- $err_msg = "\n==================================================================================\n";
56
  $err_msg .= "DUPLICATOR ERROR\n";
57
  $err_msg .= "Please try again! If the error persists see the Duplicator 'Help' menu.\n";
58
  $err_msg .= "---------------------------------------------------------------------------------\n";
@@ -62,25 +227,67 @@ class DUP_Log {
62
  }
63
  $err_msg .= "TRACE:\n{$source}";
64
  $err_msg .= "==================================================================================\n\n";
65
- @fwrite(self::$logFileHandle, "{$err_msg}");
66
- die("DUPLICATOR ERROR: Please see the 'Package Log' file link below.");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
-
69
-
70
- /**
71
- * The current strack trace of a PHP call
72
  * @param $stacktrace The current debug stack
73
- * @return string
74
- */
75
- public static function getStack($stacktrace) {
76
- $output = "";
77
- $i = 1;
78
- foreach($stacktrace as $node) {
79
- $output .= "\t $i. ".basename($node['file']) ." : " .$node['function'] ." (" .$node['line'].")\n";
80
- $i++;
81
- }
 
82
  return $output;
83
- }
 
 
 
 
 
 
 
 
 
 
 
 
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  }
86
- ?>
1
  <?php
2
+ // Exit if accessed directly
3
+ if (!defined('DUPLICATOR_VERSION')) exit;
4
 
5
  /**
6
  * Helper Class for logging
7
+ * @package Duplicator\classes
8
  */
9
+ abstract class Dup_ErrorBehavior
10
+ {
11
+ const LogOnly = 0;
12
+ const ThrowException = 1;
13
+ const Quit = 2;
14
+
15
+ }
16
+
17
+ class DUP_Log
18
+ {
19
+ static $debugging = true;
20
+ private static $traceEnabled;
21
+
22
  /**
23
  * The file handle used to write to the log file
24
+ * @var file resource
25
  */
26
+ public static $logFileHandle = null;
27
+
28
+ /**
29
+ * Init this static object
30
+ */
31
+ public static function Init()
32
+ {
33
+ self::$traceEnabled = (DUP_Settings::Get('trace_log_enabled') == 1);
34
+ }
35
+
36
  /**
37
  * Open a log file connection for writing
38
  * @param string $name Name of the log file to create
39
  */
40
+ public static function Open($name)
41
+ {
42
+ if (!isset($name)) throw new Exception("A name value is required to open a file log.");
43
+ //self::$logFileHandle = @fopen(DUPLICATOR_SSDIR_PATH . "/{$name}.log", "c+");
44
+ self::$logFileHandle = @fopen(DUPLICATOR_SSDIR_PATH."/{$name}.log", "a+");
45
  }
46
+
47
  /**
48
  * Close the log file connection
49
  */
50
+ public static function Close()
51
+ {
52
+ @fclose(self::$logFileHandle);
53
  }
54
+
55
  /**
56
  * General information logging
57
  * @param string $msg The message to log
58
+ *
59
+ * REPLACE TO DEBUG: Memory consumption as script runs
60
+ * $results = DUP_Util::byteSize(memory_get_peak_usage(true)) . "\t" . $msg;
61
+ * @fwrite(self::$logFileHandle, "{$results} \n");
62
  */
63
+ public static function Info($msg)
64
+ {
65
+ self::Trace($msg);
66
+
67
+ @fwrite(self::$logFileHandle, "{$msg} \n");
68
+ }
69
+
70
+ /**
71
+ * Does the trace file exists
72
+ *
73
+ * @return bool Returns true if an active trace file exists
74
+ */
75
+ public static function TraceFileExists()
76
+ {
77
+ $file_path = self::getTraceFilepath();
78
+
79
+ return file_exists($file_path);
80
  }
81
+
82
  /**
83
+ * Gets the current file size of the active trace file
84
+ *
85
+ * @return string Returns a human readable file size of the active trace file
86
+ */
87
+ public static function getTraceStatus()
88
+ {
89
+ $file_path = DUP_Log::getTraceFilepath();
90
+ $backup_path = DUP_Log::getBackupTraceFilepath();
91
+
92
+ if (file_exists($file_path)) {
93
+ $filesize = filesize($file_path);
94
+
95
+ if (file_exists($backup_path)) {
96
+ $filesize += filesize($backup_path);
97
+ }
98
+
99
+ $message = sprintf('%1$s', DUP_Util::byteSize($filesize));
100
+ } else {
101
+ $message = esc_html__('No Log', 'duplicator');
102
+ }
103
+
104
+ return $message;
105
+ }
106
+
107
+ // RSR TODO: Swap trace logic out for real trace later
108
+ public static function Trace($message, $calling_function_override = null)
109
+ {
110
+
111
+ if (self::$traceEnabled) {
112
+ $unique_id = sprintf("%08x", abs(crc32($_SERVER['REMOTE_ADDR'].$_SERVER['REQUEST_TIME'].$_SERVER['REMOTE_PORT'])));
113
+
114
+ if ($calling_function_override == null) {
115
+ $calling_function = SnapLibUtil::getCallingFunctionName();
116
+ } else {
117
+ $calling_function = $calling_function_override;
118
+ }
119
+
120
+ if (is_object($message)) {
121
+ $ov = get_object_vars($message);
122
+ $message = print_r($ov, true);
123
+ } else if (is_array($message)) {
124
+ $message = print_r($message, true);
125
+ }
126
+
127
+ $logging_message = "{$unique_id}|{$calling_function} | {$message}";
128
+ $ticks = time() + ((int) get_option('gmt_offset') * 3600);
129
+ $formatted_time = date('d-m-H:i:s', $ticks);
130
+ $formatted_logging_message = "{$formatted_time}|DUP|{$logging_message} \r\n";
131
+
132
+ // Always write to error log - if they don't want the info they can turn off WordPress error logging or tracing
133
+ self::ErrLog($logging_message);
134
+
135
+ // Everything goes to the plugin log, whether it's part of package generation or not.
136
+ self::WriteToTrace($formatted_logging_message);
137
+ }
138
+ }
139
+
140
+ public static function errLog($message)
141
+ {
142
+ $message = 'DUP:'.$message;
143
+ error_log($message);
144
+ }
145
+
146
+ public static function TraceObject($msg, $o, $log_private_members = true)
147
+ {
148
+
149
+ if (self::$traceEnabled) {
150
+
151
+ if (!$log_private_members) {
152
+ $o = get_object_vars($o);
153
+ }
154
+
155
+ self::Trace($msg.':'.print_r($o, true));
156
+ }
157
+ }
158
+
159
+ public static function GetDefaultKey()
160
+ {
161
+ $auth_key = defined('AUTH_KEY') ? AUTH_KEY : 'atk';
162
+ $auth_key .= defined('DB_HOST') ? DB_HOST : 'dbh';
163
+ $auth_key .= defined('DB_NAME') ? DB_NAME : 'dbn';
164
+ $auth_key .= defined('DB_USER') ? DB_USER : 'dbu';
165
+
166
+ return hash('md5', $auth_key);
167
+ }
168
+
169
+ public static function GetBackupTraceFilepath()
170
+ {
171
+ $default_key = self::getDefaultKey();
172
+ $backup_log_filename = "dup_$default_key.log1";
173
+ $backup_path = DUPLICATOR_SSDIR_PATH."/".$backup_log_filename;
174
+
175
+ return $backup_path;
176
+ }
177
+
178
+ /**
179
+ * Gets the active trace file path
180
+ *
181
+ * @return string Returns the full path to the active trace file (i.e. dup-pro_hash.log)
182
+ */
183
+ public static function GetTraceFilepath()
184
+ {
185
+ $default_key = self::getDefaultKey();
186
+ $log_filename = "dup_$default_key.log";
187
+ $file_path = DUPLICATOR_SSDIR_PATH."/".$log_filename;
188
+
189
+ return $file_path;
190
+ }
191
+
192
+ /**
193
+ * Deletes the trace log and backup trace log files
194
+ *
195
+ * @return null
196
+ */
197
+ public static function DeleteTraceLog()
198
+ {
199
+ $file_path = self::GetTraceFilepath();
200
+ $backup_path = self::GetBackupTraceFilepath();
201
+
202
+ self::trace("deleting $file_path");
203
+ @unlink($file_path);
204
+ self::trace("deleting $backup_path");
205
+ @unlink($backup_path);
206
+ }
207
+
208
+ /**
209
+ * Called when an error is detected and no further processing should occur
210
+ * @param string $msg The message to log
211
+ * @param string $details Additional details to help resolve the issue if possible
212
+ */
213
+ public static function Error($msg, $detail, $behavior = Dup_ErrorBehavior::Quit)
214
+ {
215
+
216
+ error_log($msg.' DETAIL:'.$detail);
217
+
218
  $source = self::getStack(debug_backtrace());
219
+
220
+ $err_msg = "\n==================================================================================\n";
221
  $err_msg .= "DUPLICATOR ERROR\n";
222
  $err_msg .= "Please try again! If the error persists see the Duplicator 'Help' menu.\n";
223
  $err_msg .= "---------------------------------------------------------------------------------\n";
227
  }
228
  $err_msg .= "TRACE:\n{$source}";
229
  $err_msg .= "==================================================================================\n\n";
230
+ @fwrite(self::$logFileHandle, "{$err_msg}");
231
+
232
+ switch ($behavior) {
233
+
234
+ case Dup_ErrorBehavior::ThrowException:
235
+ DUP_LOG::trace("throwing exception");
236
+ throw new Exception("DUPLICATOR ERROR: Please see the 'Package Log' file link below.");
237
+ break;
238
+
239
+ case Dup_ErrorBehavior::Quit:
240
+ DUP_LOG::trace("quitting");
241
+ die("DUPLICATOR ERROR: Please see the 'Package Log' file link below.");
242
+ break;
243
+
244
+ default:
245
+ // Nothing
246
+ }
247
  }
248
+
249
+ /**
250
+ * The current stack trace of a PHP call
 
251
  * @param $stacktrace The current debug stack
252
+ * @return string
253
+ */
254
+ public static function getStack($stacktrace)
255
+ {
256
+ $output = "";
257
+ $i = 1;
258
+ foreach ($stacktrace as $node) {
259
+ $output .= "\t $i. ".basename($node['file'])." : ".$node['function']." (".$node['line'].")\n";
260
+ $i++;
261
+ }
262
  return $output;
263
+ }
264
+
265
+ /**
266
+ * Manages writing the active or backup log based on the size setting
267
+ *
268
+ * @return null
269
+ */
270
+ private static function WriteToTrace($formatted_logging_message)
271
+ {
272
+ $log_filepath = self::GetTraceFilepath();
273
+
274
+ if (@filesize($log_filepath) > DUPLICATOR_MAX_LOG_SIZE) {
275
+ $backup_log_filepath = self::GetBackupTraceFilepath();
276
 
277
+ if (file_exists($backup_log_filepath)) {
278
+ if (@unlink($backup_log_filepath) === false) {
279
+ DUP_PRO_Low_U::errLog("Couldn't delete backup log $backup_log_filepath");
280
+ }
281
+ }
282
+
283
+ if (@rename($log_filepath, $backup_log_filepath) === false) {
284
+ self::errLog("Couldn't rename log $log_filepath to $backup_log_filepath");
285
+ }
286
+ }
287
+
288
+ if (@file_put_contents($log_filepath, $formatted_logging_message, FILE_APPEND) === false) {
289
+ // Not en error worth reporting
290
+ }
291
+ }
292
  }
293
+ DUP_Log::Init();
classes/class.password.php CHANGED
@@ -24,6 +24,10 @@
24
  # Obviously, since this code is in the public domain, the above are not
25
  # requirements (there can be none), but merely suggestions.
26
  #
 
 
 
 
27
  class DUP_PasswordHash
28
  {
29
 
24
  # Obviously, since this code is in the public domain, the above are not
25
  # requirements (there can be none), but merely suggestions.
26
  #
27
+
28
+ // Exit if accessed directly
29
+ if (! defined('DUPLICATOR_VERSION')) exit;
30
+
31
  class DUP_PasswordHash
32
  {
33
 
classes/class.server.php CHANGED
@@ -1,4 +1,6 @@
1
  <?php
 
 
2
  /**
3
  * Used to get various pieces of information about the server environment
4
  *
@@ -6,63 +8,89 @@
6
  * @link http://www.php-fig.org/psr/psr-2
7
  *
8
  * @package Duplicator
9
- * @subpackage classes/utilites
10
  * @copyright (c) 2017, Snapcreek LLC
11
- * @since 1.1.0
12
- *
13
  */
14
- require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.php');
15
 
16
  // Exit if accessed directly
17
- if (!defined('DUPLICATOR_VERSION')) {
18
- exit;
19
- }
 
 
20
 
21
- class DUP_Server
22
- {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  /**
25
- * Gets the system requirements which must pass to buld a package
26
  *
27
  * @return array An array of requirements
28
  */
29
- public static function getRequirements()
30
- {
31
  global $wpdb;
32
  $dup_tests = array();
33
 
34
  //PHP SUPPORT
35
- $safe_ini = strtolower(ini_get('safe_mode'));
36
  $dup_tests['PHP']['SAFE_MODE'] = $safe_ini != 'on' || $safe_ini != 'yes' || $safe_ini != 'true' || ini_get("safe_mode") != 1 ? 'Pass' : 'Fail';
37
- $dup_tests['PHP']['VERSION'] = DUP_Util::$on_php_529_plus ? 'Pass' : 'Fail';
38
- $dup_tests['PHP']['ZIP'] = class_exists('ZipArchive') ? 'Pass' : 'Fail';
39
- $dup_tests['PHP']['FUNC_1'] = function_exists("file_get_contents") ? 'Pass' : 'Fail';
40
- $dup_tests['PHP']['FUNC_2'] = function_exists("file_put_contents") ? 'Pass' : 'Fail';
41
- $dup_tests['PHP']['FUNC_3'] = function_exists("mb_strlen") ? 'Pass' : 'Fail';
42
- $dup_tests['PHP']['ALL'] = !in_array('Fail', $dup_tests['PHP']) ? 'Pass' : 'Fail';
 
 
 
 
43
 
44
  //REQUIRED PATHS
45
- $handle_test = @opendir(DUPLICATOR_WPROOTPATH);
46
- $dup_tests['IO']['WPROOT'] = is_writeable(DUPLICATOR_WPROOTPATH) && $handle_test ? 'Pass' : 'Warn';
47
- @closedir($handle_test);
48
 
49
- $dup_tests['IO']['SSDIR'] = (file_exists(DUPLICATOR_SSDIR_PATH) && is_writeable(DUPLICATOR_SSDIR_PATH)) ? 'Pass' : 'Fail';
50
  $dup_tests['IO']['SSTMP'] = is_writeable(DUPLICATOR_SSDIR_PATH_TMP) ? 'Pass' : 'Fail';
51
- $dup_tests['IO']['ALL'] = !in_array('Fail', $dup_tests['IO']) ? 'Pass' : 'Fail';
52
 
53
  //SERVER SUPPORT
54
- $dup_tests['SRV']['MYSQLi'] = function_exists('mysqli_connect') ? 'Pass' : 'Fail';
55
  $dup_tests['SRV']['MYSQL_VER'] = version_compare(DUP_DB::getVersion(), '5.0', '>=') ? 'Pass' : 'Fail';
56
- $dup_tests['SRV']['ALL'] = !in_array('Fail', $dup_tests['SRV']) ? 'Pass' : 'Fail';
57
 
58
  //RESERVED FILES
59
  $dup_tests['RES']['INSTALL'] = !(self::hasInstallerFiles()) ? 'Pass' : 'Fail';
60
- $dup_tests['Success'] = $dup_tests['PHP']['ALL'] == 'Pass'
61
- && $dup_tests['IO']['ALL'] == 'Pass'
62
- && $dup_tests['SRV']['ALL'] == 'Pass'
63
- && $dup_tests['RES']['INSTALL'] == 'Pass';
64
-
65
- $dup_tests['Warning'] = $dup_tests['IO']['WPROOT'] == 'Warn';
66
 
67
  return $dup_tests;
68
  }
@@ -72,12 +100,11 @@ class DUP_Server
72
  *
73
  * @return array An array of system checks
74
  */
75
- public static function getChecks()
76
- {
77
  $checks = array();
78
 
79
  //PHP/SYSTEM SETTINGS
80
- //Web Server
81
  $php_test0 = false;
82
  foreach ($GLOBALS['DUPLICATOR_SERVER_LIST'] as $value) {
83
  if (stristr($_SERVER['SERVER_SOFTWARE'], $value)) {
@@ -92,21 +119,21 @@ class DUP_Server
92
  $php_test2 = ($php_test2 > DUPLICATOR_SCAN_TIMEOUT) || (strcmp($php_test2, 'Off') == 0 || $php_test2 == 0) ? true : false;
93
  $php_test3 = function_exists('mysqli_connect');
94
  $php_test4 = DUP_Util::$on_php_53_plus ? true : false;
95
-
96
- $checks['SRV']['PHP']['websrv'] = $php_test0;
97
  $checks['SRV']['PHP']['openbase'] = $php_test1;
98
- $checks['SRV']['PHP']['maxtime'] = $php_test2;
99
- $checks['SRV']['PHP']['mysqli'] = $php_test3;
100
- $checks['SRV']['PHP']['version'] = $php_test4;
101
- $checks['SRV']['PHP']['ALL'] = ($php_test0 && $php_test1 && $php_test2 && $php_test3 && $php_test4) ? 'Good' : 'Warn';
102
 
103
  //WORDPRESS SETTINGS
104
  global $wp_version;
105
  $wp_test1 = version_compare($wp_version, DUPLICATOR_SCAN_MIN_WP) >= 0 ? true : false;
106
 
107
  //Core Files
108
- $files = array();
109
- $files['wp-config.php'] = file_exists(DUP_Util::safePath(DUPLICATOR_WPROOTPATH.'/wp-config.php'));
110
 
111
  /** searching wp-config in working word press is not worthy
112
  * if this script is executing that means wp-config.php exists :)
@@ -118,26 +145,30 @@ class DUP_Server
118
  if (isset($_POST['file_notice']) && isset($_POST['dir_notice'])) {
119
  //means if there are core directories excluded or core files excluded return false
120
  if ((bool) $_POST['file_notice'] || (bool) $_POST['dir_notice'])
121
- $wp_test2 = false;
122
- else $wp_test2 = true;
 
123
  }else {
124
  $wp_test2 = $files['wp-config.php'];
125
  }
126
 
127
  //Cache
128
- $Package = DUP_Package::getActive();
129
- $cache_path = DUP_Util::safePath(WP_CONTENT_DIR).'/cache';
130
- $dirEmpty = DUP_Util::isDirectoryEmpty($cache_path);
131
- $dirSize = DUP_Util::getDirectorySize($cache_path);
 
132
  $cach_filtered = in_array($cache_path, explode(';', $Package->Archive->FilterDirs));
133
- $wp_test3 = ($cach_filtered || $dirEmpty || $dirSize < DUPLICATOR_SCAN_CACHESIZE ) ? true : false;
134
- $wp_test4 = is_multisite();
 
135
 
136
  $checks['SRV']['WP']['version'] = $wp_test1;
137
- $checks['SRV']['WP']['core'] = $wp_test2;
138
- $checks['SRV']['WP']['cache'] = $wp_test3;
139
- $checks['SRV']['WP']['ismu'] = $wp_test4;
140
- $checks['SRV']['WP']['ALL'] = $wp_test1 && $wp_test2 && $wp_test3 && !$wp_test4 ? 'Good' : 'Warn';
 
141
 
142
  return $checks;
143
  }
@@ -147,38 +178,45 @@ class DUP_Server
147
  *
148
  * @return bool True if any reserved files are found
149
  */
150
- public static function hasInstallerFiles()
151
- {
152
  $files = self::getInstallerFiles();
153
  foreach ($files as $file => $path) {
154
- if (false !== stripos($file, '[hash]')) {
155
  $glob_files = glob($path);
156
  if (!empty($glob_files)) {
157
  return true;
158
  }
159
- } elseif (file_exists($path)) return true;
 
160
  }
161
  return false;
162
  }
163
-
164
  /**
165
  * Gets a list of all the installer files by name and full path
166
- *
 
 
 
 
 
 
 
167
  * @return array [file_name, file_path]
168
  */
169
- public static function getInstallerFiles()
170
- {
171
  // alphanumeric 7 time, then -(dash), then 8 digits
172
- $hashPattern = '[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]';
173
- // Files: installer.php, installer-backup.php, installer-data.sql, installer-log.txt, database.sql
174
- return array(
175
- DUPLICATOR_INSTALL_PHP => DUPLICATOR_WPROOTPATH.DUPLICATOR_INSTALL_PHP,
176
- DUPLICATOR_INSTALL_BAK => DUPLICATOR_WPROOTPATH.DUPLICATOR_INSTALL_BAK,
177
-
178
- 'dup-installer-data__[HASH].sql' => DUPLICATOR_WPROOTPATH . 'dup-installer-data__'.$hashPattern.'.sql',
179
- 'dup-database__[HASH].sql' => DUPLICATOR_WPROOTPATH . 'dup-database__'.$hashPattern.'.sql',
180
- 'dup-installer-log_[HASH].txt' => DUPLICATOR_WPROOTPATH . 'dup-installer-log__'.$hashPattern.'.txt',
181
- );
 
182
  }
183
 
184
  /**
@@ -186,8 +224,7 @@ class DUP_Server
186
  *
187
  * @return string IP of the client machine
188
  */
189
- public static function getClientIP()
190
- {
191
  if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
192
  return $_SERVER["HTTP_X_FORWARDED_FOR"];
193
  } else if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
@@ -199,12 +236,11 @@ class DUP_Server
199
  }
200
 
201
  /**
202
- * Get PHP memory useage
203
  *
204
- * @return string Returns human readable memory useage.
205
  */
206
- public static function getPHPMemory($peak = false)
207
- {
208
  if ($peak) {
209
  $result = 'Unable to read PHP peak memory usage';
210
  if (function_exists('memory_get_peak_usage')) {
@@ -218,5 +254,5 @@ class DUP_Server
218
  }
219
  return $result;
220
  }
221
- }
222
- ?>
1
  <?php
2
+ require_once (DUPLICATOR_PLUGIN_PATH . 'classes/utilities/class.u.php');
3
+
4
  /**
5
  * Used to get various pieces of information about the server environment
6
  *
8
  * @link http://www.php-fig.org/psr/psr-2
9
  *
10
  * @package Duplicator
11
+ * @subpackage classes/utilities
12
  * @copyright (c) 2017, Snapcreek LLC
13
+ *
 
14
  */
 
15
 
16
  // Exit if accessed directly
17
+ if (! defined('DUPLICATOR_VERSION')) exit;
18
+
19
+ class DUP_Server {
20
+
21
+ const LockFileName = 'lockfile.txt';
22
 
23
+ // Possibly use in the future if we want to prevent double building
24
+ public static function isEngineLocked() {
25
+ if (self::setEngineLock(true)) {
26
+ self::setEngineLock(false);
27
+ $locked = false;
28
+ } else {
29
+ $locked = true;
30
+ }
31
+ }
32
+
33
+ // Possibly use in the future if we want to prevent double building
34
+ public static function setEngineLock($shouldLock) {
35
+ $success = false;
36
+
37
+ $locking_file = @fopen(self::LockFileName, 'c+');
38
+
39
+ if ($locking_file != false) {
40
+ if ($shouldLock) {
41
+ $success = @flock($locking_file, LOCK_EX | LOCK_NB);
42
+ } else {
43
+ $success = @flock($locking_file, LOCK_UN);
44
+ }
45
+
46
+ @fclose($locking_file);
47
+ }
48
+
49
+ return $success;
50
+ }
51
 
52
  /**
53
+ * Gets the system requirements which must pass to build a package
54
  *
55
  * @return array An array of requirements
56
  */
57
+ public static function getRequirements() {
 
58
  global $wpdb;
59
  $dup_tests = array();
60
 
61
  //PHP SUPPORT
62
+ $safe_ini = strtolower(ini_get('safe_mode'));
63
  $dup_tests['PHP']['SAFE_MODE'] = $safe_ini != 'on' || $safe_ini != 'yes' || $safe_ini != 'true' || ini_get("safe_mode") != 1 ? 'Pass' : 'Fail';
64
+ $dup_tests['PHP']['VERSION'] = DUP_Util::$on_php_529_plus ? 'Pass' : 'Fail';
65
+
66
+ if (DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::ZipArchive) {
67
+ $dup_tests['PHP']['ZIP'] = class_exists('ZipArchive') ? 'Pass' : 'Fail';
68
+ }
69
+
70
+ $dup_tests['PHP']['FUNC_1'] = function_exists("file_get_contents") ? 'Pass' : 'Fail';
71
+ $dup_tests['PHP']['FUNC_2'] = function_exists("file_put_contents") ? 'Pass' : 'Fail';
72
+ $dup_tests['PHP']['FUNC_3'] = function_exists("mb_strlen") ? 'Pass' : 'Fail';
73
+ $dup_tests['PHP']['ALL'] = !in_array('Fail', $dup_tests['PHP']) ? 'Pass' : 'Fail';
74
 
75
  //REQUIRED PATHS
76
+ $handle_test = @opendir(DUPLICATOR_WPROOTPATH);
77
+ $dup_tests['IO']['WPROOT'] = is_writeable(DUPLICATOR_WPROOTPATH) && $handle_test ? 'Pass' : 'Warn';
78
+ @closedir($handle_test);
79
 
80
+ $dup_tests['IO']['SSDIR'] = (file_exists(DUPLICATOR_SSDIR_PATH) && is_writeable(DUPLICATOR_SSDIR_PATH)) ? 'Pass' : 'Fail';
81
  $dup_tests['IO']['SSTMP'] = is_writeable(DUPLICATOR_SSDIR_PATH_TMP) ? 'Pass' : 'Fail';
82
+ $dup_tests['IO']['ALL'] = !in_array('Fail', $dup_tests['IO']) ? 'Pass' : 'Fail';
83
 
84
  //SERVER SUPPORT
85
+ $dup_tests['SRV']['MYSQLi'] = function_exists('mysqli_connect') ? 'Pass' : 'Fail';
86
  $dup_tests['SRV']['MYSQL_VER'] = version_compare(DUP_DB::getVersion(), '5.0', '>=') ? 'Pass' : 'Fail';
87
+ $dup_tests['SRV']['ALL'] = !in_array('Fail', $dup_tests['SRV']) ? 'Pass' : 'Fail';
88
 
89
  //RESERVED FILES
90
  $dup_tests['RES']['INSTALL'] = !(self::hasInstallerFiles()) ? 'Pass' : 'Fail';
91
+ $dup_tests['Success'] = $dup_tests['PHP']['ALL'] == 'Pass' && $dup_tests['IO']['ALL'] == 'Pass' && $dup_tests['SRV']['ALL'] == 'Pass' && $dup_tests['RES']['INSTALL'] == 'Pass';
92
+
93
+ $dup_tests['Warning'] = $dup_tests['IO']['WPROOT'] == 'Warn';
 
 
 
94
 
95
  return $dup_tests;
96
  }
100
  *
101
  * @return array An array of system checks
102
  */
103
+ public static function getChecks() {
 
104
  $checks = array();
105
 
106
  //PHP/SYSTEM SETTINGS
107
+ //Web Server
108
  $php_test0 = false;
109
  foreach ($GLOBALS['DUPLICATOR_SERVER_LIST'] as $value) {
110
  if (stristr($_SERVER['SERVER_SOFTWARE'], $value)) {
119
  $php_test2 = ($php_test2 > DUPLICATOR_SCAN_TIMEOUT) || (strcmp($php_test2, 'Off') == 0 || $php_test2 == 0) ? true : false;
120
  $php_test3 = function_exists('mysqli_connect');
121
  $php_test4 = DUP_Util::$on_php_53_plus ? true : false;
122
+
123
+ $checks['SRV']['PHP']['websrv'] = $php_test0;
124
  $checks['SRV']['PHP']['openbase'] = $php_test1;
125
+ $checks['SRV']['PHP']['maxtime'] = $php_test2;
126
+ $checks['SRV']['PHP']['mysqli'] = $php_test3;
127
+ $checks['SRV']['PHP']['version'] = $php_test4;
128
+ $checks['SRV']['PHP']['ALL'] = ($php_test0 && $php_test1 && $php_test2 && $php_test3 && $php_test4) ? 'Good' : 'Warn';
129
 
130
  //WORDPRESS SETTINGS
131
  global $wp_version;
132
  $wp_test1 = version_compare($wp_version, DUPLICATOR_SCAN_MIN_WP) >= 0 ? true : false;
133
 
134
  //Core Files
135
+ $files = array();
136
+ $files['wp-config.php'] = file_exists(DUP_Util::safePath(DUPLICATOR_WPROOTPATH . '/wp-config.php'));
137
 
138
  /** searching wp-config in working word press is not worthy
139
  * if this script is executing that means wp-config.php exists :)
145
  if (isset($_POST['file_notice']) && isset($_POST['dir_notice'])) {
146
  //means if there are core directories excluded or core files excluded return false
147
  if ((bool) $_POST['file_notice'] || (bool) $_POST['dir_notice'])
148
+ $wp_test2 = false;
149
+ else
150
+ $wp_test2 = true;
151
  }else {
152
  $wp_test2 = $files['wp-config.php'];
153
  }
154
 
155
  //Cache
156
+ /*
157
+ $Package = DUP_Package::getActive();
158
+ $cache_path = DUP_Util::safePath(WP_CONTENT_DIR) . '/cache';
159
+ $dirEmpty = DUP_Util::isDirectoryEmpty($cache_path);
160
+ $dirSize = DUP_Util::getDirectorySize($cache_path);
161
  $cach_filtered = in_array($cache_path, explode(';', $Package->Archive->FilterDirs));
162
+ $wp_test3 = ($cach_filtered || $dirEmpty || $dirSize < DUPLICATOR_SCAN_CACHESIZE ) ? true : false;
163
+ */
164
+ $wp_test4 = is_multisite();
165
 
166
  $checks['SRV']['WP']['version'] = $wp_test1;
167
+ $checks['SRV']['WP']['core'] = $wp_test2;
168
+ // $checks['SRV']['WP']['cache'] = $wp_test3;
169
+ $checks['SRV']['WP']['ismu'] = $wp_test4;
170
+ // $checks['SRV']['WP']['ALL'] = $wp_test1 && $wp_test2 && $wp_test3 && !$wp_test4 ? 'Good' : 'Warn';
171
+ $checks['SRV']['WP']['ALL'] = $wp_test1 && $wp_test2 && !$wp_test4 ? 'Good' : 'Warn';
172
 
173
  return $checks;
174
  }
178
  *
179
  * @return bool True if any reserved files are found
180
  */
181
+ public static function hasInstallerFiles() {
 
182
  $files = self::getInstallerFiles();
183
  foreach ($files as $file => $path) {
184
+ if (false !== strpos($path, '*')) {
185
  $glob_files = glob($path);
186
  if (!empty($glob_files)) {
187
  return true;
188
  }
189
+ } elseif (file_exists($path))
190
+ return true;
191
  }
192
  return false;
193
  }
194
+
195
  /**
196
  * Gets a list of all the installer files by name and full path
197
+ *
198
+ * @remarks
199
+ * FILES: installer.php, installer-backup.php, dup-installer-bootlog__[HASH].txt
200
+ * DIRS: dup-installer
201
+ * DEV FILES: wp-config.orig
202
+ * Last set is for lazy developer cleanup files that a developer may have
203
+ * accidently left around lets be proactive for the user just in case.
204
+ *
205
  * @return array [file_name, file_path]
206
  */
207
+ public static function getInstallerFiles() {
 
208
  // alphanumeric 7 time, then -(dash), then 8 digits
209
+
210
+ $retArr = array(
211
+ basename(DUPLICATOR_INSTALLER_DIRECTORY) . ' ' . esc_html__('(directory)', 'duplicator') => DUPLICATOR_INSTALLER_DIRECTORY,
212
+ DUPLICATOR_INSTALL_PHP => DUPLICATOR_WPROOTPATH . DUPLICATOR_INSTALL_PHP,
213
+ DUPLICATOR_INSTALL_BAK => DUPLICATOR_WPROOTPATH . DUPLICATOR_INSTALL_BAK,
214
+ 'dup-installer-bootlog__[HASH].txt' => DUPLICATOR_WPROOTPATH .'dup-installer-bootlog__'.DUPLICATOR_INSTALLER_HASH_PATTERN.'.txt',
215
+ );
216
+ if (DUPLICATOR_INSTALL_SITE_OVERWRITE_ON) {
217
+ $retArr['dup-wp-config-arc__[HASH].txt'] = DUPLICATOR_WPROOTPATH . 'dup-wp-config-arc__'.DUPLICATOR_INSTALLER_HASH_PATTERN.'.txt';
218
+ }
219
+ return $retArr;
220
  }
221
 
222
  /**
224
  *
225
  * @return string IP of the client machine
226
  */
227
+ public static function getClientIP() {
 
228
  if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
229
  return $_SERVER["HTTP_X_FORWARDED_FOR"];
230
  } else if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
236
  }
237
 
238
  /**
239
+ * Get PHP memory usage
240
  *
241
+ * @return string Returns human readable memory usage.
242
  */
243
+ public static function getPHPMemory($peak = false) {
 
244
  if ($peak) {
245
  $result = 'Unable to read PHP peak memory usage';
246
  if (function_exists('memory_get_peak_usage')) {
254
  }
255
  return $result;
256
  }
257
+
258
+ }
classes/class.settings.php CHANGED
@@ -1,10 +1,20 @@
1
  <?php
2
- if ( ! defined( 'DUPLICATOR_VERSION' ) ) exit; // Exit if accessed directly
 
3
 
4
 
 
 
 
 
 
 
 
 
 
5
  class DUP_Settings
6
  {
7
-
8
  const OPT_SETTINGS = 'duplicator_settings';
9
 
10
  public static $Data;
@@ -30,12 +40,12 @@ class DUP_Settings
30
  public static function Get($key = '') {
31
  $result = null;
32
  if (isset(self::$Data[$key])) {
33
- $result = self::$Data[$key];
34
  } else {
35
  $defaults = self::GetAllDefaults();
36
  if (isset($defaults[$key])) {
37
  $result = $defaults[$key];
38
- }
39
  }
40
  return $result;
41
  }
@@ -79,38 +89,20 @@ class DUP_Settings
79
  self::$Data = $defaults;
80
  return self::Save();
81
  }
82
-
83
- /**
84
- * LegacyClean: Cleans up legacy data
85
- */
86
- public static function LegacyClean() {
87
- global $wpdb;
88
-
89
- //PRE 5.0
90
- $table = $wpdb->prefix."duplicator";
91
- $wpdb->query("DROP TABLE IF EXISTS $table");
92
- delete_option('duplicator_pack_passcount');
93
- delete_option('duplicator_add1_passcount');
94
- delete_option('duplicator_add1_clicked');
95
- delete_option('duplicator_options');
96
-
97
- //PRE 5.n
98
- //Next version here if needed
99
- }
100
-
101
  /**
102
  * DeleteWPOption: Cleans up legacy data
103
  */
104
  public static function DeleteWPOption($optionName) {
105
-
106
  if ( in_array($optionName, $GLOBALS['DUPLICATOR_OPTS_DELETE']) ) {
107
- return delete_option($optionName);
108
  }
109
  return false;
110
  }
111
-
112
-
113
- public static function GetAllDefaults() {
114
  $default = array();
115
  $default['version'] = self::$Version;
116
 
@@ -120,7 +112,7 @@ class DUP_Settings
120
  $default['uninstall_files'] = isset(self::$Data['uninstall_files']) ? self::$Data['uninstall_files'] : true;
121
  //Flag used to remove all tables
122
  $default['uninstall_tables'] = isset(self::$Data['uninstall_tables']) ? self::$Data['uninstall_tables'] : true;
123
-
124
  //Flag used to show debug info
125
  $default['package_debug'] = isset(self::$Data['package_debug']) ? self::$Data['package_debug'] : false;
126
  //Flag used to enable mysqldump
@@ -131,10 +123,15 @@ class DUP_Settings
131
  $default['package_phpdump_qrylimit'] = isset(self::$Data['package_phpdump_qrylimit']) ? self::$Data['package_phpdump_qrylimit'] : "100";
132
  //Optional mysqldump search path
133
  $default['package_zip_flush'] = isset(self::$Data['package_zip_flush']) ? self::$Data['package_zip_flush'] : false;
134
-
135
  //Flag for .htaccess file
136
  $default['storage_htaccess_off'] = isset(self::$Data['storage_htaccess_off']) ? self::$Data['storage_htaccess_off'] : false;
137
-
 
 
 
 
 
138
  return $default;
139
  }
140
  }
1
  <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
 
5
 
6
+ abstract class DUP_Archive_Build_Mode
7
+ {
8
+ const Unconfigured = -1;
9
+ const Auto = 0; // should no longer be used
10
+ // const Shell_Exec = 1;
11
+ const ZipArchive = 2;
12
+ const DupArchive = 3;
13
+ }
14
+
15
  class DUP_Settings
16
  {
17
+
18
  const OPT_SETTINGS = 'duplicator_settings';
19
 
20
  public static $Data;
40
  public static function Get($key = '') {
41
  $result = null;
42
  if (isset(self::$Data[$key])) {
43
+ $result = self::$Data[$key];
44
  } else {
45
  $defaults = self::GetAllDefaults();
46
  if (isset($defaults[$key])) {
47
  $result = $defaults[$key];
48
+ }
49
  }
50
  return $result;
51
  }
89
  self::$Data = $defaults;
90
  return self::Save();
91
  }
92
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  /**
94
  * DeleteWPOption: Cleans up legacy data
95
  */
96
  public static function DeleteWPOption($optionName) {
97
+
98
  if ( in_array($optionName, $GLOBALS['DUPLICATOR_OPTS_DELETE']) ) {
99
+ return delete_option($optionName);
100
  }
101
  return false;
102
  }
103
+
104
+
105
+ public static function GetAllDefaults() {
106
  $default = array();
107
  $default['version'] = self::$Version;
108
 
112
  $default['uninstall_files'] = isset(self::$Data['uninstall_files']) ? self::$Data['uninstall_files'] : true;
113
  //Flag used to remove all tables
114
  $default['uninstall_tables'] = isset(self::$Data['uninstall_tables']) ? self::$Data['uninstall_tables'] : true;
115
+
116
  //Flag used to show debug info
117
  $default['package_debug'] = isset(self::$Data['package_debug']) ? self::$Data['package_debug'] : false;
118
  //Flag used to enable mysqldump
123
  $default['package_phpdump_qrylimit'] = isset(self::$Data['package_phpdump_qrylimit']) ? self::$Data['package_phpdump_qrylimit'] : "100";
124
  //Optional mysqldump search path
125
  $default['package_zip_flush'] = isset(self::$Data['package_zip_flush']) ? self::$Data['package_zip_flush'] : false;
126
+
127
  //Flag for .htaccess file
128
  $default['storage_htaccess_off'] = isset(self::$Data['storage_htaccess_off']) ? self::$Data['storage_htaccess_off'] : false;
129
+
130
+ // Initial archive build mode
131
+ $default['archive_build_mode'] = isset(self::$Data['archive_build_mode']) ? self::$Data['archive_build_mode'] : DUP_Archive_Build_Mode::ZipArchive;
132
+
133
+ $default['active_package_id'] = -1;
134
+
135
  return $default;
136
  }
137
  }
classes/package/class.pack.archive.filters.php CHANGED
@@ -1,84 +1,86 @@
1
- <?php
2
- /**
3
- * The base class for all filter types Directories/Files/Extentions
4
- *
5
- * @package Duplicator
6
- * @subpackage classes/package
7
- * @since 1.1.0
8
- *
9
- */
10
- class DUP_Archive_Filter_Scope_Base
11
- {
12
- //All internal storage items that duplicator decides to filter
13
- public $Core = array();
14
- //Items when creating a package or template that a user decides to filter
15
- public $Instance = array();
16
- }
17
-
18
- /**
19
- * The filter types that belong to directories
20
- *
21
- * @package Duplicator
22
- * @subpackage classes/package
23
- * @since 1.1.0
24
- *
25
- */
26
- class DUP_Archive_Filter_Scope_Directory extends DUP_Archive_Filter_Scope_Base
27
- {
28
- //Items that are not readable
29
- public $Warning = array();
30
- //Items that are not readable
31
- public $Unreadable = array();
32
- }
33
-
34
- /**
35
- * The filter types that belong to files
36
- *
37
- * @package Duplicator
38
- * @subpackage classes/package
39
- * @since 1.1.0
40
- *
41
- */
42
- class DUP_Archive_Filter_Scope_File extends DUP_Archive_Filter_Scope_Directory
43
- {
44
- //Items that are too large
45
- public $Size = array();
46
-
47
- }
48
-
49
- /**
50
- * The filter information object which store all information about the filtered
51
- * data that is gathered to the execution of a scan process
52
- *
53
- * @package Duplicator
54
- * @subpackage classes/package
55
- * @since 1.1.0
56
- *
57
- */
58
- class DUP_Archive_Filter_Info
59
- {
60
- //Contains all folder filter info
61
- public $Dirs = array();
62
- //Contains all file filter info
63
- public $Files = array();
64
- //Contains all extensions filter info
65
- public $Exts = array();
66
- public $UDirCount = 0;
67
- public $UFileCount = 0;
68
- public $UExtCount = 0;
69
- public $TreeSize;
70
- public $TreeWarning;
71
-
72
- /**
73
- * Init this object
74
- */
75
- public function __construct()
76
- {
77
- $this->Dirs = new DUP_Archive_Filter_Scope_Directory();
78
- $this->Files = new DUP_Archive_Filter_Scope_File();
79
- $this->Exts = new DUP_Archive_Filter_Scope_Base();
80
- $this->TreeSize = array();
81
- $this->TreeWarning = array();
82
- }
83
- }
84
-
 
 
1
+ <?php
2
+ /**
3
+ * The base class for all filter types Directories/Files/Extentions
4
+ *
5
+ * @package Duplicator
6
+ * @subpackage classes/package
7
+ *
8
+ */
9
+
10
+ // Exit if accessed directly
11
+ if (! defined('DUPLICATOR_VERSION')) exit;
12
+
13
+ class DUP_Archive_Filter_Scope_Base
14
+ {
15
+ //All internal storage items that duplicator decides to filter
16
+ public $Core = array();
17
+ //Global filter items added from settings
18
+ public $Global = array();
19
+ //Items when creating a package or template that a user decides to filter
20
+ public $Instance = array();
21
+ }
22
+
23
+ /**
24
+ * The filter types that belong to directories
25
+ *
26
+ * @package Duplicator
27
+ * @subpackage classes/package
28
+ *
29
+ */
30
+ class DUP_Archive_Filter_Scope_Directory extends DUP_Archive_Filter_Scope_Base
31
+ {
32
+ //Items that are not readable
33
+ public $Warning = array();
34
+ //Items that are not readable
35
+ public $Unreadable = array();
36
+ }
37
+
38
+ /**
39
+ * The filter types that belong to files
40
+ *
41
+ * @package Duplicator
42
+ * @subpackage classes/package
43
+ *
44
+ */
45
+ class DUP_Archive_Filter_Scope_File extends DUP_Archive_Filter_Scope_Directory
46
+ {
47
+ //Items that are too large
48
+ public $Size = array();
49
+
50
+ }
51
+
52
+ /**
53
+ * The filter information object which store all information about the filtered
54
+ * data that is gathered to the execution of a scan process
55
+ *
56
+ * @package Duplicator
57
+ * @subpackage classes/package
58
+ *
59
+ */
60
+ class DUP_Archive_Filter_Info
61
+ {
62
+ //Contains all folder filter info
63
+ public $Dirs = array();
64
+ //Contains all file filter info
65
+ public $Files = array();
66
+ //Contains all extensions filter info
67
+ public $Exts = array();
68
+ public $UDirCount = 0;
69
+ public $UFileCount = 0;
70
+ public $UExtCount = 0;
71
+ public $TreeSize;
72
+ public $TreeWarning;
73
+
74
+ /**
75
+ * Init this object
76
+ */
77
+ public function __construct()
78
+ {
79
+ $this->Dirs = new DUP_Archive_Filter_Scope_Directory();
80
+ $this->Files = new DUP_Archive_Filter_Scope_File();
81
+ $this->Exts = new DUP_Archive_Filter_Scope_Base();
82
+ $this->TreeSize = array();
83
+ $this->TreeWarning = array();
84
+ }
85
+ }
86
+
classes/package/class.pack.archive.php CHANGED
@@ -1,605 +1,661 @@
1
- <?php
2
- if (!defined('DUPLICATOR_VERSION')) exit; // Exit if accessed directly
3
-
4
- require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.filters.php');
5
- require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.zip.php');
6
- require_once (DUPLICATOR_PLUGIN_PATH.'lib/forceutf8/Encoding.php');
7
-
8
- /**
9
- * Class for handling archive setup and build process
10
- *
11
- * Standard: PSR-2 (almost)
12
- * @link http://www.php-fig.org/psr/psr-2
13
- *
14
- * @package DUP
15
- * @subpackage classes/package
16
- * @copyright (c) 2017, Snapcreek LLC
17
- * @license https://opensource.org/licenses/GPL-3.0 GNU Public License
18
- * @since 1.0.0
19
- *
20
- */
21
- class DUP_Archive
22
- {
23
- //PUBLIC
24
- public $FilterDirs;
25
- public $FilterFiles;
26
- public $FilterExts;
27
- public $FilterDirsAll = array();
28
- public $FilterFilesAll = array();
29
- public $FilterExtsAll = array();
30
- public $FilterOn;
31
- public $ExportOnlyDB;
32
- public $File;
33
- public $Format;
34
- public $PackDir;
35
- public $Size = 0;
36
- public $Dirs = array();
37
- public $Files = array();
38
- public $FilterInfo;
39
- public $RecursiveLinks = array();
40
-
41
- //PROTECTED
42
- protected $Package;
43
- private $tmpFilterDirsAll = array();
44
- private $wpCorePaths = array();
45
-
46
-
47
- /**
48
- * Init this object
49
- */
50
- public function __construct($package)
51
- {
52
- $this->Package = $package;
53
- $this->FilterOn = false;
54
- $this->ExportOnlyDB = false;
55
- $this->FilterInfo = new DUP_Archive_Filter_Info();
56
-
57
- $rootPath = DUP_Util::safePath(rtrim(DUPLICATOR_WPROOTPATH, '//'));
58
-
59
- $this->wpCorePaths[] = DUP_Util::safePath("{$rootPath}/wp-admin");
60
- $this->wpCorePaths[] = DUP_Util::safePath(WP_CONTENT_DIR . "/uploads");
61
- $this->wpCorePaths[] = DUP_Util::safePath(WP_CONTENT_DIR . "/languages");
62
- $this->wpCorePaths[] = DUP_Util::safePath(WP_PLUGIN_DIR);
63
- $this->wpCorePaths[] = DUP_Util::safePath(get_theme_root());
64
- $this->wpCorePaths[] = DUP_Util::safePath("{$rootPath}/wp-includes");
65
- }
66
-
67
- /**
68
- * Builds the archive based on the archive type
69
- *
70
- * @param obj $package The package object that started this process
71
- *
72
- * @return null
73
- */
74
- public function build($package)
75
- {
76
- try {
77
- $this->Package = $package;
78
- if (!isset($this->PackDir) && !is_dir($this->PackDir)) throw new Exception("The 'PackDir' property must be a valid diretory.");
79
- if (!isset($this->File)) throw new Exception("A 'File' property must be set.");
80
-
81
- $this->Package->setStatus(DUP_PackageStatus::ARCSTART);
82
- switch ($this->Format) {
83
- case 'TAR': break;
84
- case 'TAR-GZIP': break;
85
- default:
86
- if (class_exists(ZipArchive)) {
87
- $this->Format = 'ZIP';
88
- DUP_Zip::create($this);
89
- }
90
- break;
91
- }
92
-
93
- $storePath = "{$this->Package->StorePath}/{$this->File}";
94
- $this->Size = @filesize($storePath);
95
- $this->Package->setStatus(DUP_PackageStatus::ARCDONE);
96
- } catch (Exception $e) {
97
- echo 'Caught exception: ', $e->getMessage(), "\n";
98
- }
99
- }
100
-
101
- /**
102
- * Builds a list of files and directories to be included in the archive
103
- *
104
- * Get the directory size recursively, but don't calc the snapshot directory, exclusion diretories
105
- * @link http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx Windows filename restrictions
106
- *
107
- * @return obj Returns a DUP_Archive object
108
- */
109
- public function getScannerData()
110
- {
111
- $this->createFilterInfo();
112
- $rootPath = DUP_Util::safePath(rtrim(DUPLICATOR_WPROOTPATH, '//'));
113
- $rootPath = (trim($rootPath) == '') ? '/' : $rootPath;
114
-
115
- //If the root directory is a filter then skip it all
116
- if (in_array($this->PackDir, $this->FilterDirsAll) || $this->Package->Archive->ExportOnlyDB) {
117
- $this->Dirs = array();
118
- } else {
119
- $this->Dirs[] = $this->PackDir;
120
- $this->getFileLists($rootPath);
121
- $this->setDirFilters();
122
- $this->setFileFilters();
123
- $this->setTreeFilters();
124
- }
125
-
126
- $this->FilterDirsAll = array_merge($this->FilterDirsAll, $this->FilterInfo->Dirs->Unreadable);
127
- $this->FilterFilesAll = array_merge($this->FilterFilesAll, $this->FilterInfo->Files->Unreadable);
128
- sort($this->FilterDirsAll);
129
-
130
- return $this;
131
- }
132
-
133
- /**
134
- * Save any property of this class through reflection
135
- *
136
- * @param $property A valid public property in this class
137
- * @param $value The value for the new dynamic property
138
- *
139
- * @return bool Returns true if the value has changed.
140
- */
141
- public function saveActiveItem($package, $property, $value)
142
- {
143
- $package = DUP_Package::getActive();
144
- $reflectionClass = new ReflectionClass($package->Archive);
145
- $reflectionClass->getProperty($property)->setValue($package->Archive, $value);
146
- return update_option(DUP_Package::OPT_ACTIVE, $package);
147
- }
148
-
149
- /**
150
- * Properly creates the directory filter list that is used for filtering directories
151
- *
152
- * @param string $dirs A semi-colon list of dir paths
153
- * /path1_/path/;/path1_/path2/;
154
- *
155
- * @returns string A cleaned up list of directory filters
156
- */
157
- public function parseDirectoryFilter($dirs = "")
158
- {
159
- $dirs = str_replace(array("\n", "\t", "\r"), '', $dirs);
160
- $filters = "";
161
- $dir_array = array_unique(explode(";", $dirs));
162
- $clean_array = array();
163
- foreach ($dir_array as $val) {
164
- if (strlen($val) >= 2) {
165
- $clean_array[] = DUP_Util::safePath(trim(rtrim($val, "/\\"))) ;
166
- }
167
- }
168
-
169
- if (count($clean_array)) {
170
- $clean_array = array_unique($clean_array);
171
- sort($clean_array);
172
- $filters = implode(';', $clean_array) . ';';
173
- }
174
- return $filters ;
175
- }
176
-
177
- /**
178
- * Properly creates the file filter list that is used for filtering files
179
- *
180
- * @param string $dirs A semi-colon list of dir paths
181
- * /path1_/path/file1.ext;/path1_/path2/file2.ext;
182
- *
183
- * @returns string A cleaned up list of file filters
184
- */
185
- public function parseFileFilter($files = "")
186
- {
187
- $files = str_replace(array("\n", "\t", "\r"), '', $files);
188
- $filters = "";
189
- $file_array = array_unique(explode(";", $files));
190
- $clean_array = array();
191
- foreach ($file_array as $val) {
192
- if (strlen($val) >= 2) {
193
- $clean_array[] = DUP_Util::safePath(trim(rtrim($val, "/\\"))) ;
194
- }
195
- }
196
-
197
- if (count($clean_array)) {
198
- $clean_array = array_unique($clean_array);
199
- sort($clean_array);
200
- $filters = implode(';', $clean_array) . ';';
201
- }
202
- return $filters ;
203
- }
204
-
205
- /**
206
- * Properly creates the extension filter list that is used for filtering extensions
207
- *
208
- * @param string $dirs A semi-colon list of dir paths
209
- * .jpg;.zip;.gif;
210
- *
211
- * @returns string A cleaned up list of extension filters
212
- */
213
- public function parseExtensionFilter($extensions = "")
214
- {
215
- $filter_exts = "";
216
- if (strlen($extensions) >= 1 && $extensions != ";") {
217
- $filter_exts = str_replace(array(' ', '.'), '', $extensions);
218
- $filter_exts = str_replace(",", ";", $filter_exts);
219
- $filter_exts = DUP_Util::appendOnce($extensions, ";");
220
- }
221
- return $filter_exts;
222
- }
223
-
224
- /**
225
- * Creates the filter info setup data used for filtering the archive
226
- *
227
- * @return null
228
- */
229
- private function createFilterInfo()
230
- {
231
- //FILTER: INSTANCE ITEMS
232
- //Add the items generated at create time
233
- if ($this->FilterOn) {
234
- $this->FilterInfo->Dirs->Instance = array_map('DUP_Util::safePath', explode(";", $this->FilterDirs, -1));
235
- $this->FilterInfo->Files->Instance = array_map('DUP_Util::safePath', explode(";", $this->FilterFiles, -1));
236
- $this->FilterInfo->Exts->Instance = explode(";", $this->FilterExts, -1);
237
- }
238
-
239
- //FILTER: CORE ITMES
240
- //Filters Duplicator free packages & All pro local directories
241
- $wp_root = rtrim(DUPLICATOR_WPROOTPATH, '/');
242
- $upload_dir = wp_upload_dir();
243
- $upload_dir = isset($upload_dir['basedir']) ? basename($upload_dir['basedir']) : 'uploads';
244
- $wp_content = str_replace("\\", "/", WP_CONTENT_DIR);
245
- $wp_content_upload = "{$wp_content}/{$upload_dir}";
246
- $this->FilterInfo->Dirs->Core = array(
247
- //WP-ROOT
248
- $wp_root . '/wp-snapshots',
249
-
250
- //WP-CONTENT
251
- $wp_content . '/backups-dup-pro',
252
- $wp_content . '/ai1wm-backups',
253
- $wp_content . '/backupwordpress',
254
- $wp_content . '/content/cache',
255
- $wp_content . '/contents/cache',
256
- $wp_content . '/infinitewp/backups',
257
- $wp_content . '/managewp/backups',
258
- $wp_content . '/old-cache',
259
- $wp_content . '/plugins/all-in-one-wp-migration/storage',
260
- $wp_content . '/updraft',
261
- $wp_content . '/wishlist-backup',
262
- $wp_content . '/wfcache',
263
-
264
- //WP-CONTENT-UPLOADS
265
- $wp_content_upload . '/aiowps_backups',
266
- $wp_content_upload . '/backupbuddy_temp',
267
- $wp_content_upload . '/backupbuddy_backups',
268
- $wp_content_upload . '/ithemes-security/backups',
269
- $wp_content_upload . '/mainwp/backup',
270
- $wp_content_upload . '/pb_backupbuddy',
271
- $wp_content_upload . '/snapshots',
272
- $wp_content_upload . '/sucuri',
273
- $wp_content_upload . '/wp-clone',
274
- $wp_content_upload . '/wp_all_backup',
275
- $wp_content_upload . '/wpbackitup_backups'
276
- );
277
-
278
- $this->FilterDirsAll = array_merge($this->FilterInfo->Dirs->Instance, $this->FilterInfo->Dirs->Core);
279
- $this->FilterExtsAll = array_merge($this->FilterInfo->Exts->Instance, $this->FilterInfo->Exts->Core);
280
- $this->FilterFilesAll = array_merge($this->FilterInfo->Files->Instance);
281
- $this->tmpFilterDirsAll = $this->FilterDirsAll;
282
-
283
- //PHP 5 on windows decode patch
284
- if (! DUP_Util::$PHP7_plus && DUP_Util::isWindows()) {
285
- foreach ($this->tmpFilterDirsAll as $key => $value) {
286
- if ( preg_match('/[^\x20-\x7f]/', $value)) {
287
- $this->tmpFilterDirsAll[$key] = utf8_decode($value);
288
- }
289
- }
290
- }
291
- }
292
-
293
- /**
294
- * Get All Directories then filter
295
- *
296
- * @return null
297
- */
298
- private function setDirFilters()
299
- {
300
- $this->FilterInfo->Dirs->Warning = array();
301
- $this->FilterInfo->Dirs->Unreadable = array();
302
- $this->FilterInfo->Dirs->AddonSites = array();
303
-
304
- $utf8_key_list = array();
305
- $unset_key_list = array();
306
-
307
- //Filter directories invalid test checks for:
308
- // - characters over 250
309
- // - invlaid characters
310
- // - empty string
311
- // - directories ending with period (Windows incompatable)
312
- foreach ($this->Dirs as $key => $val) {
313
- $name = basename($val);
314
-
315
- //Dir is not readble remove flag for removal
316
- if (! is_readable($this->Dirs[$key])) {
317
- $unset_key_list[] = $key;
318
- $this->FilterInfo->Dirs->Unreadable[] = DUP_Encoding::toUTF8($val);
319
- }
320
-
321
- //Locate invalid directories and warn
322
- $invalid_test = strlen($val) > 244
323
- || preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $name)
324
- || trim($name) == ''
325
- || (strrpos($name, '.') == strlen($name) - 1 && substr($name, -1) == '.')
326
- || preg_match('/[^\x20-\x7f]/', $name);
327
-
328
- if ($invalid_test) {
329
- $utf8_key_list[] = $key;
330
- $this->FilterInfo->Dirs->Warning[] = DUP_Encoding::toUTF8($val);
331
- }
332
-
333
- //Check for other WordPress installs
334
- if ($name === 'wp-admin') {
335
- $parent_dir = realpath(dirname($this->Dirs[$key]));
336
- if ($parent_dir != realpath(DUPLICATOR_WPROOTPATH)) {
337
- if (file_exists("$parent_dir/wp-includes")) {
338
- if (file_exists("$parent_dir/wp-config.php")) {
339
- // Ensure we aren't adding any critical directories
340
- $parent_name = basename($parent_dir);
341
- if (($parent_name != 'wp-includes') && ($parent_name != 'wp-content') && ($parent_name != 'wp-admin')) {
342
- $this->FilterInfo->Dirs->AddonSites[] = str_replace("\\", '/',$parent_dir);
343
- }
344
- }
345
- }
346
- }
347
- }
348
-
349
- }
350
-
351
- //Try to repair utf8 paths
352
- foreach ($utf8_key_list as $key) {
353
- $this->Dirs[$key] = DUP_Encoding::toUTF8($this->Dirs[$key]);
354
- }
355
-
356
- //Remove unreadable items outside of main loop for performance
357
- if (count($unset_key_list)) {
358
- foreach ($unset_key_list as $key) {
359
- unset($this->Dirs[$key]);
360
- }
361
- $this->Dirs = array_values($this->Dirs);
362
- }
363
-
364
- }
365
-
366
- /**
367
- * Get all files and filter out error prone subsets
368
- *
369
- * @return null
370
- */
371
- private function setFileFilters()
372
- {
373
- //Init for each call to prevent concatination from stored entity objects
374
- $this->Size = 0;
375
- $this->FilterInfo->Files->Size = array();
376
- $this->FilterInfo->Files->Warning = array();
377
- $this->FilterInfo->Files->Unreadable = array();
378
-
379
- $utf8_key_list = array();
380
- $unset_key_list = array();
381
-
382
- foreach ($this->Files as $key => $filePath) {
383
-
384
- $fileName = basename($filePath);
385
-
386
- if (! is_readable($filePath)) {
387
- $unset_key_list[] = $key;
388
- $this->FilterInfo->Files->Unreadable[] = $filePath;
389
- continue;
390
- }
391
-
392
- $invalid_test = strlen($filePath) > 250
393
- || preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $fileName)
394
- || trim($fileName) == ""
395
- || preg_match('/[^\x20-\x7f]/', $fileName);
396
-
397
- if ($invalid_test) {
398
- $utf8_key_list[] = $key;
399
- $filePath = DUP_Encoding::toUTF8($filePath);
400
- $fileName = basename($filePath);
401
- $this->FilterInfo->Files->Warning[] = array(
402
- 'name' => $fileName,
403
- 'dir' => pathinfo($filePath, PATHINFO_DIRNAME),
404
- 'path' => $filePath);
405
-
406
- }
407
-
408
- $fileSize = @filesize($filePath);
409
- $fileSize = empty($fileSize) ? 0 : $fileSize;
410
- $this->Size += $fileSize;
411
-
412
- if ($fileSize > DUPLICATOR_SCAN_WARNFILESIZE) {
413
- $ext = pathinfo($filePath, PATHINFO_EXTENSION);
414
- $this->FilterInfo->Files->Size[] = array(
415
- 'ubytes' => $fileSize,
416
- 'bytes' => DUP_Util::byteSize($fileSize, 0),
417
- 'name' => $fileName,
418
- 'dir' => pathinfo($filePath, PATHINFO_DIRNAME),
419
- 'path' => $filePath);
420
- }
421
- }
422
-
423
- //Try to repair utf8 paths
424
- foreach ($utf8_key_list as $key) {
425
- $this->Files[$key] = DUP_Encoding::toUTF8($this->Files[$key]);
426
- }
427
-
428
- //Remove unreadable items outside of main loop for performance
429
- if (count($unset_key_list)) {
430
- foreach ($unset_key_list as $key) {
431
- unset($this->Files[$key]);
432
- }
433
- $this->Files = array_values($this->Files);
434
- }
435
-
436
- }
437
-
438
- /**
439
- * Recursive function to get all directories in a wp install
440
- *
441
- * @notes:
442
- * Older PHP logic which is more stable on older version of PHP
443
- * NOTE RecursiveIteratorIterator is problematic on some systems issues include:
444
- * - error 'too many files open' for recursion
445
- * - $file->getExtension() is not reliable as it silently fails at least in php 5.2.17
446
- * - issues with when a file has a permission such as 705 and trying to get info (had to fallback to pathinfo)
447
- * - basic conclusion wait on the SPL libs until after php 5.4 is a requirments
448
- * - tight recursive loop use caution for speed
449
- *
450
- * @return array Returns an array of directories to include in the archive
451
- */
452
- private function getFileLists($path)
453
- {
454
- $handle = @opendir($path);
455
-
456
- if ($handle) {
457
- while (($file = readdir($handle)) !== false) {
458
-
459
- if ($file == '.' || $file == '..') {
460
- continue;
461
- }
462
-
463
- $fullPath = str_replace("\\", '/', "{$path}/{$file}");
464
-
465
- // @todo: Don't leave it like this. Convert into an option on the package to not follow symbolic links
466
- // if (is_dir($fullPath) && (is_link($fullPath) == false))
467
- if (is_dir($fullPath)) {
468
-
469
- $add = true;
470
- if(!is_link($fullPath)){
471
- foreach ($this->tmpFilterDirsAll as $key => $val) {
472
- $trimmedFilterDir = rtrim($val, '/');
473
- if ($fullPath == $trimmedFilterDir || strpos($fullPath, $trimmedFilterDir . '/') !== false) {
474
- $add = false;
475
- unset($this->tmpFilterDirsAll[$key]);
476
- break;
477
- }
478
- }
479
- }else{
480
- //Convert relative path of link to absolute path
481
- chdir($fullPath);
482
- $link_path = realpath(readlink($fullPath));
483
- chdir(dirname(__FILE__));
484
-
485
- $link_pos = strpos($fullPath,$link_path);
486
- if($link_pos === 0 && (strlen($link_path) < strlen($fullPath))){
487
- $add = false;
488
- $this->RecursiveLinks[] = $fullPath;
489
- $this->FilterDirsAll[] = $fullPath;
490
- }
491
- }
492
-
493
- if ($add) {
494
- $this->getFileLists($fullPath);
495
- $this->Dirs[] = $fullPath;
496
- }
497
- } else {
498
- if ( ! (in_array(pathinfo($file, PATHINFO_EXTENSION), $this->FilterExtsAll)
499
- || in_array($fullPath, $this->FilterFilesAll))) {
500
- $this->Files[] = $fullPath;
501
- }
502
- }
503
- }
504
- closedir($handle);
505
- }
506
- return $this->Dirs;
507
- }
508
-
509
- /**
510
- * Builds a tree for both file size warnings and name check warnings
511
- * The trees are used to apply filters from the scan screen
512
- *
513
- * @return null
514
- */
515
- private function setTreeFilters()
516
- {
517
- //-------------------------
518
- //SIZE TREE
519
- //BUILD: File Size tree
520
- $dir_group = DUP_Util::array_group_by($this->FilterInfo->Files->Size, "dir" );
521
- ksort($dir_group);
522
- foreach ($dir_group as $dir => $files) {
523
- $sum = 0;
524
- foreach ($files as $key => $value) {
525
- $sum += $value['ubytes'];
526
- }
527
-
528
- //Locate core paths, wp-admin, wp-includes, etc.
529
- $iscore = 0;
530
- foreach ($this->wpCorePaths as $core_dir) {
531
- if (strpos(DUP_Util::safePath($dir), DUP_Util::safePath($core_dir)) !== false) {
532
- $iscore = 1;
533
- break;
534
- }
535
- }
536
-
537
- $this->FilterInfo->TreeSize[] = array(
538
- 'size' => DUP_Util::byteSize($sum, 0),
539
- 'dir' => $dir,
540
- 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '', $dir),
541
- 'iscore' => $iscore,
542
- 'files' => $files
543
- );
544
- }
545
-
546
- //-------------------------
547
- //NAME TREE
548
- //BUILD: Warning tree for file names
549
- $dir_group = DUP_Util::array_group_by($this->FilterInfo->Files->Warning, "dir" );
550
- ksort($dir_group);
551
- foreach ($dir_group as $dir => $files) {
552
-
553
- //Locate core paths, wp-admin, wp-includes, etc.
554
- $iscore = 0;
555
- foreach ($this->wpCorePaths as $core_dir) {
556
- if (strpos($dir, $core_dir) !== false) {
557
- $iscore = 1;
558
- break;
559
- }
560
- }
561
-
562
- $this->FilterInfo->TreeWarning[] = array(
563
- 'dir' => $dir,
564
- 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '', $dir),
565
- 'iscore' => $iscore,
566
- 'count' => count($files),
567
- 'files' => $files);
568
- }
569
-
570
- //BUILD: Warning tree for dir names
571
- foreach ($this->FilterInfo->Dirs->Warning as $dir) {
572
- $add_dir = true;
573
- foreach ($this->FilterInfo->TreeWarning as $key => $value) {
574
- if ($value['dir'] == $dir) {
575
- $add_dir = false;
576
- break;
577
- }
578
- }
579
- if ($add_dir) {
580
-
581
- //Locate core paths, wp-admin, wp-includes, etc.
582
- $iscore = 0;
583
- foreach ($this->wpCorePaths as $core_dir) {
584
- if (strpos(DUP_Util::safePath($dir), DUP_Util::safePath($core_dir)) !== false) {
585
- $iscore = 1;
586
- break;
587
- }
588
- }
589
-
590
- $this->FilterInfo->TreeWarning[] = array(
591
- 'dir' => $dir,
592
- 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '', $dir),
593
- 'iscore' => $iscore,
594
- 'count' => 0);
595
- }
596
- }
597
-
598
- function _sortDir($a, $b){
599
- return strcmp($a["dir"], $b["dir"]);
600
- }
601
- usort($this->FilterInfo->TreeWarning, "_sortDir");
602
- }
603
-
604
-
605
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
+
5
+ require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/duparchive/class.pack.archive.duparchive.php');
6
+ require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.filters.php');
7
+ require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.zip.php');
8
+ require_once (DUPLICATOR_PLUGIN_PATH.'lib/forceutf8/Encoding.php');
9
+
10
+ /**
11
+ * Class for handling archive setup and build process
12
+ *
13
+ * Standard: PSR-2 (almost)
14
+ * @link http://www.php-fig.org/psr/psr-2
15
+ *
16
+ * @package DUP
17
+ * @subpackage classes/package
18
+ * @copyright (c) 2017, Snapcreek LLC
19
+ * @license https://opensource.org/licenses/GPL-3.0 GNU Public License
20
+ *
21
+ */
22
+ class DUP_Archive
23
+ {
24
+ //PUBLIC
25
+ public $FilterDirs;
26
+ public $FilterFiles;
27
+ public $FilterExts;
28
+ public $FilterDirsAll = array();
29
+ public $FilterFilesAll = array();
30
+ public $FilterExtsAll = array();
31
+ public $FilterOn;
32
+ public $ExportOnlyDB;
33
+ public $File;
34
+ public $Format;
35
+ public $PackDir;
36
+ public $Size = 0;
37
+ public $Dirs = array();
38
+ public $Files = array();
39
+ public $FilterInfo;
40
+ public $RecursiveLinks = array();
41
+
42
+ //PROTECTED
43
+ protected $Package;
44
+ private $tmpFilterDirsAll = array();
45
+ private $wpCorePaths = array();
46
+ private $wpCoreExactPaths = array();
47
+
48
+ /**
49
+ * Init this object
50
+ */
51
+ public function __construct($package)
52
+ {
53
+ $this->Package = $package;
54
+ $this->FilterOn = false;
55
+ $this->ExportOnlyDB = false;
56
+ $this->FilterInfo = new DUP_Archive_Filter_Info();
57
+
58
+ $rootPath = DUP_Util::safePath(rtrim(DUPLICATOR_WPROOTPATH, '//'));
59
+
60
+ $this->wpCorePaths[] = DUP_Util::safePath("{$rootPath}/wp-admin");
61
+ $this->wpCorePaths[] = DUP_Util::safePath(WP_CONTENT_DIR . "/uploads");
62
+ $this->wpCorePaths[] = DUP_Util::safePath(WP_CONTENT_DIR . "/languages");
63
+ $this->wpCorePaths[] = DUP_Util::safePath(get_theme_root());
64
+ $this->wpCorePaths[] = DUP_Util::safePath("{$rootPath}/wp-includes");
65
+
66
+ $this->wpCoreExactPaths[] = DUP_Util::safePath("{$rootPath}");
67
+ $this->wpCoreExactPaths[] = DUP_Util::safePath(WP_CONTENT_DIR);
68
+ }
69
+
70
+ /**
71
+ * Builds the archive based on the archive type
72
+ *
73
+ * @param obj $package The package object that started this process
74
+ *
75
+ * @return null
76
+ */
77
+ public function build($package, $rethrow_exception = false)
78
+ {
79
+ DUP_LOG::trace("b1");
80
+ $this->Package = $package;
81
+ if (!isset($this->PackDir) && !is_dir($this->PackDir)) throw new Exception("The 'PackDir' property must be a valid directory.");
82
+ if (!isset($this->File)) throw new Exception("A 'File' property must be set.");
83
+
84
+ DUP_LOG::trace("b2");
85
+ $completed = false;
86
+
87
+ switch ($this->Format) {
88
+ case 'TAR': break;
89
+ case 'TAR-GZIP': break;
90
+ case 'DAF':
91
+ $completed = DUP_DupArchive::create($this, $this->Package->BuildProgress, $this->Package);
92
+
93
+ $this->Package->Update();
94
+ break;
95
+
96
+ default:
97
+ if (class_exists('ZipArchive')) {
98
+ $this->Format = 'ZIP';
99
+ DUP_Zip::create($this, $this->Package->BuildProgress);
100
+ $completed = true;
101
+ }
102
+ break;
103
+ }
104
+
105
+ DUP_LOG::Trace("Completed build or build thread");
106
+
107
+ if($this->Package->BuildProgress === null) {
108
+ // Zip path
109
+ DUP_LOG::Trace("Completed Zip");
110
+ $storePath = "{$this->Package->StorePath}/{$this->File}";
111
+ $this->Size = @filesize($storePath);
112
+ $this->Package->setStatus(DUP_PackageStatus::ARCDONE);
113
+ } else if($completed) {
114
+ // Completed DupArchive path
115
+ DUP_LOG::Trace("Completed DupArchive build");
116
+ if ($this->Package->BuildProgress->failed) {
117
+ DUP_LOG::Trace("Error building DupArchive");
118
+ $this->Package->setStatus(DUP_PackageStatus::ERROR);
119
+ } else {
120
+ $filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->File}");
121
+ $this->Size = @filesize($filepath);
122
+ $this->Package->setStatus(DUP_PackageStatus::ARCDONE);
123
+ DUP_LOG::Trace("Done building archive");
124
+ }
125
+ } else {
126
+ DUP_Log::trace("DupArchive chunk done but package not completed yet");
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Builds a list of files and directories to be included in the archive
132
+ *
133
+ * Get the directory size recursively, but don't calc the snapshot directory, exclusion directories
134
+ * @link http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx Windows filename restrictions
135
+ *
136
+ * @return obj Returns a DUP_Archive object
137
+ */
138
+ public function getScannerData()
139
+ {
140
+ $this->createFilterInfo();
141
+ $rootPath = DUP_Util::safePath(rtrim(DUPLICATOR_WPROOTPATH, '//'));
142
+ $rootPath = (trim($rootPath) == '') ? '/' : $rootPath;
143
+
144
+ //If the root directory is a filter then skip it all
145
+ if (in_array($this->PackDir, $this->FilterDirsAll) || $this->Package->Archive->ExportOnlyDB) {
146
+ $this->Dirs = array();
147
+ } else {
148
+ $this->Dirs[] = $this->PackDir;
149
+ $this->getFileLists($rootPath);
150
+ $this->setDirFilters();
151
+ $this->setFileFilters();
152
+ $this->setTreeFilters();
153
+ }
154
+
155
+ $this->FilterDirsAll = array_merge($this->FilterDirsAll, $this->FilterInfo->Dirs->Unreadable);
156
+ $this->FilterFilesAll = array_merge($this->FilterFilesAll, $this->FilterInfo->Files->Unreadable);
157
+ sort($this->FilterDirsAll);
158
+
159
+ return $this;
160
+ }
161
+
162
+ /**
163
+ * Save any property of this class through reflection
164
+ *
165
+ * @param $property A valid public property in this class
166
+ * @param $value The value for the new dynamic property
167
+ *
168
+ * @return bool Returns true if the value has changed.
169
+ */
170
+ public function saveActiveItem($package, $property, $value)
171
+ {
172
+ $package = DUP_Package::getActive();
173
+ $reflectionClass = new ReflectionClass($package->Archive);
174
+ $reflectionClass->getProperty($property)->setValue($package->Archive, $value);
175
+ return update_option(DUP_Package::OPT_ACTIVE, $package);
176
+ }
177
+
178
+ /**
179
+ * Properly creates the directory filter list that is used for filtering directories
180
+ *
181
+ * @param string $dirs A semi-colon list of dir paths
182
+ * /path1_/path/;/path1_/path2/;
183
+ *
184
+ * @returns string A cleaned up list of directory filters
185
+ */
186
+ public function parseDirectoryFilter($dirs = "")
187
+ {
188
+ $dirs = str_replace(array("\n", "\t", "\r"), '', $dirs);
189
+ $filters = "";
190
+ $dir_array = array_unique(explode(";", $dirs));
191
+ $clean_array = array();
192
+ foreach ($dir_array as $val) {
193
+ if (strlen($val) >= 2) {
194
+ $clean_array[] = DUP_Util::safePath(trim(rtrim($val, "/\\"))) ;
195
+ }
196
+ }
197
+
198
+ if (count($clean_array)) {
199
+ $clean_array = array_unique($clean_array);
200
+ sort($clean_array);
201
+ $filters = implode(';', $clean_array) . ';';
202
+ }
203
+ return $filters ;
204
+ }
205
+
206
+ /**
207
+ * Properly creates the file filter list that is used for filtering files
208
+ *
209
+ * @param string $dirs A semi-colon list of dir paths
210
+ * /path1_/path/file1.ext;/path1_/path2/file2.ext;
211
+ *
212
+ * @returns string A cleaned up list of file filters
213
+ */
214
+ public function parseFileFilter($files = "")
215
+ {
216
+ $files = str_replace(array("\n", "\t", "\r"), '', $files);
217
+ $filters = "";
218
+ $file_array = array_unique(explode(";", $files));
219
+ $clean_array = array();
220
+ foreach ($file_array as $val) {
221
+ if (strlen($val) >= 2) {
222
+ $clean_array[] = DUP_Util::safePath(trim(rtrim($val, "/\\"))) ;
223
+ }
224
+ }
225
+
226
+ if (count($clean_array)) {
227
+ $clean_array = array_unique($clean_array);
228
+ sort($clean_array);
229
+ $filters = implode(';', $clean_array) . ';';
230
+ }
231
+ return $filters ;
232
+ }
233
+
234
+ /**
235
+ * Properly creates the extension filter list that is used for filtering extensions
236
+ *
237
+ * @param string $dirs A semi-colon list of dir paths
238
+ * .jpg;.zip;.gif;
239
+ *
240
+ * @returns string A cleaned up list of extension filters
241
+ */
242
+ public function parseExtensionFilter($extensions = "")
243
+ {
244
+ $filter_exts = "";
245
+ if (strlen($extensions) >= 1 && $extensions != ";") {
246
+ $filter_exts = str_replace(array(' ', '.'), '', $extensions);
247
+ $filter_exts = str_replace(",", ";", $filter_exts);
248
+ $filter_exts = DUP_Util::appendOnce($extensions, ";");
249
+ }
250
+ return $filter_exts;
251
+ }
252
+
253
+ /**
254
+ * Creates the filter info setup data used for filtering the archive
255
+ *
256
+ * @return null
257
+ */
258
+ private function createFilterInfo()
259
+ {
260
+ //FILTER: INSTANCE ITEMS
261
+ //Add the items generated at create time
262
+ if ($this->FilterOn) {
263
+ $this->FilterInfo->Dirs->Instance = array_map('DUP_Util::safePath', explode(";", $this->FilterDirs, -1));
264
+ $this->FilterInfo->Files->Instance = array_map('DUP_Util::safePath', explode(";", $this->FilterFiles, -1));
265
+ $this->FilterInfo->Exts->Instance = explode(";", $this->FilterExts, -1);
266
+ }
267
+
268
+ //FILTER: CORE ITMES
269
+ //Filters Duplicator free packages & All pro local directories
270
+ $wp_root = rtrim(DUPLICATOR_WPROOTPATH, '/');
271
+ $upload_dir = wp_upload_dir();
272
+ $upload_dir = isset($upload_dir['basedir']) ? basename($upload_dir['basedir']) : 'uploads';
273
+ $wp_content = str_replace("\\", "/", WP_CONTENT_DIR);
274
+ $wp_content_upload = "{$wp_content}/{$upload_dir}";
275
+ $this->FilterInfo->Dirs->Core = array(
276
+ //WP-ROOT
277
+ $wp_root . '/wp-snapshots',
278
+
279
+ //WP-CONTENT
280
+ $wp_content . '/backups-dup-pro',
281
+ $wp_content . '/ai1wm-backups',
282
+ $wp_content . '/backupwordpress',
283
+ $wp_content . '/content/cache',
284
+ $wp_content . '/contents/cache',
285
+ $wp_content . '/infinitewp/backups',
286
+ $wp_content . '/managewp/backups',
287
+ $wp_content . '/old-cache',
288
+ $wp_content . '/plugins/all-in-one-wp-migration/storage',
289
+ $wp_content . '/updraft',
290
+ $wp_content . '/wishlist-backup',
291
+ $wp_content . '/wfcache',
292
+ $wp_content . '/cache',
293
+ //WP-CONTENT-UPLOADS
294
+ $wp_content_upload . '/aiowps_backups',
295
+ $wp_content_upload . '/backupbuddy_temp',
296
+ $wp_content_upload . '/backupbuddy_backups',
297
+ $wp_content_upload . '/ithemes-security/backups',
298
+ $wp_content_upload . '/mainwp/backup',
299
+ $wp_content_upload . '/pb_backupbuddy',
300
+ $wp_content_upload . '/snapshots',
301
+ $wp_content_upload . '/sucuri',
302
+ $wp_content_upload . '/wp-clone',
303
+ $wp_content_upload . '/wp_all_backup',
304
+ $wp_content_upload . '/wpbackitup_backups'
305
+ );
306
+
307
+ if ($GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON']) {
308
+ $this->FilterInfo->Files->Global = $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS'];
309
+ }
310
+
311
+ $this->FilterDirsAll = array_merge($this->FilterInfo->Dirs->Instance, $this->FilterInfo->Dirs->Core);
312
+ $this->FilterExtsAll = array_merge($this->FilterInfo->Exts->Instance, $this->FilterInfo->Exts->Core);
313
+ $this->FilterFilesAll = array_merge($this->FilterInfo->Files->Instance, $this->FilterInfo->Files->Global);
314
+
315
+ $this->FilterFilesAll[] = DUPLICATOR_WPROOTPATH . '.htaccess';
316
+ $this->FilterFilesAll[] = DUPLICATOR_WPROOTPATH . 'web.config';
317
+ $this->FilterFilesAll[] = DUPLICATOR_WPROOTPATH . 'wp-config.php';
318
+
319
+ $this->tmpFilterDirsAll = $this->FilterDirsAll;
320
+
321
+ //PHP 5 on windows decode patch
322
+ if (! DUP_Util::$PHP7_plus && DUP_Util::isWindows()) {
323
+ foreach ($this->tmpFilterDirsAll as $key => $value) {
324
+ if ( preg_match('/[^\x20-\x7f]/', $value)) {
325
+ $this->tmpFilterDirsAll[$key] = utf8_decode($value);
326
+ }
327
+ }
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Get All Directories then filter
333
+ *
334
+ * @return null
335
+ */
336
+ private function setDirFilters()
337
+ {
338
+ $this->FilterInfo->Dirs->Warning = array();
339
+ $this->FilterInfo->Dirs->Unreadable = array();
340
+ $this->FilterInfo->Dirs->AddonSites = array();
341
+
342
+ $utf8_key_list = array();
343
+ $unset_key_list = array();
344
+
345
+ //Filter directories invalid test checks for:
346
+ // - characters over 250
347
+ // - invlaid characters
348
+ // - empty string
349
+ // - directories ending with period (Windows incompatable)
350
+ foreach ($this->Dirs as $key => $val) {
351
+ $name = basename($val);
352
+
353
+ //Dir is not readble remove flag for removal
354
+ if (! is_readable($this->Dirs[$key])) {
355
+ $unset_key_list[] = $key;
356
+ $this->FilterInfo->Dirs->Unreadable[] = DUP_Encoding::toUTF8($val);
357
+ }
358
+
359
+ //Locate invalid directories and warn
360
+ $invalid_test = strlen($val) > 244
361
+ || preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $name)
362
+ || trim($name) == ''
363
+ || (strrpos($name, '.') == strlen($name) - 1 && substr($name, -1) == '.')
364
+ || preg_match('/[^\x20-\x7f]/', $name);
365
+
366
+ if ($invalid_test) {
367
+ $utf8_key_list[] = $key;
368
+ $this->FilterInfo->Dirs->Warning[] = DUP_Encoding::toUTF8($val);
369
+ }
370
+
371
+ //Check for other WordPress installs
372
+ if ($name === 'wp-admin') {
373
+ $parent_dir = realpath(dirname($this->Dirs[$key]));
374
+ if ($parent_dir != realpath(DUPLICATOR_WPROOTPATH)) {
375
+ if (file_exists("$parent_dir/wp-includes")) {
376
+ if (file_exists("$parent_dir/wp-config.php")) {
377
+ // Ensure we aren't adding any critical directories
378
+ $parent_name = basename($parent_dir);
379
+ if (($parent_name != 'wp-includes') && ($parent_name != 'wp-content') && ($parent_name != 'wp-admin')) {
380
+ $this->FilterInfo->Dirs->AddonSites[] = str_replace("\\", '/',$parent_dir);
381
+ }
382
+ }
383
+ }
384
+ }
385
+ }
386
+
387
+ }
388
+
389
+ //Try to repair utf8 paths
390
+ foreach ($utf8_key_list as $key) {
391
+ $this->Dirs[$key] = DUP_Encoding::toUTF8($this->Dirs[$key]);
392
+ }
393
+
394
+ //Remove unreadable items outside of main loop for performance
395
+ if (count($unset_key_list)) {
396
+ foreach ($unset_key_list as $key) {
397
+ unset($this->Dirs[$key]);
398
+ }
399
+ $this->Dirs = array_values($this->Dirs);
400
+ }
401
+
402
+ }
403
+
404
+ /**
405
+ * Get all files and filter out error prone subsets
406
+ *
407
+ * @return null
408
+ */
409
+ private function setFileFilters()
410
+ {
411
+ //Init for each call to prevent concatination from stored entity objects
412
+ $this->Size = 0;
413
+ $this->FilterInfo->Files->Size = array();
414
+ $this->FilterInfo->Files->Warning = array();
415
+ $this->FilterInfo->Files->Unreadable = array();
416
+
417
+ $utf8_key_list = array();
418
+ $unset_key_list = array();
419
+
420
+ foreach ($this->Files as $key => $filePath) {
421
+
422
+ $fileName = basename($filePath);
423
+
424
+ if (! is_readable($filePath)) {
425
+ $unset_key_list[] = $key;
426
+ $this->FilterInfo->Files->Unreadable[] = $filePath;
427
+ continue;
428
+ }
429
+
430
+ $invalid_test = strlen($filePath) > 250
431
+ || preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $fileName)
432
+ || trim($fileName) == ""
433
+ || preg_match('/[^\x20-\x7f]/', $fileName);
434
+
435
+ if ($invalid_test) {
436
+ $utf8_key_list[] = $key;
437
+ $filePath = DUP_Encoding::toUTF8($filePath);
438
+ $fileName = basename($filePath);
439
+ $this->FilterInfo->Files->Warning[] = array(
440
+ 'name' => $fileName,
441
+ 'dir' => pathinfo($filePath, PATHINFO_DIRNAME),
442
+ 'path' => $filePath);
443
+
444
+ }
445
+
446
+ $fileSize = @filesize($filePath);
447
+ $fileSize = empty($fileSize) ? 0 : $fileSize;
448
+ $this->Size += $fileSize;
449
+
450
+ if ($fileSize > DUPLICATOR_SCAN_WARNFILESIZE) {
451
+ $ext = pathinfo($filePath, PATHINFO_EXTENSION);
452
+ $this->FilterInfo->Files->Size[] = array(
453
+ 'ubytes' => $fileSize,
454
+ 'bytes' => DUP_Util::byteSize($fileSize, 0),
455
+ 'name' => $fileName,
456
+ 'dir' => pathinfo($filePath, PATHINFO_DIRNAME),
457
+ 'path' => $filePath);
458
+ }
459
+ }
460
+
461
+ //Try to repair utf8 paths
462
+ foreach ($utf8_key_list as $key) {
463
+ $this->Files[$key] = DUP_Encoding::toUTF8($this->Files[$key]);
464
+ }
465
+
466
+ //Remove unreadable items outside of main loop for performance
467
+ if (count($unset_key_list)) {
468
+ foreach ($unset_key_list as $key) {
469
+ unset($this->Files[$key]);
470
+ }
471
+ $this->Files = array_values($this->Files);
472
+ }
473
+
474
+ }
475
+
476
+ /**
477
+ * Recursive function to get all directories in a wp install
478
+ *
479
+ * @notes:
480
+ * Older PHP logic which is more stable on older version of PHP
481
+ * NOTE RecursiveIteratorIterator is problematic on some systems issues include:
482
+ * - error 'too many files open' for recursion
483
+ * - $file->getExtension() is not reliable as it silently fails at least in php 5.2.17
484
+ * - issues with when a file has a permission such as 705 and trying to get info (had to fallback to pathinfo)
485
+ * - basic conclusion wait on the SPL libs until after php 5.4 is a requirments
486
+ * - tight recursive loop use caution for speed
487
+ *
488
+ * @return array Returns an array of directories to include in the archive
489
+ */
490
+ private function getFileLists($path)
491
+ {
492
+ $handle = @opendir($path);
493
+
494
+ if ($handle) {
495
+ while (($file = readdir($handle)) !== false) {
496
+
497
+ if ($file == '.' || $file == '..') {
498
+ continue;
499
+ }
500
+
501
+ $fullPath = str_replace("\\", '/', "{$path}/{$file}");
502
+
503
+ // @todo: Don't leave it like this. Convert into an option on the package to not follow symbolic links
504
+ // if (is_dir($fullPath) && (is_link($fullPath) == false))
505
+ if (is_dir($fullPath)) {
506
+
507
+ $add = true;
508
+ if(!is_link($fullPath)){
509
+ foreach ($this->tmpFilterDirsAll as $key => $val) {
510
+ $trimmedFilterDir = rtrim($val, '/');
511
+ if ($fullPath == $trimmedFilterDir || strpos($fullPath, $trimmedFilterDir . '/') !== false) {
512
+ $add = false;
513
+ unset($this->tmpFilterDirsAll[$key]);
514
+ break;
515
+ }
516
+ }
517
+ }else{
518
+ //Convert relative path of link to absolute path
519
+ chdir($fullPath);
520
+ $link_path = realpath(readlink($fullPath));
521
+ chdir(dirname(__FILE__));
522
+
523
+ $link_pos = strpos($fullPath,$link_path);
524
+ if($link_pos === 0 && (strlen($link_path) < strlen($fullPath))){
525
+ $add = false;
526
+ $this->RecursiveLinks[] = $fullPath;
527
+ $this->FilterDirsAll[] = $fullPath;
528
+ }
529
+ }
530
+
531
+ if ($add) {
532
+ $this->getFileLists($fullPath);
533
+ $this->Dirs[] = $fullPath;
534
+ }
535
+ } else {
536
+ if ( ! (in_array(pathinfo($file, PATHINFO_EXTENSION), $this->FilterExtsAll)
537
+ || in_array($fullPath, $this->FilterFilesAll)
538
+ || in_array($file, $this->FilterFilesAll))) {
539
+ $this->Files[] = $fullPath;
540
+ }
541
+ }
542
+ }
543
+ closedir($handle);
544
+ }
545
+ return $this->Dirs;
546
+ }
547
+
548
+ /**
549
+ * Builds a tree for both file size warnings and name check warnings
550
+ * The trees are used to apply filters from the scan screen
551
+ *
552
+ * @return null
553
+ */
554
+ private function setTreeFilters()
555
+ {
556
+ //-------------------------
557
+ //SIZE TREE
558
+ //BUILD: File Size tree
559
+ $dir_group = DUP_Util::array_group_by($this->FilterInfo->Files->Size, "dir" );
560
+ ksort($dir_group);
561
+ foreach ($dir_group as $dir => $files) {
562
+ $sum = 0;
563
+ foreach ($files as $key => $value) {
564
+ $sum += $value['ubytes'];
565
+ }
566
+
567
+ //Locate core paths, wp-admin, wp-includes, etc.
568
+ $iscore = 0;
569
+ foreach ($this->wpCorePaths as $core_dir) {
570
+ if (strpos(DUP_Util::safePath($dir), DUP_Util::safePath($core_dir)) !== false) {
571
+ $iscore = 1;
572
+ break;
573
+ }
574
+ }
575
+ // Check root and content exact dir
576
+ if (!$iscore) {
577
+ if (in_array($dir, $this->wpCoreExactPaths)) {
578
+ $iscore = 1;
579
+ }
580
+ }
581
+
582
+ $this->FilterInfo->TreeSize[] = array(
583
+ 'size' => DUP_Util::byteSize($sum, 0),
584
+ 'dir' => $dir,
585
+ 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '', $dir),
586
+ 'iscore' => $iscore,
587
+ 'files' => $files
588
+ );
589
+ }
590
+
591
+ //-------------------------
592
+ //NAME TREE
593
+ //BUILD: Warning tree for file names
594
+ $dir_group = DUP_Util::array_group_by($this->FilterInfo->Files->Warning, "dir" );
595
+ ksort($dir_group);
596
+ foreach ($dir_group as $dir => $files) {
597
+
598
+ //Locate core paths, wp-admin, wp-includes, etc.
599
+ $iscore = 0;
600
+ foreach ($this->wpCorePaths as $core_dir) {
601
+ if (strpos($dir, $core_dir) !== false) {
602
+ $iscore = 1;
603
+ break;
604
+ }
605
+ }
606
+ // Check root and content exact dir
607
+ if (!$iscore) {
608
+ if (in_array($dir, $this->wpCoreExactPaths)) {
609
+ $iscore = 1;
610
+ }
611
+ }
612
+
613
+ $this->FilterInfo->TreeWarning[] = array(
614
+ 'dir' => $dir,
615
+ 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '', $dir),
616
+ 'iscore' => $iscore,
617
+ 'count' => count($files),
618
+ 'files' => $files);
619
+ }
620
+
621
+ //BUILD: Warning tree for dir names
622
+ foreach ($this->FilterInfo->Dirs->Warning as $dir) {
623
+ $add_dir = true;
624
+ foreach ($this->FilterInfo->TreeWarning as $key => $value) {
625
+ if ($value['dir'] == $dir) {
626
+ $add_dir = false;
627
+ break;
628
+ }
629
+ }
630
+ if ($add_dir) {
631
+
632
+ //Locate core paths, wp-admin, wp-includes, etc.
633
+ $iscore = 0;
634
+ foreach ($this->wpCorePaths as $core_dir) {
635
+ if (strpos(DUP_Util::safePath($dir), DUP_Util::safePath($core_dir)) !== false) {
636
+ $iscore = 1;
637
+ break;
638
+ }
639
+ }
640
+ // Check root and content exact dir
641
+ if (!$iscore) {
642
+ if (in_array($dir, $this->wpCoreExactPaths)) {
643
+ $iscore = 1;
644
+ }
645
+ }
646
+
647
+ $this->FilterInfo->TreeWarning[] = array(
648
+ 'dir' => $dir,
649
+ 'sdir' => str_replace(DUPLICATOR_WPROOTPATH, '', $dir),
650
+ 'iscore' => $iscore,
651
+ 'count' => 0);
652
+ }
653
+ }
654
+
655
+ function _sortDir($a, $b){
656
+ return strcmp($a["dir"], $b["dir"]);
657
+ }
658
+ usort($this->FilterInfo->TreeWarning, "_sortDir");
659
+ }
660
+
661
+ }
classes/package/class.pack.archive.zip.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
- if (!defined('DUPLICATOR_VERSION')) exit; // Exit if accessed directly
 
 
3
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.php');
4
 
5
  /**
@@ -22,7 +24,7 @@ class DUP_Zip extends DUP_Archive
22
  /**
23
  * Creates the zip file and adds the SQL file to the archive
24
  */
25
- public static function create(DUP_Archive $archive)
26
  {
27
  try {
28
  $timerAllStart = DUP_Util::getMicrotime();
@@ -51,7 +53,13 @@ class DUP_Zip extends DUP_Archive
51
  DUP_Log::Info("********************************************************************************");
52
  $isZipOpen = (self::$zipArchive->open(self::$zipPath, ZIPARCHIVE::CREATE) === TRUE);
53
  if (!$isZipOpen) {
54
- DUP_Log::Error("Cannot open zip file with PHP ZipArchive.", "Path location [".self::$zipPath."]");
 
 
 
 
 
 
55
  }
56
  DUP_Log::Info("ARCHIVE DIR: ".self::$compressDir);
57
  DUP_Log::Info("ARCHIVE FILE: ".basename(self::$zipPath));
@@ -66,12 +74,17 @@ class DUP_Zip extends DUP_Archive
66
  DUP_Log::Info("STATS:\tDirs ".self::$scanReport->ARC->DirCount." | Files ".self::$scanReport->ARC->FileCount);
67
 
68
  //ADD SQL
69
- $sqlArkFilePath = $archive->Package->getSqlArkFilePath();
70
- $isSQLInZip = self::$zipArchive->addFile(self::$sqlPath, $sqlArkFilePath);
71
  if ($isSQLInZip) {
72
  DUP_Log::Info("SQL ADDED: ".basename(self::$sqlPath));
73
  } else {
74
- DUP_Log::Error("Unable to add ".$sqlArkFilePath." to archive.", "SQL File Path [".self::$sqlath."]");
 
 
 
 
 
75
  }
76
  self::$zipArchive->close();
77
  self::$zipArchive->open(self::$zipPath, ZipArchive::CREATE);
@@ -85,7 +98,7 @@ class DUP_Zip extends DUP_Archive
85
  } else {
86
  //Don't warn when dirtory is the root path
87
  if (strcmp($dir, rtrim(self::$compressDir, '/')) != 0) {
88
- $dir_path = strlen($dir) ? "[".esc_html($dir)."]" : "[Read Error] - last successful read was: [{$lastDirSuccess}]";
89
  $info .= "DIR: {$dir_path}\n";
90
  }
91
  }
@@ -98,12 +111,14 @@ class DUP_Zip extends DUP_Archive
98
  }
99
 
100
  /* ZIP FILES: Network Flush
101
- * This allows the process to not timeout on fcgi
102
  * setups that need a response every X seconds */
 
103
  $info = '';
104
  if (self::$networkFlush) {
105
  foreach (self::$scanReport->ARC->Files as $file) {
106
  if (is_readable($file) && self::$zipArchive->addFile($file, ltrim(str_replace(self::$compressDir, '', $file), '/'))) {
 
107
  self::$limitItems++;
108
  self::$countFiles++;
109
  } else {
@@ -118,6 +133,12 @@ class DUP_Zip extends DUP_Archive
118
  DUP_Util::fcgiFlush();
119
  DUP_Log::Info("Items archived [{$sumItems}] flushing response.");
120
  }
 
 
 
 
 
 
121
  }
122
  }
123
  //Normal
@@ -128,6 +149,12 @@ class DUP_Zip extends DUP_Archive
128
  } else {
129
  $info .= "FILE: [{$file}]\n";
130
  }
 
 
 
 
 
 
131
  }
132
  }
133
 
@@ -144,8 +171,18 @@ class DUP_Zip extends DUP_Archive
144
  //LOG FINAL RESULTS
145
  DUP_Util::fcgiFlush();
146
  $zipCloseResult = self::$zipArchive->close();
147
- ($zipCloseResult) ? DUP_Log::Info("COMPRESSION RESULT: '{$zipCloseResult}'") : DUP_Log::Error("ZipArchive close failure.",
148
- "This hosted server may have a disk quota limit.\nCheck to make sure this archive file can be stored.");
 
 
 
 
 
 
 
 
 
 
149
 
150
  $timerAllEnd = DUP_Util::getMicrotime();
151
  $timerAllSum = DUP_Util::elapsedTime($timerAllEnd, $timerAllStart);
@@ -153,11 +190,15 @@ class DUP_Zip extends DUP_Archive
153
 
154
  self::$zipFileSize = @filesize(self::$zipPath);
155
  DUP_Log::Info("COMPRESSED SIZE: ".DUP_Util::byteSize(self::$zipFileSize));
156
- DUP_Log::Info("ARCHIVE RUNTIME: ".esc_html($timerAllSum));
157
- DUP_Log::Info("MEMORY STACK: ".esc_html(DUP_Server::getPHPMemory()));
158
  } catch (Exception $e) {
159
- DUP_Log::Error("Runtime error in class.pack.archive.zip.php constructor.", "Exception: {$e}");
 
 
 
 
 
160
  }
161
  }
162
- }
163
- ?>
1
  <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
+
5
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.php');
6
 
7
  /**
24
  /**
25
  * Creates the zip file and adds the SQL file to the archive
26
  */
27
+ public static function create(DUP_Archive $archive, $buildProgress)
28
  {
29
  try {
30
  $timerAllStart = DUP_Util::getMicrotime();
53
  DUP_Log::Info("********************************************************************************");
54
  $isZipOpen = (self::$zipArchive->open(self::$zipPath, ZIPARCHIVE::CREATE) === TRUE);
55
  if (!$isZipOpen) {
56
+ $error_message = "Cannot open zip file with PHP ZipArchive.";
57
+
58
+ $buildProgress->set_failed($error_message);
59
+
60
+ DUP_Log::Error($error_message, "Path location [".self::$zipPath."]", Dup_ErrorBehavior::LogOnly);
61
+
62
+ return;
63
  }
64
  DUP_Log::Info("ARCHIVE DIR: ".self::$compressDir);
65
  DUP_Log::Info("ARCHIVE FILE: ".basename(self::$zipPath));
74
  DUP_Log::Info("STATS:\tDirs ".self::$scanReport->ARC->DirCount." | Files ".self::$scanReport->ARC->FileCount);
75
 
76
  //ADD SQL
77
+ $sql_ark_file_path = $archive->Package->getSqlArkFilePath();
78
+ $isSQLInZip = self::$zipArchive->addFile(self::$sqlPath, $sql_ark_file_path);
79
  if ($isSQLInZip) {
80
  DUP_Log::Info("SQL ADDED: ".basename(self::$sqlPath));
81
  } else {
82
+ $error_message = "Unable to add database.sql to archive.";
83
+
84
+ DUP_Log::Error($error_message, "SQL File Path [".self::$sqlath."]", Dup_ErrorBehavior::LogOnly);
85
+
86
+ $buildProgress->set_failed($error_message);
87
+ return;
88
  }
89
  self::$zipArchive->close();
90
  self::$zipArchive->open(self::$zipPath, ZipArchive::CREATE);
98
  } else {
99
  //Don't warn when dirtory is the root path
100
  if (strcmp($dir, rtrim(self::$compressDir, '/')) != 0) {
101
+ $dir_path = strlen($dir) ? "[{$dir}]" : "[Read Error] - last successful read was: [{$lastDirSuccess}]";
102
  $info .= "DIR: {$dir_path}\n";
103
  }
104
  }
111
  }
112
 
113
  /* ZIP FILES: Network Flush
114
+ * This allows the process to not timeout on fcgi
115
  * setups that need a response every X seconds */
116
+ $totalFileCount = count(self::$scanReport->ARC->Files);
117
  $info = '';
118
  if (self::$networkFlush) {
119
  foreach (self::$scanReport->ARC->Files as $file) {
120
  if (is_readable($file) && self::$zipArchive->addFile($file, ltrim(str_replace(self::$compressDir, '', $file), '/'))) {
121
+ Dup_Log::Info("Adding {$file} to zip");
122
  self::$limitItems++;
123
  self::$countFiles++;
124
  } else {
133
  DUP_Util::fcgiFlush();
134
  DUP_Log::Info("Items archived [{$sumItems}] flushing response.");
135
  }
136
+
137
+ if(self::$countFiles % 500 == 0) {
138
+ // Every so many files update the status so the UI can display
139
+ $archive->Package->Status = SnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCSTART, DUP_PackageStatus::ARCVALIDATION, $totalFileCount, self::$countFiles);
140
+ $archive->Package->update();
141
+ }
142
  }
143
  }
144
  //Normal
149
  } else {
150
  $info .= "FILE: [{$file}]\n";
151
  }
152
+
153
+ if(self::$countFiles % 500 == 0) {
154
+ // Every so many files update the status so the UI can display
155
+ $archive->Package->Status = SnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCSTART, DUP_PackageStatus::ARCVALIDATION, $totalFileCount, self::$countFiles);
156
+ $archive->Package->update();
157
+ }
158
  }
159
  }
160
 
171
  //LOG FINAL RESULTS
172
  DUP_Util::fcgiFlush();
173
  $zipCloseResult = self::$zipArchive->close();
174
+ if($zipCloseResult) {
175
+ DUP_Log::Info("COMPRESSION RESULT: '{$zipCloseResult}'");
176
+ } else {
177
+ $error_message = "ZipArchive close failure.";
178
+
179
+ DUP_Log::Error($error_message,
180
+ "This hosted server may have a disk quota limit.\nCheck to make sure this archive file can be stored.",
181
+ Dup_ErrorBehavior::LogOnly);
182
+
183
+ $buildProgress->set_failed($error_message);
184
+ return;
185
+ }
186
 
187
  $timerAllEnd = DUP_Util::getMicrotime();
188
  $timerAllSum = DUP_Util::elapsedTime($timerAllEnd, $timerAllStart);
190
 
191
  self::$zipFileSize = @filesize(self::$zipPath);
192
  DUP_Log::Info("COMPRESSED SIZE: ".DUP_Util::byteSize(self::$zipFileSize));
193
+ DUP_Log::Info("ARCHIVE RUNTIME: {$timerAllSum}");
194
+ DUP_Log::Info("MEMORY STACK: ".DUP_Server::getPHPMemory());
195
  } catch (Exception $e) {
196
+ $error_message = "Runtime error in class.pack.archive.zip.php constructor.";
197
+
198
+ DUP_Log::Error($error_message, "Exception: {$e}", Dup_ErrorBehavior::LogOnly);
199
+
200
+ $buildProgress->set_failed($error_message);
201
+ return;
202
  }
203
  }
204
+ }
 
classes/package/class.pack.database.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php
2
- if (!defined('DUPLICATOR_VERSION')) exit; // Exit if accessed directly
 
3
 
4
  class DUP_Database
5
  {
@@ -34,15 +35,16 @@ class DUP_Database
34
  /**
35
  * Build the database script
36
  *
37
- * @param obj $package A reference to the package that this database object belongs in
38
  *
39
  * @return null
40
  */
41
- public function build($package)
42
  {
43
  try {
44
 
45
  $this->Package = $package;
 
46
 
47
  $time_start = DUP_Util::getMicrotime();
48
  $this->Package->setStatus(DUP_PackageStatus::DBSTART);
@@ -69,11 +71,19 @@ class DUP_Database
69
 
70
  //Reserved file found
71
  if (file_exists($reserved_db_filepath)) {
72
- DUP_Log::Error("Reserverd SQL file detected",
 
 
 
 
 
 
73
  "The file database.sql was found at [{$reserved_db_filepath}].\n"
74
- ."\tPlease remove/rename this file to continue with the package creation.");
75
  }
76
 
 
 
77
  switch ($mode) {
78
  case 'MYSQLDUMP':
79
  $this->mysqlDump($mysqlDumpPath);
@@ -87,25 +97,37 @@ class DUP_Database
87
  $time_end = DUP_Util::getMicrotime();
88
  $time_sum = DUP_Util::elapsedTime($time_end, $time_start);
89
 
90
- //File below 10k will be incomplete
91
  $sql_file_size = filesize($this->dbStorePath);
92
  DUP_Log::Info("SQL FILE SIZE: ".DUP_Util::byteSize($sql_file_size)." ({$sql_file_size})");
93
- if ($sql_file_size < 10000) {
94
- DUP_Log::Error("SQL file size too low.", "File does not look complete. Check permission on file and parent directory at [{$this->dbStorePath}]");
 
 
 
 
 
 
 
 
 
 
95
  }
96
 
97
  DUP_Log::Info("SQL FILE TIME: ".date("Y-m-d H:i:s"));
98
  DUP_Log::Info("SQL RUNTIME: {$time_sum}");
99
 
100
  $this->Size = @filesize($this->dbStorePath);
 
101
  $this->Package->setStatus(DUP_PackageStatus::DBDONE);
102
  } catch (Exception $e) {
103
- DUP_Log::Error("Runtime error in DUP_Database::Build", "Exception: {$e}");
 
104
  }
105
  }
106
 
107
  /**
108
- * Get the database meta-data suc as tables as all there details
109
  *
110
  * @return array Returns an array full of meta-data about the database
111
  */
@@ -186,6 +208,7 @@ class DUP_Database
186
  $info['Status']['TBL_Rows'] = ($tblRowsFound) ? 'Warn' : 'Good';
187
  $info['Status']['TBL_Size'] = ($tblSizeFound) ? 'Warn' : 'Good';
188
 
 
189
  $info['Size'] = DUP_Util::byteSize($info['Size']) or "unknown";
190
  $info['Rows'] = number_format($info['Rows']) or "unknown";
191
  $info['TableList'] = $info['TableList'] or "unknown";
@@ -197,12 +220,12 @@ class DUP_Database
197
  /**
198
  * Build the database script using mysqldump
199
  *
200
- * @return bool Returns true if the sql script was succesfully created
201
  */
202
  private function mysqlDump($exePath)
203
  {
204
-
205
  global $wpdb;
 
206
 
207
  $host = explode(':', DB_HOST);
208
  $host = reset($host);
@@ -216,6 +239,11 @@ class DUP_Database
216
  $cmd .= ' --single-transaction';
217
  $cmd .= ' --hex-blob';
218
  $cmd .= ' --skip-add-drop-table';
 
 
 
 
 
219
 
220
  //Compatibility mode
221
  if ($mysqlcompat_on) {
@@ -227,6 +255,7 @@ class DUP_Database
227
  $tables = $wpdb->get_col('SHOW TABLES');
228
  $filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : null;
229
  $tblAllCount = count($tables);
 
230
 
231
  if (is_array($filterTables) && $this->FilterOn) {
232
  foreach ($tables as $key => $val) {
@@ -238,33 +267,113 @@ class DUP_Database
238
  }
239
 
240
  $cmd .= ' -u '.escapeshellarg(DB_USER);
241
- if(DUP_Util::isWindows())
242
- $cmd .= (DB_PASSWORD) ? ' -p'.escapeshellcmd(DB_PASSWORD) : '';
243
- else
244
- $cmd .= (DB_PASSWORD) ? ' -p'.escapeshellarg(DB_PASSWORD) : '';
245
-
246
  $cmd .= ' -h '.escapeshellarg($host);
247
  $cmd .= (!empty($port) && is_numeric($port) ) ?
248
  ' -P '.$port : '';
249
- $cmd .= ' -r '.escapeshellarg($this->dbStorePath);
 
 
 
 
 
 
250
  $cmd .= ' '.escapeshellarg(DB_NAME);
251
  $cmd .= ' 2>&1';
252
- $output = shell_exec($cmd);
 
 
 
 
 
 
 
 
 
253
 
254
- // Password bug > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
255
- if (trim($output) === 'Warning: Using a password on the command line interface can be insecure.') {
256
- $output = '';
257
- }
258
- $output = (strlen($output)) ? $output : "Ran from {$exePath}";
 
 
 
 
 
259
 
260
- $tblCreateCount = count($tables);
261
- $tblFilterCount = $tblAllCount - $tblCreateCount;
 
 
 
 
 
 
 
 
 
 
 
262
 
263
- //DEBUG
264
- //DUP_Log::Info("COMMAND: {$cmd}");
265
- DUP_Log::Info("FILTERED: [{$this->FilterTables}]");
266
- DUP_Log::Info("RESPONSE: {$output}");
267
- DUP_Log::Info("TABLES: total:{$tblAllCount} | filtered:{$tblFilterCount} | create:{$tblCreateCount}");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
 
269
  $sql_footer = "\n\n/* Duplicator WordPress Timestamp: ".date("Y-m-d H:i:s")."*/\n";
270
  $sql_footer .= "/* ".DUPLICATOR_DB_EOF_MARKER." */\n";
@@ -276,21 +385,22 @@ class DUP_Database
276
  /**
277
  * Build the database script using php
278
  *
279
- * @return bool Returns true if the sql script was succesfully created
280
  */
281
  private function phpDump()
282
  {
283
-
284
  global $wpdb;
285
-
286
  $wpdb->query("SET session wait_timeout = ".DUPLICATOR_DB_MAX_TIME);
287
  $handle = fopen($this->dbStorePath, 'w+');
288
- $tables = $wpdb->get_col('SHOW TABLES');
289
-
290
  $filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : null;
291
  $tblAllCount = count($tables);
 
292
  $qryLimit = DUP_Settings::Get('package_phpdump_qrylimit');
293
-
294
  if (is_array($filterTables) && $this->FilterOn) {
295
  foreach ($tables as $key => $val) {
296
  if (in_array($tables[$key], $filterTables)) {
@@ -300,43 +410,75 @@ class DUP_Database
300
  }
301
  $tblCreateCount = count($tables);
302
  $tblFilterCount = $tblAllCount - $tblCreateCount;
303
-
304
  DUP_Log::Info("TABLES: total:{$tblAllCount} | filtered:{$tblFilterCount} | create:{$tblCreateCount}");
305
  DUP_Log::Info("FILTERED: [{$this->FilterTables}]");
306
-
307
- //Added 'NO_AUTO_VALUE_ON_ZERO' at plugin version 1.2.12 to fix :
308
- //**ERROR** database error write 'Invalid default value for for older mysql versions
309
  $sql_header = "/* DUPLICATOR-LITE (PHP BUILD MODE) MYSQL SCRIPT CREATED ON : ".@date("Y-m-d H:i:s")." */\n\n";
310
- $sql_header .= "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n\n";
311
  $sql_header .= "SET FOREIGN_KEY_CHECKS = 0;\n\n";
312
  fwrite($handle, $sql_header);
313
-
314
  //BUILD CREATES:
315
  //All creates must be created before inserts do to foreign key constraints
316
  foreach ($tables as $table) {
 
317
  //$sql_del = ($GLOBALS['duplicator_opts']['dbadd_drop']) ? "DROP TABLE IF EXISTS {$table};\n\n" : "";
318
  //@fwrite($handle, $sql_del);
319
  $create = $wpdb->get_row("SHOW CREATE TABLE `{$table}`", ARRAY_N);
320
- @fwrite($handle, "{$create[1]};\n\n");
 
 
321
  }
322
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  //BUILD INSERTS:
324
  //Create Insert in 100 row increments to better handle memory
325
  foreach ($tables as $table) {
326
-
 
 
 
 
 
 
327
  $row_count = $wpdb->get_var("SELECT Count(*) FROM `{$table}`");
328
  //DUP_Log::Info("{$table} ({$row_count})");
329
-
330
  if ($row_count > $qryLimit) {
331
  $row_count = ceil($row_count / $qryLimit);
332
  } else if ($row_count > 0) {
333
  $row_count = 1;
334
  }
335
-
336
  if ($row_count >= 1) {
337
  fwrite($handle, "\n/* INSERT TABLE DATA: {$table} */\n");
338
  }
339
-
 
 
340
  for ($i = 0; $i < $row_count; $i++) {
341
  $sql = "";
342
  $limit = $i * $qryLimit;
@@ -344,16 +486,16 @@ class DUP_Database
344
  $rows = $wpdb->get_results($query, ARRAY_A);
345
  if (is_array($rows)) {
346
  foreach ($rows as $row) {
347
- $sql .= "INSERT INTO `{$table}` VALUES(";
348
  $num_values = count($row);
349
  $num_counter = 1;
350
  foreach ($row as $value) {
351
  if (is_null($value) || !isset($value)) {
352
  ($num_values == $num_counter) ? $sql .= 'NULL' : $sql .= 'NULL, ';
353
  } else {
354
- ($num_values == $num_counter)
355
- ? $sql .= '"' . DUP_DB::escSQL($value, true) . '"'
356
- : $sql .= '"' . DUP_DB::escSQL($value, true) . '", ';
357
  }
358
  $num_counter++;
359
  }
@@ -362,7 +504,7 @@ class DUP_Database
362
  fwrite($handle, $sql);
363
  }
364
  }
365
-
366
  //Flush buffer if enabled
367
  if ($this->networkFlush) {
368
  DUP_Util::fcgiFlush();
@@ -370,7 +512,7 @@ class DUP_Database
370
  $sql = null;
371
  $rows = null;
372
  }
373
-
374
  $sql_footer = "\nSET FOREIGN_KEY_CHECKS = 1; \n\n";
375
  $sql_footer .= "/* Duplicator WordPress Timestamp: ".date("Y-m-d H:i:s")."*/\n";
376
  $sql_footer .= "/* ".DUPLICATOR_DB_EOF_MARKER." */\n";
@@ -378,5 +520,32 @@ class DUP_Database
378
  $wpdb->flush();
379
  fclose($handle);
380
  }
381
- }
382
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
 
5
  class DUP_Database
6
  {
35
  /**
36
  * Build the database script
37
  *
38
+ * @param DUP_Package $package A reference to the package that this database object belongs in
39
  *
40
  * @return null
41
  */
42
+ public function build($package, $errorBehavior = Dup_ErrorBehavior::Quit)
43
  {
44
  try {
45
 
46
  $this->Package = $package;
47
+ do_action('duplicator_lite_build_database_before_start' , $package);
48
 
49
  $time_start = DUP_Util::getMicrotime();
50
  $this->Package->setStatus(DUP_PackageStatus::DBSTART);
71
 
72
  //Reserved file found
73
  if (file_exists($reserved_db_filepath)) {
74
+ $error_message = 'Reserved SQL file detected';
75
+
76
+ $package->BuildProgress->set_failed($error_message);
77
+
78
+ $package->Update();
79
+
80
+ DUP_Log::Error($error_message,
81
  "The file database.sql was found at [{$reserved_db_filepath}].\n"
82
+ ."\tPlease remove/rename this file to continue with the package creation.", $errorBehavior);
83
  }
84
 
85
+ do_action('duplicator_lite_build_database_start' , $package);
86
+
87
  switch ($mode) {
88
  case 'MYSQLDUMP':
89
  $this->mysqlDump($mysqlDumpPath);
97
  $time_end = DUP_Util::getMicrotime();
98
  $time_sum = DUP_Util::elapsedTime($time_end, $time_start);
99
 
100
+ //File below 10k considered incomplete
101
  $sql_file_size = filesize($this->dbStorePath);
102
  DUP_Log::Info("SQL FILE SIZE: ".DUP_Util::byteSize($sql_file_size)." ({$sql_file_size})");
103
+
104
+ if ($sql_file_size < 1350) {
105
+ $error_message = "SQL file size too low.";
106
+
107
+ $package->BuildProgress->set_failed($error_message);
108
+
109
+ $package->Update();
110
+ DUP_Log::Error($error_message, "File does not look complete. Check permission on file and parent directory at [{$this->dbStorePath}]", $errorBehavior);
111
+ do_action('duplicator_lite_build_database_fail' , $package);
112
+
113
+ } else {
114
+ do_action('duplicator_lite_build_database_completed' , $package);
115
  }
116
 
117
  DUP_Log::Info("SQL FILE TIME: ".date("Y-m-d H:i:s"));
118
  DUP_Log::Info("SQL RUNTIME: {$time_sum}");
119
 
120
  $this->Size = @filesize($this->dbStorePath);
121
+
122
  $this->Package->setStatus(DUP_PackageStatus::DBDONE);
123
  } catch (Exception $e) {
124
+ do_action('duplicator_lite_build_database_fail' , $package);
125
+ DUP_Log::Error("Runtime error in DUP_Database::Build", "Exception: {$e}", $errorBehavior);
126
  }
127
  }
128
 
129
  /**
130
+ * Get the database meta-data such as tables as all there details
131
  *
132
  * @return array Returns an array full of meta-data about the database
133
  */
208
  $info['Status']['TBL_Rows'] = ($tblRowsFound) ? 'Warn' : 'Good';
209
  $info['Status']['TBL_Size'] = ($tblSizeFound) ? 'Warn' : 'Good';
210
 
211
+ $info['RawSize'] = $info['Size'];
212
  $info['Size'] = DUP_Util::byteSize($info['Size']) or "unknown";
213
  $info['Rows'] = number_format($info['Rows']) or "unknown";
214
  $info['TableList'] = $info['TableList'] or "unknown";
220
  /**
221
  * Build the database script using mysqldump
222
  *
223
+ * @return bool Returns true if the sql script was successfully created
224
  */
225
  private function mysqlDump($exePath)
226
  {
 
227
  global $wpdb;
228
+ require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.shell.php');
229
 
230
  $host = explode(':', DB_HOST);
231
  $host = reset($host);
239
  $cmd .= ' --single-transaction';
240
  $cmd .= ' --hex-blob';
241
  $cmd .= ' --skip-add-drop-table';
242
+ $cmd .= ' --routines';
243
+ $cmd .= ' --quote-names';
244
+ $cmd .= ' --skip-comments';
245
+ $cmd .= ' --skip-set-charset';
246
+ $cmd .= ' --allow-keywords';
247
 
248
  //Compatibility mode
249
  if ($mysqlcompat_on) {
255
  $tables = $wpdb->get_col('SHOW TABLES');
256
  $filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : null;
257
  $tblAllCount = count($tables);
258
+ $tblFilterOn = ($this->FilterOn) ? 'ON' : 'OFF';
259
 
260
  if (is_array($filterTables) && $this->FilterOn) {
261
  foreach ($tables as $key => $val) {
267
  }
268
 
269
  $cmd .= ' -u '.escapeshellarg(DB_USER);
270
+ $cmd .= (DB_PASSWORD) ?
271
+ ' -p'.DUP_Shell_U::escapeshellargWindowsSupport(DB_PASSWORD) : '';
272
+
 
 
273
  $cmd .= ' -h '.escapeshellarg($host);
274
  $cmd .= (!empty($port) && is_numeric($port) ) ?
275
  ' -P '.$port : '';
276
+
277
+ $isPopenEnabled = DUP_Shell_U::isPopenEnabled();
278
+
279
+ if (!$isPopenEnabled) {
280
+ $cmd .= ' -r '.escapeshellarg($this->dbStorePath);
281
+ }
282
+
283
  $cmd .= ' '.escapeshellarg(DB_NAME);
284
  $cmd .= ' 2>&1';
285
+
286
+ if ($isPopenEnabled) {
287
+ $needToRewrite = false;
288
+ foreach ($tables as $tableName) {
289
+ $rewriteTableAs = $this->rewriteTableNameAs($tableName);
290
+ if ($tableName != $rewriteTableAs) {
291
+ $needToRewrite = true;
292
+ break;
293
+ }
294
+ }
295
 
296
+ if ($needToRewrite) {
297
+ $findReplaceTableNames = array(); // orignal table name => rewrite table name
298
+
299
+ foreach ($tables as $tableName) {
300
+ $rewriteTableAs = $this->rewriteTableNameAs($tableName);
301
+ if ($tableName != $rewriteTableAs) {
302
+ $findReplaceTableNames[$tableName] = $rewriteTableAs;
303
+ }
304
+ }
305
+ }
306
 
307
+ $firstLine = '';
308
+ DUP_LOG::trace("Executing mysql dump command by popen: $cmd");
309
+ $handle = popen($cmd, "r");
310
+ if ($handle) {
311
+ $sql_header = "/* DUPLICATOR-LITE (MYSQL-DUMP BUILD MODE) MYSQL SCRIPT CREATED ON : ".@date("Y-m-d H:i:s")." */\n\n";
312
+ file_put_contents($this->dbStorePath, $sql_header, FILE_APPEND);
313
+ while (!feof($handle)) {
314
+ $line = fgets($handle); //get ony one line
315
+ if ($line) {
316
+ if (empty($firstLine)) {
317
+ $firstLine = $line;
318
+ if (false !== stripos($line, 'Using a password on the command line interface can be insecure')) continue;
319
+ }
320
 
321
+ if ($needToRewrite) {
322
+ $replaceCount = 1;
323
+
324
+ if (preg_match('/CREATE TABLE `(.*?)`/', $line, $matches)) {
325
+ $tableName = $matches[1];
326
+ if (isset($findReplaceTableNames[$tableName])) {
327
+ $rewriteTableAs = $findReplaceTableNames[$tableName];
328
+ $line = str_replace('CREATE TABLE `'.$tableName.'`', 'CREATE TABLE `'.$rewriteTableAs.'`', $line, $replaceCount);
329
+ }
330
+ } elseif (preg_match('/INSERT INTO `(.*?)`/', $line, $matches)) {
331
+ $tableName = $matches[1];
332
+ if (isset($findReplaceTableNames[$tableName])) {
333
+ $rewriteTableAs = $findReplaceTableNames[$tableName];
334
+ $line = str_replace('INSERT INTO `'.$tableName.'`', 'INSERT INTO `'.$rewriteTableAs.'`', $line, $replaceCount);
335
+ }
336
+ } elseif (preg_match('/LOCK TABLES `(.*?)`/', $line, $matches)) {
337
+ $tableName = $matches[1];
338
+ if (isset($findReplaceTableNames[$tableName])) {
339
+ $rewriteTableAs = $findReplaceTableNames[$tableName];
340
+ $line = str_replace('LOCK TABLES `'.$tableName.'`', 'LOCK TABLES `'.$rewriteTableAs.'`', $line, $replaceCount);
341
+ }
342
+ }
343
+ }
344
+
345
+ file_put_contents($this->dbStorePath, $line, FILE_APPEND);
346
+ $output = "Ran from {$exePath}";
347
+ }
348
+ }
349
+ $ret = pclose($handle);
350
+ } else {
351
+ $output = '';
352
+ }
353
+
354
+ // Password bug > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
355
+ if (empty($output) && trim($firstLine) === 'Warning: Using a password on the command line interface can be insecure.') {
356
+ $output = '';
357
+ }
358
+ } else {
359
+ DUP_LOG::trace("Executing mysql dump command $cmd");
360
+ $output = shell_exec($cmd);
361
+
362
+ // Password bug > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
363
+ if (trim($output) === 'Warning: Using a password on the command line interface can be insecure.') {
364
+ $output = '';
365
+ }
366
+ $output = (strlen($output)) ? $output : "Ran from {$exePath}";
367
+
368
+ $tblCreateCount = count($tables);
369
+ $tblFilterCount = $tblAllCount - $tblCreateCount;
370
+
371
+ //DEBUG
372
+ //DUP_Log::Info("COMMAND: {$cmd}");
373
+ DUP_Log::Info("FILTERED: [{$this->FilterTables}]");
374
+ DUP_Log::Info("RESPONSE: {$output}");
375
+ DUP_Log::Info("TABLES: total:{$tblAllCount} | filtered:{$tblFilterCount} | create:{$tblCreateCount}");
376
+ }
377
 
378
  $sql_footer = "\n\n/* Duplicator WordPress Timestamp: ".date("Y-m-d H:i:s")."*/\n";
379
  $sql_footer .= "/* ".DUPLICATOR_DB_EOF_MARKER." */\n";
385
  /**
386
  * Build the database script using php
387
  *
388
+ * @return bool Returns true if the sql script was successfully created
389
  */
390
  private function phpDump()
391
  {
392
+
393
  global $wpdb;
394
+
395
  $wpdb->query("SET session wait_timeout = ".DUPLICATOR_DB_MAX_TIME);
396
  $handle = fopen($this->dbStorePath, 'w+');
397
+ $tables = $wpdb->get_col("SHOW FULL TABLES WHERE Table_Type != 'VIEW'");
398
+
399
  $filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : null;
400
  $tblAllCount = count($tables);
401
+ $tblFilterOn = ($this->FilterOn) ? 'ON' : 'OFF';
402
  $qryLimit = DUP_Settings::Get('package_phpdump_qrylimit');
403
+
404
  if (is_array($filterTables) && $this->FilterOn) {
405
  foreach ($tables as $key => $val) {
406
  if (in_array($tables[$key], $filterTables)) {
410
  }
411
  $tblCreateCount = count($tables);
412
  $tblFilterCount = $tblAllCount - $tblCreateCount;
413
+
414
  DUP_Log::Info("TABLES: total:{$tblAllCount} | filtered:{$tblFilterCount} | create:{$tblCreateCount}");
415
  DUP_Log::Info("FILTERED: [{$this->FilterTables}]");
416
+
417
+ //Added 'NO_AUTO_VALUE_ON_ZERO' at plugin version 1.2.12 to fix :
418
+ //**ERROR** database error write 'Invalid default value for for older mysql versions
419
  $sql_header = "/* DUPLICATOR-LITE (PHP BUILD MODE) MYSQL SCRIPT CREATED ON : ".@date("Y-m-d H:i:s")." */\n\n";
420
+ $sql_header .= "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n\n";
421
  $sql_header .= "SET FOREIGN_KEY_CHECKS = 0;\n\n";
422
  fwrite($handle, $sql_header);
423
+
424
  //BUILD CREATES:
425
  //All creates must be created before inserts do to foreign key constraints
426
  foreach ($tables as $table) {
427
+ $rewrite_table_as = $this->rewriteTableNameAs($table);
428
  //$sql_del = ($GLOBALS['duplicator_opts']['dbadd_drop']) ? "DROP TABLE IF EXISTS {$table};\n\n" : "";
429
  //@fwrite($handle, $sql_del);
430
  $create = $wpdb->get_row("SHOW CREATE TABLE `{$table}`", ARRAY_N);
431
+ $count = 1;
432
+ $create_table_query = str_replace($table, $rewrite_table_as, $create[1], $count);
433
+ @fwrite($handle, "{$create_table_query};\n\n");
434
  }
435
+
436
+ $procedures = $wpdb->get_col("SHOW PROCEDURE STATUS WHERE `Db` = '{$wpdb->dbname}'",1);
437
+ if(count($procedures)){
438
+ foreach ($procedures as $procedure){
439
+ @fwrite($handle, "DELIMITER ;;\n");
440
+ $create = $wpdb->get_row("SHOW CREATE PROCEDURE `{$procedure}`", ARRAY_N);
441
+ @fwrite($handle, "{$create[2]} ;;\n");
442
+ @fwrite($handle, "DELIMITER ;\n\n");
443
+ }
444
+ }
445
+
446
+ $views = $wpdb->get_col("SHOW FULL TABLES WHERE Table_Type = 'VIEW'");
447
+ if(count($views)){
448
+ foreach ($views as $view){
449
+ $create = $wpdb->get_row("SHOW CREATE VIEW `{$view}`", ARRAY_N);
450
+ @fwrite($handle, "{$create[1]};\n\n");
451
+ }
452
+ }
453
+
454
+ $table_count = count($tables);
455
+ $table_number = 0;
456
+
457
  //BUILD INSERTS:
458
  //Create Insert in 100 row increments to better handle memory
459
  foreach ($tables as $table) {
460
+
461
+ $table_number++;
462
+ if($table_number % 2 == 0) {
463
+ $this->Package->Status = SnapLibUtil::getWorkPercent(DUP_PackageStatus::DBSTART, DUP_PackageStatus::DBDONE, $table_count, $table_number);
464
+ $this->Package->update();
465
+ }
466
+
467
  $row_count = $wpdb->get_var("SELECT Count(*) FROM `{$table}`");
468
  //DUP_Log::Info("{$table} ({$row_count})");
469
+
470
  if ($row_count > $qryLimit) {
471
  $row_count = ceil($row_count / $qryLimit);
472
  } else if ($row_count > 0) {
473
  $row_count = 1;
474
  }
475
+
476
  if ($row_count >= 1) {
477
  fwrite($handle, "\n/* INSERT TABLE DATA: {$table} */\n");
478
  }
479
+
480
+ $rewrite_table_as = $this->rewriteTableNameAs($table);
481
+
482
  for ($i = 0; $i < $row_count; $i++) {
483
  $sql = "";
484
  $limit = $i * $qryLimit;
486
  $rows = $wpdb->get_results($query, ARRAY_A);
487
  if (is_array($rows)) {
488
  foreach ($rows as $row) {
489
+ $sql .= "INSERT INTO `{$rewrite_table_as}` VALUES(";
490
  $num_values = count($row);
491
  $num_counter = 1;
492
  foreach ($row as $value) {
493
  if (is_null($value) || !isset($value)) {
494
  ($num_values == $num_counter) ? $sql .= 'NULL' : $sql .= 'NULL, ';
495
  } else {
496
+ ($num_values == $num_counter)
497
+ ? $sql .= '"' . DUP_DB::escSQL($value, true) . '"'
498
+ : $sql .= '"' . DUP_DB::escSQL($value, true) . '", ';
499
  }
500
  $num_counter++;
501
  }
504
  fwrite($handle, $sql);
505
  }
506
  }
507
+
508
  //Flush buffer if enabled
509
  if ($this->networkFlush) {
510
  DUP_Util::fcgiFlush();
512
  $sql = null;
513
  $rows = null;
514
  }
515
+
516
  $sql_footer = "\nSET FOREIGN_KEY_CHECKS = 1; \n\n";
517
  $sql_footer .= "/* Duplicator WordPress Timestamp: ".date("Y-m-d H:i:s")."*/\n";
518
  $sql_footer .= "/* ".DUPLICATOR_DB_EOF_MARKER." */\n";
520
  $wpdb->flush();
521
  fclose($handle);
522
  }
523
+
524
+ private function rewriteTableNameAs($table) {
525
+ $table_prefix = $this->getTablePrefix();
526
+ if (!isset($this->sameNameTableExists)) {
527
+ global $wpdb;
528
+ $this->sameNameTableExists = false;
529
+ $all_tables = $wpdb->get_col("SHOW FULL TABLES WHERE Table_Type != 'VIEW'");
530
+ foreach ($all_tables as $table_name) {
531
+ if (strtolower($table_name) != $table_name && in_array(strtolower($table_name), $all_tables)) {
532
+ $this->sameNameTableExists = true;
533
+ break;
534
+ }
535
+ }
536
+ }
537
+ if (false === $this->sameNameTableExists && 0 === stripos($table, $table_prefix) && 0 !== strpos($table, $table_prefix)) {
538
+ $post_fix = substr($table, strlen($table_prefix));
539
+ $rewrite_table_name = $table_prefix.$post_fix;
540
+ } else {
541
+ $rewrite_table_name = $table;
542
+ }
543
+ return $rewrite_table_name;
544
+ }
545
+
546
+ private function getTablePrefix() {
547
+ global $wpdb;
548
+ $table_prefix = (is_multisite() && !defined('MULTISITE')) ? $wpdb->base_prefix : $wpdb->get_blog_prefix(0);
549
+ return $table_prefix;
550
+ }
551
+ }
classes/package/class.pack.installer.php CHANGED
@@ -1,5 +1,10 @@
1
  <?php
2
- if (!defined('DUPLICATOR_VERSION')) exit; // Exit if accessed directly
 
 
 
 
 
3
  require_once(DUPLICATOR_PLUGIN_PATH . '/classes/class.password.php');
4
 
5
  class DUP_Installer
@@ -13,7 +18,10 @@ class DUP_Installer
13
  public $OptsDBUser;
14
  public $OptsSecureOn = 0;
15
  public $OptsSecurePass;
16
- //PROTECTED
 
 
 
17
  protected $Package;
18
 
19
  /**
@@ -24,203 +32,446 @@ class DUP_Installer
24
  $this->Package = $package;
25
  }
26
 
27
- /**
28
- * Build the installer script
29
- *
30
- * @param obj $package A reference to the package that this installer object belongs to
31
- *
32
- * @return null
33
- */
34
- public function build($package)
35
  {
 
36
 
37
  $this->Package = $package;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
- DUP_Log::Info("\n********************************************************************************");
40
- DUP_Log::Info("MAKE INSTALLER:");
41
- DUP_Log::Info("********************************************************************************");
42
- DUP_Log::Info("Build Start");
43
-
44
- $template_uniqid = uniqid('').'_'.time();
45
- $template_path = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/installer.template_{$template_uniqid}.php");
46
- $main_path = DUP_Util::safePath(DUPLICATOR_PLUGIN_PATH.'installer/build/main.installer.php');
47
- @chmod($template_path, 0777);
48
- @chmod($main_path, 0777);
49
-
50
- @touch($template_path);
51
- $main_data = file_get_contents("{$main_path}");
52
- $template_result = file_put_contents($template_path, $main_data);
53
- if ($main_data === false || $template_result == false) {
54
- $err_info = "These files may have permission issues. Please validate that PHP has read/write access.\n";
55
- $err_info .= "Main Installer: '{$main_path}' \nTemplate Installer: '$template_path'";
56
- DUP_Log::Error("Install builder failed to generate files.", "{$err_info}");
57
- }
58
-
59
- $embeded_files = array(
60
- "assets/inc.libs.css.php" => "@@INC.LIBS.CSS.PHP@@",
61
- "assets/inc.css.php" => "@@INC.CSS.PHP@@",
62
- "assets/inc.libs.js.php" => "@@INC.LIBS.JS.PHP@@",
63
- "assets/inc.js.php" => "@@INC.JS.PHP@@",
64
- "classes/utilities/class.u.php" => "@@CLASS.U.PHP@@",
65
- "classes/class.csrf.php" => "@@CLASS.CSRF.PHP@@",
66
- "classes/class.server.php" => "@@CLASS.SERVER.PHP@@",
67
- "classes/class.db.php" => "@@CLASS.DB.PHP@@",
68
- "classes/class.logging.php" => "@@CLASS.LOGGING.PHP@@",
69
- "classes/class.engine.php" => "@@CLASS.ENGINE.PHP@@",
70
- "classes/class.http.php" => "@@CLASS.HTTP.PHP@@",
71
- "classes/config/class.conf.wp.php" => "@@CLASS.CONF.WP.PHP@@",
72
- "classes/config/class.conf.srv.php" => "@@CLASS.CONF.SRV.PHP@@",
73
- "classes/class.password.php" => "@@CLASS.PASSWORD.PHP@@",
74
- "ctrls/ctrl.step1.php" => "@@CTRL.STEP1.PHP@@",
75
- "ctrls/ctrl.step2.php" => "@@CTRL.STEP2.PHP@@",
76
- "ctrls/ctrl.step3.php" => "@@CTRL.STEP3.PHP@@",
77
- "view.init1.php" => "@@VIEW.INIT1.PHP@@",
78
- "view.step1.php" => "@@VIEW.STEP1.PHP@@",
79
- "view.step2.php" => "@@VIEW.STEP2.PHP@@",
80
- "view.step3.php" => "@@VIEW.STEP3.PHP@@",
81
- "view.step4.php" => "@@VIEW.STEP4.PHP@@",
82
- "view.help.php" => "@@VIEW.HELP.PHP@@",);
83
-
84
- foreach ($embeded_files as $name => $token) {
85
- $file_path = DUPLICATOR_PLUGIN_PATH."installer/build/{$name}";
86
- @chmod($file_path, 0777);
87
-
88
- $search_data = @file_get_contents($template_path);
89
- $insert_data = @file_get_contents($file_path);
90
- file_put_contents($template_path, str_replace("${token}", "{$insert_data}", $search_data));
91
- if ($search_data === false || $insert_data == false) {
92
- DUP_Log::Error("Installer generation failed at {$token}.", '');
93
  }
94
- @chmod($file_path, 0644);
 
 
 
 
 
 
 
 
 
 
 
 
95
  }
96
 
97
- @chmod($template_path, 0644);
98
- @chmod($main_path, 0644);
 
 
 
 
99
 
100
- DUP_Log::Info("Build Finished");
101
- $this->createFromTemplate($template_path);
102
- $storePath = "{$this->Package->StorePath}/{$this->File}";
103
- $this->Size = @filesize($storePath);
104
- $this->addBackup();
105
  }
106
 
107
  /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  * Puts an installer zip file in the archive for backup purposes.
109
- *
110
- * @return null
111
  */
112
- private function addBackup()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  {
 
 
 
114
 
115
- $zipPath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Archive->File}");
116
- $installer = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_installer.php";
117
 
118
  $zipArchive = new ZipArchive();
119
- if ($zipArchive->open($zipPath, ZIPARCHIVE::CREATE) === TRUE) {
120
- if ($zipArchive->addFile($installer, "installer-backup.php")) {
121
- DUP_Log::Info("Added to archive");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  } else {
123
- DUP_Log::Info("Unable to add installer-backup.php to archive.", "Installer File Path [{$installer}]");
 
 
 
 
 
124
  }
125
- $zipArchive->close();
 
126
  }
 
 
127
  }
128
 
129
- /**
130
- * Generates the final installer file from the template file
131
- *
132
- * @param string $template The path to the installer template which is originally copied from main.installer.php
133
- *
134
- * @return null
135
- */
136
- private function createFromTemplate($template)
137
  {
 
 
 
 
 
138
 
139
- global $wpdb;
140
 
141
- DUP_Log::Info("Preparing for use");
142
- $installer = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_installer.php";
143
-
144
- //Option values to delete at install time
145
- $deleteOpts = $GLOBALS['DUPLICATOR_OPTS_DELETE'];
146
-
147
- DUP_Log::Info("PACK SIZE: {$this->Package->Size}");
148
-
149
- $hasher = new DUP_PasswordHash(8, FALSE);
150
- $pass_hash = $hasher->HashPassword($this->Package->Installer->OptsSecurePass);
151
-
152
- $replace_items = Array(
153
- //COMPARE VALUES
154
- "fwrite_created" => $this->Package->Created,
155
- "fwrite_version_dup" => DUPLICATOR_VERSION,
156
- "fwrite_version_wp" => $this->Package->VersionWP,
157
- "fwrite_version_db" => $this->Package->VersionDB,
158
- "fwrite_version_php" => $this->Package->VersionPHP,
159
- "fwrite_version_os" => $this->Package->VersionOS,
160
- //GENERAL
161
- "fwrite_url_old" => get_option('siteurl'),
162
- "fwrite_archive_name" => "{$this->Package->NameHash}_archive.zip",
163
- "fwrite_archive_onlydb" => $this->Package->Archive->ExportOnlyDB,
164
- "fwrite_package_notes" => $this->Package->Notes,
165
- "fwrite_package_size" => $this->Package->Archive->Size,
166
- "fwrite_secure_name" => $this->Package->NameHash,
167
- "fwrite_dbhost" => $this->Package->Installer->OptsDBHost,
168
- "fwrite_dbport" => $this->Package->Installer->OptsDBPort,
169
- "fwrite_dbname" => $this->Package->Installer->OptsDBName,
170
- "fwrite_dbuser" => $this->Package->Installer->OptsDBUser,
171
- "fwrite_secureon" => $this->Package->Installer->OptsSecureOn,
172
- "fwrite_securepass" => $pass_hash,
173
- "fwrite_dbpass" => '',
174
- "fwrite_wp_tableprefix" => $wpdb->prefix,
175
- "fwrite_opts_delete" => json_encode($deleteOpts),
176
- "fwrite_blogname" => esc_html(get_option('blogname')),
177
- "fwrite_wproot" => DUPLICATOR_WPROOTPATH,
178
- "fwrite_wplogin_url" => wp_login_url(),
179
- "package_hash" => $this->Package->getPackageHash(),
180
- "fwrite_duplicator_version" => DUPLICATOR_VERSION
181
- );
182
-
183
- if (file_exists($template) && is_readable($template)) {
184
- $err_msg = "ERROR: Unable to read/write installer. \nERROR INFO: Check permission/owner on file and parent folder.\nInstaller File = <{$installer}>";
185
- $install_str = $this->parseTemplate($template, $replace_items);
186
- (empty($install_str)) ? DUP_Log::Error("{$err_msg}", "DUP_Installer::createFromTemplate => file-empty-read") : DUP_Log::Info("Template parsed with new data");
187
-
188
- //INSTALLER FILE
189
- $fp = (!file_exists($installer)) ? fopen($installer, 'x+') : fopen($installer, 'w');
190
- if (!$fp || !fwrite($fp, $install_str, strlen($install_str))) {
191
- DUP_Log::Error("{$err_msg}", "DUP_Installer::createFromTemplate => file-write-error");
192
- }
193
 
194
- @fclose($fp);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  } else {
196
- DUP_Log::Error("Installer Template missing or unreadable.", "Template [{$template}]");
197
  }
198
- @unlink($template);
199
- DUP_Log::Info("Complete [{$installer}]");
200
  }
201
 
202
  /**
203
- * Tokenize a file based on an array key
204
- *
205
- * @param string $filename The filename to tokenize
206
- * @param array $data The array of key value items to tokenize
207
  */
208
- private function parseTemplate($filename, $data)
209
  {
210
- $q = file_get_contents($filename);
211
- foreach ($data as $key => $value) {
212
- //NOTE: Use var_export as it's probably best and most "thorough" way to
213
- //make sure the values are set correctly in the template. But in the template,
214
- //need to make things properly formatted so that when real syntax errors
215
- //exist they are easy to spot. So the values will be surrounded by quotes
216
-
217
- $find = array("'%{$key}%'", "\"%{$key}%\"");
218
- $q = str_replace($find, var_export($value, true), $q);
219
- //now, account for places that do not surround with quotes... these
220
- //places do NOT need to use var_export as they are not inside strings
221
- $q = str_replace('%'.$key.'%', $value, $q);
222
- }
223
- return $q;
 
 
 
 
 
 
 
 
 
 
 
224
  }
 
225
  }
226
- ?>
1
  <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
+
5
+ require_once(DUPLICATOR_PLUGIN_PATH . '/classes/class.archive.config.php');
6
+ require_once(DUPLICATOR_PLUGIN_PATH . '/classes/utilities/class.u.zip.php');
7
+ require_once(DUPLICATOR_PLUGIN_PATH . '/classes/utilities/class.u.multisite.php');
8
  require_once(DUPLICATOR_PLUGIN_PATH . '/classes/class.password.php');
9
 
10
  class DUP_Installer
18
  public $OptsDBUser;
19
  public $OptsSecureOn = 0;
20
  public $OptsSecurePass;
21
+ public $numFilesAdded = 0;
22
+ public $numDirsAdded = 0;
23
+
24
+ //PROTECTED
25
  protected $Package;
26
 
27
  /**
32
  $this->Package = $package;
33
  }
34
 
35
+ public function build($package, $error_behavior = Dup_ErrorBehavior::Quit)
 
 
 
 
 
 
 
36
  {
37
+ DUP_Log::Info("building installer");
38
 
39
  $this->Package = $package;
40
+ $success = false;
41
+
42
+ if ($this->create_enhanced_installer_files()) {
43
+ $success = $this->add_extra_files($package);
44
+ } else {
45
+ DUP_Log::Info("error creating enhanced installer files");
46
+ }
47
+
48
+
49
+ if ($success) {
50
+ $package->BuildProgress->installer_built = true;
51
+ } else {
52
+ $error_message = 'Error adding installer';
53
+
54
+ $package->BuildProgress->set_failed($error_message);
55
+ $package->Update();
56
+
57
+ DUP_Log::error($error_message, "Marking build progress as failed because couldn't add installer files", $error_behavior);
58
+ //$package->BuildProgress->failed = true;
59
+ //$package->setStatus(DUP_PackageStatus::ERROR);
60
+ }
61
+
62
+ return $success;
63
+ }
64
+
65
+ private function create_enhanced_installer_files()
66
+ {
67
+ $success = false;
68
 
69
+ if ($this->create_enhanced_installer()) {
70
+ $success = $this->create_archive_config_file();
71
+ }
72
+
73
+ return $success;
74
+ }
75
+
76
+ private function create_enhanced_installer()
77
+ {
78
+ $success = true;
79
+
80
+ $archive_filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Archive->File}");
81
+ $installer_filepath = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_installer.php";
82
+ $template_filepath = DUPLICATOR_PLUGIN_PATH.'/installer/installer.tpl';
83
+ $mini_expander_filepath = DUPLICATOR_PLUGIN_PATH.'/lib/dup_archive/classes/class.duparchive.mini.expander.php';
84
+
85
+ // Replace the @@ARCHIVE@@ token
86
+ $installer_contents = file_get_contents($template_filepath);
87
+
88
+ if (DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::DupArchive) {
89
+ $mini_expander_string = file_get_contents($mini_expander_filepath);
90
+
91
+ if ($mini_expander_string === false) {
92
+ DUP_Log::error(DUP_U::__('Error reading DupArchive mini expander'), DUP_U::__('Error reading DupArchive mini expander'), Dup_ErrorBehavior::LogOnly);
93
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  }
95
+ } else {
96
+ $mini_expander_string = '';
97
+ }
98
+
99
+ $search_array = array('@@ARCHIVE@@', '@@VERSION@@', '@@ARCHIVE_SIZE@@', '@@PACKAGE_HASH@@', '@@DUPARCHIVE_MINI_EXPANDER@@');
100
+ $package_hash = $this->Package->getPackageHash();
101
+ $replace_array = array($this->Package->Archive->File, DUPLICATOR_VERSION, @filesize($archive_filepath), $package_hash, $mini_expander_string);
102
+
103
+ $installer_contents = str_replace($search_array, $replace_array, $installer_contents);
104
+
105
+ if (@file_put_contents($installer_filepath, $installer_contents) === false) {
106
+ DUP_Log::error(esc_html__('Error writing installer contents', 'duplicator'), esc_html__("Couldn't write to $installer_filepath", 'duplicator'));
107
+ $success = false;
108
  }
109
 
110
+ $yn = file_exists($installer_filepath) ? 'yes' : 'no';
111
+
112
+ if ($success) {
113
+ $storePath = "{$this->Package->StorePath}/{$this->File}";
114
+ $this->Size = @filesize($storePath);
115
+ }
116
 
117
+ return $success;
 
 
 
 
118
  }
119
 
120
  /**
121
+ * Create archive.txt file */
122
+ private function create_archive_config_file()
123
+ {
124
+ global $wpdb;
125
+
126
+ $success = true;
127
+ $archive_config_filepath = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_archive.txt";
128
+ $ac = new DUP_Archive_Config();
129
+ $extension = strtolower($this->Package->Archive->Format);
130
+
131
+ $hasher = new DUP_PasswordHash(8, FALSE);
132
+ $pass_hash = $hasher->HashPassword($this->Package->Installer->OptsSecurePass);
133
+
134
+ //READ-ONLY: COMPARE VALUES
135
+ $ac->created = $this->Package->Created;
136
+ $ac->version_dup = DUPLICATOR_VERSION;
137
+ $ac->version_wp = $this->Package->VersionWP;
138
+ $ac->version_db = $this->Package->VersionDB;
139
+ $ac->version_php = $this->Package->VersionPHP;
140
+ $ac->version_os = $this->Package->VersionOS;
141
+ $ac->dbInfo = $this->Package->Database->info;
142
+
143
+ //READ-ONLY: GENERAL
144
+ // $ac->installer_base_name = $global->installer_base_name;
145
+ $ac->installer_base_name = 'installer.php';
146
+ $ac->package_name = "{$this->Package->NameHash}_archive.{$extension}";
147
+ $ac->package_hash = $this->Package->getPackageHash();
148
+ $ac->package_notes = $this->Package->Notes;
149
+ $ac->url_old = get_option('siteurl');
150
+ $ac->opts_delete = json_encode($GLOBALS['DUPLICATOR_OPTS_DELETE']);
151
+ $ac->blogname = esc_html(get_option('blogname'));
152
+ $ac->wproot = DUPLICATOR_WPROOTPATH;
153
+ $ac->relative_content_dir = str_replace(ABSPATH, '', WP_CONTENT_DIR);
154
+ $ac->exportOnlyDB = $this->Package->Archive->ExportOnlyDB;
155
+ $ac->installSiteOverwriteOn = DUPLICATOR_INSTALL_SITE_OVERWRITE_ON;
156
+ $ac->wplogin_url = wp_login_url();
157
+
158
+ //PRE-FILLED: GENERAL
159
+ $ac->secure_on = $this->Package->Installer->OptsSecureOn;
160
+ $ac->secure_pass = $pass_hash;
161
+ $ac->skipscan = false;
162
+ $ac->dbhost = $this->Package->Installer->OptsDBHost;
163
+ $ac->dbname = $this->Package->Installer->OptsDBName;
164
+ $ac->dbuser = $this->Package->Installer->OptsDBUser;
165
+ $ac->dbpass = '';
166
+ $ac->wp_tableprefix = $wpdb->base_prefix;
167
+
168
+ $ac->mu_mode = DUP_MU::getMode();
169
+
170
+ $json = json_encode($ac);
171
+
172
+ DUP_Log::TraceObject('json', $json);
173
+
174
+ if (file_put_contents($archive_config_filepath, $json) === false) {
175
+ DUP_Log::error("Error writing archive config", "Couldn't write archive config at $archive_config_filepath", Dup_ErrorBehavior::LogOnly);
176
+ $success = false;
177
+ }
178
+
179
+ return $success;
180
+ }
181
+
182
+ /**
183
  * Puts an installer zip file in the archive for backup purposes.
 
 
184
  */
185
+ private function add_extra_files($package)
186
+ {
187
+ $success = false;
188
+ $installer_filepath = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_installer.php";
189
+ $scan_filepath = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_scan.json";
190
+ $sql_filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Database->File}");
191
+ $archive_filepath = DUP_Util::safePath("{$this->Package->StorePath}/{$this->Package->Archive->File}");
192
+ $archive_config_filepath = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP)."/{$this->Package->NameHash}_archive.txt";
193
+
194
+ DUP_Log::Info("add_extra_files1");
195
+
196
+ if (file_exists($installer_filepath) == false) {
197
+ DUP_Log::error("Installer $installer_filepath not present", '', Dup_ErrorBehavior::LogOnly);
198
+ return false;
199
+ }
200
+
201
+ DUP_Log::Info("add_extra_files2");
202
+ if (file_exists($sql_filepath) == false) {
203
+ DUP_Log::error("Database SQL file $sql_filepath not present", '', Dup_ErrorBehavior::LogOnly);
204
+ return false;
205
+ }
206
+
207
+ DUP_Log::Info("add_extra_files3");
208
+ if (file_exists($archive_config_filepath) == false) {
209
+ DUP_Log::error("Archive configuration file $archive_config_filepath not present", '', Dup_ErrorBehavior::LogOnly);
210
+ return false;
211
+ }
212
+
213
+ DUP_Log::Info("add_extra_files4");
214
+ if ($package->Archive->file_count != 2) {
215
+ DUP_Log::Info("Doing archive file check");
216
+ // Only way it's 2 is if the root was part of the filter in which case the archive won't be there
217
+ DUP_Log::Info("add_extra_files5");
218
+ if (file_exists($archive_filepath) == false) {
219
+
220
+ DUP_Log::error("$error_text. **RECOMMENDATION: $fix_text", '', Dup_ErrorBehavior::LogOnly);
221
+
222
+ return false;
223
+ }
224
+ DUP_Log::Info("add_extra_files6");
225
+ }
226
+
227
+ if($package->Archive->Format == 'DAF') {
228
+ DUP_Log::Info("add_extra_files7");
229
+ $success = $this->add_extra_files_using_duparchive($installer_filepath, $scan_filepath, $sql_filepath, $archive_filepath, $archive_config_filepath);
230
+ } else {
231
+ DUP_Log::Info("add_extra_files8");
232
+ $success = $this->add_extra_files_using_ziparchive($installer_filepath, $scan_filepath, $sql_filepath, $archive_filepath, $archive_config_filepath);
233
+ }
234
+
235
+ // No sense keeping the archive config around
236
+ @unlink($archive_config_filepath);
237
+
238
+ $package->Archive->Size = @filesize($archive_filepath);
239
+
240
+ return $success;
241
+ }
242
+
243
+ private function add_extra_files_using_duparchive($installer_filepath, $scan_filepath, $sql_filepath, $archive_filepath, $archive_config_filepath)
244
+ {
245
+ $success = false;
246
+
247
+ try {
248
+ DUP_Log::Info("add_extra_files_using_da1");
249
+ $htaccess_filepath = DUPLICATOR_WPROOTPATH . '.htaccess';
250
+ $webconf_filepath = DUPLICATOR_WPROOTPATH . 'web.config';
251
+ $wpconfig_filepath = DUPLICATOR_WPROOTPATH . 'wp-config.php';
252
+
253
+ $logger = new DUP_DupArchive_Logger();
254
+
255
+ DupArchiveEngine::init($logger, 'DUP_Log::profile');
256
+
257
+ $embedded_scan_ark_file_path = $this->getEmbeddedScanFilePath();
258
+ DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $scan_filepath, $embedded_scan_ark_file_path);
259
+ $this->numFilesAdded++;
260
+
261
+ if(file_exists($htaccess_filepath)) {
262
+ try {
263
+ DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $htaccess_filepath, DUPLICATOR_HTACCESS_ORIG_FILENAME);
264
+ $this->numFilesAdded++;
265
+ } catch (Exception $ex) {
266
+ // Non critical so bury exception
267
+ }
268
+ }
269
+
270
+ if(file_exists($webconf_filepath)) {
271
+ try {
272
+ DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $webconf_filepath, DUPLICATOR_WEBCONFIG_ORIG_FILENAME);
273
+ $this->numFilesAdded++;
274
+ } catch (Exception $ex) {
275
+ // Non critical so bury exception
276
+ }
277
+ }
278
+
279
+ if(file_exists($wpconfig_filepath)) {
280
+ $conf_ark_file_path = $this->getWPConfArkFilePath();
281
+ DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $wpconfig_filepath, $conf_ark_file_path);
282
+ $this->numFilesAdded++;
283
+ }
284
+
285
+ $this->add_installer_files_using_duparchive($archive_filepath, $installer_filepath, $archive_config_filepath);
286
+
287
+ $success = true;
288
+ } catch (Exception $ex) {
289
+ DUP_Log::Error("Error adding installer files to archive. ", $ex->getMessage(), Dup_ErrorBehavior::ThrowException);
290
+ }
291
+
292
+ return $success;
293
+ }
294
+
295
+ private function add_installer_files_using_duparchive($archive_filepath, $installer_filepath, $archive_config_filepath)
296
+ {
297
+ /* @var $global DUP_Global_Entity */
298
+ // $global = DUP_Global_Entity::get_instance();
299
+ // $installer_backup_filename = $global->get_installer_backup_filename();
300
+ $installer_backup_filename = 'installer-backup.php';
301
+
302
+ $installer_backup_filepath = dirname($installer_filepath) . "/{$installer_backup_filename}";
303
+
304
+ DUP_Log::Info('Adding enhanced installer files to archive using DupArchive');
305
+
306
+ SnapLibIOU::copy($installer_filepath, $installer_backup_filepath);
307
+
308
+ DupArchiveEngine::addFileToArchiveUsingBaseDirST($archive_filepath, dirname($installer_backup_filepath), $installer_backup_filepath);
309
+
310
+ SnapLibIOU::rm($installer_backup_filepath);
311
+
312
+ $this->numFilesAdded++;
313
+
314
+ $base_installer_directory = DUPLICATOR_PLUGIN_PATH.'installer';
315
+ $installer_directory = "$base_installer_directory/dup-installer";
316
+
317
+ $counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $installer_directory, $base_installer_directory, true);
318
+ $this->numFilesAdded += $counts->numFilesAdded;
319
+ $this->numDirsAdded += $counts->numDirsAdded;
320
+
321
+ $archive_config_relative_path = $this->getArchiveTxtFilePath();
322
+
323
+ DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $archive_config_filepath, $archive_config_relative_path);
324
+ $this->numFilesAdded++;
325
+
326
+ // Include dup archive
327
+ $duparchive_lib_directory = DUPLICATOR_PLUGIN_PATH.'lib/dup_archive';
328
+ $duparchive_lib_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $duparchive_lib_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/');
329
+ $this->numFilesAdded += $duparchive_lib_counts->numFilesAdded;
330
+ $this->numDirsAdded += $duparchive_lib_counts->numDirsAdded;
331
+
332
+ // Include snaplib
333
+ $snaplib_directory = DUPLICATOR_PLUGIN_PATH.'lib/snaplib';
334
+ $snaplib_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $snaplib_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/');
335
+ $this->numFilesAdded += $snaplib_counts->numFilesAdded;
336
+ $this->numDirsAdded += $snaplib_counts->numDirsAdded;
337
+
338
+ // Include fileops
339
+ $fileops_directory = DUPLICATOR_PLUGIN_PATH.'lib/fileops';
340
+ $fileops_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $fileops_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/');
341
+ $this->numFilesAdded += $fileops_counts->numFilesAdded;
342
+ $this->numDirsAdded += $fileops_counts->numDirsAdded;
343
+ }
344
+
345
+ private function add_extra_files_using_ziparchive($installer_filepath, $scan_filepath, $sql_filepath, $zip_filepath, $archive_config_filepath)
346
  {
347
+ $htaccess_filepath = DUPLICATOR_WPROOTPATH . '.htaccess';
348
+ $webconfig_filepath = DUPLICATOR_WPROOTPATH . 'web.config';
349
+ $wpconfig_filepath = DUPLICATOR_WPROOTPATH . 'wp-config.php';
350
 
351
+ $success = false;
 
352
 
353
  $zipArchive = new ZipArchive();
354
+
355
+ if ($zipArchive->open($zip_filepath, ZIPARCHIVE::CREATE) === TRUE) {
356
+ DUP_Log::Info("Successfully opened zip $zip_filepath");
357
+
358
+ if(file_exists($htaccess_filepath)) {
359
+ DUP_Zip_U::addFileToZipArchive($zipArchive, $htaccess_filepath, DUPLICATOR_HTACCESS_ORIG_FILENAME, true);
360
+ }
361
+
362
+ if(file_exists($webconfig_filepath)) {
363
+ DUP_Zip_U::addFileToZipArchive($zipArchive, $webconfig_filepath, DUPLICATOR_WEBCONFIG_ORIG_FILENAME, true);
364
+ }
365
+
366
+ if(file_exists($wpconfig_filepath)) {
367
+ $conf_ark_file_path = $this->getWPConfArkFilePath();
368
+ DUP_Zip_U::addFileToZipArchive($zipArchive, $wpconfig_filepath, $conf_ark_file_path, true);
369
+ }
370
+
371
+ $embedded_scan_file_path = $this->getEmbeddedScanFilePath();
372
+ if (DUP_Zip_U::addFileToZipArchive($zipArchive, $scan_filepath, $embedded_scan_file_path, true)) {
373
+ if ($this->add_installer_files_using_zip_archive($zipArchive, $installer_filepath, $archive_config_filepath, true)) {
374
+ DUP_Log::info("Installer files added to archive");
375
+ DUP_Log::info("Added to archive");
376
+
377
+ $success = true;
378
+ } else {
379
+ DUP_Log::error("Unable to add enhanced enhanced installer files to archive.", '', Dup_ErrorBehavior::LogOnly);
380
+ }
381
  } else {
382
+ DUP_Log::error("Unable to add scan file to archive.", '', Dup_ErrorBehavior::LogOnly);
383
+ }
384
+
385
+ if ($zipArchive->close() === false) {
386
+ DUP_Log::error("Couldn't close archive when adding extra files.", '');
387
+ $success = false;
388
  }
389
+
390
+ DUP_Log::Info('After ziparchive close when adding installer');
391
  }
392
+
393
+ return $success;
394
  }
395
 
396
+ // Add installer directory to the archive and the archive.cfg
397
+ private function add_installer_files_using_zip_archive(&$zip_archive, $installer_filepath, $archive_config_filepath, $is_compressed)
 
 
 
 
 
 
398
  {
399
+ $success = false;
400
+ /* @var $global DUP_Global_Entity */
401
+ // $global = DUP_Global_Entity::get_instance();
402
+ // $installer_backup_filename = $global->get_installer_backup_filename();
403
+ $installer_backup_filename = 'installer-backup.php';
404
 
405
+ DUP_Log::Info('Adding enhanced installer files to archive using ZipArchive');
406
 
407
+ // if ($zip_archive->addFile($installer_filepath, $installer_backup_filename)) {
408
+ if (DUP_Zip_U::addFileToZipArchive($zip_archive, $installer_filepath, $installer_backup_filename, true)) {
409
+ DUPLICATOR_PLUGIN_PATH.'installer/';
410
+
411
+ $installer_directory = DUPLICATOR_PLUGIN_PATH.'installer/dup-installer';
412
+
413
+
414
+ if (DUP_Zip_U::addDirWithZipArchive($zip_archive, $installer_directory, true, '', $is_compressed)) {
415
+ $archive_config_local_name = $this->getArchiveTxtFilePath();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
 
417
+ // if ($zip_archive->addFile($archive_config_filepath, $archive_config_local_name)) {
418
+ if (DUP_Zip_U::addFileToZipArchive($zip_archive, $archive_config_filepath, $archive_config_local_name, true)) {
419
+
420
+ $snaplib_directory = DUPLICATOR_PLUGIN_PATH . 'lib/snaplib';
421
+ // $fileops_directory = DUPLICATOR_PLUGIN_PATH . 'lib/fileops';
422
+
423
+ //DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $snaplib_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/');
424
+ if (DUP_Zip_U::addDirWithZipArchive($zip_archive, $snaplib_directory, true, 'dup-installer/lib/', $is_compressed))// &&
425
+ // DUP_Zip_U::addDirWithZipArchive($zip_archive, $fileops_directory, true, 'dup-installer/lib/', $is_compressed)) {
426
+ {
427
+ $success = true;
428
+ } else {
429
+ // DUP_Log::error("Error adding directory {$snaplib_directory} or {$fileops_directory} to zipArchive", '', false);
430
+ DUP_Log::error("Error adding directory {$snaplib_directory} to zipArchive", '', Dup_ErrorBehavior::LogOnly);
431
+ }
432
+ } else {
433
+ DUP_Log::error("Error adding $archive_config_filepath to zipArchive", '', Dup_ErrorBehavior::LogOnly);
434
+ }
435
+ } else {
436
+ DUP_Log::error("Error adding directory $installer_directory to zipArchive", '', Dup_ErrorBehavior::LogOnly);
437
+ }
438
  } else {
439
+ DUP_Log::error("Error adding backup installer file to zipArchive", '', Dup_ErrorBehavior::LogOnly);
440
  }
441
+
442
+ return $success;
443
  }
444
 
445
  /**
446
+ * Get wp-config.php file path along with name in archive file
 
 
 
447
  */
448
+ private function getWPConfArkFilePath()
449
  {
450
+ if (DUPLICATOR_INSTALL_SITE_OVERWRITE_ON) {
451
+ $package_hash = $this->Package->getPackageHash();
452
+ $conf_ark_file_path = 'dup-wp-config-arc__'.$package_hash.'.txt';
453
+ } else {
454
+ $conf_ark_file_path = 'wp-config.php';
455
+ }
456
+ return $conf_ark_file_path;
457
+ }
458
+
459
+ /**
460
+ * Get scan.json file path along with name in archive file
461
+ */
462
+ private function getEmbeddedScanFilePath() {
463
+ $package_hash = $this->Package->getPackageHash();
464
+ $embedded_scan_ark_file_path = 'dup-installer/dup-scan__'.$package_hash.'.json';
465
+ return $embedded_scan_ark_file_path;
466
+ }
467
+
468
+ /**
469
+ * Get archive.txt file path along with name in archive file
470
+ */
471
+ private function getArchiveTxtFilePath() {
472
+ $package_hash = $this->Package->getPackageHash();
473
+ $archive_txt_file_path = 'dup-installer/dup-archive__'.$package_hash.'.txt';
474
+ return $archive_txt_file_path;
475
  }
476
+
477
  }
 
classes/package/class.pack.php CHANGED
@@ -1,37 +1,145 @@
1
  <?php
2
- if (!defined('DUPLICATOR_VERSION')) exit; // Exit if accessed directly
 
3
 
4
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.php');
5
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.php');
6
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.installer.php');
7
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.database.php');
8
 
9
- final class DUP_PackageStatus
 
 
 
 
 
10
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- private function __construct()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
 
 
 
 
 
 
 
 
 
15
  }
 
 
 
16
  const START = 10;
17
  const DBSTART = 20;
18
  const DBDONE = 30;
19
  const ARCSTART = 40;
20
- const ARCDONE = 50;
 
21
  const COMPLETE = 100;
22
-
23
  }
24
 
 
 
 
 
 
 
25
  final class DUP_PackageType
26
  {
27
  const MANUAL = 0;
28
  const SCHEDULED = 1;
 
29
 
 
 
 
 
 
 
 
 
 
 
 
30
  }
31
 
32
  /**
33
  * Class used to store and process all Package logic
34
  *
 
 
 
35
  * @package Duplicator\classes
36
  */
37
  class DUP_Package
@@ -49,11 +157,13 @@ class DUP_Package
49
  public $Name;
50
  public $Hash;
51
  public $NameHash;
 
52
  public $Type;
53
  public $Notes;
54
  public $StorePath;
55
  public $StoreURL;
56
  public $ScanFile;
 
57
  public $Runtime;
58
  public $ExeSize;
59
  public $ZipSize;
@@ -64,15 +174,15 @@ class DUP_Package
64
  public $Installer;
65
  public $Database;
66
 
 
 
67
  /**
68
  * Manages the Package Process
69
  */
70
  function __construct()
71
  {
72
-
73
  $this->ID = null;
74
  $this->Version = DUPLICATOR_VERSION;
75
-
76
  $this->Type = DUP_PackageType::MANUAL;
77
  $this->Name = self::getDefaultName();
78
  $this->Notes = null;
@@ -81,10 +191,12 @@ class DUP_Package
81
  $this->Database = new DUP_Database($this);
82
  $this->Archive = new DUP_Archive($this);
83
  $this->Installer = new DUP_Installer($this);
 
 
84
  }
85
 
86
  /**
87
- * Generates a json scan report
88
  *
89
  * @return array of scan results
90
  *
@@ -127,20 +239,24 @@ class DUP_Package
127
  $report['ARC']['Dirs'] = $this->Archive->Dirs;
128
  $report['ARC']['Files'] = $this->Archive->Files;
129
  $report['ARC']['Status']['AddonSites'] = count($this->Archive->FilterInfo->Dirs->AddonSites) ? 'Warn' : 'Good';
130
-
131
-
132
 
133
  //DATABASE
134
  $db = $this->Database->getScannerData();
135
  $report['DB'] = $db;
136
 
 
 
 
 
 
137
  $warnings = array(
138
  $report['SRV']['PHP']['ALL'],
139
  $report['SRV']['WP']['ALL'],
140
  $report['ARC']['Status']['Size'],
141
  $report['ARC']['Status']['Names'],
142
  $db['Status']['DB_Size'],
143
- $db['Status']['DB_Rows']);
 
144
 
145
  //array_count_values will throw a warning message if it has null values,
146
  //so lets replace all nulls with empty string
@@ -149,7 +265,7 @@ class DUP_Package
149
  $warnings[$i] = '';
150
  }
151
  }
152
-
153
  $warn_counts = is_array($warnings) ? array_count_values($warnings) : 0;
154
  $report['RPT']['Warnings'] = is_null($warn_counts['Warn']) ? 0 : $warn_counts['Warn'];
155
  $report['RPT']['Success'] = is_null($warn_counts['Good']) ? 0 : $warn_counts['Good'];
@@ -164,72 +280,653 @@ class DUP_Package
164
  }
165
 
166
  /**
167
- * Starts the package build process
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  *
169
- * @return obj Returns a DUP_Package object
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  */
171
- public function runBuild()
172
  {
173
- global $wp_version;
174
  global $wpdb;
175
- global $current_user;
176
 
177
- $timerStart = DUP_Util::getMicrotime();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
- $this->Archive->File = "{$this->NameHash}_archive.zip";
180
- $this->Installer->File = "{$this->NameHash}_installer.php";
181
- $this->Database->File = "{$this->NameHash}_database.sql";
182
- $this->WPUser = isset($current_user->user_login) ? $current_user->user_login : 'unknown';
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
184
- //START LOGGING
185
- DUP_Log::Open($this->NameHash);
186
- $php_max_time = @ini_get("max_execution_time");
187
- $php_max_memory = @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY);
188
- $php_max_time = ($php_max_time == 0) ? "(0) no time limit imposed" : "[{$php_max_time}] not allowed";
189
- $php_max_memory = ($php_max_memory === false) ? "Unabled to set php memory_limit" : DUPLICATOR_PHP_MAX_MEMORY." ({$php_max_memory} default)";
190
 
191
- $info = "********************************************************************************\n";
192
- $info .= "DUPLICATOR-LITE PACKAGE-LOG: ".@date(get_option('date_format')." ".get_option('time_format'))."\n";
193
- $info .= "NOTICE: Do NOT post to public sites or forums \n";
194
- $info .= "********************************************************************************\n";
195
- $info .= "VERSION:\t".DUPLICATOR_VERSION."\n";
196
- $info .= "WORDPRESS:\t{$wp_version}\n";
197
- $info .= "PHP INFO:\t".phpversion().' | '.'SAPI: '.php_sapi_name()."\n";
198
- $info .= "SERVER:\t\t{$_SERVER['SERVER_SOFTWARE']} \n";
199
- $info .= "PHP TIME LIMIT: {$php_max_time} \n";
200
- $info .= "PHP MAX MEMORY: {$php_max_memory} \n";
201
- $info .= "MEMORY STACK: ".DUP_Server::getPHPMemory();
202
- DUP_Log::Info($info);
203
- $info = null;
204
 
205
- //CREATE DB RECORD
206
- $packageObj = serialize($this);
207
- if (!$packageObj) {
208
- DUP_Log::Error("Unable to serialize pacakge object while building record.");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  }
210
 
211
- $this->ID = $this->getHashKey($this->Hash);
 
212
 
213
- if ($this->ID != 0) {
214
- $this->setStatus(DUP_PackageStatus::START);
215
  } else {
216
- $results = $wpdb->insert($wpdb->prefix."duplicator_packages",
217
- array(
218
- 'name' => $this->Name,
219
- 'hash' => $this->Hash,
220
- 'status' => DUP_PackageStatus::START,
221
- 'created' => current_time('mysql', get_option('gmt_offset', 1)),
222
- 'owner' => isset($current_user->user_login) ? $current_user->user_login : 'unknown',
223
- 'package' => $packageObj)
224
- );
225
- if ($results === false) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
- $wpdb->print_error();
228
- DUP_Log::Error("Duplicator is unable to insert a package record into the database table.", "'{$wpdb->last_error}'");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  }
230
- $this->ID = $wpdb->insert_id;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  }
232
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  //START BUILD
234
  //PHPs serialze method will return the object, but the ID above is not passed
235
  //for one reason or another so passing the object back in seems to do the trick
@@ -289,7 +986,7 @@ class DUP_Package
289
  * @see DUP_Package::getActive
290
  *
291
  * @param $_POST $post The Post server object
292
- *
293
  * @return null
294
  */
295
  public function saveActive($post = null)
@@ -299,20 +996,49 @@ class DUP_Package
299
  if (isset($post)) {
300
  $post = stripslashes_deep($post);
301
 
302
- $name = ( isset($post['package-name']) && !empty($post['package-name'])) ? $post['package-name'] : self::getDefaultName();
303
- $name = substr(sanitize_file_name($name), 0, 40);
304
- $name = str_replace(array('.', '-', ';', ':', "'", '"'), '', $name);
 
 
305
 
306
- $filter_dirs = isset($post['filter-dirs']) ? $this->Archive->parseDirectoryFilter($post['filter-dirs']) : '';
307
- $filter_files = isset($post['filter-files']) ? $this->Archive->parseFileFilter($post['filter-files']) : '';
308
- $filter_exts = isset($post['filter-exts']) ? $this->Archive->parseExtensionFilter($post['filter-exts']) : '';
309
- $tablelist = isset($post['dbtables']) ? implode(',', $post['dbtables']) : '';
310
- $compatlist = isset($post['dbcompat']) ? implode(',', $post['dbcompat']) : '';
311
- $dbversion = DUP_DB::getVersion();
312
- $dbversion = is_null($dbversion) ? '- unknown -' : $dbversion;
313
- $dbcomments = DUP_DB::getVariable('version_comment');
314
- $dbcomments = is_null($dbcomments) ? '- unknown -' : $dbcomments;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
 
 
 
 
 
 
 
 
 
 
 
 
316
 
317
  //PACKAGE
318
  $this->Created = date("Y-m-d H:i:s");
@@ -323,7 +1049,7 @@ class DUP_Package
323
  $this->VersionDB = sanitize_text_field($dbversion);
324
  $this->Name = sanitize_text_field($name);
325
  $this->Hash = $this->makeHash();
326
- $this->NameHash = "{$this->Name}_{$this->Hash}";
327
 
328
  $this->Notes = sanitize_textarea_field($post['package-notes']);
329
  //ARCHIVE
@@ -332,16 +1058,16 @@ class DUP_Package
332
  $this->Archive->FilterOn = isset($post['filter-on']) ? 1 : 0;
333
  $this->Archive->ExportOnlyDB = isset($post['export-onlydb']) ? 1 : 0;
334
  $this->Archive->FilterDirs = sanitize_textarea_field($filter_dirs);
335
- $this->Archive->FilterFiles = sanitize_textarea_field($filter_files);
336
- $this->Archive->FilterExts = str_replace(array('.', ' '), '', sanitize_textarea_field($filter_exts));
337
  //INSTALLER
338
  $this->Installer->OptsDBHost = sanitize_text_field($post['dbhost']);
339
  $this->Installer->OptsDBPort = sanitize_text_field($post['dbport']);
340
  $this->Installer->OptsDBName = sanitize_text_field($post['dbname']);
341
  $this->Installer->OptsDBUser = sanitize_text_field($post['dbuser']);
342
  $this->Installer->OptsSecureOn = isset($post['secure-on']) ? 1 : 0;
343
- $post_secure_pass = sanitize_text_field($post['secure-pass']);
344
- $this->Installer->OptsSecurePass = DUP_Util::installerScramble($post_secure_pass);
345
  //DATABASE
346
  $this->Database->FilterOn = isset($post['dbfilter-on']) ? 1 : 0;
347
  $this->Database->FilterTables = sanitize_text_field($tablelist);
@@ -352,6 +1078,37 @@ class DUP_Package
352
  }
353
  }
354
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
  /**
356
  * Save any property of this class through reflection
357
  *
@@ -378,26 +1135,17 @@ class DUP_Package
378
  */
379
  public function setStatus($status)
380
  {
381
- global $wpdb;
382
-
383
- $packageObj = serialize($this);
384
-
385
  if (!isset($status)) {
386
  DUP_Log::Error("Package SetStatus did not receive a proper code.");
387
  }
388
 
389
- if (!$packageObj) {
390
- DUP_Log::Error("Package SetStatus was unable to serialize package object while updating record.");
391
- }
392
 
393
- $wpdb->flush();
394
- $table = $wpdb->prefix."duplicator_packages";
395
- $sql = "UPDATE `{$table}` SET status = ".intval($status).", package = '".esc_sql($packageObj)."' WHERE ID = ".intval($this->ID);
396
- $wpdb->query($sql);
397
  }
398
 
399
  /**
400
- * Does a hash already exist
401
  *
402
  * @param string $hash An existing hash value
403
  *
@@ -407,9 +1155,10 @@ class DUP_Package
407
  {
408
  global $wpdb;
409
 
410
- $table = $wpdb->prefix."duplicator_packages";
 
411
  $qry = $wpdb->get_row("SELECT ID, hash FROM `{$table}` WHERE hash = '{$hash}'");
412
- if (strlen($qry->hash) == 0) {
413
  return 0;
414
  } else {
415
  return $qry->ID;
@@ -417,14 +1166,12 @@ class DUP_Package
417
  }
418
 
419
  /**
420
- * Makes the hashkey for the package files
421
- * Rare cases will need to fall back to GUID
422
  *
423
- * @return string Returns a unique hashkey
424
  */
425
  public function makeHash()
426
  {
427
- // IMPORTANT! Be VERY careful in changing this format - the FTP delete logic requires 3 segments with the last segment to be the date in YmdHis format.
428
  try {
429
  if (function_exists('random_bytes') && DUP_Util::PHP53()) {
430
  return bin2hex(random_bytes(8)) . mt_rand(1000, 9999) . '_' . date("YmdHis");
@@ -455,24 +1202,24 @@ class DUP_Package
455
  }
456
  //Incase unserilaize fails
457
  $obj = (is_object($obj)) ? $obj : new DUP_Package();
458
-
459
  return $obj;
460
  }
461
 
462
  /**
463
  * Gets the Package by ID
464
- *
465
  * @param int $id A valid package id form the duplicator_packages table
466
  *
467
  * @return obj A copy of the DUP_Package object
468
  */
469
  public static function getByID($id)
470
  {
471
-
472
  global $wpdb;
473
  $obj = new DUP_Package();
474
-
475
- $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM `{$wpdb->prefix}duplicator_packages` WHERE ID = %s", $id));
 
476
  if (is_object($row)) {
477
  $obj = @unserialize($row->package);
478
  $obj->Status = $row->status;
@@ -491,7 +1238,7 @@ class DUP_Package
491
  {
492
  //Remove specail_chars from final result
493
  $special_chars = array(".", "-");
494
- $name = ($preDate)
495
  ? date('Ymd') . '_' . sanitize_title(get_bloginfo('name', 'display'))
496
  : sanitize_title(get_bloginfo('name', 'display')) . '_' . date('Ymd');
497
  $name = substr(sanitize_file_name($name), 0, 40);
@@ -528,10 +1275,10 @@ class DUP_Package
528
 
529
  /**
530
  * Provides various date formats
531
- *
532
  * @param $date The date to format
533
  * @param $format Various date formats to apply
534
- *
535
  * @return a formated date based on the $format
536
  */
537
  public static function getCreatedDateFormat($date, $format = 1)
@@ -573,9 +1320,8 @@ class DUP_Package
573
  /**
574
  * Cleans up all the tmp files as part of the package build process
575
  */
576
- private function buildCleanup()
577
  {
578
-
579
  $files = DUP_Util::listFiles(DUPLICATOR_SSDIR_PATH_TMP);
580
  $newPath = DUPLICATOR_SSDIR_PATH;
581
 
@@ -597,17 +1343,19 @@ class DUP_Package
597
  }
598
  }
599
 
 
 
600
  /**
601
  * Get package hash
602
- *
603
  * @return string package hash
604
  */
605
  public function getPackageHash() {
606
  $hashParts = explode('_', $this->Hash);
607
  $firstPart = substr($hashParts[0], 0, 7);
608
  $secondPart = substr($hashParts[1], -8);
609
- $packageHash = $firstPart.'-'.$secondPart;
610
- return $packageHash;
611
  }
612
 
613
  /**
@@ -617,9 +1365,31 @@ class DUP_Package
617
  */
618
  public function getSqlArkFilePath()
619
  {
620
- $packageHash = $this->getPackageHash();
621
- $sqlArkFilePath = 'dup-database__'.$packageHash.'.sql';
622
- return $sqlArkFilePath;
623
  }
624
- }
625
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
 
5
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.php');
6
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.php');
7
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.installer.php');
8
  require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.database.php');
9
 
10
+ /**
11
+ * Class used to keep track of the build progress
12
+ *
13
+ * @package Duplicator\classes
14
+ */
15
+ class DUP_Build_Progress
16
  {
17
+ public $thread_start_time;
18
+ public $initialized = false;
19
+ public $installer_built = false;
20
+ public $archive_started = false;
21
+ public $archive_has_database = false;
22
+ public $archive_built = false;
23
+ public $database_script_built = false;
24
+ public $failed = false;
25
+ public $retries = 0;
26
+ public $build_failures = array();
27
+ public $validation_failures = array();
28
+
29
+ private $package;
30
+
31
+ public function __construct($package)
32
+ {
33
+ $this->package = $package;
34
+ }
35
 
36
+ public function has_completed()
37
+ {
38
+ return $this->failed || ($this->installer_built && $this->archive_built && $this->database_script_built);
39
+ }
40
+
41
+ public function timed_out($max_time)
42
+ {
43
+ if ($max_time > 0) {
44
+ $time_diff = time() - $this->thread_start_time;
45
+ return ($time_diff >= $max_time);
46
+ } else {
47
+ return false;
48
+ }
49
+ }
50
+
51
+ public function start_timer()
52
+ {
53
+ $this->thread_start_time = time();
54
+ }
55
+
56
+ public function set_validation_failures($failures)
57
+ {
58
+ $this->validation_failures = array();
59
+
60
+ foreach ($failures as $failure) {
61
+ $this->validation_failures[] = $failure;
62
+ }
63
+ }
64
+
65
+ public function set_build_failures($failures)
66
+ {
67
+ $this->build_failures = array();
68
+
69
+ foreach ($failures as $failure) {
70
+ $this->build_failures[] = $failure->description;
71
+ }
72
+ }
73
+
74
+ public function set_failed($failure_message = null)
75
  {
76
+ if($failure_message !== null) {
77
+ $failure = new StdClass();
78
+ $failure->type = 0;
79
+ $failure->subject = '';
80
+ $failure->description = $failure_message;
81
+ $failure->isCritical = true;
82
+ $this->build_failures[] = $failure;
83
+ }
84
+
85
+ $this->failed = true;
86
+ $this->package->Status = DUP_PackageStatus::ERROR;
87
+ }
88
+ }
89
 
90
+ /**
91
+ * Class used to emulate and ENUM to give the status of a package from 0 to 100%
92
+ *
93
+ * @package Duplicator\classes
94
+ */
95
+ final class DUP_PackageStatus
96
+ {
97
+ private function __construct()
98
+ {
99
  }
100
+
101
+ const ERROR = -1;
102
+ const CREATED = 0;
103
  const START = 10;
104
  const DBSTART = 20;
105
  const DBDONE = 30;
106
  const ARCSTART = 40;
107
+ const ARCVALIDATION = 60;
108
+ const ARCDONE = 65;
109
  const COMPLETE = 100;
 
110
  }
111
 
112
+ /**
113
+ * Class used to emulate and ENUM to determine how the package was made.
114
+ * For lite only the MANUAL type is used.
115
+ *
116
+ * @package Duplicator\classes
117
+ */
118
  final class DUP_PackageType
119
  {
120
  const MANUAL = 0;
121
  const SCHEDULED = 1;
122
+ }
123
 
124
+ /**
125
+ * Class used to emulate and ENUM to determine the various file types used in a package
126
+ *
127
+ * @package Duplicator\classes
128
+ */
129
+ abstract class DUP_PackageFileType
130
+ {
131
+ const Installer = 0;
132
+ const Archive = 1;
133
+ const SQL = 2;
134
+ const Log = 3;
135
  }
136
 
137
  /**
138
  * Class used to store and process all Package logic
139
  *
140
+ * Standard: PSR-2
141
+ * @link http://www.php-fig.org/psr/psr-2
142
+ *
143
  * @package Duplicator\classes
144
  */
145
  class DUP_Package
157
  public $Name;
158
  public $Hash;
159
  public $NameHash;
160
+ //Set to DUP_PackageType
161
  public $Type;
162
  public $Notes;
163
  public $StorePath;
164
  public $StoreURL;
165
  public $ScanFile;
166
+ public $TimerStart = -1;
167
  public $Runtime;
168
  public $ExeSize;
169
  public $ZipSize;
174
  public $Installer;
175
  public $Database;
176
 
177
+ public $BuildProgress;
178
+
179
  /**
180
  * Manages the Package Process
181
  */
182
  function __construct()
183
  {
 
184
  $this->ID = null;
185
  $this->Version = DUPLICATOR_VERSION;
 
186
  $this->Type = DUP_PackageType::MANUAL;
187
  $this->Name = self::getDefaultName();
188
  $this->Notes = null;
191
  $this->Database = new DUP_Database($this);
192
  $this->Archive = new DUP_Archive($this);
193
  $this->Installer = new DUP_Installer($this);
194
+ $this->BuildProgress = new DUP_Build_Progress($this);
195
+ $this->Status = DUP_PackageStatus::CREATED;
196
  }
197
 
198
  /**
199
+ * Generates a JSON scan report
200
  *
201
  * @return array of scan results
202
  *
239
  $report['ARC']['Dirs'] = $this->Archive->Dirs;
240
  $report['ARC']['Files'] = $this->Archive->Files;
241
  $report['ARC']['Status']['AddonSites'] = count($this->Archive->FilterInfo->Dirs->AddonSites) ? 'Warn' : 'Good';
 
 
242
 
243
  //DATABASE
244
  $db = $this->Database->getScannerData();
245
  $report['DB'] = $db;
246
 
247
+ //Lite Limits
248
+ $rawTotalSize = $this->Archive->Size + $report['DB']['RawSize'];
249
+ $report['LL']['TotalSize'] = DUP_Util::byteSize($rawTotalSize);
250
+ $report['LL']['Status']['TotalSize'] = ($rawTotalSize > DUPLICATOR_MAX_DUPARCHIVE_SIZE) ? 'Fail' : 'Good';
251
+
252
  $warnings = array(
253
  $report['SRV']['PHP']['ALL'],
254
  $report['SRV']['WP']['ALL'],
255
  $report['ARC']['Status']['Size'],
256
  $report['ARC']['Status']['Names'],
257
  $db['Status']['DB_Size'],
258
+ $db['Status']['DB_Rows']
259
+ );
260
 
261
  //array_count_values will throw a warning message if it has null values,
262
  //so lets replace all nulls with empty string
265
  $warnings[$i] = '';
266
  }
267
  }
268
+
269
  $warn_counts = is_array($warnings) ? array_count_values($warnings) : 0;
270
  $report['RPT']['Warnings'] = is_null($warn_counts['Warn']) ? 0 : $warn_counts['Warn'];
271
  $report['RPT']['Success'] = is_null($warn_counts['Good']) ? 0 : $warn_counts['Good'];
280
  }
281
 
282
  /**
283
+ * Validates the inputs from the UI for correct data input
284
+ *
285
+ * @return DUP_Validator
286
+ */
287
+ public function validateInputs()
288
+ {
289
+ $validator = new DUP_Validator();
290
+
291
+ $validator->filter_custom($this->Name , DUP_Validator::FILTER_VALIDATE_NOT_EMPTY ,
292
+ array( 'valkey' => 'Name' ,
293
+ 'errmsg' => __('Package name can\'t be empty', 'duplicator'),
294
+ )
295
+ );
296
+
297
+ $validator->explode_filter_custom($this->Archive->FilterDirs, ';' , DUP_Validator::FILTER_VALIDATE_FOLDER ,
298
+ array( 'valkey' => 'FilterDirs' ,
299
+ 'errmsg' => __('Directories: <b>%1$s</b> isn\'t a valid path', 'duplicator'),
300
+ )
301
+ );
302
+
303
+ $validator->explode_filter_custom($this->Archive->FilterExts, ';' , DUP_Validator::FILTER_VALIDATE_FILE_EXT ,
304
+ array( 'valkey' => 'FilterExts' ,
305
+ 'errmsg' => __('File extension: <b>%1$s</b> isn\'t a valid extension', 'duplicator'),
306
+ )
307
+ );
308
+
309
+ $validator->explode_filter_custom($this->Archive->FilterFiles, ';' , DUP_Validator::FILTER_VALIDATE_FILE ,
310
+ array( 'valkey' => 'FilterFiles' ,
311
+ 'errmsg' => __('Files: <b>%1$s</b> isn\'t a valid file name', 'duplicator'),
312
+ )
313
+ );
314
+
315
+ $validator->filter_var($this->Installer->OptsDBHost, FILTER_VALIDATE_URL , array(
316
+ 'valkey' => 'OptsDBHost' ,
317
+ 'errmsg' => __('MySQL Server Host: <b>%1$s</b> isn\'t a valid host', 'duplicator'),
318
+ 'acc_vals' => array(
319
+ '' ,
320
+ 'localhost'
321
+ )
322
+ )
323
+ );
324
+
325
+ $validator->filter_var($this->Installer->OptsDBPort, FILTER_VALIDATE_INT , array(
326
+ 'valkey' => 'OptsDBPort' ,
327
+ 'errmsg' => __('MySQL Server Port: <b>%1$s</b> isn\'t a valid port', 'duplicator'),
328
+ 'acc_vals' => array(
329
+ ''
330
+ ),
331
+ 'options' => array(
332
+ 'min_range' => 0
333
+ )
334
+ )
335
+ );
336
+
337
+ return $validator;
338
+ }
339
+
340
+ /**
341
+ * Saves the active package to the package table
342
  *
343
+ * @return void
344
+ */
345
+ public function save($extension)
346
+ {
347
+ global $wpdb;
348
+
349
+ $this->Archive->Format = strtoupper($extension);
350
+ $this->Archive->File = "{$this->NameHash}_archive.{$extension}";
351
+ $this->Installer->File = "{$this->NameHash}_installer.php";
352
+ $this->Database->File = "{$this->NameHash}_database.sql";
353
+ $this->WPUser = isset($current_user->user_login) ? $current_user->user_login : 'unknown';
354
+
355
+ //START LOGGING
356
+ DUP_Log::Open($this->NameHash);
357
+
358
+ do_action('duplicator_lite_build_before_start' , $this);
359
+
360
+ $this->writeLogHeader();
361
+
362
+ //CREATE DB RECORD
363
+ $packageObj = serialize($this);
364
+ if (!$packageObj) {
365
+ DUP_Log::Error("Unable to serialize package object while building record.");
366
+ }
367
+
368
+ $this->ID = $this->getHashKey($this->Hash);
369
+
370
+ if ($this->ID != 0) {
371
+ DUP_LOG::Trace("ID non zero so setting to start");
372
+ $this->setStatus(DUP_PackageStatus::START);
373
+ } else {
374
+ DUP_LOG::Trace("ID IS zero so creating another package");
375
+ $tablePrefix = DUP_Util::getTablePrefix();
376
+ $results = $wpdb->insert($tablePrefix . "duplicator_packages", array(
377
+ 'name' => $this->Name,
378
+ 'hash' => $this->Hash,
379
+ 'status' => DUP_PackageStatus::START,
380
+ 'created' => current_time('mysql', get_option('gmt_offset', 1)),
381
+ 'owner' => isset($current_user->user_login) ? $current_user->user_login : 'unknown',
382
+ 'package' => $packageObj)
383
+ );
384
+ if ($results === false) {
385
+ $wpdb->print_error();
386
+ DUP_LOG::Trace("Problem inserting package: {$wpdb->last_error}");
387
+
388
+ DUP_Log::Error("Duplicator is unable to insert a package record into the database table.", "'{$wpdb->last_error}'");
389
+ }
390
+ $this->ID = $wpdb->insert_id;
391
+ }
392
+
393
+ do_action('duplicator_lite_build_start' , $this);
394
+ }
395
+
396
+ /**
397
+ * Delete all files associated with this package ID
398
+ *
399
+ * @return void
400
  */
401
+ public function delete()
402
  {
 
403
  global $wpdb;
 
404
 
405
+ $tablePrefix = DUP_Util::getTablePrefix();
406
+ $tblName = $tablePrefix.'duplicator_packages';
407
+ $getResult = $wpdb->get_results($wpdb->prepare("SELECT name, hash FROM `{$tblName}` WHERE id = %d", $this->ID), ARRAY_A);
408
+
409
+ if ($getResult) {
410
+ $row = $getResult[0];
411
+ $nameHash = "{$row['name']}_{$row['hash']}";
412
+ $delResult = $wpdb->query($wpdb->prepare("DELETE FROM `{$tblName}` WHERE id = %d", $this->ID));
413
+
414
+ if ($delResult != 0) {
415
+ //Perms
416
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_archive.zip"), 0644);
417
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_database.sql"), 0644);
418
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_installer.php"), 0644);
419
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_scan.json"), 0644);
420
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}.log"), 0644);
421
+
422
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_archive.zip"), 0644);
423
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_database.sql"), 0644);
424
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_installer.php"), 0644);
425
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_scan.json"), 0644);
426
+ @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}.log"), 0644);
427
+ //Remove
428
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_archive.zip"));
429
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_database.sql"));
430
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_installer.php"));
431
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_scan.json"));
432
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}.log"));
433
+
434
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_archive.zip"));
435
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_database.sql"));
436
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_installer.php"));
437
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_scan.json"));
438
+ @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}.log"));
439
+ }
440
+ }
441
+ }
442
 
443
+ /**
444
+ * Get all packages with status conditions
445
+ * @global wpdb $wpdb
446
+ * @param array $conditions es. [
447
+ * relation = 'AND',
448
+ * [ 'op' => '>=' ,
449
+ * 'status' => DUP_PackageStatus::START ]
450
+ * [ 'op' => '<' ,
451
+ * 'status' => DUP_PackageStatus::COMPLETED ]
452
+ * ]
453
+ * @return DUP_Package[]
454
+ */
455
+ public static function get_all_by_status($conditions = array())
456
+ {
457
+ global $wpdb;
458
+ $tablePrefix = DUP_Util::getTablePrefix();
459
+ $table = $tablePrefix . "duplicator_packages";
460
 
461
+ $accepted_op = array('<', '>', '=', '<>', '>=', '<=');
462
+ $relation = (isset($conditions['relation']) && strtoupper($conditions['relation']) == 'OR') ? ' OR ' : ' AND ';
463
+ unset($conditions['relation']);
 
 
 
464
 
465
+ $where = '';
 
 
 
 
 
 
 
 
 
 
 
 
466
 
467
+ if (!empty($conditions)) {
468
+ $str_conds = array();
469
+
470
+ foreach ($conditions as $cond) {
471
+ $op = (isset($cond['op']) && in_array($cond['op'], $accepted_op)) ? $cond['op'] : '=';
472
+ $status = isset($cond['status']) ? (int) $cond['status'] : 0;
473
+ $str_conds[] = 'status '.$op.' '.$status;
474
+ }
475
+ $where = ' WHERE '.implode($relation, $str_conds).' ';
476
+ }
477
+
478
+ $packages = array();
479
+ $rows = $wpdb->get_results("SELECT * FROM `{$table}` {$where} ORDER BY id DESC", ARRAY_A);
480
+
481
+ if ($rows != null) {
482
+ foreach ($rows as $row) {
483
+ $Package = unserialize($row['package']);
484
+ if ($Package) {
485
+ // We was not storing Status in Lite 1.2.52, so it is for backward compatibility
486
+ if (!isset($Package->Status)) {
487
+ $Package->Status = $row['status'];
488
+ }
489
+
490
+ $packages[] = $Package;
491
+ }
492
+ }
493
+ }
494
+ return $packages;
495
+ }
496
+
497
+ /**
498
+ *
499
+ * @global wpdb $wpdb
500
+ * @return DUP_Package[]
501
+ */
502
+ public static function get_all()
503
+ {
504
+ global $wpdb;
505
+ $tablePrefix = DUP_Util::getTablePrefix();
506
+ $table = $tablePrefix."duplicator_packages";
507
+
508
+ $packages = array();
509
+ $rows = $wpdb->get_results("SELECT * FROM `{$table}` ORDER BY id DESC", ARRAY_A);
510
+ if ($rows != null) {
511
+ foreach ($rows as $row) {
512
+ $Package = unserialize($row['package']);
513
+ if ($Package) {
514
+ // We was not storing Status in Lite 1.2.52, so it is for backward compatibility
515
+ if (!isset($Package->Status)) {
516
+ $Package->Status = $row['status'];
517
+ }
518
+
519
+ $packages[] = $Package;
520
+ }
521
+ }
522
+ }
523
+ return $packages;
524
+ }
525
+
526
+ /**
527
+ * Check the DupArchive build to make sure it is good
528
+ *
529
+ * @return void
530
+ */
531
+ public function runDupArchiveBuildIntegrityCheck()
532
+ {
533
+ //INTEGRITY CHECKS
534
+ //We should not rely on data set in the serlized object, we need to manually check each value
535
+ //indepentantly to have a true integrity check.
536
+ DUP_Log::info("\n********************************************************************************");
537
+ DUP_Log::info("INTEGRITY CHECKS:");
538
+ DUP_Log::info("********************************************************************************");
539
+
540
+ //------------------------
541
+ //SQL CHECK: File should be at minimum 5K. A base WP install with only Create tables is about 9K
542
+ $sql_temp_path = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP . '/' . $this->Database->File);
543
+ $sql_temp_size = @filesize($sql_temp_path);
544
+ $sql_easy_size = DUP_Util::byteSize($sql_temp_size);
545
+ $sql_done_txt = DUP_Util::tailFile($sql_temp_path, 3);
546
+ DUP_Log::Trace('rundupa1');
547
+
548
+ // Note: Had to add extra size check of 800 since observed bad sql when filter was on
549
+ if (!strstr($sql_done_txt, 'DUPLICATOR_MYSQLDUMP_EOF') || (!$this->Database->FilterOn && $sql_temp_size < 5120) || ($this->Database->FilterOn && $this->Database->info->tablesFinalCount > 0 && $sql_temp_size < 800)) {
550
+ DUP_Log::Trace('rundupa2');
551
+
552
+ $error_text = "ERROR: SQL file not complete. The file {$sql_temp_path} looks too small ($sql_temp_size bytes) or the end of file marker was not found.";
553
+ $this->BuildProgress->set_failed($error_text);
554
+ $this->update();
555
+ //$this->setStatus(DUP_PackageStatus::ERROR);
556
+ DUP_Log::Error("$error_text", '', Dup_ErrorBehavior::LogOnly);
557
+
558
+ return;
559
+ }
560
+
561
+ DUP_Log::Trace('rundupa3');
562
+ DUP_Log::Info("SQL FILE: {$sql_easy_size}");
563
+
564
+ //------------------------
565
+ //INSTALLER CHECK:
566
+ $exe_temp_path = DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP . '/' . $this->Installer->File);
567
+
568
+ $exe_temp_size = @filesize($exe_temp_path);
569
+ $exe_easy_size = DUP_Util::byteSize($exe_temp_size);
570
+ $exe_done_txt = DUP_Util::tailFile($exe_temp_path, 10);
571
+
572
+ if (!strstr($exe_done_txt, 'DUPLICATOR_INSTALLER_EOF') && !$this->BuildProgress->failed) {
573
+ //$this->BuildProgress->failed = true;
574
+ $error_message = 'ERROR: Installer file not complete. The end of file marker was not found. Please try to re-create the package.';
575
+
576
+ $this->BuildProgress->set_failed($error_message);
577
+ $this->update();
578
+ //$this->setStatus(DUP_PackageStatus::ERROR);
579
+ DUP_Log::error($error_message, '', Dup_ErrorBehavior::LogOnly);
580
+ return;
581
+ }
582
+ DUP_Log::info("INSTALLER FILE: {$exe_easy_size}");
583
+
584
+ //------------------------
585
+ //ARCHIVE CHECK:
586
+ DUP_LOG::trace("Archive file count is " . $this->Archive->file_count);
587
+
588
+ if ($this->Archive->file_count != -1) {
589
+ $zip_easy_size = DUP_Util::byteSize($this->Archive->Size);
590
+ if (!($this->Archive->Size)) {
591
+ //$this->BuildProgress->failed = true;
592
+ $error_message = "ERROR: The archive file contains no size.";
593
+
594
+ $this->BuildProgress->set_failed($error_message);
595
+ $this->update();
596
+ //$this->setStatus(DUP_PackageStatus::ERROR);
597
+ DUP_Log::error($error_message, "Archive Size: {$zip_easy_size}", Dup_ErrorBehavior::LogOnly);
598
+ return;
599
+ }
600
+
601
+ $scan_filepath = DUPLICATOR_SSDIR_PATH_TMP . "/{$this->NameHash}_scan.json";
602
+ $json = '';
603
+
604
+ DUP_LOG::Trace("***********Does $scan_filepath exist?");
605
+ if (file_exists($scan_filepath)) {
606
+ $json = file_get_contents($scan_filepath);
607
+ } else {
608
+ $error_message = sprintf(__("Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name.", 'duplicator'), $scan_filepath);
609
+
610
+ //$this->BuildProgress->failed = true;
611
+ $this->setStatus(DUP_PackageStatus::ERROR);
612
+ $this->BuildProgress->set_failed($error_message);
613
+ $this->update();
614
+
615
+ DUP_Log::Error($error_message, '', Dup_ErrorBehavior::LogOnly);
616
+ return;
617
+ }
618
+
619
+ $scanReport = json_decode($json);
620
+
621
+ //RSR TODO: rework/simplify the validateion of duparchive
622
+ $dirCount = count($scanReport->ARC->Dirs);
623
+ $numInstallerDirs = $this->Installer->numDirsAdded;
624
+ $fileCount = count($scanReport->ARC->Files);
625
+ $numInstallerFiles = $this->Installer->numFilesAdded;
626
+
627
+ $expected_filecount = $dirCount + $numInstallerDirs + $fileCount + $numInstallerFiles + 1 -1; // Adding database.sql but subtracting the root dir
628
+ //Dup_Log::trace("#### a:{$dirCount} b:{$numInstallerDirs} c:{$fileCount} d:{$numInstallerFiles} = {$expected_filecount}");
629
+
630
+ DUP_Log::info("ARCHIVE FILE: {$zip_easy_size} ");
631
+ DUP_Log::info(sprintf(__('EXPECTED FILE/DIRECTORY COUNT: %1$s', 'duplicator'), number_format($expected_filecount)));
632
+ DUP_Log::info(sprintf(__('ACTUAL FILE/DIRECTORY COUNT: %1$s', 'duplicator'), number_format($this->Archive->file_count)));
633
+
634
+ $this->ExeSize = $exe_easy_size;
635
+ $this->ZipSize = $zip_easy_size;
636
+
637
+ /* ------- ZIP Filecount Check -------- */
638
+ // Any zip of over 500 files should be within 2% - this is probably too loose but it will catch gross errors
639
+ DUP_LOG::trace("Expected filecount = $expected_filecount and archive filecount=" . $this->Archive->file_count);
640
+
641
+ if ($expected_filecount > 500) {
642
+ $straight_ratio = (float) $expected_filecount / (float) $this->Archive->file_count;
643
+
644
+ $warning_count = $scanReport->ARC->WarnFileCount + $scanReport->ARC->WarnDirCount + $scanReport->ARC->UnreadableFileCount + $scanReport->ARC->UnreadableDirCount;
645
+ DUP_LOG::trace("Warn/unread counts) warnfile:{$scanReport->ARC->WarnFileCount} warndir:{$scanReport->ARC->WarnDirCount} unreadfile:{$scanReport->ARC->UnreadableFileCount} unreaddir:{$scanReport->ARC->UnreadableDirCount}");
646
+
647
+ $warning_ratio = ((float) ($expected_filecount + $warning_count)) / (float) $this->Archive->file_count;
648
+ DUP_LOG::trace("Straight ratio is $straight_ratio and warning ratio is $warning_ratio. # Expected=$expected_filecount # Warning=$warning_count and #Archive File {$this->Archive->file_count}");
649
+
650
+ // Allow the real file count to exceed the expected by 10% but only allow 1% the other way
651
+ if (($straight_ratio < 0.90) || ($straight_ratio > 1.01)) {
652
+ // Has to exceed both the straight as well as the warning ratios
653
+ if (($warning_ratio < 0.90) || ($warning_ratio > 1.01)) {
654
+
655
+ $error_message = sprintf('ERROR: File count in archive vs expected suggests a bad archive (%1$d vs %2$d).', $archive_file_count, $expected_filecount);
656
+ $this->BuildProgress->set_failed($error_message);
657
+ $this->update();
658
+ $archive_file_count = $this->Archive->file_count;
659
+ DUP_Log::error($error_message, '', Dup_ErrorBehavior::LogOnly);
660
+ return;
661
+ }
662
+ }
663
+ }
664
+ }
665
+ }
666
+
667
+ public function getLocalPackageFile($file_type)
668
+ {
669
+ $file_path = null;
670
+
671
+ if ($file_type == DUP_PackageFileType::Installer) {
672
+ DUP_Log::Trace("Installer requested");
673
+ $file_name = $this->getInstallerFilename();
674
+ } else if ($file_type == DUP_PackageFileType::Archive) {
675
+ DUP_Log::Trace("Archive requested");
676
+ $file_name = $this->getArchiveFilename();
677
+ } else if ($file_type == DUP_PackageFileType::SQL) {
678
+ DUP_Log::Trace("SQL requested");
679
+ $file_name = $this->getDatabaseFilename();
680
+ } else {
681
+ DUP_Log::Trace("Log requested");
682
+ $file_name = $this->getLogFilename();
683
  }
684
 
685
+ $file_path = Dup_Util::safePath(DUPLICATOR_SSDIR_PATH) . "/$file_name";
686
+ DUP_Log::Trace("File path $file_path");
687
 
688
+ if (file_exists($file_path)) {
689
+ return $file_path;
690
  } else {
691
+ return null;
692
+ }
693
+ }
694
+
695
+ public function getScanFilename()
696
+ {
697
+ return $this->NameHash . '_scan.json';
698
+ }
699
+
700
+ public function getLogFilename()
701
+ {
702
+ return $this->NameHash . '.log';
703
+ }
704
+
705
+ public function getArchiveFilename()
706
+ {
707
+ $extension = strtolower($this->Archive->Format);
708
+
709
+ return "{$this->NameHash}_archive.{$extension}";
710
+ }
711
+
712
+ public function getInstallerFilename()
713
+ {
714
+ return "{$this->NameHash}_installer.php";
715
+ }
716
+
717
+ public function getDatabaseFilename()
718
+ {
719
+ return $this->NameHash . '_database.sql';
720
+ }
721
+
722
+ /**
723
+ * Removes all files except those of active packages
724
+ */
725
+ public static function not_active_files_tmp_cleanup()
726
+ {
727
+ //Check for the 'tmp' folder just for safe measures
728
+ if (! is_dir(DUPLICATOR_SSDIR_PATH_TMP) && (strpos(DUPLICATOR_SSDIR_PATH_TMP, 'tmp') !== false) ) {
729
+ return;
730
+ }
731
+
732
+ $iterator = new FilesystemIterator(DUPLICATOR_SSDIR_PATH_TMP);
733
+
734
+ // if tmp is empty return
735
+ if (!$iterator->valid()) {
736
+ return;
737
+ }
738
+
739
+ // RUNNING PACKAGES
740
+ $active_pack = self::get_all_by_status(array(
741
+ 'relation' => 'AND',
742
+ array('op' => '>=' , 'status' => DUP_PackageStatus::CREATED ),
743
+ array('op' => '<' , 'status' => DUP_PackageStatus::COMPLETE )
744
+ ));
745
+ $active_files = array();
746
+ foreach($active_pack as $package) {
747
+ $active_files[] = $package->NameHash;
748
+ }
749
+
750
+ // ERRORS PACKAGES
751
+ $err_pack = self::get_all_by_status(array(
752
+ array('op' => '<' , 'status' => DUP_PackageStatus::CREATED )
753
+ ));
754
+ $force_del_files = array();
755
+ foreach($err_pack as $package) {
756
+ $force_del_files[] = $package->NameHash;
757
+ }
758
+
759
+ // Don't remove json file;
760
+ $extension_filter = array('json');
761
+
762
+ // Calculate delta time for old files
763
+ $oldTimeToClean = time() - DUPLICATOR_TEMP_CLEANUP_SECONDS;
764
+
765
+ foreach ($iterator as $fileinfo) {
766
+ // Don't remove sub dir
767
+ if ($fileinfo->isDir()) {
768
+ continue;
769
+ }
770
+
771
+ // skip all active packages
772
+ foreach ($active_files as $c_nameHash) {
773
+ if (strpos($fileinfo->getFilename(), $c_nameHash) === 0) {
774
+ continue 2;
775
+ }
776
+ }
777
+
778
+ // Remove all old files
779
+ if ($fileinfo->getCTime() <= $oldTimeToClean) {
780
+ @unlink($fileinfo->getRealPath());
781
+ continue;
782
+ }
783
 
784
+ // remove all error packages files
785
+ foreach ($force_del_files as $c_nameHash) {
786
+ if (strpos($fileinfo->getFilename(), $c_nameHash) === 0) {
787
+ @unlink($fileinfo->getRealPath());
788
+ continue 2;
789
+ }
790
+ }
791
+
792
+ // skip json file for pre build packages
793
+ if (in_array($fileinfo->getExtension(),$extension_filter) || in_array($fileinfo->getFilename() , $active_files)) {
794
+ continue;
795
+ }
796
+
797
+ @unlink($fileinfo->getRealPath());
798
+ }
799
+ }
800
+
801
+ /**
802
+ * Cleans up the temp storage folder have a time interval
803
+ *
804
+ * @return void
805
+ */
806
+ public static function safeTmpCleanup($purge_temp_archives = false)
807
+ {
808
+ if ($purge_temp_archives) {
809
+ $dir = DUPLICATOR_SSDIR_PATH_TMP . "/*_archive.zip.*";
810
+ foreach (glob($dir) as $file_path) {
811
+ unlink($file_path);
812
+ }
813
+ $dir = DUPLICATOR_SSDIR_PATH_TMP . "/*_archive.daf.*";
814
+ foreach (glob($dir) as $file_path) {
815
+ unlink($file_path);
816
+ }
817
+ } else {
818
+ //Remove all temp files that are 24 hours old
819
+ $dir = DUPLICATOR_SSDIR_PATH_TMP . "/*";
820
+
821
+ $files = glob($dir);
822
+
823
+ if ($files !== false) {
824
+ foreach ($files as $file_path) {
825
+ // Cut back to keeping things around for just an hour 15 min
826
+ if (filemtime($file_path) <= time() - DUPLICATOR_TEMP_CLEANUP_SECONDS) {
827
+ unlink($file_path);
828
+ }
829
+ }
830
  }
831
+ }
832
+ }
833
+
834
+ /**
835
+ * Starts the package DupArchive progressive build process - always assumed to only run off active package, NOT one in the package table
836
+ *
837
+ * @return obj Returns a DUP_Package object
838
+ */
839
+ public function runDupArchiveBuild()
840
+ {
841
+ $this->BuildProgress->start_timer();
842
+ DUP_Log::Trace('Called');
843
+
844
+ if ($this->BuildProgress->failed) {
845
+
846
+ DUP_LOG::Trace("build progress failed so setting package to failed");
847
+ $this->setStatus(DUP_PackageStatus::ERROR);
848
+ $message = "Package creation failed.";
849
+ DUP_Log::Trace($message);
850
+ return true;
851
+ }
852
+
853
+ if ($this->BuildProgress->initialized == false) {
854
+ DUP_Log::Trace('Initializing');
855
+ $this->BuildProgress->initialized = true;
856
+ $this->TimerStart = Dup_Util::getMicrotime();
857
+ $this->update();
858
  }
859
 
860
+ //START BUILD
861
+ if (!$this->BuildProgress->database_script_built) {
862
+ DUP_Log::Trace('Building database script');
863
+
864
+ $this->Database->build($this, Dup_ErrorBehavior::ThrowException);
865
+ $this->BuildProgress->database_script_built = true;
866
+ $this->update();
867
+ DUP_LOG::Trace("Built database script");
868
+ } else if (!$this->BuildProgress->archive_built) {
869
+ DUP_Log::Trace('e');
870
+
871
+ $this->Archive->build($this);
872
+ $this->update();
873
+ } else if (!$this->BuildProgress->installer_built) {
874
+
875
+ DUP_Log::Trace('f');
876
+ // Installer being built is stuffed into the archive build phase
877
+ }
878
+
879
+ if ($this->BuildProgress->has_completed()) {
880
+
881
+ DUP_Log::Trace('c');
882
+
883
+ if (!$this->BuildProgress->failed) {
884
+ DUP_LOG::trace("top of loop build progress not failed");
885
+ // Only makees sense to perform build integrity check on completed archives
886
+ $this->runDupArchiveBuildIntegrityCheck();
887
+ } else {
888
+ DUP_LOG::trace("top of loop build progress failed");
889
+ }
890
+
891
+ $timerEnd = DUP_Util::getMicrotime();
892
+ $timerSum = DUP_Util::elapsedTime($timerEnd, $this->TimerStart);
893
+ $this->Runtime = $timerSum;
894
+
895
+ //FINAL REPORT
896
+ $info = "\n********************************************************************************\n";
897
+ $info .= "RECORD ID:[{$this->ID}]\n";
898
+ $info .= "TOTAL PROCESS RUNTIME: {$timerSum}\n";
899
+ $info .= "PEAK PHP MEMORY USED: " . DUP_Server::getPHPMemory(true) . "\n";
900
+ $info .= "DONE PROCESSING => {$this->Name} " . @date("Y-m-d H:i:s") . "\n";
901
+
902
+ DUP_Log::info($info);
903
+ DUP_LOG::trace("Done package building");
904
+
905
+ if (!$this->BuildProgress->failed) {
906
+
907
+ $this->setStatus(DUP_PackageStatus::COMPLETE);
908
+ DUP_LOG::Trace("Cleaning up duparchive temp files");
909
+ //File Cleanup
910
+ $this->buildCleanup();
911
+ do_action('duplicator_lite_build_completed' , $this);
912
+ }
913
+ }
914
+
915
+ DUP_Log::Close();
916
+
917
+ return $this->BuildProgress->has_completed();
918
+ }
919
+
920
+ /**
921
+ * Starts the package build process
922
+ *
923
+ * @return obj Returns a DUP_Package object
924
+ */
925
+ public function runZipBuild()
926
+ {
927
+ $timerStart = DUP_Util::getMicrotime();
928
+
929
+ DUP_Log::Trace('#### start of zip build');
930
  //START BUILD
931
  //PHPs serialze method will return the object, but the ID above is not passed
932
  //for one reason or another so passing the object back in seems to do the trick
986
  * @see DUP_Package::getActive
987
  *
988
  * @param $_POST $post The Post server object
989
+ *
990
  * @return null
991
  */
992
  public function saveActive($post = null)
996
  if (isset($post)) {
997
  $post = stripslashes_deep($post);
998
 
999
+ $name = isset($post['package-name']) ? trim($post['package-name']) : self::getDefaultName();
1000
+ $name = str_replace(array(' ', '-'), '_', $name);
1001
+ $name = str_replace(array('.', ';', ':', "'", '"'), '', $name);
1002
+ $name = sanitize_file_name($name);
1003
+ $name = substr(trim($name), 0, 40);
1004
 
1005
+ if (isset($post['filter-dirs'])) {
1006
+ $post_filter_dirs = sanitize_text_field($post['filter-dirs']);
1007
+ $filter_dirs = $this->Archive->parseDirectoryFilter($post_filter_dirs);
1008
+ } else {
1009
+ $filter_dirs = '';
1010
+ }
1011
+
1012
+ if (isset($post['filter-files'])) {
1013
+ $post_filter_files = sanitize_text_field($post['filter-files']);
1014
+ $filter_files = $this->Archive->parseFileFilter($post_filter_files);
1015
+ } else {
1016
+ $filter_files = '';
1017
+ }
1018
+
1019
+ if (isset($post['filter-exts'])) {
1020
+ $post_filter_exts = sanitize_text_field($post['filter-exts']);
1021
+ $filter_exts = $this->Archive->parseExtensionFilter($post_filter_exts);
1022
+ } else {
1023
+ $filter_exts = '';
1024
+ }
1025
+
1026
+ $tablelist = '';
1027
+ if (isset($post['dbtables'])) {
1028
+ $tablelist = implode(',', $post['dbtables']);
1029
+ }
1030
 
1031
+ if (isset($post['dbcompat'])) {
1032
+ $post_dbcompat = sanitize_text_field($post['dbcompat']);
1033
+ $compatlist = isset($post['dbcompat']) ? implode(',', $post_dbcompat) : '';
1034
+ } else {
1035
+ $compatlist = '';
1036
+ }
1037
+
1038
+ $dbversion = DUP_DB::getVersion();
1039
+ $dbversion = is_null($dbversion) ? '- unknown -' : sanitize_text_field($dbversion);
1040
+ $dbcomments = sanitize_text_field(DUP_DB::getVariable('version_comment'));
1041
+ $dbcomments = is_null($dbcomments) ? '- unknown -' : sanitize_text_field($dbcomments);
1042
 
1043
  //PACKAGE
1044
  $this->Created = date("Y-m-d H:i:s");
1049
  $this->VersionDB = sanitize_text_field($dbversion);
1050
  $this->Name = sanitize_text_field($name);
1051
  $this->Hash = $this->makeHash();
1052
+ $this->NameHash = sanitize_text_field("{$this->Name}_{$this->Hash}");
1053
 
1054
  $this->Notes = sanitize_textarea_field($post['package-notes']);
1055
  //ARCHIVE
1058
  $this->Archive->FilterOn = isset($post['filter-on']) ? 1 : 0;
1059
  $this->Archive->ExportOnlyDB = isset($post['export-onlydb']) ? 1 : 0;
1060
  $this->Archive->FilterDirs = sanitize_textarea_field($filter_dirs);
1061
+ $this->Archive->FilterFiles = sanitize_textarea_field($filter_files);
1062
+ $this->Archive->FilterExts = str_replace(array('.', ' '), '', $filter_exts);
1063
  //INSTALLER
1064
  $this->Installer->OptsDBHost = sanitize_text_field($post['dbhost']);
1065
  $this->Installer->OptsDBPort = sanitize_text_field($post['dbport']);
1066
  $this->Installer->OptsDBName = sanitize_text_field($post['dbname']);
1067
  $this->Installer->OptsDBUser = sanitize_text_field($post['dbuser']);
1068
  $this->Installer->OptsSecureOn = isset($post['secure-on']) ? 1 : 0;
1069
+ $post_secure_pass = sanitize_text_field($post['secure-pass']);
1070
+ $this->Installer->OptsSecurePass = DUP_Util::installerScramble($post_secure_pass);
1071
  //DATABASE
1072
  $this->Database->FilterOn = isset($post['dbfilter-on']) ? 1 : 0;
1073
  $this->Database->FilterTables = sanitize_text_field($tablelist);
1078
  }
1079
  }
1080
 
1081
+ /**
1082
+ * Update the serialized package and status in the database
1083
+ *
1084
+ * @return void
1085
+ */
1086
+ public function update()
1087
+ {
1088
+ global $wpdb;
1089
+
1090
+ $packageObj = serialize($this);
1091
+
1092
+ if (!$packageObj) {
1093
+ DUP_Log::Error("Package SetStatus was unable to serialize package object while updating record.");
1094
+ }
1095
+
1096
+ $wpdb->flush();
1097
+ $tablePrefix = DUP_Util::getTablePrefix();
1098
+ $table = $tablePrefix."duplicator_packages";
1099
+ $sql = "UPDATE `{$table}` SET status = {$this->Status},";
1100
+ $sql .= "package = '" . esc_sql($packageObj) . "'";
1101
+ $sql .= "WHERE ID = {$this->ID}";
1102
+
1103
+ DUP_Log::Trace('-------------------------');
1104
+ DUP_Log::Trace("status = {$this->Status}");
1105
+ DUP_Log::Trace("ID = {$this->ID}");
1106
+ DUP_Log::Trace('-------------------------');
1107
+
1108
+ //DUP_Log::Trace('####Executing SQL' . $sql . '-----------');
1109
+ $wpdb->query($sql);
1110
+ }
1111
+
1112
  /**
1113
  * Save any property of this class through reflection
1114
  *
1135
  */
1136
  public function setStatus($status)
1137
  {
 
 
 
 
1138
  if (!isset($status)) {
1139
  DUP_Log::Error("Package SetStatus did not receive a proper code.");
1140
  }
1141
 
1142
+ $this->Status = $status;
 
 
1143
 
1144
+ $this->update();
 
 
 
1145
  }
1146
 
1147
  /**
1148
+ * Does a hash already exists
1149
  *
1150
  * @param string $hash An existing hash value
1151
  *
1155
  {
1156
  global $wpdb;
1157
 
1158
+ $tablePrefix = DUP_Util::getTablePrefix();
1159
+ $table = $tablePrefix."duplicator_packages";
1160
  $qry = $wpdb->get_row("SELECT ID, hash FROM `{$table}` WHERE hash = '{$hash}'");
1161
+ if (is_null($qry) || strlen($qry->hash) == 0) {
1162
  return 0;
1163
  } else {
1164
  return $qry->ID;
1166
  }
1167
 
1168
  /**
1169
+ * Makes the hashkey for the package files
 
1170
  *
1171
+ * @return string A unique hashkey
1172
  */
1173
  public function makeHash()
1174
  {
 
1175
  try {
1176
  if (function_exists('random_bytes') && DUP_Util::PHP53()) {
1177
  return bin2hex(random_bytes(8)) . mt_rand(1000, 9999) . '_' . date("YmdHis");
1202
  }
1203
  //Incase unserilaize fails
1204
  $obj = (is_object($obj)) ? $obj : new DUP_Package();
1205
+
1206
  return $obj;
1207
  }
1208
 
1209
  /**
1210
  * Gets the Package by ID
1211
+ *
1212
  * @param int $id A valid package id form the duplicator_packages table
1213
  *
1214
  * @return obj A copy of the DUP_Package object
1215
  */
1216
  public static function getByID($id)
1217
  {
 
1218
  global $wpdb;
1219
  $obj = new DUP_Package();
1220
+ $tablePrefix = DUP_Util::getTablePrefix();
1221
+ $sql = $wpdb->prepare("SELECT * FROM `{$tablePrefix}duplicator_packages` WHERE ID = %d", $id);
1222
+ $row = $wpdb->get_row($sql);
1223
  if (is_object($row)) {
1224
  $obj = @unserialize($row->package);
1225
  $obj->Status = $row->status;
1238
  {
1239
  //Remove specail_chars from final result
1240
  $special_chars = array(".", "-");
1241
+ $name = ($preDate)
1242
  ? date('Ymd') . '_' . sanitize_title(get_bloginfo('name', 'display'))
1243
  : sanitize_title(get_bloginfo('name', 'display')) . '_' . date('Ymd');
1244
  $name = substr(sanitize_file_name($name), 0, 40);
1275
 
1276
  /**
1277
  * Provides various date formats
1278
+ *
1279
  * @param $date The date to format
1280
  * @param $format Various date formats to apply
1281
+ *
1282
  * @return a formated date based on the $format
1283
  */
1284
  public static function getCreatedDateFormat($date, $format = 1)
1320
  /**
1321
  * Cleans up all the tmp files as part of the package build process
1322
  */
1323
+ public function buildCleanup()
1324
  {
 
1325
  $files = DUP_Util::listFiles(DUPLICATOR_SSDIR_PATH_TMP);
1326
  $newPath = DUPLICATOR_SSDIR_PATH;
1327
 
1343
  }
1344
  }
1345
 
1346
+
1347
+
1348
  /**
1349
  * Get package hash
1350
+ *
1351
  * @return string package hash
1352
  */
1353
  public function getPackageHash() {
1354
  $hashParts = explode('_', $this->Hash);
1355
  $firstPart = substr($hashParts[0], 0, 7);
1356
  $secondPart = substr($hashParts[1], -8);
1357
+ $package_hash = $firstPart.'-'.$secondPart;
1358
+ return $package_hash;
1359
  }
1360
 
1361
  /**
1365
  */
1366
  public function getSqlArkFilePath()
1367
  {
1368
+ $package_hash = $this->getPackageHash();
1369
+ $sql_ark_file_Path = 'dup-installer/dup-database__'.$package_hash.'.sql';
1370
+ return $sql_ark_file_Path;
1371
  }
1372
+
1373
+ private function writeLogHeader()
1374
+ {
1375
+ $php_max_time = @ini_get("max_execution_time");
1376
+ $php_max_memory = @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY);
1377
+ $php_max_time = ($php_max_time == 0) ? "(0) no time limit imposed" : "[{$php_max_time}] not allowed";
1378
+ $php_max_memory = ($php_max_memory === false) ? "Unabled to set php memory_limit" : DUPLICATOR_PHP_MAX_MEMORY." ({$php_max_memory} default)";
1379
+
1380
+ $info = "********************************************************************************\n";
1381
+ $info .= "DUPLICATOR-LITE PACKAGE-LOG: ".@date(get_option('date_format')." ".get_option('time_format'))."\n";
1382
+ $info .= "NOTICE: Do NOT post to public sites or forums \n";
1383
+ $info .= "********************************************************************************\n";
1384
+ $info .= "VERSION:\t".DUPLICATOR_VERSION."\n";
1385
+ $info .= "WORDPRESS:\t{$GLOBALS['wp_version']}\n";
1386
+ $info .= "PHP INFO:\t".phpversion().' | '.'SAPI: '.php_sapi_name()."\n";
1387
+ $info .= "SERVER:\t\t{$_SERVER['SERVER_SOFTWARE']} \n";
1388
+ $info .= "PHP TIME LIMIT: {$php_max_time} \n";
1389
+ $info .= "PHP MAX MEMORY: {$php_max_memory} \n";
1390
+ $info .= "MEMORY STACK: ".DUP_Server::getPHPMemory();
1391
+ DUP_Log::Info($info);
1392
+
1393
+ $info = null;
1394
+ }
1395
+ }
classes/package/duparchive/class.pack.archive.duparchive.php ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined("ABSPATH") or die("");
3
+ if (!defined('DUPLICATOR_VERSION')) exit; // Exit if accessed directly
4
+
5
+ //?require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.php');
6
+ //require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.php');
7
+ require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/duparchive/class.pack.archive.duparchive.state.expand.php');
8
+ require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/duparchive/class.pack.archive.duparchive.state.create.php');
9
+ require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.loggerbase.php');
10
+ require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.engine.php');
11
+ require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.create.php');
12
+ require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.expand.php');
13
+
14
+ class DUP_DupArchive_Logger extends DupArchiveLoggerBase
15
+ {
16
+
17
+ public function log($s, $flush = false, $callingFunctionOverride = null)
18
+ {
19
+ DUP_Log::Trace($s, true, $callingFunctionOverride);
20
+ }
21
+ }
22
+
23
+ class DUP_DupArchive
24
+ {
25
+ // Using a worker time override since evidence shorter time works much
26
+ const WorkerTimeInSec = 10;
27
+
28
+ /**
29
+ * CREATE
30
+ * Creates the zip file and adds the SQL file to the archive
31
+ */
32
+ public static function create($archive, $buildProgress, $package)
33
+ {
34
+ /* @var $buildProgress DUP_Build_Progress */
35
+
36
+ DUP_LOG::trace("start");
37
+ try {
38
+ if(DUP_Log::$logFileHandle == null) {
39
+ DUP_Log::Open($package->NameHash);
40
+ }
41
+
42
+ DUP_LOG::trace("c2");
43
+
44
+ if ($buildProgress->retries > DUPLICATOR_MAX_BUILD_RETRIES) {
45
+ DUP_LOG::trace("c3");
46
+ $error_msg = __('Package build appears stuck so marking package as failed. Is the Max Worker Time set too high?.', 'duplicator');
47
+ DUP_Log::error(esc_html__('Build Failure', 'duplicator'), esc_html($error_msg), Dup_ErrorBehavior::LogOnly);
48
+ //$buildProgress->failed = true;
49
+ $buildProgress->set_failed($error_msg);
50
+ return true;
51
+ } else {
52
+ DUP_LOG::trace("c4");
53
+ // If all goes well retries will be reset to 0 at the end of this function.
54
+ $buildProgress->retries++;
55
+ $package->update();
56
+ }
57
+
58
+ $done = false;
59
+
60
+ DUP_LOG::trace("c5");
61
+ DupArchiveEngine::init(new DUP_DupArchive_Logger());
62
+
63
+ DUP_LOG::trace("c6");
64
+ DUP_Package::safeTmpCleanup(true);
65
+
66
+ $compressDir = rtrim(DUP_Util::safePath($archive->PackDir), '/');
67
+ $sqlPath = DUP_Util::safePath("{$package->StorePath}/{$package->Database->File}");
68
+ $archivePath = DUP_Util::safePath("{$package->StorePath}/{$archive->File}");
69
+
70
+ $scanFilepath = DUPLICATOR_SSDIR_PATH_TMP."/{$package->NameHash}_scan.json";
71
+
72
+ DUP_LOG::trace("c7");
73
+ $skipArchiveFinalization = false;
74
+ $json = '';
75
+
76
+ DUP_LOG::trace("c8");
77
+ if (file_exists($scanFilepath)) {
78
+
79
+ DUP_LOG::trace("c9");
80
+ $json = file_get_contents($scanFilepath);
81
+
82
+ if (empty($json)) {
83
+ DUP_LOG::trace("c10");
84
+ $errorText = __("Scan file $scanFilepath is empty!", 'duplicator');
85
+ $fixText = __("Click on \"Resolve This\" button to fix the JSON settings.", 'duplicator');
86
+
87
+ DUP_Log::Trace($errorText);
88
+ DUP_Log::error(esc_html($errorText)." **RECOMMENDATION: ".esc_html($fixText).".", '', Dup_ErrorBehavior::LogOnly);
89
+
90
+ //$buildProgress->failed = true;
91
+ $buildProgress->set_failed($errorText);
92
+ return true;
93
+ }
94
+ } else {
95
+ DUP_LOG::trace("c11");
96
+ DUP_Log::trace("**** scan file $scanFilepath doesn't exist!!");
97
+ $errorMessage = sprintf(__("ERROR: Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name.", 'duplicator'), $scanFilepath);
98
+
99
+ DUP_Log::error($errorMessage, '', Dup_ErrorBehavior::LogOnly);
100
+
101
+ //$buildProgress->failed = true;
102
+ $buildProgress->set_failed($errorMessage);
103
+ return true;
104
+ }
105
+
106
+ DUP_LOG::trace("c12");
107
+ Dup_Log::TraceObject("buildprogress object", $buildProgress, false);
108
+
109
+ $scanReport = json_decode($json);
110
+
111
+ if ($buildProgress->archive_started == false) {
112
+
113
+ $filterDirs = empty($archive->FilterDirs) ? 'not set' : $archive->FilterDirs;
114
+ $filterExts = empty($archive->FilterExts) ? 'not set' : $archive->FilterExts;
115
+ $filterFiles = empty($archive->FilterFiles) ? 'not set' : $archive->FilterFiles;
116
+ $filterOn = ($archive->FilterOn) ? 'ON' : 'OFF';
117
+ $filterDirsFormat = rtrim(str_replace(';', "\n\t", $filterDirs));
118
+ $filterFilesFormat = rtrim(str_replace(';', "\n\t", $filterFiles));
119
+
120
+ DUP_LOG::trace("c13");
121
+ DUP_Log::info("\n********************************************************************************");
122
+ DUP_Log::info("ARCHIVE Type=DUP Mode=DupArchive");
123
+ DUP_Log::info("********************************************************************************");
124
+ DUP_Log::info("ARCHIVE DIR: ".$compressDir);
125
+ DUP_Log::info("ARCHIVE FILE: ".basename($archivePath));
126
+ DUP_Log::info("FILTERS: *{$filterOn}*");
127
+ DUP_Log::Info("DIRS:\n\t{$filterDirsFormat}");
128
+ DUP_Log::Info("FILES:\n\t{$filterFilesFormat}");
129
+ DUP_Log::info("EXTS: {$filterExts}");
130
+
131
+ DUP_Log::info("----------------------------------------");
132
+ DUP_Log::info("COMPRESSING");
133
+ DUP_Log::info("SIZE:\t".$scanReport->ARC->Size);
134
+ DUP_Log::info("STATS:\tDirs ".$scanReport->ARC->DirCount." | Files ".$scanReport->ARC->FileCount." | Total ".$scanReport->ARC->FullCount);
135
+
136
+ if (($scanReport->ARC->DirCount == '') || ($scanReport->ARC->FileCount == '') || ($scanReport->ARC->FullCount == '')) {
137
+ $error_message = 'Invalid Scan Report Detected';
138
+
139
+ DUP_Log::error($error_message, 'Invalid Scan Report Detected', Dup_ErrorBehavior::LogOnly);
140
+ //$buildProgress->failed = true;
141
+ $buildProgress->set_failed($error_message);
142
+ return true;
143
+ }
144
+
145
+ try {
146
+ DupArchiveEngine::createArchive($archivePath, true);
147
+ $sql_ark_file_path = $package->getSqlArkFilePath();
148
+ DupArchiveEngine::addRelativeFileToArchiveST($archivePath, $sqlPath, $sql_ark_file_path);
149
+ } catch (Exception $ex) {
150
+ $error_message = 'Error adding database.sql to archive';
151
+
152
+ DUP_Log::error($error_message, $ex->getMessage(), Dup_ErrorBehavior::LogOnly);
153
+ //$buildProgress->failed = true;
154
+ $buildProgress->set_failed($error_message);
155
+ return true;
156
+ }
157
+
158
+ $buildProgress->archive_started = true;
159
+
160
+ $buildProgress->retries = 0;
161
+
162
+ $createState = DUP_DupArchive_Create_State::createNew($archivePath, $compressDir, self::WorkerTimeInSec, true, true);
163
+ $createState->throttleDelayInUs = 0;
164
+
165
+ $createState->save();
166
+
167
+ $package->Update();
168
+ }
169
+
170
+ try {
171
+
172
+ DUP_LOG::trace("c14");
173
+ $createState = DUP_DupArchive_Create_State::get_instance();
174
+
175
+ if($buildProgress->retries > 1) {
176
+ // Indicates it had problems before so move into robustness mode
177
+ $createState->isRobust = true;
178
+
179
+ $createState->save();
180
+ }
181
+
182
+ if ($createState->working) {
183
+ DUP_LOG::Trace("Create state is working");
184
+ //die(0);//rsr
185
+
186
+ DupArchiveEngine::addItemsToArchive($createState, $scanReport->ARC);
187
+
188
+ $buildProgress->set_build_failures($createState->failures);
189
+
190
+ if($createState->isCriticalFailurePresent()) {
191
+
192
+ throw new Exception($createState->getFailureSummary());
193
+ }
194
+
195
+ $totalFileCount = count($scanReport->ARC->Files);
196
+
197
+ $package->Status = SnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCSTART, DUP_PackageStatus::ARCVALIDATION, $totalFileCount, $createState->currentFileIndex);
198
+
199
+ $buildProgress->retries = 0;
200
+
201
+ $createState->save();
202
+
203
+ DUP_LOG::TraceObject("Stored Create State", $createState);
204
+ DUP_LOG::TraceObject('Stored build_progress', $package->BuildProgress);
205
+
206
+ if ($createState->working == false) {
207
+ // Want it to do the final cleanup work in an entirely new thread so return immediately
208
+ $skipArchiveFinalization = true;
209
+ DUP_LOG::TraceObject("Done build phase. Create State=", $createState);
210
+ }
211
+ }
212
+ }
213
+ catch (Exception $ex) {
214
+ DUP_LOG::trace("c15");
215
+ $message = __('Problem adding items to archive.', 'duplicator').' '.$ex->getMessage();
216
+
217
+ DUP_Log::Error(__('Problems adding items to archive.', 'duplicator'), $message, Dup_ErrorBehavior::LogOnly);
218
+ DUP_Log::TraceObject($message." EXCEPTION:", $ex);
219
+ //$buildProgress->failed = true;
220
+ $buildProgress->set_failed($message);
221
+ return true;
222
+ }
223
+
224
+ DUP_LOG::trace("c16");
225
+
226
+ //-- Final Wrapup of the Archive
227
+ if ((!$skipArchiveFinalization) && ($createState->working == false)) {
228
+
229
+ DUP_LOG::Trace("Create state is not working and not skip archive finalization");
230
+
231
+ DUP_LOG::trace("c17");
232
+
233
+ if(!$buildProgress->installer_built) {
234
+
235
+ if($package->Installer->build($package, false))
236
+ {
237
+ $package->Runtime = -1;
238
+ $package->ExeSize = DUP_Util::byteSize($package->Installer->Size);
239
+ $package->ZipSize = DUP_Util::byteSize($package->Archive->Size);
240
+ $package->update();
241
+ }
242
+ else
243
+ {
244
+ $package->update();
245
+ return;
246
+ }
247
+
248
+
249
+
250
+ //rsr todo need this somewhere $package->buildCleanup();
251
+
252
+ DUP_Log::Trace("Installer has been built so running expand now");
253
+
254
+ $expandState = DUP_DupArchive_Expand_State::getInstance(true);
255
+
256
+ $expandState->archivePath = $archivePath;
257
+ $expandState->working = true;
258
+ $expandState->timeSliceInSecs = self::WorkerTimeInSec;
259
+ $expandState->basePath = DUPLICATOR_SSDIR_PATH_TMP.'/validate';
260
+ $expandState->throttleDelayInUs = 0; // RSR TODO
261
+ $expandState->validateOnly = true;
262
+ $expandState->validationType = DupArchiveValidationTypes::Standard;
263
+ $expandState->working = true;
264
+ $expandState->expectedDirectoryCount = count($scanReport->ARC->Dirs) - $createState->skippedDirectoryCount + $package->Installer->numDirsAdded;
265
+ $expandState->expectedFileCount = count($scanReport->ARC->Files) + 1 - $createState->skippedFileCount + $package->Installer->numFilesAdded; // database.sql will be in there
266
+
267
+ $expandState->save();
268
+
269
+ $sfc = count($scanReport->ARC->Files);
270
+ $nfa = $package->Installer->numFilesAdded;
271
+ Dup_Log::trace("####scan files {$sfc} skipped files {$createState->skippedFileCount} num files added {$nfa}");
272
+ DUP_LOG::traceObject("EXPAND STATE AFTER SAVE", $expandState);
273
+ }
274
+ else {
275
+
276
+ DUP_LOG::trace("c18");
277
+ try {
278
+
279
+ $expandState = DUP_DupArchive_Expand_State::getInstance();
280
+
281
+ if($buildProgress->retries > 1) {
282
+
283
+ // Indicates it had problems before so move into robustness mode
284
+ $expandState->isRobust = true;
285
+
286
+ $expandState->save();
287
+ }
288
+
289
+ DUP_Log::traceObject('Resumed validation expand state', $expandState);
290
+
291
+ DupArchiveEngine::expandArchive($expandState);
292
+
293
+ $buildProgress->set_validation_failures($expandState->failures);
294
+
295
+ $totalFileCount = count($scanReport->ARC->Files);
296
+ $archiveSize = @filesize($expandState->archivePath);
297
+
298
+ $package->Status = SnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCVALIDATION, DUP_PackageStatus::COMPLETE, $archiveSize,
299
+ $expandState->archiveOffset);
300
+ DUP_LOG::TraceObject("package status after expand=", $package->Status);
301
+ DUP_LOG::Trace("archive size:{$archiveSize} expand offset:{$expandState->archiveOffset}");
302
+
303
+ } catch (Exception $ex) {
304
+ DUP_Log::Trace('Exception:'.$ex->getMessage().':'.$ex->getTraceAsString());
305
+ //$buildProgress->failed = true;
306
+ $buildProgress->set_failed('Error validating archive');
307
+ return true;
308
+ }
309
+
310
+ if($expandState->isCriticalFailurePresent())
311
+ {
312
+ DUP_LOG::trace("c20");
313
+ // Fail immediately if critical failure present - even if havent completed processing the entire archive.
314
+
315
+ $error_message = __('Critical failure present in validation', 'duplicator');
316
+
317
+ DUP_Log::Error($error_message, $expandState->getFailureSummary(), Dup_ErrorBehavior::LogOnly);
318
+
319
+ //$buildProgress->failed = true;
320
+ $buildProgress->set_failed($error_message);
321
+ return true;
322
+ } else if (!$expandState->working) {
323
+ DUP_LOG::trace("c21");
324
+
325
+ $buildProgress->archive_built = true;
326
+ $buildProgress->retries = 0;
327
+
328
+ // rsr todo is this required?
329
+ $package->update();
330
+
331
+ $timerAllEnd = DUP_Util::getMicrotime();
332
+ $timerAllSum = DUP_Util::elapsedTime($timerAllEnd, $package->TimerStart);
333
+
334
+ DUP_LOG::traceObject("create state", $createState);
335
+
336
+ $archiveFileSize = @filesize($archivePath);
337
+ DUP_Log::info("COMPRESSED SIZE: ".DUP_Util::byteSize($archiveFileSize));
338
+ DUP_Log::info("ARCHIVE RUNTIME: {$timerAllSum}");
339
+ DUP_Log::info("MEMORY STACK: ".DUP_Server::getPHPMemory());
340
+ DUP_Log::info("CREATE WARNINGS: ".$createState->getFailureSummary(false, true));
341
+ DUP_Log::info("VALIDATION WARNINGS: ".$expandState->getFailureSummary(false, true));
342
+
343
+ $archive->file_count = $expandState->fileWriteCount + $expandState->directoryWriteCount;
344
+
345
+ $package->update();
346
+
347
+ DUP_LOG::trace("c22");
348
+ $done = true;
349
+ } else {
350
+ DUP_LOG::trace("c23");
351
+ $expandState->save();
352
+ DUP_LOG::trace("c24");
353
+ }
354
+ }
355
+ }
356
+ } catch (Exception $ex) {
357
+ // Have to have a catchall since the main system that calls this function is not prepared to handle exceptions
358
+ DUP_Log::trace('Top level create Exception:'.$ex->getMessage().':'.$ex->getTraceAsString());
359
+ //$buildProgress->failed = true;
360
+ $buildProgress->set_failed('Error encoundtered creating archive. See package log');
361
+ return true;
362
+ }
363
+
364
+ $buildProgress->retries = 0;
365
+
366
+ return $done;
367
+ }
368
+ }
classes/package/duparchive/class.pack.archive.duparchive.state.create.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined("ABSPATH") or die("");
3
+ /*
4
+ * To change this license header, choose License Headers in Project Properties.
5
+ * To change this template file, choose Tools | Templates
6
+ * and open the template in the editor.
7
+ */
8
+
9
+ require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.create.php');
10
+
11
+ class DUP_DupArchive_Create_State extends DupArchiveCreateState
12
+ {
13
+ /* @var $package DUP_Package */
14
+ // private $package;
15
+
16
+ // public function setPackage(&$package)
17
+ public function setPackage(&$package)
18
+ {
19
+ // $this->package = &$package;
20
+ }
21
+
22
+ // Only one active package so straightforward
23
+ // public static function createFromPackage(&$package)
24
+ public static function get_instance()
25
+ {
26
+ $instance = new DUP_DupArchive_Create_State();
27
+
28
+ $data = DUP_Settings::Get('duparchive_create_state');
29
+
30
+ DUP_Util::objectCopy($data, $instance);
31
+
32
+ $instance->startTimestamp = time();
33
+
34
+ DUP_Log::TraceObject("retrieving create state", $instance);
35
+
36
+ return $instance;
37
+ }
38
+
39
+ public static function createNew($archivePath, $basePath, $timeSliceInSecs, $isCompressed, $setArchiveOffsetToEndOfArchive)
40
+ {
41
+ $instance = new DUP_DupArchive_Create_State();
42
+
43
+ /* @var $buildProgress DUP_Build_Progress */
44
+ $buildProgress = &$package->BuildProgress;
45
+
46
+ if ($setArchiveOffsetToEndOfArchive) {
47
+ $instance->archiveOffset = filesize($archivePath);
48
+ } else {
49
+ $instance->archiveOffset = 0;
50
+ }
51
+
52
+ $instance->archivePath = $archivePath;
53
+ $instance->basePath = $basePath;
54
+ $instance->currentDirectoryIndex = 0;
55
+ $instance->currentFileOffset = 0;
56
+ $instance->currentFileIndex = 0;
57
+ $instance->failures = array();
58
+ $instance->globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE;
59
+ $instance->isCompressed = $isCompressed;
60
+ $instance->timeSliceInSecs = $timeSliceInSecs;
61
+ $instance->working = true;
62
+ $instance->skippedDirectoryCount = 0;
63
+ $instance->skippedFileCount = 0;
64
+
65
+ $instance->startTimestamp = time();
66
+
67
+ return $instance;
68
+ }
69
+
70
+ public function addFailure($type, $subject, $description, $isCritical = false)
71
+ {
72
+ $failure = parent::addFailure($type, $subject, $description, $isCritical);
73
+ }
74
+
75
+ public function save()
76
+ {
77
+ DUP_Log::TraceObject("Saving create state", $this);
78
+ DUP_Settings::Set('duparchive_create_state', $this);
79
+
80
+ DUP_Settings::Save();
81
+ }
82
+ }
classes/package/duparchive/class.pack.archive.duparchive.state.expand.php ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * To change this license header, choose License Headers in Project Properties.
4
+ * To change this template file, choose Tools | Templates
5
+ * and open the template in the editor.
6
+ */
7
+
8
+ require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.expand.php');
9
+
10
+ class DUP_DupArchive_Expand_State extends DupArchiveExpandState
11
+ {
12
+ public static function getInstance($reset = false)
13
+ {
14
+ $instance = new DUP_DupArchive_Expand_State();
15
+
16
+ if ($reset) {
17
+ $instance->initMembers();
18
+ } else {
19
+ $instance->loadMembers();
20
+ }
21
+
22
+ return $instance;
23
+ }
24
+
25
+ private function loadMembers()
26
+ {
27
+ $data = DUP_Settings::Get('duparchive_expand_state');
28
+
29
+ DUP_LOG::traceObject("****RAW EXPAND STATE LOADED****", $data);
30
+
31
+ if($data->currentFileHeaderString != null) {
32
+ $this->currentFileHeader = DUP_JSON::decode($data->currentFileHeaderString);
33
+ } else {
34
+ $this->currentFileHeader = null;
35
+ }
36
+
37
+ if($data->archiveHeaderString != null) {
38
+ $this->archiveHeader = DUP_JSON::decode($data->archiveHeaderString);
39
+ } else {
40
+ $this->archiveHeader = null;
41
+ }
42
+
43
+ if($data->failuresString)
44
+ {
45
+ $this->failures = DUP_JSON::decode($data->failuresString);
46
+ }
47
+ else
48
+ {
49
+ $this->failures = array();
50
+ }
51
+
52
+ DUP_Util::objectCopy($data, $this, array('archiveHeaderString', 'currentFileHeaderString', 'failuresString'));
53
+
54
+ //
55
+ // $this->archiveOffset = $data->archiveOffset;
56
+ // $this->archivePath = $data->archivePath;
57
+ // $this->basePath = $data->basePath;
58
+ // $this->currentFileOffset = $data->currentFileOffset;
59
+ // $this->failures = $data->failures;
60
+ // $this->isCompressed = $data->isCompressed;
61
+ // $this->startTimestamp = $data->startTimestamp;
62
+ // $this->timeSliceInSecs = $data->timeSliceInSecs;
63
+ // $this->fileWriteCount = $data->fileWriteCount;
64
+ // $this->directoryWriteCount = $data->directoryWriteCount;
65
+ // $this->working = $data->working;
66
+ // $this->directoryModeOverride = $data->directoryModeOverride;
67
+ // $this->fileModeOverride = $data->fileModeOverride;
68
+ // $this->throttleDelayInUs = $data->throttleDelayInUs;
69
+ // $this->validateOnly = $data->validateOnly;
70
+ // $this->validationType = $data->validationType;
71
+ }
72
+
73
+ public function save()
74
+ {
75
+ $data = new stdClass();
76
+
77
+ if($this->currentFileHeader != null) {
78
+ $data->currentFileHeaderString = json_encode($this->currentFileHeader);
79
+ } else {
80
+ $data->currentFileHeaderString = null;
81
+ }
82
+
83
+ if($this->archiveHeader != null) {
84
+ $data->archiveHeaderString = json_encode($this->archiveHeader);
85
+ } else {
86
+ $data->archiveHeaderString = null;
87
+ }
88
+
89
+ $data->failuresString = json_encode($this->failures, JSON_FORCE_OBJECT);
90
+
91
+ // Object members auto skipped
92
+ DUP_Util::objectCopy($this, $data);
93
+
94
+ // $data->archiveOffset = $this->archiveOffset;
95
+ // $data->archivePath = $this->archivePath;
96
+ // $data->basePath = $this->basePath;
97
+ // $data->currentFileOffset = $this->currentFileOffset;
98
+ // $data->failures = $this->failures;
99
+ // $data->isCompressed = $this->isCompressed;
100
+ // $data->startTimestamp = $this->startTimestamp;
101
+ // $data->timeSliceInSecs = $this->timeSliceInSecs;
102
+ // $data->fileWriteCount = $this->fileWriteCount;
103
+ // $data->directoryWriteCount = $this->directoryWriteCount;
104
+ // $data->working = $this->working;
105
+ // $data->directoryModeOverride = $this->directoryModeOverride;
106
+ // $data->fileModeOverride = $this->fileModeOverride;
107
+ // $data->throttleDelayInUs = $this->throttleDelayInUs;
108
+ // $data->validateOnly = $this->validateOnly;
109
+ // $data->validationType = $this->validationType;
110
+
111
+ DUP_LOG::traceObject("****SAVING EXPAND STATE****", $this);
112
+ DUP_LOG::traceObject("****SERIALIZED STATE****", $data);
113
+ DUP_Settings::Set('duparchive_expand_state', $data);
114
+ DUP_Settings::Save();
115
+ }
116
+
117
+ private function initMembers()
118
+ {
119
+ $this->currentFileHeader = null;
120
+ $this->archiveOffset = 0;
121
+ $this->archiveHeader = null;
122
+ $this->archivePath = null;
123
+ $this->basePath = null;
124
+ $this->currentFileOffset = 0;
125
+ $this->failures = array();
126
+ $this->isCompressed = false;
127
+ $this->startTimestamp = time();
128
+ $this->timeSliceInSecs = -1;
129
+ $this->working = false;
130
+ $this->validateOnly = false;
131
+ $this->directoryModeOverride = -1;
132
+ $this->fileModeOverride = -1;
133
+ $this->throttleDelayInUs = 0;
134
+ }
135
+ }
classes/package/duparchive/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ //silent
classes/ui/class.ui.dialog.php CHANGED
@@ -1,202 +1,198 @@
1
- <?php
2
- /**
3
- * Used to generate a thinkbox inline dialog such as an alert or confirm popup
4
- *
5
- * Standard: PSR-2
6
- * @link http://www.php-fig.org/psr/psr-2
7
- *
8
- * @package Duplicator
9
- * @subpackage classes/ui
10
- * @copyright (c) 2017, Snapcreek LLC
11
- * @since 1.1.32
12
- *
13
- */
14
-
15
- // Exit if accessed directly
16
- if (!defined('DUPLICATOR_VERSION')) {
17
- exit;
18
- }
19
-
20
- class DUP_UI_Dialog
21
- {
22
- /**
23
- * The title that shows up in the dialog
24
- */
25
- public $title;
26
-
27
- /**
28
- * The message displayed in the body of the dialog
29
- */
30
- public $message;
31
-
32
- /**
33
- * The width of the dialog the default is used if not set
34
- * Alert = 475px (default) | Confirm = 500px (default)
35
- */
36
- public $width;
37
-
38
- /**
39
- * The height of the dialog the default is used if not set
40
- * Alert = 125px (default) | Confirm = 150px (default)
41
- */
42
- public $height;
43
-
44
- /**
45
- * When the progress meter is running show this text
46
- * Available only on confirm dialogs
47
- */
48
- public $progressText;
49
-
50
- /**
51
- * When true a progress meter will run until page is reloaded
52
- * Available only on confirm dialogs
53
- */
54
- public $progressOn = true;
55
-
56
- /**
57
- * The javascript call back method to call when the 'Yes' button is clicked
58
- * Available only on confirm dialogs
59
- */
60
- public $jscallback;
61
-
62
- /**
63
- * The id given to the full dialog
64
- */
65
- private $id;
66
-
67
- /**
68
- * A unique id that is added to all id elements
69
- */
70
- private $uniqid;
71
-
72
- /**
73
- * Init this object when created
74
- */
75
- public function __construct()
76
- {
77
- add_thickbox();
78
- $this->progressText = __('Processing please wait...', 'duplicator');
79
- $this->uniqid = substr(uniqid('',true),0,14) . rand();
80
- $this->id = 'dup-dlg-'.$this->uniqid;
81
- }
82
-
83
- /**
84
- * Gets the unique id that is assigned to each instance of a dialog
85
- *
86
- * @return int The unique ID of this dialog
87
- */
88
- public function getID()
89
- {
90
- return $this->id;
91
- }
92
-
93
- /**
94
- * Gets the unique id that is assigned to each instance of a dialogs message text
95
- *
96
- * @return int The unique ID of the message
97
- */
98
- public function getMessageID()
99
- {
100
- return "{$this->id}_message";
101
- }
102
-
103
- /**
104
- * Initialize the alert base html code used to display when needed
105
- *
106
- * @return string The html content used for the alert dialog
107
- */
108
- public function initAlert()
109
- {
110
- $ok = __('OK', 'duplicator');
111
-
112
- $html = '<div id="'.esc_attr($this->id).'" style="display:none">
113
- <div class="dup-dlg-alert-txt">
114
- '.$this->message.'
115
- <br/><br/>
116
- </div>
117
- <div class="dup-dlg-alert-btns">
118
- <input type="button" class="button button-large" value="'.esc_attr($ok).'" onclick="tb_remove()" />
119
- </div>
120
- </div>';
121
-
122
- echo $html;
123
- }
124
-
125
- /**
126
- * Shows the alert base js code used to display when needed
127
- *
128
- * @return string The javascript content used for the alert dialog
129
- */
130
- public function showAlert()
131
- {
132
- $this->width = is_numeric($this->width) ? $this->width : 500;
133
- $this->height = is_numeric($this->height) ? $this->height : 175;
134
-
135
- $html = "tb_show('".esc_js($this->title)."', '#TB_inline?width=".esc_js($this->width)."&height=".esc_js($this->height)."&inlineId=".esc_js($this->id)."');\n" .
136
- "var styleData = jQuery('#TB_window').attr('style') + 'height: ".esc_js($this->height)."px !important';\n" .
137
- "jQuery('#TB_window').attr('style', styleData);";
138
-
139
- echo $html;
140
- }
141
-
142
- /**
143
- * Shows the confirm base js code used to display when needed
144
- *
145
- * @return string The javascript content used for the confirm dialog
146
- */
147
- public function initConfirm()
148
- {
149
- $ok = __('OK', 'duplicator');
150
- $cancel = __('Cancel', 'duplicator');
151
-
152
- $progress_data = '';
153
- $progress_func2 = '';
154
-
155
- //Enable the progress spinner
156
- if ($this->progressOn) {
157
- $progress_func1 = "__DUP_UI_Dialog_".$this->uniqid;
158
- $progress_func2 = ";{$progress_func1}(this)";
159
- $progress_data = <<<HTML
160
- <div class='dup-dlg-confirm-progress'><i class='fa fa-circle-o-notch fa-spin fa-lg fa-fw'></i> {$this->progressText}</div>
161
- <script>
162
- function {$progress_func1}(obj)
163
- {
164
- jQuery(obj).parent().parent().find('.dup-dlg-confirm-progress').show();
165
- jQuery(obj).closest('.dup-dlg-confirm-btns').find('input').attr('disabled', 'true');
166
- }
167
- </script>
168
- HTML;
169
- }
170
-
171
- $html =
172
- '<div id="'.esc_attr($this->id).'" style="display:none">
173
- <div class="dup-dlg-confirm-txt">
174
- <span id="'.esc_attr($this->id).'_message">'.esc_html($this->message).'</span>
175
- <br/><br/>
176
- '.$progress_data.'
177
- </div>
178
- <div class="dup-dlg-confirm-btns">
179
- <input type="button" class="button button-large" value="'.esc_attr($ok).'" onclick="'.$this->jscallback.$progress_func2.'" />
180
- <input type="button" class="button button-large" value="'.esc_attr($cancel).'" onclick="tb_remove()" />
181
- </div>
182
- </div>';
183
-
184
- echo $html;
185
- }
186
-
187
- /**
188
- * Shows the confirm base js code used to display when needed
189
- *
190
- * @return string The javascript content used for the confirm dialog
191
- */
192
- public function showConfirm()
193
- {
194
- $this->width = is_numeric($this->width) ? $this->width : 500;
195
- $this->height = is_numeric($this->height) ? $this->height : 225;
196
- $html = "tb_show('{$this->title}', '#TB_inline?width={$this->width}&height={$this->height}&inlineId={$this->id}');\n" .
197
- "var styleData = jQuery('#TB_window').attr('style') + 'height: {$this->height}px !important';\n" .
198
- "jQuery('#TB_window').attr('style', styleData);";
199
-
200
- echo $html;
201
- }
202
  }
1
+ <?php
2
+ /**
3
+ * Used to generate a thick-box inline dialog such as an alert or confirm pop-up
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2
7
+ *
8
+ * @package Duplicator
9
+ * @subpackage classes/ui
10
+ * @copyright (c) 2017, Snapcreek LLC
11
+ *
12
+ */
13
+
14
+ // Exit if accessed directly
15
+ if (! defined('DUPLICATOR_VERSION')) exit;
16
+
17
+ class DUP_UI_Dialog
18
+ {
19
+ /**
20
+ * The title that shows up in the dialog
21
+ */
22
+ public $title;
23
+
24
+ /**
25
+ * The message displayed in the body of the dialog
26
+ */
27
+ public $message;
28
+
29
+ /**
30
+ * The width of the dialog the default is used if not set
31
+ * Alert = 475px (default) | Confirm = 500px (default)
32
+ */
33
+ public $width;
34
+
35
+ /**
36
+ * The height of the dialog the default is used if not set
37
+ * Alert = 125px (default) | Confirm = 150px (default)
38
+ */
39
+ public $height;
40
+
41
+ /**
42
+ * When the progress meter is running show this text
43
+ * Available only on confirm dialogs
44
+ */
45
+ public $progressText;
46
+
47
+ /**
48
+ * When true a progress meter will run until page is reloaded
49
+ * Available only on confirm dialogs
50
+ */
51
+ public $progressOn = true;
52
+
53
+ /**
54
+ * The javascript call back method to call when the 'Yes' button is clicked
55
+ * Available only on confirm dialogs
56
+ */
57
+ public $jscallback;
58
+
59
+ /**
60
+ * The id given to the full dialog
61
+ */
62
+ private $id;
63
+
64
+ /**
65
+ * A unique id that is added to all id elements
66
+ */
67
+ private $uniqid;
68
+
69
+ /**
70
+ * Init this object when created
71
+ */
72
+ public function __construct()
73
+ {
74
+ add_thickbox();
75
+ $this->progressText = __('Processing please wait...', 'duplicator');
76
+ $this->uniqid = substr(uniqid('',true),0,14) . rand();
77
+ $this->id = 'dup-dlg-'.$this->uniqid;
78
+ }
79
+
80
+ /**
81
+ * Gets the unique id that is assigned to each instance of a dialog
82
+ *
83
+ * @return int The unique ID of this dialog
84
+ */
85
+ public function getID()
86
+ {
87
+ return $this->id;
88
+ }
89
+
90
+ /**
91
+ * Gets the unique id that is assigned to each instance of a dialogs message text
92
+ *
93
+ * @return int The unique ID of the message
94
+ */
95
+ public function getMessageID()
96
+ {
97
+ return "{$this->id}_message";
98
+ }
99
+
100
+ /**
101
+ * Initialize the alert base html code used to display when needed
102
+ *
103
+ * @return string The html content used for the alert dialog
104
+ */
105
+ public function initAlert()
106
+ {
107
+ $ok = __('OK', 'duplicator');
108
+
109
+ $html = '
110
+ <div id="'.esc_attr($this->id).'" style="display:none">
111
+ <div class="dup-dlg-alert-txt">
112
+ '.$this->message.'
113
+ <br/><br/>
114
+ </div>
115
+ <div class="dup-dlg-alert-btns">
116
+ <input type="button" class="button button-large" value="'.esc_attr($ok).'" onclick="tb_remove()" />
117
+ </div>
118
+ </div>';
119
+
120
+ echo $html;
121
+ }
122
+
123
+ /**
124
+ * Shows the alert base JS code used to display when needed
125
+ *
126
+ * @return string The javascript content used for the alert dialog
127
+ */
128
+ public function showAlert()
129
+ {
130
+ $this->width = is_numeric($this->width) ? $this->width : 500;
131
+ $this->height = is_numeric($this->height) ? $this->height : 175;
132
+
133
+ $html = "tb_show('".esc_js($this->title)."', '#TB_inline?width=".esc_js($this->width)."&height=".esc_js($this->height)."&inlineId=".esc_js($this->id)."');\n" .
134
+ "var styleData = jQuery('#TB_window').attr('style') + 'height: ".esc_js($this->height)."px !important';\n" .
135
+ "jQuery('#TB_window').attr('style', styleData);";
136
+
137
+ echo $html;
138
+ }
139
+
140
+ /**
141
+ * Shows the confirm base JS code used to display when needed
142
+ *
143
+ * @return string The javascript content used for the confirm dialog
144
+ */
145
+ public function initConfirm()
146
+ {
147
+ $ok = __('OK', 'duplicator');
148
+ $cancel = __('Cancel', 'duplicator');
149
+
150
+ $progress_data = '';
151
+ $progress_func2 = '';
152
+
153
+ //Enable the progress spinner
154
+ if ($this->progressOn) {
155
+ $progress_func1 = "__DUP_UI_Dialog_".$this->uniqid;
156
+ $progress_func2 = ";{$progress_func1}(this)";
157
+ $progress_data = "<div class='dup-dlg-confirm-progress'><i class='fa fa-circle-o-notch fa-spin fa-lg fa-fw'></i> ".esc_js($this->progressText)."</div>
158
+ <script>
159
+ function {$progress_func1}(obj)
160
+ {
161
+ jQuery(obj).parent().parent().find('.dup-dlg-confirm-progress').show();
162
+ jQuery(obj).closest('.dup-dlg-confirm-btns').find('input').attr('disabled', 'true');
163
+ }
164
+ </script>";
165
+ }
166
+
167
+ $html =
168
+ '<div id="'.esc_attr($this->id).'" style="display:none">
169
+ <div class="dup-dlg-confirm-txt">
170
+ <span id="'.esc_attr($this->id).'_message">'.esc_html($this->message).'</span>
171
+ <br/><br/>
172
+ '.$progress_data.'
173
+ </div>
174
+ <div class="dup-dlg-confirm-btns">
175
+ <input type="button" class="button button-large" value="'.esc_attr($ok).'" onclick="'.$this->jscallback.$progress_func2.'" />
176
+ <input type="button" class="button button-large" value="'.esc_attr($cancel).'" onclick="tb_remove()" />
177
+ </div>
178
+ </div>';
179
+
180
+ echo $html;
181
+ }
182
+
183
+ /**
184
+ * Shows the confirm base JS code used to display when needed
185
+ *
186
+ * @return string The javascript content used for the confirm dialog
187
+ */
188
+ public function showConfirm()
189
+ {
190
+ $this->width = is_numeric($this->width) ? $this->width : 500;
191
+ $this->height = is_numeric($this->height) ? $this->height : 225;
192
+ $html = "tb_show('".esc_js($this->title)."', '#TB_inline?width=".esc_js($this->width)."&height=".esc_js($this->height)."&inlineId=".esc_js($this->id)."');\n" .
193
+ "var styleData = jQuery('#TB_window').attr('style') + 'height: ".esc_js($this->height)."px !important';\n" .
194
+ "jQuery('#TB_window').attr('style', styleData);";
195
+
196
+ echo $html;
197
+ }
 
 
 
 
198
  }
classes/ui/class.ui.notice.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /**
3
  * Used to display notices in the WordPress Admin area
4
- * This class takes advatage of the 'admin_notice' action.
5
  *
6
  * Standard: PSR-2
7
  * @link http://www.php-fig.org/psr/psr-2
@@ -9,14 +9,11 @@
9
  * @package Duplicator
10
  * @subpackage classes/ui
11
  * @copyright (c) 2017, Snapcreek LLC
12
- * @since 1.1.0
13
  *
14
  */
15
 
16
  // Exit if accessed directly
17
- if (!defined('DUPLICATOR_VERSION')) {
18
- exit;
19
- }
20
 
21
  class DUP_UI_Notice
22
  {
@@ -41,30 +38,29 @@ class DUP_UI_Notice
41
  if (DUP_Server::hasInstallerFiles() && !$is_installer_cleanup_req) {
42
 
43
  $on_active_tab = isset($_GET['section'])? $_GET['section']: '';
44
- echo '<div class="updated notice-success" id="dup-global-error-reserved-files"><p>';
45
 
46
  //Safe Mode Notice
47
  $safe_html = '';
48
  if(get_option("duplicator_exe_safe_mode", 0) > 0 ){
49
  $safe_msg1 = __('Safe Mode:', 'duplicator');
50
  $safe_msg2 = __('During the install safe mode was enabled deactivating all plugins.<br/> Please be sure to ', 'duplicator');
51
- $safe_msg3 = __('reactivate the plugins', 'duplicator');
52
  $safe_html = "<div class='notice-safemode'><b>{$safe_msg1}</b><br/>{$safe_msg2} <a href='plugins.php'>{$safe_msg3}</a>!</div><br/>";
53
  }
54
 
55
  //On Tools > Cleanup Page
56
-
57
  if ($screen->id == 'duplicator_page_duplicator-tools' && ($on_active_tab == "info" || $on_active_tab == '') ) {
58
 
59
  $title = __('This site has been successfully migrated!', 'duplicator');
60
  $msg1 = __('Final step(s):', 'duplicator');
61
- $msg2 = __('This message will be removed after all installer files are removed. Installer files must be removed to maintain a secure site.<br/>'
62
  . 'Click the link above or button below to remove all installer files and complete the migration.', 'duplicator');
63
 
64
  echo "<b class='pass-msg'><i class='fa fa-check-circle'></i> ".esc_html($title)."</b> <br/> {$safe_html} <b>".esc_html($msg1)."</b> <br/>";
65
  printf("1. <a href='javascript:void(0)' onclick='jQuery(\"#dup-remove-installer-files-btn\").click()'>%s</a><br/>", esc_html__('Remove Installation Files Now!', 'duplicator'));
66
- printf("2. <a href='https://wordpress.org/support/plugin/duplicator/reviews/?filter=5' target='wporg'>%s</a> <br/> ", esc_html__('Optionally, Review Duplicator at WordPress.org...', 'duplicator'));
67
- echo "<div class='pass-msg' style='color:maroon'>" . $msg2 . "</div>";
68
 
69
  //All other Pages
70
  } else {
@@ -91,9 +87,9 @@ class DUP_UI_Notice
91
  public static function redirect($location)
92
  {
93
  echo '<div class="dup-redirect"><i class="fa fa-circle-o-notch fa-spin fa-fw"></i>';
94
- __('Redirecting Please Wait...', 'duplicator');
95
  echo '</div>';
96
  echo "<script>window.location = '{$location}';</script>";
97
- die(__('Invalid token permissions to perform this request.', 'duplicator'));
98
  }
99
- }
1
  <?php
2
  /**
3
  * Used to display notices in the WordPress Admin area
4
+ * This class takes advantage of the admin_notice action.
5
  *
6
  * Standard: PSR-2
7
  * @link http://www.php-fig.org/psr/psr-2
9
  * @package Duplicator
10
  * @subpackage classes/ui
11
  * @copyright (c) 2017, Snapcreek LLC
 
12
  *
13
  */
14
 
15
  // Exit if accessed directly
16
+ if (! defined('DUPLICATOR_VERSION')) exit;
 
 
17
 
18
  class DUP_UI_Notice
19
  {
38
  if (DUP_Server::hasInstallerFiles() && !$is_installer_cleanup_req) {
39
 
40
  $on_active_tab = isset($_GET['section'])? $_GET['section']: '';
41
+ echo '<div class="dup-updated notice-success" id="dup-global-error-reserved-files"><p>';
42
 
43
  //Safe Mode Notice
44
  $safe_html = '';
45
  if(get_option("duplicator_exe_safe_mode", 0) > 0 ){
46
  $safe_msg1 = __('Safe Mode:', 'duplicator');
47
  $safe_msg2 = __('During the install safe mode was enabled deactivating all plugins.<br/> Please be sure to ', 'duplicator');
48
+ $safe_msg3 = __('re-activate the plugins', 'duplicator');
49
  $safe_html = "<div class='notice-safemode'><b>{$safe_msg1}</b><br/>{$safe_msg2} <a href='plugins.php'>{$safe_msg3}</a>!</div><br/>";
50
  }
51
 
52
  //On Tools > Cleanup Page
 
53
  if ($screen->id == 'duplicator_page_duplicator-tools' && ($on_active_tab == "info" || $on_active_tab == '') ) {
54
 
55
  $title = __('This site has been successfully migrated!', 'duplicator');
56
  $msg1 = __('Final step(s):', 'duplicator');
57
+ $msg2 = __('This message will be removed after all installer files are removed. Installer files must be removed to maintain a secure site. '
58
  . 'Click the link above or button below to remove all installer files and complete the migration.', 'duplicator');
59
 
60
  echo "<b class='pass-msg'><i class='fa fa-check-circle'></i> ".esc_html($title)."</b> <br/> {$safe_html} <b>".esc_html($msg1)."</b> <br/>";
61
  printf("1. <a href='javascript:void(0)' onclick='jQuery(\"#dup-remove-installer-files-btn\").click()'>%s</a><br/>", esc_html__('Remove Installation Files Now!', 'duplicator'));
62
+ printf("2. <a href='https://wordpress.org/support/plugin/duplicator/reviews/?filter=5' target='wporg'>%s</a> <br/> ", esc_html__('Optionally, Review Duplicator at WordPress.org...', 'duplicator'));
63
+ echo "<div class='pass-msg'>".esc_html($msg2)."</div>";
64
 
65
  //All other Pages
66
  } else {
87
  public static function redirect($location)
88
  {
89
  echo '<div class="dup-redirect"><i class="fa fa-circle-o-notch fa-spin fa-fw"></i>';
90
+ esc_html__('Redirecting Please Wait...', 'duplicator');
91
  echo '</div>';
92
  echo "<script>window.location = '{$location}';</script>";
93
+ die(esc_html__('Invalid token permissions to perform this request.', 'duplicator'));
94
  }
95
+ }
classes/ui/class.ui.screen.base.php CHANGED
@@ -1,77 +1,78 @@
1
- <?php
2
- defined("ABSPATH") or die("");
3
-
4
- /**
5
- * The base class for all screen.php files. This class is used to control items that are common
6
- * among all screens, namely the Help tab and Screen Options drop down items. When creating a
7
- * screen object please extent this class.
8
- *
9
- * Standard: PSR-2
10
- * @link http://www.php-fig.org/psr/psr-2
11
- *
12
- * @package Duplicator
13
- * @subpackage classes/ui
14
- * @copyright (c) 2017, Snapcreek LLC
15
- * @since 1.1.0
16
- *
17
- */
18
- class DUP_UI_Screen
19
- {
20
- /**
21
- * Used as a placeholder for the current screen object
22
- */
23
- public $screen;
24
-
25
- /**
26
- * Init this object when created
27
- */
28
- public function __construct()
29
- {
30
-
31
- }
32
-
33
- /**
34
- * Get the help support tab view content shown in the help system
35
- *
36
- * @param string $guide The target URL to navigate to on the online user guide
37
- * @param string $faq The target URL to navigate to on the online user tech FAQ
38
- *
39
- * @return null
40
- */
41
- public function getSupportTab($guide, $faq)
42
- {
43
- $content = __("<b>Need Help?</b> Please check out these resources first:"
44
- ."<ul>"
45
- ."<li><a href='https://snapcreek.com/duplicator/docs/guide{$guide}' target='_sc-faq'>Full Online User Guide</a></li>"
46
- ."<li><a href='https://snapcreek.com/duplicator/docs/faqs-tech{$faq}' target='_sc-faq'>Frequently Asked Questions</a></li>"
47
- ."</ul>", 'duplicator');
48
-
49
- $this->screen->add_help_tab(array(
50
- 'id' => 'dup_help_tab_callback',
51
- 'title' => __('Support', 'duplicator'),
52
- 'content' => "<p>{$content}</p>"
53
- )
54
- );
55
- }
56
-
57
- /**
58
- * Get the help support side bar found in the right most part of the help system
59
- *
60
- * @return null
61
- */
62
- public function getHelpSidbar()
63
- {
64
- $txt_title = __("Resources", 'duplicator');
65
- $txt_home = __("Knowledge Base", 'duplicator');
66
- $txt_guide = __("Full User Guide", 'duplicator');
67
- $txt_faq = __("Technical FAQs", 'duplicator');
68
- $txt_sets = __("Package Settings", 'duplicator');
69
- $this->screen->set_help_sidebar(
70
- "<div class='dup-screen-hlp-info'><b>".esc_html($txt_title).":</b> <br/>"
71
- ."<i class='fa fa-home'></i> <a href='https://snapcreek.com/duplicator/docs/' target='_sc-home'>".esc_html($txt_home)."</a> <br/>"
72
- ."<i class='fa fa-book'></i> <a href='https://snapcreek.com/duplicator/docs/guide/' target='_sc-guide'>".esc_html($txt_guide)."</a> <br/>"
73
- ."<i class='fa fa-file-code-o'></i> <a href='https://snapcreek.com/duplicator/docs/faqs-tech/' target='_sc-faq'>".esc_html($txt_faq)."</a> <br/>"
74
- ."<i class='fa fa-gear'></i> <a href='admin.php?page=duplicator-settings&tab=package'>".esc_html($txt_sets)."</a></div>"
75
- );
76
- }
 
77
  }
1
+ <?php
2
+ /**
3
+ * The base class for all screen.php files. This class is used to control items that are common
4
+ * among all screens, namely the Help tab and Screen Options drop down items. When creating a
5
+ * screen object please extent this class.
6
+ *
7
+ * Standard: PSR-2
8
+ * @link http://www.php-fig.org/psr/psr-2
9
+ *
10
+ * @package Duplicator
11
+ * @subpackage classes/ui
12
+ * @copyright (c) 2017, Snapcreek LLC
13
+ *
14
+ */
15
+
16
+ // Exit if accessed directly
17
+ if (! defined('DUPLICATOR_VERSION')) exit;
18
+
19
+ class DUP_UI_Screen
20
+ {
21
+ /**
22
+ * Used as a placeholder for the current screen object
23
+ */
24
+ public $screen;
25
+
26
+ /**
27
+ * Init this object when created
28
+ */
29
+ public function __construct()
30
+ {
31
+
32
+ }
33
+
34
+ /**
35
+ * Get the help support tab view content shown in the help system
36
+ *
37
+ * @param string $guide The target URL to navigate to on the online user guide
38
+ * @param string $faq The target URL to navigate to on the online user tech FAQ
39
+ *
40
+ * @return null
41
+ */
42
+ public function getSupportTab($guide, $faq)
43
+ {
44
+ $content = __("<b>Need Help?</b> Please check out these resources first:"
45
+ ."<ul>"
46
+ ."<li><a href='https://snapcreek.com/duplicator/docs/guide{$guide}' target='_sc-faq'>Full Online User Guide</a></li>"
47
+ ."<li><a href='https://snapcreek.com/duplicator/docs/faqs-tech{$faq}' target='_sc-faq'>Frequently Asked Questions</a></li>"
48
+ ."</ul>", 'duplicator');
49
+
50
+ $this->screen->add_help_tab(array(
51
+ 'id' => 'dup_help_tab_callback',
52
+ 'title' => esc_html__('Support', 'duplicator'),
53
+ 'content' => "<p>{$content}</p>"
54
+ )
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Get the help support side bar found in the right most part of the help system
60
+ *
61
+ * @return null
62
+ */
63
+ public function getHelpSidbar()
64
+ {
65
+ $txt_title = __("Resources", 'duplicator');
66
+ $txt_home = __("Knowledge Base", 'duplicator');
67
+ $txt_guide = __("Full User Guide", 'duplicator');
68
+ $txt_faq = __("Technical FAQs", 'duplicator');
69
+ $txt_sets = __("Package Settings", 'duplicator');
70
+ $this->screen->set_help_sidebar(
71
+ "<div class='dup-screen-hlp-info'><b>".esc_html($txt_title).":</b> <br/>"
72
+ ."<i class='fa fa-home'></i> <a href='https://snapcreek.com/duplicator/docs/' target='_sc-home'>".esc_html($txt_home)."</a> <br/>"
73
+ ."<i class='fa fa-book'></i> <a href='https://snapcreek.com/duplicator/docs/guide/' target='_sc-guide'>".esc_html($txt_guide)."</a> <br/>"
74
+ ."<i class='fa fa-file-code-o'></i> <a href='https://snapcreek.com/duplicator/docs/faqs-tech/' target='_sc-faq'>".esc_html($txt_faq)."</a> <br/>"
75
+ ."<i class='fa fa-gear'></i> <a href='admin.php?page=duplicator-settings&tab=package'>".esc_html($txt_sets)."</a></div>"
76
+ );
77
+ }
78
  }
classes/ui/class.ui.viewstate.php CHANGED
@@ -1,74 +1,71 @@
1
- <?php
2
- /**
3
- * Gets the view state of UI elements to remember its viewable state
4
- *
5
- * Standard: PSR-2
6
- * @link http://www.php-fig.org/psr/psr-2
7
- *
8
- * @package Duplicator
9
- * @subpackage classes/ui
10
- * @copyright (c) 2017, Snapcreek LLC
11
- * @since 1.1.0
12
- *
13
- */
14
-
15
- // Exit if accessed directly
16
- if (!defined('DUPLICATOR_VERSION')) {
17
- exit;
18
- }
19
-
20
- class DUP_UI_ViewState
21
- {
22
- /**
23
- * The key used in the wp_options table
24
- *
25
- * @var string
26
- */
27
- private static $optionsViewStateKey = 'duplicator_ui_view_state';
28
-
29
- /**
30
- * Save the view state of UI elements
31
- *
32
- * @param string $key A unique key to define the ui element
33
- * @param string $value A generic value to use for the view state
34
- *
35
- * @return bool Returns true if the value was succesfully saved
36
- */
37
- public static function save($key, $value)
38
- {
39
- $view_state = array();
40
- $view_state = get_option(self::$optionsViewStateKey);
41
- $view_state[$key] = $value;
42
- $success = update_option(self::$optionsViewStateKey, $view_state);
43
- return $success;
44
- }
45
-
46
- /**
47
- * Gets all the values from the settings array
48
- *
49
- * @return array Returns and array of all the values stored in the settings array
50
- */
51
- public static function getArray()
52
- {
53
- return get_option(self::$optionsViewStateKey);
54
- }
55
-
56
- /**
57
- * Return the value of the of view state item
58
- *
59
- * @param type $searchKey The key to search on
60
- * @return string Returns the value of the key searched or null if key is not found
61
- */
62
- public static function getValue($searchKey)
63
- {
64
- $view_state = get_option(self::$optionsViewStateKey);
65
- if (is_array($view_state)) {
66
- foreach ($view_state as $key => $value) {
67
- if ($key == $searchKey) {
68
- return $value;
69
- }
70
- }
71
- }
72
- return null;
73
- }
74
  }
1
+ <?php
2
+ /**
3
+ * Gets the view state of UI elements to remember its viewable state
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2
7
+ *
8
+ * @package Duplicator
9
+ * @subpackage classes/ui
10
+ * @copyright (c) 2017, Snapcreek LLC
11
+ *
12
+ */
13
+
14
+ // Exit if accessed directly
15
+ if (! defined('DUPLICATOR_VERSION')) exit;
16
+
17
+ class DUP_UI_ViewState
18
+ {
19
+ /**
20
+ * The key used in the wp_options table
21
+ *
22
+ * @var string
23
+ */
24
+ private static $optionsViewStateKey = 'duplicator_ui_view_state';
25
+
26
+ /**
27
+ * Save the view state of UI elements
28
+ *
29
+ * @param string $key A unique key to define the UI element
30
+ * @param string $value A generic value to use for the view state
31
+ *
32
+ * @return bool Returns true if the value was successfully saved
33
+ */
34
+ public static function save($key, $value)
35
+ {
36
+ $view_state = array();
37
+ $view_state = get_option(self::$optionsViewStateKey);
38
+ $view_state[$key] = $value;
39
+ $success = update_option(self::$optionsViewStateKey, $view_state);
40
+ return $success;
41
+ }
42
+
43
+ /**
44
+ * Gets all the values from the settings array
45
+ *
46
+ * @return array Returns and array of all the values stored in the settings array
47
+ */
48
+ public static function getArray()
49
+ {
50
+ return get_option(self::$optionsViewStateKey);
51
+ }
52
+
53
+ /**
54
+ * Return the value of the of view state item
55
+ *
56
+ * @param type $searchKey The key to search on
57
+ * @return string Returns the value of the key searched or null if key is not found
58
+ */
59
+ public static function getValue($searchKey)
60
+ {
61
+ $view_state = get_option(self::$optionsViewStateKey);
62
+ if (is_array($view_state)) {
63
+ foreach ($view_state as $key => $value) {
64
+ if ($key == $searchKey) {
65
+ return $value;
66
+ }
67
+ }
68
+ }
69
+ return null;
70
+ }
 
 
 
71
  }
classes/utilities/class.u.json.php CHANGED
@@ -1,153 +1,193 @@
1
- <?php
2
-
3
- class DUP_JSON
4
- {
5
- protected static $_messages = array(
6
- JSON_ERROR_NONE => 'No error has occurred',
7
- JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
8
- JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
9
- JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
10
- JSON_ERROR_SYNTAX => 'Syntax error',
11
- JSON_ERROR_UTF8 => 'Malformed UTF-8 characters. To resolve see https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=malformed_utf8#faq-package-170-q'
12
- );
13
-
14
- public static function customEncode($value, $iteration = 1)
15
- {
16
- if (DUP_Util::$on_php_53_plus) {
17
-
18
- $encoded = json_encode($value);
19
-
20
- switch (json_last_error()) {
21
- case JSON_ERROR_NONE:
22
- return $encoded;
23
- case JSON_ERROR_DEPTH:
24
- throw new RuntimeException('Maximum stack depth exceeded');
25
- case JSON_ERROR_STATE_MISMATCH:
26
- throw new RuntimeException('Underflow or the modes mismatch');
27
- case JSON_ERROR_CTRL_CHAR:
28
- throw new RuntimeException('Unexpected control character found');
29
- case JSON_ERROR_SYNTAX:
30
- throw new RuntimeException('Syntax error, malformed JSON');
31
- case JSON_ERROR_UTF8:
32
- if ($iteration == 1) {
33
- $clean = self::makeUTF8($value);
34
- return self::customEncode($clean, $iteration + 1);
35
- } else {
36
- throw new RuntimeException('UTF-8 error loop');
37
- }
38
- default:
39
- throw new RuntimeException('Unknown error');
40
- }
41
- } else {
42
- return self::oldCustomEncode($value);
43
- }
44
- }
45
-
46
- public static function encode($value, $options = 0)
47
- {
48
- $result = json_encode($value, $options);
49
-
50
- if ($result !== FALSE) {
51
- return $result;
52
- }
53
-
54
- if (function_exists('json_last_error')) {
55
- $message = self::$_messages[json_last_error()];
56
- } else {
57
- $message = __('One or more filenames isn\'t compatible with JSON encoding');
58
- }
59
-
60
- throw new RuntimeException($message);
61
- }
62
-
63
- public static function safeEncode($value)
64
- {
65
- $jsonString = json_encode($value);
66
-
67
- if (($jsonString === false) || trim($jsonString) == '') {
68
- $jsonString = self::customEncode($value);
69
-
70
- if (($jsonString === false) || trim($jsonString) == '') {
71
- throw new Exception('Unable to generate JSON from object');
72
- }
73
- }
74
-
75
- return $jsonString;
76
- }
77
-
78
- public static function decode($json, $assoc = false)
79
- {
80
- $result = json_decode($json, $assoc);
81
-
82
- if ($result) {
83
- return $result;
84
- }
85
-
86
- if (function_exists('json_last_error')) {
87
- throw new RuntimeException(self::$_messages[json_last_error()]);
88
- } else {
89
- throw new RuntimeException("DUP_JSON decode error");
90
- }
91
-
92
- }
93
-
94
- private static function makeUTF8($mixed)
95
- {
96
- if (is_array($mixed)) {
97
- foreach ($mixed as $key => $value) {
98
- $mixed[$key] = self::makeUTF8($value);
99
- }
100
- } else if (is_string($mixed)) {
101
- return utf8_encode($mixed);
102
- }
103
- return $mixed;
104
- }
105
-
106
- private static function escapeString($str)
107
- {
108
- return addcslashes($str, "\v\t\n\r\f\"\\/");
109
- }
110
-
111
- private static function oldCustomEncode($in)
112
- {
113
- $out = "";
114
-
115
- if (is_object($in)) {
116
- $arr[$key] = "\"".self::escapeString($key)."\":\"{$val}\"";
117
- $in = get_object_vars($in);
118
- }
119
-
120
- if (is_array($in)) {
121
- $obj = false;
122
- $arr = array();
123
-
124
- foreach ($in AS $key => $val) {
125
- if (!is_numeric($key)) {
126
- $obj = true;
127
- }
128
- $arr[$key] = self::oldCustomEncode($val);
129
- }
130
-
131
- if ($obj) {
132
- foreach ($arr AS $key => $val) {
133
- $arr[$key] = "\"".self::escapeString($key)."\":{$val}";
134
- }
135
- $val = implode(',', $arr);
136
- $out .= "{{$val}}";
137
- } else {
138
- $val = implode(',', $arr);
139
- $out .= "[{$val}]";
140
- }
141
- } elseif (is_bool($in)) {
142
- $out .= $in ? 'true' : 'false';
143
- } elseif (is_null($in)) {
144
- $out .= 'null';
145
- } elseif (is_string($in)) {
146
- $out .= "\"".self::escapeString($in)."\"";
147
- } else {
148
- $out .= $in;
149
- }
150
-
151
- return "{$out}";
152
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  }
1
+ <?php
2
+ /**
3
+ * Utility class for working with JSON data
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2
7
+ *
8
+ * @subpackage classes/utilities
9
+ * @copyright (c) 2017, Snapcreek LLC
10
+ * @license https://opensource.org/licenses/GPL-3.0 GNU Public License
11
+ */
12
+
13
+ // Exit if accessed directly
14
+ if (! defined('DUPLICATOR_VERSION')) exit;
15
+
16
+ class DUP_JSON
17
+ {
18
+ protected static $_messages = array(
19
+ JSON_ERROR_NONE => 'No error has occurred',
20
+ JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
21
+ JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
22
+ JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
23
+ JSON_ERROR_SYNTAX => 'Syntax error',
24
+ JSON_ERROR_UTF8 => 'Malformed UTF-8 characters. To resolve see https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=malformed_utf8#faq-package-170-q'
25
+ );
26
+
27
+ /**
28
+ * Used on PHP 5.3+ to better handle calling the json_encode method
29
+ *
30
+ * Returns a string containing the JSON representation of the supplied value
31
+ *
32
+ * @return string
33
+ */
34
+ public static function customEncode($value, $iteration = 1)
35
+ {
36
+ if (DUP_Util::$on_php_53_plus) {
37
+
38
+ $encoded = json_encode($value);
39
+
40
+ switch (json_last_error()) {
41
+ case JSON_ERROR_NONE:
42
+ return $encoded;
43
+ case JSON_ERROR_DEPTH:
44
+ throw new RuntimeException('Maximum stack depth exceeded');
45
+ case JSON_ERROR_STATE_MISMATCH:
46
+ throw new RuntimeException('Underflow or the modes mismatch');
47
+ case JSON_ERROR_CTRL_CHAR:
48
+ throw new RuntimeException('Unexpected control character found');
49
+ case JSON_ERROR_SYNTAX:
50
+ throw new RuntimeException('Syntax error, malformed JSON');
51
+ case JSON_ERROR_UTF8:
52
+ if ($iteration == 1) {
53
+ $clean = self::makeUTF8($value);
54
+ return self::customEncode($clean, $iteration + 1);
55
+ } else {
56
+ throw new RuntimeException('UTF-8 error loop');
57
+ }
58
+ default:
59
+ throw new RuntimeException('Unknown error');
60
+ }
61
+ } else {
62
+ return self::oldCustomEncode($value);
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Attempts to only call the json_encode method directly
68
+ *
69
+ * Returns a string containing the JSON representation of the supplied value
70
+ *
71
+ * @return string
72
+ */
73
+ public static function encode($value, $options = 0)
74
+ {
75
+ $result = json_encode($value, $options);
76
+
77
+ if ($result !== FALSE) {
78
+ return $result;
79
+ }
80
+
81
+ if (function_exists('json_last_error')) {
82
+ $message = self::$_messages[json_last_error()];
83
+ } else {
84
+ $message = esc_html__("One or more filenames isn't compatible with JSON encoding", 'duplicator');
85
+ }
86
+
87
+ throw new RuntimeException($message);
88
+ }
89
+
90
+ /**
91
+ * Attempts to call json_encode upon error DUP_JSON::customEncode is called
92
+ *
93
+ * Returns a string containing the JSON representation of the supplied value
94
+ *
95
+ * @return string
96
+ */
97
+ public static function safeEncode($value)
98
+ {
99
+ $jsonString = json_encode($value);
100
+ if (($jsonString === false) || trim($jsonString) == '') {
101
+ $jsonString = self::customEncode($value);
102
+
103
+ if (($jsonString === false) || trim($jsonString) == '') {
104
+ throw new Exception('Unable to generate JSON from object');
105
+ }
106
+ }
107
+ return $jsonString;
108
+ }
109
+
110
+ /**
111
+ * Attempts to only call the json_decode method directly
112
+ *
113
+ * Returns the value encoded in json in appropriate PHP type. Values true, false and null are returned as TRUE, FALSE and NULL respectively.
114
+ * NULL is returned if the json cannot be decoded or if the encoded data is deeper than the recursion limit.
115
+ *
116
+ * @return object
117
+ */
118
+ public static function decode($json, $assoc = false)
119
+ {
120
+ $result = json_decode($json, $assoc);
121
+
122
+ if ($result) {
123
+ return $result;
124
+ }
125
+
126
+ if (function_exists('json_last_error')) {
127
+ throw new RuntimeException(self::$_messages[json_last_error()]);
128
+ } else {
129
+ throw new RuntimeException("DUP_JSON decode error");
130
+ }
131
+
132
+ }
133
+
134
+ private static function makeUTF8($mixed)
135
+ {
136
+ if (is_array($mixed)) {
137
+ foreach ($mixed as $key => $value) {
138
+ $mixed[$key] = self::makeUTF8($value);
139
+ }
140
+ } else if (is_string($mixed)) {
141
+ return utf8_encode($mixed);
142
+ }
143
+ return $mixed;
144
+ }
145
+
146
+ private static function escapeString($str)
147
+ {
148
+ return addcslashes($str, "\v\t\n\r\f\"\\/");
149
+ }
150
+
151
+ private static function oldCustomEncode($in)
152
+ {
153
+ $out = "";
154
+
155
+ if (is_object($in)) {
156
+ $arr[$key] = "\"".self::escapeString($key)."\":\"{$val}\"";
157
+ $in = get_object_vars($in);
158
+ }
159
+
160
+ if (is_array($in)) {
161
+ $obj = false;
162
+ $arr = array();
163
+
164
+ foreach ($in AS $key => $val) {
165
+ if (!is_numeric($key)) {
166
+ $obj = true;
167
+ }
168
+ $arr[$key] = self::oldCustomEncode($val);
169
+ }
170
+
171
+ if ($obj) {
172
+ foreach ($arr AS $key => $val) {
173
+ $arr[$key] = "\"".self::escapeString($key)."\":{$val}";
174
+ }
175
+ $val = implode(',', $arr);
176
+ $out .= "{{$val}}";
177
+ } else {
178
+ $val = implode(',', $arr);
179
+ $out .= "[{$val}]";
180
+ }
181
+ } elseif (is_bool($in)) {
182
+ $out .= $in ? 'true' : 'false';
183
+ } elseif (is_null($in)) {
184
+ $out .= 'null';
185
+ } elseif (is_string($in)) {
186
+ $out .= "\"".self::escapeString($in)."\"";
187
+ } else {
188
+ $out .= $in;
189
+ }
190
+
191
+ return "{$out}";
192
+ }
193
  }
classes/utilities/class.u.multisite.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Methods used to work with WordPress MU sites
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2
7
+ *
8
+ * @package Duplicator
9
+ * @subpackage classes/utilities
10
+ * @copyright (c) 2017, Snapcreek LLC
11
+ *
12
+ * @todo Refactor out IO methods into class.io.php file
13
+ */
14
+
15
+ // Exit if accessed directly
16
+ if (! defined('DUPLICATOR_VERSION')) exit;
17
+
18
+ class DUP_MU
19
+ {
20
+ public static function isMultisite()
21
+ {
22
+ return self::getMode() > 0;
23
+ }
24
+
25
+ // 0 = single site; 1 = multisite subdomain; 2 = multisite subdirectory
26
+ public static function getMode()
27
+ {
28
+ if(is_multisite()) {
29
+ if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
30
+ return 1;
31
+ } else {
32
+ return 2;
33
+ }
34
+ } else {
35
+ return 0;
36
+ }
37
+ }
38
+
39
+ public static function getGeneration()
40
+ {
41
+ if (self::getMode() == 0) {
42
+ return DUP_PRO_MU_Generations::NotMultisite;
43
+ } else {
44
+ $sitesDir = WP_CONTENT_DIR.'/uploads/sites';
45
+
46
+ if (file_exists($sitesDir)) {
47
+ return DUP_PRO_MU_Generations::ThreeFivePlus;
48
+ } else {
49
+ return DUP_PRO_MU_Generations::PreThreeFive;
50
+ }
51
+ }
52
+ }
53
+ }
classes/utilities/class.u.php CHANGED
@@ -8,17 +8,12 @@
8
  * @package Duplicator
9
  * @subpackage classes/utilities
10
  * @copyright (c) 2017, Snapcreek LLC
11
- * @since 1.1.0
12
  *
13
  * @todo Refactor out IO methods into class.io.php file
14
  */
15
 
16
  // Exit if accessed directly
17
- if (!defined('DUPLICATOR_VERSION')) {
18
- exit;
19
- }
20
-
21
- //require_once (DUPLICATOR_PLUGIN_PATH.'classes/class.crypt.php');
22
 
23
  class DUP_Util
24
  {
@@ -53,6 +48,15 @@ class DUP_Util
53
  self::$PHP7_plus = version_compare(PHP_VERSION, '7.0.0', '>=');
54
  }
55
 
 
 
 
 
 
 
 
 
 
56
 
57
  public static function getWPCoreDirs()
58
  {
@@ -69,10 +73,10 @@ class DUP_Util
69
  $wp_core_dirs[] = $wp_path.'/plugins';
70
  $wp_core_dirs[] = $wp_path.'/themes';
71
 
72
-
73
  return $wp_core_dirs;
74
  }
75
- /**
 
76
  * return absolute path for the files that are core directories
77
  * @return string array
78
  */
@@ -92,7 +96,7 @@ class DUP_Util
92
  * @param mixed $key,... The key to group or split by. Can be a _string_, an _integer_, a _float_, or a _callable_.
93
  * - If the key is a callback, it must return a valid key from the array.
94
  * - If the key is _NULL_, the iterated element is skipped.
95
- * - string|int callback ( mixed $item )
96
  *
97
  * @return array|null Returns a multidimensional array or `null` if `$key` is invalid.
98
  */
@@ -133,7 +137,7 @@ class DUP_Util
133
  }
134
 
135
  /**
136
- * PHP_SAPI for fcgi requires a data flush of at least 256
137
  * bytes every 40 seconds or else it forces a script halt
138
  *
139
  * @return string A series of 256 space characters
@@ -146,9 +150,9 @@ class DUP_Util
146
  }
147
 
148
  /**
149
- * Returns the wp-snapshot url
150
  *
151
- * @return string The full url of the duplicators snapshot storage directory
152
  */
153
  public static function snapshotURL()
154
  {
@@ -156,7 +160,7 @@ class DUP_Util
156
  }
157
 
158
  /**
159
- * Returns the last N lines of a file. equivalent to tail command
160
  *
161
  * @param string $filepath The full path to the file to be tailed
162
  * @param int $lines The number of lines to return with each tail call
@@ -165,7 +169,6 @@ class DUP_Util
165
  */
166
  public static function tailFile($filepath, $lines = 2)
167
  {
168
-
169
  // Open file
170
  $f = @fopen($filepath, "rb");
171
  if ($f === false) return false;
@@ -208,21 +211,6 @@ class DUP_Util
208
  return trim($output);
209
  }
210
 
211
- /**
212
- * Runs the APC cache to pre-cache the php files
213
- *
214
- * @returns bool True if all files where cached
215
- */
216
- public static function runAPC()
217
- {
218
- if (function_exists('apc_compile_file')) {
219
- $file01 = @apc_compile_file(DUPLICATOR_PLUGIN_PATH."duplicator.php");
220
- return ($file01);
221
- } else {
222
- return false;
223
- }
224
- }
225
-
226
  /**
227
  * Display human readable byte sizes
228
  *
@@ -246,7 +234,7 @@ class DUP_Util
246
  /**
247
  * Makes path safe for any OS
248
  * Paths should ALWAYS READ be "/"
249
- * uni: /home/path/file.xt
250
  * win: D:/home/path/file.txt
251
  *
252
  * @param string $path The path to make safe
@@ -304,7 +292,7 @@ class DUP_Util
304
  * @param string $path The full path to a system directory
305
  *
306
  * @return array of all files in that path
307
- *
308
  * Notes:
309
  * - Avoid using glob() as GLOB_BRACE is not an option on some operating systems
310
  * - Pre PHP 5.3 DirectoryIterator will crash on unreadable files
@@ -320,7 +308,6 @@ class DUP_Util
320
  return $files;
321
 
322
  } catch (Exception $exc) {
323
-
324
  $result = array();
325
  $files = @scandir($path);
326
  if (is_array($files)) {
@@ -426,6 +413,32 @@ class DUP_Util
426
  return false;
427
  }
428
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  /**
430
  * Does the current user have the capability
431
  *
@@ -482,32 +495,6 @@ class DUP_Util
482
  }
483
  }
484
 
485
- /**
486
- * Wrap to prevent malware scanners from reporting false/positive
487
- * Switched from our old method to avoid WordFence reporting a false positive
488
- *
489
- * @param string $string The string to decrypt i.e. base64_decode
490
- *
491
- * @return string Returns the string base64 decoded
492
- */
493
- public static function installerUnscramble($string)
494
- {
495
- return base64_decode($string);
496
- }
497
-
498
- /**
499
- * Wrap to prevent malware scanners from reporting false/positive
500
- * Switched from our old method to avoid WordFence reporting a false positive
501
- *
502
- * @param string $string The string to decrypt i.e. base64_encode
503
- *
504
- * @return string Returns the string base64 encode
505
- */
506
- public static function installerScramble($string)
507
- {
508
- return base64_encode($string);
509
- }
510
-
511
  /**
512
  * Creates the snapshot directory if it doesn't already exist
513
  *
@@ -604,6 +591,16 @@ class DUP_Util
604
  return $filepath;
605
  }
606
 
 
 
 
 
 
 
 
 
 
 
607
  /**
608
  * Returns an array of the WordPress core tables.
609
  *
@@ -626,13 +623,14 @@ class DUP_Util
626
  "{$wpdb->prefix}usermeta",
627
  "{$wpdb->prefix}users");
628
  }
629
-
630
- /**
631
- * Finds if its a valid executable or not
632
- * @param type $exe A non zero length executable path to find if that is executable or not.
633
- * @param type $expectedValue expected value for the result
634
- * @return boolean
635
- */
 
636
  public static function isExecutable($cmd)
637
  {
638
  if (strlen($cmd) < 1) return false;
@@ -654,14 +652,29 @@ class DUP_Util
654
  return false;
655
  }
656
 
657
- /**
658
- * Is the server PHP 5.3 or better
659
- *
660
- * @return bool Returns true if the server PHP 5.3 or better
661
- */
662
- public static function PHP53()
663
- {
664
- return version_compare(PHP_VERSION, '5.3.2', '>=');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
665
  }
666
  }
667
- DUP_Util::init();
8
  * @package Duplicator
9
  * @subpackage classes/utilities
10
  * @copyright (c) 2017, Snapcreek LLC
 
11
  *
12
  * @todo Refactor out IO methods into class.io.php file
13
  */
14
 
15
  // Exit if accessed directly
16
+ if (! defined('DUPLICATOR_VERSION')) exit;
 
 
 
 
17
 
18
  class DUP_Util
19
  {
48
  self::$PHP7_plus = version_compare(PHP_VERSION, '7.0.0', '>=');
49
  }
50
 
51
+ public static function objectCopy($srcObject, $destObject, $skipMemberArray = null)
52
+ {
53
+ foreach ($srcObject as $member_name => $member_value) {
54
+ if (!is_object($member_value) && (($skipMemberArray == null) || !in_array($member_name, $skipMemberArray))) {
55
+ // Skipping all object members
56
+ $destObject->$member_name = $member_value;
57
+ }
58
+ }
59
+ }
60
 
61
  public static function getWPCoreDirs()
62
  {
73
  $wp_core_dirs[] = $wp_path.'/plugins';
74
  $wp_core_dirs[] = $wp_path.'/themes';
75
 
 
76
  return $wp_core_dirs;
77
  }
78
+
79
+ /**
80
  * return absolute path for the files that are core directories
81
  * @return string array
82
  */
96
  * @param mixed $key,... The key to group or split by. Can be a _string_, an _integer_, a _float_, or a _callable_.
97
  * - If the key is a callback, it must return a valid key from the array.
98
  * - If the key is _NULL_, the iterated element is skipped.
99
+ * - string|oink callback ( mixed $item )
100
  *
101
  * @return array|null Returns a multidimensional array or `null` if `$key` is invalid.
102
  */
137
  }
138
 
139
  /**
140
+ * PHP_SAPI for FCGI requires a data flush of at least 256
141
  * bytes every 40 seconds or else it forces a script halt
142
  *
143
  * @return string A series of 256 space characters
150
  }
151
 
152
  /**
153
+ * Returns the wp-snapshot URL
154
  *
155
+ * @return string The full URL of the duplicators snapshot storage directory
156
  */
157
  public static function snapshotURL()
158
  {
160
  }
161
 
162
  /**
163
+ * Returns the last N lines of a file. Equivalent to tail command
164
  *
165
  * @param string $filepath The full path to the file to be tailed
166
  * @param int $lines The number of lines to return with each tail call
169
  */
170
  public static function tailFile($filepath, $lines = 2)
171
  {
 
172
  // Open file
173
  $f = @fopen($filepath, "rb");
174
  if ($f === false) return false;
211
  return trim($output);
212
  }
213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  /**
215
  * Display human readable byte sizes
216
  *
234
  /**
235
  * Makes path safe for any OS
236
  * Paths should ALWAYS READ be "/"
237
+ * uni: /home/path/file.txt
238
  * win: D:/home/path/file.txt
239
  *
240
  * @param string $path The path to make safe
292
  * @param string $path The full path to a system directory
293
  *
294
  * @return array of all files in that path
295
+ *
296
  * Notes:
297
  * - Avoid using glob() as GLOB_BRACE is not an option on some operating systems
298
  * - Pre PHP 5.3 DirectoryIterator will crash on unreadable files
308
  return $files;
309
 
310
  } catch (Exception $exc) {
 
311
  $result = array();
312
  $files = @scandir($path);
313
  if (is_array($files)) {
413
  return false;
414
  }
415
 
416
+ /**
417
+ * Wrap to prevent malware scanners from reporting false/positive
418
+ * Switched from our old method to avoid WordFence reporting a false positive
419
+ *
420
+ * @param string $string The string to decrypt i.e. base64_decode
421
+ *
422
+ * @return string Returns the string base64 decoded
423
+ */
424
+ public static function installerUnscramble($string)
425
+ {
426
+ return base64_decode($string);
427
+ }
428
+
429
+ /**
430
+ * Wrap to prevent malware scanners from reporting false/positive
431
+ * Switched from our old method to avoid WordFence reporting a false positive
432
+ *
433
+ * @param string $string The string to decrypt i.e. base64_encode
434
+ *
435
+ * @return string Returns the string base64 encode
436
+ */
437
+ public static function installerScramble($string)
438
+ {
439
+ return base64_encode($string);
440
+ }
441
+
442
  /**
443
  * Does the current user have the capability
444
  *
495
  }
496
  }
497
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
498
  /**
499
  * Creates the snapshot directory if it doesn't already exist
500
  *
591
  return $filepath;
592
  }
593
 
594
+ /**
595
+ * Is the server PHP 5.3 or better
596
+ *
597
+ * @return bool Returns true if the server PHP 5.3 or better
598
+ */
599
+ public static function PHP53()
600
+ {
601
+ return version_compare(PHP_VERSION, '5.3.2', '>=');
602
+ }
603
+
604
  /**
605
  * Returns an array of the WordPress core tables.
606
  *
623
  "{$wpdb->prefix}usermeta",
624
  "{$wpdb->prefix}users");
625
  }
626
+
627
+ /**
628
+ * Finds if its a valid executable or not
629
+ *
630
+ * @param type $exe A non zero length executable path to find if that is executable or not.
631
+ * @param type $expectedValue expected value for the result
632
+ * @return boolean
633
+ */
634
  public static function isExecutable($cmd)
635
  {
636
  if (strlen($cmd) < 1) return false;
652
  return false;
653
  }
654
 
655
+ /**
656
+ * Display human readable byte sizes
657
+ *
658
+ * @param string $size The size in bytes
659
+ *
660
+ * @return string Human readable bytes such as 50MB, 1GB
661
+ */
662
+ public static function readableByteSize($size)
663
+ {
664
+ try {
665
+ $units = array('B', 'KB', 'MB', 'GB', 'TB');
666
+ for ($i = 0; $size >= 1024 && $i < 4; $i++)
667
+ $size /= 1024;
668
+ return round($size, 2).$units[$i];
669
+ } catch (Exception $e) {
670
+ return "n/a";
671
+ }
672
+ }
673
+
674
+ public static function getTablePrefix() {
675
+ global $wpdb;
676
+ $tablePrefix = (is_multisite() && is_plugin_active_for_network('duplicator/duplicator.php')) ? $wpdb->base_prefix : $wpdb->prefix;
677
+ return $tablePrefix;
678
  }
679
  }
680
+ DUP_Util::init();
classes/utilities/class.u.scancheck.php CHANGED
@@ -6,16 +6,13 @@
6
  * @link http://www.php-fig.org/psr/psr-2
7
  *
8
  * @package Duplicator
9
- * @subpackage classes/utilites
10
  * @copyright (c) 2017, Snapcreek LLC
11
- * @since 1.1.26
12
  *
13
  */
14
 
15
  // Exit if accessed directly
16
- if (!defined('DUPLICATOR_VERSION')) {
17
- exit;
18
- }
19
 
20
  class DUP_ScanCheck
21
  {
@@ -154,7 +151,7 @@ class DUP_ScanCheck
154
  }
155
  }
156
  }
157
-
158
  $this->dirCount++;
159
  }
160
  }
@@ -164,9 +161,9 @@ class DUP_ScanCheck
164
  }
165
 
166
  /**
167
- * Seperation logic for supporting how different operating systems work
168
  *
169
- * @param string $target A valid file path
170
  *
171
  * @return bool Is the target a sym link
172
  */
6
  * @link http://www.php-fig.org/psr/psr-2
7
  *
8
  * @package Duplicator
9
+ * @subpackage classes/utilities
10
  * @copyright (c) 2017, Snapcreek LLC
 
11
  *
12
  */
13
 
14
  // Exit if accessed directly
15
+ if (! defined('DUPLICATOR_VERSION')) exit;
 
 
16
 
17
  class DUP_ScanCheck
18
  {
151
  }
152
  }
153
  }
154
+
155
  $this->dirCount++;
156
  }
157
  }
161
  }
162
 
163
  /**
164
+ * Separation logic for supporting how different operating systems work
165
  *
166
+ * @param string $target A valid file path
167
  *
168
  * @return bool Is the target a sym link
169
  */
classes/utilities/class.u.shell.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined("ABSPATH") or die("");
3
+
4
+ // Exit if accessed directly
5
+ if (! defined('DUPLICATOR_VERSION')) exit;
6
+
7
+ class DUP_Shell_U
8
+ {
9
+ /**
10
+ * Escape a string to be used as a shell argument with bypass support for Windows
11
+ *
12
+ * NOTES:
13
+ * Provides a way to support shell args on Windows OS and allows %,! on Windows command line
14
+ * Safe if input is know such as a defined constant and not from user input escape shellarg
15
+ * on Windows with turn %,! into spaces
16
+ *
17
+ * @return string
18
+ */
19
+ public static function escapeshellargWindowsSupport($string)
20
+ {
21
+ if (strncasecmp(PHP_OS, 'WIN', 3) == 0) {
22
+ if (strstr($string, '%') || strstr($string, '!')) {
23
+ $result = '"'.str_replace('"', '', $string).'"';
24
+ return $result;
25
+ }
26
+ }
27
+ return escapeshellarg($string);
28
+ }
29
+
30
+ public static function isPopenEnabled() {
31
+ if (!function_exists('popen') || !function_exists('proc_open')) {
32
+ $ret = false;
33
+ } else {
34
+ $ret = true;
35
+ }
36
+ $ret = apply_filters('duplicator_pro_is_popen_enabled', $ret);
37
+ return $ret;
38
+ }
39
+ }
classes/utilities/class.u.string.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Utility class working with strings
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2
7
+ *
8
+ * @package DUP
9
+ * @subpackage classes/utilities
10
+ * @copyright (c) 2017, Snapcreek LLC
11
+ * @license https://opensource.org/licenses/GPL-3.0 GNU Public License
12
+ *
13
+ */
14
+ class DUP_STR
15
+ {
16
+
17
+ /**
18
+ * Append the value to the string if it doesn't already exist
19
+ *
20
+ * @param string $string The string to append to
21
+ * @param string $value The string to append to the $string
22
+ *
23
+ * @return string Returns the string with the $value appended once
24
+ */
25
+ public static function appendOnce($string, $value)
26
+ {
27
+ return $string.(substr($string, -1) == $value ? '' : $value);
28
+ }
29
+
30
+ /**
31
+ * Returns true if the string contains UTF8 characters
32
+ * @see http://php.net/manual/en/function.mb-detect-encoding.php
33
+ *
34
+ * @param string $string The class name where the $destArray exists
35
+ *
36
+ * @return null
37
+ */
38
+ public static function hasUTF8($string)
39
+ {
40
+ return preg_match('%(?:
41
+ [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
42
+ |\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
43
+ |[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
44
+ |\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
45
+ |\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
46
+ |[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
47
+ |\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
48
+ )+%xs', $string);
49
+ }
50
+
51
+ /**
52
+ * Returns true if the $needle is found in the $haystack
53
+ *
54
+ * @param string $haystack The full string to search in
55
+ * @param string $needle The string to for
56
+ *
57
+ * @return bool
58
+ */
59
+ public static function contains($haystack, $needle)
60
+ {
61
+ $pos = strpos($haystack, $needle);
62
+ return ($pos !== false);
63
+ }
64
+
65
+ /**
66
+ * Returns true if the $haystack string starts with the $needle
67
+ *
68
+ * @param string $haystack The full string to search in
69
+ * @param string $needle The string to for
70
+ *
71
+ * @return bool Returns true if the $haystack string starts with the $needle
72
+ */
73
+ public static function startsWith($haystack, $needle)
74
+ {
75
+ $length = strlen($needle);
76
+ return (substr($haystack, 0, $length) === $needle);
77
+ }
78
+
79
+ /**
80
+ * Returns true if the $haystack string ends with the $needle
81
+ *
82
+ * @param string $haystack The full string to search in
83
+ * @param string $needle The string to for
84
+ *
85
+ * @return bool Returns true if the $haystack string ends with the $needle
86
+ */
87
+ public static function endsWith($haystack, $needle)
88
+ {
89
+ $length = strlen($needle);
90
+ if ($length == 0) {
91
+ return true;
92
+ }
93
+ return (substr($haystack, -$length) === $needle);
94
+ }
95
+
96
+
97
+ }
98
+
classes/utilities/class.u.validator.php ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Validate variables
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2
7
+ *
8
+ * @package Duplicator
9
+ * @subpackage classes/utilities
10
+ * @copyright (c) 2017, Snapcreek LLC
11
+ *
12
+ */
13
+
14
+ // Exit if accessed directly
15
+ if (! defined('DUPLICATOR_VERSION')) exit;
16
+
17
+ class DUP_Validator
18
+ {
19
+ /**
20
+ * @var array $patterns
21
+ */
22
+ private static $patterns = array(
23
+ 'fdir' => '/^([a-zA-Z]:|\/|\\\\\\\\)[\p{L}\s0-9-_!%&()=\[\]#@,.;+\\\\\/]+$/',
24
+ 'ffile' => '/^([a-zA-Z]:|\/|\\\\\\\\)[\p{L}\s0-9-_!%&()=\[\]#@,.;+\\\\\/]+\.[A-Za-z0-9]{2,4}$/',
25
+ 'fext' => '/^\.?[A-Za-z0-9]{2,4}$/',
26
+ 'email' => '[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+',
27
+ 'empty' => '/^$/',
28
+ 'nempty' => '/^.+$/',
29
+ );
30
+
31
+ const FILTER_VALIDATE_IS_EMPTY = 'empty';
32
+ const FILTER_VALIDATE_NOT_EMPTY = 'nempty';
33
+ const FILTER_VALIDATE_FILE = 'ffile';
34
+ const FILTER_VALIDATE_FOLDER = 'fdir';
35
+ const FILTER_VALIDATE_FILE_EXT = 'fext';
36
+
37
+ /**
38
+ * @var array $errors [ ['key' => string field key,
39
+ * 'msg' => error message ] , [] ]
40
+ */
41
+ private $errors = array();
42
+
43
+ /**
44
+ *
45
+ */
46
+ public function __construct()
47
+ {
48
+ $this->errors = array();
49
+ }
50
+
51
+ /**
52
+ *
53
+ */
54
+ public function reset()
55
+ {
56
+ $this->errors = array();
57
+ }
58
+
59
+ /**
60
+ *
61
+ * @return bool
62
+ */
63
+ public function isSuccess()
64
+ {
65
+ return empty($this->errors);
66
+ }
67
+
68
+ /**
69
+ *
70
+ * @return array
71
+ */
72
+ public function getErrors()
73
+ {
74
+ return $this->errors;
75
+ }
76
+
77
+ /**
78
+ *
79
+ * @return array return errors messages
80
+ */
81
+ public function getErrorsMsg()
82
+ {
83
+ $result = array();
84
+ foreach ($this->errors as $err) {
85
+ $result[] = $err['msg'];
86
+ }
87
+ return $result;
88
+ }
89
+
90
+ /**
91
+ *
92
+ * @param string $format printf format message where %s is the variable content default "%s\n"
93
+ * @param bool $echo if false return string
94
+ * @return void|string
95
+ */
96
+ public function getErrorsFormat($format = "%s\n", $echo = true)
97
+ {
98
+ $msgs = $this->getErrorsMsg();
99
+
100
+ ob_start();
101
+ foreach ($msgs as $msg) {
102
+ printf($format, $msg);
103
+ }
104
+
105
+ if ($echo) {
106
+ ob_end_flush();
107
+ } else {
108
+ return ob_get_clean();
109
+ }
110
+ }
111
+
112
+ /**
113
+ *
114
+ * @param string $key
115
+ * @param string $msg
116
+ */
117
+ protected function addError($key, $msg)
118
+ {
119
+ $this->errors[] = array(
120
+ 'key' => $key,
121
+ 'msg' => $msg
122
+ );
123
+ }
124
+
125
+ /**
126
+ * filter_var function wrapper see http://php.net/manual/en/function.filter-var.php
127
+ *
128
+ * additional options
129
+ * valkey => key of field
130
+ * errmsg => error message; % s will be replaced with the contents of the variable es. "<b>%s</b> isn't a valid field"
131
+ * acc_vals => array of accepted values that skip validation
132
+ *
133
+ * @param mixed $variable
134
+ * @param int $filter
135
+ * @param array $options
136
+ * @return mixed
137
+ */
138
+ public function filter_var($variable, $filter = FILTER_DEFAULT, $options = array())
139
+ {
140
+ $success = true;
141
+ $result = null;
142
+
143
+ if (isset($options['acc_vals']) && in_array($variable , $options['acc_vals'])) {
144
+ return $variable;
145
+ }
146
+
147
+ if ($filter === FILTER_VALIDATE_BOOLEAN) {
148
+ $options['flags'] = FILTER_NULL_ON_FAILURE;
149
+
150
+ $result = filter_var($variable, $filter, $options);
151
+
152
+ if (is_null($result)) {
153
+ $success = false;
154
+ }
155
+ } else {
156
+ $result = filter_var($variable, $filter, $options);
157
+
158
+ if ($result === false) {
159
+ $success = false;
160
+ }
161
+ }
162
+
163
+ if (!$success) {
164
+ $key = isset($options['valkey']) ? $options['valkey'] : '';
165
+
166
+ if (isset($options['errmsg'])) {
167
+ $msg = sprintf($options['errmsg'], $variable);
168
+ } else {
169
+ $msg = sprintf('%1$s isn\'t a valid value', $variable);
170
+ }
171
+
172
+ $this->addError($key, $msg);
173
+ }
174
+
175
+ return $result;
176
+ }
177
+
178
+ /**
179
+ * validation of predefined regular expressions
180
+ *
181
+ * @param mixed $variable
182
+ * @param string $filter
183
+ * @param array $options
184
+ * @return type
185
+ * @throws Exception
186
+ */
187
+ public function filter_custom($variable, $filter, $options = array())
188
+ {
189
+
190
+ if (!isset(self::$patterns[$filter])) {
191
+ throw new Exception('Filter not valid');
192
+ }
193
+
194
+ $options = array_merge($options, array(
195
+ 'options' => array(
196
+ 'regexp' => self::$patterns[$filter])
197
+ )
198
+ );
199
+
200
+ //$options['regexp'] = self::$patterns[$filter];
201
+
202
+ return $this->filter_var($variable, FILTER_VALIDATE_REGEXP, $options);
203
+ }
204
+
205
+ /**
206
+ * it explodes a string with a delimiter and validates every element of the array
207
+ *
208
+ * @param string $variable
209
+ * @param string $delimiter
210
+ * @param string $filter
211
+ * @param array $options
212
+ */
213
+ public function explode_filter_custom($variable, $delimiter , $filter, $options = array()) {
214
+ if (empty($variable)) {
215
+ return array();
216
+ }
217
+
218
+ $vals = explode($delimiter, trim($variable, $delimiter));
219
+ $res = array();
220
+
221
+ foreach ($vals as $val) {
222
+ $res[] = $this->filter_custom($val, $filter, $options);
223
+ }
224
+
225
+ return $res;
226
+ }
227
+
228
+ }
classes/utilities/class.u.zip.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined("ABSPATH") or die("");
3
+ /**
4
+ * Utility class for zipping up content
5
+ *
6
+ * Standard: PSR-2
7
+ * @link http://www.php-fig.org/psr/psr-2
8
+ *
9
+ * @subpackage classes/utilities
10
+ * @copyright (c) 2017, Snapcreek LLC
11
+ * @license https://opensource.org/licenses/GPL-3.0 GNU Public License
12
+ */
13
+
14
+ // Exit if accessed directly
15
+ if (! defined('DUPLICATOR_VERSION')) exit;
16
+
17
+ class DUP_Zip_U
18
+ {
19
+ /**
20
+ * Add a directory to an existing ZipArchive object
21
+ *
22
+ * @param ZipArchive $zipArchive An existing ZipArchive object
23
+ * @param string $directoryPath The full directory path to add to the ZipArchive
24
+ * @param bool $retainDirectory Should the full directory path be retained in the archive
25
+ *
26
+ * @return bool Returns true if the directory was added to the object
27
+ */
28
+ public static function addDirWithZipArchive(&$zipArchive, $directoryPath, $retainDirectory, $localPrefix, $isCompressed)
29
+ {
30
+ $success = true;
31
+
32
+ $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directoryPath), RecursiveIteratorIterator::SELF_FIRST);
33
+
34
+ foreach ($objects as $path => $object) {
35
+ $path = DUP_Util::safePath($path);
36
+ $local_name = ltrim(str_replace($directoryPath, '', $path), '/');
37
+
38
+ if ($retainDirectory) {
39
+ $local_name = basename($directoryPath)."/$local_name";
40
+ }
41
+
42
+ $local_name = $localPrefix . $local_name;
43
+
44
+ if (!is_dir($path)) {
45
+ if (is_readable($path)) {
46
+ $added = DUP_Zip_U::addFileToZipArchive($zipArchive, $path, $local_name, $isCompressed);
47
+ } else {
48
+ $added = false;
49
+ }
50
+ } else {
51
+ $added = true;
52
+ }
53
+
54
+ if (!$added) {
55
+ DUP_Log::error("Couldn't add file $path to archive", '', Dup_ErrorBehavior::LogOnly);
56
+ $success = false;
57
+ break;
58
+ }
59
+ }
60
+
61
+ return $success;
62
+ }
63
+
64
+
65
+ public static function extractFiles($archiveFilepath, $relativeFilesToExtract, $destinationDirectory, $useShellUnZip)
66
+ {
67
+ // TODO: Unzip using either shell unzip or ziparchive
68
+ if($useShellUnZip) {
69
+ $shellExecPath = DUPX_Server::get_unzip_filepath();
70
+
71
+ $filenameString = implode(' ', $relativeFilesToExtract);
72
+
73
+ $command = "{$shellExecPath} -o -qq \"{$archiveFilepath}\" {$filenameString} -d {$destinationDirectory} 2>&1";
74
+
75
+ $stderr = shell_exec($command);
76
+
77
+ if ($stderr != '') {
78
+ $errorMessage = DUP_U::__("Error extracting {$archiveFilepath}): {$stderr}");
79
+
80
+ throw new Exception($errorMessage);
81
+ }
82
+ } else {
83
+ $zipArchive = new ZipArchive();
84
+
85
+ $result = $zipArchive->open($archiveFilepath);
86
+
87
+ if($result !== true) {
88
+ throw new Exception("Error opening {$archiveFilepath} when extracting. Error code: {$retVal}");
89
+ }
90
+
91
+ $result = $zipArchive->extractTo($destinationDirectory, $relativeFilesToExtract);
92
+
93
+ if($result === false) {
94
+ throw new Exception("Error extracting {$archiveFilepath}.");
95
+ }
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Add a directory to an existing ZipArchive object
101
+ *
102
+ * @param string $sourceFilePath The file to add to the zip file
103
+ * @param string $zipFilePath The zip file to be added to
104
+ * @param bool $deleteOld Delete the zip file before adding a file
105
+ * @param string $newName Rename the $sourceFile if needed
106
+ *
107
+ * @return bool Returns true if the file was added to the zip file
108
+ */
109
+ public static function zipFile($sourceFilePath, $zipFilePath, $deleteOld, $newName, $isCompressed)
110
+ {
111
+ if ($deleteOld && file_exists($zipFilePath)) {
112
+ DUP_IO::deleteFile($zipFilePath);
113
+ }
114
+
115
+ if (file_exists($sourceFilePath)) {
116
+ $zip_archive = new ZipArchive();
117
+
118
+ $is_zip_open = ($zip_archive->open($zipFilePath, ZIPARCHIVE::CREATE) === TRUE);
119
+
120
+ if ($is_zip_open === false) {
121
+ DUP_Log::error("Cannot create zip archive {$zipFilePath}");
122
+ } else {
123
+ //ADD SQL
124
+ if ($newName == null) {
125
+ $source_filename = basename($sourceFilePath);
126
+ DUP_Log::Info("adding {$source_filename}");
127
+ } else {
128
+ $source_filename = $newName;
129
+ DUP_Log::Info("new name added {$newName}");
130
+ }
131
+
132
+ $in_zip = DUP_Zip_U::addFileToZipArchive($zip_archive, $sourceFilePath, $source_filename, $isCompressed);
133
+
134
+ if ($in_zip === false) {
135
+ DUP_Log::error("Unable to add {$sourceFilePath} to $zipFilePath");
136
+ }
137
+
138
+ $zip_archive->close();
139
+
140
+ return true;
141
+ }
142
+ } else {
143
+ DUP_Log::error("Trying to add {$sourceFilePath} to a zip but it doesn't exist!");
144
+ }
145
+
146
+ return false;
147
+ }
148
+
149
+ public static function addFileToZipArchive(&$zipArchive, $filepath, $localName, $isCompressed)
150
+ {
151
+ $added = $zipArchive->addFile($filepath, $localName);
152
+
153
+ return $added;
154
+ }
155
+ }
ctrls/ctrl.base.php CHANGED
@@ -1,4 +1,7 @@
1
  <?php
 
 
 
2
  require_once(DUPLICATOR_PLUGIN_PATH.'/classes/utilities/class.u.php');
3
 
4
  //Enum used to define the various test statues
@@ -37,6 +40,13 @@ class DUP_CTRL_Base
37
  $post = is_array($post) ? $post : array();
38
  return array_merge($_POST, $post);
39
  }
 
 
 
 
 
 
 
40
  }
41
 
42
  /**
1
  <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
+
5
  require_once(DUPLICATOR_PLUGIN_PATH.'/classes/utilities/class.u.php');
6
 
7
  //Enum used to define the various test statues
40
  $post = is_array($post) ? $post : array();
41
  return array_merge($_POST, $post);
42
  }
43
+
44
+ //Merges $_GET params with custom parameters.
45
+ public function getParamMerge($params)
46
+ {
47
+ $params = is_array($params) ? $params : array();
48
+ return array_merge($_GET, $params);
49
+ }
50
  }
51
 
52
  /**
ctrls/ctrl.package.php CHANGED
@@ -1,9 +1,13 @@
1
  <?php
 
 
2
 
3
- require_once(DUPLICATOR_PLUGIN_PATH . '/ctrls/ctrl.base.php');
4
- require_once(DUPLICATOR_PLUGIN_PATH . '/classes/utilities/class.u.scancheck.php');
5
- require_once(DUPLICATOR_PLUGIN_PATH . '/classes/utilities/class.u.json.php');
6
- require_once(DUPLICATOR_PLUGIN_PATH . '/classes/package/class.pack.php');
 
 
7
 
8
  /**
9
  * DUPLICATOR_PACKAGE_SCAN
@@ -12,28 +16,29 @@ require_once(DUPLICATOR_PLUGIN_PATH . '/classes/package/class.pack.php');
12
  * @return json JSON report object
13
  * @example to test: /wp-admin/admin-ajax.php?action=duplicator_package_scan
14
  */
15
- function duplicator_package_scan() {
 
16
  $nonce = sanitize_text_field($_REQUEST['nonce']);
17
- if (!wp_verify_nonce($nonce, 'duplicator_package_scan')) {
18
- die('Security check disrupted, please return to packages screen.');
19
- }
20
-
21
- header('Content-Type: application/json;');
22
- DUP_Util::hasCapability('export');
23
-
24
- @set_time_limit(0);
25
- $errLevel = error_reporting();
26
- error_reporting(E_ERROR);
27
- DUP_Util::initSnapshotDirectory();
28
-
29
- $package = DUP_Package::getActive();
30
- $report = $package->runScanner();
31
-
32
- $package->saveActiveItem('ScanFile', $package->ScanFile);
33
- $json_response = DUP_JSON::safeEncode($report);
34
-
35
- DUP_Package::tempFileCleanup();
36
- error_reporting($errLevel);
37
  die($json_response);
38
  }
39
 
@@ -43,41 +48,146 @@ function duplicator_package_scan() {
43
  *
44
  * @return json JSON object of package results
45
  */
46
- function duplicator_package_build() {
47
-
48
- DUP_Util::hasCapability('export');
49
-
50
- check_ajax_referer( 'dup_package_build', 'nonce');
51
-
52
- header('Content-Type: application/json');
53
-
54
- @set_time_limit(0);
55
- $errLevel = error_reporting();
56
- error_reporting(E_ERROR);
57
- DUP_Util::initSnapshotDirectory();
58
 
59
- $Package = DUP_Package::getActive();
60
-
61
- if (!is_readable(DUPLICATOR_SSDIR_PATH_TMP . "/{$Package->ScanFile}")) {
62
- die("The scan result file was not found. Please run the scan step before building the package.");
63
- }
64
-
65
- $Package->runBuild();
66
-
67
- //JSON:Debug Response
68
- //Pass = 1, Warn = 2, Fail = 3
69
- $json = array();
70
- $json['Status'] = 1;
71
- $json['Package'] = $Package;
72
- $json['Runtime'] = $Package->Runtime;
73
- $json['ExeSize'] = $Package->ExeSize;
74
- $json['ZipSize'] = $Package->ZipSize;
75
- $json_response = json_encode($json);
76
-
77
- //Simulate a Host Build Interrupt
 
 
 
 
 
 
 
 
 
 
 
 
78
  //die(0);
79
 
80
- error_reporting($errLevel);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  die($json_response);
82
  }
83
 
@@ -86,73 +196,79 @@ function duplicator_package_build() {
86
  * Deletes the files and database record entries
87
  *
88
  * @return json A JSON message about the action.
89
- * Use console.log to debug from client
90
  */
91
- function duplicator_package_delete() {
92
-
93
- DUP_Util::hasCapability('export');
94
- check_ajax_referer( 'package_list', 'nonce' );
95
-
 
 
 
 
 
 
 
 
 
 
96
  try {
97
- global $wpdb;
98
- $json = array();
99
- $post = stripslashes_deep($_POST);
100
- $tblName = $wpdb->prefix . 'duplicator_packages';
101
- $postIDs = isset($post['duplicator_delid']) ? sanitize_text_field($post['duplicator_delid']) : null;
102
- $list = explode(",", $postIDs);
103
- $delCount = 0;
104
-
 
105
  if ($postIDs != null) {
106
-
107
  foreach ($list as $id) {
108
-
109
- $getResult = $wpdb->get_results($wpdb->prepare("SELECT name, hash FROM `{$tblName}` WHERE id = %d", $id), ARRAY_A);
110
-
111
- if ($getResult) {
112
- $row = $getResult[0];
113
- $nameHash = "{$row['name']}_{$row['hash']}";
114
- $delResult = $wpdb->query($wpdb->prepare( "DELETE FROM `{$tblName}` WHERE id = %d", $id ));
115
- if ($delResult != 0) {
116
- //Perms
117
- @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_archive.zip"), 0644);
118
- @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_database.sql"), 0644);
119
- @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_installer.php"), 0644);
120
- @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_archive.zip"), 0644);
121
- @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_database.sql"), 0644);
122
- @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_installer.php"), 0644);
123
- @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_scan.json"), 0644);
124
- @chmod(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}.log"), 0644);
125
- //Remove
126
- @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_archive.zip"));
127
- @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_database.sql"));
128
- @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_installer.php"));
129
- @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_archive.zip"));
130
- @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_database.sql"));
131
- @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_installer.php"));
132
- @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}_scan.json"));
133
- @unlink(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH . "/{$nameHash}.log"));
134
- //Unfinished Zip files
135
- $tmpZip = DUPLICATOR_SSDIR_PATH_TMP . "/{$nameHash}_archive.zip.*";
136
- if ($tmpZip !== false) {
137
- array_map('unlink', glob($tmpZip));
138
- }
139
- $delCount++;
140
- }
141
- }
142
  }
143
  }
144
-
145
  } catch (Exception $e) {
146
- $json['error'] = "{$e}";
147
  die(json_encode($json));
148
  }
149
-
150
- $json['ids'] = "{$postIDs}";
151
- $json['removed'] = $delCount;
152
- die(json_encode($json));
153
- }
154
-
155
 
 
 
 
 
 
156
 
157
  /**
158
  * Controller for Tools
@@ -160,59 +276,211 @@ function duplicator_package_delete() {
160
  */
161
  class DUP_CTRL_Package extends DUP_CTRL_Base
162
  {
163
- /**
 
164
  * Init this instance of the object
165
  */
166
- function __construct()
167
- {
168
- add_action('wp_ajax_DUP_CTRL_Package_addQuickFilters', array($this, 'addQuickFilters'));
169
- }
170
-
 
171
 
172
- /**
173
  * Removed all reserved installer files names
174
- *
175
- * @param string $_POST['dir_paths'] A semi-colon separated list of directory paths
176
- *
177
- * @return string Returns all of the active directory filters as a ";" separated string
178
  */
179
- public function addQuickFilters($post)
180
- {
181
- $post = $this->postParamMerge($post);
182
- check_ajax_referer($post['action'], 'nonce');
183
- $result = new DUP_CTRL_Result($this);
 
184
 
185
- try {
186
- //CONTROLLER LOGIC
187
- $package = DUP_Package::getActive();
188
 
189
- //DIRS
190
- $dir_filters = $package->Archive->FilterDirs.';' . $post['dir_paths'];
191
- $dir_filters = $package->Archive->parseDirectoryFilter($dir_filters);
192
- $changed = $package->Archive->saveActiveItem($package, 'FilterDirs', $dir_filters);
 
 
193
 
194
- //FILES
195
- $file_filters = $package->Archive->FilterFiles.';' . $post['file_paths'];
196
- $file_filters = $package->Archive->parseFileFilter($file_filters);
197
- $changed = $package->Archive->saveActiveItem($package, 'FilterFiles', $file_filters);
 
 
198
 
199
-
200
- $changed = $package->Archive->saveActiveItem($package, 'FilterOn', 1);
 
201
 
202
- //Result
203
- $package = DUP_Package::getActive();
204
- $payload['dirs-in'] = $post['dir_paths'];
205
- $payload['dir-out'] = $package->Archive->FilterDirs;
206
- $payload['files-in'] = $post['file_paths'];
207
- $payload['files-out'] = $package->Archive->FilterFiles;
208
 
209
- //RETURN RESULT
210
- $test = ($changed) ? DUP_CTRL_Status::SUCCESS : DUP_CTRL_Status::FAILED;
211
- $result->process($payload, $test);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
- } catch (Exception $exc) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  $result->processError($exc);
215
  }
216
- }
217
-
218
  }
1
  <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
 
5
+ require_once(DUPLICATOR_PLUGIN_PATH.'/ctrls/ctrl.base.php');
6
+ require_once(DUPLICATOR_PLUGIN_PATH.'/classes/utilities/class.u.scancheck.php');
7
+ require_once(DUPLICATOR_PLUGIN_PATH.'/classes/utilities/class.u.json.php');
8
+ require_once(DUPLICATOR_PLUGIN_PATH.'/classes/package/class.pack.php');
9
+ require_once(DUPLICATOR_PLUGIN_PATH.'/classes/package/duparchive/class.pack.archive.duparchive.state.create.php');
10
+ /* @var $package DUP_Package */
11
 
12
  /**
13
  * DUPLICATOR_PACKAGE_SCAN
16
  * @return json JSON report object
17
  * @example to test: /wp-admin/admin-ajax.php?action=duplicator_package_scan
18
  */
19
+ function duplicator_package_scan()
20
+ {
21
  $nonce = sanitize_text_field($_REQUEST['nonce']);
22
+ if (!wp_verify_nonce($nonce, 'duplicator_package_scan')) {
23
+ die('An unathorized security request was made to this page. Please try again!');
24
+ }
25
+
26
+ header('Content-Type: application/json;');
27
+ DUP_Util::hasCapability('export');
28
+
29
+ @set_time_limit(0);
30
+ $errLevel = error_reporting();
31
+ error_reporting(E_ERROR);
32
+ DUP_Util::initSnapshotDirectory();
33
+
34
+ $package = DUP_Package::getActive();
35
+ $report = $package->runScanner();
36
+
37
+ $package->saveActiveItem('ScanFile', $package->ScanFile);
38
+ $json_response = DUP_JSON::safeEncode($report);
39
+
40
+ DUP_Package::tempFileCleanup();
41
+ error_reporting($errLevel);
42
  die($json_response);
43
  }
44
 
48
  *
49
  * @return json JSON object of package results
50
  */
51
+ function duplicator_package_build()
52
+ {
53
+ DUP_Util::hasCapability('export');
 
 
 
 
 
 
 
 
 
54
 
55
+ check_ajax_referer('duplicator_package_build', 'nonce');
56
+ header('Content-Type: application/json');
57
+
58
+ @set_time_limit(0);
59
+ $errLevel = error_reporting();
60
+ error_reporting(E_ERROR);
61
+ DUP_Util::initSnapshotDirectory();
62
+
63
+ $Package = DUP_Package::getActive();
64
+ $Package->save('zip');
65
+
66
+ DUP_Settings::Set('active_package_id', $Package->ID);
67
+ DUP_Settings::Save();
68
+
69
+ if (!is_readable(DUPLICATOR_SSDIR_PATH_TMP."/{$Package->ScanFile}")) {
70
+ die("The scan result file was not found. Please run the scan step before building the package.");
71
+ }
72
+
73
+ $Package->runZipBuild();
74
+
75
+ //JSON:Debug Response
76
+ //Pass = 1, Warn = 2, Fail = 3
77
+ $json = array();
78
+ $json['status'] = 1;
79
+ $json['package'] = $Package;
80
+ $json['runtime'] = $Package->Runtime;
81
+ $json['exeSize'] = $Package->ExeSize;
82
+ $json['archiveSize'] = $Package->ZipSize;
83
+ $json_response = json_encode($json);
84
+
85
+ //Simulate a Host Build Interrupt
86
  //die(0);
87
 
88
+ error_reporting($errLevel);
89
+ die($json_response);
90
+ }
91
+
92
+ /**
93
+ * Returns the package result status
94
+ *
95
+ * @return json JSON object of package results
96
+ */
97
+ function duplicator_duparchive_package_build()
98
+ {
99
+ DUP_LOG::Trace("call to duplicator_duparchive_package_build");
100
+
101
+ DUP_Util::hasCapability('export');
102
+ check_ajax_referer('duplicator_duparchive_package_build', 'nonce');
103
+ header('Content-Type: application/json');
104
+
105
+ @set_time_limit(0);
106
+ $errLevel = error_reporting();
107
+ error_reporting(E_ERROR);
108
+
109
+ // The DupArchive build process always works on a saved package so the first time through save the active package to the package table.
110
+ // After that, just retrieve it.
111
+ $active_package_id = DUP_Settings::Get('active_package_id');
112
+
113
+ if ($active_package_id == -1) {
114
+
115
+ $package = DUP_Package::getActive();
116
+ $package->save('daf');
117
+ DUP_Log::TraceObject("saving active package as new id={$package->ID}", package);
118
+ DUP_Settings::Set('active_package_id', $package->ID);
119
+ DUP_Settings::Save();
120
+ } else {
121
+
122
+ DUP_Log::TraceObject("getting active package by id {$active_package_id}", package);
123
+ $package = DUP_Package::getByID($active_package_id);
124
+ }
125
+
126
+ if (!is_readable(DUPLICATOR_SSDIR_PATH_TMP."/{$package->ScanFile}")) {
127
+ die("The scan result file was not found. Please run the scan step before building the package.");
128
+ }
129
+
130
+ if ($package === null) {
131
+ die("There is no active package.");
132
+ }
133
+
134
+ if($package->Status == DUP_PackageStatus::ERROR) {
135
+ $hasCompleted = true;
136
+ } else {
137
+ try {
138
+ $hasCompleted = $package->runDupArchiveBuild();
139
+ }
140
+ catch(Exception $ex) {
141
+ Dup_Log::Trace('#### caught exception');
142
+ Dup_Log::Error('Caught exception', $ex->getMessage(), Dup_ErrorBehavior::LogOnly);
143
+ Dup_Log::Trace('#### after log');
144
+ $package->setStatus(DUP_PackageStatus::ERROR);
145
+ $hasCompleted = true;
146
+ }
147
+ }
148
+
149
+ $json = array();
150
+ $json['failures'] = array_merge($package->BuildProgress->build_failures, $package->BuildProgress->validation_failures);
151
+ DUP_LOG::traceObject("#### failures", $json['failures']);
152
+
153
+ //JSON:Debug Response
154
+ //Pass = 1, Warn = 2, 3 = Failure, 4 = Not Done
155
+ if ($hasCompleted) {
156
+
157
+ Dup_Log::Trace('#### completed');
158
+
159
+ if($package->Status == DUP_PackageStatus::ERROR) {
160
+
161
+ Dup_Log::Trace('#### error');
162
+ $error_message = __('Error building DupArchive package') . '<br/>';
163
+
164
+ foreach($json['failures'] as $failure) {
165
+ $error_message .= implode(',', $failure->description);
166
+ }
167
+
168
+ Dup_Log::Error("Build failed so sending back error", esc_html($error_message), Dup_ErrorBehavior::LogOnly);
169
+ Dup_Log::Trace('#### after log 2');
170
+
171
+ $json['status'] = 3;
172
+ } else {
173
+ Dup_Log::Info("sending back success status");
174
+ $json['status'] = 1;
175
+ }
176
+
177
+ Dup_Log::Trace('#### json package');
178
+ $json['package'] = $package;
179
+ $json['runtime'] = $package->Runtime;
180
+ $json['exeSize'] = $package->ExeSize;
181
+ $json['archiveSize'] = $package->ZipSize;
182
+ } else {
183
+ Dup_Log::Info("sending back continue status");
184
+ $json['status'] = 4;
185
+ }
186
+
187
+ $json_response = json_encode($json);
188
+
189
+ Dup_Log::TraceObject('json response', $json_response);
190
+ error_reporting($errLevel);
191
  die($json_response);
192
  }
193
 
196
  * Deletes the files and database record entries
197
  *
198
  * @return json A JSON message about the action.
199
+ * Use console.log to debug from client
200
  */
201
+ function duplicator_package_delete()
202
+ {
203
+ DUP_Util::hasCapability('export');
204
+ check_ajax_referer('package_list', 'nonce');
205
+
206
+ function _unlinkFile($file) {
207
+ if (! file_exists($file)) {
208
+ return;
209
+ }
210
+ if (! @unlink($file)) {
211
+ @chmod($file, 0644);
212
+ @unlink($file);
213
+ }
214
+ }
215
+
216
  try {
217
+ global $wpdb;
218
+ $json = array();
219
+ $post = stripslashes_deep($_POST);
220
+ $tablePrefix = DUP_Util::getTablePrefix();
221
+ $tblName = $tablePrefix.'duplicator_packages';
222
+ $postIDs = isset($post['duplicator_delid']) ? sanitize_text_field($post['duplicator_delid']) : null;
223
+ $list = explode(",", $postIDs);
224
+ $delCount = 0;
225
+
226
  if ($postIDs != null) {
227
+
228
  foreach ($list as $id) {
229
+
230
+ $getResult = $wpdb->get_results($wpdb->prepare("SELECT name, hash FROM `{$tblName}` WHERE id = %d", $id), ARRAY_A);
231
+
232
+ if ($getResult) {
233
+ $row = $getResult[0];
234
+ $nameHash = "{$row['name']}_{$row['hash']}";
235
+ $delResult = $wpdb->query($wpdb->prepare("DELETE FROM `{$tblName}` WHERE id = %d", $id));
236
+ if ($delResult != 0) {
237
+
238
+ //TMP FILES
239
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_archive.daf"));
240
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_archive.zip"));
241
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_database.sql"));
242
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_installer.php"));
243
+
244
+ //WP-SNAPSHOT FILES
245
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_archive.daf"));
246
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_archive.zip"));
247
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_database.sql"));
248
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_installer.php"));
249
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}_scan.json"));
250
+ _unlinkFile(DUP_Util::safePath(DUPLICATOR_SSDIR_PATH."/{$nameHash}.log"));
251
+
252
+ //Unfinished Zip files
253
+ $tmpZip = DUPLICATOR_SSDIR_PATH_TMP."/{$nameHash}_archive.zip.*";
254
+ if ($tmpZip !== false) {
255
+ array_map('unlink', glob($tmpZip));
256
+ }
257
+ $delCount++;
258
+ }
259
+ }
 
 
 
260
  }
261
  }
 
262
  } catch (Exception $e) {
263
+ $json['error'] = "{$e}";
264
  die(json_encode($json));
265
  }
 
 
 
 
 
 
266
 
267
+ $json['ids'] = "{$postIDs}";
268
+ $json['removed'] = $delCount;
269
+ echo json_encode($json);
270
+ die();
271
+ }
272
 
273
  /**
274
  * Controller for Tools
276
  */
277
  class DUP_CTRL_Package extends DUP_CTRL_Base
278
  {
279
+
280
+ /**
281
  * Init this instance of the object
282
  */
283
+ function __construct()
284
+ {
285
+ add_action('wp_ajax_DUP_CTRL_Package_addQuickFilters', array($this, 'addQuickFilters'));
286
+ add_action('wp_ajax_DUP_CTRL_Package_getPackageFile', array($this, 'getPackageFile'));
287
+ add_action('wp_ajax_DUP_CTRL_Package_getActivePackageStatus', array($this, 'getActivePackageStatus'));
288
+ }
289
 
290
+ /**
291
  * Removed all reserved installer files names
292
+ *
293
+ * @param string $_POST['dir_paths'] A semi-colon separated list of directory paths
294
+ *
295
+ * @return string Returns all of the active directory filters as a ";" separated string
296
  */
297
+ public function addQuickFilters($post)
298
+ {
299
+ $post = $this->postParamMerge($post);
300
+ $action = sanitize_text_field($post['action']);
301
+ check_ajax_referer($action, 'nonce');
302
+ $result = new DUP_CTRL_Result($this);
303
 
304
+ try {
305
+ //CONTROLLER LOGIC
306
+ $package = DUP_Package::getActive();
307
 
308
+ //DIRS
309
+ $dir_filters = ($package->Archive->FilterOn)
310
+ ? $package->Archive->FilterDirs.';'.sanitize_text_field($post['dir_paths'])
311
+ : sanitize_text_field($post['dir_paths']);
312
+ $dir_filters = $package->Archive->parseDirectoryFilter($dir_filters);
313
+ $changed = $package->Archive->saveActiveItem($package, 'FilterDirs', $dir_filters);
314
 
315
+ //FILES
316
+ $file_filters = ($package->Archive->FilterOn)
317
+ ? $package->Archive->FilterFiles.';'.sanitize_text_field($post['file_paths'])
318
+ : sanitize_text_field($post['file_paths']);
319
+ $file_filters = $package->Archive->parseFileFilter($file_filters);
320
+ $changed = $package->Archive->saveActiveItem($package, 'FilterFiles', $file_filters);
321
 
322
+ if (!$package->Archive->FilterOn && !empty($package->Archive->FilterExts)) {
323
+ $changed = $package->Archive->saveActiveItem($package, 'FilterExts', '');
324
+ }
325
 
326
+ $changed = $package->Archive->saveActiveItem($package, 'FilterOn', 1);
 
 
 
 
 
327
 
328
+ //Result
329
+ $package = DUP_Package::getActive();
330
+ $payload['dirs-in'] = esc_html(sanitize_text_field($post['dir_paths']));
331
+ $payload['dir-out'] = esc_html($package->Archive->FilterDirs);
332
+ $payload['files-in'] = esc_html(sanitize_text_field($post['file_paths']));
333
+ $payload['files-out'] = esc_html($package->Archive->FilterFiles);
334
+
335
+ //RETURN RESULT
336
+ $test = ($changed) ? DUP_CTRL_Status::SUCCESS : DUP_CTRL_Status::FAILED;
337
+ $result->process($payload, $test);
338
+ } catch (Exception $exc) {
339
+ $result->processError($exc);
340
+ }
341
+ }
342
+
343
+ /**
344
+ * Download the requested package file
345
+ *
346
+ * @param string $_POST['which']
347
+ * @param string $_POST['package_id']
348
+ *
349
+ * @return downloadable file
350
+ */
351
+ function getPackageFile($post)
352
+ {
353
+ $params = $this->postParamMerge($post);
354
 
355
+ $nonce = sanitize_text_field($_GET['nonce']);
356
+ if (!wp_verify_nonce($nonce, 'DUP_CTRL_Package_getPackageFile')) {
357
+ die('An unathorized security request was made to this page. Please try again!');
358
+ }
359
+
360
+ $params = $this->getParamMerge($params);
361
+ // check_ajax_referer($post['action'], 'nonce');
362
+
363
+ $result = new DUP_CTRL_Result($this);
364
+
365
+ try {
366
+ //CONTROLLER LOGIC
367
+
368
+ DUP_Util::hasCapability('export');
369
+
370
+ $request = stripslashes_deep($_REQUEST);
371
+ $which = (int) $request['which'];
372
+ $packageId = (int) $request['package_id'];
373
+ $package = DUP_Package::getByID($packageId);
374
+ $isBinary = ($which != DUP_PackageFileType::Log);
375
+ $filePath = $package->getLocalPackageFile($which);
376
+
377
+ //OUTPUT: Installer, Archive, SQL File
378
+ if ($isBinary) {
379
+ header("Pragma: public");
380
+ header("Expires: 0");
381
+ header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
382
+ header("Cache-Control: private", false);
383
+ header("Content-Transfer-Encoding: binary");
384
+
385
+ if ($filePath != null) {
386
+ $fp = fopen($filePath, 'rb');
387
+ if ($fp !== false) {
388
+
389
+ if ($which == DUP_PackageFileType::Installer) {
390
+ $fileName = 'installer.php';
391
+ } else {
392
+ $fileName = basename($filePath);
393
+ }
394
+
395
+ header("Content-Type: application/octet-stream");
396
+ header("Content-Disposition: attachment; filename=\"{$fileName}\";");
397
+
398
+ @ob_end_clean(); // required or large files wont work
399
+ DUP_Log::Trace("streaming $filePath");
400
+
401
+ if (fpassthru($fp) === false) {
402
+ DUP_Log::Trace("Error with fpassthru for {$filePath}");
403
+ }
404
+ fclose($fp);
405
+ die(); //Supress additional ouput
406
+ } else {
407
+ header("Content-Type: text/plain");
408
+ header("Content-Disposition: attachment; filename=\"error.txt\";");
409
+ $message = "Couldn't open $filePath.";
410
+ DUP_Log::Trace($message);
411
+ echo esc_html($message);
412
+ }
413
+ } else {
414
+ $message = __("Couldn't find a local copy of the file requested.", 'duplicator');
415
+
416
+ header("Content-Type: text/plain");
417
+ header("Content-Disposition: attachment; filename=\"error.txt\";");
418
+
419
+ // Report that we couldn't find the file
420
+ DUP_Log::Trace($message);
421
+ echo esc_html($message);
422
+ }
423
+
424
+ //OUTPUT: Log File
425
+ } else {
426
+ if ($filePath != null) {
427
+ header("Content-Type: text/plain");
428
+ $text = file_get_contents($filePath);
429
+
430
+ die($text);
431
+ } else {
432
+ $message = __("Couldn't find a local copy of the file requested.", 'duplicator');
433
+ echo esc_html($message);
434
+ }
435
+ }
436
+ } catch (Exception $exc) {
437
+ $result->processError($exc);
438
+ }
439
+ }
440
+
441
+ /**
442
+ * Get active package status
443
+ *
444
+ * <code>
445
+ * //JavaScript Ajax Request
446
+ * Duplicator.Package.getActivePackageStatus()
447
+ * </code>
448
+ */
449
+ public function getActivePackageStatus($post)
450
+ {
451
+ $post = $this->postParamMerge($post);
452
+ $nonce = sanitize_text_field($post['nonce']);
453
+ if (!wp_verify_nonce($nonce, 'DUP_CTRL_Package_getActivePackageStatus')) {
454
+ die('An unathorized security request was made to this page. Please try again!');
455
+ }
456
+ $result = new DUP_CTRL_Result($this);
457
+
458
+ try
459
+ {
460
+ //CONTROLLER LOGIC
461
+ $post = stripslashes_deep($_POST);
462
+
463
+ $active_package_id = DUP_Settings::Get('active_package_id');
464
+
465
+ $package = DUP_Package::getByID($active_package_id);
466
+
467
+ $payload = array();
468
+
469
+ if($package != null) {
470
+ $test = DUP_CTRL_Status::SUCCESS;
471
+
472
+ $payload['status'] = $package->Status;
473
+ } else {
474
+ $test = DUP_CTRL_Status::FAILED;
475
+ }
476
+
477
+ //RETURN RESULT
478
+ return $result->process($payload, $test);
479
+ }
480
+ catch (Exception $exc)
481
+ {
482
  $result->processError($exc);
483
  }
484
+ }
485
+
486
  }
ctrls/ctrl.tools.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php
2
- if ( ! defined('DUPLICATOR_VERSION') ) exit; // Exit if accessed directly
 
3
 
4
  require_once(DUPLICATOR_PLUGIN_PATH . '/ctrls/ctrl.base.php');
5
  require_once(DUPLICATOR_PLUGIN_PATH . '/classes/utilities/class.u.scancheck.php');
@@ -16,6 +17,7 @@ class DUP_CTRL_Tools extends DUP_CTRL_Base
16
  function __construct()
17
  {
18
  add_action('wp_ajax_DUP_CTRL_Tools_runScanValidator', array($this, 'runScanValidator'));
 
19
  }
20
 
21
  /**
@@ -29,20 +31,26 @@ class DUP_CTRL_Tools extends DUP_CTRL_Base
29
  public function runScanValidator($post)
30
  {
31
  @set_time_limit(0);
32
- $post = $this->postParamMerge($post);
33
- check_ajax_referer($post['action'], 'nonce');
 
34
 
35
  $result = new DUP_CTRL_Result($this);
36
 
37
  try
38
  {
39
  //CONTROLLER LOGIC
40
- $path = isset($post['scan-path']) ? sanitize_text_field($post['scan-path']) : sanitize_text_field(DUPLICATOR_WPROOTPATH);
41
  if (!is_dir($path)) {
42
  throw new Exception("Invalid directory provided '{$path}'!");
43
  }
44
- $scanner = new DUP_ScanCheck();
45
- $scanner->recursion = (isset($post['scan-recursive']) && $post['scan-recursive'] != 'false') ? true : false;
 
 
 
 
 
46
  $payload = $scanner->run($path);
47
 
48
  //RETURN RESULT
@@ -56,4 +64,67 @@ class DUP_CTRL_Tools extends DUP_CTRL_Base
56
  $result->processError($exc);
57
  }
58
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
1
  <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
 
5
  require_once(DUPLICATOR_PLUGIN_PATH . '/ctrls/ctrl.base.php');
6
  require_once(DUPLICATOR_PLUGIN_PATH . '/classes/utilities/class.u.scancheck.php');
17
  function __construct()
18
  {
19
  add_action('wp_ajax_DUP_CTRL_Tools_runScanValidator', array($this, 'runScanValidator'));
20
+ add_action('wp_ajax_DUP_CTRL_Tools_getTraceLog', array($this, 'getTraceLog'));
21
  }
22
 
23
  /**
31
  public function runScanValidator($post)
32
  {
33
  @set_time_limit(0);
34
+ $post = $this->postParamMerge($post);
35
+ $action = sanitize_text_field($post['action']);
36
+ check_ajax_referer($action, 'nonce');
37
 
38
  $result = new DUP_CTRL_Result($this);
39
 
40
  try
41
  {
42
  //CONTROLLER LOGIC
43
+ $path = isset($post['scan-path']) ? sanitize_text_field($post['scan-path']) : DUPLICATOR_WPROOTPATH;
44
  if (!is_dir($path)) {
45
  throw new Exception("Invalid directory provided '{$path}'!");
46
  }
47
+ $scanner = new DUP_ScanCheck();
48
+ if (isset($post['scan-recursive'])) {
49
+ $scan_recursive_val = sanitize_text_field($post['scan-recursive']);
50
+ $scan_recursive = ($scan_recursive_val != 'false');
51
+ }
52
+
53
+ $scanner->recursion = $scan_recursive ? true : false;
54
  $payload = $scanner->run($path);
55
 
56
  //RETURN RESULT
64
  $result->processError($exc);
65
  }
66
  }
67
+
68
+ public function getTraceLog()
69
+ {
70
+ DUP_Log::Trace("enter");
71
+
72
+ $nonce = sanitize_text_field($_GET['nonce']);
73
+ if (!wp_verify_nonce($nonce, 'DUP_CTRL_Tools_getTraceLog')) {
74
+ die('An unathorized security request was made to this page. Please try again!');
75
+ }
76
+
77
+ Dup_Util::hasCapability('export');
78
+
79
+ $request = stripslashes_deep($_REQUEST);
80
+ $file_path = DUP_Log::GetTraceFilepath();
81
+ $backup_path = DUP_Log::GetBackupTraceFilepath();
82
+ $zip_path = DUPLICATOR_SSDIR_PATH."/".DUPLICATOR_ZIPPED_LOG_FILENAME;
83
+ $zipped = DUP_Zip_U::zipFile($file_path, $zip_path, true, null, true);
84
+
85
+ if ($zipped && file_exists($backup_path)) {
86
+ $zipped = DUP_Zip_U::zipFile($backup_path, $zip_path, false, null, true);
87
+ }
88
+
89
+ header("Pragma: public");
90
+ header("Expires: 0");
91
+ header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
92
+ header("Cache-Control: private", false);
93
+ header("Content-Transfer-Encoding: binary");
94
+
95
+ $fp = fopen($zip_path, 'rb');
96
+
97
+ if (($fp !== false) && $zipped) {
98
+ $zip_filename = basename($zip_path);
99
+
100
+ header("Content-Type: application/octet-stream");
101
+ header("Content-Disposition: attachment; filename=\"$zip_filename\";");
102
+
103
+ // required or large files wont work
104
+ if (ob_get_length()) {
105
+ ob_end_clean();
106
+ }
107
+
108
+ DUP_Log::trace("streaming $zip_path");
109
+ if (fpassthru($fp) === false) {
110
+ DUP_Log::trace("Error with fpassthru for $zip_path");
111
+ }
112
+
113
+ fclose($fp);
114
+ @unlink($zip_path);
115
+ } else {
116
+ header("Content-Type: text/plain");
117
+ header("Content-Disposition: attachment; filename=\"error.txt\";");
118
+ if ($zipped === false) {
119
+ $message = "Couldn't create zip file.";
120
+ } else {
121
+ $message = "Couldn't open $file_path.";
122
+ }
123
+ DUP_Log::trace($message);
124
+ echo esc_html($message);
125
+ }
126
+
127
+ exit;
128
+ }
129
+
130
  }
ctrls/ctrl.ui.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php
2
- if ( ! defined('DUPLICATOR_VERSION') ) exit; // Exit if accessed directly
 
3
 
4
  require_once(DUPLICATOR_PLUGIN_PATH . '/ctrls/ctrl.base.php');
5
  require_once(DUPLICATOR_PLUGIN_PATH . '/classes/ui/class.ui.viewstate.php');
@@ -42,9 +43,10 @@ class DUP_CTRL_UI extends DUP_CTRL_Base
42
 
43
  $nonce = sanitize_text_field($post['nonce']);
44
  if (!wp_verify_nonce($nonce, 'DUP_CTRL_UI_SaveViewState')) {
45
- die('Security check disrupted, please return to packages screen.');
46
  }
47
 
 
48
  $result = new DUP_CTRL_Result($this);
49
 
50
  try
@@ -84,13 +86,6 @@ class DUP_CTRL_UI extends DUP_CTRL_Base
84
  */
85
  public function GetViewStateList()
86
  {
87
- if (isset($_REQUEST['nonce'])) {
88
- $nonce = sanitize_text_field($_REQUEST['nonce']);
89
- if (!wp_verify_nonce($nonce, 'DUP_CTRL_UI_GetViewStateList')) {
90
- die('Security check disrupted, please return to packages screen.');
91
- }
92
- }
93
-
94
  $result = new DUP_CTRL_Result($this);
95
 
96
  try
1
  <?php
2
+ // Exit if accessed directly
3
+ if (! defined('DUPLICATOR_VERSION')) exit;
4
 
5
  require_once(DUPLICATOR_PLUGIN_PATH . '/ctrls/ctrl.base.php');
6
  require_once(DUPLICATOR_PLUGIN_PATH . '/classes/ui/class.ui.viewstate.php');
43
 
44
  $nonce = sanitize_text_field($post['nonce']);
45
  if (!wp_verify_nonce($nonce, 'DUP_CTRL_UI_SaveViewState')) {
46
+ die('An unathorized security request was made to this page. Please try again!');
47
  }
48
 
49
+
50
  $result = new DUP_CTRL_Result($this);
51
 
52
  try
86
  */
87
  public function GetViewStateList()
88
  {
 
 
 
 
 
 
 
89
  $result = new DUP_CTRL_Result($this);
90
 
91
  try
debug/main.php DELETED
@@ -1,191 +0,0 @@
1
- <?php
2
- DUP_Util::hasCapability('read');
3
-
4
- require_once(DUPLICATOR_PLUGIN_PATH . '/assets/js/javascript.php');
5
- require_once(DUPLICATOR_PLUGIN_PATH . '/views/inc.header.php');
6
-
7
-
8
- function DUP_DEBUG_TestSetup($CTRL)
9
- {
10
- $title = $CTRL['Title'];
11
- $action = $CTRL['Action'];
12
- $testable = $CTRL['Test'] ? 1 : 0;
13
- $test_css = $testable ? '' : 'style="display:none"';
14
- $nonce = wp_create_nonce($action);
15
-
16
- $html = '
17
- <div class="keys">
18
- <input type="hidden" name="testable" value="'.esc_attr($testable).'" />
19
- <input type="hidden" name="action" value="'.esc_attr($action).'" />
20
- <input type="hidden" name="nonce" value="'.esc_attr($nonce).'" />
21
- <span class="result"><i class="fa fa-cube fa-lg"></i></span>
22
- <input type="checkbox" id="'.esc_attr($action).'" name="'.esc_attr($action).'" '.$test_css.' />
23
- <label for="'.esc_attr($action).'">'.esc_html($title).'</label> &nbsp;
24
- <a href="javascript:void(0)" onclick=\'jQuery(this).closest("form").find("div.params").toggle()\'>Params</a> |
25
- <a href="javascript:void(0)" onclick="jQuery(this).closest("form").submit()">Test</a>
26
- </div>';
27
- echo $html;
28
- }
29
-
30
- ?>
31
- <style>
32
- div.debug-area {line-height: 26px}
33
- table.debug-toolbar {width:100%; margin: 3px 0 -10px -5px; }
34
- table.debug-toolbar td {padding:3px; white-space: nowrap}
35
- table.debug-toolbar td:last-child {width: 100%}
36
-
37
- div.debug-area form {margin: 15px 0 0 0; border-top: 1px solid #dfdfdf; padding-top: 5px}
38
- div.debug-area div.keys label {font-weight: bold; font-size: 14px; padding-right: 5px }
39
- div.debug-area div.params label {width:150px; display:inline-block}
40
- div.debug-area input[type=text] {width:400px}
41
-
42
- div.section-hdr {margin:35px 0 0 0; font-size: 16px; font-weight: bold; border:1px solid silver; border-radius: 3px; padding:1px 5px 1px 5px; background: #dfdfdf;}
43
- div.params {display:none}
44
- i.result-pass {color:green}
45
- i.result-fail {color:red}
46
- </style>
47
-
48
- <script>
49
- var UNIT_TEST_FORMS;
50
- var UNIT_TEST_CHKBOXES;
51
- var UNIT_TEST_PASSED;
52
- var UNIT_TEST_COUNTER;
53
- var UNIT_TEST_RUNNING = false;
54
- </script>
55
-
56
- <div class="wrap dup-wrap dup-support-all">
57
- <h1><?php esc_html_e('Testing Interface', 'duplicator'); ?></h1>
58
- <hr size="1" />
59
-
60
- <table class="debug-toolbar">
61
- <tr>
62
- <td>
63
- <span id="results-all"><i class="fa fa-cube fa-lg"></i></span>
64
- <input id="test-checkall" type="checkbox" onclick="Duplicator.Debug.CheckAllTests()">
65
- </td>
66
- <td>
67
- <input type="button" class="button button-small" value="<?php esc_attr_e('Run Tests', 'duplicator'); ?>" onclick="Duplicator.Debug.RunTests()" />
68
- <input type="button" class="button button-small" value="<?php esc_html_e('Refresh Page', 'duplicator'); ?>" onclick="window.location.reload();" />
69
- </td>
70
- <td> <input type="checkbox" id="test-openwindow" onchange="Duplicator.Debug.TestNewWindow()" /> <label for="test-openwindow">Tests in new window</label> </td>
71
- </tr>
72
- </table>
73
-
74
- <div class="debug-area">
75
- <?php
76
- include_once 'tst.tools.php';
77
- include_once 'tst.ui.php';
78
- include_once 'tst.packages.php';
79
- ?>
80
- </div>
81
- </div>
82
-
83
- <script>
84
- jQuery(document).ready(function($)
85
- {
86
- //Run test on all checked options
87
- Duplicator.Debug.RunTests = function()
88
- {
89
- try
90
- {
91
- UNIT_TEST_RUNNING = true;
92
- UNIT_TEST_PASSED = true;
93
- UNIT_TEST_COUNTER = 0;
94
- UNIT_TEST_CHKBOXES = $("div.keys input[type='checkbox']:checked").length;
95
- UNIT_TEST_FORMS = $("div.keys input[name='testable'][value='1']").closest('form');
96
-
97
- $(UNIT_TEST_FORMS).each(function(index)
98
- {
99
- var $form = $(this);
100
- var $result = $form.find('span.result');
101
- var $check = $form.find('div.keys input[type="checkbox"]');
102
- var input;
103
-
104
- if ($check.is(':checked'))
105
- {
106
- $('#results-all').html('<i class="fa fa-cog fa-spin fa-fw fa-lg"></i>');
107
- $result.html('<i class="fa fa-circle-o-notch fa-spin fa-fw fa-lg"></i>');
108
-
109
- //Run any callbacks if defined
110
- if ($form.attr("onsubmit") != undefined) {
111
- $form.submit();
112
- }
113
- input = $form.serialize();
114
-
115
- $.ajax({
116
- type: "POST",
117
- url: ajaxurl,
118
- dataType: "json",
119
- data: input,
120
- success: function(data) { Duplicator.Debug.ProcessResult(data, $result) },
121
- error: function(data) {},
122
- done: function(data) {}
123
- });
124
- }
125
- });
126
- }
127
- catch (e) {
128
- console.log(e);
129
- } finally {
130
- UNIT_TEST_RUNNING = false;
131
- }
132
- }
133
-
134
- //Call back used to test the status of a result
135
- Duplicator.Debug.ProcessResult = function(data, result)
136
- {
137
- UNIT_TEST_COUNTER++;
138
- var status = data.report.status || 0;
139
- //console.log(data);
140
-
141
- if (status > 0) {
142
- result.html('<i class="fa fa-check-circle fa-lg result-pass"></i>');
143
- } else {
144
- UNIT_TEST_PASSED = false;
145
- result.html('<i class="fa fa-check-circle fa-lg result-fail"></i>');
146
- }
147
-
148
- //Set after all tests have ran
149
- if (UNIT_TEST_COUNTER >= UNIT_TEST_CHKBOXES) {
150
- (UNIT_TEST_PASSED)
151
- ? $('#results-all').html('<i class="fa fa-check-circle fa-lg result-pass"></i>')
152
- : $('#results-all').html('<i class="fa fa-check-circle fa-lg result-fail"></i>');
153
- }
154
- }
155
-
156
- //Check all of the check boxes
157
- Duplicator.Debug.CheckAllTests = function()
158
- {
159
- var checkAll = $('#test-checkall').is(':checked');
160
- $("div.keys input[type='checkbox']:visible").each(function() {
161
- (checkAll)
162
- ? $(this).attr('checked', '1')
163
- : $(this).removeAttr('checked');
164
- });
165
- }
166
-
167
- //Test links will open in seperate window if checked
168
- Duplicator.Debug.TestNewWindow = function()
169
- {
170
- var check = $('#test-openwindow').is(':checked');
171
- var count = 0;
172
- $("form").each(function(index)
173
- {
174
- count++;
175
- (check)
176
- ? $(this).attr('target', 'dup_debug' + count)
177
- : $(this).attr('target', 'dup_debug');
178
- });
179
- }
180
-
181
- //INIT
182
- $("form").each(function(index)
183
- {
184
- var $form = $(this);
185
- $form.attr('action', 'admin-ajax.php');
186
- $form.attr('target', 'dup_debug');
187
- $form.attr('method', 'post');
188
- });
189
-
190
- });
191
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
debug/tst.packages.php DELETED
@@ -1,31 +0,0 @@
1
- <div class="section-hdr">PACKAGE CTRLS</div>
2
-
3
- <form>
4
- <?php
5
- $CTRL['Title'] = 'duplicator_package_scan';
6
- $CTRL['Action'] = 'duplicator_package_scan';
7
- $CTRL['Test'] = false;
8
- DUP_DEBUG_TestSetup($CTRL);
9
- ?>
10
- <div class="params">
11
- No Params
12
- </div>
13
- </form>
14
-
15
- <form>
16
- <?php
17
- $CTRL['Title'] = 'DUP_CTRL_Package_addQuickFilters';
18
- $CTRL['Action'] = 'DUP_CTRL_Package_addQuickFilters';
19
- $CTRL['Test'] = true;
20
- DUP_DEBUG_TestSetup($CTRL);
21
- ?>
22
- <div class="params">
23
- <textarea style="width:200px; height: 50px" name="dir_paths">D:/path1/;
24
- D:/path2/path/;
25
- </textarea>
26
- <textarea style="width:200px; height: 50px" name="file_paths">D:/path1/test.txt;
27
- D:/path2/path/test2.txt;
28
- </textarea>
29
- </div>
30
- </form>
31
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
debug/tst.tools.php DELETED
@@ -1,38 +0,0 @@
1
-
2
- <div class="section-tests">
3
- <div class="section-hdr">TOOLS CTRLS</div>
4
-
5
- <!-- METHOD TEST -->
6
- <form>
7
- <?php
8
- $CTRL['Title'] = 'DUP_CTRL_Tools_runScanValidator';
9
- $CTRL['Action'] = 'DUP_CTRL_Tools_runScanValidator';
10
- $CTRL['Test'] = true;
11
- DUP_DEBUG_TestSetup($CTRL);
12
- ?>
13
- <div class="params">
14
- <label>Allow Recursion:</label>
15
- <input type="checkbox" name="scan-recursive" /><br/>
16
- <label>Search Path:</label>
17
- <input type="text" name="scan-path" value="<?php echo DUPLICATOR_WPROOTPATH ?>" /> <br/>
18
- </div>
19
- </form>
20
-
21
- <!-- METHOD TEST -->
22
- <form>
23
- <?php
24
- $CTRL['Title'] = 'DUP_CTRL_Tools_runScanValidatorFull';
25
- $CTRL['Action'] = 'DUP_CTRL_Tools_runScanValidator';
26
- $CTRL['Test'] = true;
27
- DUP_DEBUG_TestSetup($CTRL);
28
- ?>
29
- <div class="params">
30
- <label>Recursion:</label> True
31
- <input type="hidden" name="scan-recursive" value="true" /><br/>
32
- <label>Search Path:</label>
33
- <input type="text" name="scan-path" value="<?php echo DUPLICATOR_WPROOTPATH ?>" /> <br/>
34
- </div>
35
- </form>
36
-
37
-
38
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
debug/tst.ui.php DELETED
@@ -1,45 +0,0 @@
1
-
2
- <div class="section-tests">
3
- <div class="section-hdr">UI CTRLS</div>
4
-
5
- <!-- METHOD TEST -->
6
- <script>
7
- function JS_DUP_CTRL_UI_SaveViewState(form)
8
- {
9
- //value param must be dynamic with each submit or else
10
- //wp update_option method will return false
11
- jQuery(form).find('input[name="value"]').val(new Date(jQuery.now()));
12
- return ! UNIT_TEST_RUNNING;
13
- }
14
- </script>
15
- <form onsubmit="return JS_DUP_CTRL_UI_SaveViewState(this);">
16
- <?php
17
- $CTRL['Title'] = 'DUP_CTRL_UI_SaveViewState';
18
- $CTRL['Action'] = 'DUP_CTRL_UI_SaveViewState';
19
- $CTRL['Test'] = true;
20
- DUP_DEBUG_TestSetup($CTRL);
21
- ?>
22
-
23
- <div class="params">
24
- <label>Key:</label>
25
- <input type="text" name="key" value="dup_ctrl_test" /><br/>
26
- <label>Value:</label>
27
- <input type="text" name="value" /> <br/>
28
- </div>
29
- </form>
30
-
31
-
32
- <!-- METHOD TEST -->
33
- <form>
34
- <?php
35
- $CTRL['Title'] = 'DUP_CTRL_UI_GetViewStateList';
36
- $CTRL['Action'] = 'DUP_CTRL_UI_GetViewStateList';
37
- $CTRL['Test'] = true;
38
- DUP_DEBUG_TestSetup($CTRL);
39
- ?>
40
-
41
- <div class="params">No Params</div>
42
- </form>
43
-
44
-
45
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
define.php CHANGED
@@ -2,8 +2,7 @@
2
  //Prevent directly browsing to the file
3
  if (function_exists('plugin_dir_url'))
4
  {
5
- define('DUPLICATOR_VERSION', '1.2.52');
6
- define('DUPLICATOR_HOMEPAGE', 'https://snapcreek.com/duplicator/duplicator-free/');
7
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
8
  define('DUPLICATOR_SITE_URL', get_site_url());
9
 
@@ -19,13 +18,18 @@ if (function_exists('plugin_dir_url'))
19
  if (! defined('DUPLICATOR_WPROOTPATH')) {
20
  define('DUPLICATOR_WPROOTPATH', str_replace('\\', '/', ABSPATH));
21
  }
22
- define('DUPLICATOR_SSDIR_NAME', 'wp-snapshots');
23
- define('DUPLICATOR_PLUGIN_PATH', str_replace("\\", "/", plugin_dir_path(__FILE__)));
24
- define('DUPLICATOR_SSDIR_PATH', str_replace("\\", "/", DUPLICATOR_WPROOTPATH . DUPLICATOR_SSDIR_NAME));
25
- define('DUPLICATOR_SSDIR_PATH_TMP', DUPLICATOR_SSDIR_PATH . '/tmp');
26
- define('DUPLICATOR_SSDIR_URL', DUPLICATOR_SITE_URL . "/" . DUPLICATOR_SSDIR_NAME);
27
- define('DUPLICATOR_INSTALL_PHP', 'installer.php');
28
- define('DUPLICATOR_INSTALL_BAK', 'installer-backup.php');
 
 
 
 
 
29
 
30
  //GENERAL CONSTRAINTS
31
  define('DUPLICATOR_PHP_MAX_MEMORY', '2048M');
@@ -41,9 +45,29 @@ if (function_exists('plugin_dir_url'))
41
  define('DUPLICATOR_SCAN_DB_TBL_SIZE', 10485760); //10MB Table
42
  define('DUPLICATOR_SCAN_TIMEOUT', 150); //Seconds
43
  define('DUPLICATOR_SCAN_MIN_WP', '4.7.0');
 
 
 
 
 
 
 
 
44
 
45
  $GLOBALS['DUPLICATOR_SERVER_LIST'] = array('Apache','LiteSpeed', 'Nginx', 'Lighttpd', 'IIS', 'WebServerX', 'uWSGI');
46
  $GLOBALS['DUPLICATOR_OPTS_DELETE'] = array('duplicator_ui_view_state', 'duplicator_package_active', 'duplicator_settings');
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
  /* Used to flush a response every N items.
49
  * Note: This value will cause the Zip file to double in size durning the creation process only*/
@@ -63,7 +87,6 @@ if (function_exists('plugin_dir_url'))
63
  if(!defined('PHP_MAJOR_VERSION')) define('PHP_MAJOR_VERSION', $version[0]);
64
  if(!defined('PHP_MINOR_VERSION')) define('PHP_MINOR_VERSION', $version[1]);
65
  if(!defined('PHP_RELEASE_VERSION')) define('PHP_RELEASE_VERSION', $version[2]);
66
-
67
  }
68
 
69
  } else {
2
  //Prevent directly browsing to the file
3
  if (function_exists('plugin_dir_url'))
4
  {
5
+ define('DUPLICATOR_VERSION', '1.3.0');
 
6
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
7
  define('DUPLICATOR_SITE_URL', get_site_url());
8
 
18
  if (! defined('DUPLICATOR_WPROOTPATH')) {
19
  define('DUPLICATOR_WPROOTPATH', str_replace('\\', '/', ABSPATH));
20
  }
21
+
22
+ define('DUPLICATOR_PLUGIN_PATH', str_replace("\\", "/", plugin_dir_path(__FILE__)));
23
+ define('DUPLICATOR_SSDIR_NAME', 'wp-snapshots');
24
+ define('DUPLICATOR_SSDIR_PATH', str_replace("\\", "/", DUPLICATOR_WPROOTPATH . DUPLICATOR_SSDIR_NAME));
25
+ define('DUPLICATOR_SSDIR_PATH_TMP', DUPLICATOR_SSDIR_PATH . '/tmp');
26
+ define("DUPLICATOR_SSDIR_PATH_INSTALLER", DUPLICATOR_SSDIR_PATH . '/installer');
27
+ define('DUPLICATOR_SSDIR_URL', DUPLICATOR_SITE_URL . "/" . DUPLICATOR_SSDIR_NAME);
28
+ define('DUPLICATOR_ZIPPED_LOG_FILENAME', 'duplicator_lite_log.zip');
29
+ define('DUPLICATOR_INSTALL_PHP', 'installer.php');
30
+ define('DUPLICATOR_INSTALL_BAK', 'installer-backup.php');
31
+ define('DUPLICATOR_INSTALLER_HASH_PATTERN', '[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]');
32
+ define('DUPLICATOR_INSTALL_SITE_OVERWRITE_ON', false);
33
 
34
  //GENERAL CONSTRAINTS
35
  define('DUPLICATOR_PHP_MAX_MEMORY', '2048M');
45
  define('DUPLICATOR_SCAN_DB_TBL_SIZE', 10485760); //10MB Table
46
  define('DUPLICATOR_SCAN_TIMEOUT', 150); //Seconds
47
  define('DUPLICATOR_SCAN_MIN_WP', '4.7.0');
48
+ define('DUPLICATOR_MAX_DUPARCHIVE_SIZE', 524288000); // 500 GB
49
+
50
+ define('DUPLICATOR_TEMP_CLEANUP_SECONDS', 900); // 15 min = How many seconds to keep temp files around when delete is requested
51
+ define('DUPLICATOR_MAX_BUILD_RETRIES', 10); // Max times to try a part of progressive build work
52
+ define('DUPLICATOR_HTACCESS_ORIG_FILENAME', 'htaccess.orig');
53
+ define('DUPLICATOR_WEBCONFIG_ORIG_FILENAME', 'web.config.orig');
54
+ define("DUPLICATOR_INSTALLER_DIRECTORY", DUPLICATOR_WPROOTPATH . 'dup-installer');
55
+ define('DUPLICATOR_MAX_LOG_SIZE', 400000); // The higher this is the more overhead
56
 
57
  $GLOBALS['DUPLICATOR_SERVER_LIST'] = array('Apache','LiteSpeed', 'Nginx', 'Lighttpd', 'IIS', 'WebServerX', 'uWSGI');
58
  $GLOBALS['DUPLICATOR_OPTS_DELETE'] = array('duplicator_ui_view_state', 'duplicator_package_active', 'duplicator_settings');
59
+ $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON'] = true;
60
+ $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS'] = array(
61
+ 'error_log',
62
+ 'error.log',
63
+ 'debug_log',
64
+ 'ws_ftp.log',
65
+ 'dbcache',
66
+ 'pgcache',
67
+ 'objectcache',
68
+ '.DS_Store'
69
+ );
70
+
71
 
72
  /* Used to flush a response every N items.
73
  * Note: This value will cause the Zip file to double in size durning the creation process only*/
87
  if(!defined('PHP_MAJOR_VERSION')) define('PHP_MAJOR_VERSION', $version[0]);
88
  if(!defined('PHP_MINOR_VERSION')) define('PHP_MINOR_VERSION', $version[1]);
89
  if(!defined('PHP_RELEASE_VERSION')) define('PHP_RELEASE_VERSION', $version[2]);
 
90
  }
91
 
92
  } else {
duplicator.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Duplicator
4
  Plugin URI: https://snapcreek.com/duplicator/duplicator-free/
5
  Description: Migrate and backup a copy of your WordPress files and database. Duplicate and move a site from one location to another quickly.
6
- Version: 1.2.52
7
  Author: Snap Creek
8
  Author URI: http://www.snapcreek.com/duplicator/
9
  Text Domain: duplicator
@@ -25,6 +25,7 @@
25
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
 
27
  SOURCE CONTRIBUTORS:
 
28
  https://github.com/interconnectit/Search-Replace-DB/
29
  ================================================================================ */
30
 
@@ -109,9 +110,11 @@ if (!function_exists('_sanitize_text_fields')) {
109
  if (is_admin() == true)
110
  {
111
  //Classes
112
- require_once 'classes/class.logging.php';
113
  require_once 'classes/class.settings.php';
 
114
  require_once 'classes/utilities/class.u.php';
 
 
115
  require_once 'classes/class.db.php';
116
  require_once 'classes/class.server.php';
117
  require_once 'classes/ui/class.ui.viewstate.php';
@@ -200,14 +203,19 @@ if (is_admin() == true)
200
  * ===================================================== */
201
  add_action('plugins_loaded', 'duplicator_update');
202
  add_action('plugins_loaded', 'duplicator_wpfront_integrate');
203
- add_action('admin_init', 'duplicator_init');
204
  add_action('admin_menu', 'duplicator_menu');
 
205
  add_action('admin_notices', array('DUP_UI_Notice', 'showReservedFilesNotice'));
206
 
207
  //CTRL ACTIONS
208
- add_action('wp_ajax_duplicator_package_scan', 'duplicator_package_scan');
209
- add_action('wp_ajax_duplicator_package_build', 'duplicator_package_build');
210
- add_action('wp_ajax_duplicator_package_delete', 'duplicator_package_delete');
 
 
 
 
211
  $GLOBALS['CTRLS_DUP_CTRL_UI'] = new DUP_CTRL_UI();
212
  $GLOBALS['CTRLS_DUP_CTRL_Tools'] = new DUP_CTRL_Tools();
213
  $GLOBALS['CTRLS_DUP_CTRL_Package'] = new DUP_CTRL_Package();
@@ -236,13 +244,29 @@ if (is_admin() == true)
236
  /* CSS */
237
  wp_register_style('dup-jquery-ui', DUPLICATOR_PLUGIN_URL . 'assets/css/jquery-ui.css', null, "1.11.2");
238
  wp_register_style('dup-font-awesome', DUPLICATOR_PLUGIN_URL . 'assets/css/font-awesome.min.css', null, '4.7.0');
239
- wp_register_style('dup-plugin-style', DUPLICATOR_PLUGIN_URL . 'assets/css/style.css', null, DUPLICATOR_VERSION);
 
 
240
  wp_register_style('dup-jquery-qtip',DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.css', null, '2.2.1');
241
- wp_register_style('dup-parsley-style', DUPLICATOR_PLUGIN_URL . 'assets/css/style.css', null, '2.3.5');
242
  /* JS */
243
  wp_register_script('dup-handlebars', DUPLICATOR_PLUGIN_URL . 'assets/js/handlebars.min.js', array('jquery'), '4.0.10');
244
- wp_register_script('dup-parsley', DUPLICATOR_PLUGIN_URL . 'assets/js/parsley.min.js', array('jquery'), '2.3.5');
245
  wp_register_script('dup-jquery-qtip', DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.js', array('jquery'), '2.2.1');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  }
247
 
248
  /**
@@ -260,7 +284,7 @@ if (is_admin() == true)
260
  case 'duplicator-settings': include('views/settings/controller.php'); break;
261
  case 'duplicator-tools': include('views/tools/controller.php'); break;
262
  case 'duplicator-debug': include('debug/main.php'); break;
263
- case 'duplicator-gopro': include('views/help/gopro.php'); break;
264
  }
265
  }
266
 
@@ -302,17 +326,6 @@ if (is_admin() == true)
302
  $go_pro_link = '<span style="color:#f18500">' . $lang_txt . '</span>';
303
  $perms = apply_filters($wpfront_caps_translator, $perms);
304
  $page_gopro = add_submenu_page('duplicator', $go_pro_link, $go_pro_link, $perms, 'duplicator-gopro', 'duplicator_get_menu');
305
-
306
- $package_debug = DUP_Settings::Get('package_debug');
307
- if ($package_debug != null && $package_debug == true)
308
- {
309
- $perms = 'manage_options';
310
- $perms = apply_filters($wpfront_caps_translator, $perms);
311
- $lang_txt = esc_html__('Debug', 'duplicator');
312
- $page_debug = add_submenu_page('duplicator', $lang_txt, $lang_txt, $perms, 'duplicator-debug', 'duplicator_get_menu');
313
- add_action('admin_print_scripts-' . $page_debug, 'duplicator_scripts');
314
- add_action('admin_print_styles-' . $page_debug, 'duplicator_styles');
315
- }
316
 
317
  //Apply Scripts
318
  add_action('admin_print_scripts-' . $page_packages, 'duplicator_scripts');
@@ -325,7 +338,6 @@ if (is_admin() == true)
325
  add_action('admin_print_styles-' . $page_settings, 'duplicator_styles');
326
  add_action('admin_print_styles-' . $page_tools, 'duplicator_styles');
327
  add_action('admin_print_styles-' . $page_gopro, 'duplicator_styles');
328
-
329
  }
330
 
331
  /**
@@ -341,6 +353,7 @@ if (is_admin() == true)
341
  wp_enqueue_script('jquery-ui-progressbar');
342
  wp_enqueue_script('dup-parsley');
343
  wp_enqueue_script('dup-jquery-qtip');
 
344
  }
345
 
346
  /**
@@ -355,7 +368,6 @@ if (is_admin() == true)
355
  wp_enqueue_style('dup-font-awesome');
356
  wp_enqueue_style('dup-plugin-style');
357
  wp_enqueue_style('dup-jquery-qtip');
358
- wp_enqueue_style('dup-parsley-style');
359
  }
360
 
361
 
@@ -378,7 +390,7 @@ if (is_admin() == true)
378
  $this_plugin = plugin_basename(__FILE__);
379
 
380
  if ($file == $this_plugin) {
381
- $settings_link = '<a href="admin.php?page=duplicator">' . __("Manage", 'duplicator') . '</a>';
382
  array_unshift($links, $settings_link);
383
  }
384
  return $links;
@@ -395,7 +407,7 @@ if (is_admin() == true)
395
  $plugin = plugin_basename(__FILE__);
396
  // create link
397
  if ($file == $plugin) {
398
- $links[] = '<a href="admin.php?page=duplicator-gopro" title="' . __('Get Help', 'duplicator') . '" style="">' . __('Go Pro', 'duplicator') . '</a>';
399
  return $links;
400
  }
401
  return $links;
3
  Plugin Name: Duplicator
4
  Plugin URI: https://snapcreek.com/duplicator/duplicator-free/
5
  Description: Migrate and backup a copy of your WordPress files and database. Duplicate and move a site from one location to another quickly.
6
+ Version: 1.3.0
7
  Author: Snap Creek
8
  Author URI: http://www.snapcreek.com/duplicator/
9
  Text Domain: duplicator
25
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
 
27
  SOURCE CONTRIBUTORS:
28
+ David Coveney of Interconnect IT Ltd
29
  https://github.com/interconnectit/Search-Replace-DB/
30
  ================================================================================ */
31
 
110
  if (is_admin() == true)
111
  {
112
  //Classes
 
113
  require_once 'classes/class.settings.php';
114
+ require_once 'classes/class.logging.php';
115
  require_once 'classes/utilities/class.u.php';
116
+ require_once 'classes/utilities/class.u.string.php';
117
+ require_once 'classes/utilities/class.u.validator.php';
118
  require_once 'classes/class.db.php';
119
  require_once 'classes/class.server.php';
120
  require_once 'classes/ui/class.ui.viewstate.php';
203
  * ===================================================== */
204
  add_action('plugins_loaded', 'duplicator_update');
205
  add_action('plugins_loaded', 'duplicator_wpfront_integrate');
206
+ add_action('admin_init', 'duplicator_init');
207
  add_action('admin_menu', 'duplicator_menu');
208
+ add_action('admin_enqueue_scripts', 'duplicator_admin_enqueue_scripts' );
209
  add_action('admin_notices', array('DUP_UI_Notice', 'showReservedFilesNotice'));
210
 
211
  //CTRL ACTIONS
212
+ add_action('wp_ajax_duplicator_package_scan', 'duplicator_package_scan');
213
+ add_action('wp_ajax_duplicator_package_build', 'duplicator_package_build');
214
+ add_action('wp_ajax_duplicator_package_delete', 'duplicator_package_delete');
215
+ add_action('wp_ajax_duplicator_duparchive_package_build', 'duplicator_duparchive_package_build');
216
+ add_action('wp_ajax_nopriv_duplicator_duparchive_package_build', 'duplicator_duparchive_package_build');
217
+
218
+
219
  $GLOBALS['CTRLS_DUP_CTRL_UI'] = new DUP_CTRL_UI();
220
  $GLOBALS['CTRLS_DUP_CTRL_Tools'] = new DUP_CTRL_Tools();
221
  $GLOBALS['CTRLS_DUP_CTRL_Package'] = new DUP_CTRL_Package();
244
  /* CSS */
245
  wp_register_style('dup-jquery-ui', DUPLICATOR_PLUGIN_URL . 'assets/css/jquery-ui.css', null, "1.11.2");
246
  wp_register_style('dup-font-awesome', DUPLICATOR_PLUGIN_URL . 'assets/css/font-awesome.min.css', null, '4.7.0');
247
+ wp_register_style('dup-plugin-global-style', DUPLICATOR_PLUGIN_URL . 'assets/css/global_admin_style.css', null , DUPLICATOR_VERSION);
248
+ wp_register_style('dup-plugin-style', DUPLICATOR_PLUGIN_URL . 'assets/css/style.css', array('dup-plugin-global-style') , DUPLICATOR_VERSION);
249
+
250
  wp_register_style('dup-jquery-qtip',DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.css', null, '2.2.1');
251
+ wp_register_style('dup-parsley-style', DUPLICATOR_PLUGIN_URL . 'assets/css/parsley.css', null, '2.3.5');
252
  /* JS */
253
  wp_register_script('dup-handlebars', DUPLICATOR_PLUGIN_URL . 'assets/js/handlebars.min.js', array('jquery'), '4.0.10');
254
+ wp_register_script('dup-parsley', DUPLICATOR_PLUGIN_URL . 'assets/js/parsley.min.js', array('jquery'), '1.1.18');
255
  wp_register_script('dup-jquery-qtip', DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.js', array('jquery'), '2.2.1');
256
+
257
+
258
+ // Clean tmp folder
259
+ DUP_Package::not_active_files_tmp_cleanup();
260
+ }
261
+
262
+ /**
263
+ * Hooked into `admin_enqueue_scripts`. Init routines for all admin pages
264
+ *
265
+ * @access global
266
+ * @return null
267
+ */
268
+ function duplicator_admin_enqueue_scripts() {
269
+ wp_enqueue_style('dup-plugin-global-style');
270
  }
271
 
272
  /**
284
  case 'duplicator-settings': include('views/settings/controller.php'); break;
285
  case 'duplicator-tools': include('views/tools/controller.php'); break;
286
  case 'duplicator-debug': include('debug/main.php'); break;
287
+ case 'duplicator-gopro': include('views/settings/gopro.php'); break;
288
  }
289
  }
290
 
326
  $go_pro_link = '<span style="color:#f18500">' . $lang_txt . '</span>';
327
  $perms = apply_filters($wpfront_caps_translator, $perms);
328
  $page_gopro = add_submenu_page('duplicator', $go_pro_link, $go_pro_link, $perms, 'duplicator-gopro', 'duplicator_get_menu');
 
 
 
 
 
 
 
 
 
 
 
329
 
330
  //Apply Scripts
331
  add_action('admin_print_scripts-' . $page_packages, 'duplicator_scripts');
338
  add_action('admin_print_styles-' . $page_settings, 'duplicator_styles');
339
  add_action('admin_print_styles-' . $page_tools, 'duplicator_styles');
340
  add_action('admin_print_styles-' . $page_gopro, 'duplicator_styles');
 
341
  }
342
 
343
  /**
353
  wp_enqueue_script('jquery-ui-progressbar');
354
  wp_enqueue_script('dup-parsley');
355
  wp_enqueue_script('dup-jquery-qtip');
356
+
357
  }
358
 
359
  /**
368
  wp_enqueue_style('dup-font-awesome');
369
  wp_enqueue_style('dup-plugin-style');
370
  wp_enqueue_style('dup-jquery-qtip');
 
371
  }
372
 
373
 
390
  $this_plugin = plugin_basename(__FILE__);
391
 
392
  if ($file == $this_plugin) {
393
+ $settings_link = '<a href="admin.php?page=duplicator">' . esc_html__("Manage", 'duplicator') . '</a>';
394
  array_unshift($links, $settings_link);
395
  }
396
  return $links;
407
  $plugin = plugin_basename(__FILE__);
408
  // create link
409
  if ($file == $plugin) {
410
+ $links[] = '<a href="admin.php?page=duplicator-gopro" title="' . esc_attr__('Get Help', 'duplicator') . '" style="">' . esc_html__('Go Pro', 'duplicator') . '</a>';
411
  return $links;
412
  }
413
  return $links;
installer/build/assets/inc.css.php DELETED
@@ -1,246 +0,0 @@
1
- <style>
2
- body {font-family:Verdana,Arial,sans-serif; font-size:13px;}
3
- fieldset {border:1px solid silver; border-radius:5px; padding:10px}
4
- h3 {margin:1px; padding:1px; font-size:13px;}
5
- a {color:#222}
6
- a:hover{color:gray}
7
- input[type=text], input[type=password], select {width:97%; border-radius:2px; border:1px solid silver; padding:4px; font-family:Verdana,Arial,sans-serif;}
8
- select {padding-left:0; width:99%}
9
- select:disabled {background:#EBEBE4}
10
- input.readonly {background-color:#efefef;}
11
-
12
- /* ============================
13
- COMMON VIEWS
14
- ============================ */
15
- div#content {border:1px solid #CDCDCD; width:750px; min-height:550px; margin:auto; margin-top:18px; border-radius:5px; box-shadow:0 8px 6px -6px #333; font-size:13px}
16
- div#content-inner {padding:10px 25px; min-height:550px}
17
- form.content-form {min-height:550px; position:relative; line-height:17px}
18
- div.status-badge-pass {border-radius:4px; color:#fff; padding:0 4px 0 4px; font-size:12px; min-width:30px; text-align:center; background-color:#418446;display:inline-block }
19
- div.status-badge-fail {border-radius:4px; color:#fff; padding:0 4px 0 4px; font-size:12px; min-width:30px; text-align:center; background-color:maroon; display:inline-block}
20
-
21
- /* WIZARD STEPS */
22
- table.dupx-header {border-top-left-radius:5px; border-top-right-radius:5px; width:100%; box-shadow:0 5px 3px -3px #999; background-color:#F1F1F1; font-weight:bold;}
23
- .dupx-header-version {white-space:nowrap; color:#777; font-size:11px; font-style:italic; text-align:right; padding:0 15px 5px 0; line-height:14px; font-weight:normal;}
24
- .dupx-header-version a {color:#555;}
25
- div.dupx-logfile-link {float:right; font-weight:normal; font-size:11px; font-style:italic}
26
- div#progress-area {padding:5px; margin:150px 0 0 0px; text-align:center;}
27
- div#ajaxerr-data {padding:5px; height:350px; width:99%; border:1px solid silver; border-radius:5px; background-color:#efefef; font-size:13px; overflow-y:scroll; line-height:24px}
28
-
29
- /*TITLE HEADERS */
30
- div.hdr-main {font-size:22px; padding:0 0 5px 0; border-bottom:1px solid #D3D3D3; font-weight:bold; margin:15px 0 20px 0;}
31
- div.hdr-main span.step {color:#DB4B38}
32
- div.hdr-sub1 {font-size:18px; margin-bottom:5px;border:1px solid #D3D3D3;padding:7px; background-color:#f9f9f9; font-weight:bold; border-radius:4px}
33
- div.hdr-sub1 a {cursor:pointer; text-decoration: none !important}
34
- div.hdr-sub1:hover {cursor:pointer; background-color:#f1f1f1; border:1px solid #dcdcdc; }
35
- div.hdr-sub1:hover a{color:#000}
36
- div.hdr-sub2 {font-size:15px; padding:2px 2px 2px 0; border-bottom:1px solid #D3D3D3; font-weight:bold; margin-bottom:5px; border:none}
37
- div.hdr-sub3 {font-size:15px; padding:2px 2px 2px 0; border-bottom:1px solid #D3D3D3; font-weight:bold; margin-bottom:5px;}
38
- div.hdr-sub4 {font-size:15px; padding:7px; border:1px solid #D3D3D3;; font-weight:bold; background-color:#e9e9e9;}
39
- div.hdr-sub4:hover {background-color:#dfdfdf; cursor:pointer}
40
-
41
- /* BUTTONS */
42
- div.dupx-footer-buttons {position:absolute; bottom:10px; padding:10px; right:0}
43
- div.dupx-footer-buttons input:hover, button:hover {border:1px solid #000}
44
- div.dupx-footer-buttons input[disabled=disabled]{background-color:#F4F4F4; color:silver; border:1px solid silver;}
45
- div.dupx-footer-buttons button[disabled]{background-color:#F4F4F4; color:silver; border:1px solid silver;}
46
- button.default-btn, input.default-btn {
47
- cursor:pointer; color:#fff; font-size:16px; border-radius:5px; padding:8px 25px 6px 25px;
48
- background-color:#13659C; border:1px solid gray;
49
- }
50
- table.dupx-opts {width:100%; border:0px;}
51
- table.dupx-opts td{white-space:nowrap; padding:3px;}
52
- table.dupx-opts td:first-child{width:125px; font-weight: bold}
53
- table.dupx-advopts td:first-child{width:125px; font-weight:bold}
54
- table.dupx-advopts td label{min-width:60px; display:inline-block; cursor:pointer}
55
-
56
- .dupx-pass {display:inline-block; color:green;}
57
- .dupx-fail {display:inline-block; color:#AF0000;}
58
- .dupx-notice {display:inline-block; color:#000;}
59
- div.dupx-ui-error {padding-top:2px; font-size:13px; line-height: 20px}
60
-
61
- /*Dialog Info */
62
- div.dlg-serv-info {line-height:22px; font-size:12px; margin:0}
63
- div.dlg-serv-info div.info-txt {text-align: center; font-size:11px; font-style:italic}
64
- div.dlg-serv-info label {display:inline-block; width:175px; font-weight: bold}
65
- div.dlg-serv-info div.hdr {background-color: #dfdfdf; font-weight: bold; margin-top:5px; border-radius: 4px; padding:2px 5px 2px 5px; border: 1px solid silver; font-size: 16px}
66
- div#modal-window div.modal-title {background-color:#D0D0D0}
67
- div#modal-window div.modal-text {padding-top:10px !important}
68
- div.installer-mode {font-weight:normal; position:absolute; top:5px; right:20px; font-style:italic; font-size:11px}
69
- i.secure-unlocked {color:maroon;}
70
-
71
-
72
- /* ============================
73
- INIT 1:SECURE PASSWORD
74
- ============================ */
75
- button.pass-toggle {height:26px; width:26px; position:absolute; top:0px; right:0px; border:1px solid silver; border-radius:0 4px 4px 0;}
76
- button.pass-toggle i { padding:0; display:block; margin:-4px 0 0 -5px}
77
- div.i1-pass-area {width:100%; text-align:center}
78
- div.i1-pass-data {padding:30px; margin:auto; text-align:center; width:300px}
79
- div.i1-pass-data table {width:100%; border-collapse:collapse; padding:0}
80
- div.i1-pass-data label {font-weight:bold}
81
- div.i1-pass-errmsg {color:maroon; font-weight:bold}
82
- div#i1-pass-input {position:relative; margin:2px 0 15px 0}
83
- input#secure-pass {border-radius:4px 0 0 4px; width:250px}
84
- div.error-pane {border:1px solid #efefef; border-left:4px solid #D54E21; padding:0 0 0 10px; margin:2px 0 10px 0}
85
- div.dupx-ui-error {padding-top:2px; font-size:13px; line-height: 20px}
86
- label.secure-lock {cursor:pointer}
87
-
88
- /* ======================================
89
- STEP 1 VIEW
90
- ====================================== */
91
- table.s1-archive-local {width:100%}
92
- table.s1-archive-local tr {vertical-align:top}
93
- table.s1-archive-local td {padding:4px 4px 4px 4px}
94
- table.s1-archive-local td:first-child {font-weight:bold; width:55px}
95
- div#s1-area-sys-setup {padding:5px 0 0 10px}
96
- div#s1-area-sys-setup div.info-top {text-align:center; font-style:italic; font-size:11px; padding:0 5px 5px 5px}
97
- table.s1-checks-area {width:100%; margin:0; padding:0}
98
- table.s1-checks-area td.title {font-size:16px; width:100%}
99
- table.s1-checks-area td.title small {font-size:11px; font-weight:normal}
100
- table.s1-checks-area td.toggle {font-size:11px; margin-right:7px; font-weight:normal}
101
-
102
- div.s1-reqs {background-color:#efefef; border:1px solid silver; border-radius:5px; margin-top:-5px}
103
- div.s1-reqs div.header {background-color:#E0E0E0; color:#000; border-bottom: 1px solid silver; padding:2px; font-weight:bold }
104
- div.s1-reqs div.notice {background-color:#E0E0E0; color:#000; text-align:center; font-size:12px; border-bottom: 1px solid silver; padding:2px; font-style:italic}
105
- div.s1-reqs div.status {float:right; border-radius:4px; color:#fff; padding:0 4px 0 4px; margin:4px 5px 0 0; font-size:12px; min-width:30px; text-align:center; font-weight:bold}
106
- div.s1-reqs div.pass {background-color:green;}
107
- div.s1-reqs div.fail {background-color:maroon;}
108
- div.s1-reqs div.title {padding:4px; font-size:13px;}
109
- div.s1-reqs div.title:hover {background-color:#dfdfdf; cursor:pointer}
110
- div.s1-reqs div.info {padding:8px 8px 20px 8px; background-color:#fff; display:none; line-height:18px; font-size: 12px}
111
- div.s1-reqs div.info a {color:#485AA3;}
112
- div.s1-archive-failed-msg {padding:15px; border:1px dashed maroon; font-size: 12px; border-radius:5px;}
113
- div.s1-err-msg {padding:8px; border:1px dashed #999; margin:20px 0 20px 0px; border-radius:5px; color:maroon}
114
-
115
- /*Terms and Notices*/
116
- div#s1-warning-check label{cursor:pointer;}
117
- div#s1-warning-msg {padding:5px;font-size:12px; color:#333; line-height:14px;font-style:italic; overflow-y:scroll; height:250px; border:1px solid #dfdfdf; background:#fff; border-radius:3px}
118
- div#s1-warning-check {padding:3px; font-size:14px; font-weight:normal;}
119
- input#accept-warnings {height: 17px; width:17px}
120
-
121
- /* ======================================
122
- STEP 2 VIEW
123
- ====================================== */
124
- /*Toggle Buttons */
125
- div.s2-btngrp {text-align:center; margin:0 auto 10px auto}
126
- div.s2-btngrp input[type=button] {font-size:14px; padding:6px; width:120px; border:1px solid silver; cursor:pointer}
127
- div.s2-btngrp input[type=button]:first-child {border-radius:5px 0 0 5px; margin-right:-2px}
128
- div.s2-btngrp input[type=button]:last-child {border-radius:0 5px 5px 0; margin-left:-4px}
129
- div.s2-btngrp input[type=button].active {background-color:#13659C; color:#fff;}
130
- div.s2-btngrp input[type=button].in-active {background-color:#E4E4E4; }
131
- div.s2-btngrp input[type=button]:hover {border:1px solid #999}
132
-
133
- div.s2-modes {padding:0px 15px 0 0px;}
134
- div#s2-dbconn {margin:auto; text-align:center; margin:15px 0 10px 0px}
135
- input.s2-small-btn {height:25px; border:1px solid gray; border-radius:3px; cursor:pointer}
136
- table.s2-opts-dbhost td {padding:0; margin:0}
137
- input#s2-dbport-btn { width:80px}
138
- div.s2-db-test small{display:block; font-style:italic; color:#333; padding:3px 2px 5px 2px; border-bottom:1px dashed silver; margin-bottom:10px; text-align: center }
139
- table.s2-db-test-dtls {text-align: left; margin: auto}
140
- table.s2-db-test-dtls td:first-child {font-weight: bold}
141
- div#s2-dbconn-test-msg {font-size:12px}
142
- div#s2-dbconn-status {border:1px solid silver; border-radius:3px; background-color:#f9f9f9; padding:2px 5px; margin-top:10px; height:200px; overflow-y: scroll}
143
- div#s2-dbconn-status div.warn-msg {text-align: left; padding:5px; margin:10px 0 10px 0}
144
- div#s2-dbconn-status div.warn-msg b{color:maroon}
145
-
146
- /*cPanel Tab */
147
- div#s2-cpnl-pane {display: none; min-height: 190px;}
148
- div.s2-gopro {color: black; margin-top:10px; padding:0 20px 10px 20px; border: 1px solid silver; background-color:#F6F6F6; border-radius: 4px}
149
- div.s2-gopro h2 {text-align: center; margin:10px}
150
- div.s2-gopro small {font-style: italic}
151
- div.s2-cpanel-login {padding:15px; color:#fff; text-align:center; margin:15px 5px 15px 5px; border:1px solid silver; border-radius:5px; background-color:#13659C; font-size:14px; line-height:22px}
152
- div.s2-cpanel-off {padding:15px; color:#fff; text-align:center; margin:15px 5px 15px 5px; border:1px solid silver; border-radius:5px; background-color:#b54949; font-size:14px; line-height:22px}
153
-
154
- /*Advanced Options & Warning Area*/
155
- div#s2-area-adv-opts label {cursor: pointer}
156
- div#s2-warning {padding:5px;font-size:12px; color:gray; line-height:12px;font-style:italic; overflow-y:scroll; height:150px; border:1px solid #dfdfdf; background-color:#fff; border-radius:3px}
157
- div#s2-warning-check {padding:5px; font-size:12px; font-weight:normal; font-style:italic;}
158
- div#s2-warning-check label {cursor: pointer; line-height: 14px}
159
- div#s2-warning-emptydb {display:none; color:#AF2222; margin:2px 0 0 0; font-size: 11px}
160
- table.s2-advopts label.radio {width:50px; display:inline-block}
161
-
162
- /* ======================================
163
- STEP 3 VIEW
164
- ====================================== */
165
- table.s3-table-inputs {width:100%; border:0px;}
166
- table.s3-table-inputs td{white-space:nowrap; padding:2px;}
167
- table.s3-table-inputs td:first-child{font-weight: bold; width:125px}
168
- div#s3-adv-opts {margin-top:5px; }
169
- div.s3-allnonelinks {font-size:11px; float:right;}
170
- select#plugins {width:330px; height:100px}
171
- select#tables {width:330px; height:100px}
172
-
173
- /* password indicator */
174
- .top_testresult{font-weight:bold; font-size:11px; color:#222; padding:1px 1px 1px 4px; margin:4px 0 0 0px; width:495px; dislay:inline-block}
175
- .top_testresult span{margin:0;}
176
- .top_shortPass{background:#edabab; border:1px solid #bc0000;display:block;}
177
- .top_badPass{background:#edabab;border:1px solid #bc0000;display:block;}
178
- .top_goodPass{background:#ffffe0; border:1px solid #e6db55; display:block;}
179
- .top_strongPass{background:#d3edab; border:1px solid #73bc00; display:block;}
180
-
181
- /* ======================================
182
- STEP 4 VIEW
183
- ====================================== */
184
- div.s4-final-title {color:#BE2323;font-size:18px}
185
- div.s4-connect {font-size:12px; text-align:center; font-style:italic; position:absolute; bottom:10px; padding:10px; width:100%; margin-top:20px}
186
- table.s4-report-results,
187
- table.s4-report-errs {border-collapse:collapse; border:1px solid #dfdfdf; }
188
- table.s4-report-errs td {text-align:center; width:33%}
189
- table.s4-report-results th, table.s4-report-errs th {background-color:#efefef; padding:0px; font-size:13px; padding:0px}
190
- table.s4-report-results td, table.s4-report-errs td {padding:0px; white-space:nowrap; border:1px solid #dfdfdf; text-align:center; font-size:12px}
191
- table.s4-report-results td:first-child {text-align:left; font-weight:bold; padding-left:3px}
192
- div.s4-err-title {background-color:#dfdfdf; font-weight: bold; margin:-3px 0 15px 0; padding:5px; border-radius:3px; font-size:13px}
193
-
194
- div.s4-err-msg {padding:8px; display:none; border:1px dashed #999; margin:10px 0 20px 0px; border-radius:5px;}
195
- div.s4-err-msg div.content{padding:5px; font-size:11px; line-height:17px; max-height:125px; overflow-y:scroll; border:1px solid silver; margin:3px; }
196
- div.s4-err-msg div.info-error{padding:7px; background-color:#f9c9c9; border:1px solid silver; border-radius:2px; font-size:12px; line-height:16px }
197
- div.s4-err-msg div.info-notice{padding:7px; background-color:#FCFEC5; border:1px solid silver; border-radius:2px; font-size:12px; line-height:16px;}
198
- table.s4-final-step {width:100%;}
199
- table.s4-final-step td {padding:5px 15px 5px 5px}
200
- table.s4-final-step td:first-child {white-space:nowrap;}
201
- div.s4-go-back {border-top:1px dotted #dfdfdf; margin:auto; font-style:italic; font-size:11px; color:#333; padding-top:4px}
202
- div.s4-go-back ul {line-height:18px}
203
- button.s4-final-btns {cursor:pointer; color:#fff; font-size:16px; border-radius:5px; padding:7px; background-color:#13659C; border:1px solid gray; width:165px;}
204
- button.s4-final-btns:hover {background-color: #dfdfdf;}
205
- div.s4-gopro-btn {text-align:center; font-size:14px; margin:auto; width:200px; font-style: italic; font-weight:bold}
206
- div.s4-gopro-btn a{color:green}
207
-
208
-
209
- /* PARSLEY:Overrides*/
210
- input.parsley-error, textarea.parsley-error, select.parsley-error {
211
- color:#B94A48 !important; background-color:#F2DEDE !important; border:1px solid #EED3D7 !important;
212
- }
213
- ul.parsley-errors-list {margin:1px 0 0 -40px; list-style-type:none; font-size:10px}
214
-
215
- /* ============================
216
- STEP 5 HELP
217
- ============================ */
218
- div.help-target {float:right; font-size:11px}
219
- div#main-help a.help-target {display:block; margin:5px}
220
- div#main-help sup {font-size:11px; font-weight:normal; font-style:italic; color:blue}
221
- div.help-online {text-align:center; font-size:18px; padding:10px 0 0 0; line-height:24px}
222
- div.help {color:#555; font-style:italic; font-size:11px; padding:4px; border-top:1px solid #dfdfdf}
223
- div.help-page {padding:5px 0 0 5px}
224
- div.help-page fieldset {margin-bottom:25px}
225
- div#main-help {font-size:13px; line-height:17px}
226
- div#main-help h2 {background-color:#F1F1F1; border:1px solid silver; border-radius:4px; padding:10px; margin:26px 0 8px 0; font-size:22px; }
227
- div#main-help h3 {border-bottom:1px solid silver; padding:8px; margin:4px 0 8px 0; font-size:20px}
228
- div#main-help span.step {color:#DB4B38}
229
- table.help-opt {width: 100%; border: none; border-collapse: collapse; margin:5px 0 0 0;}
230
- table.help-opt td.section {background-color:#dfdfdf;}
231
- table.help-opt td, th {padding:7px; border:1px solid silver;}
232
- table.help-opt td:first-child {font-weight:bold; padding-right:10px; white-space:nowrap}
233
- table.help-opt th {background: #333; color: #fff;border:1px solid #333; padding:3px}
234
-
235
-
236
- <?php if ($GLOBALS['DUPX_DEBUG']) : ?>
237
- .dupx-debug {display:block; margin:4px 0 30px 0; font-size:11px;}
238
- .dupx-debug label {font-weight:bold; display:block; margin:6px 0 2px 0}
239
- .dupx-debug textarea {width:95%; height:100px; font-size:11px}
240
- <?php else : ?>
241
- .dupx-debug {display:none}
242
- <?php endif; ?>
243
- small.s3-warn {color: maroon;font-style: italic;}
244
- div.s4-warn {color: maroon;}
245
-
246
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/assets/inc.js.php DELETED
@@ -1,78 +0,0 @@
1
- <?php defined("DUPXABSPATH") or die(""); ?>
2
- <script>
3
- //Unique namespace
4
- DUPX = new Object();
5
-
6
- DUPX.showProgressBar = function ()
7
- {
8
- DUPX.animateProgressBar('progress-bar');
9
- $('#ajaxerr-area').hide();
10
- $('#progress-area').show();
11
- }
12
-
13
- DUPX.hideProgressBar = function ()
14
- {
15
- $('#progress-area').hide(100);
16
- $('#ajaxerr-area').fadeIn(400);
17
- }
18
-
19
- DUPX.animateProgressBar = function(id)
20
- {
21
- //Create Progress Bar
22
- var $mainbar = $("#" + id);
23
- $mainbar.progressbar({ value: 100 });
24
- $mainbar.height(25);
25
- runAnimation($mainbar);
26
-
27
- function runAnimation($pb) {
28
- $pb.css({ "padding-left": "0%", "padding-right": "90%" });
29
- $pb.progressbar("option", "value", 100);
30
- $pb.animate({ paddingLeft: "90%", paddingRight: "0%" }, 3500, "linear", function () { runAnimation($pb); });
31
- }
32
- }
33
-
34
- DUPX.toggleAll = function(id)
35
- {
36
- $(id + " *[data-type='toggle']").each(function() {
37
- $(this).trigger('click');
38
- });
39
- }
40
-
41
-
42
- DUPX.toggleClick = function()
43
- {
44
- var id = $(this).attr('data-target');
45
- var text = $(this).text().replace(/\+|\-/, "");
46
- var icon = $(this).find('i.dupx-plus-square, i.dupx-minus-square');
47
- var target = $(id);
48
- $(icon).removeClass('dupx-plus-square dupx-minus-square');
49
-
50
- if (target.is(':hidden') ) {
51
- (icon.length)
52
- ? $(icon).addClass('dupx-minus-square')
53
- : $(this).html("- " + text );
54
- target.show();
55
- } else {
56
- (icon.length)
57
- ? $(icon).addClass('dupx-plus-square')
58
- : $(this).html("+ " + text );
59
- target.hide();
60
- }
61
- }
62
-
63
- $(document).ready(function()
64
- {
65
- <?php if ($GLOBALS['DUPX_DEBUG']) : ?>
66
- $("div.dupx-debug input[type=hidden], div.dupx-debug textarea").each(function() {
67
- var label = '<label>' + $(this).attr('name') + ':</label>';
68
- $(this).before(label);
69
- $(this).after('<br/>');
70
- });
71
- $("div.dupx-debug input[type=hidden]").each(function() {
72
- $(this).attr('type', 'text');
73
- });
74
-
75
- $("div.dupx-debug").prepend('<h2>Debug View</h2>');
76
- <?php endif; ?>
77
- });
78
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/assets/inc.libs.css.php DELETED
@@ -1,48 +0,0 @@
1
- <?php defined("DUPXABSPATH") or die(""); ?>
2
- <?php
3
- // Exit if accessed directly
4
- if (! defined('DUPLICATOR_INIT')) {
5
- $_baseURL = "http://" . strlen($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'];
6
- header("HTTP/1.1 301 Moved Permanently");
7
- header("Location: $_baseURL");
8
- exit;
9
- }
10
- ?>
11
- <?php if( DUPX_U::isURLActive("ajax.googleapis.com", 443) ): ?>
12
- <link rel='stylesheet' href='//ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css' type='text/css' media='all' />
13
- <?php else: ?>
14
- <style type="text/css">
15
- /*! jQuery UI - v1.11.2 - 2014-12-20
16
- * http://jqueryui.com
17
- * Includes: core.css, progressbar.css, theme.css
18
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
19
- * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
20
-
21
- .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,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");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url("images/ui-bg_flat_75_ffffff_40x100.png") 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_888888_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_454545_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_454545_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_2e83ff_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cd0a0a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px}
22
- </style>
23
- <?php endif; ?>
24
-
25
-
26
- <style type="text/css">
27
- /*! * CSS Modal
28
- * Copyright (c) 2015 CreativeDream
29
- * Website https://github.com/CreativeDream/jquery.modal
30
- * Version: 1.2.3 (10-04-2015)
31
- */
32
- #modal-window{background-color:rgba(0,0,0,.35)}#modal-window>*{margin:0;padding:0;border:0;font:inherit;line-height:normal;vertical-align:baseline}#modal-window .modal-box{position:absolute;margin-bottom:10px;top:40%!important;background-color:#fff;font-family:sans-serif;color:#444;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;-webkit-box-shadow:0 0 7px rgba(0,0,0,.3);-moz-box-shadow:0 0 7px rgba(0,0,0,.3);box-shadow:0 0 7px rgba(0,0,0,.3);outline:0;overflow:hidden}#modal-window .modal-box.modal-size-normal{width:560px}#modal-window .modal-box.modal-size-small{width:350px}#modal-window .modal-box.modal-size-large{width:1000px}@media only screen and (max-width :580px){#modal-window .modal-box.modal-size-normal{width:96%;left:0!important;margin-left:2%!important;margin-right:2%}}@media only screen and (max-width :1020px){#modal-window .modal-box.modal-size-large{width:96%;left:0!important;margin-left:2%!important;margin-right:2%}}@media only screen and (max-width :370px){#modal-window .modal-box.modal-size-small{width:96%;left:0!important;margin-left:2%!important;margin-right:2%}}#modal-window .modal-box .modal-title{position:relative;padding:12px 15px;border-bottom:1px solid #e5e5e5;font-size:20px;overflow:hidden}#modal-window .modal-box .modal-title h3{font-size:20px;font-weight:400;line-height:normal;display:inline-block;margin:0;padding:0}#modal-window .modal-box .modal-title .modal-close-btn{position:absolute;display:block;width:14px;height:14px;right:20px;top:50%;margin-top:-7px;cursor:pointer;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpGNzdGMTE3NDA3MjA2ODExOEMxNDkyODc0N0NBMUEwNCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo3N0ZBOTUxNzNERkIxMUUyQUZGMEFDRjY0RjNFODlDOCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo3N0ZBOTUxNjNERkIxMUUyQUZGMEFDRjY0RjNFODlDOCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkY3N0YxMTc0MDcyMDY4MTE4MDgzRkQyMTE2MTM0QUNBIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkY3N0YxMTc0MDcyMDY4MTE4QzE0OTI4NzQ3Q0ExQTA0Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+5Ke+4QAAAMlJREFUeNqkk90KwyAMha0dvp/ghfthsFcb67YLYe83EBdZlCxL3KCFU0nM+WqjTqUUs+bZ1Nd2d6jDDDqDHqCk1AeQBx1B+Xa9vAFovmNBwFwSzAvIoWKFWJxciNGxmJtp3FeQMDkziCEfcCTObYUUEPE3JAg3xwawZKJBMsm5kZkDNIhqlgC0+J/cFyAIDTOD3fkABKXbeQSxP8xRaWyHNIAfdFvbHU8BJ9JdqdscktDTD9ITtCcnTLpMDRLwMlWPmdZe55cAAwD+1kOdnSr5eQAAAABJRU5ErkJggg==) center no-repeat;background-size:14px,14px;opacity:.5;filter:alpha(opacity=50)}#modal-window .modal-box .modal-title .modal-close-btn:hover{opacity:1;filter:alpha(opacity=100)}#modal-window .modal-box .modal-text{font-size:14px;padding:18px 15px;overflow-y:auto}#modal-window .modal-box img{height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#modal-window .modal-box .modal-text input.modal-prompt-input{width:97%;width:-webkit-calc(100% - 14px);width:-moz-calc(100% - 14px);width:calc(100% - 14px);display:block;outline:0;border:1px solid #ddd;border-top:1px solid #ccc;margin:10px 0;padding:6px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 0 2px #eee;-moz-box-shadow:inset 0 0 2px #eee;box-shadow:inset 0 0 2px #eee;-webkit-transition:all .1s linear;transition:all .1s linear}#modal-window .modal-box .modal-text input.modal-prompt-input:hover{border:1px solid #bbb;border-top:1px solid #aaa}#modal-window .modal-box .modal-text input.modal-prompt-input:active,#modal-window .modal-box .modal-text input.modal-prompt-input:focus{border-color:rgba(82,168,236,.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.3);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.3);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.3)}#modal-window .modal-box .modal-buttons{padding:10px 15px;text-align:right;background-color:#f9f9f9;border-top:1px solid #ddd}#modal-window .modal-box .modal-buttons a.modal-btn{display:inline-block;padding:8px 12px;outline:0;border:1px solid transparent;cursor:pointer;text-decoration:none;text-align:center;white-space:nowrap;font-size:12px;font-weight:700;line-height:normal;color:#555;vertical-align:middle}#modal-window .modal-box .modal-buttons a.modal-btn:active,a.modal-btn:focus{outline:0!important}#modal-window .modal-box .modal-buttons a.modal-btn:active,a.modal-btn.active{-webkit-box-shadow:inset 0 0 7px rgba(0,0,0,.2);-moz-box-shadow:inset 0 0 7px rgba(0,0,0,.2);box-shadow:inset 0 0 7px rgba(0,0,0,.2)}#modal-window .modal-box .modal-buttons a.modal-btn+a.modal-btn{margin-left:5px}#modal-window .modal-box .modal-buttons a.modal-btn.btn-disabled{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65)}#modal-window .modal-box .modal-buttons a.modal-btn.btn-large{padding:8px 14px;font-size:16px}#modal-window .modal-box .modal-buttons a.modal-btn.btn-small{padding:6px 8px;font-size:10px}#modal-window .modal-box .modal-buttons a.modal-btn.btn-rounded{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}#modal-window .modal-box .modal-buttons a.modal-btn.btn-circle{-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}#modal-window .modal-box .modal-buttons a.modal-btn.btn-square{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}#modal-window .modal-box .modal-buttons a.modal-btn i,#modal-window .modal-box .modal-buttons a.modal-btn img{vertical-align:middle;display:inline-block;float:left;max-height:16px;margin-right:5px}#modal-window .modal-box .modal-buttons a.modal-btn{background-color:#fcfcfc;border-color:#c9c9c9;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.08);-moz-box-shadow:0 1px 1px rgba(0,0,0,.08);box-shadow:0 1px 1px rgba(0,0,0,.08)}#modal-window .modal-box .modal-buttons a.modal-btn.btn-green{background-color:#5cb85c;border-color:#4cae4c;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-green:hover{background-color:#449d44;border-color:#398439;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-purple{background-color:#8149B4;border-color:#6922AD;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-purple:hover{background-color:#6f32a8;border-color:#5b149e;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-orange{background-color:#f7aa47;border-color:#eea236;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-orange:hover{background-color:#f69f2f;border-color:#d58512;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-pink{background-color:#ff6264;border-color:#eb5b5c;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-pink:hover{background-color:#ff484b;border-color:#e53a3d;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-turquoise{background-color:#00b19d;border-color:#11a594;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-turquoise:hover{background-color:#009886;border-color:#0b8173;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-light-green{background-color:#8dc63f;border-color:#7db432;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-light-green:hover{background-color:#82b838;border-color:#75a336;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-light-blue{background-color:#428bca;border-color:#357ebd;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-light-blue:hover{background-color:#3071a9;border-color:#285e8e;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-blue{background-color:#0e62c7;border-color:#0D54AA;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-blue:hover{background-color:#0c56af;border-color:#0B4992;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-red{background-color:#cc3f44;border-color:#bd1b21;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-red:hover{background-color:#ab2d32;border-color:#96050b;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-light-red{background-color:#d9534f;border-color:#d43f3a;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-light-red:hover{background-color:#c9302c;border-color:#ac2925;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-yellow{background-color:#ffba00;border-color:#e4a703;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-yellow:hover{background-color:#f0bb2e;border-color:#dba71a;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-black{background-color:#444;border-color:#313131;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-black:hover{background-color:#333;border-color:#222;color:#fff}#modal-window .modal-box .modal-buttons a.modal-btn.btn-white{background-color:#fff;color:#555;border:1px solid #ddd}#modal-window .modal-box .modal-buttons a.modal-btn.btn-white:hover{background-color:#f7f7f7;border:1px solid #ccc}#modal-window .modal-box .modal-buttons a.modal-btn.btn-white:active,#modal-window .modal-box .modal-buttons a.modal-btn.btn-white:focus{-webkit-box-shadow:inset 0 0 10px rgba(0,0,0,.1);-moz-box-shadow:inset 0 0 10px rgba(0,0,0,.1);box-shadow:inset 0 0 10px rgba(0,0,0,.1)}#modal-window .modal-box.modal-type-success .modal-title{background-color:#61b832}#modal-window .modal-box.modal-type-warning .modal-title{background-color:#f1b40e}#modal-window .modal-box.modal-type-error .modal-title{background-color:#de4343}#modal-window .modal-box.modal-type-info .modal-title{background-color:#4ea5cd}#modal-window .modal-box.modal-type-inverted .modal-title{background-color:#232B31}#modal-window .modal-box.modal-type-primary .modal-title{background-color:#428bca}#modal-window .modal-box.modal-type-error .modal-title,#modal-window .modal-box.modal-type-info .modal-title,#modal-window .modal-box.modal-type-inverted .modal-title,#modal-window .modal-box.modal-type-primary .modal-title,#modal-window .modal-box.modal-type-success .modal-title,#modal-window .modal-box.modal-type-warning .modal-title{color:#FFF;text-shadow:0 1px 3px rgba(0,0,0,.25);border-bottom-color:transparent}#modal-window .modal-box.modal-type-error .modal-title .modal-close-btn,#modal-window .modal-box.modal-type-info .modal-title .modal-close-btn,#modal-window .modal-box.modal-type-inverted .modal-title .modal-close-btn,#modal-window .modal-box.modal-type-primary .modal-title .modal-close-btn,#modal-window .modal-box.modal-type-success .modal-title .modal-close-btn,#modal-window .modal-box.modal-type-warning .modal-title .modal-close-btn{background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBoj k8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAKNJREFUeNqkk9EKwyAMRdMKfqG/WBD2hYWMs4epZBLjoBcEibnHNokHIE90mn0SkUtESpBfWk4aEUCABLz46gZKi9tV2hktNwEDUPnVDLHmrmoBBdAFxDNrv2D+RA+yNM+AFWRp9gARRL3inot2vf+MSdQqT3f0C6tqawTZmcumxQNwbQrmQS4LyGaUNRhlNaOc5xrkNp6e2UJqNwNyPH3OnwEACDCs273A8sIAAAAASUVORK5CYII=') center no-repeat}#modal-window .modal-box.modal-theme-reseted{background:0 0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}#modal-window .modal-box.modal-theme-reseted .modal-title{border-bottom:0;padding:0}#modal-window .modal-box.modal-theme-reseted .modal-title .modal-close-btn{right:0}#modal-window .modal-box.modal-theme-reseted .modal-text{padding:0}#modal-window .modal-box.modal-theme-reseted .modal-buttons{border-top:0;background:0 0;padding:0}
33
-
34
- /*CSS ICONS
35
- http://androidcss.com/css-shape-icon-generator/
36
- */
37
-
38
- .dupx-plus-square{display:inline-block!important;position:relative;width:14px;height:14px;border-radius:25%;background-color:#000000;box-sizing:content-box}
39
- .dupx-plus-square:before{position:absolute;content:'';margin:auto;width:calc(14px/8);height:calc(14px/1.5);background-color:#fff;top:0;bottom:0;left:0;right:0}
40
- .dupx-plus-square:after{position:absolute;content:'';margin:auto;width:calc(14px/1.5);height:calc(14px/8);background-color:#fff;top:0;bottom:0;left:0;right:0}
41
-
42
- .dupx-minus-square{display:inline-block!important;position:relative;width:14px;height:14px;border-radius:25%;background-color:#000000;box-sizing:content-box}
43
- .dupx-minus-square:after{position:absolute;content:'';margin:auto;width:calc(14px/1.5);height:calc(14px/10);background-color:#fff;top:0;bottom:0;left:0;right:0}
44
-
45
-
46
- </style>
47
-
48
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/assets/inc.libs.js.php DELETED
@@ -1,191 +0,0 @@
1
- <?php defined("DUPXABSPATH") or die(""); ?>
2
- <?php
3
- // Exit if accessed directly
4
- if (! defined('DUPLICATOR_INIT')) {
5
- $_baseURL = "http://" . strlen($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'];
6
- header("HTTP/1.1 301 Moved Permanently");
7
- header("Location: $_baseURL");
8
- exit;
9
- }
10
- ?>
11
- <!-- ========================================
12
- JQUERY ASSETS -->
13
- <?php if(DUPX_U::isURLActive("ajax.googleapis.com", 443) ): ?>
14
- <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
15
- <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
16
- <?php else: ?>
17
- <script type="text/javascript">
18
- /*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
19
- !function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=mb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=nb(b);function qb(){}qb.prototype=d.filters=d.pseudos,d.setFilters=new qb,g=gb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?gb.error(a):z(a,i).slice(0)};function rb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)
20
- },removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),f.removeChild(c),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:"0",fontWeight:"400"},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?zb.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=yb(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(n.cssHooks[a+b].set=Gb)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}n.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Kb.prototype.init,n.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=n.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||tb(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?tb(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ub(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return n.map(k,Ub,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xb,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xb(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),n.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Lb=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Lb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Mb||(Mb=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Mb),Mb=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Yb,Zb,$b=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))
21
- },removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=n.now(),dc=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var ec=/#.*$/,fc=/([?&])_=[^&]*/,gc=/^(.*?):[ \t]*([^\r\n]*)$/gm,hc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ic=/^(?:GET|HEAD)$/,jc=/^\/\//,kc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lc={},mc={},nc="*/".concat("*"),oc=a.location.href,pc=kc.exec(oc.toLowerCase())||[];function qc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rc(a,b,c,d){var e={},f=a===mc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function uc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:oc,type:"GET",isLocal:hc.test(pc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sc(sc(a,n.ajaxSettings),b):sc(n.ajaxSettings,a)},ajaxPrefilter:qc(lc),ajaxTransport:qc(mc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gc.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||oc)+"").replace(ec,"").replace(jc,pc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pc[1]&&h[2]===pc[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pc[3]||("http:"===pc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rc(lc,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ic.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fc.test(d)?d.replace(fc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rc(mc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tc(k,v,f)),u=uc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vc=/%20/g,wc=/\[\]$/,xc=/\r?\n/g,yc=/^(?:submit|button|image|reset|file)$/i,zc=/^(?:input|select|textarea|keygen)/i;function Ac(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wc.test(a)?d(a,e):Ac(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ac(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ac(c,a[c],b,e);return d.join("&").replace(vc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zc.test(this.nodeName)&&!yc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xc,"\r\n")}}):{name:b.name,value:c.replace(xc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bc=0,Cc={},Dc={0:200,1223:204},Ec=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cc)Cc[a]()}),k.cors=!!Ec&&"withCredentials"in Ec,k.ajax=Ec=!!Ec,n.ajaxTransport(function(a){var b;return k.cors||Ec&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Dc[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cc[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Fc=[],Gc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Fc.pop()||n.expando+"_"+cc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Gc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Gc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Gc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Fc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Hc=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Hc)return Hc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Ic=a.document.documentElement;function Jc(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Jc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Ic;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ic})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Jc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=yb(k.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Kc=a.jQuery,Lc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Lc),b&&a.jQuery===n&&(a.jQuery=Kc),n},typeof b===U&&(a.jQuery=a.$=n),n});
22
- </script>
23
- <script type="text/javascript">
24
- /*! jQuery UI - v1.11.2 - 2014-12-20
25
- * http://jqueryui.com
26
- * Includes: core.js, widget.js, progressbar.js
27
- * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
28
- (function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}e.ui=e.ui||{},e.extend(e.ui,{version:"1.11.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(t){var i=this.css("position"),s="absolute"===i,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var t=e(this);return s&&"static"===t.css("position")?!1:n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==i&&a.length?a:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),n=isNaN(s);return(n||s>=0)&&t(i,!n)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(a,s(this,t)+"px")})},e.fn["outer"+i]=function(t,n){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(a,s(this,t,!0,n)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,n=e(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var n,a=e.ui[t].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(e,t,i,s){var n,a=e.plugins[t];if(a&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)e.options[a[n][0]]&&a[n][1].apply(e.element,i)}};var s=0,n=Array.prototype.slice;e.cleanData=function(t){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=e._data(n,"events"),s&&s.remove&&e(n).triggerHandler("remove")}catch(o){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var n,a,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],n=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[l]=e[l]||{},a=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,a,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},n=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,a=this._superApply;return this._super=e,this._superApply=n,t=s.apply(this,arguments),this._super=i,this._superApply=a,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:n}),a?(e.each(a._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,a=n.call(arguments,1),o=0,r=a.length;r>o;o++)for(i in a[o])s=a[o][i],a[o].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(a){var o="string"==typeof a,r=n.call(arguments,1),h=this;return a=!o&&r.length?e.widget.extend.apply(null,[a].concat(r)):a,o?this.each(function(){var i,n=e.data(this,s);return"instance"===a?(h=n,!1):n?e.isFunction(n[a])&&"_"!==a.charAt(0)?(i=n[a].apply(n,r),i!==n&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+a+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+a+"'")}):this.each(function(){var t=e.data(this,s);t?(t.option(a||{}),t._init&&t._init()):e.data(this,s,new i(a,this))}),h}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=s++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,n,a,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(n=o[t]=e.widget.extend({},this.options[t]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(t=s.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var n,a=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=n=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),e.each(s,function(s,o){function r(){return t||a.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(t,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(i).undelegate(i),this.bindings=e(this.bindings.not(t).get()),this.focusable=e(this.focusable.not(t).get()),this.hoverable=e(this.hoverable.not(t).get())},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),o=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&e.effects&&e.effects.effect[r]?s[t](n):r!==t&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}}),e.widget,e.widget("ui.progressbar",{version:"1.11.2",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=e("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(e){return void 0===e?this.options.value:(this.options.value=this._constrainedValue(e),this._refreshValue(),void 0)},_constrainedValue:function(e){return void 0===e&&(e=this.options.value),this.indeterminate=e===!1,"number"!=typeof e&&(e=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,e))},_setOptions:function(e){var t=e.value;delete e.value,this._super(e),this.options.value=this._constrainedValue(t),this._refreshValue()},_setOption:function(e,t){"max"===e&&(t=Math.max(this.min,t)),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var t=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||t>this.min).toggleClass("ui-corner-right",t===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=e("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":t}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==t&&(this.oldValue=t,this._trigger("change")),t===this.options.max&&this._trigger("complete")}})});
29
- </script>
30
- <?php endif; ?>
31
-
32
- <!-- ========================================
33
- KNOCKOUT ASSETS -->
34
- <?php if( DUPX_U::isURLActive("ajax.aspnetcdn.com", 443) ): ?>
35
- <script src="//ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
36
- <?php else: ?>
37
- <script type="text/javascript">
38
- // Knockout JavaScript library v2.2.1
39
- // (c) Steven Sanderson - http://knockoutjs.com/
40
- // License: MIT (http://www.opensource.org/licenses/mit-license.php)
41
-
42
- (function() {function j(w){throw w;}var m=!0,p=null,r=!1;function u(w){return function(){return w}};var x=window,y=document,ga=navigator,F=window.jQuery,I=void 0;
43
- function L(w){function ha(a,d,c,e,f){var g=[];a=b.j(function(){var a=d(c,f)||[];0<g.length&&(b.a.Ya(M(g),a),e&&b.r.K(e,p,[c,a,f]));g.splice(0,g.length);b.a.P(g,a)},p,{W:a,Ka:function(){return 0==g.length||!b.a.X(g[0])}});return{M:g,j:a.pa()?a:I}}function M(a){for(;a.length&&!b.a.X(a[0]);)a.splice(0,1);if(1<a.length){for(var d=a[0],c=a[a.length-1],e=[d];d!==c;){d=d.nextSibling;if(!d)return;e.push(d)}Array.prototype.splice.apply(a,[0,a.length].concat(e))}return a}function S(a,b,c,e,f){var g=Math.min,
44
- h=Math.max,k=[],l,n=a.length,q,s=b.length,v=s-n||1,G=n+s+1,J,A,z;for(l=0;l<=n;l++){A=J;k.push(J=[]);z=g(s,l+v);for(q=h(0,l-1);q<=z;q++)J[q]=q?l?a[l-1]===b[q-1]?A[q-1]:g(A[q]||G,J[q-1]||G)+1:q+1:l+1}g=[];h=[];v=[];l=n;for(q=s;l||q;)s=k[l][q]-1,q&&s===k[l][q-1]?h.push(g[g.length]={status:c,value:b[--q],index:q}):l&&s===k[l-1][q]?v.push(g[g.length]={status:e,value:a[--l],index:l}):(g.push({status:"retained",value:b[--q]}),--l);if(h.length&&v.length){a=10*n;var t;for(b=c=0;(f||b<a)&&(t=h[c]);c++){for(e=
45
- 0;k=v[e];e++)if(t.value===k.value){t.moved=k.index;k.moved=t.index;v.splice(e,1);b=e=0;break}b+=e}}return g.reverse()}function T(a,d,c,e,f){f=f||{};var g=a&&N(a),g=g&&g.ownerDocument,h=f.templateEngine||O;b.za.vb(c,h,g);c=h.renderTemplate(c,e,f,g);("number"!=typeof c.length||0<c.length&&"number"!=typeof c[0].nodeType)&&j(Error("Template engine must return an array of DOM nodes"));g=r;switch(d){case "replaceChildren":b.e.N(a,c);g=m;break;case "replaceNode":b.a.Ya(a,c);g=m;break;case "ignoreTargetNode":break;
46
- default:j(Error("Unknown renderMode: "+d))}g&&(U(c,e),f.afterRender&&b.r.K(f.afterRender,p,[c,e.$data]));return c}function N(a){return a.nodeType?a:0<a.length?a[0]:p}function U(a,d){if(a.length){var c=a[0],e=a[a.length-1];V(c,e,function(a){b.Da(d,a)});V(c,e,function(a){b.s.ib(a,[d])})}}function V(a,d,c){var e;for(d=b.e.nextSibling(d);a&&(e=a)!==d;)a=b.e.nextSibling(e),(1===e.nodeType||8===e.nodeType)&&c(e)}function W(a,d,c){a=b.g.aa(a);for(var e=b.g.Q,f=0;f<a.length;f++){var g=a[f].key;if(e.hasOwnProperty(g)){var h=
47
- e[g];"function"===typeof h?(g=h(a[f].value))&&j(Error(g)):h||j(Error("This template engine does not support the '"+g+"' binding within its templates"))}}a="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+b.g.ba(a)+" } })()})";return c.createJavaScriptEvaluatorBlock(a)+d}function X(a,d,c,e){function f(a){return function(){return k[a]}}function g(){return k}var h=0,k,l;b.j(function(){var n=c&&c instanceof b.z?c:new b.z(b.a.d(c)),q=n.$data;e&&b.eb(a,n);if(k=("function"==typeof d?
48
- d(n,a):d)||b.J.instance.getBindings(a,n)){if(0===h){h=1;for(var s in k){var v=b.c[s];v&&8===a.nodeType&&!b.e.I[s]&&j(Error("The binding '"+s+"' cannot be used with virtual elements"));if(v&&"function"==typeof v.init&&(v=(0,v.init)(a,f(s),g,q,n))&&v.controlsDescendantBindings)l!==I&&j(Error("Multiple bindings ("+l+" and "+s+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.")),l=s}h=2}if(2===h)for(s in k)(v=b.c[s])&&"function"==
49
- typeof v.update&&(0,v.update)(a,f(s),g,q,n)}},p,{W:a});return{Nb:l===I}}function Y(a,d,c){var e=m,f=1===d.nodeType;f&&b.e.Ta(d);if(f&&c||b.J.instance.nodeHasBindings(d))e=X(d,p,a,c).Nb;e&&Z(a,d,!f)}function Z(a,d,c){for(var e=b.e.firstChild(d);d=e;)e=b.e.nextSibling(d),Y(a,d,c)}function $(a,b){var c=aa(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:p}function aa(a,b){for(var c=a,e=1,f=[];c=c.nextSibling;){if(H(c)&&(e--,0===e))return f;f.push(c);B(c)&&e++}b||j(Error("Cannot find closing comment tag to match: "+
50
- a.nodeValue));return p}function H(a){return 8==a.nodeType&&(K?a.text:a.nodeValue).match(ia)}function B(a){return 8==a.nodeType&&(K?a.text:a.nodeValue).match(ja)}function P(a,b){for(var c=p;a!=c;)c=a,a=a.replace(ka,function(a,c){return b[c]});return a}function la(){var a=[],d=[];this.save=function(c,e){var f=b.a.i(a,c);0<=f?d[f]=e:(a.push(c),d.push(e))};this.get=function(c){c=b.a.i(a,c);return 0<=c?d[c]:I}}function ba(a,b,c){function e(e){var g=b(a[e]);switch(typeof g){case "boolean":case "number":case "string":case "function":f[e]=
51
- g;break;case "object":case "undefined":var h=c.get(g);f[e]=h!==I?h:ba(g,b,c)}}c=c||new la;a=b(a);if(!("object"==typeof a&&a!==p&&a!==I&&!(a instanceof Date)))return a;var f=a instanceof Array?[]:{};c.save(a,f);var g=a;if(g instanceof Array){for(var h=0;h<g.length;h++)e(h);"function"==typeof g.toJSON&&e("toJSON")}else for(h in g)e(h);return f}function ca(a,d){if(a)if(8==a.nodeType){var c=b.s.Ua(a.nodeValue);c!=p&&d.push({sb:a,Fb:c})}else if(1==a.nodeType)for(var c=0,e=a.childNodes,f=e.length;c<f;c++)ca(e[c],
52
- d)}function Q(a,d,c,e){b.c[a]={init:function(a){b.a.f.set(a,da,{});return{controlsDescendantBindings:m}},update:function(a,g,h,k,l){h=b.a.f.get(a,da);g=b.a.d(g());k=!c!==!g;var n=!h.Za;if(n||d||k!==h.qb)n&&(h.Za=b.a.Ia(b.e.childNodes(a),m)),k?(n||b.e.N(a,b.a.Ia(h.Za)),b.Ea(e?e(l,g):l,a)):b.e.Y(a),h.qb=k}};b.g.Q[a]=r;b.e.I[a]=m}function ea(a,d,c){c&&d!==b.k.q(a)&&b.k.T(a,d);d!==b.k.q(a)&&b.r.K(b.a.Ba,p,[a,"change"])}var b="undefined"!==typeof w?w:{};b.b=function(a,d){for(var c=a.split("."),e=b,f=0;f<
53
- c.length-1;f++)e=e[c[f]];e[c[c.length-1]]=d};b.p=function(a,b,c){a[b]=c};b.version="2.2.1";b.b("version",b.version);b.a=new function(){function a(a,d){if("input"!==b.a.u(a)||!a.type||"click"!=d.toLowerCase())return r;var c=a.type;return"checkbox"==c||"radio"==c}var d=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,c={},e={};c[/Firefox\/2/i.test(ga.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];c.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");
54
- for(var f in c){var g=c[f];if(g.length)for(var h=0,k=g.length;h<k;h++)e[g[h]]=f}var l={propertychange:m},n,c=3;f=y.createElement("div");for(g=f.getElementsByTagName("i");f.innerHTML="\x3c!--[if gt IE "+ ++c+"]><i></i><![endif]--\x3e",g[0];);n=4<c?c:I;return{Na:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],o:function(a,b){for(var d=0,c=a.length;d<c;d++)b(a[d])},i:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var d=0,c=a.length;d<
55
- c;d++)if(a[d]===b)return d;return-1},lb:function(a,b,d){for(var c=0,e=a.length;c<e;c++)if(b.call(d,a[c]))return a[c];return p},ga:function(a,d){var c=b.a.i(a,d);0<=c&&a.splice(c,1)},Ga:function(a){a=a||[];for(var d=[],c=0,e=a.length;c<e;c++)0>b.a.i(d,a[c])&&d.push(a[c]);return d},V:function(a,b){a=a||[];for(var d=[],c=0,e=a.length;c<e;c++)d.push(b(a[c]));return d},fa:function(a,b){a=a||[];for(var d=[],c=0,e=a.length;c<e;c++)b(a[c])&&d.push(a[c]);return d},P:function(a,b){if(b instanceof Array)a.push.apply(a,
56
- b);else for(var d=0,c=b.length;d<c;d++)a.push(b[d]);return a},extend:function(a,b){if(b)for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);return a},ka:function(a){for(;a.firstChild;)b.removeNode(a.firstChild)},Hb:function(a){a=b.a.L(a);for(var d=y.createElement("div"),c=0,e=a.length;c<e;c++)d.appendChild(b.A(a[c]));return d},Ia:function(a,d){for(var c=0,e=a.length,g=[];c<e;c++){var f=a[c].cloneNode(m);g.push(d?b.A(f):f)}return g},N:function(a,d){b.a.ka(a);if(d)for(var c=0,e=d.length;c<e;c++)a.appendChild(d[c])},
57
- Ya:function(a,d){var c=a.nodeType?[a]:a;if(0<c.length){for(var e=c[0],g=e.parentNode,f=0,h=d.length;f<h;f++)g.insertBefore(d[f],e);f=0;for(h=c.length;f<h;f++)b.removeNode(c[f])}},bb:function(a,b){7>n?a.setAttribute("selected",b):a.selected=b},D:function(a){return(a||"").replace(d,"")},Rb:function(a,d){for(var c=[],e=(a||"").split(d),f=0,g=e.length;f<g;f++){var h=b.a.D(e[f]);""!==h&&c.push(h)}return c},Ob:function(a,b){a=a||"";return b.length>a.length?r:a.substring(0,b.length)===b},tb:function(a,b){if(b.compareDocumentPosition)return 16==
58
- (b.compareDocumentPosition(a)&16);for(;a!=p;){if(a==b)return m;a=a.parentNode}return r},X:function(a){return b.a.tb(a,a.ownerDocument)},u:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},n:function(b,d,c){var e=n&&l[d];if(!e&&"undefined"!=typeof F){if(a(b,d)){var f=c;c=function(a,b){var d=this.checked;b&&(this.checked=b.nb!==m);f.call(this,a);this.checked=d}}F(b).bind(d,c)}else!e&&"function"==typeof b.addEventListener?b.addEventListener(d,c,r):"undefined"!=typeof b.attachEvent?b.attachEvent("on"+
59
- d,function(a){c.call(b,a)}):j(Error("Browser doesn't support addEventListener or attachEvent"))},Ba:function(b,d){(!b||!b.nodeType)&&j(Error("element must be a DOM node when calling triggerEvent"));if("undefined"!=typeof F){var c=[];a(b,d)&&c.push({nb:b.checked});F(b).trigger(d,c)}else"function"==typeof y.createEvent?"function"==typeof b.dispatchEvent?(c=y.createEvent(e[d]||"HTMLEvents"),c.initEvent(d,m,m,x,0,0,0,0,0,r,r,r,r,0,b),b.dispatchEvent(c)):j(Error("The supplied element doesn't support dispatchEvent")):
60
- "undefined"!=typeof b.fireEvent?(a(b,d)&&(b.checked=b.checked!==m),b.fireEvent("on"+d)):j(Error("Browser doesn't support triggering events"))},d:function(a){return b.$(a)?a():a},ua:function(a){return b.$(a)?a.t():a},da:function(a,d,c){if(d){var e=/[\w-]+/g,f=a.className.match(e)||[];b.a.o(d.match(e),function(a){var d=b.a.i(f,a);0<=d?c||f.splice(d,1):c&&f.push(a)});a.className=f.join(" ")}},cb:function(a,d){var c=b.a.d(d);if(c===p||c===I)c="";if(3===a.nodeType)a.data=c;else{var e=b.e.firstChild(a);
61
- !e||3!=e.nodeType||b.e.nextSibling(e)?b.e.N(a,[y.createTextNode(c)]):e.data=c;b.a.wb(a)}},ab:function(a,b){a.name=b;if(7>=n)try{a.mergeAttributes(y.createElement("<input name='"+a.name+"'/>"),r)}catch(d){}},wb:function(a){9<=n&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},ub:function(a){if(9<=n){var b=a.style.width;a.style.width=0;a.style.width=b}},Lb:function(a,d){a=b.a.d(a);d=b.a.d(d);for(var c=[],e=a;e<=d;e++)c.push(e);return c},L:function(a){for(var b=[],d=0,c=a.length;d<
62
- c;d++)b.push(a[d]);return b},Pb:6===n,Qb:7===n,Z:n,Oa:function(a,d){for(var c=b.a.L(a.getElementsByTagName("input")).concat(b.a.L(a.getElementsByTagName("textarea"))),e="string"==typeof d?function(a){return a.name===d}:function(a){return d.test(a.name)},f=[],g=c.length-1;0<=g;g--)e(c[g])&&f.push(c[g]);return f},Ib:function(a){return"string"==typeof a&&(a=b.a.D(a))?x.JSON&&x.JSON.parse?x.JSON.parse(a):(new Function("return "+a))():p},xa:function(a,d,c){("undefined"==typeof JSON||"undefined"==typeof JSON.stringify)&&
63
- j(Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js"));return JSON.stringify(b.a.d(a),d,c)},Jb:function(a,d,c){c=c||{};var e=c.params||{},f=c.includeFields||this.Na,g=a;if("object"==typeof a&&"form"===b.a.u(a))for(var g=a.action,h=f.length-1;0<=h;h--)for(var k=b.a.Oa(a,f[h]),l=k.length-1;0<=l;l--)e[k[l].name]=k[l].value;d=b.a.d(d);var n=y.createElement("form");
64
- n.style.display="none";n.action=g;n.method="post";for(var w in d)a=y.createElement("input"),a.name=w,a.value=b.a.xa(b.a.d(d[w])),n.appendChild(a);for(w in e)a=y.createElement("input"),a.name=w,a.value=e[w],n.appendChild(a);y.body.appendChild(n);c.submitter?c.submitter(n):n.submit();setTimeout(function(){n.parentNode.removeChild(n)},0)}}};b.b("utils",b.a);b.b("utils.arrayForEach",b.a.o);b.b("utils.arrayFirst",b.a.lb);b.b("utils.arrayFilter",b.a.fa);b.b("utils.arrayGetDistinctValues",b.a.Ga);b.b("utils.arrayIndexOf",
65
- b.a.i);b.b("utils.arrayMap",b.a.V);b.b("utils.arrayPushAll",b.a.P);b.b("utils.arrayRemoveItem",b.a.ga);b.b("utils.extend",b.a.extend);b.b("utils.fieldsIncludedWithJsonPost",b.a.Na);b.b("utils.getFormFields",b.a.Oa);b.b("utils.peekObservable",b.a.ua);b.b("utils.postJson",b.a.Jb);b.b("utils.parseJson",b.a.Ib);b.b("utils.registerEventHandler",b.a.n);b.b("utils.stringifyJson",b.a.xa);b.b("utils.range",b.a.Lb);b.b("utils.toggleDomNodeCssClass",b.a.da);b.b("utils.triggerEvent",b.a.Ba);b.b("utils.unwrapObservable",
66
- b.a.d);Function.prototype.bind||(Function.prototype.bind=function(a){var b=this,c=Array.prototype.slice.call(arguments);a=c.shift();return function(){return b.apply(a,c.concat(Array.prototype.slice.call(arguments)))}});b.a.f=new function(){var a=0,d="__ko__"+(new Date).getTime(),c={};return{get:function(a,d){var c=b.a.f.la(a,r);return c===I?I:c[d]},set:function(a,d,c){c===I&&b.a.f.la(a,r)===I||(b.a.f.la(a,m)[d]=c)},la:function(b,f){var g=b[d];if(!g||!("null"!==g&&c[g])){if(!f)return I;g=b[d]="ko"+
67
- a++;c[g]={}}return c[g]},clear:function(a){var b=a[d];return b?(delete c[b],a[d]=p,m):r}}};b.b("utils.domData",b.a.f);b.b("utils.domData.clear",b.a.f.clear);b.a.F=new function(){function a(a,d){var e=b.a.f.get(a,c);e===I&&d&&(e=[],b.a.f.set(a,c,e));return e}function d(c){var e=a(c,r);if(e)for(var e=e.slice(0),k=0;k<e.length;k++)e[k](c);b.a.f.clear(c);"function"==typeof F&&"function"==typeof F.cleanData&&F.cleanData([c]);if(f[c.nodeType])for(e=c.firstChild;c=e;)e=c.nextSibling,8===c.nodeType&&d(c)}
68
- var c="__ko_domNodeDisposal__"+(new Date).getTime(),e={1:m,8:m,9:m},f={1:m,9:m};return{Ca:function(b,d){"function"!=typeof d&&j(Error("Callback must be a function"));a(b,m).push(d)},Xa:function(d,e){var f=a(d,r);f&&(b.a.ga(f,e),0==f.length&&b.a.f.set(d,c,I))},A:function(a){if(e[a.nodeType]&&(d(a),f[a.nodeType])){var c=[];b.a.P(c,a.getElementsByTagName("*"));for(var k=0,l=c.length;k<l;k++)d(c[k])}return a},removeNode:function(a){b.A(a);a.parentNode&&a.parentNode.removeChild(a)}}};b.A=b.a.F.A;b.removeNode=
69
- b.a.F.removeNode;b.b("cleanNode",b.A);b.b("removeNode",b.removeNode);b.b("utils.domNodeDisposal",b.a.F);b.b("utils.domNodeDisposal.addDisposeCallback",b.a.F.Ca);b.b("utils.domNodeDisposal.removeDisposeCallback",b.a.F.Xa);b.a.ta=function(a){var d;if("undefined"!=typeof F)if(F.parseHTML)d=F.parseHTML(a);else{if((d=F.clean([a]))&&d[0]){for(a=d[0];a.parentNode&&11!==a.parentNode.nodeType;)a=a.parentNode;a.parentNode&&a.parentNode.removeChild(a)}}else{var c=b.a.D(a).toLowerCase();d=y.createElement("div");
70
- c=c.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!c.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!c.indexOf("<td")||!c.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""];a="ignored<div>"+c[1]+a+c[2]+"</div>";for("function"==typeof x.innerShiv?d.appendChild(x.innerShiv(a)):d.innerHTML=a;c[0]--;)d=d.lastChild;d=b.a.L(d.lastChild.childNodes)}return d};b.a.ca=function(a,d){b.a.ka(a);d=b.a.d(d);if(d!==p&&d!==I)if("string"!=typeof d&&(d=d.toString()),
71
- "undefined"!=typeof F)F(a).html(d);else for(var c=b.a.ta(d),e=0;e<c.length;e++)a.appendChild(c[e])};b.b("utils.parseHtmlFragment",b.a.ta);b.b("utils.setHtml",b.a.ca);var R={};b.s={ra:function(a){"function"!=typeof a&&j(Error("You can only pass a function to ko.memoization.memoize()"));var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);R[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},hb:function(a,b){var c=R[a];c===I&&j(Error("Couldn't find any memo with ID "+
72
- a+". Perhaps it's already been unmemoized."));try{return c.apply(p,b||[]),m}finally{delete R[a]}},ib:function(a,d){var c=[];ca(a,c);for(var e=0,f=c.length;e<f;e++){var g=c[e].sb,h=[g];d&&b.a.P(h,d);b.s.hb(c[e].Fb,h);g.nodeValue="";g.parentNode&&g.parentNode.removeChild(g)}},Ua:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:p}};b.b("memoization",b.s);b.b("memoization.memoize",b.s.ra);b.b("memoization.unmemoize",b.s.hb);b.b("memoization.parseMemoText",b.s.Ua);b.b("memoization.unmemoizeDomNodeAndDescendants",
73
- b.s.ib);b.Ma={throttle:function(a,d){a.throttleEvaluation=d;var c=p;return b.j({read:a,write:function(b){clearTimeout(c);c=setTimeout(function(){a(b)},d)}})},notify:function(a,d){a.equalityComparer="always"==d?u(r):b.m.fn.equalityComparer;return a}};b.b("extenders",b.Ma);b.fb=function(a,d,c){this.target=a;this.ha=d;this.rb=c;b.p(this,"dispose",this.B)};b.fb.prototype.B=function(){this.Cb=m;this.rb()};b.S=function(){this.w={};b.a.extend(this,b.S.fn);b.p(this,"subscribe",this.ya);b.p(this,"extend",
74
- this.extend);b.p(this,"getSubscriptionsCount",this.yb)};b.S.fn={ya:function(a,d,c){c=c||"change";var e=new b.fb(this,d?a.bind(d):a,function(){b.a.ga(this.w[c],e)}.bind(this));this.w[c]||(this.w[c]=[]);this.w[c].push(e);return e},notifySubscribers:function(a,d){d=d||"change";this.w[d]&&b.r.K(function(){b.a.o(this.w[d].slice(0),function(b){b&&b.Cb!==m&&b.ha(a)})},this)},yb:function(){var a=0,b;for(b in this.w)this.w.hasOwnProperty(b)&&(a+=this.w[b].length);return a},extend:function(a){var d=this;if(a)for(var c in a){var e=
75
- b.Ma[c];"function"==typeof e&&(d=e(d,a[c]))}return d}};b.Qa=function(a){return"function"==typeof a.ya&&"function"==typeof a.notifySubscribers};b.b("subscribable",b.S);b.b("isSubscribable",b.Qa);var C=[];b.r={mb:function(a){C.push({ha:a,La:[]})},end:function(){C.pop()},Wa:function(a){b.Qa(a)||j(Error("Only subscribable things can act as dependencies"));if(0<C.length){var d=C[C.length-1];d&&!(0<=b.a.i(d.La,a))&&(d.La.push(a),d.ha(a))}},K:function(a,b,c){try{return C.push(p),a.apply(b,c||[])}finally{C.pop()}}};
76
- var ma={undefined:m,"boolean":m,number:m,string:m};b.m=function(a){function d(){if(0<arguments.length){if(!d.equalityComparer||!d.equalityComparer(c,arguments[0]))d.H(),c=arguments[0],d.G();return this}b.r.Wa(d);return c}var c=a;b.S.call(d);d.t=function(){return c};d.G=function(){d.notifySubscribers(c)};d.H=function(){d.notifySubscribers(c,"beforeChange")};b.a.extend(d,b.m.fn);b.p(d,"peek",d.t);b.p(d,"valueHasMutated",d.G);b.p(d,"valueWillMutate",d.H);return d};b.m.fn={equalityComparer:function(a,
77
- b){return a===p||typeof a in ma?a===b:r}};var E=b.m.Kb="__ko_proto__";b.m.fn[E]=b.m;b.ma=function(a,d){return a===p||a===I||a[E]===I?r:a[E]===d?m:b.ma(a[E],d)};b.$=function(a){return b.ma(a,b.m)};b.Ra=function(a){return"function"==typeof a&&a[E]===b.m||"function"==typeof a&&a[E]===b.j&&a.zb?m:r};b.b("observable",b.m);b.b("isObservable",b.$);b.b("isWriteableObservable",b.Ra);b.R=function(a){0==arguments.length&&(a=[]);a!==p&&(a!==I&&!("length"in a))&&j(Error("The argument passed when initializing an observable array must be an array, or null, or undefined."));
78
- var d=b.m(a);b.a.extend(d,b.R.fn);return d};b.R.fn={remove:function(a){for(var b=this.t(),c=[],e="function"==typeof a?a:function(b){return b===a},f=0;f<b.length;f++){var g=b[f];e(g)&&(0===c.length&&this.H(),c.push(g),b.splice(f,1),f--)}c.length&&this.G();return c},removeAll:function(a){if(a===I){var d=this.t(),c=d.slice(0);this.H();d.splice(0,d.length);this.G();return c}return!a?[]:this.remove(function(d){return 0<=b.a.i(a,d)})},destroy:function(a){var b=this.t(),c="function"==typeof a?a:function(b){return b===
79
- a};this.H();for(var e=b.length-1;0<=e;e--)c(b[e])&&(b[e]._destroy=m);this.G()},destroyAll:function(a){return a===I?this.destroy(u(m)):!a?[]:this.destroy(function(d){return 0<=b.a.i(a,d)})},indexOf:function(a){var d=this();return b.a.i(d,a)},replace:function(a,b){var c=this.indexOf(a);0<=c&&(this.H(),this.t()[c]=b,this.G())}};b.a.o("pop push reverse shift sort splice unshift".split(" "),function(a){b.R.fn[a]=function(){var b=this.t();this.H();b=b[a].apply(b,arguments);this.G();return b}});b.a.o(["slice"],
80
- function(a){b.R.fn[a]=function(){var b=this();return b[a].apply(b,arguments)}});b.b("observableArray",b.R);b.j=function(a,d,c){function e(){b.a.o(z,function(a){a.B()});z=[]}function f(){var a=h.throttleEvaluation;a&&0<=a?(clearTimeout(t),t=setTimeout(g,a)):g()}function g(){if(!q)if(n&&w())A();else{q=m;try{var a=b.a.V(z,function(a){return a.target});b.r.mb(function(c){var d;0<=(d=b.a.i(a,c))?a[d]=I:z.push(c.ya(f))});for(var c=s.call(d),e=a.length-1;0<=e;e--)a[e]&&z.splice(e,1)[0].B();n=m;h.notifySubscribers(l,
81
- "beforeChange");l=c}finally{b.r.end()}h.notifySubscribers(l);q=r;z.length||A()}}function h(){if(0<arguments.length)return"function"===typeof v?v.apply(d,arguments):j(Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.")),this;n||g();b.r.Wa(h);return l}function k(){return!n||0<z.length}var l,n=r,q=r,s=a;s&&"object"==typeof s?(c=s,s=c.read):(c=c||{},s||(s=c.read));"function"!=typeof s&&j(Error("Pass a function that returns the value of the ko.computed"));
82
- var v=c.write,G=c.disposeWhenNodeIsRemoved||c.W||p,w=c.disposeWhen||c.Ka||u(r),A=e,z=[],t=p;d||(d=c.owner);h.t=function(){n||g();return l};h.xb=function(){return z.length};h.zb="function"===typeof c.write;h.B=function(){A()};h.pa=k;b.S.call(h);b.a.extend(h,b.j.fn);b.p(h,"peek",h.t);b.p(h,"dispose",h.B);b.p(h,"isActive",h.pa);b.p(h,"getDependenciesCount",h.xb);c.deferEvaluation!==m&&g();if(G&&k()){A=function(){b.a.F.Xa(G,arguments.callee);e()};b.a.F.Ca(G,A);var D=w,w=function(){return!b.a.X(G)||D()}}return h};
83
- b.Bb=function(a){return b.ma(a,b.j)};w=b.m.Kb;b.j[w]=b.m;b.j.fn={};b.j.fn[w]=b.j;b.b("dependentObservable",b.j);b.b("computed",b.j);b.b("isComputed",b.Bb);b.gb=function(a){0==arguments.length&&j(Error("When calling ko.toJS, pass the object you want to convert."));return ba(a,function(a){for(var c=0;b.$(a)&&10>c;c++)a=a();return a})};b.toJSON=function(a,d,c){a=b.gb(a);return b.a.xa(a,d,c)};b.b("toJS",b.gb);b.b("toJSON",b.toJSON);b.k={q:function(a){switch(b.a.u(a)){case "option":return a.__ko__hasDomDataOptionValue__===
84
- m?b.a.f.get(a,b.c.options.sa):7>=b.a.Z?a.getAttributeNode("value").specified?a.value:a.text:a.value;case "select":return 0<=a.selectedIndex?b.k.q(a.options[a.selectedIndex]):I;default:return a.value}},T:function(a,d){switch(b.a.u(a)){case "option":switch(typeof d){case "string":b.a.f.set(a,b.c.options.sa,I);"__ko__hasDomDataOptionValue__"in a&&delete a.__ko__hasDomDataOptionValue__;a.value=d;break;default:b.a.f.set(a,b.c.options.sa,d),a.__ko__hasDomDataOptionValue__=m,a.value="number"===typeof d?
85
- d:""}break;case "select":for(var c=a.options.length-1;0<=c;c--)if(b.k.q(a.options[c])==d){a.selectedIndex=c;break}break;default:if(d===p||d===I)d="";a.value=d}}};b.b("selectExtensions",b.k);b.b("selectExtensions.readValue",b.k.q);b.b("selectExtensions.writeValue",b.k.T);var ka=/\@ko_token_(\d+)\@/g,na=["true","false"],oa=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;b.g={Q:[],aa:function(a){var d=b.a.D(a);if(3>d.length)return[];"{"===d.charAt(0)&&(d=d.substring(1,d.length-1));a=[];for(var c=
86
- p,e,f=0;f<d.length;f++){var g=d.charAt(f);if(c===p)switch(g){case '"':case "'":case "/":c=f,e=g}else if(g==e&&"\\"!==d.charAt(f-1)){g=d.substring(c,f+1);a.push(g);var h="@ko_token_"+(a.length-1)+"@",d=d.substring(0,c)+h+d.substring(f+1),f=f-(g.length-h.length),c=p}}e=c=p;for(var k=0,l=p,f=0;f<d.length;f++){g=d.charAt(f);if(c===p)switch(g){case "{":c=f;l=g;e="}";break;case "(":c=f;l=g;e=")";break;case "[":c=f,l=g,e="]"}g===l?k++:g===e&&(k--,0===k&&(g=d.substring(c,f+1),a.push(g),h="@ko_token_"+(a.length-
87
- 1)+"@",d=d.substring(0,c)+h+d.substring(f+1),f-=g.length-h.length,c=p))}e=[];d=d.split(",");c=0;for(f=d.length;c<f;c++)k=d[c],l=k.indexOf(":"),0<l&&l<k.length-1?(g=k.substring(l+1),e.push({key:P(k.substring(0,l),a),value:P(g,a)})):e.push({unknown:P(k,a)});return e},ba:function(a){var d="string"===typeof a?b.g.aa(a):a,c=[];a=[];for(var e,f=0;e=d[f];f++)if(0<c.length&&c.push(","),e.key){var g;a:{g=e.key;var h=b.a.D(g);switch(h.length&&h.charAt(0)){case "'":case '"':break a;default:g="'"+h+"'"}}e=e.value;
88
- c.push(g);c.push(":");c.push(e);e=b.a.D(e);0<=b.a.i(na,b.a.D(e).toLowerCase())?e=r:(h=e.match(oa),e=h===p?r:h[1]?"Object("+h[1]+")"+h[2]:e);e&&(0<a.length&&a.push(", "),a.push(g+" : function(__ko_value) { "+e+" = __ko_value; }"))}else e.unknown&&c.push(e.unknown);d=c.join("");0<a.length&&(d=d+", '_ko_property_writers' : { "+a.join("")+" } ");return d},Eb:function(a,d){for(var c=0;c<a.length;c++)if(b.a.D(a[c].key)==d)return m;return r},ea:function(a,d,c,e,f){if(!a||!b.Ra(a)){if((a=d()._ko_property_writers)&&
89
- a[c])a[c](e)}else(!f||a.t()!==e)&&a(e)}};b.b("expressionRewriting",b.g);b.b("expressionRewriting.bindingRewriteValidators",b.g.Q);b.b("expressionRewriting.parseObjectLiteral",b.g.aa);b.b("expressionRewriting.preProcessBindings",b.g.ba);b.b("jsonExpressionRewriting",b.g);b.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",b.g.ba);var K="\x3c!--test--\x3e"===y.createComment("test").text,ja=K?/^\x3c!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*--\x3e$/:/^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/,ia=K?/^\x3c!--\s*\/ko\s*--\x3e$/:
90
- /^\s*\/ko\s*$/,pa={ul:m,ol:m};b.e={I:{},childNodes:function(a){return B(a)?aa(a):a.childNodes},Y:function(a){if(B(a)){a=b.e.childNodes(a);for(var d=0,c=a.length;d<c;d++)b.removeNode(a[d])}else b.a.ka(a)},N:function(a,d){if(B(a)){b.e.Y(a);for(var c=a.nextSibling,e=0,f=d.length;e<f;e++)c.parentNode.insertBefore(d[e],c)}else b.a.N(a,d)},Va:function(a,b){B(a)?a.parentNode.insertBefore(b,a.nextSibling):a.firstChild?a.insertBefore(b,a.firstChild):a.appendChild(b)},Pa:function(a,d,c){c?B(a)?a.parentNode.insertBefore(d,
91
- c.nextSibling):c.nextSibling?a.insertBefore(d,c.nextSibling):a.appendChild(d):b.e.Va(a,d)},firstChild:function(a){return!B(a)?a.firstChild:!a.nextSibling||H(a.nextSibling)?p:a.nextSibling},nextSibling:function(a){B(a)&&(a=$(a));return a.nextSibling&&H(a.nextSibling)?p:a.nextSibling},jb:function(a){return(a=B(a))?a[1]:p},Ta:function(a){if(pa[b.a.u(a)]){var d=a.firstChild;if(d){do if(1===d.nodeType){var c;c=d.firstChild;var e=p;if(c){do if(e)e.push(c);else if(B(c)){var f=$(c,m);f?c=f:e=[c]}else H(c)&&
92
- (e=[c]);while(c=c.nextSibling)}if(c=e){e=d.nextSibling;for(f=0;f<c.length;f++)e?a.insertBefore(c[f],e):a.appendChild(c[f])}}while(d=d.nextSibling)}}}};b.b("virtualElements",b.e);b.b("virtualElements.allowedBindings",b.e.I);b.b("virtualElements.emptyNode",b.e.Y);b.b("virtualElements.insertAfter",b.e.Pa);b.b("virtualElements.prepend",b.e.Va);b.b("virtualElements.setDomNodeChildren",b.e.N);b.J=function(){this.Ha={}};b.a.extend(b.J.prototype,{nodeHasBindings:function(a){switch(a.nodeType){case 1:return a.getAttribute("data-bind")!=
93
- p;case 8:return b.e.jb(a)!=p;default:return r}},getBindings:function(a,b){var c=this.getBindingsString(a,b);return c?this.parseBindingsString(c,b,a):p},getBindingsString:function(a){switch(a.nodeType){case 1:return a.getAttribute("data-bind");case 8:return b.e.jb(a);default:return p}},parseBindingsString:function(a,d,c){try{var e;if(!(e=this.Ha[a])){var f=this.Ha,g,h="with($context){with($data||{}){return{"+b.g.ba(a)+"}}}";g=new Function("$context","$element",h);e=f[a]=g}return e(d,c)}catch(k){j(Error("Unable to parse bindings.\nMessage: "+
94
- k+";\nBindings value: "+a))}}});b.J.instance=new b.J;b.b("bindingProvider",b.J);b.c={};b.z=function(a,d,c){d?(b.a.extend(this,d),this.$parentContext=d,this.$parent=d.$data,this.$parents=(d.$parents||[]).slice(0),this.$parents.unshift(this.$parent)):(this.$parents=[],this.$root=a,this.ko=b);this.$data=a;c&&(this[c]=a)};b.z.prototype.createChildContext=function(a,d){return new b.z(a,this,d)};b.z.prototype.extend=function(a){var d=b.a.extend(new b.z,this);return b.a.extend(d,a)};b.eb=function(a,d){if(2==
95
- arguments.length)b.a.f.set(a,"__ko_bindingContext__",d);else return b.a.f.get(a,"__ko_bindingContext__")};b.Fa=function(a,d,c){1===a.nodeType&&b.e.Ta(a);return X(a,d,c,m)};b.Ea=function(a,b){(1===b.nodeType||8===b.nodeType)&&Z(a,b,m)};b.Da=function(a,b){b&&(1!==b.nodeType&&8!==b.nodeType)&&j(Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node"));b=b||x.document.body;Y(a,b,m)};b.ja=function(a){switch(a.nodeType){case 1:case 8:var d=b.eb(a);if(d)return d;
96
- if(a.parentNode)return b.ja(a.parentNode)}return I};b.pb=function(a){return(a=b.ja(a))?a.$data:I};b.b("bindingHandlers",b.c);b.b("applyBindings",b.Da);b.b("applyBindingsToDescendants",b.Ea);b.b("applyBindingsToNode",b.Fa);b.b("contextFor",b.ja);b.b("dataFor",b.pb);var fa={"class":"className","for":"htmlFor"};b.c.attr={update:function(a,d){var c=b.a.d(d())||{},e;for(e in c)if("string"==typeof e){var f=b.a.d(c[e]),g=f===r||f===p||f===I;g&&a.removeAttribute(e);8>=b.a.Z&&e in fa?(e=fa[e],g?a.removeAttribute(e):
97
- a[e]=f):g||a.setAttribute(e,f.toString());"name"===e&&b.a.ab(a,g?"":f.toString())}}};b.c.checked={init:function(a,d,c){b.a.n(a,"click",function(){var e;if("checkbox"==a.type)e=a.checked;else if("radio"==a.type&&a.checked)e=a.value;else return;var f=d(),g=b.a.d(f);"checkbox"==a.type&&g instanceof Array?(e=b.a.i(g,a.value),a.checked&&0>e?f.push(a.value):!a.checked&&0<=e&&f.splice(e,1)):b.g.ea(f,c,"checked",e,m)});"radio"==a.type&&!a.name&&b.c.uniqueName.init(a,u(m))},update:function(a,d){var c=b.a.d(d());
98
- "checkbox"==a.type?a.checked=c instanceof Array?0<=b.a.i(c,a.value):c:"radio"==a.type&&(a.checked=a.value==c)}};b.c.css={update:function(a,d){var c=b.a.d(d());if("object"==typeof c)for(var e in c){var f=b.a.d(c[e]);b.a.da(a,e,f)}else c=String(c||""),b.a.da(a,a.__ko__cssValue,r),a.__ko__cssValue=c,b.a.da(a,c,m)}};b.c.enable={update:function(a,d){var c=b.a.d(d());c&&a.disabled?a.removeAttribute("disabled"):!c&&!a.disabled&&(a.disabled=m)}};b.c.disable={update:function(a,d){b.c.enable.update(a,function(){return!b.a.d(d())})}};
99
- b.c.event={init:function(a,d,c,e){var f=d()||{},g;for(g in f)(function(){var f=g;"string"==typeof f&&b.a.n(a,f,function(a){var g,n=d()[f];if(n){var q=c();try{var s=b.a.L(arguments);s.unshift(e);g=n.apply(e,s)}finally{g!==m&&(a.preventDefault?a.preventDefault():a.returnValue=r)}q[f+"Bubble"]===r&&(a.cancelBubble=m,a.stopPropagation&&a.stopPropagation())}})})()}};b.c.foreach={Sa:function(a){return function(){var d=a(),c=b.a.ua(d);if(!c||"number"==typeof c.length)return{foreach:d,templateEngine:b.C.oa};
100
- b.a.d(d);return{foreach:c.data,as:c.as,includeDestroyed:c.includeDestroyed,afterAdd:c.afterAdd,beforeRemove:c.beforeRemove,afterRender:c.afterRender,beforeMove:c.beforeMove,afterMove:c.afterMove,templateEngine:b.C.oa}}},init:function(a,d){return b.c.template.init(a,b.c.foreach.Sa(d))},update:function(a,d,c,e,f){return b.c.template.update(a,b.c.foreach.Sa(d),c,e,f)}};b.g.Q.foreach=r;b.e.I.foreach=m;b.c.hasfocus={init:function(a,d,c){function e(e){a.__ko_hasfocusUpdating=m;var f=a.ownerDocument;"activeElement"in
101
- f&&(e=f.activeElement===a);f=d();b.g.ea(f,c,"hasfocus",e,m);a.__ko_hasfocusUpdating=r}var f=e.bind(p,m),g=e.bind(p,r);b.a.n(a,"focus",f);b.a.n(a,"focusin",f);b.a.n(a,"blur",g);b.a.n(a,"focusout",g)},update:function(a,d){var c=b.a.d(d());a.__ko_hasfocusUpdating||(c?a.focus():a.blur(),b.r.K(b.a.Ba,p,[a,c?"focusin":"focusout"]))}};b.c.html={init:function(){return{controlsDescendantBindings:m}},update:function(a,d){b.a.ca(a,d())}};var da="__ko_withIfBindingData";Q("if");Q("ifnot",r,m);Q("with",m,r,function(a,
102
- b){return a.createChildContext(b)});b.c.options={update:function(a,d,c){"select"!==b.a.u(a)&&j(Error("options binding applies only to SELECT elements"));for(var e=0==a.length,f=b.a.V(b.a.fa(a.childNodes,function(a){return a.tagName&&"option"===b.a.u(a)&&a.selected}),function(a){return b.k.q(a)||a.innerText||a.textContent}),g=a.scrollTop,h=b.a.d(d());0<a.length;)b.A(a.options[0]),a.remove(0);if(h){c=c();var k=c.optionsIncludeDestroyed;"number"!=typeof h.length&&(h=[h]);if(c.optionsCaption){var l=y.createElement("option");
103
- b.a.ca(l,c.optionsCaption);b.k.T(l,I);a.appendChild(l)}d=0;for(var n=h.length;d<n;d++){var q=h[d];if(!q||!q._destroy||k){var l=y.createElement("option"),s=function(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c},v=s(q,c.optionsValue,q);b.k.T(l,b.a.d(v));q=s(q,c.optionsText,v);b.a.cb(l,q);a.appendChild(l)}}h=a.getElementsByTagName("option");d=k=0;for(n=h.length;d<n;d++)0<=b.a.i(f,b.k.q(h[d]))&&(b.a.bb(h[d],m),k++);a.scrollTop=g;e&&"value"in c&&ea(a,b.a.ua(c.value),m);b.a.ub(a)}}};
104
- b.c.options.sa="__ko.optionValueDomData__";b.c.selectedOptions={init:function(a,d,c){b.a.n(a,"change",function(){var e=d(),f=[];b.a.o(a.getElementsByTagName("option"),function(a){a.selected&&f.push(b.k.q(a))});b.g.ea(e,c,"value",f)})},update:function(a,d){"select"!=b.a.u(a)&&j(Error("values binding applies only to SELECT elements"));var c=b.a.d(d());c&&"number"==typeof c.length&&b.a.o(a.getElementsByTagName("option"),function(a){var d=0<=b.a.i(c,b.k.q(a));b.a.bb(a,d)})}};b.c.style={update:function(a,
105
- d){var c=b.a.d(d()||{}),e;for(e in c)if("string"==typeof e){var f=b.a.d(c[e]);a.style[e]=f||""}}};b.c.submit={init:function(a,d,c,e){"function"!=typeof d()&&j(Error("The value for a submit binding must be a function"));b.a.n(a,"submit",function(b){var c,h=d();try{c=h.call(e,a)}finally{c!==m&&(b.preventDefault?b.preventDefault():b.returnValue=r)}})}};b.c.text={update:function(a,d){b.a.cb(a,d())}};b.e.I.text=m;b.c.uniqueName={init:function(a,d){if(d()){var c="ko_unique_"+ ++b.c.uniqueName.ob;b.a.ab(a,
106
- c)}}};b.c.uniqueName.ob=0;b.c.value={init:function(a,d,c){function e(){h=r;var e=d(),f=b.k.q(a);b.g.ea(e,c,"value",f)}var f=["change"],g=c().valueUpdate,h=r;g&&("string"==typeof g&&(g=[g]),b.a.P(f,g),f=b.a.Ga(f));if(b.a.Z&&("input"==a.tagName.toLowerCase()&&"text"==a.type&&"off"!=a.autocomplete&&(!a.form||"off"!=a.form.autocomplete))&&-1==b.a.i(f,"propertychange"))b.a.n(a,"propertychange",function(){h=m}),b.a.n(a,"blur",function(){h&&e()});b.a.o(f,function(c){var d=e;b.a.Ob(c,"after")&&(d=function(){setTimeout(e,
107
- 0)},c=c.substring(5));b.a.n(a,c,d)})},update:function(a,d){var c="select"===b.a.u(a),e=b.a.d(d()),f=b.k.q(a),g=e!=f;0===e&&(0!==f&&"0"!==f)&&(g=m);g&&(f=function(){b.k.T(a,e)},f(),c&&setTimeout(f,0));c&&0<a.length&&ea(a,e,r)}};b.c.visible={update:function(a,d){var c=b.a.d(d()),e="none"!=a.style.display;c&&!e?a.style.display="":!c&&e&&(a.style.display="none")}};b.c.click={init:function(a,d,c,e){return b.c.event.init.call(this,a,function(){var a={};a.click=d();return a},c,e)}};b.v=function(){};b.v.prototype.renderTemplateSource=
108
- function(){j(Error("Override renderTemplateSource"))};b.v.prototype.createJavaScriptEvaluatorBlock=function(){j(Error("Override createJavaScriptEvaluatorBlock"))};b.v.prototype.makeTemplateSource=function(a,d){if("string"==typeof a){d=d||y;var c=d.getElementById(a);c||j(Error("Cannot find template with ID "+a));return new b.l.h(c)}if(1==a.nodeType||8==a.nodeType)return new b.l.O(a);j(Error("Unknown template type: "+a))};b.v.prototype.renderTemplate=function(a,b,c,e){a=this.makeTemplateSource(a,e);
109
- return this.renderTemplateSource(a,b,c)};b.v.prototype.isTemplateRewritten=function(a,b){return this.allowTemplateRewriting===r?m:this.makeTemplateSource(a,b).data("isRewritten")};b.v.prototype.rewriteTemplate=function(a,b,c){a=this.makeTemplateSource(a,c);b=b(a.text());a.text(b);a.data("isRewritten",m)};b.b("templateEngine",b.v);var qa=/(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi,ra=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;b.za={vb:function(a,
110
- d,c){d.isTemplateRewritten(a,c)||d.rewriteTemplate(a,function(a){return b.za.Gb(a,d)},c)},Gb:function(a,b){return a.replace(qa,function(a,e,f,g,h,k,l){return W(l,e,b)}).replace(ra,function(a,e){return W(e,"\x3c!-- ko --\x3e",b)})},kb:function(a){return b.s.ra(function(d,c){d.nextSibling&&b.Fa(d.nextSibling,a,c)})}};b.b("__tr_ambtns",b.za.kb);b.l={};b.l.h=function(a){this.h=a};b.l.h.prototype.text=function(){var a=b.a.u(this.h),a="script"===a?"text":"textarea"===a?"value":"innerHTML";if(0==arguments.length)return this.h[a];
111
- var d=arguments[0];"innerHTML"===a?b.a.ca(this.h,d):this.h[a]=d};b.l.h.prototype.data=function(a){if(1===arguments.length)return b.a.f.get(this.h,"templateSourceData_"+a);b.a.f.set(this.h,"templateSourceData_"+a,arguments[1])};b.l.O=function(a){this.h=a};b.l.O.prototype=new b.l.h;b.l.O.prototype.text=function(){if(0==arguments.length){var a=b.a.f.get(this.h,"__ko_anon_template__")||{};a.Aa===I&&a.ia&&(a.Aa=a.ia.innerHTML);return a.Aa}b.a.f.set(this.h,"__ko_anon_template__",{Aa:arguments[0]})};b.l.h.prototype.nodes=
112
- function(){if(0==arguments.length)return(b.a.f.get(this.h,"__ko_anon_template__")||{}).ia;b.a.f.set(this.h,"__ko_anon_template__",{ia:arguments[0]})};b.b("templateSources",b.l);b.b("templateSources.domElement",b.l.h);b.b("templateSources.anonymousTemplate",b.l.O);var O;b.wa=function(a){a!=I&&!(a instanceof b.v)&&j(Error("templateEngine must inherit from ko.templateEngine"));O=a};b.va=function(a,d,c,e,f){c=c||{};(c.templateEngine||O)==I&&j(Error("Set a template engine before calling renderTemplate"));
113
- f=f||"replaceChildren";if(e){var g=N(e);return b.j(function(){var h=d&&d instanceof b.z?d:new b.z(b.a.d(d)),k="function"==typeof a?a(h.$data,h):a,h=T(e,f,k,h,c);"replaceNode"==f&&(e=h,g=N(e))},p,{Ka:function(){return!g||!b.a.X(g)},W:g&&"replaceNode"==f?g.parentNode:g})}return b.s.ra(function(e){b.va(a,d,c,e,"replaceNode")})};b.Mb=function(a,d,c,e,f){function g(a,b){U(b,k);c.afterRender&&c.afterRender(b,a)}function h(d,e){k=f.createChildContext(b.a.d(d),c.as);k.$index=e;var g="function"==typeof a?
114
- a(d,k):a;return T(p,"ignoreTargetNode",g,k,c)}var k;return b.j(function(){var a=b.a.d(d)||[];"undefined"==typeof a.length&&(a=[a]);a=b.a.fa(a,function(a){return c.includeDestroyed||a===I||a===p||!b.a.d(a._destroy)});b.r.K(b.a.$a,p,[e,a,h,c,g])},p,{W:e})};b.c.template={init:function(a,d){var c=b.a.d(d());if("string"!=typeof c&&!c.name&&(1==a.nodeType||8==a.nodeType))c=1==a.nodeType?a.childNodes:b.e.childNodes(a),c=b.a.Hb(c),(new b.l.O(a)).nodes(c);return{controlsDescendantBindings:m}},update:function(a,
115
- d,c,e,f){d=b.a.d(d());c={};e=m;var g,h=p;"string"!=typeof d&&(c=d,d=c.name,"if"in c&&(e=b.a.d(c["if"])),e&&"ifnot"in c&&(e=!b.a.d(c.ifnot)),g=b.a.d(c.data));"foreach"in c?h=b.Mb(d||a,e&&c.foreach||[],c,a,f):e?(f="data"in c?f.createChildContext(g,c.as):f,h=b.va(d||a,f,c,a)):b.e.Y(a);f=h;(g=b.a.f.get(a,"__ko__templateComputedDomDataKey__"))&&"function"==typeof g.B&&g.B();b.a.f.set(a,"__ko__templateComputedDomDataKey__",f&&f.pa()?f:I)}};b.g.Q.template=function(a){a=b.g.aa(a);return 1==a.length&&a[0].unknown||
116
- b.g.Eb(a,"name")?p:"This template engine does not support anonymous templates nested within its templates"};b.e.I.template=m;b.b("setTemplateEngine",b.wa);b.b("renderTemplate",b.va);b.a.Ja=function(a,b,c){a=a||[];b=b||[];return a.length<=b.length?S(a,b,"added","deleted",c):S(b,a,"deleted","added",c)};b.b("utils.compareArrays",b.a.Ja);b.a.$a=function(a,d,c,e,f){function g(a,b){t=l[b];w!==b&&(z[a]=t);t.na(w++);M(t.M);s.push(t);A.push(t)}function h(a,c){if(a)for(var d=0,e=c.length;d<e;d++)c[d]&&b.a.o(c[d].M,
117
- function(b){a(b,d,c[d].U)})}d=d||[];e=e||{};var k=b.a.f.get(a,"setDomNodeChildrenFromArrayMapping_lastMappingResult")===I,l=b.a.f.get(a,"setDomNodeChildrenFromArrayMapping_lastMappingResult")||[],n=b.a.V(l,function(a){return a.U}),q=b.a.Ja(n,d),s=[],v=0,w=0,B=[],A=[];d=[];for(var z=[],n=[],t,D=0,C,E;C=q[D];D++)switch(E=C.moved,C.status){case "deleted":E===I&&(t=l[v],t.j&&t.j.B(),B.push.apply(B,M(t.M)),e.beforeRemove&&(d[D]=t,A.push(t)));v++;break;case "retained":g(D,v++);break;case "added":E!==I?
118
- g(D,E):(t={U:C.value,na:b.m(w++)},s.push(t),A.push(t),k||(n[D]=t))}h(e.beforeMove,z);b.a.o(B,e.beforeRemove?b.A:b.removeNode);for(var D=0,k=b.e.firstChild(a),H;t=A[D];D++){t.M||b.a.extend(t,ha(a,c,t.U,f,t.na));for(v=0;q=t.M[v];k=q.nextSibling,H=q,v++)q!==k&&b.e.Pa(a,q,H);!t.Ab&&f&&(f(t.U,t.M,t.na),t.Ab=m)}h(e.beforeRemove,d);h(e.afterMove,z);h(e.afterAdd,n);b.a.f.set(a,"setDomNodeChildrenFromArrayMapping_lastMappingResult",s)};b.b("utils.setDomNodeChildrenFromArrayMapping",b.a.$a);b.C=function(){this.allowTemplateRewriting=
119
- r};b.C.prototype=new b.v;b.C.prototype.renderTemplateSource=function(a){var d=!(9>b.a.Z)&&a.nodes?a.nodes():p;if(d)return b.a.L(d.cloneNode(m).childNodes);a=a.text();return b.a.ta(a)};b.C.oa=new b.C;b.wa(b.C.oa);b.b("nativeTemplateEngine",b.C);b.qa=function(){var a=this.Db=function(){if("undefined"==typeof F||!F.tmpl)return 0;try{if(0<=F.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,c,e){e=e||{};2>a&&j(Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later."));
120
- var f=b.data("precompiled");f||(f=b.text()||"",f=F.template(p,"{{ko_with $item.koBindingContext}}"+f+"{{/ko_with}}"),b.data("precompiled",f));b=[c.$data];c=F.extend({koBindingContext:c},e.templateOptions);c=F.tmpl(f,b,c);c.appendTo(y.createElement("div"));F.fragments={};return c};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){y.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(F.tmpl.tag.ko_code=
121
- {open:"__.push($1 || '');"},F.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};b.qa.prototype=new b.v;w=new b.qa;0<w.Db&&b.wa(w);b.b("jqueryTmplTemplateEngine",b.qa)}"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?L(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],L):L(x.ko={});m;
122
- })();
123
- </script>
124
- <?php endif; ?>
125
-
126
- <script type="text/javascript">
127
- /* json2.js
128
- * See www.JSON.org/js.html*/
129
- if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}
130
- Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+
131
- f(this.getUTCMonth()+1)+'-'+
132
- f(this.getUTCDate())+'T'+
133
- f(this.getUTCHours())+':'+
134
- f(this.getUTCMinutes())+':'+
135
- f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;}
136
- c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+
137
- (c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
138
- if(typeof value.toJSON==='function'){return stringify(value.toJSON());}
139
- a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i<l;i+=1){a.push(stringify(value[i],whitelist)||'null');}
140
- return'['+a.join(',')+']';}
141
- if(whitelist){l=whitelist.length;for(i=0;i<l;i+=1){k=whitelist[i];if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}else{for(k in value){if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}
142
- return'{'+a.join(',')+'}';}}
143
- return{stringify:stringify,parse:function(text,filter){var j;function walk(k,v){var i,n;if(v&&typeof v==='object'){for(i in v){if(Object.prototype.hasOwnProperty.apply(v,[i])){n=walk(i,v[i]);if(n!==undefined){v[i]=n;}}}}
144
- return filter(k,v);}
145
- if(/^[\],:{}\s]*$/.test(text.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof filter==='function'?walk('',j):j;}
146
- throw new SyntaxError('parseJSON');}};}();}
147
- </script>
148
-
149
- <script type="text/javascript">
150
- /**
151
- * password_strength_plugin.js
152
- * Copyright (c) 20010 myPocket technologies (www.mypocket-technologies.com)
153
- * @author Darren Mason (djmason9@gmail.com)
154
- * @date 3/13/2009
155
- * @projectDescription Password Strength Meter is a jQuery plug-in provide you smart algorithm to detect a password strength.
156
- * Based on Firas Kassem orginal plugin - phiras.wordpress.com/2007/04/08/password-strength-meter-a-jquery-plugin/
157
- * @version 1.0.1 */
158
- (function(a){a.fn.shortPass="Too short";a.fn.badPass="Weak";a.fn.goodPass="Good";a.fn.strongPass="Strong";a.fn.samePassword="Username and Password identical.";a.fn.resultStyle="";a.fn.passStrength=function(b){var d={shortPass:"shortPass",badPass:"badPass",goodPass:"goodPass",strongPass:"strongPass",baseStyle:"testresult",userid:"",messageloc:1};
159
- var c=a.extend(d,b);return this.each(function(){var e=a(this);a(e).unbind().keyup(function(){var f=a.fn.teststrength(a(this).val(),a(c.userid).val(),c);if(c.messageloc===1){a(this).next("."+c.baseStyle).remove();a(this).after('<span class="'+c.baseStyle+'"><span></span></span>');a(this).next("."+c.baseStyle).addClass(a(this).resultStyle).find("span").text(f)
160
- }else{a(this).prev("."+c.baseStyle).remove();a(this).before('<span class="'+c.baseStyle+'"><span></span></span>');a(this).prev("."+c.baseStyle).addClass(a(this).resultStyle).find("span").text(f)}});a.fn.teststrength=function(f,i,g){var h=0;if(f.length<4){this.resultStyle=g.shortPass;return a(this).shortPass
161
- }if(f.toLowerCase()==i.toLowerCase()){this.resultStyle=g.badPass;return a(this).samePassword}h+=f.length*4;h+=(a.fn.checkRepetition(1,f).length-f.length)*1;h+=(a.fn.checkRepetition(2,f).length-f.length)*1;h+=(a.fn.checkRepetition(3,f).length-f.length)*1;h+=(a.fn.checkRepetition(4,f).length-f.length)*1;
162
- if(f.match(/(.*[0-9].*[0-9].*[0-9])/)){h+=5}if(f.match(/(.*[!,@,#,$,%,^,&,*,?,_,~].*[!,@,#,$,%,^,&,*,?,_,~])/)){h+=5}if(f.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)){h+=10}if(f.match(/([a-zA-Z])/)&&f.match(/([0-9])/)){h+=15}if(f.match(/([!,@,#,$,%,^,&,*,?,_,~])/)&&f.match(/([0-9])/)){h+=15}if(f.match(/([!,@,#,$,%,^,&,*,?,_,~])/)&&f.match(/([a-zA-Z])/)){h+=15
163
- }if(f.match(/^\w+$/)||f.match(/^\d+$/)){h-=10}if(h<0){h=0}if(h>100){h=100}if(h<34){this.resultStyle=g.badPass;return a(this).badPass}if(h<68){this.resultStyle=g.goodPass;return a(this).goodPass}this.resultStyle=g.strongPass;return a(this).strongPass}})}})(jQuery);$.fn.checkRepetition=function(a,f){var d="";
164
- for(var c=0;c<f.length;c++){var e=true;for(var b=0;b<a&&(b+c+a)<f.length;b++){e=e&&(f.charAt(b+c)==f.charAt(b+c+a))}if(b<a){e=false}if(e){c+=a-1;e=false}else{d+=f.charAt(c)}}return d};
165
- </script>
166
-
167
-
168
- <script type="text/javascript">
169
- /*!
170
- * Parsley.js
171
- * Version 2.3.5 - built Sun, Feb 28th 2016, 6:25 am
172
- * http://parsleyjs.org
173
- * Guillaume Potier - <guillaume@wisembly.com>
174
- * Marc-Andre Lafortune - <petroselinum@marc-andre.ca>
175
- * MIT Licensed
176
- */
177
- function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,i=Array(e.length);t<e.length;t++)i[t]=e[t];return i}return Array.from(e)}var _slice=Array.prototype.slice;!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):e.parsley=t(e.jQuery)}(this,function(e){"use strict";function t(e,t){return e.parsleyAdaptedCallback||(e.parsleyAdaptedCallback=function(){var i=Array.prototype.slice.call(arguments,0);i.unshift(this),e.apply(t||A,i)}),e.parsleyAdaptedCallback}function i(e){return 0===e.lastIndexOf(D,0)?e.substr(D.length):e}var n=1,r={},s={attr:function(e,t,i){var n,r,s,a=new RegExp("^"+t,"i");if("undefined"==typeof i)i={};else for(n in i)i.hasOwnProperty(n)&&delete i[n];if("undefined"==typeof e||"undefined"==typeof e[0])return i;for(s=e[0].attributes,n=s.length;n--;)r=s[n],r&&r.specified&&a.test(r.name)&&(i[this.camelize(r.name.slice(t.length))]=this.deserializeValue(r.value));return i},checkAttr:function(e,t,i){return e.is("["+t+i+"]")},setAttr:function(e,t,i,n){e[0].setAttribute(this.dasherize(t+i),String(n))},generateID:function(){return""+n++},deserializeValue:function(t){var i;try{return t?"true"==t||("false"==t?!1:"null"==t?null:isNaN(i=Number(t))?/^[\[\{]/.test(t)?e.parseJSON(t):t:i):t}catch(n){return t}},camelize:function(e){return e.replace(/-+(.)?/g,function(e,t){return t?t.toUpperCase():""})},dasherize:function(e){return e.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()},warn:function(){var e;window.console&&"function"==typeof window.console.warn&&(e=window.console).warn.apply(e,arguments)},warnOnce:function(e){r[e]||(r[e]=!0,this.warn.apply(this,arguments))},_resetWarnings:function(){r={}},trimString:function(e){return e.replace(/^\s+|\s+$/g,"")},namespaceEvents:function(t,i){return t=this.trimString(t||"").split(/\s+/),t[0]?e.map(t,function(e){return e+"."+i}).join(" "):""},objectCreate:Object.create||function(){var e=function(){};return function(t){if(arguments.length>1)throw Error("Second argument not supported");if("object"!=typeof t)throw TypeError("Argument must be an object");e.prototype=t;var i=new e;return e.prototype=null,i}}()},a=s,o={namespace:"data-parsley-",inputs:"input, textarea, select",excluded:"input[type=button], input[type=submit], input[type=reset], input[type=hidden]",priorityEnabled:!0,multiple:null,group:null,uiEnabled:!0,validationThreshold:3,focus:"first",trigger:!1,triggerAfterFailure:"input",errorClass:"parsley-error",successClass:"parsley-success",classHandler:function(e){},errorsContainer:function(e){},errorsWrapper:'<ul class="parsley-errors-list"></ul>',errorTemplate:"<li></li>"},l=function(){};l.prototype={asyncSupport:!0,actualizeOptions:function(){return a.attr(this.$element,this.options.namespace,this.domOptions),this.parent&&this.parent.actualizeOptions&&this.parent.actualizeOptions(),this},_resetOptions:function(e){this.domOptions=a.objectCreate(this.parent.options),this.options=a.objectCreate(this.domOptions);for(var t in e)e.hasOwnProperty(t)&&(this.options[t]=e[t]);this.actualizeOptions()},_listeners:null,on:function(e,t){this._listeners=this._listeners||{};var i=this._listeners[e]=this._listeners[e]||[];return i.push(t),this},subscribe:function(t,i){e.listenTo(this,t.toLowerCase(),i)},off:function(e,t){var i=this._listeners&&this._listeners[e];if(i)if(t)for(var n=i.length;n--;)i[n]===t&&i.splice(n,1);else delete this._listeners[e];return this},unsubscribe:function(t,i){e.unsubscribeTo(this,t.toLowerCase())},trigger:function(e,t,i){t=t||this;var n,r=this._listeners&&this._listeners[e];if(r)for(var s=r.length;s--;)if(n=r[s].call(t,t,i),n===!1)return n;return this.parent?this.parent.trigger(e,t,i):!0},reset:function(){if("ParsleyForm"!==this.__class__)return this._resetUI(),this._trigger("reset");for(var e=0;e<this.fields.length;e++)this.fields[e].reset();this._trigger("reset")},destroy:function(){if(this._destroyUI(),"ParsleyForm"!==this.__class__)return this.$element.removeData("Parsley"),this.$element.removeData("ParsleyFieldMultiple"),void this._trigger("destroy");for(var e=0;e<this.fields.length;e++)this.fields[e].destroy();this.$element.removeData("Parsley"),this._trigger("destroy")},asyncIsValid:function(e,t){return a.warnOnce("asyncIsValid is deprecated; please use whenValid instead"),this.whenValid({group:e,force:t})},_findRelated:function(){return this.options.multiple?this.parent.$element.find("["+this.options.namespace+'multiple="'+this.options.multiple+'"]'):this.$element}};var u={string:function(e){return e},integer:function(e){if(isNaN(e))throw'Requirement is not an integer: "'+e+'"';return parseInt(e,10)},number:function(e){if(isNaN(e))throw'Requirement is not a number: "'+e+'"';return parseFloat(e)},reference:function(t){var i=e(t);if(0===i.length)throw'No such reference: "'+t+'"';return i},"boolean":function(e){return"false"!==e},object:function(e){return a.deserializeValue(e)},regexp:function(e){var t="";return/^\/.*\/(?:[gimy]*)$/.test(e)?(t=e.replace(/.*\/([gimy]*)$/,"$1"),e=e.replace(new RegExp("^/(.*?)/"+t+"$"),"$1")):e="^"+e+"$",new RegExp(e,t)}},d=function(e,t){var i=e.match(/^\s*\[(.*)\]\s*$/);if(!i)throw'Requirement is not an array: "'+e+'"';var n=i[1].split(",").map(a.trimString);if(n.length!==t)throw"Requirement has "+n.length+" values when "+t+" are needed";return n},h=function(e,t){var i=u[e||"string"];if(!i)throw'Unknown requirement specification: "'+e+'"';return i(t)},p=function(e,t,i){var n=null,r={};for(var s in e)if(s){var a=i(s);"string"==typeof a&&(a=h(e[s],a)),r[s]=a}else n=h(e[s],t);return[n,r]},f=function(t){e.extend(!0,this,t)};f.prototype={validate:function(t,i){if(this.fn)return arguments.length>3&&(i=[].slice.call(arguments,1,-1)),this.fn.call(this,t,i);if(e.isArray(t)){if(!this.validateMultiple)throw"Validator `"+this.name+"` does not handle multiple values";return this.validateMultiple.apply(this,arguments)}if(this.validateNumber)return isNaN(t)?!1:(arguments[0]=parseFloat(arguments[0]),this.validateNumber.apply(this,arguments));if(this.validateString)return this.validateString.apply(this,arguments);throw"Validator `"+this.name+"` only handles multiple values"},parseRequirements:function(t,i){if("string"!=typeof t)return e.isArray(t)?t:[t];var n=this.requirementType;if(e.isArray(n)){for(var r=d(t,n.length),s=0;s<r.length;s++)r[s]=h(n[s],r[s]);return r}return e.isPlainObject(n)?p(n,t,i):[h(n,t)]},requirementType:"string",priority:2};var c=function(e,t){this.__class__="ParsleyValidatorRegistry",this.locale="en",this.init(e||{},t||{})},m={email:/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,number:/^-?(\d*\.)?\d+(e[-+]?\d+)?$/i,integer:/^-?\d+$/,digits:/^\d+$/,alphanum:/^\w+$/i,url:new RegExp("^(?:(?:https?|ftp)://)?(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:/\\S*)?$","i")};m.range=m.number;var g=function(e){var t=(""+e).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);return t?Math.max(0,(t[1]?t[1].length:0)-(t[2]?+t[2]:0)):0};c.prototype={init:function(t,i){this.catalog=i,this.validators=e.extend({},this.validators);for(var n in t)this.addValidator(n,t[n].fn,t[n].priority);window.Parsley.trigger("parsley:validator:init")},setLocale:function(e){if("undefined"==typeof this.catalog[e])throw new Error(e+" is not available in the catalog");return this.locale=e,this},addCatalog:function(e,t,i){return"object"==typeof t&&(this.catalog[e]=t),!0===i?this.setLocale(e):this},addMessage:function(e,t,i){return"undefined"==typeof this.catalog[e]&&(this.catalog[e]={}),this.catalog[e][t]=i,this},addMessages:function(e,t){for(var i in t)this.addMessage(e,i,t[i]);return this},addValidator:function(e,t,i){if(this.validators[e])a.warn('Validator "'+e+'" is already defined.');else if(o.hasOwnProperty(e))return void a.warn('"'+e+'" is a restricted keyword and is not a valid validator name.');return this._setValidator.apply(this,arguments)},updateValidator:function(e,t,i){return this.validators[e]?this._setValidator(this,arguments):(a.warn('Validator "'+e+'" is not already defined.'),this.addValidator.apply(this,arguments))},removeValidator:function(e){return this.validators[e]||a.warn('Validator "'+e+'" is not defined.'),delete this.validators[e],this},_setValidator:function(e,t,i){"object"!=typeof t&&(t={fn:t,priority:i}),t.validate||(t=new f(t)),this.validators[e]=t;for(var n in t.messages||{})this.addMessage(n,e,t.messages[n]);return this},getErrorMessage:function(e){var t;if("type"===e.name){var i=this.catalog[this.locale][e.name]||{};t=i[e.requirements]}else t=this.formatMessage(this.catalog[this.locale][e.name],e.requirements);return t||this.catalog[this.locale].defaultMessage||this.catalog.en.defaultMessage},formatMessage:function(e,t){if("object"==typeof t){for(var i in t)e=this.formatMessage(e,t[i]);return e}return"string"==typeof e?e.replace(/%s/i,t):""},validators:{notblank:{validateString:function(e){return/\S/.test(e)},priority:2},required:{validateMultiple:function(e){return e.length>0},validateString:function(e){return/\S/.test(e)},priority:512},type:{validateString:function(e,t){var i=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],n=i.step,r=void 0===n?"1":n,s=i.base,a=void 0===s?0:s,o=m[t];if(!o)throw new Error("validator type `"+t+"` is not supported");if(!o.test(e))return!1;if("number"===t&&!/^any$/i.test(r||"")){var l=Number(e),u=Math.max(g(r),g(a));if(g(l)>u)return!1;var d=function(e){return Math.round(e*Math.pow(10,u))};if((d(l)-d(a))%d(r)!=0)return!1}return!0},requirementType:{"":"string",step:"string",base:"number"},priority:256},pattern:{validateString:function(e,t){return t.test(e)},requirementType:"regexp",priority:64},minlength:{validateString:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxlength:{validateString:function(e,t){return e.length<=t},requirementType:"integer",priority:30},length:{validateString:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},mincheck:{validateMultiple:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxcheck:{validateMultiple:function(e,t){return e.length<=t},requirementType:"integer",priority:30},check:{validateMultiple:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},min:{validateNumber:function(e,t){return e>=t},requirementType:"number",priority:30},max:{validateNumber:function(e,t){return t>=e},requirementType:"number",priority:30},range:{validateNumber:function(e,t,i){return e>=t&&i>=e},requirementType:["number","number"],priority:30},equalto:{validateString:function(t,i){var n=e(i);return n.length?t===n.val():t===i},priority:256}}};var y={},v=function T(e,t,i){for(var n=[],r=[],s=0;s<e.length;s++){for(var a=!1,o=0;o<t.length;o++)if(e[s].assert.name===t[o].assert.name){a=!0;break}a?r.push(e[s]):n.push(e[s])}return{kept:r,added:n,removed:i?[]:T(t,e,!0).added}};y.Form={_actualizeTriggers:function(){var e=this;this.$element.on("submit.Parsley",function(t){e.onSubmitValidate(t)}),this.$element.on("click.Parsley",'input[type="submit"], button[type="submit"]',function(t){e.onSubmitButton(t)}),!1!==this.options.uiEnabled&&this.$element.attr("novalidate","")},focus:function(){if(this._focusedField=null,!0===this.validationResult||"none"===this.options.focus)return null;for(var e=0;e<this.fields.length;e++){var t=this.fields[e];if(!0!==t.validationResult&&t.validationResult.length>0&&"undefined"==typeof t.options.noFocus&&(this._focusedField=t.$element,"first"===this.options.focus))break}return null===this._focusedField?null:this._focusedField.focus()},_destroyUI:function(){this.$element.off(".Parsley")}},y.Field={_reflowUI:function(){if(this._buildUI(),this._ui){var e=v(this.validationResult,this._ui.lastValidationResult);this._ui.lastValidationResult=this.validationResult,this._manageStatusClass(),this._manageErrorsMessages(e),this._actualizeTriggers(),!e.kept.length&&!e.added.length||this._failedOnce||(this._failedOnce=!0,this._actualizeTriggers())}},getErrorsMessages:function(){if(!0===this.validationResult)return[];for(var e=[],t=0;t<this.validationResult.length;t++)e.push(this.validationResult[t].errorMessage||this._getErrorMessage(this.validationResult[t].assert));return e},addError:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],i=t.message,n=t.assert,r=t.updateClass,s=void 0===r?!0:r;this._buildUI(),this._addError(e,{message:i,assert:n}),s&&this._errorClass()},updateError:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],i=t.message,n=t.assert,r=t.updateClass,s=void 0===r?!0:r;this._buildUI(),this._updateError(e,{message:i,assert:n}),s&&this._errorClass()},removeError:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],i=t.updateClass,n=void 0===i?!0:i;this._buildUI(),this._removeError(e),n&&this._manageStatusClass()},_manageStatusClass:function(){this.hasConstraints()&&this.needsValidation()&&!0===this.validationResult?this._successClass():this.validationResult.length>0?this._errorClass():this._resetClass()},_manageErrorsMessages:function(t){if("undefined"==typeof this.options.errorsMessagesDisabled){if("undefined"!=typeof this.options.errorMessage)return t.added.length||t.kept.length?(this._insertErrorWrapper(),0===this._ui.$errorsWrapper.find(".parsley-custom-error-message").length&&this._ui.$errorsWrapper.append(e(this.options.errorTemplate).addClass("parsley-custom-error-message")),this._ui.$errorsWrapper.addClass("filled").find(".parsley-custom-error-message").html(this.options.errorMessage)):this._ui.$errorsWrapper.removeClass("filled").find(".parsley-custom-error-message").remove();for(var i=0;i<t.removed.length;i++)this._removeError(t.removed[i].assert.name);for(i=0;i<t.added.length;i++)this._addError(t.added[i].assert.name,{message:t.added[i].errorMessage,assert:t.added[i].assert});for(i=0;i<t.kept.length;i++)this._updateError(t.kept[i].assert.name,{message:t.kept[i].errorMessage,assert:t.kept[i].assert})}},_addError:function(t,i){var n=i.message,r=i.assert;this._insertErrorWrapper(),this._ui.$errorsWrapper.addClass("filled").append(e(this.options.errorTemplate).addClass("parsley-"+t).html(n||this._getErrorMessage(r)))},_updateError:function(e,t){var i=t.message,n=t.assert;this._ui.$errorsWrapper.addClass("filled").find(".parsley-"+e).html(i||this._getErrorMessage(n))},_removeError:function(e){this._ui.$errorsWrapper.removeClass("filled").find(".parsley-"+e).remove()},_getErrorMessage:function(e){var t=e.name+"Message";return"undefined"!=typeof this.options[t]?window.Parsley.formatMessage(this.options[t],e.requirements):window.Parsley.getErrorMessage(e)},_buildUI:function(){if(!this._ui&&!1!==this.options.uiEnabled){var t={};this.$element.attr(this.options.namespace+"id",this.__id__),t.$errorClassHandler=this._manageClassHandler(),t.errorsWrapperId="parsley-id-"+(this.options.multiple?"multiple-"+this.options.multiple:this.__id__),t.$errorsWrapper=e(this.options.errorsWrapper).attr("id",t.errorsWrapperId),t.lastValidationResult=[],t.validationInformationVisible=!1,this._ui=t}},_manageClassHandler:function(){if("string"==typeof this.options.classHandler&&e(this.options.classHandler).length)return e(this.options.classHandler);var t=this.options.classHandler.call(this,this);return"undefined"!=typeof t&&t.length?t:!this.options.multiple||this.$element.is("select")?this.$element:this.$element.parent()},_insertErrorWrapper:function(){var t;if(0!==this._ui.$errorsWrapper.parent().length)return this._ui.$errorsWrapper.parent();if("string"==typeof this.options.errorsContainer){if(e(this.options.errorsContainer).length)return e(this.options.errorsContainer).append(this._ui.$errorsWrapper);a.warn("The errors container `"+this.options.errorsContainer+"` does not exist in DOM")}else"function"==typeof this.options.errorsContainer&&(t=this.options.errorsContainer.call(this,this));if("undefined"!=typeof t&&t.length)return t.append(this._ui.$errorsWrapper);var i=this.$element;return this.options.multiple&&(i=i.parent()),i.after(this._ui.$errorsWrapper)},_actualizeTriggers:function(){var e=this,t=this._findRelated();t.off(".Parsley"),this._failedOnce?t.on(a.namespaceEvents(this.options.triggerAfterFailure,"Parsley"),function(){e.validate()}):t.on(a.namespaceEvents(this.options.trigger,"Parsley"),function(t){e._eventValidate(t)})},_eventValidate:function(e){(!/key|input/.test(e.type)||this._ui&&this._ui.validationInformationVisible||!(this.getValue().length<=this.options.validationThreshold))&&this.validate()},_resetUI:function(){this._failedOnce=!1,this._actualizeTriggers(),"undefined"!=typeof this._ui&&(this._ui.$errorsWrapper.removeClass("filled").children().remove(),this._resetClass(),this._ui.lastValidationResult=[],this._ui.validationInformationVisible=!1)},_destroyUI:function(){this._resetUI(),"undefined"!=typeof this._ui&&this._ui.$errorsWrapper.remove(),delete this._ui},_successClass:function(){this._ui.validationInformationVisible=!0,this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass)},_errorClass:function(){this._ui.validationInformationVisible=!0,this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass)},_resetClass:function(){this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass)}};var _=function(t,i,n){this.__class__="ParsleyForm",this.__id__=a.generateID(),this.$element=e(t),this.domOptions=i,this.options=n,this.parent=window.Parsley,this.fields=[],this.validationResult=null},w={pending:null,resolved:!0,rejected:!1};_.prototype={onSubmitValidate:function(e){var t=this;if(!0!==e.parsley){var i=this._$submitSource||this.$element.find('input[type="submit"], button[type="submit"]').first();if(this._$submitSource=null,this.$element.find(".parsley-synthetic-submit-button").prop("disabled",!0),!i.is("[formnovalidate]")){var n=this.whenValidate({event:e});"resolved"===n.state()&&!1!==this._trigger("submit")||(e.stopImmediatePropagation(),e.preventDefault(),"pending"===n.state()&&n.done(function(){t._submit(i)}))}}},onSubmitButton:function(t){this._$submitSource=e(t.target)},_submit:function(t){if(!1!==this._trigger("submit")){if(t){var i=this.$element.find(".parsley-synthetic-submit-button").prop("disabled",!1);0===i.length&&(i=e('<input class="parsley-synthetic-submit-button" type="hidden">').appendTo(this.$element)),i.attr({name:t.attr("name"),value:t.attr("value")})}this.$element.trigger(e.extend(e.Event("submit"),{parsley:!0}))}},validate:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling validate on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1],s=i[2];t={group:n,force:r,event:s}}return w[this.whenValidate(t).state()]},whenValidate:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force,s=i.event;this.submitEvent=s,s&&(this.submitEvent=e.extend({},s,{preventDefault:function(){a.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`"),t.validationResult=!1}})),this.validationResult=!0,this._trigger("validate"),this._refreshFields();var o=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValidate({force:r,group:n})})}),l=function(){var i=e.Deferred();return!1===t.validationResult&&i.reject(),i.resolve().promise()};return e.when.apply(e,_toConsumableArray(o)).done(function(){t._trigger("success")}).fail(function(){t.validationResult=!1,t.focus(),t._trigger("error")}).always(function(){t._trigger("validated")}).pipe(l,l)},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={group:n,force:r}}return w[this.whenValid(t).state()]},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force;this._refreshFields();var s=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValid({group:n,force:r})})});return e.when.apply(e,_toConsumableArray(s))},_refreshFields:function(){return this.actualizeOptions()._bindFields()},_bindFields:function(){var t=this,i=this.fields;return this.fields=[],this.fieldsMappedById={},this._withoutReactualizingFormOptions(function(){t.$element.find(t.options.inputs).not(t.options.excluded).each(function(e,i){var n=new window.Parsley.Factory(i,{},t);"ParsleyField"!==n.__class__&&"ParsleyFieldMultiple"!==n.__class__||!0===n.options.excluded||"undefined"==typeof t.fieldsMappedById[n.__class__+"-"+n.__id__]&&(t.fieldsMappedById[n.__class__+"-"+n.__id__]=n,t.fields.push(n))}),e(i).not(t.fields).each(function(e,t){t._trigger("reset")})}),this},_withoutReactualizingFormOptions:function(e){var t=this.actualizeOptions;this.actualizeOptions=function(){return this};var i=e();return this.actualizeOptions=t,i},_trigger:function(e){return this.trigger("form:"+e)}};var b=function(t,i,n,r,s){if(!/ParsleyField/.test(t.__class__))throw new Error("ParsleyField or ParsleyFieldMultiple instance expected");var a=window.Parsley._validatorRegistry.validators[i],o=new f(a);e.extend(this,{validator:o,name:i,requirements:n,priority:r||t.options[i+"Priority"]||o.priority,isDomConstraint:!0===s}),this._parseRequirements(t.options)},F=function(e){var t=e[0].toUpperCase();return t+e.slice(1)};b.prototype={validate:function(e,t){var i=this.requirementList.slice(0);return i.unshift(e),i.push(t),this.validator.validate.apply(this.validator,i)},_parseRequirements:function(e){var t=this;this.requirementList=this.validator.parseRequirements(this.requirements,function(i){return e[t.name+F(i)]})}};var C=function(t,i,n,r){this.__class__="ParsleyField",this.__id__=a.generateID(),this.$element=e(t),"undefined"!=typeof r&&(this.parent=r),this.options=n,this.domOptions=i,this.constraints=[],this.constraintsByName={},this.validationResult=[],this._bindConstraints()},$={pending:null,resolved:!0,rejected:!1};C.prototype={validate:function(t){arguments.length>=1&&!e.isPlainObject(t)&&(a.warnOnce("Calling validate on a parsley field without passing arguments as an object is deprecated."),t={options:t});var i=this.whenValidate(t);if(!i)return!0;switch(i.state()){case"pending":return null;case"resolved":return!0;case"rejected":return this.validationResult}},whenValidate:function(){var e=this,t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],i=t.force,n=t.group;return this.refreshConstraints(),!n||this._isInGroup(n)?(this.value=this.getValue(),this._trigger("validate"),this.whenValid({force:i,value:this.value,_refreshed:!0}).always(function(){e._reflowUI()}).done(function(){e._trigger("success")}).fail(function(){e._trigger("error")}).always(function(){e._trigger("validated")})):void 0},hasConstraints:function(){return 0!==this.constraints.length},needsValidation:function(e){return"undefined"==typeof e&&(e=this.getValue()),e.length||this._isRequired()||"undefined"!=typeof this.options.validateIfEmpty?!0:!1},_isInGroup:function(t){return e.isArray(this.options.group)?-1!==e.inArray(t,this.options.group):this.options.group===t},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley field without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={force:n,value:r}}var s=this.whenValid(t);return s?$[s.state()]:!0},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.force,r=void 0===n?!1:n,s=i.value,a=i.group,o=i._refreshed;if(o||this.refreshConstraints(),!a||this._isInGroup(a)){if(this.validationResult=!0,!this.hasConstraints())return e.when();if(("undefined"==typeof s||null===s)&&(s=this.getValue()),!this.needsValidation(s)&&!0!==r)return e.when();var l=this._getGroupedConstraints(),u=[];return e.each(l,function(i,n){var r=e.when.apply(e,_toConsumableArray(e.map(n,function(e){return t._validateConstraint(s,e)})));return u.push(r),"rejected"===r.state()?!1:void 0}),e.when.apply(e,u)}},_validateConstraint:function(t,i){var n=this,r=i.validate(t,this);return!1===r&&(r=e.Deferred().reject()),e.when(r).fail(function(e){!0===n.validationResult&&(n.validationResult=[]),n.validationResult.push({assert:i,errorMessage:"string"==typeof e&&e})})},getValue:function(){var e;return e="function"==typeof this.options.value?this.options.value(this):"undefined"!=typeof this.options.value?this.options.value:this.$element.val(),"undefined"==typeof e||null===e?"":this._handleWhitespace(e)},refreshConstraints:function(){return this.actualizeOptions()._bindConstraints()},addConstraint:function(e,t,i,n){if(window.Parsley._validatorRegistry.validators[e]){var r=new b(this,e,t,i,n);"undefined"!==this.constraintsByName[r.name]&&this.removeConstraint(r.name),this.constraints.push(r),this.constraintsByName[r.name]=r}return this},removeConstraint:function(e){for(var t=0;t<this.constraints.length;t++)if(e===this.constraints[t].name){this.constraints.splice(t,1);break}return delete this.constraintsByName[e],this},updateConstraint:function(e,t,i){return this.removeConstraint(e).addConstraint(e,t,i)},_bindConstraints:function(){for(var e=[],t={},i=0;i<this.constraints.length;i++)!1===this.constraints[i].isDomConstraint&&(e.push(this.constraints[i]),t[this.constraints[i].name]=this.constraints[i]);this.constraints=e,this.constraintsByName=t;for(var n in this.options)this.addConstraint(n,this.options[n],void 0,!0);return this._bindHtml5Constraints()},_bindHtml5Constraints:function(){(this.$element.hasClass("required")||this.$element.attr("required"))&&this.addConstraint("required",!0,void 0,!0),"string"==typeof this.$element.attr("pattern")&&this.addConstraint("pattern",this.$element.attr("pattern"),void 0,!0),"undefined"!=typeof this.$element.attr("min")&&"undefined"!=typeof this.$element.attr("max")?this.addConstraint("range",[this.$element.attr("min"),this.$element.attr("max")],void 0,!0):"undefined"!=typeof this.$element.attr("min")?this.addConstraint("min",this.$element.attr("min"),void 0,!0):"undefined"!=typeof this.$element.attr("max")&&this.addConstraint("max",this.$element.attr("max"),void 0,!0),"undefined"!=typeof this.$element.attr("minlength")&&"undefined"!=typeof this.$element.attr("maxlength")?this.addConstraint("length",[this.$element.attr("minlength"),this.$element.attr("maxlength")],void 0,!0):"undefined"!=typeof this.$element.attr("minlength")?this.addConstraint("minlength",this.$element.attr("minlength"),void 0,!0):"undefined"!=typeof this.$element.attr("maxlength")&&this.addConstraint("maxlength",this.$element.attr("maxlength"),void 0,!0);var e=this.$element.attr("type");return"undefined"==typeof e?this:"number"===e?this.addConstraint("type",["number",{step:this.$element.attr("step"),base:this.$element.attr("min")||this.$element.attr("value")}],void 0,!0):/^(email|url|range)$/i.test(e)?this.addConstraint("type",e,void 0,!0):this},_isRequired:function(){return"undefined"==typeof this.constraintsByName.required?!1:!1!==this.constraintsByName.required.requirements},_trigger:function(e){return this.trigger("field:"+e)},_handleWhitespace:function(e){return!0===this.options.trimValue&&a.warnOnce('data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"'),"squish"===this.options.whitespace&&(e=e.replace(/\s{2,}/g," ")),("trim"===this.options.whitespace||"squish"===this.options.whitespace||!0===this.options.trimValue)&&(e=a.trimString(e)),e},_getGroupedConstraints:function(){if(!1===this.options.priorityEnabled)return[this.constraints];for(var e=[],t={},i=0;i<this.constraints.length;i++){var n=this.constraints[i].priority;t[n]||e.push(t[n]=[]),t[n].push(this.constraints[i])}return e.sort(function(e,t){return t[0].priority-e[0].priority}),e}};var x=C,P=function(){this.__class__="ParsleyFieldMultiple"};P.prototype={addElement:function(e){return this.$elements.push(e),this},refreshConstraints:function(){var t;if(this.constraints=[],this.$element.is("select"))return this.actualizeOptions()._bindConstraints(),this;for(var i=0;i<this.$elements.length;i++)if(e("html").has(this.$elements[i]).length){t=this.$elements[i].data("ParsleyFieldMultiple").refreshConstraints().constraints;for(var n=0;n<t.length;n++)this.addConstraint(t[n].name,t[n].requirements,t[n].priority,t[n].isDomConstraint)}else this.$elements.splice(i,1);return this},getValue:function(){if("function"==typeof this.options.value)value=this.options.value(this);else if("undefined"!=typeof this.options.value)return this.options.value;if(this.$element.is("input[type=radio]"))return this._findRelated().filter(":checked").val()||"";if(this.$element.is("input[type=checkbox]")){var t=[];return this._findRelated().filter(":checked").each(function(){t.push(e(this).val())}),t}return this.$element.is("select")&&null===this.$element.val()?[]:this.$element.val()},_init:function(){return this.$elements=[this.$element],this}};var E=function(t,i,n){this.$element=e(t);var r=this.$element.data("Parsley");if(r)return"undefined"!=typeof n&&r.parent===window.Parsley&&(r.parent=n,r._resetOptions(r.options)),r;if(!this.$element.length)throw new Error("You must bind Parsley on an existing element.");if("undefined"!=typeof n&&"ParsleyForm"!==n.__class__)throw new Error("Parent instance must be a ParsleyForm instance");return this.parent=n||window.Parsley,this.init(i)};E.prototype={init:function(e){return this.__class__="Parsley",this.__version__="2.3.5",this.__id__=a.generateID(),this._resetOptions(e),this.$element.is("form")||a.checkAttr(this.$element,this.options.namespace,"validate")&&!this.$element.is(this.options.inputs)?this.bind("parsleyForm"):this.isMultiple()?this.handleMultiple():this.bind("parsleyField")},isMultiple:function(){return this.$element.is("input[type=radio], input[type=checkbox]")||this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple")},handleMultiple:function(){var t,i,n=this;if(this.options.multiple||("undefined"!=typeof this.$element.attr("name")&&this.$element.attr("name").length?this.options.multiple=t=this.$element.attr("name"):"undefined"!=typeof this.$element.attr("id")&&this.$element.attr("id").length&&(this.options.multiple=this.$element.attr("id"))),this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple"))return this.options.multiple=this.options.multiple||this.__id__,this.bind("parsleyFieldMultiple");if(!this.options.multiple)return a.warn("To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.",this.$element),this;this.options.multiple=this.options.multiple.replace(/(:|\.|\[|\]|\{|\}|\$)/g,""),
178
- "undefined"!=typeof t&&e('input[name="'+t+'"]').each(function(t,i){e(i).is("input[type=radio], input[type=checkbox]")&&e(i).attr(n.options.namespace+"multiple",n.options.multiple)});for(var r=this._findRelated(),s=0;s<r.length;s++)if(i=e(r.get(s)).data("Parsley"),"undefined"!=typeof i){this.$element.data("ParsleyFieldMultiple")||i.addElement(this.$element);break}return this.bind("parsleyField",!0),i||this.bind("parsleyFieldMultiple")},bind:function(t,i){var n;switch(t){case"parsleyForm":n=e.extend(new _(this.$element,this.domOptions,this.options),window.ParsleyExtend)._bindFields();break;case"parsleyField":n=e.extend(new x(this.$element,this.domOptions,this.options,this.parent),window.ParsleyExtend);break;case"parsleyFieldMultiple":n=e.extend(new x(this.$element,this.domOptions,this.options,this.parent),new P,window.ParsleyExtend)._init();break;default:throw new Error(t+"is not a supported Parsley type")}return this.options.multiple&&a.setAttr(this.$element,this.options.namespace,"multiple",this.options.multiple),"undefined"!=typeof i?(this.$element.data("ParsleyFieldMultiple",n),n):(this.$element.data("Parsley",n),n._actualizeTriggers(),n._trigger("init"),n)}};var V=e.fn.jquery.split(".");if(parseInt(V[0])<=1&&parseInt(V[1])<8)throw"The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.";V.forEach||a.warn("Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim");var M=e.extend(new l,{$element:e(document),actualizeOptions:null,_resetOptions:null,Factory:E,version:"2.3.5"});e.extend(x.prototype,y.Field,l.prototype),e.extend(_.prototype,y.Form,l.prototype),e.extend(E.prototype,l.prototype),e.fn.parsley=e.fn.psly=function(t){if(this.length>1){var i=[];return this.each(function(){i.push(e(this).parsley(t))}),i}return e(this).length?new E(this,t):void a.warn("You must bind Parsley on an existing element.")},"undefined"==typeof window.ParsleyExtend&&(window.ParsleyExtend={}),M.options=e.extend(a.objectCreate(o),window.ParsleyConfig),window.ParsleyConfig=M.options,window.Parsley=window.psly=M,window.ParsleyUtils=a;var O=window.Parsley._validatorRegistry=new c(window.ParsleyConfig.validators,window.ParsleyConfig.i18n);window.ParsleyValidator={},e.each("setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator".split(" "),function(t,i){window.Parsley[i]=e.proxy(O,i),window.ParsleyValidator[i]=function(){var e;return a.warnOnce("Accessing the method '"+i+"' through ParsleyValidator is deprecated. Simply call 'window.Parsley."+i+"(...)'"),(e=window.Parsley)[i].apply(e,arguments)}}),window.Parsley.UI=y,window.ParsleyUI={removeError:function(e,t,i){var n=!0!==i;return a.warnOnce("Accessing ParsleyUI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e.removeError(t,{updateClass:n})},getErrorsMessages:function(e){return a.warnOnce("Accessing ParsleyUI is deprecated. Call 'getErrorsMessages' on the instance directly."),e.getErrorsMessages()}},e.each("addError updateError".split(" "),function(e,t){window.ParsleyUI[t]=function(e,i,n,r,s){var o=!0!==s;return a.warnOnce("Accessing ParsleyUI is deprecated. Call '"+t+"' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e[t](i,{message:n,assert:r,updateClass:o})}}),/firefox/i.test(navigator.userAgent)&&e(document).on("change","select",function(t){e(t.target).trigger("input")}),!1!==window.ParsleyConfig.autoBind&&e(function(){e("[data-parsley-validate]").length&&e("[data-parsley-validate]").parsley()});var A=e({}),R=function(){a.warnOnce("Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley")},D="parsley:";e.listen=function(e,n){var r;if(R(),"object"==typeof arguments[1]&&"function"==typeof arguments[2]&&(r=arguments[1],n=arguments[2]),"function"!=typeof n)throw new Error("Wrong parameters");window.Parsley.on(i(e),t(n,r))},e.listenTo=function(e,n,r){if(R(),!(e instanceof x||e instanceof _))throw new Error("Must give Parsley instance");if("string"!=typeof n||"function"!=typeof r)throw new Error("Wrong parameters");e.on(i(n),t(r))},e.unsubscribe=function(e,t){if(R(),"string"!=typeof e||"function"!=typeof t)throw new Error("Wrong arguments");window.Parsley.off(i(e),t.parsleyAdaptedCallback)},e.unsubscribeTo=function(e,t){if(R(),!(e instanceof x||e instanceof _))throw new Error("Must give Parsley instance");e.off(i(t))},e.unsubscribeAll=function(t){R(),window.Parsley.off(i(t)),e("form,input,textarea,select").each(function(){var n=e(this).data("Parsley");n&&n.off(i(t))})},e.emit=function(e,t){var n;R();var r=t instanceof x||t instanceof _,s=Array.prototype.slice.call(arguments,r?2:1);s.unshift(i(e)),r||(t=window.Parsley),(n=t).trigger.apply(n,_toConsumableArray(s))};e.extend(!0,M,{asyncValidators:{"default":{fn:function(e){return e.status>=200&&e.status<300},url:!1},reverse:{fn:function(e){return e.status<200||e.status>=300},url:!1}},addAsyncValidator:function(e,t,i,n){return M.asyncValidators[e]={fn:t,url:i||!1,options:n||{}},this}}),M.addValidator("remote",{requirementType:{"":"string",validator:"string",reverse:"boolean",options:"object"},validateString:function(t,i,n,r){var s,a,o={},l=n.validator||(!0===n.reverse?"reverse":"default");if("undefined"==typeof M.asyncValidators[l])throw new Error("Calling an undefined async validator: `"+l+"`");i=M.asyncValidators[l].url||i,i.indexOf("{value}")>-1?i=i.replace("{value}",encodeURIComponent(t)):o[r.$element.attr("name")||r.$element.attr("id")]=t;var u=e.extend(!0,n.options||{},M.asyncValidators[l].options);s=e.extend(!0,{},{url:i,data:o,type:"GET"},u),r.trigger("field:ajaxoptions",r,s),a=e.param(s),"undefined"==typeof M._remoteCache&&(M._remoteCache={});var d=M._remoteCache[a]=M._remoteCache[a]||e.ajax(s),h=function(){var t=M.asyncValidators[l].fn.call(r,d,i,n);return t||(t=e.Deferred().reject()),e.when(t)};return d.then(h,h)},priority:-1}),M.on("form:submit",function(){M._remoteCache={}}),window.ParsleyExtend.addAsyncValidator=function(){return ParsleyUtils.warnOnce("Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`"),M.addAsyncValidator.apply(M,arguments)},M.addMessages("en",{defaultMessage:"This value seems to be invalid.",type:{email:"This value should be a valid email.",url:"This value should be a valid url.",number:"This value should be a valid number.",integer:"This value should be a valid integer.",digits:"This value should be digits.",alphanum:"This value should be alphanumeric."},notblank:"This value should not be blank.",required:"This value is required.",pattern:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or fewer.",length:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or fewer.",check:"You must select between %s and %s choices.",equalto:"This value should be the same."}),M.setLocale("en");var q=M;return q});
179
- </script>
180
-
181
- <script type="text/javascript">
182
- /*!
183
- * jQuery Modal (minified)
184
- * Copyright (c) 2015 CreativeDream
185
- * https://github.com/CreativeDream/jquery.modal
186
- * Version: 1.2.3 (10-04-2015)
187
- * Requires: jQuery v1.7.1 or later
188
- * type: 'inverted', //Type of Modal Box (alert | confirm | prompt | success | warning | error | info | inverted | primary)
189
- */
190
- function modal(t){return $.cModal(t)}!function(t){t.cModal=function(n){var e,o={type:"default",title:null,text:null,size:"normal",buttons:[{text:"OK",val:!0,onClick:function(){return!0}}],center:!0,autoclose:!1,callback:null,onShow:null,animate:!0,closeClick:!0,closable:!0,theme:"default",background:null,zIndex:1050,buttonText:{ok:"OK",yes:"Yes",cancel:"Cancel"},template:'<div class="modal-box"><div class="modal-inner"><div class="modal-title"><a class="modal-close-btn"></a></div><div class="modal-text"></div><div class="modal-buttons"></div></div></div>',_classes:{box:".modal-box",boxInner:".modal-inner",title:".modal-title",content:".modal-text",buttons:".modal-buttons",closebtn:".modal-close-btn"}},n=t.extend({},o,n),a=t("<div id='modal-window' />").hide(),l=n._classes.box,s=a.append(n.template),i={init:function(){t("#modal-window").remove(),i._setStyle(),i._modalShow(),i._modalConent(),a.on("click","a.modal-btn",function(){i._modalBtn(t(this))}).on("click",n._classes.closebtn,function(){e=!1,i._modalHide()}).click(function(t){n.closeClick&&"modal-window"==t.target.id&&(e=!1,i._modalHide())}),t(window).bind("keyup",i._keyUpF).resize(function(){var t=n.animate;n.animate=!1,i._position(),n.animate=t})},_setStyle:function(){a.css({position:"fixed",width:"100%",height:"100%",top:"0",left:"0","z-index":n.zIndex,overflow:"auto"}),a.find(n._classes.box).css({position:"absolute"})},_keyUpF:function(t){switch(t.keyCode){case 13:if(s.find("input:not(.modal-prompt-input),textarea").is(":focus"))return!1;i._modalBtn(a.find(n._classes.buttons+" a.modal-btn"+("undefined"!=typeof i.btnForEKey&&a.find(n._classes.buttons+" a.modal-btn:eq("+i.btnForEKey+")").size()>0?":eq("+i.btnForEKey+")":":last-child")));break;case 27:i._modalHide()}},_modalShow:function(){t("body").css({overflow:"hidden",width:t("body").innerWidth()}).append(s)},_modalHide:function(o){if(n.closable===!1)return!1;e="undefined"==typeof e?!1:e;var s=function(){if(null!=n.callback&&"function"==typeof n.callback&&0==n.callback(e,a,i.actions)?!1:!0){a.fadeOut(200,function(){t(this).remove(),t("body").css({overflow:"",width:""})});var o=100*parseFloat(t(l).css("top"))/parseFloat(t(l).parent().css("height"));t(l).stop(!0,!0).animate({top:o+(n.animate?3:0)+"%"},"fast")}};o?setTimeout(function(){s()},o):s(),t(window).unbind("keyup",i._keyUpF)},_modalConent:function(){var e=n._classes.title,o=n._classes.content,s=n._classes.buttons,d=n.buttonText,c=["alert","confirm","prompt"],u=["xenon","atlant","reseted"];if(-1==t.inArray(n.type,c)&&"default"!=n.type&&t(l).addClass("modal-type-"+n.type),t(l).addClass(n.size&&null!=n.size?"modal-size-"+n.size:"modal-size-normal"),n.theme&&null!=n.theme&&"default"!=n.theme&&t(l).addClass((-1==t.inArray(n.theme,u)?"":"modal-theme-")+n.theme),n.background&&null!=n.background&&a.css("background-color",n.background),n.title||null!=n.title?t(e).prepend("<h3>"+n.title+"</h3>"):t(e).remove(),"prompt"==n.type?n.text=(null!=n.text?n.text:"")+'<input type="text" name="modal-prompt-input" class="modal-prompt-input" autocomplete="off" autofocus="on" />':"",t(o).html(n.text),n.buttons||null!=n.buttons){var r="";switch(n.type){case"alert":r='<a class="modal-btn'+(n.buttons[0].addClass?" "+n.buttons[0].addClass:"")+'">'+d.ok+"</a>";break;case"confirm":r='<a class="modal-btn'+(n.buttons[0].addClass?" "+n.buttons[0].addClass:"")+'">'+d.cancel+'</a><a class="modal-btn '+(n.buttons[1]&&n.buttons[1].addClass?" "+n.buttons[1].addClass:"btn-light-blue")+'">'+d.yes+"</a>";break;case"prompt":r='<a class="modal-btn'+(n.buttons[0].addClass?" "+n.buttons[0].addClass:"")+'">'+d.cancel+'</a><a class="modal-btn '+(n.buttons[1]&&n.buttons[1].addClass?" "+n.buttons[1].addClass:"btn-light-blue")+'">'+d.ok+"</a>";break;default:n.buttons.length>0&&t.isArray(n.buttons)?t.each(n.buttons,function(t,n){var e=n.addClass&&"undefined"!=typeof n.addClass?" "+n.addClass:"";r+='<a class="modal-btn'+e+'">'+n.text+"</a>",n.eKey&&(i.btnForEKey=t)}):r+='<a class="modal-btn">'+d.ok+"</a>"}t(s).html(r)}else t(s).remove();if("prompt"==n.type&&$(".modal-prompt-input").focus(),n.autoclose){var m=n.buttons||null!=n.buttons?32*t(o).text().length:900;i._modalHide(900>m?900:m)}a.fadeIn(200,function(){null!=n.onShow?n.onShow(i.actions):null}),i._position()},_position:function(){var e,o,a;n.center?(e={top:t(window).height()<t(l).outerHeight()?1:50,left:50,marginTop:t(window).height()<t(l).outerHeight()?0:-t(l).outerHeight()/2,marginLeft:-t(l).outerWidth()/2},o={top:e.top-(n.animate?3:0)+"%",left:e.left+"%","margin-top":e.marginTop,"margin-left":e.marginLeft},a={top:e.top+"%"}):(e={top:t(window).height()<t(l).outerHeight()?1:10,left:50,marginTop:0,marginLeft:-t(l).outerWidth()/2},o={top:e.top-(n.animate?3:0)+"%",left:e.left+"%","margin-top":e.marginTop,"margin-left":e.marginLeft},a={top:e.top+"%"}),t(l).css(o).stop(!0,!0).animate(a,"fast")},_modalBtn:function(o){var l=!1,s=n.type,d=o.index(),c=n.buttons[d];if(t.inArray(s,["alert","confirm","prompt"])>-1)e=l=1==d?!0:!1,"prompt"==s&&(e=l=l&&a.find("input.modal-prompt-input").size()>0!=0?a.find("input.modal-prompt-input").val():!1),i._modalHide();else{if(o.hasClass("btn-disabled"))return!1;e=l=c&&c.val?c.val:!0,(!c.onClick||c.onClick(t.extend({val:l,bObj:o,bOpts:c},i.actions)))&&i._modalHide()}e=l},actions:{html:a,close:function(){i._modalHide()},getModal:function(){return a},getBox:function(){return a.find(n._classes.box)},getInner:function(){return a.find(n._classes.boxInner)},getTitle:function(){return a.find(n._classes.title)},getContet:function(){return a.find(n._classes.content)},getButtons:function(){return a.find(n._classes.buttons).find("a")},setTitle:function(t){return a.find(n._classes.title+" h3").html(t),a.find(n._classes.title+" h3").size()>0},setContent:function(t){return a.find(n._classes.content).html(t),a.find(n._classes.content).size()>0}}};return i.init(),i.actions}}(jQuery);
191
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/classes/class.csrf.php DELETED
@@ -1,75 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- /******************************************************************
5
- *
6
- * Projectname: PHP Cross-Site Request Forgery (DUPX_CSRF) Protection Class
7
- * Version: 1.0
8
- * Author: Radovan Janjic <hi@radovanjanjic.com>
9
- * Last modified: 19 06 2014
10
- * Copyright (C): 2014 IT-radionica.com, All Rights Reserved
11
- *
12
- * GNU General Public License (Version 2, June 1991)
13
- *
14
- * This program is free software; you can redistribute
15
- * it and/or modify it under the terms of the GNU
16
- * General Public License as published by the Free
17
- * Software Foundation; either version 2 of the License,
18
- * or (at your option) any later version.
19
- *
20
- * This program is distributed in the hope that it will
21
- * be useful, but WITHOUT ANY WARRANTY; without even the
22
- * implied warranty of MERCHANTABILITY or FITNESS FOR A
23
- * PARTICULAR PURPOSE. See the GNU General Public License
24
- * for more details.
25
- *
26
- ******************************************************************/
27
-
28
- class DUPX_CSRF {
29
-
30
- /** Session var name
31
- * @var string
32
- */
33
- public static $session = '_DUPX_CSRF';
34
-
35
- /** Generate DUPX_CSRF value for form
36
- * @param string $form - Form name as session key
37
- * @return string - token
38
- */
39
- static function generate($form = NULL) {
40
- $token = DUPX_CSRF::token() . DUPX_CSRF::fingerprint();
41
- $_SESSION[DUPX_CSRF::$session . '_' . $form] = $token;
42
- return $token;
43
- }
44
-
45
- /** Check DUPX_CSRF value of form
46
- * @param string $token - Token
47
- * @param string $form - Form name as session key
48
- * @return boolean
49
- */
50
- public static function check($token, $form = NULL) {
51
- if (isset($_SESSION[DUPX_CSRF::$session . '_' . $form]) && $_SESSION[DUPX_CSRF::$session . '_' . $form] == $token) { // token OK
52
- return (substr($token, -32) == DUPX_CSRF::fingerprint()); // fingerprint OK?
53
- }
54
- return FALSE;
55
- }
56
-
57
- /** Generate token
58
- * @param void
59
- * @return string
60
- */
61
- protected static function token() {
62
- mt_srand((double) microtime() * 10000);
63
- $charid = strtoupper(md5(uniqid(rand(), TRUE)));
64
- return substr($charid, 0, 8) . substr($charid, 8, 4) . substr($charid, 12, 4) . substr($charid, 16, 4) . substr($charid, 20, 12);
65
- }
66
-
67
- /** Returns "digital fingerprint" of user
68
- * @param void
69
- * @return string - MD5 hashed data
70
- */
71
- protected static function fingerprint() {
72
- return strtoupper(md5(implode('|', array($_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']))));
73
- }
74
- }
75
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/classes/class.db.php DELETED
@@ -1,215 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- /**
5
- * Lightweight abstraction layer for common simple database routines
6
- *
7
- * Standard: PSR-2
8
- * @link http://www.php-fig.org/psr/psr-2 Full Documentation
9
- *
10
- * @package SC\DUPX\DB
11
- *
12
- */
13
- class DUPX_DB
14
- {
15
-
16
- /**
17
- * MySQL connection wrapper with support for port
18
- *
19
- * @param string $host The server host name
20
- * @param string $username The server DB user name
21
- * @param string $password The server DB password
22
- * @param string $dbname The server DB name
23
- * @param int $port The server DB port
24
- *
25
- * @return database connection handle
26
- */
27
- public static function connect($host, $username, $password, $dbname = '', $port = null)
28
- {
29
- //sock connections
30
- if ('sock' === substr($host, -4)) {
31
- $url_parts = parse_url($host);
32
- $dbh = @mysqli_connect('localhost', $username, $password, $dbname, null, $url_parts['path']);
33
- } else {
34
- $dbh = @mysqli_connect($host, $username, $password, $dbname, $port);
35
- }
36
- return $dbh;
37
- }
38
-
39
- /**
40
- * Count the tables in a given database
41
- *
42
- * @param obj $dbh A valid database link handle
43
- * @param string $dbname Database to count tables in
44
- *
45
- * @return int The number of tables in the database
46
- */
47
- public static function countTables($dbh, $dbname)
48
- {
49
- $res = mysqli_query($dbh, "SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = '".mysqli_real_escape_string($dbh, $dbname)."' ");
50
- $row = mysqli_fetch_row($res);
51
- return is_null($row) ? 0 : $row[0];
52
- }
53
-
54
- /**
55
- * Returns the number of rows in a table
56
- *
57
- * @param obj $dbh A valid database link handle
58
- * @param string $name A valid table name
59
- */
60
- public static function countTableRows($dbh, $name)
61
- {
62
- $total = mysqli_query($dbh, "SELECT COUNT(*) FROM `".mysqli_real_escape_string($dbh, $name)."`");
63
- if ($total) {
64
- $total = @mysqli_fetch_array($total);
65
- return $total[0];
66
- } else {
67
- return 0;
68
- }
69
- }
70
-
71
- /**
72
- * Returns the tables for a database as an array
73
- *
74
- * @param obj $dbh A valid database link handle
75
- *
76
- * @return array A list of all table names
77
- */
78
- public static function getTables($dbh)
79
- {
80
- $query = @mysqli_query($dbh, 'SHOW TABLES');
81
- if ($query) {
82
- while ($table = @mysqli_fetch_array($query)) {
83
- $all_tables[] = $table[0];
84
- }
85
- if (isset($all_tables) && is_array($all_tables)) {
86
- return $all_tables;
87
- }
88
- }
89
- return array();
90
- }
91
-
92
- /**
93
- * Get the requested MySQL system variable
94
- *
95
- * @param obj $dbh A valid database link handle
96
- * @param string $name The database variable name to lookup
97
- *
98
- * @return string the server variable to query for
99
- */
100
- public static function getVariable($dbh, $name)
101
- {
102
- $result = @mysqli_query($dbh, "SHOW VARIABLES LIKE '".mysqli_real_escape_string($dbh, $name)."'");
103
- $row = @mysqli_fetch_array($result);
104
- @mysqli_free_result($result);
105
- return isset($row[1]) ? $row[1] : null;
106
- }
107
-
108
- /**
109
- * Gets the MySQL database version number
110
- *
111
- * @param obj $dbh A valid database link handle
112
- * @param bool $full True: Gets the full version
113
- * False: Gets only the numeric portion i.e. 5.5.6 or 10.1.2 (for MariaDB)
114
- *
115
- * @return false|string 0 on failure, version number on success
116
- */
117
- public static function getVersion($dbh, $full = false)
118
- {
119
- if ($full) {
120
- $version = self::getVariable($dbh, 'version');
121
- } else {
122
- $version = preg_replace('/[^0-9.].*/', '', self::getVariable($dbh, 'version'));
123
- }
124
-
125
- $version = is_null($version) ? null : $version;
126
- return empty($version) ? 0 : $version;
127
- }
128
-
129
- /**
130
- * Returns a more detailed string about the msyql server version
131
- * For example on some systems the result is 5.5.5-10.1.21-MariaDB
132
- * this format is helpful for providing the user a full overview
133
- *
134
- * @param conn $dbh Database connection handle
135
- *
136
- * @return string The full details of mysql
137
- */
138
- public static function getServerInfo($dbh)
139
- {
140
- return mysqli_get_server_info($dbh);
141
- }
142
-
143
- /**
144
- * Get an array of all supported collation names
145
- *
146
- * @param conn $dbh Database connection handle
147
- *
148
- * @return array
149
- */
150
- public static function getSupportedCollationsList($dbh)
151
- {
152
- $collations = array();
153
-
154
- $query = "SHOW COLLATION";
155
- if ($result = $dbh->query($query)) {
156
-
157
- while ($row = $result->fetch_assoc()) {
158
- $collations[] = $row["Collation"];
159
- }
160
-
161
- }
162
- $result->free();
163
-
164
- return $collations;
165
- }
166
-
167
- /**
168
- * Determine if a MySQL database supports a particular feature
169
- *
170
- * @param conn $dbh Database connection handle
171
- * @param string $feature the feature to check for
172
- *
173
- * @return bool
174
- */
175
- public static function hasAbility($dbh, $feature)
176
- {
177
- $version = self::getVersion($dbh);
178
-
179
- switch (strtolower($feature)) {
180
- case 'collation' :
181
- case 'group_concat' :
182
- case 'subqueries' :
183
- return version_compare($version, '4.1', '>=');
184
- case 'set_charset' :
185
- return version_compare($version, '5.0.7', '>=');
186
- };
187
- return false;
188
- }
189
-
190
- /**
191
- * Sets the MySQL connection's character set.
192
- *
193
- * @param resource $dbh The resource given by mysqli_connect
194
- * @param string $charset The character set (optional)
195
- * @param string $collate The collation (optional)
196
- *
197
- * @return bool True on success
198
- */
199
- public static function setCharset($dbh, $charset = null, $collate = null)
200
- {
201
- $charset = (!isset($charset) ) ? $GLOBALS['DBCHARSET_DEFAULT'] : $charset;
202
- $collate = (!isset($collate) ) ? $GLOBALS['DBCOLLATE_DEFAULT'] : $collate;
203
-
204
- if (self::hasAbility($dbh, 'collation') && !empty($charset)) {
205
- if (function_exists('mysqli_set_charset') && self::hasAbility($dbh, 'set_charset')) {
206
- return mysqli_set_charset($dbh, $charset);
207
- } else {
208
- $sql = " SET NAMES ".mysqli_real_escape_string($dbh, $charset);
209
- if (!empty($collate)) $sql .= " COLLATE ".mysqli_real_escape_string($dbh, $collate);
210
- return mysqli_query($dbh, $sql);
211
- }
212
- }
213
- }
214
- }
215
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/classes/class.engine.php DELETED
@@ -1,450 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- /**
5
- * Walks every table in db that then walks every row and column replacing searches with replaces
6
- * large tables are split into 50k row blocks to save on memory.
7
- *
8
- * Standard: PSR-2
9
- * @link http://www.php-fig.org/psr/psr-2 Full Documentation
10
- *
11
- * @package SC\DUPX\UpdateEngine
12
- *
13
- */
14
- class DUPX_UpdateEngine
15
- {
16
-
17
- /**
18
- * Used to report on all log errors into the installer-txt.log
19
- *
20
- * @param string $report The report error array of all error types
21
- *
22
- * @return string Writes the results of the update engine tables to the log
23
- */
24
- public static function logErrors($report)
25
- {
26
- if (!empty($report['errsql'])) {
27
- DUPX_Log::info("--------------------------------------");
28
- DUPX_Log::info("DATA-REPLACE ERRORS (MySQL)");
29
- foreach ($report['errsql'] as $error) {
30
- DUPX_Log::info($error);
31
- }
32
- DUPX_Log::info("");
33
- }
34
- if (!empty($report['errser'])) {
35
- DUPX_Log::info("--------------------------------------");
36
- DUPX_Log::info("DATA-REPLACE ERRORS (Serialization):");
37
- foreach ($report['errser'] as $error) {
38
- DUPX_Log::info($error);
39
- }
40
- DUPX_Log::info("");
41
- }
42
- if (!empty($report['errkey'])) {
43
- DUPX_Log::info("--------------------------------------");
44
- DUPX_Log::info("DATA-REPLACE ERRORS (Key):");
45
- DUPX_Log::info('Use SQL: SELECT @row := @row + 1 as row, t.* FROM some_table t, (SELECT @row := 0) r');
46
- foreach ($report['errkey'] as $error) {
47
- DUPX_Log::info($error);
48
- }
49
- }
50
- }
51
-
52
- /**
53
- * Used to report on all log stats into the installer-txt.log
54
- *
55
- * @param string $report The report stats array of all error types
56
- *
57
- * @return string Writes the results of the update engine tables to the log
58
- */
59
- public static function logStats($report)
60
- {
61
- if (!empty($report) && is_array($report)) {
62
- $stats = "--------------------------------------\n";
63
- $srchnum = 0;
64
- foreach ($GLOBALS['REPLACE_LIST'] as $item) {
65
- $srchnum++;
66
- $stats .= sprintf("Search{$srchnum}:\t'%s' \nChange{$srchnum}:\t'%s' \n", $item['search'], $item['replace']);
67
- }
68
- $stats .= sprintf("SCANNED:\tTables:%d \t|\t Rows:%d \t|\t Cells:%d \n", $report['scan_tables'], $report['scan_rows'], $report['scan_cells']);
69
- $stats .= sprintf("UPDATED:\tTables:%d \t|\t Rows:%d \t|\t Cells:%d \n", $report['updt_tables'], $report['updt_rows'], $report['updt_cells']);
70
- $stats .= sprintf("ERRORS:\t\t%d \nRUNTIME:\t%f sec", $report['err_all'], $report['time']);
71
- DUPX_Log::info($stats);
72
- }
73
- }
74
-
75
- /**
76
- * Returns only the text type columns of a table ignoring all numeric types
77
- *
78
- * @param obj $dbh A valid database link handle
79
- * @param string $table A valid table name
80
- *
81
- * @return array All the column names of a table
82
- */
83
- public static function getTextColumns($dbh, $table)
84
- {
85
- $type_where = "type NOT LIKE 'tinyint%' AND ";
86
- $type_where .= "type NOT LIKE 'smallint%' AND ";
87
- $type_where .= "type NOT LIKE 'mediumint%' AND ";
88
- $type_where .= "type NOT LIKE 'int%' AND ";
89
- $type_where .= "type NOT LIKE 'bigint%' AND ";
90
- $type_where .= "type NOT LIKE 'float%' AND ";
91
- $type_where .= "type NOT LIKE 'double%' AND ";
92
- $type_where .= "type NOT LIKE 'decimal%' AND ";
93
- $type_where .= "type NOT LIKE 'numeric%' AND ";
94
- $type_where .= "type NOT LIKE 'date%' AND ";
95
- $type_where .= "type NOT LIKE 'time%' AND ";
96
- $type_where .= "type NOT LIKE 'year%' ";
97
-
98
- $result = mysqli_query($dbh, "SHOW COLUMNS FROM `".mysqli_real_escape_string($dbh, $table)."` WHERE {$type_where}");
99
- if (!$result) {
100
- return null;
101
- }
102
- $fields = array();
103
- if (mysqli_num_rows($result) > 0) {
104
- while ($row = mysqli_fetch_assoc($result)) {
105
- $fields[] = $row['Field'];
106
- }
107
- }
108
-
109
- //Return Primary which is needed for index lookup
110
- //$result = mysqli_query($dbh, "SHOW INDEX FROM `{$table}` WHERE KEY_NAME LIKE '%PRIMARY%'"); 1.1.15 updated
111
- $result = mysqli_query($dbh, "SHOW INDEX FROM `".mysqli_real_escape_string($dbh, $table)."`");
112
- if (mysqli_num_rows($result) > 0) {
113
- while ($row = mysqli_fetch_assoc($result)) {
114
- $fields[] = $row['Column_name'];
115
- }
116
- }
117
-
118
- return (count($fields) > 0) ? $fields : null;
119
- }
120
-
121
- /**
122
- * Begins the processing for replace logic
123
- *
124
- * @param mysql $dbh The db connection object
125
- * @param array $list Key value pair of 'search' and 'replace' arrays
126
- * @param array $tables The tables we want to look at
127
- * @param array $fullsearch Search every column regardless of its data type
128
- *
129
- * @return array Collection of information gathered during the run.
130
- */
131
- public static function load($dbh, $list = array(), $tables = array(), $fullsearch = false)
132
- {
133
- $report = array(
134
- 'scan_tables' => 0,
135
- 'scan_rows' => 0,
136
- 'scan_cells' => 0,
137
- 'updt_tables' => 0,
138
- 'updt_rows' => 0,
139
- 'updt_cells' => 0,
140
- 'errsql' => array(),
141
- 'errser' => array(),
142
- 'errkey' => array(),
143
- 'errsql_sum' => 0,
144
- 'errser_sum' => 0,
145
- 'errkey_sum' => 0,
146
- 'time' => '',
147
- 'err_all' => 0
148
- );
149
-
150
- function set_sql_column_safe(&$str) {
151
- $str = "`$str`";
152
- }
153
-
154
- $profile_start = DUPX_U::getMicrotime();
155
- if (is_array($tables) && !empty($tables)) {
156
-
157
- foreach ($tables as $table) {
158
- $report['scan_tables'] ++;
159
- $columns = array();
160
-
161
- // Get a list of columns in this table
162
- $fields = mysqli_query($dbh, 'DESCRIBE '.mysqli_real_escape_string($dbh, $table));
163
- while ($column = mysqli_fetch_array($fields)) {
164
- $columns[$column['Field']] = $column['Key'] == 'PRI' ? true : false;
165
- }
166
-
167
- // Count the number of rows we have in the table if large we'll split into blocks
168
- $row_count = mysqli_query($dbh, "SELECT COUNT(*) FROM `".mysqli_real_escape_string($dbh, $table)."`");
169
- $rows_result = mysqli_fetch_array($row_count);
170
- @mysqli_free_result($row_count);
171
- $row_count = $rows_result[0];
172
- if ($row_count == 0) {
173
- DUPX_Log::info("{$table}^ ({$row_count})");
174
- continue;
175
- }
176
-
177
- $page_size = 25000;
178
- $offset = ($page_size + 1);
179
- $pages = ceil($row_count / $page_size);
180
-
181
- // Grab the columns of the table. Only grab text based columns because
182
- // they are the only data types that should allow any type of search/replace logic
183
- $colList = '*';
184
- $colMsg = '*';
185
- if (!$fullsearch) {
186
- $colList = self::getTextColumns($dbh, $table);
187
- if ($colList != null && is_array($colList)) {
188
- array_walk($colList, set_sql_column_safe);
189
- $colList = implode(',', $colList);
190
- }
191
- $colMsg = (empty($colList)) ? '*' : '~';
192
- }
193
-
194
- if (empty($colList)) {
195
- DUPX_Log::info("{$table}^ ({$row_count})");
196
- continue;
197
- } else {
198
- DUPX_Log::info("{$table}{$colMsg} ({$row_count})");
199
- }
200
-
201
- //Paged Records
202
- for ($page = 0; $page < $pages; $page++) {
203
- $current_row = 0;
204
- $start = $page * $page_size;
205
- $end = $start + $page_size;
206
- $sql = sprintf("SELECT {$colList} FROM `%s` LIMIT %d, %d", mysqli_real_escape_string($dbh, $table), $start, $offset);
207
- $data = mysqli_query($dbh, $sql);
208
-
209
- if (!$data) $report['errsql'][] = mysqli_error($dbh);
210
-
211
- $scan_count = ($row_count < $end) ? $row_count : $end;
212
- DUPX_Log::info("\tScan => {$start} of {$scan_count}", 2);
213
-
214
- //Loops every row
215
- while ($row = mysqli_fetch_array($data)) {
216
- $report['scan_rows'] ++;
217
- $current_row++;
218
- $upd_col = array();
219
- $upd_sql = array();
220
- $where_sql = array();
221
- $upd = false;
222
- $serial_err = 0;
223
- $is_unkeyed = !in_array(true,$columns);
224
-
225
- //Loops every cell
226
- foreach ($columns as $column => $primary_key) {
227
- $report['scan_cells'] ++;
228
- $edited_data = $data_to_fix = $row[$column];
229
- $base64converted = false;
230
- $txt_found = false;
231
-
232
- //Unkeyed table code
233
- //Added this here to add all columns to $where_sql
234
- //The if statement with $txt_found would skip additional columns
235
- if($is_unkeyed && ! empty($data_to_fix)) {
236
- $where_sql[] = $column.' = "'.mysqli_real_escape_string($dbh, $data_to_fix).'"';
237
- }
238
-
239
- //Only replacing string values
240
- if (!empty($row[$column]) && !is_numeric($row[$column]) && $primary_key != 1) {
241
- //Base 64 detection
242
- if (base64_decode($row[$column], true)) {
243
- $decoded = base64_decode($row[$column], true);
244
- if (self::isSerialized($decoded)) {
245
- $edited_data = $decoded;
246
- $base64converted = true;
247
- }
248
- }
249
-
250
- //Skip table cell if match not found
251
- foreach ($list as $item) {
252
- if (strpos($edited_data, $item['search']) !== false) {
253
- $txt_found = true;
254
- break;
255
- }
256
- }
257
- if (!$txt_found) {
258
- continue;
259
- }
260
-
261
- //Replace logic - level 1: simple check on any string or serialized strings
262
- foreach ($list as $item) {
263
- $edited_data = self::recursiveUnserializeReplace($item['search'], $item['replace'], $edited_data);
264
- }
265
-
266
- //Replace logic - level 2: repair serialized strings that have become broken
267
- $serial_check = self::fixSerialString($edited_data);
268
- if ($serial_check['fixed']) {
269
- $edited_data = $serial_check['data'];
270
- } elseif ($serial_check['tried'] && !$serial_check['fixed']) {
271
- $serial_err++;
272
- }
273
- }
274
-
275
- //Change was made
276
- if ($edited_data != $data_to_fix || $serial_err > 0) {
277
- $report['updt_cells'] ++;
278
- //Base 64 encode
279
- if ($base64converted) {
280
- $edited_data = base64_encode($edited_data);
281
- }
282
- $upd_col[] = $column;
283
- $upd_sql[] = $column.' = "'.mysqli_real_escape_string($dbh, $edited_data).'"';
284
- $upd = true;
285
- }
286
-
287
- if ($primary_key) {
288
- $where_sql[] = $column.' = "'.mysqli_real_escape_string($dbh, $data_to_fix).'"';
289
- }
290
- }
291
-
292
- //PERFORM ROW UPDATE
293
- if ($upd && !empty($where_sql)) {
294
- $sql = "UPDATE `".mysqli_real_escape_string($dbh, $table)."` SET ".implode(', ', $upd_sql).' WHERE '.implode(' AND ', array_filter($where_sql));
295
- $result = mysqli_query($dbh, $sql);
296
- if ($result) {
297
- if ($serial_err > 0) {
298
- $report['errser'][] = "SELECT " . implode(', ', $upd_col) . " FROM `{$table}` WHERE " . implode(' AND ', array_filter($where_sql)) . ';';
299
- }
300
- $report['updt_rows']++;
301
- } else {
302
- $report['errsql'][] = ($GLOBALS["LOGGING"] == 1)
303
- ? 'DB ERROR: ' . mysqli_error($dbh)
304
- : 'DB ERROR: ' . mysqli_error($dbh) . "\nSQL: [{$sql}]\n";
305
- }
306
-
307
- //DEBUG ONLY:
308
- DUPX_Log::info("\t{$sql}\n", 3);
309
-
310
- } elseif ($upd) {
311
- $report['errkey'][] = sprintf("Row [%s] on Table [%s] requires a manual update.", $current_row, $table);
312
- }
313
- }
314
- //DUPX_U::fcgiFlush();
315
- @mysqli_free_result($data);
316
- }
317
-
318
- if ($upd) {
319
- $report['updt_tables'] ++;
320
- }
321
- }
322
- }
323
- $profile_end = DUPX_U::getMicrotime();
324
- $report['time'] = DUPX_U::elapsedTime($profile_end, $profile_start);
325
- $report['errsql_sum'] = empty($report['errsql']) ? 0 : count($report['errsql']);
326
- $report['errser_sum'] = empty($report['errser']) ? 0 : count($report['errser']);
327
- $report['errkey_sum'] = empty($report['errkey']) ? 0 : count($report['errkey']);
328
- $report['err_all'] = $report['errsql_sum'] + $report['errser_sum'] + $report['errkey_sum'];
329
- return $report;
330
- }
331
-
332
- /**
333
- * Take a serialized array and unserialized it replacing elements and
334
- * unserializing any subordinate arrays and performing the replace.
335
- *
336
- * @param string $from String we're looking to replace.
337
- * @param string $to What we want it to be replaced with
338
- * @param array $data Used to pass any subordinate arrays back to in.
339
- * @param bool $serialised Does the array passed via $data need serializing.
340
- *
341
- * @return array The original array with all elements replaced as needed.
342
- */
343
- public static function recursiveUnserializeReplace($from = '', $to = '', $data = '', $serialised = false)
344
- {
345
- // some unseriliased data cannot be re-serialised eg. SimpleXMLElements
346
- try {
347
- if (is_string($data) && ($unserialized = @unserialize($data)) !== false) {
348
- $data = self::recursiveUnserializeReplace($from, $to, $unserialized, true);
349
- } elseif (is_array($data)) {
350
- $_tmp = array();
351
- foreach ($data as $key => $value) {
352
- $_tmp[$key] = self::recursiveUnserializeReplace($from, $to, $value, false);
353
- }
354
- $data = $_tmp;
355
- unset($_tmp);
356
-
357
- /* CJL
358
- Check for an update to the key of an array e.g. [http://localhost/projects/wpplugins/] => 1.41
359
- This could have unintended consequences would need to enable with full-search needs more testing
360
- if (array_key_exists($from, $data))
361
- {
362
- $data[$to] = $data[$from];
363
- unset($data[$from]);
364
- } */
365
- } elseif (is_object($data)) {
366
- /* RSR Old logic that didn't work with Beaver Builder - they didn't want to create a brand new
367
- object instead reused the existing one...
368
- $dataClass = get_class($data);
369
- $_tmp = new $dataClass();
370
- foreach ($data as $key => $value) {
371
- $_tmp->$key = self::recursiveUnserializeReplace($from, $to, $value, false);
372
- }
373
- $data = $_tmp;
374
- unset($_tmp); */
375
-
376
- // RSR NEW LOGIC
377
- $_tmp = $data;
378
- $props = get_object_vars($data);
379
- foreach ($props as $key => $value) {
380
- $_tmp->$key = self::recursiveUnserializeReplace($from, $to, $value, false);
381
- }
382
- $data = $_tmp;
383
- unset($_tmp);
384
- } else {
385
- if (is_string($data)) {
386
- $data = str_replace($from, $to, $data);
387
- }
388
- }
389
-
390
- if ($serialised) return serialize($data);
391
- } catch (Exception $error) {
392
- DUPX_Log::info("\nRECURSIVE UNSERIALIZE ERROR: With string\n".$error, 2);
393
- }
394
- return $data;
395
- }
396
-
397
- /**
398
- * Test if a string in properly serialized
399
- *
400
- * @param string $data Any string type
401
- *
402
- * @return bool Is the string a serialized string
403
- */
404
- public static function isSerialized($data)
405
- {
406
- $test = @unserialize(($data));
407
- return ($test !== false || $test === 'b:0;') ? true : false;
408
- }
409
-
410
- /**
411
- * Fixes the string length of a string object that has been serialized but the length is broken
412
- *
413
- * @param string $data The string ojbect to recalculate the size on.
414
- *
415
- * @return string A serialized string that fixes and string length types
416
- */
417
- public static function fixSerialString($data)
418
- {
419
- $result = array('data' => $data, 'fixed' => false, 'tried' => false);
420
- if (preg_match("/s:[0-9]+:/", $data)) {
421
- if (!self::isSerialized($data)) {
422
- $regex = '!(?<=^|;)s:(\d+)(?=:"(.*?)";(?:}|a:|s:|b:|d:|i:|o:|N;))!s';
423
- $serial_string = preg_match('/^s:[0-9]+:"(.*$)/s', trim($data), $matches);
424
- //Nested serial string
425
- if ($serial_string) {
426
- $inner = preg_replace_callback($regex, 'DUPX_UpdateEngine::fixStringCallback', rtrim($matches[1], '";'));
427
- $serialized_fixed = 's:'.strlen($inner).':"'.$inner.'";';
428
- } else {
429
- $serialized_fixed = preg_replace_callback($regex, 'DUPX_UpdateEngine::fixStringCallback', $data);
430
- }
431
-
432
- if (self::isSerialized($serialized_fixed)) {
433
- $result['data'] = $serialized_fixed;
434
- $result['fixed'] = true;
435
- }
436
- $result['tried'] = true;
437
- }
438
- }
439
- return $result;
440
- }
441
-
442
- /**
443
- * The call back method call from via fixSerialString
444
- */
445
- private static function fixStringCallback($matches)
446
- {
447
- return 's:'.strlen(($matches[2]));
448
- }
449
- }
450
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/classes/class.logging.php DELETED
@@ -1,67 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- define('ERR_CONFIG_FOUND', 'A wp-config.php already exists in this location. This error prevents users from accidentally overwriting the wrong directories contents. You have three options: <ul><li>Empty this root directory except for the package and installer and try again.</li><li>Delete just the wp-config.php file and try again. This will over-write all other files in the directory.</li><li>Check the "Manual package extraction" checkbox under advanced options to skip extraction</li></ul>');
5
- define('ERR_ZIPNOTFOUND', 'The packaged zip file was not found. Be sure the zip package is in the same directory as the installer file and as the correct permissions. If you are trying to reinstall a package you can copy the package from the "' . DUPLICATOR_SSDIR_NAME . '" directory back up to your root which is the same location as your installer.php file.');
6
- define('ERR_ZIPOPEN', 'Failed to open zip archive file. Please be sure the archive is completely downloaded before running the installer. Try to extract the archive manually to make sure the file is not corrupted.');
7
- define('ERR_ZIPEXTRACTION', 'Errors extracting zip file. Portions or part of the zip archive did not extract correctly. Try to extract the archive manually with a client side program like unzip/win-zip/winrar or your hosts cPanel to make sure the file is not corrupted. If the file extracts correctly then there is an invalid file or directory that PHP is unable to extract. This can happen if your moving from one operating system to another where certain naming conventions work on one environment and not another. <br/><br/> <b>Workarounds:</b> <br/> 1. Create a new package and be sure to exclude any directories that have invalid names or files in them. This warning will be displayed on the scan results under "Name Checks". <br/> 2. Manually extract the zip file with a client side program or your hosts cPanel. Then under options in step 1 of this installer check the "Manual Archive Extraction" option and perform the install.');
8
- define('ERR_ZIPMANUAL', "When choosing manual package extraction, the contents of the package must already be extracted and the wp-config.php and dup-database__{$GLOBALS['PACKAGE_HASH']}.sql files must be present in the same directory as the installer.php for the process to continue. Please manually extract the package into the current directory before continuing in manual extraction mode. Also validate that the wp-config.php and dup-database__[HASH].sql files are present.");
9
- define('ERR_MAKELOG', 'PHP is having issues writing to the log file <b>' . DUPX_U::setSafePath($GLOBALS['CURRENT_ROOT_PATH']) . '\".$GLOBALS["LOG_FILE_NAME"]." .</b> In order for the Duplicator to proceed validate your owner/group and permission settings for PHP on this path. Try temporarily setting you permissions to 777 to see if the issue gets resolved. If you are on a shared hosting environment please contact your hosting company and tell them you are getting errors writing files to the path above when using PHP.');
10
- define('ERR_ZIPARCHIVE', 'In order to extract the archive.zip file the PHP ZipArchive module must be installed. Please read the FAQ for more details. You can still install this package but you will need to check the Manual package extraction checkbox found in the Advanced Options. Please read the online user guide for details in performing a manual package extraction.');
11
- define('ERR_MYSQLI_SUPPORT', 'In order to complete an install the mysqli extension for PHP is required. If you are on a hosted server please contact your host and request that mysqli be enabled. For more information visit: http://php.net/manual/en/mysqli.installation.php');
12
- define('ERR_DBCONNECT', 'DATABASE CONNECTION FAILED!<br/>');
13
- define('ERR_DBCONNECT_INFO', '<b>DATABASE CONNECTION FAILED!</b><br/>If the problem persists see the online FAQ for <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-100-q" target="_blank">recommended fixes</a>.');
14
- define('ERR_DBCONNECT_CREATE', 'DATABASE CREATION FAILURE!<br/> Unable to create database "%s". Check to make sure the user has "Create" privileges. Some hosts will restrict creation of a database only through the cpanel. Try creating the database manually to proceed with installation. If the database already exists then check the radio button labeled "Connect and Remove All Data" which will remove all existing tables.');
15
- define('ERR_DBTRYCLEAN', 'DATABASE CREATION FAILURE!<br/> Unable to remove all tables from database "%s".<br/> Please remove all tables from this database and try the installation again.');
16
- define('ERR_DBCREATE', 'The database "%s" does not exists.<br/> Change mode to create in order to create a new database.');
17
- define('ERR_DBEMPTY', 'The database "%s" has "%s" tables. The Duplicator only works with an EMPTY database. Enable the action "Connect and Remove All Data" radio button to remove all tables and or create a new database. Some hosting providers do not allow table removal from scripts. In this case you will need to login to your hosting providers control panel and remove the tables manually. Please contact your hosting provider for further details. Always backup all your data before proceeding!');
18
- define('ERR_TESTDB_UTF8', 'UTF8 Characters were detected as part of the database connection string. If your connection fails be sure to update the MySQL my.ini configuration file setting to support UTF8 characters by enabling this option [character_set_server=utf8] and restarting the database server.');
19
- define('ERR_TESTDB_VERSION_INFO', 'If the current version detected is below 5.5.3 (release on April 8th 2010) then support for utf8mb4 tables will not work. The utf8mb4 format is only supported in MySQL server 5.5.3+. It is highly recommended to upgrade your version of MySQL server on this server to be more compatible with recent releases of WordPress and avoid issues with install errors.');
20
- define('ERR_TESTDB_VERSION_COMPAT', 'In order to avoid database incompatibility issues make sure the database versions between the build and installer servers are as close as possible. If the package was created on a newer database version than where it is being installed then you might run into issues.<br/><br/> It is best to make sure the server where the installer is running has the same or higher version number than where it was built. If the major and minor version are the same or close for example [5.7 to 5.6], then the migration should work without issues. A version pair of [5.7 to 5.1] is more likely to cause issues unless you have a very simple setup. If the versions are too far apart work with your hosting provider to upgrade the MySQL engine on this server.<br/><br/> <b>MariaDB:</b> If a version of 10.N.N shows then the database distribution is a MariaDB flavor of MySQL. While the distributions are very close there are some subtle differences. Some operating systems will report the version such as "5.5.5-10.1.21-MariaDB" showing the correlation of both. Please visit the online <a href="https://mariadb.com/kb/en/mariadb/mariadb-vs-mysql-compatibility/" target="_blank">MariaDB versus MySQL - Compatibility</a> page for more details.<br/><br/> Please note these messages are simply notices. It is highly recommended that you continue with the install process and closely monitor the <?php echo DUPX_U::esc_html($GLOBALS["LOG_FILE_NAME"]);?> file along with the install report found on step 3 of the installer. Be sure to look for any notices/warnings/errors in these locations to validate the install process did not detect any errors. If any issues are found please visit the FAQ pages and see the question <a href="https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=database_incompatibility#faq-installer-260-q" target="_blank">What if I get database errors or general warnings on the install report?</a>.');
21
-
22
- /**
23
- * Class used to log information to the installer-log.txt file
24
- *
25
- * Standard: PSR-2
26
- * @link http://www.php-fig.org/psr/psr-2 Full Documentation
27
- *
28
- * @package SC\DUPX\Log
29
- *
30
- */
31
- class DUPX_Log
32
- {
33
-
34
- /**
35
- * Used to write debug info to the text log file
36
- *
37
- * @param string $msg Any text data
38
- * @param int $loglevel Log level
39
- *
40
- * @return string Write info to both the log and browser
41
- */
42
- public static function info($msg, $logging = 1)
43
- {
44
- if ($logging <= $GLOBALS["LOGGING"]) {
45
- @fwrite($GLOBALS["LOG_FILE_HANDLE"], "{$msg}\n");
46
- }
47
- }
48
-
49
- /**
50
- * Used to write errors to the text log file
51
- *
52
- * @param string $msg Any text data
53
- * @param int $loglevel Log level
54
- *
55
- * @return string Write errors to both the log and browser
56
- */
57
- public static function error($msg)
58
- {
59
- $breaks = array("<br />","<br>","<br/>");
60
- $log_msg = str_ireplace($breaks, "\r\n", $msg);
61
- $log_msg = strip_tags($log_msg);
62
- @fwrite($GLOBALS["LOG_FILE_HANDLE"], "\nINSTALLER ERROR:\n{$log_msg}\n");
63
- @fclose($GLOBALS["LOG_FILE_HANDLE"]);
64
- die("<div class='dupx-ui-error'><hr size='1' /><b style='color:#B80000;'>INSTALL ERROR!</b><br/>{$msg}</div>");
65
- }
66
- }
67
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/classes/class.server.php DELETED
@@ -1,183 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- /**
5
- * Lightweight abstraction layer for common simple server based routines
6
- *
7
- * Standard: PSR-2
8
- * @link http://www.php-fig.org/psr/psr-2 Full Documentation
9
- *
10
- * @package SC\DUPX\Server
11
- *
12
- */
13
- class DUPX_Server
14
- {
15
- /**
16
- * Returns true if safe mode is enabled
17
- */
18
- public static $php_safe_mode_on = false;
19
-
20
- /**
21
- * The servers current PHP version
22
- */
23
- public static $php_version = 0;
24
-
25
- /**
26
- * The minimum PHP version the installer will support
27
- */
28
- public static $php_version_min = "5.2.7";
29
-
30
- /**
31
- * Is the current servers version of PHP safe to use with the installer
32
- */
33
- public static $php_version_safe = false;
34
-
35
-
36
- /**
37
- * Is PHP 5.3 or better running
38
- */
39
- public static $php_version_53_plus;
40
-
41
- /**
42
- * Used to init the static properties
43
- */
44
- public static function init()
45
- {
46
- self::$php_safe_mode_on = in_array(strtolower(@ini_get('safe_mode')), array('on', 'yes', 'true', 1, "1"));
47
- self::$php_version = phpversion();
48
- self::$php_version_safe = DUPX_U::isVersion(self::$php_version_min);
49
- self::$php_version_53_plus = DUPX_U::isVersion('5.3.0');
50
- }
51
-
52
- /**
53
- * Is the directory provided writable by PHP
54
- *
55
- * @param string $path A physical directory path
56
- *
57
- * @return bool Returns true if PHP can write to the path provided
58
- */
59
- public static function isDirWritable($path)
60
- {
61
- if (!@is_writeable($path)) return false;
62
-
63
- if (is_dir($path)) {
64
- if ($dh = @opendir($path)) {
65
- closedir($dh);
66
- } else {
67
- return false;
68
- }
69
- }
70
- return true;
71
- }
72
-
73
- /**
74
- * Can this server process in shell_exec mode
75
- *
76
- * @return bool Returns true is the server can run shell_exec commands
77
- */
78
- public static function hasShellExec()
79
- {
80
- if (array_intersect(array('shell_exec', 'escapeshellarg', 'escapeshellcmd', 'extension_loaded'), array_map('trim', explode(',', @ini_get('disable_functions'))))) return false;
81
-
82
- //Suhosin: http://www.hardened-php.net/suhosin/
83
- //Will cause PHP to silently fail.
84
- if (extension_loaded('suhosin')) return false;
85
-
86
- // Can we issue a simple echo command?
87
- if (!@shell_exec('echo duplicator')) return false;
88
-
89
- return true;
90
- }
91
-
92
- /**
93
- * Returns the path where the zip command can be called on this server
94
- *
95
- * @return string The path to where the zip command can be processed
96
- */
97
- public static function getUnzipPath()
98
- {
99
- $filepath = null;
100
- if (self::hasShellExec()) {
101
- if (shell_exec('hash unzip 2>&1') == NULL) {
102
- $filepath = 'unzip';
103
- } else {
104
- $try_paths = array(
105
- '/usr/bin/unzip',
106
- '/opt/local/bin/unzip');
107
- foreach ($try_paths as $path) {
108
- if (file_exists($path)) {
109
- $filepath = $path;
110
- break;
111
- }
112
- }
113
- }
114
- }
115
- return $filepath;
116
- }
117
-
118
-
119
- /**
120
- * A safe method used to copy larger files
121
- *
122
- * @param string $source The path to the file being copied
123
- * @param string $destination The path to the file being made
124
- *
125
- * @return bool True if the file was copied
126
- */
127
- public static function copyFile($source, $destination)
128
- {
129
- try {
130
- $sp = fopen($source, 'r');
131
- $op = fopen($destination, 'w');
132
-
133
- while (!feof($sp)) {
134
- $buffer = fread($sp, 512); // use a buffer of 512 bytes
135
- fwrite($op, $buffer);
136
- }
137
- // close handles
138
- fclose($op);
139
- fclose($sp);
140
- return true;
141
-
142
- } catch (Exception $ex) {
143
- return false;
144
- }
145
- }
146
-
147
-
148
- /**
149
- * Returns an array of zip files found in the current executing directory
150
- *
151
- * @return array of zip files
152
- */
153
- public static function getZipFiles()
154
- {
155
- $files = array();
156
- foreach (glob("*.zip") as $name) {
157
- if (file_exists($name)) {
158
- $files[] = $name;
159
- }
160
- }
161
-
162
- if (count($files) > 0) {
163
- return $files;
164
- }
165
-
166
- //FALL BACK: Windows XP has bug with glob,
167
- //add secondary check for PHP lameness
168
- if ($dh = opendir('.')) {
169
- while (false !== ($name = readdir($dh))) {
170
- $ext = substr($name, strrpos($name, '.') + 1);
171
- if (in_array($ext, array("zip"))) {
172
- $files[] = $name;
173
- }
174
- }
175
- closedir($dh);
176
- }
177
-
178
- return $files;
179
- }
180
- }
181
- //INIT Class Properties
182
- DUPX_Server::init();
183
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/classes/config/class.conf.srv.php DELETED
@@ -1,113 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
- /**
4
- * Class used to update and edit web server configuration files
5
- *
6
- * Standard: PSR-2
7
- * @link http://www.php-fig.org/psr/psr-2 Full Documentation
8
- *
9
- * @package SC\DUPX\ServerConfig
10
- *
11
- */
12
- class DUPX_ServerConfig
13
- {
14
-
15
- /**
16
- * Clear .htaccess and web.config files and backup
17
- *
18
- * @return null
19
- */
20
- public static function reset()
21
- {
22
-
23
-
24
- DUPX_Log::info("\nWEB SERVER CONFIGURATION FILE RESET:");
25
- $timeStamp = date("ymdHis");
26
-
27
- //Apache
28
- @copy('.htaccess', ".htaccess.{$timeStamp}.orig");
29
- @unlink('.htaccess');
30
- @file_put_contents('.htaccess', "#Reset by Duplicator Installer. Original can be found in .htaccess.{$timeStamp}.orig");
31
-
32
- //IIS
33
- @copy('web.config', "web.config.{$timeStamp}.orig");
34
- @unlink('web.config');
35
- $xml_contents = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
36
- $xml_contents .= "<!-- Reset by Duplicator Installer. Original can be found in web.config.{$timeStamp}.orig -->\n";
37
- $xml_contents .= "<configuration></configuration>\n";
38
- @file_put_contents('web.config', $xml_contents);
39
-
40
- //.user.ini - For WordFence
41
- @copy('.user.ini', ".user.ini.{$timeStamp}.orig");
42
- @unlink('.user.ini');
43
-
44
- DUPX_Log::info("- Backup of .htaccess/web.config made to *.{$timeStamp}.orig");
45
- DUPX_Log::info("- Reset of .htaccess/web.config files");
46
-
47
-
48
- @chmod('.htaccess', 0644);
49
- }
50
-
51
- /**
52
- * Resets the .htaccess file to a very slimed down version with new paths
53
- *
54
- * @return null
55
- */
56
- public static function setup($dbh)
57
- {
58
- if (!isset($_POST['url_new'])) {
59
- return;
60
- }
61
-
62
- DUPX_Log::info("\nWEB SERVER CONFIGURATION FILE BASIC SETUP:");
63
- $post_url_old = DUPX_U::sanitize_text_field($_POST['url_old']);
64
- $currdata = parse_url($_POST['url_old']);
65
- $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
66
- $newdata = parse_url($post_url_new);
67
- $currpath = DUPX_U::addSlash(isset($currdata['path']) ? $currdata['path'] : "");
68
- $newpath = DUPX_U::addSlash(isset($newdata['path']) ? $newdata['path'] : "");
69
- $timestamp = date("Y-m-d H:i:s");
70
- $update_msg = "# This file was updated by Duplicator on {$timestamp}. See .htaccess.orig for the original .htaccess file.\n";
71
- $update_msg .= "# Please note that other plugins and resources write to this file. If the time-stamp above is different\n";
72
- $update_msg .= "# than the current time-stamp on the file system then another resource has updated this file.\n";
73
- $update_msg .= "# Duplicator only writes to this file once during the install process while running the installer.php file.\n";
74
-
75
- $empty_htaccess = false;
76
- $query_result = @mysqli_query($dbh, "SELECT option_value FROM `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."options` WHERE option_name = 'permalink_structure' ");
77
-
78
- //If the permalink is set to Plain then don't update the rewrite rules
79
- if ($query_result) {
80
- $row = @mysqli_fetch_array($query_result);
81
- if ($row != null) {
82
- $permalink_structure = trim($row[0]);
83
- $empty_htaccess = empty($permalink_structure);
84
- }
85
- }
86
-
87
- if ($empty_htaccess) {
88
- $tmp_htaccess = "{$update_msg}";
89
- DUPX_Log::info("- No permalink structures set creating blank .htaccess file.");
90
- } else {
91
- $tmp_htaccess = <<<HTACCESS
92
- {$update_msg}
93
- # BEGIN WordPress
94
- <IfModule mod_rewrite.c>
95
- RewriteEngine On
96
- RewriteBase {$newpath}
97
- RewriteRule ^index\.php$ - [L]
98
- RewriteCond %{REQUEST_FILENAME} !-f
99
- RewriteCond %{REQUEST_FILENAME} !-d
100
- RewriteRule . {$newpath}index.php [L]
101
- </IfModule>
102
- # END WordPress
103
- HTACCESS;
104
- DUPX_Log::info("- Preparing .htaccess file with basic setup.");
105
- }
106
-
107
- file_put_contents('.htaccess', $tmp_htaccess);
108
- @chmod('.htaccess', 0644);
109
- DUPX_Log::info("Basic .htaccess file edit complete. If using IIS web.config this process will need to be done manually.");
110
-
111
- }
112
- }
113
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/classes/config/class.conf.wp.php DELETED
@@ -1,246 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
- /**
4
- * Class used to update and edit and update the wp-config.php
5
- *
6
- * Standard: PSR-2
7
- * @link http://www.php-fig.org/psr/psr-2 Full Documentation
8
- *
9
- * @package SC\DUPX\WPConfig
10
- *
11
- */
12
- class DUPX_WPConfig
13
- {
14
- /**
15
- * Updates the web server config files in Step 3
16
- *
17
- * @return null
18
- */
19
- public static function updateStandard()
20
- {
21
- if (!file_exists('wp-config.php')) {
22
- DUPX_Log::info('WARNING: Unable to locate wp-config.php file during standard update process. Be sure the file is present in your archive.');
23
- return;
24
- }
25
-
26
- $root_path = DUPX_U::setSafePath($GLOBALS['CURRENT_ROOT_PATH']);
27
- $wpconfig = @file_get_contents('wp-config.php', true);
28
-
29
- $db_port = is_int($_POST['dbport']) ? DUPX_U::sanitize_text_field($_POST['dbport']) : 3306;
30
- $db_host = ($db_port == 3306) ? DUPX_U::sanitize_text_field($_POST['dbhost']) : DUPX_U::sanitize_text_field($_POST['dbhost']).':'.DUPX_U::sanitize_text_field($db_port);
31
- $db_name = isset($_POST['dbname']) ? DUPX_U::sanitize_text_field($_POST['dbname']) : null;
32
- $db_user = isset($_POST['dbuser']) ? DUPX_U::sanitize_text_field($_POST['dbuser']) : null;
33
- $db_pass = isset($_POST['dbpass']) ? DUPX_U::sanitize_text_field($_POST['dbpass']) : null;
34
-
35
- $patterns = array(
36
- "/'DB_NAME',\s*'.*?'/",
37
- "/'DB_USER',\s*'.*?'/",
38
- "/'DB_PASSWORD',\s*'.*?'/",
39
- "/'DB_HOST',\s*'.*?'/"
40
- );
41
-
42
- $replace = array(
43
- "'DB_NAME', " . "'{$db_name}'",
44
- "'DB_USER', " . "'{$db_user}'",
45
- "'DB_PASSWORD', " . "'{$db_pass}'",
46
- "'DB_HOST', " . "'{$db_host}'"
47
- );
48
-
49
- //SSL CHECKS
50
- if ($_POST['ssl_admin']) {
51
- if (!strstr($wpconfig, 'FORCE_SSL_ADMIN')) {
52
- $wpconfig = $wpconfig.PHP_EOL."define('FORCE_SSL_ADMIN', true);";
53
- }
54
- } else {
55
- array_push($patterns, "/'FORCE_SSL_ADMIN',\s*true/");
56
- array_push($replace, "'FORCE_SSL_ADMIN', false");
57
- }
58
-
59
- //CACHE CHECKS
60
- if ($_POST['cache_wp']) {
61
- if (!strstr($wpconfig, 'WP_CACHE')) {
62
- $wpconfig = $wpconfig.PHP_EOL."define('WP_CACHE', true);";
63
- }
64
- } else {
65
- array_push($patterns, "/'WP_CACHE',\s*true/");
66
- array_push($replace, "'WP_CACHE', false");
67
- }
68
- if (!$_POST['cache_path']) {
69
- array_push($patterns, "/'WPCACHEHOME',\s*'.*?'/");
70
- array_push($replace, "'WPCACHEHOME', ''");
71
- }
72
-
73
- if (!is_writable("{$root_path}/wp-config.php")) {
74
- if (file_exists("{$root_path}/wp-config.php")) {
75
- chmod("{$root_path}/wp-config.php", 0644) ? DUPX_Log::info('File Permission Update: wp-config.php set to 0644') : DUPX_Log::info('WARNING: Unable to update file permissions and write to wp-config.php. Please visit the online FAQ for setting file permissions and work with your hosting provider or server administrator to enable this installer.php script to write to the wp-config.php file.');
76
- } else {
77
- DUPX_Log::info('WARNING: Unable to locate wp-config.php file. Be sure the file is present in your archive.');
78
- }
79
- }
80
-
81
- // array_map replaced because of installer error in PHP 5.2.9 - Cannot call method self::customEscape() or method does not exist in installer.php on line 1480
82
- // $replace = array_map('self::customEscape', $replace);
83
- foreach ($replace as $key=>$val) {
84
- $replace[$key] = self::customEscape($val);
85
- }
86
-
87
- $wpconfig = preg_replace($patterns, $replace, $wpconfig);
88
-
89
- file_put_contents('wp-config.php', $wpconfig);
90
- $wpconfig = null;
91
- }
92
-
93
- /**
94
- * Updates the web server config files in Step 3
95
- *
96
- * @return null
97
- */
98
- public static function updateExtended()
99
- {
100
- $config_file = '';
101
- if (!file_exists('wp-config.php')) {
102
- return $config_file;
103
- }
104
-
105
- $root_path = DUPX_U::setSafePath($GLOBALS['CURRENT_ROOT_PATH']);
106
- $wpconfig_path = "{$root_path}/wp-config.php";
107
- $config_file = @file_get_contents($wpconfig_path, true);
108
-
109
- $patterns = array(
110
- "/('|\")WP_HOME.*?\)\s*;/",
111
- "/('|\")WP_SITEURL.*?\)\s*;/");
112
-
113
- $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
114
- $replace = array(
115
- "'WP_HOME', '".$post_url_new."');",
116
- "'WP_SITEURL', '".$post_url_new."');");
117
-
118
- //Not sure how well tokenParser works on all servers so only using for not critical constants at this point.
119
- //$count checks for dynamic variable types such as: define('WP_TEMP_DIR', 'D:/' . $var . 'somepath/');
120
- //which should not be updated.
121
- $defines = self::tokenParser($wpconfig_path);
122
-
123
- //WP_CONTENT_DIR
124
- if (isset($defines['WP_CONTENT_DIR'])) {
125
- $post_path_old = DUPX_U::sanitize_text_field($_POST['path_old']);
126
- $post_path_new = DUPX_U::sanitize_text_field($_POST['path_new']);
127
- $val = str_replace($post_path_old, $post_path_new, DUPX_U::setSafePath($defines['WP_CONTENT_DIR']), $count);
128
- if ($count > 0) {
129
- array_push($patterns, "/('|\")WP_CONTENT_DIR.*?\)\s*;/");
130
- array_push($replace, "'WP_CONTENT_DIR', '{$val}');");
131
- }
132
- }
133
-
134
- //WP_CONTENT_URL
135
- if (isset($defines['WP_CONTENT_URL'])) {
136
- $post_url_old = DUPX_U::sanitize_text_field($_POST['url_old']);
137
- $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
138
- $val = str_replace($post_url_old . '/', $post_url_new . '/', $defines['WP_CONTENT_URL'], $count);
139
- if ($count > 0) {
140
- array_push($patterns, "/('|\")WP_CONTENT_URL.*?\)\s*;/");
141
- array_push($replace, "'WP_CONTENT_URL', '{$val}');");
142
- }
143
- }
144
-
145
- //WP_TEMP_DIR
146
- if (isset($defines['WP_TEMP_DIR'])) {
147
- $post_path_old = DUPX_U::sanitize_text_field($_POST['path_old']);
148
- $post_path_new = DUPX_U::sanitize_text_field($_POST['path_new']);
149
- $val = str_replace($post_path_old, $post_path_new, DUPX_U::setSafePath($defines['WP_TEMP_DIR']) , $count);
150
- if ($count > 0) {
151
- array_push($patterns, "/('|\")WP_TEMP_DIR.*?\)\s*;/");
152
- array_push($replace, "'WP_TEMP_DIR', '{$val}');");
153
- }
154
- }
155
-
156
- //DOMAIN_CURRENT_SITE
157
- if (isset($defines['DOMAIN_CURRENT_SITE'])) {
158
- $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
159
- $mu_newDomainHost = parse_url($post_url_new, PHP_URL_HOST);
160
- array_push($patterns, "/('|\")DOMAIN_CURRENT_SITE.*?\)\s*;/");
161
- array_push($replace, "'DOMAIN_CURRENT_SITE', '{$mu_newDomainHost}');");
162
- }
163
-
164
- //PATH_CURRENT_SITE
165
- if (isset($defines['PATH_CURRENT_SITE'])) {
166
- $post_url_new = DUPX_U::sanitize_text_field($_POST['url_new']);
167
- $mu_newUrlPath = parse_url($post_url_new, PHP_URL_PATH);
168
- array_push($patterns, "/('|\")PATH_CURRENT_SITE.*?\)\s*;/");
169
- array_push($replace, "'PATH_CURRENT_SITE', '{$mu_newUrlPath}');");
170
- }
171
-
172
- $config_file = preg_replace($patterns, $replace, $config_file);
173
- file_put_contents($wpconfig_path, $config_file);
174
- $config_file = file_get_contents($wpconfig_path, true);
175
-
176
- return $config_file;
177
- }
178
-
179
- /**
180
- * Used to parse the wp-config.php file
181
- *
182
- * @return null
183
- */
184
- public static function tokenParser($wpconfig_path)
185
- {
186
- $defines = array();
187
- $wpconfig_file = @file_get_contents($wpconfig_path);
188
-
189
- if (!function_exists('token_get_all')) {
190
- DUPX_Log::info("\nNOTICE: PHP function 'token_get_all' does not exist so skipping WP_CONTENT_DIR and WP_CONTENT_URL processing.");
191
- return $defines;
192
- }
193
-
194
- if ($wpconfig_file === false) {
195
- return $defines;
196
- }
197
-
198
- $defines = array();
199
- $tokens = token_get_all($wpconfig_file);
200
- $token = reset($tokens);
201
- while ($token) {
202
- if (is_array($token)) {
203
- if ($token[0] == T_WHITESPACE || $token[0] == T_COMMENT || $token[0] == T_DOC_COMMENT) {
204
- // do nothing
205
- } else if ($token[0] == T_STRING && strtolower($token[1]) == 'define') {
206
- $state = 1;
207
- } else if ($state == 2 && self::isConstant($token[0])) {
208
- $key = $token[1];
209
- $state = 3;
210
- } else if ($state == 4 && self::isConstant($token[0])) {
211
- $value = $token[1];
212
- $state = 5;
213
- }
214
- } else {
215
- $symbol = trim($token);
216
- if ($symbol == '(' && $state == 1) {
217
- $state = 2;
218
- } else if ($symbol == ',' && $state == 3) {
219
- $state = 4;
220
- } else if ($symbol == ')' && $state == 5) {
221
- $defines[self::tokenStrip($key)] = self::tokenStrip($value);
222
- $state = 0;
223
- }
224
- }
225
- $token = next($tokens);
226
- }
227
-
228
- return $defines;
229
- }
230
-
231
- private static function tokenStrip($value)
232
- {
233
- return preg_replace('!^([\'"])(.*)\1$!', '$2', $value);
234
- }
235
-
236
- private static function customEscape($str)
237
- {
238
- return str_replace('\\', '\\\\', $str);
239
- }
240
-
241
- private static function isConstant($token)
242
- {
243
- return $token == T_CONSTANT_ENCAPSED_STRING || $token == T_STRING || $token == T_LNUMBER || $token == T_DNUMBER;
244
- }
245
- }
246
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/ctrls/ctrl.step1.php DELETED
@@ -1,148 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- //POST PARAMS
5
- $_POST['archive_engine'] = isset($_POST['archive_engine']) ? DUPX_U::sanitize_text_field($_POST['archive_engine']) : 'manual';
6
- $_POST['archive_filetime'] = (isset($_POST['archive_filetime'])) ? DUPX_U::sanitize_text_field($_POST['archive_filetime']) : 'current';
7
- $_POST['retain_config'] = (isset($_POST['retain_config']) && $_POST['retain_config'] == '1') ? true : false;
8
- $_POST['exe_safe_mode'] = (isset($_POST['exe_safe_mode'])) ? DUPX_U::sanitize_text_field($_POST['exe_safe_mode']) : 0;
9
- //LOGGING
10
- $POST_LOG = $_POST;
11
- unset($POST_LOG['dbpass']);
12
- ksort($POST_LOG);
13
-
14
- //PAGE VARS
15
- $php_max_time = @ini_get("max_execution_time");
16
- $php_max_time = ($php_max_time == 0) ? "[0] time limit restriction disabled" : "[{$php_max_time}] time limit restriction enabled";
17
- $root_path = DUPX_U::setSafePath($GLOBALS['CURRENT_ROOT_PATH']);
18
- $package_path = "{$root_path}/{$GLOBALS['FW_PACKAGE_NAME']}";
19
- $ajax1_start = DUPX_U::getMicrotime();
20
- $zip_support = class_exists('ZipArchive') ? 'Enabled' : 'Not Enabled';
21
- $JSON = array();
22
- $JSON['pass'] = 0;
23
-
24
- /** JSON RESPONSE: Most sites have warnings turned off by default, but if they're turned on the warnings
25
- cause errors in the JSON data Here we hide the status so warning level is reset at it at the end */
26
- if (!headers_sent()) {
27
- header('Content-Type: application/json');
28
- }
29
- $ajax1_error_level = error_reporting();
30
- error_reporting(E_ERROR);
31
-
32
- //===============================
33
- //ERROR MESSAGES
34
- //===============================
35
- ($GLOBALS['LOG_FILE_HANDLE'] != false) or DUPX_Log::error(ERR_MAKELOG);
36
-
37
- if (!$GLOBALS['FW_ARCHIVE_ONLYDB']) {
38
- //ERR_ZIPMANUAL
39
- $post_archive_engine = DUPX_U::sanitize_text_field($_POST['archive_engine']);
40
- if ($post_archive_engine == 'manual') {
41
- if (!file_exists("wp-config.php") && !file_exists("dup-database__{$GLOBALS['PACKAGE_HASH']}.sql")) {
42
- DUPX_Log::error(ERR_ZIPMANUAL);
43
- }
44
- } else {
45
- //ERR_CONFIG_FOUND
46
- (!file_exists('wp-config.php'))
47
- or DUPX_Log::error(ERR_CONFIG_FOUND);
48
- //ERR_ZIPNOTFOUND
49
- (is_readable("{$package_path}"))
50
- or DUPX_Log::error(ERR_ZIPNOTFOUND);
51
- }
52
- }
53
-
54
-
55
-
56
- DUPX_Log::info("********************************************************************************");
57
- DUPX_Log::info('* DUPLICATOR-LITE: INSTALL-LOG');
58
- DUPX_Log::info("* VERSION: {$GLOBALS['FW_DUPLICATOR_VERSION']}");
59
- DUPX_Log::info('* STEP-1 START @ '.@date('h:i:s'));
60
- DUPX_Log::info('* NOTICE: Do NOT post this data to public sites or forums');
61
- DUPX_Log::info("********************************************************************************");
62
- DUPX_Log::info("PHP VERSION:\t".phpversion().' | SAPI: '.php_sapi_name());
63
- DUPX_Log::info("PHP TIME LIMIT:\t{$php_max_time}");
64
- DUPX_Log::info("PHP MEMORY:\t".$GLOBALS['PHP_MEMORY_LIMIT'].' | SUHOSIN: '.$GLOBALS['PHP_SUHOSIN_ON']);
65
- DUPX_Log::info("SERVER:\t\t{$_SERVER['SERVER_SOFTWARE']}");
66
- DUPX_Log::info("DOC ROOT:\t{$root_path}");
67
- DUPX_Log::info("DOC ROOT 755:\t".var_export($GLOBALS['CHOWN_ROOT_PATH'], true));
68
- DUPX_Log::info("LOG FILE 644:\t".var_export($GLOBALS['CHOWN_LOG_PATH'], true));
69
- DUPX_Log::info("REQUEST URL:\t{$GLOBALS['URL_PATH']}");
70
- DUPX_Log::info("SAFE MODE :\t{$_POST['exe_safe_mode']}");
71
-
72
- $log = "--------------------------------------\n";
73
- $log .= "POST DATA\n";
74
- $log .= "--------------------------------------\n";
75
- $log .= print_r($POST_LOG, true);
76
- DUPX_Log::info($log, 2);
77
-
78
- $log = "--------------------------------------\n";
79
- $log .= "ARCHIVE EXTRACTION\n";
80
- $log .= "--------------------------------------\n";
81
- $log .= "NAME:\t{$GLOBALS['FW_PACKAGE_NAME']}\n";
82
- $log .= "SIZE:\t".DUPX_U::readableByteSize(@filesize($GLOBALS['FW_PACKAGE_NAME']))."\n";
83
- $log .= "ZIP:\t{$zip_support} (ZipArchive Support)";
84
- DUPX_Log::info($log);
85
-
86
-
87
- if ($_POST['archive_engine'] == 'manual') {
88
- DUPX_Log::info("\n** PACKAGE EXTRACTION IS IN MANUAL MODE ** \n");
89
- } else {
90
- if (!class_exists('ZipArchive')) {
91
- DUPX_Log::info("ERROR: Stopping install process. Trying to extract without ZipArchive module installed. Please use the 'Manual Package extraction' mode to extract zip file.");
92
- DUPX_Log::error(ERR_ZIPARCHIVE);
93
- }
94
-
95
- $target = $root_path;
96
- $zip = new ZipArchive();
97
- if ($zip->open($GLOBALS['FW_PACKAGE_NAME']) === TRUE) {
98
-
99
- DUPX_Log::info("\n>>> START EXTRACTION:");
100
- if (!$zip->extractTo($target)) {
101
- DUPX_Log::error(ERR_ZIPEXTRACTION);
102
- }
103
- $log = print_r($zip, true);
104
-
105
- //Keep original timestamp on the file
106
- if ($_POST['archive_filetime'] == 'original') {
107
- $log .= "File timestamp is 'Original' mode.\n";
108
- for ($idx = 0; $s = $zip->statIndex($idx); $idx++) {
109
- touch($target.DIRECTORY_SEPARATOR.$s['name'], $s['mtime']);
110
- }
111
- } else {
112
- $now = date("Y-m-d H:i:s");
113
- $log .= "File timestamp is 'Current' mode: {$now}\n";
114
- }
115
-
116
- $close_response = $zip->close();
117
- $log .= "<<< EXTRACTION COMPLETE: " . var_export($close_response, true);
118
- DUPX_Log::info($log);
119
- } else {
120
- DUPX_Log::error(ERR_ZIPOPEN);
121
- }
122
- }
123
-
124
- //===============================
125
- //RESET SERVER CONFIG FILES
126
- //===============================
127
- if ($_POST['retain_config']) {
128
- DUPX_Log::info("\nNOTICE: Manual update of permalinks required see: Admin > Settings > Permalinks > Click Save Changes");
129
- DUPX_Log::info("Retaining the original htaccess, user.ini or web.config files may cause issues with the setup of this site.");
130
- DUPX_Log::info("If you run into issues during or after the install process please uncheck the 'Config Files' checkbox labeled:");
131
- DUPX_Log::info("'Retain original .htaccess, .user.ini and web.config' from Step 1 and re-run the installer. Backups of the");
132
- DUPX_Log::info("orginal config files will be made and can be merged per required directive.");
133
- } else {
134
- DUPX_ServerConfig::reset();
135
- }
136
-
137
-
138
- //FINAL RESULTS
139
- $ajax1_end = DUPX_U::getMicrotime();
140
- $ajax1_sum = DUPX_U::elapsedTime($ajax1_end, $ajax1_start);
141
- DUPX_Log::info("\nSTEP-1 COMPLETE @ " . @date('h:i:s') . " - RUNTIME: {$ajax1_sum}");
142
-
143
-
144
- $JSON['pass'] = 1;
145
- echo json_encode($JSON);
146
- error_reporting($ajax1_error_level);
147
- die('');
148
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/ctrls/ctrl.step2.php DELETED
@@ -1,499 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- //POST PARAMS
5
- $_POST['dbaction'] = isset($_POST['dbaction']) ? DUPX_U::sanitize_text_field($_POST['dbaction']) : 'create';
6
-
7
- if (isset($_POST['dbhost'])) {
8
- $post_db_host = DUPX_U::sanitize_text_field($_POST['dbhost']);
9
- $_POST['dbhost'] = DUPX_U::sanitize_text_field($post_db_host);
10
- } else {
11
- $_POST['dbhost'] = null;
12
- }
13
-
14
- if (isset($_POST['dbname'])) {
15
- $post_db_name = DUPX_U::sanitize_text_field($_POST['dbname']);
16
- $_POST['dbname'] = trim($post_db_name);
17
- } else {
18
- $_POST['dbname'] = null;
19
- }
20
-
21
- $_POST['dbuser'] = isset($_POST['dbuser']) ? DUPX_U::sanitize_text_field($_POST['dbuser']) : null;
22
- $_POST['dbpass'] = isset($_POST['dbpass']) ? DUPX_U::sanitize_text_field($_POST['dbpass']) : null;
23
-
24
- if (isset($_POST['dbcharset'])) {
25
- $post_db_charset = DUPX_U::sanitize_text_field($_POST['dbcharset']);
26
- $_POST['dbcharset'] = trim($post_db_charset);
27
- } else {
28
- $_POST['dbcharset'] = $GLOBALS['DBCHARSET_DEFAULT'];
29
- }
30
-
31
- if (isset($_POST['dbcollate'])) {
32
- $post_db_collate = DUPX_U::sanitize_text_field($_POST['dbcollate']);
33
- $_POST['dbcollate'] = trim($post_db_collate);
34
- } else {
35
- $_POST['dbcollate'] = $GLOBALS['DBCOLLATE_DEFAULT'];
36
- }
37
-
38
- $_POST['dbnbsp'] = (isset($_POST['dbnbsp']) && $_POST['dbnbsp'] == '1') ? true : false;
39
- $_POST['ssl_admin'] = (isset($_POST['ssl_admin'])) ? true : false;
40
- $_POST['cache_wp'] = (isset($_POST['cache_wp'])) ? true : false;
41
- $_POST['cache_path'] = (isset($_POST['cache_path'])) ? true : false;
42
- $_POST['retain_config'] = (isset($_POST['retain_config']) && $_POST['retain_config'] == '1') ? true : false;
43
- $_POST['dbcollatefb'] = isset($_POST['dbcollatefb']) ? DUPX_U::sanitize_text_field($_POST['dbcollatefb']) : false;
44
-
45
- //LOGGING
46
- $POST_LOG = $_POST;
47
- unset($POST_LOG['dbpass']);
48
- ksort($POST_LOG);
49
-
50
- //PAGE VARS
51
- $date_time = @date('h:i:s');
52
- $root_path = DUPX_U::setSafePath($GLOBALS['CURRENT_ROOT_PATH']);
53
- $ajax2_start = DUPX_U::getMicrotime();
54
- $JSON = array();
55
- $JSON['pass'] = 0;
56
-
57
- /** JSON RESPONSE: Most sites have warnings turned off by default, but if they're turned on the warnings
58
- cause errors in the JSON data Here we hide the status so warning level is reset at it at the end*/
59
- $ajax1_error_level = error_reporting();
60
- error_reporting(E_ERROR);
61
-
62
- //====================================================================================================
63
- //DATABASE TEST CONNECTION
64
- //====================================================================================================
65
- if (isset($_GET['dbtest']))
66
- {
67
- $html = "";
68
- $baseport = parse_url($_POST['dbhost'], PHP_URL_PORT);
69
- $dbConn = DUPX_DB::connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass'], null, $_POST['dbport']);
70
- $dbErr = mysqli_connect_error();
71
-
72
- $dbFound = mysqli_select_db($dbConn, $_POST['dbname']);
73
- $port_view = (is_int($baseport) || substr($_POST['dbhost'], -1) == ":") ? "Port=[Set in Host]" : "Port=".DUPX_U::esc_html($_POST['dbport']);
74
-
75
- $tstSrv = ($dbConn) ? "<div class='dupx-pass'>Success</div>" : "<div class='dupx-fail'>Fail</div>";
76
- $tstDB = ($dbFound) ? "<div class='dupx-pass'>Success</div>" : "<div class='dupx-fail'>Fail</div>";
77
-
78
- $dbversion_info = DUPX_DB::getServerInfo($dbConn);
79
- $dbversion_info = empty($dbversion_info) ? 'no connection' : $dbversion_info;
80
- $dbversion_info_fail = $dbConn && version_compare(DUPX_DB::getVersion($dbConn), '5.5.3') < 0;
81
-
82
- $dbversion_compat = DUPX_DB::getVersion($dbConn);
83
- $dbversion_compat = empty($dbversion_compat) ? 'no connection' : $dbversion_compat;
84
- $dbversion_compat_fail = $dbConn && version_compare($dbversion_compat, $GLOBALS['FW_VERSION_DB']) < 0;
85
-
86
- $tstInfo = ($dbversion_info_fail)
87
- ? "<div class='dupx-notice'>".DUPX_U::esc_html($dbversion_info)."</div>"
88
- : "<div class='dupx-pass'>".DUPX_U::esc_html($dbversion_info)."</div>";
89
-
90
- $tstCompat = ($dbversion_compat_fail)
91
- ? "<div class='dupx-notice'>This Server: [".DUPX_U::esc_html($dbversion_compat)."] -- Package Server: [".DUPX_U::esc_html($GLOBALS['FW_VERSION_DB'])."]</div>"
92
- : "<div class='dupx-pass'>This Server: [".DUPX_U::esc_html($dbversion_compat)."] -- Package Server: [".DUPX_U::esc_html($GLOBALS['FW_VERSION_DB'])."]</div>";
93
-
94
- $html .= "
95
- <div class='s2-db-test'>
96
- <small>
97
- Using Connection String:<br/>
98
- Host=".DUPX_U::esc_html($_POST['dbhost'])."; Database=".DUPX_U::esc_html($_POST['dbname'])."; Uid=".DUPX_U::esc_html($_POST['dbuser'])."; Pwd=".DUPX_U::esc_html($_POST['dbpass'])."; {$port_view}
99
- </small>
100
- <table class='s2-db-test-dtls'>
101
- <tr>
102
- <td>Host:</td>
103
- <td>".$tstSrv."</td>
104
- </tr>
105
- <tr>
106
- <td>Database:</td>
107
- <td>".$tstDB."</td>
108
- </tr>
109
- <tr>
110
- <td>Version:</td>
111
- <td>".$tstInfo."</td>
112
- </tr>
113
- <tr>
114
- <td>Compatibility:</td>
115
- <td>".$tstCompat."</td>
116
- </tr>
117
- </table>";
118
-
119
- //--------------------------------
120
- //WARNING: Unable to connect
121
- $html .= (!$dbConn || !$dbFound)
122
- ? "<div class='warn-msg'>" . ERR_DBCONNECT_INFO . "</div>"
123
- : '';
124
-
125
- //WARNING: DB has tables with create option
126
- if ($_POST['dbaction'] == 'create')
127
- {
128
- $tblcount = DUPX_DB::countTables($dbConn, $_POST['dbname']);
129
- $html .= ($tblcount > 0)
130
- ? "<div class='warn-msg'><b>WARNING:</b> " . sprintf(ERR_DBEMPTY, DUPX_U::esc_html($_POST['dbname']), DUPX_U::esc_html($tblcount)) . "</div>"
131
- : '';
132
- }
133
-
134
- //WARNNG: Input has utf8
135
- $dbConnItems = array($_POST['dbhost'], $_POST['dbuser'], $_POST['dbname'],$_POST['dbpass']);
136
- $dbUTF8_tst = false;
137
- foreach ($dbConnItems as $value) {
138
- if (DUPX_U::isNonASCII($value)) {
139
- $dbUTF8_tst = true;
140
- break;
141
- }
142
- }
143
-
144
- //WARNING: UTF8 Data in Connection String
145
- $html .= (!$dbConn && $dbUTF8_tst)
146
- ? "<div class='warn-msg'><b>WARNING:</b> " . ERR_TESTDB_UTF8 . "</div>"
147
- : '';
148
-
149
- //NOTICE: Version Too Low
150
- $html .= ($dbversion_info_fail)
151
- ? "<div class='warn-msg'><b>NOTICE:</b> " . ERR_TESTDB_VERSION_INFO . "</div>"
152
- : '';
153
-
154
- //NOTICE: Version Incompatibility
155
- $html .= ($dbversion_compat_fail)
156
- ? "<div class='warn-msg'><b>NOTICE:</b> " . ERR_TESTDB_VERSION_COMPAT . "</div>"
157
- : '';
158
-
159
- $html .= "</div>";
160
- die($html);
161
- }
162
-
163
- //===============================
164
- //ERROR MESSAGES
165
- //===============================
166
-
167
- //ERR_MAKELOG
168
- ($GLOBALS['LOG_FILE_HANDLE'] != false) or DUPX_Log::error(ERR_MAKELOG);
169
-
170
- //ERR_MYSQLI_SUPPORT
171
- function_exists('mysqli_connect') or DUPX_Log::error(ERR_MYSQLI_SUPPORT);
172
-
173
- //ERR_DBCONNECT
174
- $dbh = DUPX_DB::connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass'], null, $_POST['dbport']);
175
- @mysqli_query($dbh, "SET wait_timeout = ".mysqli_real_escape_string($dbh, $GLOBALS['DB_MAX_TIME']));
176
- ($dbh) or DUPX_Log::error(ERR_DBCONNECT . mysqli_connect_error());
177
- if ($_POST['dbaction'] == 'empty') {
178
- mysqli_select_db($dbh, $_POST['dbname']) or DUPX_Log::error(sprintf(ERR_DBCREATE, $_POST['dbname']));
179
- }
180
- //ERR_DBEMPTY
181
- if ($_POST['dbaction'] == 'create' ) {
182
- $tblcount = DUPX_DB::countTables($dbh, $_POST['dbname']);
183
- if ($tblcount > 0) {
184
- DUPX_Log::error(sprintf(ERR_DBEMPTY, $_POST['dbname'], $tblcount));
185
- }
186
- }
187
-
188
-
189
-
190
- $log = <<<LOG
191
- \n\n********************************************************************************
192
- * DUPLICATOR-LITE: INSTALL-LOG
193
- * STEP-2 START @ {$date_time}
194
- * NOTICE: Do NOT post to public sites or forums
195
- ********************************************************************************
196
- LOG;
197
- DUPX_Log::info($log);
198
-
199
- $log = "--------------------------------------\n";
200
- $log .= "POST DATA\n";
201
- $log .= "--------------------------------------\n";
202
- $log .= print_r($POST_LOG, true);
203
- DUPX_Log::info($log, 2);
204
-
205
-
206
- //====================================================================================================
207
- //DATABASE ROUTINES
208
- //====================================================================================================
209
- $log = '';
210
- $faq_url = $GLOBALS['FAQ_URL'];
211
- $utm_prefix = '?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=';
212
- $db_file_size = filesize("dup-database__{$GLOBALS['PACKAGE_HASH']}.sql");
213
- $php_mem = $GLOBALS['PHP_MEMORY_LIMIT'];
214
- $php_mem_range = DUPX_U::getBytes($GLOBALS['PHP_MEMORY_LIMIT']);
215
- $php_mem_range = $php_mem_range == null ? 0 : $php_mem_range - 5000000; //5 MB Buffer
216
-
217
- //Fatal Memory errors from file_get_contents is not catchable.
218
- //Try to warn ahead of time with a buffer in memory difference
219
- if ($db_file_size >= $php_mem_range && $php_mem_range != 0)
220
- {
221
- $db_file_size = DUPX_U::readableByteSize($db_file_size);
222
- $msg = "\nWARNING: The database script is '{$db_file_size}' in size. The PHP memory allocation is set\n";
223
- $msg .= "at '{$php_mem}'. There is a high possibility that the installer script will fail with\n";
224
- $msg .= "a memory allocation error when trying to load the dup-database__{$GLOBALS['PACKAGE_HASH']}.sql file. It is\n";
225
- $msg .= "recommended to increase the 'memory_limit' setting in the php.ini config file.\n";
226
- $msg .= "see: {$faq_url}{$utm_prefix}inst_step2_lgdbscript#faq-trouble-056-q \n";
227
- DUPX_Log::info($msg);
228
- }
229
-
230
- @chmod("{$root_path}/dup-database__{$GLOBALS['PACKAGE_HASH']}.sql", 0777);
231
- $sql_file = file_get_contents("dup-database__{$GLOBALS['PACKAGE_HASH']}.sql", true);
232
-
233
- //ERROR: Reading database.sql file
234
- if ($sql_file === FALSE || strlen($sql_file) < 10)
235
- {
236
- $msg = "<b>Unable to read the dup-database__{$GLOBALS['PACKAGE_HASH']}.sql file from the archive. Please check these items:</b> <br/>";
237
- $msg .= "1. Validate permissions and/or group-owner rights on these items: <br/>";
238
- $msg .= " - File: dup-database__{$GLOBALS['PACKAGE_HASH']}.sql <br/> - Directory: [{$root_path}] <br/>";
239
- $msg .= "<i>see: <a href='{$faq_url}{$utm_prefix}inst_step2_dbperms#faq-trouble-055-q' target='_blank'>{$faq_url}#faq-trouble-055-q</a></i> <br/>";
240
- $msg .= "2. Validate the dup-database__{$GLOBALS['PACKAGE_HASH']}.sql file exists and is in the root of the archive.zip file <br/>";
241
- $msg .= "<i>see: <a href='{$faq_url}{$utm_prefix}inst_step2_sqlroot#faq-installer-020-q' target='_blank'>{$faq_url}#faq-installer-020-q</a></i> <br/>";
242
- DUPX_Log::error($msg);
243
- }
244
-
245
- //Removes invalid space characters
246
- //Complex Subject See: http://webcollab.sourceforge.net/unicode.html
247
- if ($_POST['dbnbsp'])
248
- {
249
- DUPX_Log::info("NOTICE: Ran fix non-breaking space characters\n");
250
- $sql_file = preg_replace('/\xC2\xA0/', ' ', $sql_file);
251
- }
252
-
253
- //Write new contents to install-data.sql
254
- $sql_file_copy_status = file_put_contents($GLOBALS['SQL_FILE_NAME'], $sql_file);
255
- $sql_result_file_data = explode(";\n", $sql_file);
256
- $sql_result_file_length = count($sql_result_file_data);
257
- $sql_result_file_path = "{$root_path}/{$GLOBALS['SQL_FILE_NAME']}";
258
- $sql_file = null;
259
- $db_collatefb_log = '';
260
-
261
- if($_POST['dbcollatefb']){
262
- $supportedCollations = DUPX_DB::getSupportedCollationsList($dbh);
263
- $collation_arr = array(
264
- 'utf8mb4_unicode_520_ci',
265
- 'utf8mb4_unicode_520',
266
- 'utf8mb4_unicode_ci',
267
- 'utf8mb4',
268
- 'utf8_unicode_520_ci',
269
- 'utf8_unicode_520',
270
- 'utf8_unicode_ci',
271
- 'utf8'
272
- );
273
- $latest_supported_collation = '';
274
- $latest_supported_index = -1;
275
-
276
- foreach ($collation_arr as $key => $val){
277
- if(in_array($val,$supportedCollations)){
278
- $latest_supported_collation = $val;
279
- $latest_supported_index = $key;
280
- break;
281
- }
282
- }
283
-
284
- //No need to replace if current DB is up to date
285
- if($latest_supported_index != 0){
286
- for($i=0; $i < $latest_supported_index; $i++){
287
- foreach ($sql_result_file_data as $index => $col_sql_query){
288
- if(strpos($col_sql_query,$collation_arr[$i]) !== false){
289
- $sql_result_file_data[$index] = str_replace($collation_arr[$i], $latest_supported_collation, $col_sql_query);
290
- if(strpos($collation_arr[$i],'utf8mb4') !== false && strpos($latest_supported_collation,'utf8mb4') === false){
291
- $sql_result_file_data[$index] = str_replace('utf8mb4','utf8',$sql_result_file_data[$index]);
292
- }
293
- $sub_query = str_replace("\n", '', substr($col_sql_query, 0, 75));
294
- $db_collatefb_log .= " - Collation '{$collation_arr[$i]}' set to '{$latest_supported_collation}' on query [{$sub_query}...]\n";
295
- }
296
- }
297
- }
298
- }
299
- }
300
-
301
- //WARNING: Create installer-data.sql failed
302
- if ($sql_file_copy_status === FALSE || filesize($sql_result_file_path) == 0 || !is_readable($sql_result_file_path))
303
- {
304
- $sql_file_size = DUPX_U::readableByteSize(filesize("dup-database__{$GLOBALS['PACKAGE_HASH']}.sql"));
305
- $msg = "\nWARNING: Unable to properly copy dup-database__{$GLOBALS['PACKAGE_HASH']}.sql ({$sql_file_size}) to {$GLOBALS['SQL_FILE_NAME']}. Please check these items:\n";
306
- $msg .= "- Validate permissions and/or group-owner rights on dup-database__{$GLOBALS['PACKAGE_HASH']}.sql and directory [{$root_path}] \n";
307
- $msg .= "- see: {$faq_url}{$utm_prefix}inst_step2_copydbsql#faq-trouble-055-q \n";
308
- DUPX_Log::info($msg);
309
- }
310
-
311
- //=================================
312
- //START DB RUN
313
- @mysqli_query($dbh, "SET wait_timeout = ".mysqli_real_escape_string($dbh, $GLOBALS['DB_MAX_TIME']));
314
- @mysqli_query($dbh, "SET max_allowed_packet = ".mysqli_real_escape_string($dbh, $GLOBALS['DB_MAX_PACKETS']));
315
- DUPX_DB::setCharset($dbh, $_POST['dbcharset'], $_POST['dbcollate']);
316
-
317
- //Will set mode to null only for this db handle session
318
- //sql_mode can cause db create issues on some systems
319
- $qry_session_custom = true;
320
- switch ($_POST['dbmysqlmode']) {
321
- case 'DISABLE':
322
- @mysqli_query($dbh, "SET SESSION sql_mode = ''");
323
- break;
324
- case 'CUSTOM':
325
- $dbmysqlmode_opts = $_POST['dbmysqlmode_opts'];
326
- $qry_session_custom = @mysqli_query($dbh, "SET SESSION sql_mode = '".mysqli_real_escape_string($dbh, $dbmysqlmode_opts)."'");
327
- if ($qry_session_custom == false) {
328
- $sql_error = mysqli_error($dbh);
329
- $log = "WARNING: Trying to set a custom sql_mode setting issue has been detected:\n{$sql_error}.\n";
330
- $log .= "For more details visit: http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html\n";
331
- }
332
- break;
333
- }
334
-
335
- //Set defaults in-case the variable could not be read
336
- $dbvar_maxtime = DUPX_DB::getVariable($dbh, 'wait_timeout');
337
- $dbvar_maxpacks = DUPX_DB::getVariable($dbh, 'max_allowed_packet');
338
- $dbvar_sqlmode = DUPX_DB::getVariable($dbh, 'sql_mode');
339
- $dbvar_maxtime = is_null($dbvar_maxtime) ? 300 : $dbvar_maxtime;
340
- $dbvar_maxpacks = is_null($dbvar_maxpacks) ? 1048576 : $dbvar_maxpacks;
341
- $dbvar_sqlmode = empty($dbvar_sqlmode) ? 'NOT_SET' : $dbvar_sqlmode;
342
- $dbvar_version = DUPX_DB::getVersion($dbh);
343
- $sql_file_size1 = DUPX_U::readableByteSize(@filesize("dup-database__{$GLOBALS['PACKAGE_HASH']}.sql"));
344
- $sql_file_size2 = DUPX_U::readableByteSize(@filesize("{$GLOBALS['SQL_FILE_NAME']}"));
345
- $db_collatefb = isset($_POST['dbcollatefb']) ? 'On' : 'Off';
346
-
347
-
348
- DUPX_Log::info("--------------------------------------");
349
- DUPX_Log::info("DATABASE ENVIRONMENT");
350
- DUPX_Log::info("--------------------------------------");
351
- DUPX_Log::info("MYSQL VERSION:\tThis Server: {$dbvar_version} -- Build Server: {$GLOBALS['FW_VERSION_DB']}");
352
- DUPX_Log::info("FILE SIZE:\tdup-database__{$GLOBALS['PACKAGE_HASH']}.sql ({$sql_file_size1}) - dup-installer-data__{$GLOBALS['PACKAGE_HASH']}.sql ({$sql_file_size2})");
353
- DUPX_Log::info("TIMEOUT:\t{$dbvar_maxtime}");
354
- DUPX_Log::info("MAXPACK:\t{$dbvar_maxpacks}");
355
- DUPX_Log::info("SQLMODE:\t{$dbvar_sqlmode}");
356
- DUPX_Log::info("NEW SQL FILE:\t[{$sql_result_file_path}]");
357
- DUPX_Log::info("COLLATE RESET:\t{$db_collatefb}\n{$db_collatefb_log}");
358
-
359
- if ($qry_session_custom == false) {
360
- DUPX_Log::info("\n{$log}\n");
361
- }
362
-
363
- //CREATE DB
364
- switch ($_POST['dbaction']) {
365
- case "create":
366
- mysqli_query($dbh, "CREATE DATABASE IF NOT EXISTS `".mysqli_real_escape_string($dbh, $_POST['dbname'])."`");
367
- mysqli_select_db($dbh, mysqli_real_escape_string($dbh, $_POST['dbname']))
368
- or DUPX_Log::error(sprintf(ERR_DBCONNECT_CREATE, $_POST['dbname']));
369
- break;
370
- case "empty":
371
- //DROP DB TABLES
372
- $drop_log = "Database already empty. Ready for install.";
373
- $sql = "SHOW FULL TABLES WHERE Table_Type != 'VIEW'";
374
- $found_tables = null;
375
- if ($result = mysqli_query($dbh, $sql)) {
376
- while ($row = mysqli_fetch_row($result)) {
377
- $found_tables[] = $row[0];
378
- }
379
- if (count($found_tables) > 0) {
380
- foreach ($found_tables as $table_name) {
381
- $sql = "DROP TABLE `".mysqli_real_escape_string($dbh, $_POST['dbname'])."`.`".mysqli_real_escape_string($dbh, $table_name)."`";
382
- if (!$result = mysqli_query($dbh, $sql)) {
383
- DUPX_Log::error(sprintf(ERR_DBTRYCLEAN, $_POST['dbname']));
384
- }
385
- }
386
- }
387
- $drop_log = count($found_tables);
388
- }
389
- break;
390
- }
391
-
392
-
393
- //WRITE DATA
394
- DUPX_Log::info("--------------------------------------");
395
- DUPX_Log::info("DATABASE RESULTS");
396
- DUPX_Log::info("--------------------------------------");
397
- $profile_start = DUPX_U::getMicrotime();
398
- $fcgi_buffer_pool = 5000;
399
- $fcgi_buffer_count = 0;
400
- $dbquery_rows = 0;
401
- $dbtable_rows = 1;
402
- $dbquery_errs = 0;
403
- $counter = 0;
404
- @mysqli_autocommit($dbh, false);
405
-
406
- while ($counter < $sql_result_file_length) {
407
-
408
- $query_strlen = strlen(trim($sql_result_file_data[$counter]));
409
-
410
- if ($dbvar_maxpacks < $query_strlen) {
411
-
412
- DUPX_Log::info("**ERROR** Query size limit [length={$query_strlen}] [sql=" . substr($sql_result_file_data[$counter], 0, 75) . "...]");
413
- $dbquery_errs++;
414
-
415
- } elseif ($query_strlen > 0) {
416
-
417
- @mysqli_free_result(@mysqli_query($dbh, ($sql_result_file_data[$counter])));
418
- $err = mysqli_error($dbh);
419
-
420
- //Check to make sure the connection is alive
421
- if (!empty($err)) {
422
-
423
- if (!mysqli_ping($dbh)) {
424
- mysqli_close($dbh);
425
- $dbh = DUPX_DB::connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass'], $_POST['dbname'], $_POST['dbport'] );
426
- // Reset session setup
427
- @mysqli_query($dbh, "SET wait_timeout = ".mysqli_real_escape_string($dbh, $GLOBALS['DB_MAX_TIME']));
428
- DUPX_DB::setCharset($dbh, $_POST['dbcharset'], $_POST['dbcollate']);
429
- }
430
- DUPX_Log::info("**ERROR** database error write '{$err}' - [sql=" . substr($sql_result_file_data[$counter], 0, 75) . "...]");
431
- $dbquery_errs++;
432
-
433
- //Buffer data to browser to keep connection open
434
- } else {
435
- if ($GLOBALS['DB_FCGI_FLUSH'] && $fcgi_buffer_count++ > $fcgi_buffer_pool) {
436
- $fcgi_buffer_count = 0;
437
- DUPX_U::fcgiFlush();
438
- }
439
- $dbquery_rows++;
440
- }
441
- }
442
- $counter++;
443
- }
444
- @mysqli_commit($dbh);
445
- @mysqli_autocommit($dbh, true);
446
-
447
- DUPX_Log::info("ERRORS FOUND:\t{$dbquery_errs}");
448
- DUPX_Log::info("TABLES DROPPED:\t{$drop_log}");
449
- DUPX_Log::info("QUERIES RAN:\t{$dbquery_rows}\n");
450
-
451
- $dbtable_count = 0;
452
- if ($result = mysqli_query($dbh, "SHOW TABLES")) {
453
- while ($row = mysqli_fetch_array($result, MYSQLI_NUM)) {
454
- $table_rows = DUPX_DB::countTableRows($dbh, $row[0]);
455
- $dbtable_rows += $table_rows;
456
- DUPX_Log::info("{$row[0]}: ({$table_rows})");
457
- $dbtable_count++;
458
- }
459
- @mysqli_free_result($result);
460
- }
461
-
462
- if ($dbtable_count == 0) {
463
- DUPX_Log::error("No tables where created during step 2 of the install. Please review the <a href='".$GLOBALS["LOG_FILE_NAME"]."' target='install_log'>".$GLOBALS["LOG_FILE_NAME"]."</a> file for
464
- ERROR messages. You may have to manually run the installer-data_[HASH].sql with a tool like phpmyadmin to validate the data input. If you have enabled compatibility mode
465
- during the package creation process then the database server version your using may not be compatible with this script.\n");
466
- }
467
-
468
-
469
- //DATA CLEANUP: Perform Transient Cache Cleanup
470
- //Remove all duplicator entries and record this one since this is a new install.
471
- $dbdelete_count = 0;
472
- @mysqli_query($dbh, "DELETE FROM `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."duplicator_packages`");
473
- $dbdelete_count1 = @mysqli_affected_rows($dbh) or 0;
474
- @mysqli_query($dbh, "DELETE FROM `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."options` WHERE `option_name` LIKE ('_transient%') OR `option_name` LIKE ('_site_transient%')");
475
- $dbdelete_count2 = @mysqli_affected_rows($dbh) or 0;
476
- $dbdelete_count = (abs($dbdelete_count1) + abs($dbdelete_count2));
477
- DUPX_Log::info("\nRemoved '{$dbdelete_count}' cache/transient rows");
478
- //Reset Duplicator Options
479
- foreach ($GLOBALS['FW_OPTS_DELETE'] as $value) {
480
- mysqli_query($dbh, "DELETE FROM `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."options` WHERE `option_name` = '".mysqli_real_escape_string($dbh, $value)."'");
481
- }
482
-
483
- @mysqli_close($dbh);
484
-
485
- //FINAL RESULTS
486
- $profile_end = DUPX_U::getMicrotime();
487
- $ajax2_end = DUPX_U::getMicrotime();
488
- $ajax1_sum = DUPX_U::elapsedTime($ajax2_end, $ajax2_start);
489
- DUPX_Log::info("\nCREATE/INSTALL RUNTIME: " . DUPX_U::elapsedTime($profile_end, $profile_start));
490
- DUPX_Log::info('STEP-2 COMPLETE @ ' . @date('h:i:s') . " - RUNTIME: {$ajax1_sum}");
491
-
492
- $JSON['pass'] = 1;
493
- $JSON['table_count'] = $dbtable_count;
494
- $JSON['table_rows'] = $dbtable_rows;
495
- $JSON['query_errs'] = $dbquery_errs;
496
- echo json_encode($JSON);
497
- error_reporting($ajax1_error_level);
498
- die('');
499
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/ctrls/ctrl.step3.php DELETED
@@ -1,390 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- // Exit if accessed directly from admin
5
- if (function_exists('duplicator_secure_check')) {
6
- duplicator_secure_check();
7
- }
8
-
9
- /** JSON RESPONSE: Most sites have warnings turned off by default, but if they're turned on the warnings
10
- cause errors in the JSON data Here we hide the status so warning level is reset at it at the end*/
11
- $ajax2_error_level = error_reporting();
12
- error_reporting(E_ERROR);
13
-
14
- //====================================================================================================
15
- //DATABASE UPDATES
16
- //====================================================================================================
17
-
18
- $ajax2_start = DUPX_U::getMicrotime();
19
-
20
- //POST PARAMS
21
- if (isset($_POST['dbhost'])) {
22
- $post_db_host = DUPX_U::sanitize_text_field($_POST['dbhost']);
23
- $_POST['dbhost'] = trim($post_db_host);
24
- } else {
25
- $_POST['dbhost'] = null;
26
- }
27
-
28
- if (isset($_POST['dbname'])) {
29
- $post_db_name = DUPX_U::sanitize_text_field($_POST['dbname']);
30
- $_POST['dbname'] = trim($post_db_name);
31
- } else {
32
- $_POST['dbname'] = null;
33
- }
34
-
35
-
36
- $_POST['dbuser'] = isset($_POST['dbuser']) ? DUPX_U::sanitize_text_field($_POST['dbuser']) : null;
37
- $_POST['dbpass'] = isset($_POST['dbpass']) ? DUPX_U::sanitize_text_field($_POST['dbpass']) : null;
38
-
39
- if (isset($_POST['blogname'])) {
40
- $post_blog_name = DUPX_U::sanitize_text_field($_POST['blogname']);
41
- $_POST['blogname'] = trim($post_blog_name);
42
- } else {
43
- $_POST['blogname'] = '';
44
- }
45
-
46
- $_POST['postguid'] = isset($_POST['postguid']) && $_POST['postguid'] == 1 ? 1 : 0;
47
- $_POST['fullsearch'] = isset($_POST['fullsearch']) && $_POST['fullsearch'] == 1 ? 1 : 0;
48
-
49
- if (isset($_POST['path_old'])) {
50
- $post_path_old = DUPX_U::sanitize_text_field($_POST['path_old']);
51
- $_POST['path_old'] = trim($post_path_old);
52
- } else {
53
- $_POST['path_old'] = null;
54
- }
55
-
56
- if (isset($_POST['path_new'])) {
57
- $post_path_new = DUPX_U::sanitize_text_field($_POST['path_new']);
58
- $_POST['path_new'] = trim($post_path_new);
59
- } else {
60
- $_POST['path_new'] = null;
61
- }
62
-
63
-
64
- $_POST['siteurl'] = isset($_POST['siteurl']) ? rtrim(trim($_POST['siteurl']), '/') : null;
65
- $_POST['tables'] = isset($_POST['tables']) && is_array($_POST['tables']) ? array_map('stripcslashes', $_POST['tables']) : array();
66
- $_POST['url_old'] = isset($_POST['url_old']) ? trim($_POST['url_old']) : null;
67
- $_POST['url_new'] = isset($_POST['url_new']) ? rtrim(trim($_POST['url_new']), '/') : null;
68
- $_POST['retain_config'] = (isset($_POST['retain_config']) && $_POST['retain_config'] == '1') ? true : false;
69
- $_POST['exe_safe_mode'] = isset($_POST['exe_safe_mode']) ? DUPX_U::sanitize_text_field($_POST['exe_safe_mode']) : 0;
70
-
71
-
72
- //MYSQL CONNECTION: If inputs are bad then die
73
- $dbh = DUPX_DB::connect($_POST['dbhost'], $_POST['dbuser'], html_entity_decode($_POST['dbpass']), $_POST['dbname'], $_POST['dbport']);
74
- $dbConnError = (mysqli_connect_error()) ? 'Error: '.mysqli_connect_error() : 'Unable to Connect';
75
- if (!$dbh) {
76
- $msg = "Unable to connect with the following parameters: <br/> <b>HOST:</b> {$_POST['dbhost']}<br/> <b>DATABASE:</b> {$_POST['dbname']}<br/>";
77
- $msg .= "<b>Connection Error:</b> {$dbConnError}";
78
- DUPX_Log::error($msg);
79
- }
80
-
81
- $charset_server = @mysqli_character_set_name($dbh);
82
- @mysqli_query($dbh, "SET wait_timeout = ".mysqli_real_escape_string($dbh, $GLOBALS['DB_MAX_TIME']));
83
- DUPX_DB::setCharset($dbh, $_POST['dbcharset'], $_POST['dbcollate']);
84
-
85
-
86
- //LOGGING
87
- $POST_LOG = $_POST;
88
- unset($POST_LOG['tables']);
89
- unset($POST_LOG['plugins']);
90
- unset($POST_LOG['dbpass']);
91
- ksort($POST_LOG);
92
-
93
- $date = @date('h:i:s');
94
- $charset_client = @mysqli_character_set_name($dbh);
95
-
96
- $log = <<<LOG
97
- \n\n********************************************************************************
98
- * DUPLICATOR-LITE: INSTALL-LOG
99
- * STEP-3 START @ {$date}
100
- * NOTICE: Do NOT post to public sites or forums
101
- ********************************************************************************
102
- CHARSET SERVER:\t{$charset_server}
103
- CHARSET CLIENT:\t{$charset_client}
104
- LOG;
105
- DUPX_Log::info($log);
106
-
107
- //Detailed logging
108
- $log = "--------------------------------------\n";
109
- $log .= "POST DATA\n";
110
- $log .= "--------------------------------------\n";
111
- $log .= print_r($POST_LOG, true);
112
- $log .= "--------------------------------------\n";
113
- $log .= "SCANNED TABLES\n";
114
- $log .= "--------------------------------------\n";
115
- $log .= (isset($_POST['tables']) && count($_POST['tables'] > 0))
116
- ? print_r($_POST['tables'], true)
117
- : 'No tables selected to update';
118
- $log .= "--------------------------------------\n";
119
- $log .= "KEEP PLUGINS ACTIVE\n";
120
- $log .= "--------------------------------------\n";
121
- $log .= (isset($_POST['plugins']) && count($_POST['plugins'] > 0))
122
- ? print_r($_POST['plugins'], true)
123
- : 'No plugins selected for activation';
124
- DUPX_Log::info($log, 2);
125
-
126
- //UPDATE SETTINGS
127
- $blog_name = $_POST['blogname'];
128
- $plugin_list = (isset($_POST['plugins'])) ? $_POST['plugins'] : array();
129
- // Force Duplicator active so we the security cleanup will be available
130
- if (!in_array('duplicator/duplicator.php', $plugin_list)) {
131
- $plugin_list[] = 'duplicator/duplicator.php';
132
- }
133
- $serial_plugin_list = @serialize($plugin_list);
134
-
135
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."options` SET option_value = '{$blog_name}' WHERE option_name = 'blogname' ");
136
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."options` SET option_value = '{$serial_plugin_list}' WHERE option_name = 'active_plugins' ");
137
-
138
- $log = "--------------------------------------\n";
139
- $log .= "SERIALIZER ENGINE\n";
140
- $log .= "[*] scan every column\n";
141
- $log .= "[~] scan only text columns\n";
142
- $log .= "[^] no searchable columns\n";
143
- $log .= "--------------------------------------";
144
- DUPX_Log::info($log);
145
-
146
- $url_old_json = str_replace('"', "", json_encode($_POST['url_old']));
147
- $url_new_json = str_replace('"', "", json_encode($_POST['url_new']));
148
- $path_old_json = str_replace('"', "", json_encode($_POST['path_old']));
149
- $path_new_json = str_replace('"', "", json_encode($_POST['path_new']));
150
-
151
- //DIRS PATHS
152
- array_push($GLOBALS['REPLACE_LIST'],
153
- array('search' => $_POST['path_old'], 'replace' => $_POST['path_new']),
154
- array('search' => $path_old_json, 'replace' => $path_new_json),
155
- array('search' => urlencode($_POST['path_old']), 'replace' => urlencode($_POST['path_new'])),
156
- array('search' => rtrim(DUPX_U::unsetSafePath($_POST['path_old']), '\\'), 'replace' => rtrim($_POST['path_new'], '/'))
157
- );
158
-
159
-
160
- //SEARCH WITH NO PROTOCAL: RAW "//"
161
- $url_old_raw = str_ireplace(array('http://', 'https://'), '//', $_POST['url_old']);
162
- $url_new_raw = str_ireplace(array('http://', 'https://'), '//', $_POST['url_new']);
163
- $url_old_raw_json = str_replace('"', "", json_encode($url_old_raw));
164
- $url_new_raw_json = str_replace('"', "", json_encode($url_new_raw));
165
- array_push($GLOBALS['REPLACE_LIST'],
166
- //RAW
167
- array('search' => $url_old_raw, 'replace' => $url_new_raw),
168
- array('search' => $url_old_raw_json, 'replace' => $url_new_raw_json),
169
- array('search' => urlencode($url_old_raw), 'replace' => urlencode($url_new_raw))
170
- );
171
-
172
-
173
- //SEARCH HTTP(S) EXPLICIT REQUEST
174
- //Because the raw replace above has already changed all urls just fix https/http issue
175
- //if the user has explicitly asked other-wise word boundary issues will occur:
176
- //Old site: http://mydomain.com/somename/
177
- //New site: http://mydomain.com/somename-dup/
178
- //Result: http://mydomain.com/somename-dup-dup/
179
- if (stristr($_POST['url_old'], 'http:') && stristr($_POST['url_new'], 'https:') ) {
180
- $url_old_http = str_ireplace('https:', 'http:', $_POST['url_new']);
181
- $url_new_http = $_POST['url_new'];
182
- $url_old_http_json = str_replace('"', "", json_encode($url_old_http));
183
- $url_new_http_json = str_replace('"', "", json_encode($url_new_http));
184
-
185
- } elseif(stristr($_POST['url_old'], 'https:') && stristr($_POST['url_new'], 'http:')) {
186
- $url_old_http = str_ireplace('http:', 'https:', $_POST['url_new']);
187
- $url_new_http = $_POST['url_new'];
188
- $url_old_http_json = str_replace('"', "", json_encode($url_old_http));
189
- $url_new_http_json = str_replace('"', "", json_encode($url_new_http));
190
- }
191
- if(isset($url_old_http)){
192
- array_push($GLOBALS['REPLACE_LIST'],
193
- array('search' => $url_old_http, 'replace' => $url_new_http),
194
- array('search' => $url_old_http_json, 'replace' => $url_new_http_json),
195
- array('search' => urlencode($url_old_http), 'replace' => urlencode($url_new_http))
196
- );
197
- }
198
-
199
- //Remove trailing slashes
200
- function _dupx_array_rtrim(&$value) {
201
- $value = rtrim($value, '\/');
202
- }
203
- array_walk_recursive($GLOBALS['REPLACE_LIST'], _dupx_array_rtrim);
204
-
205
- @mysqli_autocommit($dbh, false);
206
- $report = DUPX_UpdateEngine::load($dbh, $GLOBALS['REPLACE_LIST'], $_POST['tables'], $_POST['fullsearch']);
207
- @mysqli_commit($dbh);
208
- @mysqli_autocommit($dbh, true);
209
-
210
-
211
- //BUILD JSON RESPONSE
212
- $JSON = array();
213
- $JSON['step2'] = json_decode(urldecode($_POST['json']));
214
- $JSON['step3'] = $report;
215
- $JSON['step3']['warn_all'] = 0;
216
- $JSON['step3']['warnlist'] = array();
217
-
218
- DUPX_UpdateEngine::logStats($report);
219
- DUPX_UpdateEngine::logErrors($report);
220
-
221
- //Reset the postguid data
222
- if ($_POST['postguid']) {
223
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."posts` SET guid = REPLACE(guid, '".mysqli_real_escape_string($dbh, $_POST['url_new'])."', '".mysqli_real_escape_string($dbh, $_POST['url_old'])."')");
224
- $update_guid = @mysqli_affected_rows($dbh) or 0;
225
- DUPX_Log::info("Reverted '{$update_guid}' post guid columns back to '{$_POST['url_old']}'");
226
- }
227
-
228
- /** FINAL UPDATES: Must happen after the global replace to prevent double pathing
229
- http://xyz.com/abc01 will become http://xyz.com/abc0101 with trailing data */
230
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."options` SET option_value = '".mysqli_real_escape_string($dbh, $_POST['url_new'])."' WHERE option_name = 'home' ");
231
- mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."options` SET option_value = '".mysqli_real_escape_string($dbh, $_POST['siteurl'])."' WHERE option_name = 'siteurl' ");
232
- mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."options` (option_value, option_name) VALUES('".mysqli_real_escape_string($dbh, $_POST['exe_safe_mode'])."','duplicator_exe_safe_mode')");
233
-
234
- //===============================================
235
- //CONFIGURATION FILE UPDATES
236
- //===============================================
237
- DUPX_Log::info("\n====================================");
238
- DUPX_Log::info('CONFIGURATION FILE UPDATES:');
239
- DUPX_Log::info("====================================\n");
240
- DUPX_WPConfig::updateStandard();
241
- $config_file = DUPX_WPConfig::updateExtended();
242
- DUPX_Log::info("UPDATED WP-CONFIG: {$root_path}/wp-config.php' (if present)");
243
-
244
- //Web Server Config Updates
245
- if (!isset($_POST['url_new']) || $_POST['retain_config']) {
246
- DUPX_Log::info("\nNOTICE: Manual update of permalinks required see: Admin > Settings > Permalinks > Click Save Changes");
247
- DUPX_Log::info("Retaining the original htaccess, user.ini or web.config files may cause issues with the setup of this site.");
248
- DUPX_Log::info("If you run into issues during or after the install process please uncheck the 'Config Files' checkbox labeled:");
249
- DUPX_Log::info("'Retain original .htaccess, .user.ini and web.config' from Step 1 and re-run the installer. Backups of the");
250
- DUPX_Log::info("orginal config files will be made and can be merged per required directive.");
251
- } else {
252
- DUPX_ServerConfig::setup($dbh);
253
- }
254
-
255
-
256
- //===============================================
257
- //GENERAL UPDATES & CLEANUP
258
- //===============================================
259
- DUPX_Log::info("\n====================================");
260
- DUPX_Log::info('GENERAL UPDATES & CLEANUP:');
261
- DUPX_Log::info("====================================\n");
262
-
263
- /** CREATE NEW USER LOGIC */
264
- if (strlen($_POST['wp_username']) >= 4 && strlen($_POST['wp_password']) >= 6) {
265
- $post_wp_username = DUPX_U::sanitize_text_field($_POST['wp_username']);
266
- $post_wp_password = DUPX_U::sanitize_text_field($_POST['wp_password']);
267
-
268
- $post_wp_username = mysqli_real_escape_string($dbh, $post_wp_username);
269
- $post_wp_password = mysqli_real_escape_string($dbh, $post_wp_password);
270
-
271
- $newuser_check = mysqli_query($dbh, "SELECT COUNT(*) AS count FROM `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."users` WHERE user_login = '{$post_wp_username}' ");
272
- $newuser_row = mysqli_fetch_row($newuser_check);
273
- $newuser_count = is_null($newuser_row) ? 0 : $newuser_row[0];
274
-
275
- if ($newuser_count == 0) {
276
-
277
- $newuser_datetime = @date("Y-m-d H:i:s");
278
- $newuser_security = mysqli_real_escape_string($dbh, 'a:1:{s:13:"administrator";s:1:"1";}');
279
-
280
- $newuser_test1 = @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."users`
281
- (`user_login`, `user_pass`, `user_nicename`, `user_email`, `user_registered`, `user_activation_key`, `user_status`, `display_name`)
282
- VALUES ('{$post_wp_username}', MD5('{$post_wp_password}'), '{$post_wp_username}', '', '{$newuser_datetime}', '', '0', '{$post_wp_username}')");
283
-
284
- $newuser_insert_id = mysqli_insert_id($dbh);
285
-
286
- $newuser_test2 = @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."usermeta`
287
- (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser_insert_id}', '".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."capabilities', '{$newuser_security}')");
288
-
289
- $newuser_test3 = @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."usermeta`
290
- (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser_insert_id}', '".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."user_level', '10')");
291
-
292
- //Misc Meta-Data Settings:
293
- @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser_insert_id}', 'rich_editing', 'true')");
294
- @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser_insert_id}', 'admin_color', 'fresh')");
295
- @mysqli_query($dbh, "INSERT INTO `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ('{$newuser_insert_id}', 'nickname', '{$post_wp_username}')");
296
-
297
- if ($newuser_test1 && $newuser_test2 && $newuser_test3) {
298
- DUPX_Log::info("NEW WP-ADMIN USER: New username '{$_POST['wp_username']}' was created successfully \n ");
299
- } else {
300
- $newuser_warnmsg = "NEW WP-ADMIN USER: Failed to create the user '{".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."}' \n ";
301
- $JSON['step3']['warnlist'][] = $newuser_warnmsg;
302
- DUPX_Log::info($newuser_warnmsg);
303
- }
304
- }
305
- else {
306
- $newuser_warnmsg = "NEW WP-ADMIN USER: Username '{$_POST['wp_username']}' already exists in the database. Unable to create new account \n";
307
- $JSON['step3']['warnlist'][] = $newuser_warnmsg;
308
- DUPX_Log::info($newuser_warnmsg);
309
- }
310
- }
311
-
312
- /** ==============================
313
- * MU Updates*/
314
- $mu_newDomain = parse_url($_POST['url_new']);
315
- $mu_oldDomain = parse_url($_POST['url_old']);
316
- $mu_newDomainHost = $mu_newDomain['host'];
317
- $mu_oldDomainHost = $mu_oldDomain['host'];
318
- $mu_newUrlPath = parse_url($_POST['url_new'], PHP_URL_PATH);
319
- $mu_oldUrlPath = parse_url($_POST['url_old'], PHP_URL_PATH);
320
-
321
- //Force a path for PATH_CURRENT_SITE
322
- $mu_newUrlPath = (empty($mu_newUrlPath) || ($mu_newUrlPath == '/')) ? '/' : rtrim($mu_newUrlPath, '/') . '/';
323
- $mu_oldUrlPath = (empty($mu_oldUrlPath) || ($mu_oldUrlPath == '/')) ? '/' : rtrim($mu_oldUrlPath, '/') . '/';
324
-
325
- $mu_updates = @mysqli_query($dbh, "UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."blogs` SET domain = '".mysqli_real_escape_string($dbh, $mu_newDomainHost)."' WHERE domain = '".mysqli_real_escape_string($dbh, $mu_oldDomainHost)."'");
326
- if ($mu_updates) {
327
- DUPX_Log::info("Update MU table blogs: domain {$mu_newDomainHost} ");
328
- DUPX_Log::info("UPDATE `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."blogs` SET domain = '".mysqli_real_escape_string($dbh, $mu_newDomainHost)."' WHERE domain = '".mysqli_real_escape_string($dbh, $mu_oldDomainHost)."'");
329
- }
330
-
331
-
332
- //Create snapshots directory in order to
333
- //compensate for permissions on some servers
334
- if (!file_exists(DUPLICATOR_SSDIR_NAME)) {
335
- mkdir(DUPLICATOR_SSDIR_NAME, 0755);
336
- DUPX_Log::info("- Created directory ". DUPLICATOR_SSDIR_NAME);
337
- }
338
- $fp = fopen(DUPLICATOR_SSDIR_NAME . '/index.php', 'w');
339
- fclose($fp);
340
- DUPX_Log::info("- Created file ". DUPLICATOR_SSDIR_NAME . '/index.php');
341
-
342
-
343
-
344
- //===============================================
345
- //NOTICES TESTS
346
- //===============================================
347
- DUPX_Log::info("\n====================================");
348
- DUPX_Log::info("NOTICES");
349
- DUPX_Log::info("====================================\n");
350
- $config_vars = array('WPCACHEHOME', 'COOKIE_DOMAIN', 'WP_SITEURL', 'WP_HOME', 'WP_TEMP_DIR');
351
- $config_found = DUPX_U::getListValues($config_vars, $config_file);
352
-
353
- //Config File:
354
- if (! empty($config_found)) {
355
- $msg = "NOTICE: The wp-config.php has the following values set [" . implode(", ", $config_found) . "]. \n";
356
- $msg .= 'Please validate these values are correct in your wp-config.php file. See the codex link for more details: https://codex.wordpress.org/Editing_wp-config.php';
357
- $JSON['step3']['warnlist'][] = $msg;
358
- DUPX_Log::info($msg);
359
- }
360
-
361
- //Database:
362
- $result = @mysqli_query($dbh, "SELECT option_value FROM `".mysqli_real_escape_string($dbh, $GLOBALS['FW_TABLEPREFIX'])."options` WHERE option_name IN ('upload_url_path','upload_path')");
363
- if ($result) {
364
- while ($row = mysqli_fetch_row($result)) {
365
- if (strlen($row[0])) {
366
- $msg = "NOTICE: The media settings values in the table '{$GLOBALS['FW_TABLEPREFIX']}options' has at least one the following values ['upload_url_path','upload_path'] set. \n";
367
- $msg .= "Please validate these settings by logging into your wp-admin and going to Settings->Media area and validating the 'Uploading Files' section";
368
- $JSON['step3']['warnlist'][] = $msg;
369
- DUPX_Log::info($msg);
370
- break;
371
- }
372
- }
373
- }
374
-
375
- if (empty($JSON['step3']['warnlist'])) {
376
- DUPX_Log::info("No Notices Found\n");
377
- }
378
-
379
- $JSON['step3']['warn_all'] = empty($JSON['step3']['warnlist']) ? 0 : count($JSON['step3']['warnlist']);
380
-
381
- mysqli_close($dbh);
382
-
383
- $ajax2_end = DUPX_U::getMicrotime();
384
- $ajax2_sum = DUPX_U::elapsedTime($ajax2_end, $ajax2_start);
385
- DUPX_Log::info("\nSTEP 3 COMPLETE @ " . @date('h:i:s') . " - RUNTIME: {$ajax2_sum}\n\n");
386
-
387
- $JSON['step3']['pass'] = 1;
388
- error_reporting($ajax2_error_level);
389
- die(json_encode($JSON));
390
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/main.installer.php DELETED
@@ -1,418 +0,0 @@
1
- <?php
2
- /*
3
- Copyright 2011-17 snapcreek.com
4
-
5
- This program is free software; you can redistribute it and/or modify
6
- it under the terms of the GNU General Public License, version 3, as
7
- published by the Free Software Foundation.
8
-
9
- This program is distributed in the hope that it will be useful,
10
- but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- GNU General Public License for more details.
13
-
14
- You should have received a copy of the GNU General Public License
15
- along with this program; if not, write to the Free Software
16
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
- GPL v3 https://www.gnu.org/licenses/gpl-3.0.en.html
18
- */
19
-
20
- if ( !defined('DUPXABSPATH') )
21
- define('DUPXABSPATH', dirname(__FILE__) . '/');
22
-
23
- if (file_exists('dtoken.php')) {
24
- //This is most likely inside the snapshot folder.
25
-
26
- //DOWNLOAD ONLY: (Only enable download from within the snapshot directory)
27
- if (isset($_GET['get']) && isset($_GET['file'])) {
28
- //Clean the input, strip out anything not alpha-numeric or "_.", so restricts
29
- //only downloading files in same folder, and removes risk of allowing directory
30
- //separators in other charsets (vulnerability in older IIS servers), also
31
- //strips out anything that might cause it to use an alternate stream since
32
- //that would require :// near the front.
33
- $filename = preg_replace('/[^a-zA-Z0-9_.]*/','',$_GET['file']);
34
- if (strlen($filename) && file_exists($filename) && (strstr($filename, '_installer.php'))) {
35
- //Attempt to push the file to the browser
36
- header('Content-Description: File Transfer');
37
- header('Content-Type: application/octet-stream');
38
- header('Content-Disposition: attachment; filename=installer.php');
39
- header('Content-Transfer-Encoding: binary');
40
- header('Expires: 0');
41
- header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
42
- header('Pragma: public');
43
- header('Content-Length: ' . filesize($filename));
44
- @ob_clean();
45
- @flush();
46
- if (@readfile($filename) == false) {
47
- $data = file_get_contents($filename);
48
- if ($data == false) {
49
- die("Unable to read installer file. The server currently has readfile and file_get_contents disabled on this server. Please contact your server admin to remove this restriction");
50
- } else {
51
- print $data;
52
- }
53
- }
54
- } else {
55
- header("HTTP/1.1 404 Not Found", true, 404);
56
- header("Status: 404 Not Found");
57
- }
58
- }
59
- //Prevent Access from rovers or direct browsing in snapshop directory, or when
60
- //requesting to download a file, should not go past this point.
61
- exit;
62
- }
63
-
64
- /* ==============================================================================================
65
- ADVANCED FEATURES - Allows admins to perform aditional logic on the import.
66
-
67
- $GLOBALS['REPLACE_LIST']
68
- Add additional search and replace items to step 2 for the serialize engine.
69
- Place directly below $GLOBALS['REPLACE_LIST'] variable below your items
70
- EXAMPLE:
71
- array_push($GLOBALS['REPLACE_LIST'], array('search' => 'https://oldurl/', 'replace' => 'https://newurl/'));
72
- array_push($GLOBALS['REPLACE_LIST'], array('search' => 'ftps://oldurl/', 'replace' => 'ftps://newurl/'));
73
- ================================================================================================= */
74
-
75
- // Some machines don’t have this set so just do it here.
76
- date_default_timezone_set('UTC');
77
-
78
- //PATCH FOR IIS: Does not support REQUEST_URI
79
- if (!isset($_SERVER['REQUEST_URI'])) {
80
- $_SERVER['REQUEST_URI'] = substr($_SERVER['PHP_SELF'],0);
81
- if (isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != "") {
82
- $_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
83
- }
84
- }
85
-
86
- //COMPARE VALUES
87
- $GLOBALS['DUPX_DEBUG'] = false;
88
- $GLOBALS['DUPX_DBPASS_CHECK'] = true;
89
- $GLOBALS['FW_CREATED'] = '%fwrite_created%';
90
- $GLOBALS['FW_VERSION_DUP'] = '%fwrite_version_dup%';
91
- $GLOBALS['FW_VERSION_WP'] = '%fwrite_version_wp%';
92
- $GLOBALS['FW_VERSION_DB'] = '%fwrite_version_db%';
93
- $GLOBALS['FW_VERSION_PHP'] = '%fwrite_version_php%';
94
- $GLOBALS['FW_VERSION_OS'] = '%fwrite_version_os%';
95
- //GENERAL
96
- $GLOBALS['FW_TABLEPREFIX'] = '%fwrite_wp_tableprefix%';
97
- $GLOBALS['FW_URL_OLD'] = '%fwrite_url_old%';
98
- $GLOBALS['FW_PACKAGE_NAME'] = '%fwrite_archive_name%';
99
- $GLOBALS['FW_PACKAGE_NOTES'] = '%fwrite_package_notes%';
100
- $GLOBALS['FW_PACKAGE_EST_SIZE'] = '%fwrite_package_size%';
101
- $GLOBALS['FW_SECURE_NAME'] = '%fwrite_secure_name%';
102
- $GLOBALS['FW_DBHOST'] = '%fwrite_dbhost%';
103
- $GLOBALS['FW_DBHOST'] = empty($GLOBALS['FW_DBHOST']) ? 'localhost' : $GLOBALS['FW_DBHOST'];
104
- $GLOBALS['FW_DBPORT'] = '%fwrite_dbport%';
105
- $GLOBALS['FW_DBPORT'] = empty($GLOBALS['FW_DBPORT']) ? 3306 : $GLOBALS['FW_DBPORT'];
106
- $GLOBALS['FW_DBNAME'] = '%fwrite_dbname%';
107
- $GLOBALS['FW_DBUSER'] = '%fwrite_dbuser%';
108
- $GLOBALS['FW_DBPASS'] = '%fwrite_dbpass%';
109
- $GLOBALS['FW_SECUREON'] = '%fwrite_secureon%';
110
- $GLOBALS['FW_SECUREPASS'] = '%fwrite_securepass%';
111
- $GLOBALS['FW_BLOGNAME'] = '%fwrite_blogname%';
112
- $GLOBALS['FW_WPROOT'] = '%fwrite_wproot%';
113
- $GLOBALS['FW_WPLOGIN_URL'] = '%fwrite_wplogin_url%';
114
- $GLOBALS['FW_OPTS_DELETE'] = json_decode("%fwrite_opts_delete%", true);
115
- $GLOBALS['FW_DUPLICATOR_VERSION'] = '%fwrite_duplicator_version%';
116
- $GLOBALS['FW_ARCHIVE_ONLYDB'] = '%fwrite_archive_onlydb%';
117
- $GLOBALS['PACKAGE_HASH'] = '%package_hash%';
118
-
119
- //DATABASE SETUP: all time in seconds
120
- $GLOBALS['DB_MAX_TIME'] = 5000;
121
- $GLOBALS['DB_MAX_PACKETS'] = 268435456;
122
- $GLOBALS['DB_FCGI_FLUSH'] = false;
123
- ini_set('mysql.connect_timeout', '5000');
124
-
125
- //PHP SETUP: all time in seconds
126
- ini_set('memory_limit', '2048M');
127
- ini_set("max_execution_time", '5000');
128
- ini_set("max_input_time", '5000');
129
- ini_set('default_socket_timeout', '5000');
130
- @set_time_limit(0);
131
-
132
- $GLOBALS['DBCHARSET_DEFAULT'] = 'utf8';
133
- $GLOBALS['DBCOLLATE_DEFAULT'] = 'utf8_general_ci';
134
- $GLOBALS['FAQ_URL'] = 'https://snapcreek.com/duplicator/docs/faqs-tech';
135
- $GLOBALS['NOW_DATE'] = @date("Y-m-d-H:i:s");
136
- $GLOBALS['DB_RENAME_PREFIX'] = 'x-bak__';
137
-
138
- //UPDATE TABLE SETTINGS
139
- $GLOBALS['REPLACE_LIST'] = array();
140
-
141
-
142
- /** ================================================================================================
143
- END ADVANCED FEATURES: Do not edit below here.
144
- =================================================================================================== */
145
-
146
- //CONSTANTS
147
- define("DUPLICATOR_INIT", 1);
148
- define("DUPLICATOR_SSDIR_NAME", 'wp-snapshots'); //This should match DUPLICATOR_SSDIR_NAME in duplicator.php
149
-
150
- //SHARED POST PARMS
151
- $_POST['action_step'] = isset($_POST['action_step']) ? DUPX_U::sanitize_text_field($_POST['action_step']) : "0";
152
- $_POST['secure-pass'] = isset($_POST['secure-pass']) ? DUPX_U::sanitize_text_field($_POST['secure-pass']) : '';
153
-
154
- if ($GLOBALS['FW_SECUREON']) {
155
- $pass_hasher = new DUPX_PasswordHash(8, FALSE);
156
- $post_secure_pass = DUPX_U::sanitize_text_field($_POST['secure-pass']);
157
- $pass_check = $pass_hasher->CheckPassword(base64_encode($post_secure_pass), $GLOBALS['FW_SECUREPASS']);
158
- if (! $pass_check) {
159
- $_POST['action_step'] = 0;
160
- }
161
- }
162
-
163
- /** Host has several combinations :
164
- localhost | localhost:55 | localhost: | http://localhost | http://localhost:55 */
165
- if (isset($_POST['dbhost'])) {
166
- $post_db_host = DUPX_U::sanitize_text_field($_POST['dbhost']);
167
- $_POST['dbhost'] = DUPX_U::sanitize_text_field($post_db_host);
168
- } else {
169
- $_POST['dbhost'] = null;
170
- }
171
-
172
- if (isset($_POST['dbport'])) {
173
- $post_db_port = DUPX_U::sanitize_text_field($_POST['dbport']);
174
- $_POST['dbport'] = trim($post_db_port);
175
- } else {
176
- $_POST['dbport'] = 3306;
177
- }
178
-
179
- $_POST['dbuser'] = isset($_POST['dbuser']) ? DUPX_U::sanitize_text_field($_POST['dbuser']) : null;
180
-
181
- if (isset($_POST['dbpass'])) {
182
- $post_db_pass = DUPX_U::sanitize_text_field($_POST['dbpass']);
183
- $_POST['dbpass'] = trim($post_db_pass);
184
- } else {
185
- $_POST['dbpass'] = null;
186
- }
187
-
188
-
189
- if (isset($_POST['dbname'])) {
190
- $post_db_name = DUPX_U::sanitize_text_field($_POST['dbname']);
191
- $_POST['dbname'] = trim($post_db_name);
192
- } else {
193
- $_POST['dbname'] = null;
194
- }
195
-
196
- if (isset($_POST['dbcharset'])) {
197
- $post_db_charset = DUPX_U::sanitize_text_field($_POST['dbcharset']);
198
- $_POST['dbcharset'] = trim($post_db_charset);
199
- } else {
200
- $_POST['dbcharset'] = $GLOBALS['DBCHARSET_DEFAULT'];
201
- }
202
-
203
- if (isset($_POST['dbcollate'])) {
204
- $post_db_collate = DUPX_U::sanitize_text_field($_POST['dbcollate']);
205
- $_POST['dbcollate'] = trim($post_db_collate);
206
- } else {
207
- $_POST['dbcollate'] = $GLOBALS['DBCOLLATE_DEFAULT'];
208
- }
209
-
210
- //GLOBALS
211
- // Constants which are dependent on the $GLOBALS['DUPX_AC']
212
- $GLOBALS['SQL_FILE_NAME'] = "dup-installer-data__{$GLOBALS['PACKAGE_HASH']}.sql";
213
- $GLOBALS['LOG_FILE_NAME'] = "dup-installer-log__{$GLOBALS['PACKAGE_HASH']}.txt";
214
- $GLOBALS['LOGGING'] = isset($_POST['logging']) ? DUPX_U::sanitize_text_field($_POST['logging']) : 1;
215
- $GLOBALS['CURRENT_ROOT_PATH'] = dirname(__FILE__);
216
- $GLOBALS['CHOWN_ROOT_PATH'] = @chmod("{$GLOBALS['CURRENT_ROOT_PATH']}", 0755);
217
- $GLOBALS['CHOWN_LOG_PATH'] = @chmod("{$GLOBALS['CURRENT_ROOT_PATH']}/{$GLOBALS['LOG_FILE_NAME']}", 0644);
218
- $GLOBALS['URL_SSL'] = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? true : false;
219
- $GLOBALS['URL_PATH'] = ($GLOBALS['URL_SSL']) ? "https://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}" : "http://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}";
220
- $GLOBALS['PHP_MEMORY_LIMIT'] = ini_get('memory_limit') === false ? 'n/a' : ini_get('memory_limit');
221
- $GLOBALS['PHP_SUHOSIN_ON'] = extension_loaded('suhosin') ? 'enabled' : 'disabled';
222
- $GLOBALS['ARCHIVE_PATH'] = $GLOBALS['CURRENT_ROOT_PATH'] . '/' . $GLOBALS['FW_PACKAGE_NAME'];
223
- $GLOBALS['ARCHIVE_PATH'] = str_replace("\\", "/", $GLOBALS['ARCHIVE_PATH']);
224
- if (isset($_GET["view"])) {
225
- $GLOBALS["VIEW"] = $_GET["view"];
226
- } elseif (!empty($_POST["view"])) {
227
- $GLOBALS["VIEW"] = $_POST["view"];
228
- } else {
229
- $GLOBALS["VIEW"] = 'step1';
230
- }
231
-
232
- //Restart log if user starts from step 1
233
- if ($_POST['action_step'] == 1 && ! isset($_GET['help'])) {
234
- $GLOBALS['LOG_FILE_HANDLE'] = @fopen($GLOBALS['LOG_FILE_NAME'], "w+");
235
- } else {
236
- $GLOBALS['LOG_FILE_HANDLE'] = @fopen($GLOBALS['LOG_FILE_NAME'], "a+");
237
- }
238
- ?>
239
- @@CLASS.U.PHP@@
240
- @@CLASS.CSRF.PHP@@
241
- @@CLASS.SERVER.PHP@@
242
- @@CLASS.DB.PHP@@
243
- @@CLASS.LOGGING.PHP@@
244
- @@CLASS.ENGINE.PHP@@
245
- @@CLASS.CONF.WP.PHP@@
246
- @@CLASS.CONF.SRV.PHP@@
247
- @@CLASS.HTTP.PHP@@
248
- @@CLASS.PASSWORD.PHP@@
249
- <?php
250
- // CSRF checking
251
- if (!empty($GLOBAL['view'])) {
252
- $csrf_views = array(
253
- 'secure',
254
- 'step1',
255
- 'step2',
256
- 'step3',
257
- 'step4',
258
- );
259
- if (in_array($GLOBAL['view'], $csrf_views)) {
260
- if (!DUPX_CSRF::check($_POST['csrf_token'], $GLOBAL['view'])) {
261
- die('CSRF security issue for the view: '.$GLOBAL['view']);
262
- }
263
- }
264
- }
265
-
266
- if (isset($_POST['action_ajax'])) :
267
-
268
- if ($GLOBALS['FW_SECUREON']) {
269
- $pass_hasher = new DUPX_PasswordHash(8, FALSE);
270
- $pass_check = $pass_hasher->CheckPassword(base64_encode($_POST['secure-pass']), $GLOBALS['FW_SECUREPASS']);
271
- if (! $pass_check) {
272
- die("Unauthorized Access: Please provide a password!");
273
- }
274
- }
275
-
276
- //Alternative control switch structer will not work in this case
277
- //see: http://php.net/manual/en/control-structures.alternative-syntax.php
278
- //Some clients will create double spaces such as the FTP client which
279
- //will break example found online
280
- switch ($_POST['action_ajax']) :
281
-
282
- case "1": ?>@@CTRL.STEP1.PHP@@<?php break;
283
-
284
- case "2": ?>@@CTRL.STEP2.PHP@@<?php break;
285
-
286
- case "3": ?>@@CTRL.STEP3.PHP@@<?php break;
287
-
288
- endswitch;
289
-
290
- @fclose($GLOBALS["LOG_FILE_HANDLE"]);
291
- die("");
292
-
293
- endif;
294
- ?>
295
-
296
- <!DOCTYPE html>
297
- <html>
298
- <head>
299
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
300
- <meta name="robots" content="noindex,nofollow">
301
- <title>Duplicator</title>
302
- @@INC.LIBS.CSS.PHP@@
303
- @@INC.CSS.PHP@@
304
- @@INC.LIBS.JS.PHP@@
305
- @@INC.JS.PHP@@
306
- </head>
307
- <body>
308
-
309
- <div id="content">
310
- <!-- =========================================
311
- HEADER TEMPLATE: Common header on all steps -->
312
- <table cellspacing="0" class="dupx-header">
313
- <tr>
314
- <td style="width:100%;">
315
- <div style="font-size:26px; padding:7px 0 7px 0">
316
- <!-- !!DO NOT CHANGE/EDIT OR REMOVE PRODUCT NAME!!
317
- If your interested in Private Label Rights please contact us at the URL below to discuss
318
- customizations to product labeling: http://snapcreek.com -->
319
- &nbsp; Duplicator
320
- </div>
321
- </td>
322
- <td class="dupx-header-version">
323
- <a href="javascript:void(0)" onclick="DUPX.showServerInfo()">version: <?php echo DUPX_U::esc_html($GLOBALS['FW_DUPLICATOR_VERSION']); ?></a><br/>
324
- <a href="?help=1" target="_blank">help</a>
325
- <?php
326
- echo ' &raquo; <a href="?help=1#secure" target="_blank">';
327
- echo ($GLOBALS['FW_SECUREON']) ? 'locked</a>' : '<i class="secure-unlocked">unlocked</i></a>';
328
- ?>
329
- </td>
330
- </tr>
331
- </table>
332
-
333
- <div style="position: relative">
334
- <div class="installer-mode">
335
- <?php
336
- echo 'Mode: ';
337
- echo ($GLOBALS['FW_ARCHIVE_ONLYDB']) ? 'Database Only' : 'Standard';
338
- ?>
339
- </div>
340
- </div>
341
-
342
- <!-- =========================================
343
- FORM DATA: Data Steps -->
344
- <div id="content-inner">
345
- <?php
346
-
347
- if (! isset($_GET['help'])) {
348
- switch ($_POST['action_step']) {
349
- case "0" :
350
- ?> @@VIEW.INIT1.PHP@@ <?php
351
- break;
352
- case "1" :
353
- ?> @@VIEW.STEP1.PHP@@ <?php
354
- break;
355
- case "2" :
356
- ?> @@VIEW.STEP2.PHP@@ <?php
357
- break;
358
- case "3" :
359
- ?> @@VIEW.STEP3.PHP@@ <?php
360
- break;
361
- case "4" :
362
- ?> @@VIEW.STEP4.PHP@@ <?php
363
- break;
364
- }
365
- } else {
366
- ?> @@VIEW.HELP.PHP@@ <?php
367
- }
368
-
369
- ?>
370
- </div>
371
- </div><br/>
372
-
373
-
374
- <!-- CONFIRM DIALOG -->
375
- <div id="dialog-server-info" style="display:none">
376
- <!-- DETAILS -->
377
- <div class="dlg-serv-info">
378
- <?php
379
- $ini_path = php_ini_loaded_file();
380
- $ini_max_time = ini_get('max_execution_time');
381
- $ini_memory = ini_get('memory_limit');
382
- ?>
383
- <div class="hdr">Current Server</div>
384
- <label>Web Server:</label> <?php echo DUPX_U::esc_html($_SERVER['SERVER_SOFTWARE']); ?><br/>
385
- <label>Operating System:</label> <?php echo DUPX_U::esc_html(PHP_OS); ?><br/>
386
- <label>PHP Version:</label> <?php echo DUPX_U::esc_html(DUPX_Server::$php_version); ?><br/>
387
- <label>PHP INI Path:</label> <?php echo empty($ini_path ) ? 'Unable to detect loaded php.ini file' : $ini_path; ?> <br/>
388
- <label>PHP SAPI:</label> <?php echo DUPX_U::esc_html(php_sapi_name()); ?><br/>
389
- <label>PHP ZIP Archive:</label> <?php echo class_exists('ZipArchive') ? 'Is Installed' : 'Not Installed'; ?> <br/>
390
- <label>PHP max_execution_time:</label> <?php echo $ini_max_time === false ? 'unable to find' : DUPX_U::esc_html($ini_max_time); ?><br/>
391
- <label>PHP memory_limit:</label> <?php echo empty($ini_memory) ? 'unable to find' : DUPX_U::esc_html($ini_memory); ?><br/>
392
-
393
- <br/>
394
- <div class="hdr">Package Server</div>
395
- <div class="info-txt">The server where the package was created</div>
396
- <label>Plugin Version:</label> <?php echo DUPX_U::esc_html($GLOBALS['FW_VERSION_DUP']); ?><br/>
397
- <label>WordPress Version:</label> <?php echo DUPX_U::esc_html($GLOBALS['FW_VERSION_WP']); ?><br/>
398
- <label>PHP Version:</label> <?php echo DUPX_U::esc_html($GLOBALS['FW_VERSION_PHP']); ?><br/>
399
- <label>Database Version:</label> <?php echo DUPX_U::esc_html($GLOBALS['FW_VERSION_DB']); ?><br/>
400
- <label>Operating System:</label> <?php echo DUPX_U::esc_html($GLOBALS['FW_VERSION_OS']); ?><br/>
401
- <br/><br/>
402
- </div>
403
- </div>
404
-
405
- <script>
406
- /* Server Info Dialog*/
407
- DUPX.showServerInfo = function()
408
- {
409
- modal({
410
- type: 'alert',
411
- title: 'Server Information',
412
- text: $('#dialog-server-info').html()
413
- });
414
- }
415
- </script>
416
-
417
- </body>
418
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/view.step1.php DELETED
@@ -1,798 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
- //VIEW: STEP 1- INPUT
4
-
5
- //ARCHIVE FILE
6
- $arcStatus = (file_exists($GLOBALS['ARCHIVE_PATH'])) ? 'Pass' : 'Fail';
7
- $arcFormat = ($arcStatus == 'Pass') ? 'Pass' : 'StatusFailed';
8
- $arcSize = @filesize($GLOBALS['ARCHIVE_PATH']);
9
- $arcSize = is_numeric($arcSize) ? $arcSize : 0;
10
- $zip_archive_enabled = class_exists('ZipArchive') ? 'Enabled' : 'Not Enabled';
11
-
12
- $arcSizeRatio = (((1.0) * $arcSize) / $GLOBALS['FW_PACKAGE_EST_SIZE']) * 100;
13
- $arcSizeStatus = ($arcSizeRatio > 90) ? 'Pass' : 'Fail';
14
-
15
- //ARCHIVE FORMAT
16
- if ($arcStatus) {
17
- if (class_exists('ZipArchive')){
18
- $zip = new ZipArchive();
19
- if($zip->open($GLOBALS['ARCHIVE_PATH']) === TRUE ) {
20
-
21
- $arcFilePath = basename($GLOBALS['ARCHIVE_PATH']);
22
- $arcFilePath = substr($arcFilePath, 0, strrpos($arcFilePath, "."));
23
- //Some systems the __MACOSX folder can cause issues on others it works fine removing
24
- //until further reports are discovered, removed on 04-06-2018
25
- //$badFiles = array('__MACOSX', $arcFilePath);
26
- $badFiles = array('', $arcFilePath);
27
- $goodFiles = array("dup-database__{$GLOBALS['PACKAGE_HASH']}.sql", 'installer-backup.php');
28
- $goodFilesFound = true;
29
- $badFilesFound = false;
30
-
31
- foreach ($badFiles as $val) {
32
- if (is_numeric($zip->locateName("{$val}/"))) {
33
- $badFilesFound = true;
34
- break;
35
- }
36
- }
37
-
38
- foreach ($goodFiles as $val) {
39
- if ($zip->locateName($val) !== true) {
40
- $goodFilesFound = false;
41
- }
42
- }
43
-
44
- $arcFormat = ($goodFilesFound == false && $badFilesFound == true) ? 'Fail' : 'Pass';
45
- }
46
- } else {
47
- $arcFormat = 'NoZipArchive';
48
- }
49
- }
50
-
51
- $all_arc = ($arcStatus == 'Pass' && $arcFormat != 'Fail' && $arcSizeStatus == 'Pass') ? 'Pass' : 'Fail';
52
-
53
- //REQUIRMENTS
54
- $req = array();
55
- $req['01'] = DUPX_Server::isDirWritable($GLOBALS["CURRENT_ROOT_PATH"]) ? 'Pass' : 'Fail';
56
- $req['02'] = 'Pass'; //Place-holder for future check
57
- $req['03'] = 'Pass'; //Place-holder for future check;
58
- $req['04'] = function_exists('mysqli_connect') ? 'Pass' : 'Fail';
59
- $req['05'] = DUPX_Server::$php_version_safe ? 'Pass' : 'Fail';
60
- $all_req = in_array('Fail', $req) ? 'Fail' : 'Pass';
61
-
62
- //NOTICES
63
- $openbase = ini_get("open_basedir");
64
- $scanfiles = @scandir($GLOBALS["CURRENT_ROOT_PATH"]);
65
- $scancount = is_array($scanfiles) ? (count($scanfiles)) : -1;
66
- $datetime1 = $GLOBALS['FW_CREATED'];
67
- $datetime2 = date("Y-m-d H:i:s");
68
- $fulldays = round(abs(strtotime($datetime1) - strtotime($datetime2))/86400);
69
- $root_path = DUPX_U::setSafePath($GLOBALS['CURRENT_ROOT_PATH']);
70
- $wpconf_path = "{$root_path}/wp-config.php";
71
- $max_time_zero = @set_time_limit(0);
72
- $max_time_size = 314572800; //300MB
73
- $max_time_ini = ini_get('max_execution_time');
74
- $max_time_warn = (is_numeric($max_time_ini) && $max_time_ini < 31 && $max_time_ini > 0) && $arcSize > $max_time_size;
75
-
76
-
77
- $notice = array();
78
- if (!$GLOBALS['FW_ARCHIVE_ONLYDB']) {
79
- $notice['01'] = ! file_exists($wpconf_path) ? 'Good' : 'Warn';
80
- $notice['02'] = $scancount <= 35 ? 'Good' : 'Warn';
81
- }
82
- $notice['03'] = $fulldays <= 120 ? 'Good' : 'Warn';
83
- $notice['04'] = 'Good'; //Place-holder for future check
84
- $notice['05'] = DUPX_Server::$php_version_53_plus ? 'Good' : 'Warn';
85
- $notice['06'] = empty($openbase) ? 'Good' : 'Warn';
86
- $notice['07'] = ! $max_time_warn ? 'Good' : 'Warn';
87
- $all_notice = in_array('Warn', $notice) ? 'Warn' : 'Good';
88
-
89
- //SUMMATION
90
- $req_success = ($all_req == 'Pass');
91
- $req_notice = ($all_notice == 'Good');
92
- $all_success = ($req_success && $req_notice);
93
- $agree_msg = "To enable this button the checkbox above under the 'Terms & Notices' must be checked.";
94
-
95
- //Get Size Data
96
- $projectedSize = DUPX_U::readableByteSize($GLOBALS['FW_PACKAGE_EST_SIZE']);
97
- $actualSize = DUPX_U::readableByteSize($arcSize);
98
- ?>
99
-
100
-
101
- <form id='s1-input-form' method="post" class="content-form" >
102
- <input type="hidden" name="action_ajax" value="1" />
103
- <input type="hidden" name="action_step" value="1" />
104
- <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
105
-
106
- <div class="hdr-main">
107
- Step <span class="step">1</span> of 4: Deployment
108
- </div>
109
- <br/>
110
-
111
-
112
- <!-- ====================================
113
- ARCHIVE
114
- ==================================== -->
115
- <div class="hdr-sub1" id="s1-area-archive-file-link" data-type="toggle" data-target="#s1-area-archive-file">
116
- <a href="javascript:void(0)"><i class="dupx-plus-square"></i> Archive</a>
117
- <div class="<?php echo ($all_arc == 'Pass') ? 'status-badge-pass' : 'status-badge-fail'; ?>" style="float:right">
118
- <?php echo ($all_arc == 'Pass') ? 'Pass' : 'Fail'; ?>
119
- </div>
120
- </div>
121
- <div id="s1-area-archive-file" style="display:none">
122
-
123
- <table class="s1-archive-local">
124
- <tr>
125
- <td colspan="2"><div class="hdr-sub3">Site Details</div></td>
126
- </tr>
127
- <tr>
128
- <td>Site:</td>
129
- <td><?php echo DUPX_U::esc_html($GLOBALS['FW_BLOGNAME']);?> </td>
130
- </tr>
131
- <tr>
132
- <td>Notes:</td>
133
- <td><?php echo strlen($GLOBALS['FW_PACKAGE_NOTES']) ? DUPX_U::esc_html($GLOBALS['FW_PACKAGE_NOTES']) : " - no notes - ";?></td>
134
- </tr>
135
- <?php if ($GLOBALS['FW_ARCHIVE_ONLYDB']) :?>
136
- <tr>
137
- <td>Mode:</td>
138
- <td>Archive only database was enabled during package package creation.</td>
139
- </tr>
140
- <?php endif; ?>
141
- </table>
142
-
143
- <table class="s1-archive-local">
144
- <tr>
145
- <td colspan="2"><div class="hdr-sub3">File Details</div></td>
146
- </tr>
147
- <tr>
148
- <td>Status:</td>
149
- <td>
150
- <?php if ($arcStatus != 'Fail') : ?>
151
- <span class="dupx-pass">Archive File Found</span>
152
- <?php else : ?>
153
- <div class="s1-archive-failed-msg">
154
- <b class="dupx-fail">Archive File Not Found!</b><br/>
155
- The installer file and the archive are bound together as a package when the archive is built. They must be downloaded together and used
156
- together at install time. The archive file name should <u>not</u> be changed when it is downloaded because the file name is strongly bound
157
- to the installer. When downloading the package files make sure both files are from the same package line in the packages view within the
158
- Duplicator WordPress admin.
159
- <br/><br/>
160
-
161
- The full archive file name must be <u>exactly</u> the same as when it was built (character for character), or the installer will not work properly.
162
- To find out the exact archive name that is bound to this installer open the installer.php file with a text editor and search for the text
163
- $GLOBALS['FW_PACKAGE_NAME']. Check to see what that value is assigned to and that should be the name of the archive file placed in the same path
164
- as this installer.
165
- <br/><br/>
166
-
167
- The following zip files were found at the deployment path:
168
- <?php
169
- //DETECT ARCHIVE FILES
170
- $zip_files = DUPX_Server::getZipFiles();
171
- $zip_count = count($zip_files);
172
-
173
- if ($zip_count >= 1) {
174
- echo "<ol style='padding:10px 20px 0 20px; font-style:italic'>";
175
- foreach($zip_files as $file) {
176
- echo "<li> '{$file}'</li>";
177
- }
178
- echo "</ol>";
179
- } else {
180
- echo "<br/><br/> <i>- No zip files found -</i>";
181
- }
182
- ?>
183
- </div>
184
- <?php endif; ?>
185
- </td>
186
- </tr>
187
- <tr>
188
- <tr>
189
- <td>Path:</td>
190
- <td><?php echo "{$GLOBALS['CURRENT_ROOT_PATH']}";?> </td>
191
- </tr>
192
- <td>Size:</td>
193
- <td>
194
- <?php if ($arcSizeStatus == 'Pass' ) : ?>
195
- <?php echo "{$actualSize}"?>
196
- <?php elseif ($arcStatus == 'Fail') : ?>
197
- <span class="dupx-fail">Archive file not found!</span>
198
- <?php else : ?>
199
- <div class="s1-archive-failed-msg">
200
- <b class='dupx-fail'>Archive File Size Incorrect!</b><br/>
201
- The archive is showing a size that is currently as <b><?php echo DUPX_U::esc_html($actualSize); ?></b>. Its estimated file size should be around
202
- <b><?php echo DUPX_U::esc_html($projectedSize); ?></b>. The archive file may not have been fully downloaded to the server. If so please wait for the file
203
- to completely download and then refresh this page.<br/><br/>
204
-
205
- This warning is only shown when the file has more than a 10% size ratio difference from when it was originally built. Please review the file sizes
206
- to make sure the archive was downloaded to this server correctly when the download is complete.
207
- </div>
208
- <?php endif; ?>
209
- </td>
210
- </tr>
211
- <tr>
212
- <td>Format:</td>
213
- <td>
214
- <?php if ($arcFormat == 'Pass') : ?>
215
- <span class="dupx-pass">Good structure</span>
216
- <?php elseif ($arcFormat == 'StatusFailed') : ?>
217
- <span class="dupx-fail">Unable to validate format</span><br/>
218
- <?php elseif ($arcFormat == 'NoZipArchive') : ?>
219
- <div class="s1-archive-failed-msg">
220
- The PHP extraction library <a href="http://php.net/manual/en/book.zip.php" target="_help">ZipArchive</a> was not found on this server. There are a few options:
221
- <ol>
222
- <li>Contact your host to enable the this PHP library. <a href="http://php.net/manual/en/zip.installation.php" target="_help">[more info]</a></li>
223
- <li>Enable 'Manual package extraction' in the options menu and <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q" target="_help">Manually extract the archive</a></li>
224
- </ol>
225
- </div>
226
- <?php else : ?>
227
- <div class="s1-archive-failed-msg">
228
- <b class="dupx-fail">Invalid Archive Format Detected!</b><br/>
229
- The archive files contents must be laid out in a specific format. If the format has been changed the install process will error out.
230
- <br/><br/>
231
-
232
- This scenario is rare but can happen on some systems during the download and upload process of the zip without a user being aware of
233
- the issue. Please check the contents of the zip archive and be sure its contents match the layout of your site.
234
- <br/><br/>
235
-
236
- Files such as dup-database_[HASH].sql and wp-config.php should be at the root of the archive. For more details see the FAQ article
237
- <a href="https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=invalid_ar_fmt#faq-installer-020-q" target="_help">The archive format is changing on my Mac what might be the problem?</a>
238
- </div>
239
- <?php endif; ?>
240
- </td>
241
- </tr>
242
- </table>
243
-
244
- </div>
245
- <br/><br/>
246
-
247
-
248
- <!-- ====================================
249
- VALIDATION
250
- ==================================== -->
251
- <div class="hdr-sub1" id="s1-area-sys-setup-link" data-type="toggle" data-target="#s1-area-sys-setup">
252
- <a href="javascript:void(0)"><i class="dupx-plus-square"></i> Validation</a>
253
- <div class="<?php echo ($req_success) ? 'status-badge-pass' : 'status-badge-fail'; ?>" style="float:right">
254
- <?php echo ($req_success) ? 'Pass' : 'Fail'; ?>
255
- </div>
256
- </div>
257
- <div id="s1-area-sys-setup" style="display:none">
258
- <div class='info-top'>The system validation checks help to make sure the system is ready for install.</div>
259
-
260
- <!-- *** REQUIREMENTS *** -->
261
- <div class="s1-reqs" id="s1-reqs-all">
262
- <div class="header">
263
- <table class="s1-checks-area">
264
- <tr>
265
- <td class="title">Requirements <small>(must pass)</small></td>
266
- <td class="toggle"><a href="javascript:void(0)" onclick="DUPX.toggleAll('#s1-reqs-all')">[toggle]</a></td>
267
- </tr>
268
- </table>
269
- </div>
270
-
271
- <!-- REQ 1 -->
272
- <?php
273
- $status_1 = strtolower($req['01']);
274
- ?>
275
- <div class="status <?php echo DUPX_U::esc_html($status_1); ?>"><?php echo DUPX_U::esc_html($req['01']); ?></div>
276
- <div class="title" data-type="toggle" data-target="#s1-reqs01">+ Permissions</div>
277
- <div class="info" id="s1-reqs01">
278
- <table>
279
- <tr>
280
- <td><b>Deployment Path:</b> </td>
281
- <td><i><?php echo "{$GLOBALS['CURRENT_ROOT_PATH']}"; ?></i> </td>
282
- </tr>
283
- <tr>
284
- <td><b>Suhosin Extension:</b> </td>
285
- <td><?php echo extension_loaded('suhosin') ? "<i class='dupx-fail'>Enabled</i>" : "<i class='dupx-pass'>Disabled</i>"; ?> </td>
286
- </tr>
287
- <tr>
288
- <td><b>PHP Safe Mode:</b> </td>
289
- <td><?php echo (DUPX_Server::$php_safe_mode_on) ? "<i class='dupx-fail'>Enabled</i>" : "<i class='dupx-pass'>Disabled</i>"; ?> </td>
290
- </tr>
291
- </table><br/>
292
-
293
- The deployment path above must be writable by PHP in order to extract the archive file. Incorrect permissions and extension such as
294
- <a href="https://suhosin.org/stories/index.html" target="_blank">suhosin</a> can sometimes interfere with PHP being able to write/extract files.
295
- Please see the <a href="https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=installer_perms#faq-trouble-055-q" target="_blank">FAQ permission</a> help link for complete details.
296
- PHP with <a href='http://php.net/manual/en/features.safe-mode.php' target='_blank'>safe mode</a> should be disabled. If this test fails
297
- please contact your hosting provider or server administrator to disable PHP safe mode.
298
- </div>
299
-
300
- <!-- REQ 2
301
- <div class="status <?php echo strtolower($req['02']); ?>"><?php echo DUPX_U::esc_html($req['02']); ?></div>
302
- <div class="title" data-type="toggle" data-target="#s1-reqs02">+ Place Holder</div>
303
- <div class="info" id="s1-reqs02"></div>-->
304
-
305
- <!-- REQ 3
306
- <div class="status <?php echo strtolower($req['03']); ?>"><?php echo DUPX_U::esc_html($req['03']); ?></div>
307
- <div class="title" data-type="toggle" data-target="#s1-reqs03">+ Place Holder</div>
308
- <div class="info" id="s1-reqs03"></div> -->
309
-
310
- <!-- REQ 4 -->
311
- <?php
312
- $status_4 = strtolower($req['04']);
313
- ?>
314
- <div class="status <?php echo DUPX_U::esc_html($status_4); ?>"><?php echo DUPX_U::esc_html($req['04']); ?></div>
315
- <div class="title" data-type="toggle" data-target="#s1-reqs04">+ PHP Mysqli</div>
316
- <div class="info" id="s1-reqs04">
317
- Support for the PHP <a href='http://us2.php.net/manual/en/mysqli.installation.php' target='_blank'>mysqli extension</a> is required.
318
- Please contact your hosting provider or server administrator to enable the mysqli extension. <i>The detection for this call uses
319
- the function_exists('mysqli_connect') call.</i>
320
- </div>
321
-
322
- <!-- REQ 5 -->
323
- <?php
324
- $status_5 = strtolower($req['05']);
325
- ?>
326
- <div class="status <?php echo DUPX_U::esc_html($status_5); ?>"><?php echo DUPX_U::esc_html($req['05']); ?></div>
327
- <div class="title" data-type="toggle" data-target="#s1-reqs05">+ PHP Min Version</div>
328
- <div class="info" id="s1-reqs05">
329
- This server is running PHP: <b><?php echo DUPX_Server::$php_version ?></b>. <i>A minimum of PHP 5.2.17 is required</i>.
330
- Contact your hosting provider or server administrator and let them know you would like to upgrade your PHP version.
331
- </div>
332
- </div><br/>
333
-
334
-
335
- <!-- *** NOTICES *** -->
336
- <div class="s1-reqs" id="s1-notice-all">
337
- <div class="header">
338
- <table class="s1-checks-area">
339
- <tr>
340
- <td class="title">Notices <small>(optional)</small></td>
341
- <td class="toggle"><a href="javascript:void(0)" onclick="DUPX.toggleAll('#s1-notice-all')">[toggle]</a></td>
342
- </tr>
343
- </table>
344
- </div>
345
-
346
- <?php if (!$GLOBALS['FW_ARCHIVE_ONLYDB']) :?>
347
-
348
- <!-- NOTICE 1 -->
349
- <div class="status <?php echo ($notice['01'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['01']); ?></div>
350
- <div class="title" data-type="toggle" data-target="#s1-notice01">+ Configuration File</div>
351
- <div class="info" id="s1-notice01">
352
- Duplicator works best by placing the installer and archive files into an empty directory. If a wp-config.php file is found in the extraction
353
- directory it might indicate that a pre-existing WordPress site exists which can lead to a bad install.
354
- <br/><br/>
355
- <b>Options:</b>
356
- <ul style="margin-bottom: 0">
357
- <li>If the archive was already manually extracted then <a href="javascript:void(0)" onclick="DUPX.getManaualArchiveOpt()">[Enable Manual Archive Extraction]</a></li>
358
- <li>If the wp-config file is not needed then remove it.</li>
359
- </ul>
360
- </div>
361
-
362
- <!-- NOTICE 2 -->
363
- <div class="status <?php echo ($notice['02'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['02']); ?></div>
364
- <div class="title" data-type="toggle" data-target="#s1-notice02">+ Directory Setup</div>
365
- <div class="info" id="s1-notice02">
366
- <b>Deployment Path:</b> <i><?php echo DUPX_U::esc_html($GLOBALS['CURRENT_ROOT_PATH']); ?></i>
367
- <br/><br/>
368
- There are currently <?php echo "<b>[{$scancount}]</b>";?> items in the deployment path. These items will be overwritten if they also exist
369
- inside the archive file. The notice is to prevent overwriting an existing site or trying to install on-top of one which
370
- can have un-intended results. <i>This notice shows if it detects more than 40 items.</i>
371
-
372
- <br/><br/>
373
- <b>Options:</b>
374
- <ul style="margin-bottom: 0">
375
- <li>If the archive was already manually extracted then <a href="javascript:void(0)" onclick="DUPX.getManaualArchiveOpt()">[Enable Manual Archive Extraction]</a></li>
376
- <li>If the files/directories are not the same as those in the archive then this notice can be ignored.</li>
377
- <li>Remove the files if they are not needed and refresh this page.</li>
378
- </ul>
379
- </div>
380
-
381
- <?php endif; ?>
382
-
383
- <!-- NOTICE 3 -->
384
- <div class="status <?php echo ($notice['03'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['03']); ?></div>
385
- <div class="title" data-type="toggle" data-target="#s1-notice03">+ Package Age</div>
386
- <div class="info" id="s1-notice03">
387
- <?php echo "The package is {$fulldays} day(s) old. Packages older than 120 days might be considered stale. If you are comfortable with a package that that was created over "
388
- . "four months ago please ignore this notice."; ?>
389
- </div>
390
-
391
- <!-- NOTICE 4
392
- <div class="status <?php echo ($notice['04'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['04']); ?></div>
393
- <div class="title" data-type="toggle" data-target="#s1-notice04">+ Placeholder</div>
394
- <div class="info" id="s1-notice04">
395
- </div>-->
396
-
397
- <!-- NOTICE 5 -->
398
- <div class="status <?php echo ($notice['05'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['05']); ?></div>
399
- <div class="title" data-type="toggle" data-target="#s1-notice05">+ PHP Version 5.2</div>
400
- <div class="info" id="s1-notice05">
401
- <?php
402
- $currentPHP = DUPX_Server::$php_version;
403
- $cssStyle = DUPX_Server::$php_version_53_plus ? 'color:green' : 'color:red';
404
- echo "<b style='{$cssStyle}'>This server is currently running PHP version [{$currentPHP}]</b>.<br/>"
405
- . "Duplicator allows PHP 5.2 to be used during install but does not officially support it. If your using PHP 5.2 we strongly recommend NOT using it and having your "
406
- . "host upgrade to a newer more stable, secure and widely supported version. The <a href='http://php.net/eol.php' target='_blank'>end of life for PHP 5.2</a> "
407
- . "was in January of 2011 and is not recommended for use.<br/><br/>";
408
-
409
- echo "Many plugin and theme authors are no longer supporting PHP 5.2 and trying to use it can result in site wide problems and compatibility warnings and errors. "
410
- . "Please note if you continue with the install using PHP 5.2 the Duplicator support team will not be able to help with issues or troubleshooting your site. "
411
- . "If your server is running <b>PHP 5.3+</b> please feel free to reach out for help if you run into issues with your migration/install.";
412
- ?>
413
- </div>
414
-
415
- <!-- NOTICE 6 -->
416
- <div class="status <?php echo ($notice['06'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['06']); ?></div>
417
- <div class="title" data-type="toggle" data-target="#s1-notice06">+ PHP Open Base</div>
418
- <div class="info" id="s1-notice06">
419
- <b>Open BaseDir:</b> <i><?php echo $notice['06'] == 'Good' ? "<i class='dupx-pass'>Disabled</i>" : "<i class='dupx-fail'>Enabled</i>"; ?></i>
420
- <br/><br/>
421
-
422
- If <a href="http://www.php.net/manual/en/ini.core.php#ini.open-basedir" target="_blank">open_basedir</a> is enabled and you're
423
- having issues getting your site to install properly; please work with your host and follow these steps to prevent issues:
424
- <ol style="margin:7px; line-height:19px">
425
- <li>Disable the open_basedir setting in the php.ini file</li>
426
- <li>If the host will not disable, then add the path below to the open_basedir setting in the php.ini<br/>
427
- <i style="color:maroon">"<?php echo str_replace('\\', '/', dirname( __FILE__ )); ?>"</i>
428
- </li>
429
- <li>Save the settings and restart the web server</li>
430
- </ol>
431
- Note: This warning will still show if you choose option #2 and open_basedir is enabled, but should allow the installer to run properly. Please work with your
432
- hosting provider or server administrator to set this up correctly.
433
- </div>
434
-
435
- <!-- NOTICE 7 -->
436
- <div class="status <?php echo ($notice['07'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['07']); ?></div>
437
- <div class="title" data-type="toggle" data-target="#s1-notice07">+ PHP Timeout</div>
438
- <div class="info" id="s1-notice07">
439
- <b>Archive Size:</b> <?php echo DUPX_U::readableByteSize($arcSize) ?> <small>(detection limit is set at <?php echo DUPX_U::readableByteSize($max_time_size) ?>) </small><br/>
440
- <b>PHP max_execution_time:</b> <?php echo "{$max_time_ini}"; ?> <small>(zero means no limit)</small> <br/>
441
- <b>PHP set_time_limit:</b> <?php echo ($max_time_zero) ? '<i style="color:green">Success</i>' : '<i style="color:maroon">Failed</i>' ?>
442
- <br/><br/>
443
-
444
- The PHP <a href="http://php.net/manual/en/info.configuration.php#ini.max-execution-time" target="_blank">max_execution_time</a> setting is used to
445
- determine how long a PHP process is allowed to run. If the setting is too small and the archive file size is too large then PHP may not have enough
446
- time to finish running before the process is killed causing a timeout.
447
- <br/><br/>
448
-
449
- Duplicator attempts to turn off the timeout by using the
450
- <a href="http://php.net/manual/en/function.set-time-limit.php" target="_blank">set_time_limit</a> setting. If this notice shows as a warning then it is
451
- still safe to continue with the install. However, if a timeout occurs then you will need to consider working with the max_execution_time setting or extracting the
452
- archive file using the 'Manual package extraction' method.
453
- Please see the <a href="https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=installer_timeout#faq-trouble-100-q" target="_blank">FAQ timeout</a> help link for more details.
454
-
455
- </div>
456
- </div>
457
- </div>
458
- <br/><br/>
459
-
460
-
461
- <!-- ====================================
462
- OPTIONS
463
- ==================================== -->
464
- <div class="hdr-sub1" data-type="toggle" data-target="#s1-area-adv-opts">
465
- <a href="javascript:void(0)"><i class="dupx-plus-square"></i> Options</a>
466
- </div>
467
- <div id="s1-area-adv-opts" style="display:none">
468
- <div class="help-target"><a href="?help#help-s1" target="_blank">[help]</a></div>
469
- <br/>
470
- <div class="hdr-sub3">General</div>
471
- <table class="dupx-opts dupx-advopts">
472
- <tr>
473
- <td>Extraction:</td>
474
- <td>
475
-
476
- <select id="archive_engine" name="archive_engine" size="2">
477
- <option value="manual">Manual Archive Extraction</option>
478
- <?php
479
- //ZIP-ARCHIVE
480
- echo (! $zip_archive_enabled)
481
- ? '<option disabled="true">PHP ZipArchive (not detected on server)</option>'
482
- : '<option value="ziparchive" selected="true">PHP ZipArchive</option>';
483
- ?>
484
- </select>
485
- </td>
486
- </tr>
487
- </table>
488
- <br>
489
- <br>
490
- <div class="hdr-sub3">Advanced</div>
491
- <table class="dupx-opts dupx-advopts">
492
- <tr>
493
- <td>Safe Mode:</td>
494
- <td>
495
- <select name="exe_safe_mode" id="exe_safe_mode" onchange="DUPX.onSafeModeSwitch();" style="width:200px;">
496
- <option value="0">Off</option>
497
- <option value="1">Basic</option>
498
- <option value="2">Advance</option>
499
- </select>
500
- </td>
501
- </tr>
502
- <tr>
503
- <td>Config Files:</td>
504
- <td>
505
- <input type="checkbox" name="retain_config" id="retain_config" value="1" />
506
- <label for="retain_config" style="font-weight: normal">Retain original .htaccess, .user.ini and web.config</label>
507
- </td>
508
- </tr>
509
- <tr>
510
- <td>File Times:</td>
511
- <td>
512
- <input type="radio" name="archive_filetime" id="archive_filetime_now" value="current" checked="checked" /> <label class="radio" for="archive_filetime_now" title='Set the files current date time to now'>Current</label>
513
- <input type="radio" name="archive_filetime" id="archive_filetime_orginal" value="original" /> <label class="radio" for="archive_filetime_orginal" title="Keep the files date time the same">Original</label>
514
- </td>
515
- </tr>
516
- <tr>
517
- <td>Logging:</td>
518
- <td>
519
- <input type="radio" name="logging" id="logging-light" value="1" checked="true"> <label for="logging-light">Light</label>
520
- <input type="radio" name="logging" id="logging-detailed" value="2"> <label for="logging-detailed">Detailed</label>
521
- <input type="radio" name="logging" id="logging-debug" value="3"> <label for="logging-debug">Debug</label>
522
- </td>
523
- </tr>
524
- </table>
525
- <br/><br/>
526
-
527
- <!-- *** SETUP HELP *** -->
528
- <div class="hdr-sub3">Setup Help</div>
529
- <div id='s1-area-setup-help'>
530
- <div style="padding:10px 0px 0px 10px;line-height:22px">
531
- <table style='width:100%'>
532
- <tr>
533
- <td style="width:200px">
534
- &raquo; Watch the <a href="https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=installer_vid_tutor#faq-resource-070-q" target="_blank">video tutorials</a> <br/>
535
- &raquo; Read helpful <a href="https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=installer_help_art" target="_blank">articles</a> <br/>
536
- </td>
537
- <td>
538
- &raquo; Visit the <a href="https://snapcreek.com/duplicator/docs/quick-start/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=inst_quickstart" target="_blank">quick start guides</a> <br/>
539
- &raquo; Browse the <a href="https://snapcreek.com/duplicator/docs/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=installer_online_docs" target="_blank">online docs</a> <br/>
540
- </td>
541
- </tr>
542
- </table>
543
- </div>
544
- </div><br/>
545
-
546
- </div>
547
- <br/><br/>
548
-
549
- <!-- ====================================
550
- NOTICES
551
- ==================================== -->
552
- <div id="dialog-server-notice" style="display:none">
553
- <div id="s1-warning-msg">
554
- <b>TERMS &amp; NOTICES</b> <br/><br/>
555
-
556
- <b>Disclaimer:</b>
557
- The Duplicator software and installer should be used at your own risk. Users should always back up or have backups of your database and files before running this installer.
558
- If you're not sure about how to use this tool then please enlist the guidance of a technical professional. <u>Always</u> test this installer in a sandbox environment
559
- before trying to deploy into a production environment. Be sure that if anything happens during the install that you have a backup recovery plan in place. By accepting
560
- this agreement the users of this software do not hold liable Snapcreek LLC or any of its affiliates/members liable for any issues that might occur during use of this software.
561
- <br/><br/>
562
-
563
-
564
- <b>Database:</b>
565
- Do not connect to an existing database unless you are 100% sure you want to remove all of it's data. Connecting to a database that already exists will permanently
566
- DELETE all data in that database. This tool is designed to populate and fill a database with NEW data from a duplicated database using the SQL script in the
567
- package name above.
568
- <br/><br/>
569
-
570
- <b>Setup:</b>
571
- Only the archive and installer file should be in the install directory, unless you have manually extracted the package and checked the
572
- 'Manual Package Extraction' checkbox. All other files will be OVERWRITTEN during install. Make sure you have full backups of all your databases and files
573
- before continuing with an installation. Manual extraction requires that all contents in the package are extracted to the same directory as the installer file.
574
- Manual extraction is only needed when your server does not support the ZipArchive extension. Please see the online help for more details.
575
- <br/><br/>
576
-
577
- <b>After Install:</b> When you are done with the installation you must remove these files/directories:
578
- <ul>
579
- <li>installer.php</li>
580
- <li>installer-backup.php</li>
581
- <li>dup-installer-data_[HASH].sql</li>
582
- <li>dup-database_[HASH].sql</li>
583
- <li>dup-installer-log_[HASH].txt</li>
584
- <li>[HASH]_archive.zip</li>
585
- </ul>
586
-
587
- These files contain sensitive information and should not remain on a production system for system integrity and security protection.
588
- <br/><br/>
589
-
590
- <b>License Overview</b><br/>
591
- Duplicator is licensed under the GPL v3 https://www.gnu.org/licenses/gpl-3.0.en.html including the following disclaimers and limitation of liability.
592
- <br/><br/>
593
-
594
- <b>Disclaimer of Warranty</b><br/>
595
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
596
- PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
597
- FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
598
- THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
- <br/><br/>
600
-
601
- <b>Limitation of Liability</b><br/>
602
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
603
- PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
604
- PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO
605
- OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
606
- <br/><br/>
607
- </div>
608
- </div>
609
-
610
- <div id="s1-warning-check">
611
- <input id="accept-warnings" name="accpet-warnings" type="checkbox" onclick="DUPX.acceptWarning()" />
612
- <label for="accept-warnings">I have read and accept all <a href="javascript:void(0)" onclick="DUPX.showNotices()">terms &amp; notices</a> <small style="font-style:italic">(required to continue)</small></label><br/>
613
- </div>
614
-
615
-
616
- <?php if (! $req_success || $all_arc == 'Fail') :?>
617
- <div class="s1-err-msg">
618
- <i>
619
- This installation will not be able to proceed until the 'Archive' and 'Validation' sections pass. Please adjust your servers settings or contact your
620
- server administrator, hosting provider or visit the resources below for additional help.
621
- </i>
622
- <div style="padding:10px">
623
- &raquo; <a href="https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=inst_validfail_techfaq" target="_blank">Technical FAQs</a> <br/>
624
- &raquo; <a href="https://snapcreek.com/support/docs/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=inst_validfail_onlinedocs" target="_blank">Online Documentation</a> <br/>
625
- </div>
626
- </div> <br/><br/>
627
- <?php else : ?>
628
- <br/><br/><br/>
629
- <br/><br/><br/>
630
- <div class="dupx-footer-buttons">
631
- <button id="s1-deploy-btn" type="button" class="default-btn" onclick="DUPX.runExtraction()" title="<?php echo DUPX_U::esc_js($agree_msg); ?>"> Next </button>
632
- </div>
633
- <?php endif; ?>
634
-
635
- </form>
636
-
637
-
638
-
639
- <!-- =========================================
640
- VIEW: STEP 1 - AJAX RESULT
641
- Auto Posts to view.step2.php
642
- ========================================= -->
643
- <form id='s1-result-form' method="post" class="content-form" style="display:none">
644
-
645
- <div class="dupx-logfile-link"><a href="<?php echo DUPX_U::esc_attr($GLOBALS["LOG_FILE_NAME"]);?>" target="install_log">dup-installer-log.txt</a></div>
646
- <div class="hdr-main">
647
- Step <span class="step">1</span> of 4: Deployment
648
- </div>
649
-
650
- <!-- POST PARAMS -->
651
- <div class="dupx-debug">
652
- <input type="hidden" name="action_step" value="2" />
653
- <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
654
- <input type="hidden" name="logging" id="ajax-logging" />
655
- <input type="hidden" name="exe_safe_mode" id="exe-safe-mode" value="0" />
656
- <input type="hidden" name="retain_config" id="ajax-retain-config" />
657
- <input type="hidden" name="json" id="ajax-json" />
658
- <textarea id='ajax-json-debug' name='json_debug_view'></textarea>
659
- <input type='submit' value='manual submit'>
660
- </div>
661
-
662
- <!-- PROGRESS BAR -->
663
- <div id="progress-area">
664
- <div style="width:500px; margin:auto">
665
- <h3>Running Deployment Processes Please Wait...</h3>
666
- <div id="progress-bar"></div>
667
- <i>This may take several minutes</i>
668
- </div>
669
- </div>
670
-
671
- <!-- AJAX SYSTEM ERROR -->
672
- <div id="ajaxerr-area" style="display:none">
673
- <p>Please try again an issue has occurred.</p>
674
- <div style="padding: 0px 10px 10px 0px;">
675
- <div id="ajaxerr-data">An unknown issue has occurred with the file and database set up process. Please see the <?php echo DUPX_U::esc_html($GLOBALS["LOG_FILE_NAME"]);?> file for more details.</div>
676
- <div style="text-align:center; margin:10px auto 0px auto">
677
- <input type="button" class="default-btn" onclick="DUPX.hideErrorResult()" value="&laquo; Try Again" /><br/><br/>
678
- <i style='font-size:11px'>See online help for more details at <a href='https://snapcreek.com/ticket?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=inst_ajaxerr_ticket' target='_blank'>snapcreek.com</a></i>
679
- </div>
680
- </div>
681
- </div>
682
- </form>
683
-
684
- <script>
685
- DUPX.getManaualArchiveOpt = function ()
686
- {
687
- $("html, body").animate({scrollTop: $(document).height()}, 1500);
688
- $("a[data-target='#s1-area-adv-opts']").find('i').removeClass('dupx-plus-square').addClass('dupx-minus-square');
689
- $('#s1-area-adv-opts').show(1000);
690
- $('select#archive_engine').val('manual').focus();
691
- };
692
-
693
- /** Performs Ajax post to extract files and create db
694
- * Timeout (10000000 = 166 minutes) */
695
- DUPX.runExtraction = function()
696
- {
697
- var $form = $('#s1-input-form');
698
-
699
- //1800000 = 30 minutes
700
- //If the extraction takes longer than 30 minutes then user
701
- //will probably want to do a manual extraction or even FTP
702
- $.ajax({
703
- type: "POST",
704
- timeout:1800000,
705
- dataType: "json",
706
- url: window.location.href,
707
- data: $form.serialize(),
708
- beforeSend: function() {
709
- DUPX.showProgressBar();
710
- $form.hide();
711
- $('#s1-result-form').show();
712
- },
713
- success: function(data) {
714
- var dataJSON = JSON.stringify(data);
715
- $("#ajax-json-debug").val(dataJSON);
716
- if (typeof(data) != 'undefined' && data.pass == 1) {
717
- $("#ajax-logging").val($("input:radio[name=logging]:checked").val());
718
- $("#ajax-retain-config").val($("#retain_config").is(":checked") ? 1 : 0);
719
- $("#exe-safe-mode").val($("#exe_safe_mode").val());
720
- $("#ajax-json").val(escape(dataJSON));
721
- <?php if (! $GLOBALS['DUPX_DEBUG']) : ?>
722
- setTimeout(function() {$('#s1-result-form').submit();}, 500);
723
- <?php endif; ?>
724
- $('#progress-area').fadeOut(1000);
725
- } else {
726
- $('#ajaxerr-data').html('Error Processing Step 1');
727
- DUPX.hideProgressBar();
728
- }
729
- },
730
- error: function(xhr) {
731
- var status = "<b>Server Code:</b> " + xhr.status + "<br/>";
732
- status += "<b>Status:</b> " + xhr.statusText + "<br/>";
733
- status += "<b>Response:</b> " + xhr.responseText + "";
734
- status += "<hr/><b>Additional Troubleshooting Tips:</b><br/>";
735
- status += "- Check the <a href='<?php echo DUPX_U::esc_js($GLOBALS["LOG_FILE_NAME"]);?>' target='install_log'>dup-installer-log.txt</a> file for warnings or errors.<br/>";
736
- status += "- Check the web server and PHP error logs. <br/>";
737
- status += "- For timeout issues visit the <a href='https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=inst_ajaxextract_tofaq#faq-trouble-100-q' target='_blank'>Timeout FAQ Section</a><br/>";
738
- $('#ajaxerr-data').html(status);
739
- DUPX.hideProgressBar();
740
- }
741
- });
742
-
743
- };
744
-
745
- /** Accetps Useage Warning */
746
- DUPX.acceptWarning = function()
747
- {
748
- if ($("#accept-warnings").is(':checked')) {
749
- $("#s1-deploy-btn").removeAttr("disabled");
750
- $("#s1-deploy-btn").removeAttr("title");
751
- } else {
752
- $("#s1-deploy-btn").attr("disabled", "true");
753
- $("#s1-deploy-btn").attr("title", "<?php echo DUPX_U::esc_js($agree_msg); ?>");
754
- }
755
- }
756
-
757
- /** Server Terms Dialog*/
758
- DUPX.showNotices = function()
759
- {
760
- modal({
761
- type: 'alert',
762
- title: 'Terms and Notices',
763
- text: $('#dialog-server-notice').html()
764
- });
765
- }
766
-
767
-
768
- /** Go back on AJAX result view */
769
- DUPX.hideErrorResult = function()
770
- {
771
- $('#s1-result-form').hide();
772
- $('#s1-input-form').show(200);
773
- }
774
-
775
- DUPX.onSafeModeSwitch = function ()
776
- {
777
- var mode = $('#exe_safe_mode').val();
778
- if(mode == 0){
779
- $("#retain_config").removeAttr("disabled");
780
- }else if(mode == 1 || mode ==2){
781
- if($("#retain_config").is(':checked'))
782
- $("#retain_config").removeAttr("checked");
783
- $("#retain_config").attr("disabled", true);
784
- }
785
-
786
- $('#exe-safe-mode').val(mode);
787
- console.log("mode set to"+mode);
788
- }
789
-
790
- //DOCUMENT LOAD
791
- $(document).ready(function()
792
- {
793
- DUPX.acceptWarning();
794
- $("*[data-type='toggle']").click(DUPX.toggleClick);
795
- <?php echo ($all_arc == 'Fail') ? "$('#s1-area-archive-file-link').trigger('click');" : ""; ?>
796
- <?php echo (! $all_success) ? "$('#s1-area-sys-setup-link').trigger('click');" : ""; ?>
797
- })
798
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/view.step2.php DELETED
@@ -1,441 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- if (isset($_POST['logging'])) {
5
- $post_logging = DUPX_U::sanitize_text_field($_POST['logging']);
6
- $_POST['logging'] = trim($post_logging);
7
- }
8
-
9
- if (isset($_POST['exe_safe_mode'])) {
10
- $_POST['exe_safe_mode'] = DUPX_U::sanitize_text_field($_POST['exe_safe_mode']);
11
- } else {
12
- $_POST['exe_safe_mode'] = 0;
13
- }
14
- ?>
15
-
16
-
17
- <!-- =========================================
18
- VIEW: STEP 2- INPUT -->
19
- <form id='s2-input-form' method="post" class="content-form" data-parsley-validate="true" data-parsley-excluded="input[type=hidden], [disabled], :hidden">
20
- <input type="hidden" name="action_ajax" value="2" />
21
- <input type="hidden" name="action_step" value="2" />
22
- <input type="hidden" name="logging" id="logging" value="<?php echo DUPX_U::esc_attr($_POST['logging']); ?>" />
23
- <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
24
-
25
- <div class="dupx-logfile-link"><a href="<?php echo DUPX_U::esc_attr($GLOBALS["LOG_FILE_NAME"]);?>?now=<?php echo DUPX_U::esc_attr($GLOBALS['NOW_DATE']); ?>" target="install_log">dup-installer-log.txt</a></div>
26
- <div class="hdr-main">
27
- Step <span class="step">2</span> of 4: Install Database
28
- </div>
29
-
30
- <div class="s2-btngrp">
31
- <input id="s2-basic-btn" type="button" value="Basic" class="active" onclick="DUPX.togglePanels('basic')" />
32
- <input id="s2-cpnl-btn" type="button" value="cPanel" class="in-active" onclick="DUPX.togglePanels('cpanel')" />
33
- </div>
34
-
35
-
36
- <!-- =========================================
37
- BASIC PANEL -->
38
- <div id="s2-basic-pane">
39
- <div class="hdr-sub1" data-type="toggle" data-target="#s2-area-setup">
40
- <a href="javascript:void(0)"><i class="dupx-minus-square"></i> Setup</a>
41
- </div>
42
- <div id="s2-area-setup">
43
- <table class="dupx-opts">
44
- <tr>
45
- <td>Action:</td>
46
- <td>
47
- <select name="dbaction" id="dbaction">
48
- <option value="create">Create New Database</option>
49
- <option value="empty" selected="true">Connect and Remove All Data</option>
50
- </select>
51
- </td>
52
- </tr>
53
- <tr>
54
- <td>Host:</td>
55
- <td>
56
- <table class="s2-opts-dbhost">
57
- <tr>
58
- <td><input type="text" name="dbhost" id="dbhost" required="true" value="<?php echo DUPX_U::esc_attr($GLOBALS['FW_DBHOST']); ?>" placeholder="localhost" style="width:450px" /></td>
59
- <td style="vertical-align:top">
60
- <input id="s2-dbport-btn" type="button" onclick="DUPX.togglePort()" class="s2-small-btn" value="Port: <?php echo DUPX_U::esc_attr($GLOBALS['FW_DBPORT']); ?>" />
61
- <input name="dbport" id="dbport" type="text" style="width:80px; display:none" value="<?php echo DUPX_U::esc_attr($GLOBALS['FW_DBPORT']); ?>" />
62
- </td>
63
- </tr>
64
- </table>
65
- </td>
66
- </tr>
67
- <tr>
68
- <td>Database:</td>
69
- <td>
70
- <input type="text" name="dbname" id="dbname" required="true" value="<?php echo DUPX_U::esc_attr($GLOBALS['FW_DBNAME']); ?>" placeholder="new or existing database name" />
71
- <div id="s2-warning-emptydb">
72
- <label for="accept-warnings">Warning: The selected 'Action' above will remove <u>all data</u> from this database!</label>
73
- </div>
74
- </td>
75
- </tr>
76
- <tr>
77
- <td>User:</td>
78
- <td><input type="text" name="dbuser" id="dbuser" required="true" value="<?php echo DUPX_U::esc_attr($GLOBALS['FW_DBUSER']); ?>" placeholder="valid database username" /></td>
79
- </tr>
80
- <tr>
81
- <td>Password:</td>
82
- <td><input type="text" name="dbpass" id="dbpass" value="<?php echo DUPX_U::esc_attr($GLOBALS['FW_DBPASS']); ?>" placeholder="valid database user password" /></td>
83
- </tr>
84
- </table>
85
- </div>
86
-
87
- <!-- =========================================
88
- DIALOG: DB CONNECTION CHECK -->
89
- <div id="s2-dbconn">
90
- <div id="s2-dbconn-status" style="display:none">
91
- <div style="padding: 0px 10px 10px 10px;">
92
- <div id="s2-dbconn-test-msg" style="min-height:80px"></div>
93
- </div>
94
- <small><input type="button" onclick="$('#s2-dbconn-status').hide(500)" class="s2-small-btn" value="Hide Message" /></small>
95
- </div>
96
- </div><br/>
97
-
98
- <!-- ====================================
99
- OPTIONS
100
- ==================================== -->
101
- <div class="hdr-sub1" data-type="toggle" data-target="#s2-area-adv-opts">
102
- <a href="javascript:void(0)"><i class="dupx-plus-square"></i> Options</a>
103
- </div>
104
- <div id='s2-area-adv-opts' style="display:none">
105
- <div class="help-target"><a href="?help#help-s2" target="_blank">[help]</a></div>
106
-
107
- <table class="dupx-opts dupx-advopts">
108
- <tr>
109
- <td>Legacy:</td>
110
- <td><input type="checkbox" name="dbcollatefb" id="dbcollatefb" value="1" /> <label for="dbcollatefb">Apply legacy collation fallback support for unknown collations types</label></td>
111
- </tr>
112
- <tr>
113
- <td>Spacing:</td>
114
- <td colspan="2">
115
- <input type="checkbox" name="dbnbsp" id="dbnbsp" value="1" /> <label for="dbnbsp">Fix non-breaking space characters</label>
116
- </td>
117
- </tr>
118
- <tr>
119
- <td style="vertical-align:top">Mode:</td>
120
- <td colspan="2">
121
- <input type="radio" name="dbmysqlmode" id="dbmysqlmode_1" checked="true" value="DEFAULT"/> <label for="dbmysqlmode_1">Default</label> &nbsp;
122
- <input type="radio" name="dbmysqlmode" id="dbmysqlmode_2" value="DISABLE"/> <label for="dbmysqlmode_2">Disable</label> &nbsp;
123
- <input type="radio" name="dbmysqlmode" id="dbmysqlmode_3" value="CUSTOM"/> <label for="dbmysqlmode_3">Custom</label> &nbsp;
124
- <div id="dbmysqlmode_3_view" style="display:none; padding:5px">
125
- <input type="text" name="dbmysqlmode_opts" value="" /><br/>
126
- <small>Separate additional <a href="?help#help-mysql-mode" target="_blank">sql modes</a> with commas &amp; no spaces.<br/>
127
- Example: <i>NO_ENGINE_SUBSTITUTION,NO_ZERO_IN_DATE,...</i>.</small>
128
- </div>
129
- </td>
130
- </tr>
131
- <tr><td style="width:130px">Charset:</td><td><input type="text" name="dbcharset" id="dbcharset" value="<?php echo DUPX_U::esc_attr($_POST['dbcharset']) ?>" /> </td></tr>
132
- <tr><td>Collation:</td><td><input type="text" name="dbcollate" id="dbcollate" value="<?php echo DUPX_U::esc_attr($_POST['dbcollate']); ?>" /> </tr>
133
- </table>
134
-
135
- </div>
136
- <br/><br/><br/>
137
- <br/><br/><br/>
138
-
139
- <div class="dupx-footer-buttons">
140
- <input type="button" onclick="DUPX.testDatabase()" class="default-btn" value="Test Database" />
141
- <input id="dup-step2-deploy-btn" type="button" class="default-btn" value=" Next " onclick="DUPX.confirmDeployment()" />
142
- </div>
143
-
144
-
145
- </div>
146
-
147
-
148
- <!-- =========================================
149
- C-PANEL PANEL -->
150
- <div id="s2-cpnl-pane">
151
- <div class="s2-gopro">
152
- <h2>cPanel Connectivity</h2>
153
-
154
- <?php if( DUPX_U::isURLActive($_SERVER['SERVER_NAME'], 2083) ): ?>
155
- <div class='s2-cpanel-login'>
156
- <b>Login to this server's cPanel</b><br/>
157
- <a href=<?php echo DUPX_U::esc_url('https://'.$_SERVER['SERVER_NAME'].':2083'); ?>" target="cpanel" style="color:#fff">[<?php echo DUPX_U::esc_html($_SERVER['SERVER_NAME']); ?>:2083]</a>
158
- </div>
159
- <?php else : ?>
160
- <div class='s2-cpanel-off'>
161
- <b>This server does not appear to support cPanel!</b><br/>
162
- Consider <a href="https://snapcreek.com/wordpress-hosting/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_install_no_cpanel&utm_campaign=duplicator_pro" target="cpanel" style="color:#fff;font-weight:bold">upgrading</a> to a host that does.<br/>
163
- </div>
164
- <?php endif; ?>
165
-
166
-
167
- <div style="text-align: center; font-size: 14px">
168
- Want <span style="font-style: italic;">even easier</span> installs?
169
- <a target="_blank" href="https://snapcreek.com/duplicator/?utm_source=duplicator_free&amp;utm_medium=wordpress_plugin&amp;utm_content=free_install_step2&amp;utm_campaign=duplicator_pro"><b>Duplicator Pro</b></a>
170
- allows the following <b>right from the installer:</b>
171
- </div>
172
- <ul>
173
- <li>Directly login to cPanel</li>
174
- <li>Instantly create new databases &amp; users</li>
175
- <li>Preview and select existing databases &amp; users</li>
176
- </ul>
177
- <small>
178
- Note: Hosts that support cPanel provide remote access to server resources, allowing operations such as direct database and user creation.
179
- Since the <a target="_blank" href="https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_install_cpanel_note&utm_campaign=duplicator_pro">Duplicator Pro</a>
180
- installer can directly access cPanel, it dramatically speeds up your workflow.
181
- </small>
182
- </div>
183
- </div>
184
-
185
- </form>
186
-
187
-
188
- <!-- =========================================
189
- VIEW: STEP 2 - AJAX RESULT
190
- Auto Posts to view.step3.php
191
- ========================================= -->
192
- <form id='s2-result-form' method="post" class="content-form" style="display:none">
193
-
194
- <div class="dupx-logfile-link"><a href="<?php echo DUPX_U::esc_attr($GLOBALS["LOG_FILE_NAME"]);?>" target="install_log">dup-installer-log.txt</a></div>
195
- <div class="hdr-main">
196
- Step <span class="step">2</span> of 4: Install Database
197
- </div>
198
-
199
- <!-- POST PARAMS -->
200
- <div class="dupx-debug">
201
- <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
202
- <input type="hidden" name="action_step" value="3" />
203
- <input type="hidden" name="logging" id="ajax-logging" />
204
- <input type="hidden" name="retain_config" value="<?php echo DUPX_U::esc_attr($_POST['retain_config']); ?>" />
205
- <input type="hidden" name="exe_safe_mode" id="exe-safe-mode" value="<?php echo DUPX_U::esc_attr($_POST['exe_safe_mode']); ?>"/>
206
- <input type="hidden" name="dbhost" id="ajax-dbhost" />
207
- <input type="hidden" name="dbport" id="ajax-dbport" />
208
- <input type="hidden" name="dbuser" id="ajax-dbuser" />
209
- <input type="hidden" name="dbpass" id="ajax-dbpass" />
210
- <input type="hidden" name="dbname" id="ajax-dbname" />
211
- <input type="hidden" name="json" id="ajax-json" />
212
- <input type="hidden" name="dbcharset" id="ajax-dbcharset" />
213
- <input type="hidden" name="dbcollate" id="ajax-dbcollate" />
214
- <br/>
215
- <input type='submit' value='manual submit'>
216
- </div>
217
-
218
- <!-- PROGRESS BAR -->
219
- <div id="progress-area">
220
- <div style="width:500px; margin:auto">
221
- <h3>Installing Database Please Wait...</h3>
222
- <div id="progress-bar"></div>
223
- <i>This may take several minutes</i>
224
- </div>
225
- </div>
226
-
227
- <!-- AJAX SYSTEM ERROR -->
228
- <div id="ajaxerr-area" style="display:none">
229
- <p>Please try again an issue has occurred.</p>
230
- <div style="padding: 0px 10px 10px 0px;">
231
- <div id="ajaxerr-data">An unknown issue has occurred with the file and database set up process. Please see the dup-installer-log.txt file for more details.</div>
232
- <div style="text-align:center; margin:10px auto 0px auto">
233
- <input type="button" class="default-btn" onclick='DUPX.hideErrorResult()' value="&laquo; Try Again" /><br/><br/>
234
- <i style='font-size:11px'>See online help for more details at <a href='https://snapcreek.com/ticket?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=inst_ajaxstep2_ticket' target='_blank'>snapcreek.com</a></i>
235
- </div>
236
- </div>
237
- </div>
238
- </form>
239
-
240
-
241
-
242
- <!-- CONFIRM DIALOG -->
243
- <div id="dialog-confirm-content" style="display:none">
244
- <div style="padding:0 0 25px 0">
245
- <b>Run installer with these settings?</b>
246
- </div>
247
-
248
- <b>Database Settings:</b><br/>
249
- <table style="margin-left:20px">
250
- <tr>
251
- <td><b>Server:</b></td>
252
- <td><i id="dlg-dbhost"></i></td>
253
- </tr>
254
- <tr>
255
- <td><b>Name:</b></td>
256
- <td><i id="dlg-dbname"></i></td>
257
- </tr>
258
- <tr>
259
- <td><b>User:</b></td>
260
- <td><i id="dlg-dbuser"></i></td>
261
- </tr>
262
- </table>
263
- <br/><br/>
264
-
265
- <small> WARNING: Be sure these database parameters are correct! Entering the wrong information WILL overwrite an existing database.
266
- Make sure to have backups of all your data before proceeding.</small><br/>
267
- </div>
268
-
269
-
270
- <script>
271
- DUPX.escapeHtml = function(unsafe) {
272
- return unsafe
273
- .replace(/&/g, "&amp;")
274
- .replace(/</g, "&lt;")
275
- .replace(/>/g, "&gt;")
276
- .replace(/"/g, "&quot;")
277
- .replace(/'/g, "&#039;");
278
- }
279
- /* Confirm Dialog to validate run */
280
- DUPX.confirmDeployment = function()
281
- {
282
- var $form = $('#s2-input-form');
283
- $form.parsley().validate();
284
- if (!$form.parsley().isValid()) {
285
- return;
286
- }
287
-
288
- $('#dlg-dbhost').html(DUPX.escapeHtml($("#dbhost").val()));
289
- $('#dlg-dbname').html(DUPX.escapeHtml($("#dbname").val()));
290
- $('#dlg-dbuser').html(DUPX.escapeHtml($("#dbuser").val()));
291
-
292
- modal({
293
- type: 'confirm',
294
- title: 'Install Confirmation',
295
- text: $('#dialog-confirm-content').html(),
296
- callback: function(result)
297
- {
298
- if (result == true) {
299
- DUPX.runDeployment();
300
- }
301
- }
302
- });
303
- }
304
-
305
-
306
- /* Performs Ajax post to extract files and create db
307
- * Timeout (10000000 = 166 minutes) */
308
- DUPX.runDeployment = function()
309
- {
310
- var $form = $('#s2-input-form');
311
- var dbhost = $("#dbhost").val();
312
- var dbname = $("#dbname").val();
313
- var dbuser = $("#dbuser").val();
314
-
315
- $.ajax({
316
- type: "POST",
317
- timeout: 1800000,
318
- dataType: "json",
319
- url: window.location.href,
320
- data: $form.serialize(),
321
- beforeSend: function() {
322
- DUPX.showProgressBar();
323
- $form.hide();
324
- $('#s2-result-form').show();
325
- },
326
- success: function(data, textStatus, xhr){
327
- if (typeof(data) != 'undefined' && data.pass == 1) {
328
- $("#ajax-dbhost").val($("#dbhost").val());
329
- $("#ajax-dbport").val($("#dbport").val());
330
- $("#ajax-dbuser").val($("#dbuser").val());
331
- $("#ajax-dbpass").val($("#dbpass").val());
332
- $("#ajax-dbname").val($("#dbname").val());
333
- $("#ajax-dbcharset").val($("#dbcharset").val());
334
- $("#ajax-dbcollate").val($("#dbcollate").val());
335
- $("#ajax-logging").val($("#logging").val());
336
- $("#ajax-json").val(escape(JSON.stringify(data)));
337
- <?php if (! $GLOBALS['DUPX_DEBUG']) : ?>
338
- setTimeout(function() {$('#s2-result-form').submit();}, 500);
339
- <?php endif; ?>
340
- $('#progress-area').fadeOut(1000);
341
- } else {
342
- DUPX.hideProgressBar();
343
- }
344
- },
345
- error: function(xhr) {
346
- var status = "<b>Server Code:</b> " + xhr.status + "<br/>";
347
- status += "<b>Status:</b> " + xhr.statusText + "<br/>";
348
- status += "<b>Response:</b> " + xhr.responseText + "";
349
- status += "<hr/><b>Additional Troubleshooting Tips:</b><br/>";
350
- status += "- Check the <a href='<?php echo DUPX_U::esc_js($GLOBALS["LOG_FILE_NAME"]);?>' target='install_log'>dup-installer-log.txt</a> file for warnings or errors.<br/>";
351
- status += "- Check the web server and PHP error logs. <br/>";
352
- status += "- For timeout issues visit the <a href='https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=inst_step2deploy_timout#faq-trouble-100-q' target='_blank'>Timeout FAQ Section</a><br/>";
353
- $('#ajaxerr-data').html(status);
354
- DUPX.hideProgressBar();
355
- }
356
- });
357
-
358
- }
359
-
360
- /**
361
- * Toggles the cpanel Login area */
362
- DUPX.togglePanels = function (pane)
363
- {
364
- $('#s2-basic-pane, #s2-cpnl-pane').hide();
365
- $('#s2-basic-btn, #s2-cpnl-btn').removeClass('active in-active');
366
- if (pane == 'basic') {
367
- $('#s2-basic-pane').show();
368
- $('#s2-basic-btn').addClass('active');
369
- $('#s2-cpnl-btn').addClass('in-active');
370
- } else {
371
- $('#s2-cpnl-pane').show(200);
372
- $('#s2-cpnl-btn').addClass('active');
373
- $('#s2-basic-btn').addClass('in-active');
374
- }
375
- }
376
-
377
-
378
- /** Go back on AJAX result view */
379
- DUPX.hideErrorResult = function()
380
- {
381
- $('#s2-result-form').hide();
382
- $('#s2-input-form').show(200);
383
- }
384
-
385
-
386
- /** Shows results of database connection
387
- * Timeout (45000 = 45 secs) */
388
- DUPX.testDatabase = function ()
389
- {
390
- $.ajax({
391
- type: "POST",
392
- timeout: 45000,
393
- url: window.location.href + '?' + 'dbtest=1',
394
- data: $('#s2-input-form').serialize(),
395
- success: function(data){ $('#s2-dbconn-test-msg').html(data); },
396
- error: function(data){ alert('An error occurred while testing the database connection! Contact your server admin to make sure the connection inputs are correct!'); }
397
- });
398
-
399
- $('#s2-dbconn-test-msg').html("Attempting Connection. Please wait...");
400
- $("#s2-dbconn-status").show(100);
401
-
402
- }
403
-
404
-
405
- DUPX.showDeleteWarning = function ()
406
- {
407
- ($('#dbaction').val() == 'empty')
408
- ? $('#s2-warning-emptydb').show(200)
409
- : $('#s2-warning-emptydb').hide(200);
410
- }
411
-
412
-
413
- DUPX.togglePort = function ()
414
- {
415
- $('#s2-dbport-btn').hide();
416
- $('#dbport').show();
417
- }
418
-
419
-
420
- //DOCUMENT LOAD
421
- $(document).ready(function()
422
- {
423
- $('#dup-s2-dialog-data').appendTo('#dup-s2-result-container');
424
- $("select#dbaction").click(DUPX.showDeleteWarning);
425
- DUPX.showDeleteWarning();
426
-
427
- //MySQL Mode
428
- $("input[name=dbmysqlmode]").click(function() {
429
- if ($(this).val() == 'CUSTOM') {
430
- $('#dbmysqlmode_3_view').show();
431
- } else {
432
- $('#dbmysqlmode_3_view').hide();
433
- }
434
- });
435
-
436
- if ($("input[name=dbmysqlmode]:checked").val() == 'CUSTOM') {
437
- $('#dbmysqlmode_3_view').show();
438
- }
439
- $("*[data-type='toggle']").click(DUPX.toggleClick);
440
- });
441
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/build/view.step3.php DELETED
@@ -1,340 +0,0 @@
1
- <?php
2
- defined("DUPXABSPATH") or die("");
3
-
4
- $dbh = DUPX_DB::connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass'], $_POST['dbname'], $_POST['dbport']);
5
-
6
- $all_tables = DUPX_DB::getTables($dbh);
7
- $active_plugins = DUPX_U::getActivePlugins($dbh);
8
-
9
- $old_path = $GLOBALS['FW_WPROOT'];
10
- $new_path = DUPX_U::setSafePath($GLOBALS['CURRENT_ROOT_PATH']);
11
- $new_path = ((strrpos($old_path, '/') + 1) == strlen($old_path)) ? DUPX_U::addSlash($new_path) : $new_path;
12
- $_POST['exe_safe_mode'] = isset($_POST['exe_safe_mode']) ? $_POST['exe_safe_mode'] : 0;
13
- ?>
14
-
15
-
16
- <!-- =========================================
17
- VIEW: STEP 3- INPUT -->
18
- <form id='s3-input-form' method="post" class="content-form">
19
-
20
- <!-- POST PARAMS -->
21
- <input type="hidden" name="action_ajax" value="3" />
22
- <input type="hidden" name="action_step" value="3" />
23
- <input type="hidden" name="logging" value="<?php echo DUPX_U::esc_attr($_POST['logging']); ?>" />
24
- <input type="hidden" name="retain_config" value="<?php echo DUPX_U::esc_attr($_POST['retain_config']); ?>" />
25
- <input type="hidden" name="json" value="<?php echo DUPX_U::esc_attr($_POST['json']); ?>" />
26
- <input type="hidden" name="dbhost" value="<?php echo DUPX_U::esc_attr($_POST['dbhost']); ?>" />
27
- <input type="hidden" name="dbport" value="<?php echo DUPX_U::esc_attr($_POST['dbport']); ?>" />
28
- <input type="hidden" name="dbuser" value="<?php echo DUPX_U::esc_attr($_POST['dbuser']); ?>" />
29
- <input type="hidden" name="dbpass" value="<?php echo DUPX_U::esc_attr($_POST['dbpass']); ?>" />
30
- <input type="hidden" name="dbname" value="<?php echo DUPX_U::esc_attr($_POST['dbname']); ?>" />
31
- <input type="hidden" name="dbcharset" value="<?php echo DUPX_U::esc_attr($_POST['dbcharset']); ?>" />
32
- <input type="hidden" name="dbcollate" value="<?php echo DUPX_U::esc_attr($_POST['dbcollate']); ?>" />
33
- <input type="hidden" name="exe_safe_mode" id="exe-safe-mode" value="<?php echo DUPX_U::esc_attr($_POST['exe_safe_mode']); ?>" />
34
- <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
35
-
36
- <div class="dupx-logfile-link"><a href="<?php echo DUPX_U::esc_attr($GLOBALS["LOG_FILE_NAME"]);?>?now=<?php echo DUPX_U::esc_attr($GLOBALS['NOW_DATE']); ?>" target="install_log">dup-installer-log.txt</a></div>
37
- <div class="hdr-main">
38
- Step <span class="step">3</span> of 4: Update Data
39
- </div>
40
-
41
- <!-- ====================================
42
- NEW SETTINGS
43
- ==================================== -->
44
- <div class="hdr-sub1" style="margin-top:8px" data-type="toggle" data-target="#s3-new-settings">
45
- <a href="javascript:void(0)"><i class="dupx-minus-square"></i> New Settings</a>
46
- </div>
47
- <div id='s3-new-settings'>
48
- <table class="s3-table-inputs">
49
- <tr>
50
- <td style="width:80px">URL:</td>
51
- <td>
52
- <input type="text" name="url_new" id="url_new" value="" />
53
- <a href="javascript:DUPX.getNewURL('url_new')" style="font-size:12px">get</a>
54
- </td>
55
- </tr>
56
- <tr>
57
- <td>Path:</td>
58
- <td><input type="text" name="path_new" id="path_new" value="<?php echo DUPX_U::esc_attr($new_path); ?>" /></td>
59
- </tr>
60
- <tr>
61
- <td>Title:</td>
62
- <td><input type="text" name="blogname" id="blogname" value="<?php echo DUPX_U::esc_attr($GLOBALS['FW_BLOGNAME']); ?>" /></td>
63
- </tr>
64
- </table>
65
- </div>
66
- <br/><br/>
67
-
68
- <!-- ====================================
69
- OPTIONS
70
- ==================================== -->
71
- <div class="hdr-sub1" data-type="toggle" data-target="#s3-adv-opts">
72
- <a href="javascript:void(0)"><i class="dupx-plus-square"></i> Options</a>
73
- </div>
74
- <div id='s3-adv-opts' style="display:none;">
75
- <div class="help-target"><a href="?help#help-s3" target="_blank">[help]</a></div>
76
- <br/>
77
-
78
- <div class="hdr-sub3">New Admin Account</div>
79
- <div style="text-align: center; margin-top:7px">
80
- <i style="color:gray;font-size: 11px">This feature is optional. If the username already exists the account will NOT be created or updated.</i>
81
- </div>
82
- <table class="s3-table-inputs">
83
- <tr>
84
- <td>Username:</td>
85
- <td><input type="text" name="wp_username" id="wp_username" value="" title="4 characters minimum" placeholder="(4 or more characters)" /></td>
86
- </tr>
87
- <tr>
88
- <td valign="top">Password:</td>
89
- <td><input type="text" name="wp_password" id="wp_password" value="" title="6 characters minimum" placeholder="(6 or more characters)" /></td>
90
- </tr>
91
- </table>
92
- <br/><br/>
93
-
94
- <div class="hdr-sub3">Scan Options</div>
95
- <table class="s3-table-inputs">
96
- <tr>
97
- <td>Site URL:</td>
98
- <td>
99
- <input type="text" name="siteurl" id="siteurl" value="" />
100
- <a href="javascript:DUPX.getNewURL('siteurl')" style="font-size:12px">get</a><br/>
101
- </td>
102
- </tr>
103
- <tr>
104
- <td>Old URL:</td>
105
- <td>
106
- <input type="text" name="url_old" id="url_old" value="<?php echo DUPX_U::esc_attr($GLOBALS['FW_URL_OLD']); ?>" readonly="readonly" class="readonly" />
107
- <a href="javascript:DUPX.editOldURL()" id="edit_url_old" style="font-size:12px">edit</a>
108
- </td>
109
- </tr>
110
- <tr>
111
- <td>Old Path:</td>
112
- <td>
113
- <input type="text" name="path_old" id="path_old" value="<?php echo DUPX_U::esc_attr($old_path); ?>" readonly="readonly" class="readonly" />
114
- <a href="javascript:DUPX.editOldPath()" id="edit_path_old" style="font-size:12px">edit</a>
115
- </td>
116
- </tr>
117
- </table><br/>
118
-
119
- <table>
120
- <tr>
121
- <td style="padding-right:10px">
122
- <b>Scan Tables:</b>
123
- <div class="s3-allnonelinks">
124
- <a href="javascript:void(0)" onclick="$('#tables option').prop('selected',true);">[All]</a>
125
- <a href="javascript:void(0)" onclick="$('#tables option').prop('selected',false);">[None]</a>
126
- </div><br style="clear:both" />
127
- <select id="tables" name="tables[]" multiple="multiple">
128
- <?php
129
- foreach( $all_tables as $table ) {
130
- echo '<option selected="selected" value="' . DUPX_U::esc_attr( $table ) . '">' . DUPX_U::esc_html($table) . '</option>';
131
- }
132
- ?>
133
- </select>
134
- </td>
135
- <td valign="top">
136
- <b>Activate Plugins:</b>
137
- <?php echo ($_POST['exe_safe_mode'] > 0) ? '<small class="s3-warn">Safe Mode Enabled</small>' : '' ; ?>
138
- <div class="s3-allnonelinks" style="<?php echo ($_POST['exe_safe_mode']>0)? 'display:none':''; ?>">
139
- <a href="javascript:void(0)" onclick="$('#plugins option').prop('selected',true);">[All]</a>
140
- <a href="javascript:void(0)" onclick="$('#plugins option').prop('selected',false);">[None]</a>
141
- </div><br style="clear:both" />
142
- <select id="plugins" name="plugins[]" multiple="multiple" <?php echo ($_POST['exe_safe_mode'] > 0) ? 'disabled="disabled"' : ''; ?>>
143
- <?php
144
- $selected_string = ($_POST['exe_safe_mode'] > 0) ? '' : 'selected="selected"';
145
- foreach ($active_plugins as $plugin) {
146
- $plug_name = dirname($plugin);
147
- echo "<option {$selected_string} value='".DUPX_U::esc_attr($plugin)."'>".DUPX_U::esc_html($plug_name)."</option>";
148
- }
149
- ?>
150
- </select>
151
- </td>
152
- </tr>
153
- </table>
154
- <br/>
155
-
156
- <input type="checkbox" name="fullsearch" id="fullsearch" value="1" /> <label for="fullsearch">Use Database Full Search Mode </label><br/>
157
- <input type="checkbox" name="postguid" id="postguid" value="1" /> <label for="postguid">Keep Post GUID Unchanged</label><br/>
158
- <br/><br/>
159
-
160
- <!-- WP-CONFIG -->
161
- <div class="hdr-sub3">WP-Config File</div>
162
- <table class="dupx-opts dupx-advopts">
163
- <tr>
164
- <td>Cache:</td>
165
- <td style="width:125px"><input type="checkbox" name="cache_wp" id="cache_wp" /> <label for="cache_wp">Keep Enabled</label></td>
166
- <td><input type="checkbox" name="cache_path" id="cache_path" /> <label for="cache_path">Keep Home Path</label></td>
167
- </tr>
168
- <tr>
169
- <td>SSL:</td>
170
- <td><input type="checkbox" name="ssl_admin" id="ssl_admin" /> <label for="ssl_admin">Enforce on Admin</label></td>
171
- <td></td>
172
- </tr>
173
- </table>
174
- <br/><br/><br/>
175
- <br/><br/>
176
- </div>
177
-
178
- <div class="dupx-footer-buttons">
179
- <input id="dup-step3-next" class="default-btn" type="button" value=" Next " onclick="DUPX.runUpdate()" />
180
- </div>
181
- </form>
182
-
183
-
184
- <!-- =========================================
185
- VIEW: STEP 3 - AJAX RESULT
186
- ========================================= -->
187
- <form id='s3-result-form' method="post" class="content-form" style="display:none">
188
-
189
- <div class="dupx-logfile-link"><a href="<?php echo DUPX_U::esc_attr($GLOBALS["LOG_FILE_NAME"]);?>" target="install_log">dup-installer-log.txt</a></div>
190
- <div class="hdr-main">
191
- Step <span class="step">3</span> of 4: Update Data
192
- </div>
193
-
194
- <!-- POST PARAMS -->
195
- <div class="dupx-debug">
196
- <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
197
- <input type="hidden" name="action_step" value="4" />
198
- <input type="hidden" name="retain_config" value="<?php echo DUPX_U::esc_attr($_POST['retain_config']); ?>" />
199
- <input type="hidden" name="exe_safe_mode" id="exe-safe-mode" value="<?php echo DUPX_U::esc_attr($_POST['exe_safe_mode']); ?>"/>
200
- <input type="hidden" name="url_new" id="ajax-url_new" />
201
- <input type="hidden" name="json" id="ajax-json" />
202
- <br/>
203
- <input type='submit' value='manual submit'>
204
- </div>
205
-
206
- <!-- PROGRESS BAR -->
207
- <div id="progress-area">
208
- <div style="width:500px; margin:auto">
209
- <h3>Updating Data Replacements Please Wait...</h3>
210
- <div id="progress-bar"></div>
211
- <i>This may take several minutes</i>
212
- </div>
213
- </div>
214
-
215
- <!-- AJAX SYSTEM ERROR -->
216
- <div id="ajaxerr-area" style="display:none">
217
- <p>Please try again an issue has occurred.</p>
218
- <div style="padding: 0px 10px 10px 10px;">
219
- <div id="ajaxerr-data">An unknown issue has occurred with the update data set up process. Please see the dup-installer-log.txt file for more details.</div>
220
- <div style="text-align:center; margin:10px auto 0px auto">
221
- <input type="button" class="default-btn" onclick='DUPX.hideErrorResult2()' value="&laquo; Try Again" /><br/><br/>
222
- <i style='font-size:11px'>See online help for more details at <a href='https://snapcreek.com/ticket?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=inst_step3_ajax' target='_blank'>snapcreek.com</a></i>
223
- </div>
224
- </div>
225
- </div>
226
- </form>
227
-
228
- <script>
229
- /**
230
- * Timeout (10000000 = 166 minutes) */
231
- DUPX.runUpdate = function()
232
- {
233
- //Validation
234
- var wp_username = $.trim($("#wp_username").val()).length || 0;
235
- var wp_password = $.trim($("#wp_password").val()).length || 0;
236
-
237
- if ( $.trim($("#url_new").val()) == "" ) {alert("The 'New URL' field is required!"); return false;}
238
- if ( $.trim($("#siteurl").val()) == "" ) {alert("The 'Site URL' field is required!"); return false;}
239
- if (wp_username >= 1 && wp_username < 4) {alert("The New Admin Account 'Username' must be four or more characters"); return false;}
240
- if (wp_username >= 4 && wp_password < 6) {alert("The New Admin Account 'Password' must be six or more characters"); return false;}
241
-
242
- $.ajax({
243
- type: "POST",
244
- timeout: 1800000,
245
- dataType: "json",
246
- url: window.location.href,
247
- data: $('#s3-input-form').serialize(),
248
- beforeSend: function() {
249
- DUPX.showProgressBar();
250
- $('#s3-input-form').hide();
251
- $('#s3-result-form').show();
252
- },
253
- success: function(data){
254
- if (typeof(data) != 'undefined' && data.step3.pass == 1) {
255
- $("#ajax-url_new").val($("#url_new").val());
256
- $("#ajax-json").val(escape(JSON.stringify(data)));
257
- <?php if (! $GLOBALS['DUPX_DEBUG']) : ?>
258
- setTimeout(function(){$('#s3-result-form').submit();}, 500);
259
- <?php endif; ?>
260
- $('#progress-area').fadeOut(1000);
261
- } else {
262
- DUPX.hideProgressBar();
263
- }
264
- },
265
- error: function(xhr) {
266
- var status = "<b>Server Code:</b> " + xhr.status + "<br/>";
267
- status += "<b>Status:</b> " + xhr.statusText + "<br/>";
268
- status += "<b>Response:</b> " + xhr.responseText + "";
269
- status += "<hr/><b>Additional Troubleshooting Tips:</b><br/>";
270
- status += "- Check the <a href='<?php echo DUPX_U::esc_attr($GLOBALS["LOG_FILE_NAME"]);?>' target='install_log'>dup-installer-log.txt</a> file for warnings or errors.<br/>";
271
- status += "- Check the web server and PHP error logs. <br/>";
272
- status += "- For timeout issues visit the <a href='https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=inst_step3_ajax_rundepl#faq-trouble-100-q' target='_blank'>Timeout FAQ Section</a><br/>";
273
- $('#ajaxerr-data').html(status);
274
- DUPX.hideProgressBar();
275
- }
276
- });
277
- }
278
-
279
- /** Returns the windows active url */
280
- DUPX.getNewURL = function(id)
281
- {
282
- var filename= window.location.pathname.split('/').pop() || 'installer.php' ;
283
- var path = window.location.href.replace(filename, '').replace(/\/$/, '');
284
- $("#" + id).val(path);
285
- }
286
-
287
- /** Allows user to edit the package url */
288
- DUPX.editOldURL = function()
289
- {
290
- var msg = 'This is the URL that was generated when the package was created.\n';
291
- msg += 'Changing this value may cause issues with the install process.\n\n';
292
- msg += 'Only modify this value if you know exactly what the value should be.\n';
293
- msg += 'See "General Settings" in the WordPress Administrator for more details.\n\n';
294
- msg += 'Are you sure you want to continue?';
295
-
296
- if (confirm(msg)) {
297
- $("#url_old").removeAttr('readonly');
298
- $("#url_old").removeClass('readonly');
299
- $('#edit_url_old').hide('slow');
300
- }
301
- }
302
-
303
- /** Allows user to edit the package path */
304
- DUPX.editOldPath = function()
305
- {
306
- var msg = 'This is the SERVER URL that was generated when the package was created.\n';
307
- msg += 'Changing this value may cause issues with the install process.\n\n';
308
- msg += 'Only modify this value if you know exactly what the value should be.\n';
309
- msg += 'Are you sure you want to continue?';
310
-
311
- if (confirm(msg)) {
312
- $("#path_old").removeAttr('readonly');
313
- $("#path_old").removeClass('readonly');
314
- $('#edit_path_old').hide('slow');
315
- }
316
- }
317
-
318
- /** Go back on AJAX result view */
319
- DUPX.hideErrorResult2 = function()
320
- {
321
- $('#s3-result-form').hide();
322
- $('#s3-input-form').show(200);
323
- }
324
-
325
- //DOCUMENT LOAD
326
- $(document).ready(function()
327
- {
328
- DUPX.getNewURL('url_new');
329
- DUPX.getNewURL('siteurl');
330
- $("*[data-type='toggle']").click(DUPX.toggleClick);
331
- $("#wp_password").passStrength({
332
- shortPass: "top_shortPass",
333
- badPass: "top_badPass",
334
- goodPass: "top_goodPass",
335
- strongPass: "top_strongPass",
336
- baseStyle: "top_testresult",
337
- userid: "#wp_username",
338
- messageloc: 1 });
339
- });
340
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/dup-installer/assets/font-awesome/css/font-awesome.min.css ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ /*!
2
+ * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
3
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:bef