WordPress Backup and Migrate Plugin – Backup Guard - Version 1.1.90

Version Description

  • Halloween campaign
Download this release

Release Info

Developer BackupGuard
Plugin Icon 128x128 WordPress Backup and Migrate Plugin – Backup Guard
Version 1.1.90
Comparing to
See all releases

Version 1.1.90

Files changed (168) hide show
  1. BackupGuard.php +777 -0
  2. README.txt +528 -0
  3. backup.php +36 -0
  4. com/.htaccess +1 -0
  5. com/boot.php +6 -0
  6. com/config/config.php +204 -0
  7. com/config/config.wordpress.free.php +42 -0
  8. com/config/config.wordpress.php +119 -0
  9. com/core/SGBoot.php +284 -0
  10. com/core/SGConfig.php +67 -0
  11. com/core/SGPing.php +37 -0
  12. com/core/backup/SGBackup.php +1408 -0
  13. com/core/backup/SGBackupDatabase.php +643 -0
  14. com/core/backup/SGBackupFiles.php +510 -0
  15. com/core/backup/SGBackupLog.php +58 -0
  16. com/core/backup/SGBackupSchedule.php +77 -0
  17. com/core/backup/SGBackupStorage.php +436 -0
  18. com/core/backup/SGIBackupDelegate.php +8 -0
  19. com/core/database/SGDatabase.php +34 -0
  20. com/core/database/SGDatabaseAdapterWordpress.php +131 -0
  21. com/core/database/SGIDatabaseAdapter.php +48 -0
  22. com/core/exception/SGException.php +90 -0
  23. com/core/extension/SGExtension.php +33 -0
  24. com/core/extension/SGExtensionAdapterWordpress.php +79 -0
  25. com/core/extension/SGIExtensionAdapter.php +11 -0
  26. com/core/functions.php +692 -0
  27. com/core/log/SGFileLogHandler.php +71 -0
  28. com/core/log/SGILogHandler.php +10 -0
  29. com/core/log/SGLog.php +94 -0
  30. com/core/notice/SGINoticeAdapter.php +8 -0
  31. com/core/notice/SGNotice.php +33 -0
  32. com/core/notice/SGNoticeAdapterWordpress.php +50 -0
  33. com/core/notice/SGNoticeHandler.php +56 -0
  34. com/core/restore/SGExternalRestore.php +162 -0
  35. com/core/restore/SGExternalRestoreWordpress.php +80 -0
  36. com/core/schedule/SGIScheduleAdapter.php +8 -0
  37. com/core/schedule/SGSchedule.php +37 -0
  38. com/core/schedule/SGScheduleAdapterWordpress.php +124 -0
  39. com/core/storage/SGDropbox.php +38 -0
  40. com/core/storage/SGDropboxStorage.php +371 -0
  41. com/core/storage/SGStorage.php +103 -0
  42. com/core/widget/SGWordPressWidget.php +166 -0
  43. com/lib/BackupGuard/Client.php +297 -0
  44. com/lib/BackupGuard/Config.php +9 -0
  45. com/lib/BackupGuard/Curl.php +99 -0
  46. com/lib/BackupGuard/Exception/BadRequest.php +10 -0
  47. com/lib/BackupGuard/Exception/Exception.php +8 -0
  48. com/lib/BackupGuard/Exception/Forbidden.php +10 -0
  49. com/lib/BackupGuard/Exception/InternalServerError.php +10 -0
  50. com/lib/BackupGuard/Exception/MethodNotAllowed.php +10 -0
  51. com/lib/BackupGuard/Exception/NotFound.php +10 -0
  52. com/lib/BackupGuard/Exception/Unauthorized.php +10 -0
  53. com/lib/BackupGuard/Helper.php +105 -0
  54. com/lib/BackupGuard/RequestHandler.php +71 -0
  55. com/lib/BackupGuard/Response.php +56 -0
  56. com/lib/BackupGuard/Stream.php +115 -0
  57. com/lib/Dropbox/AppInfo.php +238 -0
  58. com/lib/Dropbox/AppInfoLoadException.php +18 -0
  59. com/lib/Dropbox/ArrayEntryStore.php +61 -0
  60. com/lib/Dropbox/AuthBase.php +75 -0
  61. com/lib/Dropbox/AuthInfo.php +85 -0
  62. com/lib/Dropbox/AuthInfoLoadException.php +18 -0
  63. com/lib/Dropbox/Checker.php +95 -0
  64. com/lib/Dropbox/Client.php +1700 -0
  65. com/lib/Dropbox/Curl.php +131 -0
  66. com/lib/Dropbox/CurlStreamRelay.php +45 -0
  67. com/lib/Dropbox/DeserializeException.php +19 -0
  68. com/lib/Dropbox/DropboxMetadataHeaderCatcher.php +83 -0
  69. com/lib/Dropbox/Exception.php +16 -0
  70. com/lib/Dropbox/Exception/BadRequest.php +17 -0
  71. com/lib/Dropbox/Exception/BadResponse.php +17 -0
  72. com/lib/Dropbox/Exception/BadResponseCode.php +33 -0
  73. com/lib/Dropbox/Exception/InvalidAccessToken.php +18 -0
  74. com/lib/Dropbox/Exception/NetworkIO.php +16 -0
  75. com/lib/Dropbox/Exception/ProtocolError.php +17 -0
  76. com/lib/Dropbox/Exception/RetryLater.php +17 -0
  77. com/lib/Dropbox/Exception/ServerError.php +15 -0
  78. com/lib/Dropbox/Host.php +100 -0
  79. com/lib/Dropbox/HttpResponse.php +17 -0
  80. com/lib/Dropbox/OAuth1AccessToken.php +61 -0
  81. com/lib/Dropbox/OAuth1Upgrader.php +142 -0
  82. com/lib/Dropbox/Path.php +171 -0
  83. com/lib/Dropbox/RequestUtil.php +347 -0
  84. com/lib/Dropbox/RootCertificates.php +144 -0
  85. com/lib/Dropbox/SSLTester.php +128 -0
  86. com/lib/Dropbox/Security.php +67 -0
  87. com/lib/Dropbox/StreamReadException.php +16 -0
  88. com/lib/Dropbox/Util.php +33 -0
  89. com/lib/Dropbox/ValueStore.php +61 -0
  90. com/lib/Dropbox/WebAuth.php +273 -0
  91. com/lib/Dropbox/WebAuthBase.php +119 -0
  92. com/lib/Dropbox/WebAuthException/BadRequest.php +20 -0
  93. com/lib/Dropbox/WebAuthException/BadState.php +19 -0
  94. com/lib/Dropbox/WebAuthException/Csrf.php +21 -0
  95. com/lib/Dropbox/WebAuthException/NotApproved.php +18 -0
  96. com/lib/Dropbox/WebAuthException/Provider.php +18 -0
  97. com/lib/Dropbox/WebAuthNoRedirect.php +82 -0
  98. com/lib/Dropbox/WriteMode.php +116 -0
  99. com/lib/Dropbox/autoload.php +32 -0
  100. com/lib/Dropbox/certs/trusted-certs.crt +1396 -0
  101. com/lib/Dropbox/strict.php +13 -0
  102. com/lib/Request/SGIRequestAdapter.php +14 -0
  103. com/lib/Request/SGRequest.php +33 -0
  104. com/lib/Request/SGRequestAdapterWordpress.php +190 -0
  105. com/lib/Request/SGResponse.php +54 -0
  106. com/lib/SGArchive.php +793 -0
  107. com/lib/SGAuthClient.php +268 -0
  108. com/lib/SGCallback.php +53 -0
  109. com/lib/SGCdrEntry.php +78 -0
  110. com/lib/SGCharsetHandler.php +93 -0
  111. com/lib/SGDBState.php +122 -0
  112. com/lib/SGEntry.php +12 -0
  113. com/lib/SGFileEntry.php +54 -0
  114. com/lib/SGFileState.php +181 -0
  115. com/lib/SGMigrateState.php +58 -0
  116. com/lib/SGMysqldump.php +1558 -0
  117. com/lib/SGReloadHandler.php +35 -0
  118. com/lib/SGReloader.php +86 -0
  119. com/lib/SGReloaderState.php +59 -0
  120. com/lib/SGState.php +189 -0
  121. com/lib/SGUploadHandler.php +38 -0
  122. com/lib/SGUploadState.php +124 -0
  123. index.php +1 -0
  124. languages/backup-guard-pro-es_ES.mo +0 -0
  125. languages/backup-guard-pro-es_ES.po +1154 -0
  126. public/ajax/awake.php +9 -0
  127. public/ajax/cancelBackup.php +10 -0
  128. public/ajax/cancelDownload.php +6 -0
  129. public/ajax/checkBackupCreation.php +17 -0
  130. public/ajax/checkPHPVersionCompatibility.php +33 -0
  131. public/ajax/checkRestoreCreation.php +27 -0
  132. public/ajax/cloudDropbox.php +25 -0
  133. public/ajax/curlChecker.php +14 -0
  134. public/ajax/deleteBackup.php +11 -0
  135. public/ajax/dismissDiscountNotice.php +5 -0
  136. public/ajax/downloadBackup.php +22 -0
  137. public/ajax/getAction.php +26 -0
  138. public/ajax/getBackupContent.php +56 -0
  139. public/ajax/getRunningActions.php +10 -0
  140. public/ajax/hideNotice.php +16 -0
  141. public/ajax/importBackup.php +17 -0
  142. public/ajax/isFeatureAvailable.php +9 -0
  143. public/ajax/manualBackup.php +38 -0
  144. public/ajax/modalImport.php +100 -0
  145. public/ajax/modalManualBackup.php +138 -0
  146. public/ajax/modalManualRestore.php +72 -0
  147. public/ajax/modalPrivacy.php +32 -0
  148. public/ajax/modalReview.php +31 -0
  149. public/ajax/modalTerms.php +31 -0
  150. public/ajax/resetStatus.php +25 -0
  151. public/ajax/restore.php +23 -0
  152. public/ajax/schedule.php +143 -0
  153. public/ajax/setReviewPopupState.php +8 -0
  154. public/ajax/setUserInfoVerificationPopupState.php +19 -0
  155. public/ajax/settings.php +143 -0
  156. public/ajax/storeSubscriberInfo.php +26 -0
  157. public/ajax/storeSurveyResult.php +35 -0
  158. public/backups.php +197 -0
  159. public/boot.php +4 -0
  160. public/cloud.php +131 -0
  161. public/config/config.php +25 -0
  162. public/config/config.wordpress.php +22 -0
  163. public/cron/sg_backup.php +17 -0
  164. public/cron/sg_storage_upload.php +5 -0
  165. public/css/bgstyle.less.css +7893 -0
  166. public/css/bgstyle.wordpress.css +204 -0
  167. public/css/bootstrap-switch.min.css +22 -0
  168. public/css/bootstrap.css +4412 -0
BackupGuard.php ADDED
@@ -0,0 +1,777 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // hook to wordpres widget
4
+ function backup_guard_register_widget()
5
+ {
6
+ if (!class_exists('SGWordPressWidget')) {
7
+ @include_once(SG_WIDGET_PATH.'SGWordPressWidget.php');
8
+ }
9
+
10
+ register_widget('SGWordPressWidget');
11
+ }
12
+ add_action('widgets_init', 'backup_guard_register_widget');
13
+
14
+ //The code that runs during plugin activation.
15
+ function activate_backup_guard()
16
+ {
17
+ //check if database should be updated
18
+ if (backupGuardShouldUpdate()) {
19
+ SGBoot::install();
20
+ SGBoot::didInstallForFirstTime();
21
+ }
22
+ }
23
+
24
+ // The code that runs during plugin deactivation.
25
+ function uninstall_backup_guard()
26
+ {
27
+ SGBoot::uninstall();
28
+ }
29
+
30
+ function deactivate_backup_guard()
31
+ {
32
+ $pluginCapabilities = backupGuardGetCapabilities();
33
+ if ($pluginCapabilities != BACKUP_GUARD_CAPABILITIES_FREE) {
34
+ require_once(SG_LIB_PATH.'SGAuthClient.php');
35
+ $res = SGAuthClient::getInstance()->logout();
36
+ SGConfig::set('SG_LICENSE_CHECK_TS', 0, true);
37
+ SGConfig::set('SG_LOGGED_USER', '', true);
38
+ }
39
+ }
40
+
41
+ function backupGuardMaybeShortenEddFilename($return, $package)
42
+ {
43
+ if (strpos($package, 'backup-guard') !== false) {
44
+ add_filter('wp_unique_filename', 'backupGuardShortenEddFilename', 10, 2);
45
+ }
46
+ return $return;
47
+ }
48
+
49
+ function backupGuardShortenEddFilename($filename, $ext)
50
+ {
51
+ $filename = substr($filename, 0, 20).$ext;
52
+ remove_filter('wp_unique_filename', 'backupGuardShortenEddFilename', 10);
53
+ return $filename;
54
+ }
55
+
56
+ add_filter('upgrader_pre_download', 'backupGuardMaybeShortenEddFilename', 10, 4);
57
+
58
+ register_activation_hook(SG_BACKUP_GUARD_MAIN_FILE, 'activate_backup_guard');
59
+ register_uninstall_hook(SG_BACKUP_GUARD_MAIN_FILE, 'uninstall_backup_guard');
60
+ register_deactivation_hook(SG_BACKUP_GUARD_MAIN_FILE, 'deactivate_backup_guard');
61
+ add_action('admin_footer', 'before_deactivate_backup_guard');
62
+
63
+ function before_deactivate_backup_guard()
64
+ {
65
+ wp_enqueue_style('before-deactivate-backup-guard-css', plugin_dir_url(__FILE__).'public/css/deactivationSurvey.css');
66
+ wp_enqueue_script('before-deactivate-backup-guard-js', plugin_dir_url(__FILE__).'public/js/deactivationSurvey.js', array('jquery'));
67
+
68
+ require_once(plugin_dir_path(__FILE__).'public/include/uninstallSurveyPopup.php');
69
+ }
70
+
71
+ // Register Admin Menus for single and multisite
72
+ if (is_multisite()) {
73
+ add_action('network_admin_menu', 'backup_guard_admin_menu');
74
+ }
75
+ else {
76
+ add_action('admin_menu', 'backup_guard_admin_menu');
77
+ }
78
+
79
+ function backup_guard_admin_menu()
80
+ {
81
+ add_menu_page('Backups', 'BackupGuard', 'manage_options', 'backup_guard_backups', 'backup_guard_backups_page', 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA0NjIuOSA1MDEuNCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgNDYyLjkgNTAxLjQiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGZpbGw9IiNhMGE1YWEiIGQ9Ik00MjYuOSwxOTkuNmgtMTk4bDAuNCwzNEgyNDZoMTYyLjdjLTAuNSwzLjMtMS4xLDYuNi0xLjcsOS45Yy02LjEsMzMtMTUuMyw2Mi4yLTI3LjcsODcuNkg3OS40Yy0xMi4zLTI1LjQtMjEuNi01NC42LTI3LjctODcuNkMzOS4zLDE3Ni4xLDQ0LDExMS41LDQ3LjIsODMuN0M2Ny43LDkwLjUsODguMyw5NCwxMDguNiw5NGM2MC43LDAsMTAzLjMtMzAuMiwxMjAuOC00NS4xQzI0Ni43LDYzLjgsMjg5LjQsOTQsMzUwLjEsOTRoMGMyMC4zLDAsNDAuOS0zLjUsNjEuNC0xMC4zYzEuNiwxMy45LDMuNSwzNy4xLDMuNiw2NS4xaDIzLjdjMC00Ny40LTUuNS04MS4xLTUuOC04My4zbC0yLjQtMTQuNmwtMTMuNyw1LjZjLTIyLjQsOS4yLTQ0LjgsMTMuOC02Ni43LDEzLjhjMCwwLDAsMCwwLDBjLTY4LjMsMC0xMTEuNy00NS4zLTExMi4xLTQ1LjdsLTguNi05LjJsLTguNyw5LjJjLTAuNCwwLjUtNDMuOCw0NS43LTExMi4xLDQ1LjdjLTIxLjksMC00NC40LTQuNi02Ni43LTEzLjhsLTEzLjctNS42bC0yLjQsMTQuNmMtMC42LDMuNi0xNC40LDg4LjcsMi42LDE4MS42QzM4LjUsMzAyLjQsNTcuNSwzNDguOCw4NC44LDM4NWMzNC42LDQ1LjgsODIuNCw3NS4zLDE0Mi4xLDg3LjdsMi40LDAuNWwyLjQtMC41YzU5LjctMTIuMywxMDcuNS00MS44LDE0Mi4xLTg3LjdjMjcuNC0zNi4zLDQ2LjQtODIuNyw1Ni41LTEzNy45YzMtMTYuMiw1LTMyLjIsNi4zLTQ3LjVMNDI2LjksMTk5LjZMNDI2LjksMTk5LjZ6Ii8+PC9zdmc+', 74);
82
+
83
+ add_submenu_page('backup_guard_backups', _backupGuardT('Backups', true), _backupGuardT('Backups', true), 'manage_options', 'backup_guard_backups', 'backup_guard_backups_page');
84
+ add_submenu_page('backup_guard_backups', _backupGuardT('Cloud', true), _backupGuardT('Cloud', true), 'manage_options', 'backup_guard_cloud', 'backup_guard_cloud_page');
85
+ add_submenu_page('backup_guard_backups', _backupGuardT('Schedule', true), _backupGuardT('Schedule', true), 'manage_options', 'backup_guard_schedule', 'backup_guard_schedule_page');
86
+
87
+ add_submenu_page('backup_guard_backups', _backupGuardT('Settings', true), _backupGuardT('Settings', true), 'manage_options', 'backup_guard_settings', 'backup_guard_settings_page');
88
+
89
+ add_submenu_page('backup_guard_backups', _backupGuardT('System Info.', true), _backupGuardT('System Info.', true), 'manage_options', 'backup_guard_system_info', 'backup_guard_system_info_page');
90
+
91
+ add_submenu_page('backup_guard_backups', _backupGuardT('Services', true), _backupGuardT('Services', true), 'manage_options', 'backup_guard_services', 'backup_guard_services_page');
92
+ add_submenu_page('backup_guard_backups', _backupGuardT('Support', true), _backupGuardT('Support', true), 'manage_options', 'backup_guard_support', 'backup_guard_support_page');
93
+
94
+ //Check if should show upgrade page
95
+ if (SGBoot::isFeatureAvailable('SHOW_UPGRADE_PAGE')) {
96
+ add_submenu_page('backup_guard_backups', _backupGuardT('Why upgrade?', true), _backupGuardT('Why upgrade?', true), 'manage_options', 'backup_guard_pro_features', 'backup_guard_pro_features_page');
97
+ }
98
+ }
99
+
100
+ function backup_guard_system_info_page()
101
+ {
102
+ if (backupGuardValidateLicense()) {
103
+ require_once(plugin_dir_path(__FILE__).'public/systemInfo.php');
104
+ }
105
+ }
106
+
107
+ function backup_guard_services_page()
108
+ {
109
+ if (backupGuardValidateLicense()) {
110
+ require_once(plugin_dir_path(__FILE__).'public/services.php');
111
+ }
112
+ }
113
+
114
+ //Pro features page
115
+ function backup_guard_pro_features_page()
116
+ {
117
+ require_once(plugin_dir_path(__FILE__).'public/proFeatures.php');
118
+ }
119
+
120
+ function backup_guard_security_page()
121
+ {
122
+ require_once(plugin_dir_path(__FILE__).'public/security.php');
123
+ }
124
+
125
+ //Support page
126
+ function backup_guard_support_page()
127
+ {
128
+ if (backupGuardValidateLicense()) {
129
+ require_once(plugin_dir_path(__FILE__).'public/support.php');
130
+ }
131
+ }
132
+
133
+ //Backups Page
134
+ function backup_guard_backups_page()
135
+ {
136
+ if (backupGuardValidateLicense()) {
137
+ wp_enqueue_script('backup-guard-iframe-transport-js', plugin_dir_url(__FILE__).'public/js/jquery.iframe-transport.js', array('jquery'));
138
+ wp_enqueue_script('backup-guard-fileupload-js', plugin_dir_url(__FILE__).'public/js/jquery.fileupload.js', array('jquery'));
139
+ wp_enqueue_script('backup-guard-jstree-js', plugin_dir_url(__FILE__).'public/js/jstree.min.js', array('jquery'));
140
+ wp_enqueue_script('backup-guard-jstree-checkbox-js', plugin_dir_url(__FILE__).'public/js/jstree.checkbox.js', array('jquery'));
141
+ wp_enqueue_script('backup-guard-jstree-wholerow-js', plugin_dir_url(__FILE__).'public/js/jstree.wholerow.js', array('jquery'));
142
+ wp_enqueue_script('backup-guard-jstree-types-js', plugin_dir_url(__FILE__).'public/js/jstree.types.js', array('jquery'));
143
+ wp_enqueue_style('backup-guard-jstree-css', plugin_dir_url(__FILE__).'public/css/default/style.min.css');
144
+ wp_enqueue_script('backup-guard-backups-js', plugin_dir_url(__FILE__).'public/js/sgbackup.js', array('jquery', 'jquery-effects-core', 'jquery-effects-transfer', 'jquery-ui-widget'));
145
+
146
+ // Localize the script with new data
147
+ wp_localize_script('backup-guard-backups-js', 'BG_BACKUP_STRINGS', array(
148
+ 'confirm' => _backupGuardT('Are you sure you want to cancel import?', true),
149
+ 'invalidBackupOption' => _backupGuardT('Please choose at least one option.', true),
150
+ 'invalidDirectorySelected' => _backupGuardT('Please choose at least one directory.', true),
151
+ 'invalidCloud' => _backupGuardT('Please choose at least one cloud.', true),
152
+ 'backupInProgress' => _backupGuardT('Backing Up...', true),
153
+ 'errorMessage' => _backupGuardT('Something went wrong. Please try again.', true),
154
+ 'noBackupsAvailable' => _backupGuardT('No backups found.', true),
155
+ 'invalidImportOption' => _backupGuardT('Please select one of the options.', true),
156
+ 'invalidDownloadFile' => _backupGuardT('Please choose one of the files.', true),
157
+ 'import' => _backupGuardT('Import', true),
158
+ 'importInProgress' => _backupGuardT('Importing please wait...', true),
159
+ 'fileUploadFailed' => _backupGuardT('File upload failed.', true)
160
+ ));
161
+
162
+ require_once(plugin_dir_path( __FILE__ ).'public/backups.php');
163
+ }
164
+ }
165
+
166
+ //Cloud Page
167
+ function backup_guard_cloud_page()
168
+ {
169
+ if (backupGuardValidateLicense()) {
170
+ wp_enqueue_style('backup-guard-switch-css', plugin_dir_url(__FILE__).'public/css/bootstrap-switch.min.css');
171
+ wp_enqueue_script('backup-guard-switch-js', plugin_dir_url(__FILE__).'public/js/bootstrap-switch.min.js', array('jquery'), '1.0.0', true);
172
+ wp_enqueue_script('backup-guard-cloud-js', plugin_dir_url(__FILE__).'public/js/sgcloud.js', array('jquery'), '1.0.0', true);
173
+
174
+ // Localize the script with new data
175
+ wp_localize_script('backup-guard-cloud-js', 'BG_CLOUD_STRINGS', array(
176
+ 'invalidImportFile' => _backupGuardT('Please select a file.', true),
177
+ 'invalidFileSize' => _backupGuardT('File is too large.', true),
178
+ 'connectionInProgress' => _backupGuardT('Connecting...', true),
179
+ 'invalidDestinationFolder' => _backupGuardT('Destination folder is required.', true),
180
+ 'successMessage' => _backupGuardT('Successfully saved.', true)
181
+ ));
182
+
183
+ require_once(plugin_dir_path(__FILE__).'public/cloud.php');
184
+ }
185
+ }
186
+
187
+ //Schedule Page
188
+ function backup_guard_schedule_page()
189
+ {
190
+ if (backupGuardValidateLicense()) {
191
+ wp_enqueue_style('backup-guard-switch-css', plugin_dir_url(__FILE__).'public/css/bootstrap-switch.min.css');
192
+ wp_enqueue_script('backup-guard-switch-js', plugin_dir_url(__FILE__).'public/js/bootstrap-switch.min.js', array('jquery'), '1.0.0', true);
193
+ wp_enqueue_script('backup-guard-schedule-js', plugin_dir_url(__FILE__).'public/js/sgschedule.js', array('jquery'), '1.0.0', true);
194
+
195
+ // Localize the script with new data
196
+ wp_localize_script('backup-guard-schedule-js', 'BG_SCHEDULE_STRINGS', array(
197
+ 'deletionError' => _backupGuardT('Unable to delete schedule', true),
198
+ 'confirm' => _backupGuardT('Are you sure?', true),
199
+ 'invalidBackupOption' => _backupGuardT('Please choose at least one option.', true),
200
+ 'invalidDirectorySelected' => _backupGuardT('Please choose at least one directory.', true),
201
+ 'invalidCloud' => _backupGuardT('Please choose at least one cloud.', true),
202
+ 'savingInProgress' => _backupGuardT('Saving...', true),
203
+ 'successMessage' => _backupGuardT('You have successfully activated schedule.', true),
204
+ 'saveButtonText' => _backupGuardT('Save', true)
205
+ ));
206
+
207
+ require_once(plugin_dir_path( __FILE__ ).'public/schedule.php');
208
+ }
209
+ }
210
+
211
+ //Settings Page
212
+ function backup_guard_settings_page()
213
+ {
214
+ if (backupGuardValidateLicense()) {
215
+ wp_enqueue_style('backup-guard-switch-css', plugin_dir_url(__FILE__).'public/css/bootstrap-switch.min.css');
216
+ wp_enqueue_script('backup-guard-switch-js', plugin_dir_url(__FILE__).'public/js/bootstrap-switch.min.js', array('jquery'), '1.0.0', true);
217
+ wp_enqueue_script('backup-guard-settings-js', plugin_dir_url(__FILE__).'public/js/sgsettings.js', array('jquery'), '1.0.0', true );
218
+
219
+ // Localize the script with new data
220
+ wp_localize_script('backup-guard-settings-js', 'BG_SETTINGS_STRINGS', array(
221
+ 'invalidEmailAddress' => _backupGuardT('Please enter valid email.', true),
222
+ 'invalidFileName' => _backupGuardT('Please enter valid file name.', true),
223
+ 'invalidRetentionNumber' => _backupGuardT('Please enter a valid retention number.', true),
224
+ 'successMessage' => _backupGuardT('Successfully saved.', true),
225
+ 'savingInProgress' => _backupGuardT('Saving...', true),
226
+ 'retentionConfirmationFirstPart' => _backupGuardT('Are you sure you want to keep the latest', true),
227
+ 'retentionConfirmationSecondPart' => _backupGuardT('backups? All older backups will be deleted.', true),
228
+ 'saveButtonText' => _backupGuardT('Save', true)
229
+ ));
230
+
231
+ require_once(plugin_dir_path(__FILE__).'public/settings.php');
232
+ }
233
+ }
234
+
235
+ function backup_guard_login_page()
236
+ {
237
+ wp_enqueue_script('backup-guard-login-js', plugin_dir_url(__FILE__).'public/js/sglogin.js', array('jquery'), '1.0.0', true);
238
+
239
+ require_once(plugin_dir_path(__FILE__).'public/login.php');
240
+ }
241
+
242
+ function backup_guard_link_license_page()
243
+ {
244
+ wp_enqueue_script('backup-guard-license-js', plugin_dir_url(__FILE__).'public/js/sglicense.js', array('jquery'), '1.0.0', true);
245
+ // Localize the script with new data
246
+ wp_localize_script('backup-guard-license-js', 'BG_LICENSE_STRINGS', array(
247
+ 'invalidLicense' => _backupGuardT('Please choose a license first', true),
248
+ 'availableLicenses' => _backupGuardT('There are no available licenses for using the selected product', true)
249
+ ));
250
+
251
+ require_once(plugin_dir_path(__FILE__).'public/link_license.php');
252
+ }
253
+
254
+ add_action('admin_enqueue_scripts', 'enqueue_backup_guard_scripts');
255
+ function enqueue_backup_guard_scripts($hook)
256
+ {
257
+ wp_enqueue_script('backup-guard-discount-notice', plugin_dir_url(__FILE__).'public/js/sgNoticeDismiss.js', array('jquery'), '1.0', true);
258
+
259
+ if (!strpos($hook,'backup_guard')) {
260
+ if($hook == "index.php"){
261
+ wp_enqueue_script('backup-guard-chart-manager', plugin_dir_url(__FILE__).'public/js/Chart.bundle.min.js');
262
+ }
263
+ return;
264
+ }
265
+
266
+ wp_enqueue_style('backup-guard-spinner', plugin_dir_url(__FILE__).'public/css/spinner.css');
267
+ wp_enqueue_style('backup-guard-wordpress', plugin_dir_url(__FILE__).'public/css/bgstyle.wordpress.css');
268
+ wp_enqueue_style('backup-guard-less', plugin_dir_url(__FILE__).'public/css/bgstyle.less.css');
269
+ wp_enqueue_style('backup-guard-styles', plugin_dir_url(__FILE__).'public/css/styles.css');
270
+
271
+ echo '<script type="text/javascript">sgBackup={};';
272
+ $sgAjaxRequestFrequency = SGConfig::get('SG_AJAX_REQUEST_FREQUENCY');
273
+ if (!$sgAjaxRequestFrequency) {
274
+ $sgAjaxRequestFrequency = SG_AJAX_DEFAULT_REQUEST_FREQUENCY;
275
+ }
276
+ echo 'SG_AJAX_REQUEST_FREQUENCY = "'.$sgAjaxRequestFrequency.'";';
277
+ echo 'function getAjaxUrl(url) {'.
278
+ 'if (url==="cloudDropbox" || url==="cloudGdrive" || url==="cloudOneDrive") return "'.admin_url('admin-post.php?action=backup_guard_').'"+url;'.
279
+ 'return "'.admin_url('admin-ajax.php').'";}</script>';
280
+
281
+ wp_enqueue_media();
282
+ wp_enqueue_script('backup-guard-less-framework', plugin_dir_url(__FILE__).'public/js/less.min.js', array('jquery'), '1.0.0', true);
283
+ wp_enqueue_script('backup-guard-bootstrap-framework', plugin_dir_url(__FILE__).'public/js/bootstrap.min.js', array('jquery'), '1.0.0', true);
284
+ wp_enqueue_script('backup-guard-sgrequest-js', plugin_dir_url(__FILE__).'public/js/sgrequesthandler.js', array('jquery'), '1.0.0', true);
285
+ wp_enqueue_script('backup-guard-sgwprequest-js', plugin_dir_url(__FILE__).'public/js/sgrequesthandler.wordpress.js', array('jquery'), '1.0.0', true);
286
+
287
+ wp_enqueue_style('backup-guard-rateyo-css', plugin_dir_url(__FILE__).'public/css/jquery.rateyo.css');
288
+ wp_enqueue_script('backup-guard-rateyo-js', plugin_dir_url(__FILE__).'public/js/jquery.rateyo.js');
289
+
290
+ wp_enqueue_script('backup-guard-main-js', plugin_dir_url(__FILE__).'public/js/main.js', array('jquery'), '1.0.0', true);
291
+
292
+ // Localize the script with new data
293
+ wp_localize_script('backup-guard-main-js', 'BG_MAIN_STRINGS', array(
294
+ 'confirmCancel' => _backupGuardT('Are you sure you want to cancel?', true)
295
+ ));
296
+ }
297
+
298
+ // adding actions to handle modal ajax requests
299
+ add_action( 'wp_ajax_backup_guard_modalManualBackup', 'backup_guard_get_manual_modal');
300
+ add_action( 'wp_ajax_backup_guard_modalManualRestore', 'backup_guard_get_manual_restore_modal');
301
+ add_action( 'wp_ajax_backup_guard_modalImport', 'backup_guard_get_import_modal');
302
+ add_action( 'wp_ajax_backup_guard_modalFtpSettings', 'backup_guard_get_ftp_modal');
303
+ add_action( 'wp_ajax_backup_guard_modalAmazonSettings', 'backup_guard_get_amazon_modal');
304
+ add_action( 'wp_ajax_backup_guard_modalPrivacy', 'backup_guard_get_privacy_modal');
305
+ add_action( 'wp_ajax_backup_guard_modalTerms', 'backup_guard_get_terms_modal');
306
+ add_action( 'wp_ajax_backup_guard_modalReview', 'backup_guard_get_review_modal');
307
+ add_action( 'wp_ajax_backup_guard_getFileDownloadProgress', 'backup_guard_get_file_download_progress');
308
+ add_action( 'wp_ajax_backup_guard_modalCreateSchedule', 'backup_guard_create_schedule');
309
+ add_action( 'wp_ajax_backup_guard_getBackupContent', 'backup_guard_get_backup_content');
310
+
311
+ function backup_guard_get_file_download_progress()
312
+ {
313
+ require_once(SG_PUBLIC_AJAX_PATH.'getFileDownloadProgress.php');
314
+ exit();
315
+ }
316
+
317
+ function backup_guard_create_schedule()
318
+ {
319
+ require_once(SG_PUBLIC_AJAX_PATH.'modalCreateSchedule.php');
320
+ exit();
321
+ }
322
+
323
+ function backup_guard_get_manual_modal()
324
+ {
325
+ require_once(SG_PUBLIC_AJAX_PATH.'modalManualBackup.php');
326
+ exit();
327
+ }
328
+
329
+ function backup_guard_get_manual_restore_modal()
330
+ {
331
+ require_once(SG_PUBLIC_AJAX_PATH.'modalManualRestore.php');
332
+ exit();
333
+ }
334
+
335
+ function backup_guard_get_backup_content()
336
+ {
337
+ require_once (SG_PUBLIC_AJAX_PATH.'getBackupContent.php');
338
+ exit();
339
+ }
340
+
341
+ function backup_guard_get_import_modal()
342
+ {
343
+ require_once(SG_PUBLIC_AJAX_PATH.'modalImport.php');
344
+ exit();
345
+ }
346
+
347
+ function backup_guard_get_ftp_modal()
348
+ {
349
+ require_once(SG_PUBLIC_AJAX_PATH.'modalFtpSettings.php');
350
+ exit();
351
+ }
352
+
353
+ function backup_guard_get_amazon_modal()
354
+ {
355
+ require_once(SG_PUBLIC_AJAX_PATH.'modalAmazonSettings.php');
356
+ exit();
357
+ }
358
+
359
+ function backup_guard_get_privacy_modal()
360
+ {
361
+ require_once(SG_PUBLIC_AJAX_PATH.'modalPrivacy.php');
362
+ }
363
+
364
+ function backup_guard_get_terms_modal()
365
+ {
366
+ require_once(SG_PUBLIC_AJAX_PATH.'modalTerms.php');
367
+ exit();
368
+ }
369
+
370
+ function backup_guard_get_review_modal()
371
+ {
372
+ require_once(SG_PUBLIC_AJAX_PATH.'modalReview.php');
373
+ exit();
374
+ }
375
+
376
+ function backup_guard_register_ajax_callbacks()
377
+ {
378
+ if (is_super_admin()) {
379
+ // adding actions to handle ajax and post requests
380
+ add_action('wp_ajax_backup_guard_cancelBackup', 'backup_guard_cancel_backup');
381
+ add_action('wp_ajax_backup_guard_checkBackupCreation', 'backup_guard_check_backup_creation');
382
+ add_action('wp_ajax_backup_guard_checkRestoreCreation', 'backup_guard_check_restore_creation');
383
+ add_action('wp_ajax_backup_guard_cloudDropbox', 'backup_guard_cloud_dropbox');
384
+ add_action('wp_ajax_backup_guard_cloudGdrive', 'backup_guard_cloud_gdrive');
385
+ add_action('wp_ajax_backup_guard_cloudOneDrive', 'backup_guard_cloud_oneDrive');
386
+ add_action('wp_ajax_backup_guard_cloudFtp', 'backup_guard_cloud_ftp');
387
+ add_action('wp_ajax_backup_guard_cloudAmazon', 'backup_guard_cloud_amazon');
388
+ add_action('wp_ajax_backup_guard_curlChecker', 'backup_guard_curl_checker');
389
+ add_action('wp_ajax_backup_guard_deleteBackup', 'backup_guard_delete_backup');
390
+ add_action('wp_ajax_backup_guard_getAction', 'backup_guard_get_action');
391
+ add_action('wp_ajax_backup_guard_getRunningActions', 'backup_guard_get_running_actions');
392
+ add_action('wp_ajax_backup_guard_importBackup', 'backup_guard_get_import_backup');
393
+ add_action('wp_ajax_backup_guard_resetStatus', 'backup_guard_reset_status');
394
+ add_action('wp_ajax_backup_guard_restore', 'backup_guard_restore');
395
+ add_action('wp_ajax_backup_guard_saveCloudFolder', 'backup_guard_save_cloud_folder');
396
+ add_action('wp_ajax_backup_guard_schedule', 'backup_guard_schedule');
397
+ add_action('wp_ajax_backup_guard_settings', 'backup_guard_settings');
398
+ add_action('wp_ajax_backup_guard_setReviewPopupState', 'backup_guard_set_review_popup_state');
399
+ add_action('wp_ajax_backup_guard_sendUsageStatistics', 'backup_guard_send_usage_statistics');
400
+ add_action('wp_ajax_backup_guard_hideNotice', 'backup_guard_hide_notice');
401
+ add_action('wp_ajax_backup_guard_downloadFromCloud', 'backup_guard_download_from_cloud');
402
+ add_action('wp_ajax_backup_guard_listStorage', 'backup_guard_list_storage');
403
+ add_action('wp_ajax_backup_guard_cancelDownload', 'backup_guard_cancel_download');
404
+ add_action('wp_ajax_backup_guard_awake', 'backup_guard_awake');
405
+ add_action('wp_ajax_backup_guard_manualBackup', 'backup_guard_manual_backup');
406
+ add_action('admin_post_backup_guard_downloadBackup', 'backup_guard_download_backup');
407
+ add_action('wp_ajax_backup_guard_login', 'backup_guard_login');
408
+ add_action('wp_ajax_backup_guard_logout', 'backup_guard_logout');
409
+ add_action('wp_ajax_backup_guard_link_license', 'backup_guard_link_license');
410
+ add_action('wp_ajax_backup_guard_importKeyFile', 'backup_guard_import_key_file');
411
+ add_action('wp_ajax_backup_guard_isFeatureAvailable', 'backup_guard_is_feature_available');
412
+ add_action('wp_ajax_backup_guard_dismiss_discount_notice', 'backup_guard_dismiss_discount_notice');
413
+ add_action('wp_ajax_backup_guard_checkPHPVersionCompatibility', 'backup_guard_check_php_version_compatibility');
414
+ add_action('wp_ajax_backup_guard_setUserInfoVerificationPopupState', 'backup_guard_set_user_info_verification_popup_state');
415
+ add_action('wp_ajax_backup_guard_storeSubscriberInfo', 'backup_guard_store_subscriber_info');
416
+ add_action('wp_ajax_backup_guard_storeSurveyResult', 'backup_guard_store_survey_result');
417
+ }
418
+ }
419
+
420
+ function backup_guard_store_survey_result()
421
+ {
422
+ require_once(SG_PUBLIC_AJAX_PATH.'storeSurveyResult.php');
423
+ }
424
+
425
+ function backup_guard_store_subscriber_info()
426
+ {
427
+ require_once(SG_PUBLIC_AJAX_PATH.'storeSubscriberInfo.php');
428
+ }
429
+
430
+ function backup_guard_set_user_info_verification_popup_state()
431
+ {
432
+ require_once(SG_PUBLIC_AJAX_PATH.'setUserInfoVerificationPopupState.php');
433
+ }
434
+
435
+ function backup_guard_dismiss_discount_notice()
436
+ {
437
+ require_once(SG_PUBLIC_AJAX_PATH.'dismissDiscountNotice.php');
438
+ }
439
+
440
+ function backup_guard_is_feature_available()
441
+ {
442
+ require_once(SG_PUBLIC_AJAX_PATH.'isFeatureAvailable.php');
443
+ }
444
+
445
+ function backup_guard_check_php_version_compatibility()
446
+ {
447
+ require_once(SG_PUBLIC_AJAX_PATH.'checkPHPVersionCompatibility.php');
448
+ }
449
+
450
+ add_action('init', 'backup_guard_init');
451
+ add_action('wp_ajax_nopriv_backup_guard_awake', 'backup_guard_awake_nopriv');
452
+ add_action('admin_post_backup_guard_cloudDropbox', 'backup_guard_cloud_dropbox');
453
+ add_action('admin_post_backup_guard_cloudGdrive', 'backup_guard_cloud_gdrive');
454
+ add_action('admin_post_backup_guard_cloudOneDrive', 'backup_guard_cloud_oneDrive');
455
+
456
+ function backup_guard_cloud_oneDrive()
457
+ {
458
+ require_once(SG_PUBLIC_AJAX_PATH.'cloudOneDrive.php');
459
+ }
460
+
461
+ function backup_guard_import_key_file()
462
+ {
463
+ require_once(SG_PUBLIC_AJAX_PATH.'importKeyFile.php');
464
+ }
465
+
466
+ function backup_guard_awake()
467
+ {
468
+ $method = SG_RELOAD_METHOD_AJAX;
469
+ require_once(SG_PUBLIC_AJAX_PATH.'awake.php');
470
+ }
471
+
472
+ function backup_guard_awake_nopriv()
473
+ {
474
+ $token = @$_GET['token'];
475
+ $method = @$_GET['method'];
476
+
477
+ if (backupGuardValidateApiCall($token)) {
478
+ require_once(SG_PUBLIC_AJAX_PATH.'awake.php');
479
+ }
480
+ }
481
+
482
+ function backup_guard_cancel_download()
483
+ {
484
+ require_once(SG_PUBLIC_AJAX_PATH.'cancelDownload.php');
485
+ }
486
+
487
+ function backup_guard_list_storage()
488
+ {
489
+ require_once(SG_PUBLIC_AJAX_PATH.'listStorage.php');
490
+ }
491
+
492
+ function backup_guard_download_from_cloud()
493
+ {
494
+ require_once(SG_PUBLIC_AJAX_PATH.'downloadFromCloud.php');
495
+ }
496
+
497
+ function backup_guard_hide_notice()
498
+ {
499
+ require_once(SG_PUBLIC_AJAX_PATH.'hideNotice.php');
500
+ }
501
+
502
+ function backup_guard_cancel_backup()
503
+ {
504
+ require_once(SG_PUBLIC_AJAX_PATH.'cancelBackup.php');
505
+ }
506
+
507
+ function backup_guard_check_backup_creation()
508
+ {
509
+ require_once(SG_PUBLIC_AJAX_PATH.'checkBackupCreation.php');
510
+ }
511
+
512
+ function backup_guard_check_restore_creation()
513
+ {
514
+ require_once(SG_PUBLIC_AJAX_PATH.'checkRestoreCreation.php');
515
+ }
516
+
517
+ function backup_guard_cloud_dropbox()
518
+ {
519
+ require_once(SG_PUBLIC_AJAX_PATH.'cloudDropbox.php');
520
+ }
521
+
522
+ function backup_guard_cloud_ftp()
523
+ {
524
+ require_once(SG_PUBLIC_AJAX_PATH.'cloudFtp.php');
525
+ }
526
+
527
+ function backup_guard_cloud_amazon()
528
+ {
529
+ require_once(SG_PUBLIC_AJAX_PATH.'cloudAmazon.php');
530
+ }
531
+
532
+ function backup_guard_cloud_gdrive()
533
+ {
534
+ require_once(SG_PUBLIC_AJAX_PATH.'cloudGdrive.php');
535
+ }
536
+
537
+ function backup_guard_curl_checker()
538
+ {
539
+ require_once(SG_PUBLIC_AJAX_PATH.'curlChecker.php');
540
+ }
541
+
542
+ function backup_guard_delete_backup()
543
+ {
544
+ require_once(SG_PUBLIC_AJAX_PATH.'deleteBackup.php');
545
+ }
546
+
547
+ function backup_guard_download_backup()
548
+ {
549
+ require_once(SG_PUBLIC_AJAX_PATH.'downloadBackup.php');
550
+ }
551
+
552
+ function backup_guard_get_action()
553
+ {
554
+ require_once(SG_PUBLIC_AJAX_PATH.'getAction.php');
555
+ }
556
+
557
+ function backup_guard_get_running_actions()
558
+ {
559
+ require_once(SG_PUBLIC_AJAX_PATH.'getRunningActions.php');
560
+ }
561
+
562
+ function backup_guard_get_import_backup()
563
+ {
564
+ require_once(SG_PUBLIC_AJAX_PATH.'importBackup.php');
565
+ }
566
+
567
+ function backup_guard_manual_backup()
568
+ {
569
+ require_once(SG_PUBLIC_AJAX_PATH.'manualBackup.php');
570
+ }
571
+
572
+ function backup_guard_reset_status()
573
+ {
574
+ require_once(SG_PUBLIC_AJAX_PATH.'resetStatus.php');
575
+ }
576
+
577
+ function backup_guard_restore()
578
+ {
579
+ require_once(SG_PUBLIC_AJAX_PATH.'restore.php');
580
+ }
581
+
582
+ function backup_guard_save_cloud_folder()
583
+ {
584
+ require_once(SG_PUBLIC_AJAX_PATH.'saveCloudFolder.php');
585
+ }
586
+
587
+ function backup_guard_schedule()
588
+ {
589
+ require_once(SG_PUBLIC_AJAX_PATH.'schedule.php');
590
+ }
591
+
592
+ function backup_guard_settings()
593
+ {
594
+ require_once(SG_PUBLIC_AJAX_PATH.'settings.php');
595
+ }
596
+
597
+ function backup_guard_set_review_popup_state()
598
+ {
599
+ require_once(SG_PUBLIC_AJAX_PATH.'setReviewPopupState.php');
600
+ }
601
+
602
+ function backup_guard_send_usage_statistics()
603
+ {
604
+ require_once(SG_PUBLIC_AJAX_PATH.'sendUsageStatistics.php');
605
+ }
606
+
607
+ function backup_guard_login()
608
+ {
609
+ require_once(SG_PUBLIC_AJAX_PATH.'login.php');
610
+ }
611
+
612
+ function backup_guard_logout()
613
+ {
614
+ require_once(SG_PUBLIC_AJAX_PATH.'logout.php');
615
+ }
616
+
617
+ function backup_guard_link_license()
618
+ {
619
+ require_once(SG_PUBLIC_AJAX_PATH.'linkLicense.php');
620
+ }
621
+
622
+ //adds once weekly to the existing schedules.
623
+ add_filter('cron_schedules', 'backup_guard_cron_add_weekly');
624
+ function backup_guard_cron_add_weekly($schedules)
625
+ {
626
+ $schedules['weekly'] = array(
627
+ 'interval' => 60*60*24*7,
628
+ 'display' => 'Once weekly'
629
+ );
630
+ return $schedules;
631
+ }
632
+
633
+ //adds once monthly to the existing schedules.
634
+ add_filter('cron_schedules', 'backup_guard_cron_add_monthly');
635
+ function backup_guard_cron_add_monthly($schedules)
636
+ {
637
+ $schedules['monthly'] = array(
638
+ 'interval' => 60*60*24*30,
639
+ 'display' => 'Once monthly'
640
+ );
641
+ return $schedules;
642
+ }
643
+
644
+ //adds once yearly to the existing schedules.
645
+ add_filter('cron_schedules', 'backup_guard_cron_add_yearly');
646
+ function backup_guard_cron_add_yearly($schedules)
647
+ {
648
+ $schedules['yearly'] = array(
649
+ 'interval' => 60*60*24*30*12,
650
+ 'display' => 'Once yearly'
651
+ );
652
+ return $schedules;
653
+ }
654
+
655
+ function backup_guard_init()
656
+ {
657
+ backup_guard_register_ajax_callbacks();
658
+ // backupGuardPluginRedirect();
659
+
660
+ //check if database should be updated
661
+ if (backupGuardShouldUpdate()) {
662
+ SGBoot::install();
663
+ }
664
+
665
+ backupGuardSymlinksCleanup(SG_SYMLINK_PATH);
666
+ }
667
+
668
+ add_action(SG_SCHEDULE_ACTION, 'backup_guard_schedule_action', 10, 1);
669
+
670
+ function backup_guard_schedule_action($id)
671
+ {
672
+ require_once(SG_PUBLIC_PATH.'cron/sg_backup.php');
673
+ }
674
+
675
+ //load pro plugin updater
676
+ $pluginCapabilities = backupGuardGetCapabilities();
677
+ if ($pluginCapabilities != BACKUP_GUARD_CAPABILITIES_FREE) {
678
+ require_once(dirname(__FILE__).'/plugin-update-checker/plugin-update-checker.php');
679
+ require_once(dirname(__FILE__).'/plugin-update-checker/Puc/v4/Utils.php');
680
+ require_once(SG_LIB_PATH.'SGAuthClient.php');
681
+
682
+ $licenseKey = SGConfig::get('SG_LICENSE_KEY');
683
+
684
+ $updateChecker = Puc_v4_Factory::buildUpdateChecker(
685
+ BackupGuard\Config::URL.'/products/details/'.$licenseKey,
686
+ SG_BACKUP_GUARD_MAIN_FILE,
687
+ SG_PRODUCT_IDENTIFIER
688
+ );
689
+
690
+ $updateChecker->addHttpRequestArgFilter(array(
691
+ SGAuthClient::getInstance(),
692
+ 'filterUpdateChecks'
693
+ ));
694
+ }
695
+
696
+ if (SGBoot::isFeatureAvailable('ALERT_BEFORE_UPDATE')) {
697
+ add_filter('upgrader_pre_download', 'backupGuardOnBeforeUpdateDownload', 10, 3);
698
+ add_action('core_upgrade_preamble', 'backupGuardOnUpgradeScreenActivate');
699
+ add_action('current_screen', 'backupGuardOnScreenActivate');
700
+ }
701
+
702
+ // Register the new dashboard widget with the 'wp_dashboard_setup' action
703
+ add_action('wp_dashboard_setup', 'backup_guard_add_dashboard_widgets');
704
+
705
+ function backup_guard_add_dashboard_widgets()
706
+ {
707
+ require_once(SG_CORE_PATH.'SGConfig.php');
708
+
709
+ $userId = get_current_user_id();
710
+ $userData = get_userdata($userId);
711
+ $userRoles = $userData->roles;
712
+ $isAdminUser = false;
713
+ for($i = 0; $i < count($userRoles); $i++) {
714
+ if ($userRoles[$i] == "administrator") {
715
+ $isAdminUser = true;
716
+ break;
717
+ }
718
+ }
719
+
720
+ if (!$isAdminUser ) {
721
+ return;
722
+ }
723
+
724
+ $isShowStatisticsWidgetEnabled = SGConfig::get('SG_SHOW_STATISTICS_WIDGET');
725
+ if (!$isShowStatisticsWidgetEnabled) {
726
+ return;
727
+ }
728
+
729
+
730
+ require_once(plugin_dir_path( __FILE__ ).'public/dashboardWidget.php');
731
+ wp_add_dashboard_widget('backupGuardWidget', 'Backup Guard', 'backup_guard_dashboard_widget_function');
732
+ }
733
+
734
+ add_action('plugins_loaded', 'backupGuardloadTextDomain');
735
+ function backupGuardloadTextDomain()
736
+ {
737
+ $backupGuardLangDir = plugin_dir_path(__FILE__).'languages/';
738
+ $backupGuardLangDir = apply_filters('backupguardLanguagesDirectory', $backupGuardLangDir);
739
+
740
+ $locale = apply_filters('bg_plugin_locale', get_locale(), BACKUP_GUARD_TEXTDOMAIN);
741
+ $mofile = sprintf('%1$s-%2$s.mo', BACKUP_GUARD_TEXTDOMAIN, $locale);
742
+
743
+ $mofileLocal = $backupGuardLangDir.$mofile;
744
+
745
+ if (file_exists($mofileLocal)) {
746
+ // Look in local /wp-content/plugins/popup-builder/languages/ folder
747
+ load_textdomain(BACKUP_GUARD_TEXTDOMAIN, $mofileLocal);
748
+ }
749
+ else {
750
+ // Load the default language files
751
+ load_plugin_textdomain(BACKUP_GUARD_TEXTDOMAIN, false, $backupGuardLangDir);
752
+ }
753
+ }
754
+
755
+ if (backupGuardShouldShowDiscountNotice() && checkDueDateDiscount()) {
756
+ add_action('admin_notices', 'backup_guard_discount_notice');
757
+ }
758
+
759
+ function backup_guard_discount_notice()
760
+ {
761
+ $capabilities = backupGuardGetCapabilities();
762
+ $upgradeUrl = BG_UPGRADE_URL;
763
+ ?>
764
+ <div class="backup-guard-discount-notice updated notice is-dismissible">
765
+ <a href="<?php echo BG_UPGRADE_URL; ?>" target="_blank"><div class="discount-banner" style="background-image: url('<?php echo SG_IMAGE_URL ?>halloween.jpg');background-repeat: no-repeat; background-position: center; height: 200px;"></div></a>
766
+ </div>
767
+ <style>
768
+ .backup-guard-discount-notice.updated.notice.is-dismissible {
769
+ padding: 0;
770
+ border-left-color: #fea500 !important;
771
+ }
772
+ .backup-guard-discount-notice button:before {
773
+ color: #fea500 !important;
774
+ }
775
+ </style>
776
+ <?php
777
+ }
README.txt ADDED
@@ -0,0 +1,528 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === WordPress Backup and Migrate Plugin - Backup Guard ===
2
+ Plugin Name: WordPress Backup and Migrate Plugin - Backup Guard
3
+ Contributors: Backup Guard, Backup Guard Support
4
+ Author: Backup Guard
5
+ Donate link: https://backup-guard.com/products/backup-wordpress
6
+ Tags: backup, wordpress backup plugin, backup plugin, database backup, migrate, back up
7
+ Requires at least: 3.8
8
+ Tested up to: 5.3
9
+ Stable tag: trunk
10
+ License: GPLv2 or later
11
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
+
13
+ Backup site, restore or migrate it wherever you need it. Backup to Dropbox, Google Drive, Amazon, OneDrive, FTP / SFTP to restore or migrate WordPress.
14
+
15
+ == Description ==
16
+
17
+ Backup Guard is the most complete WordPress backup plugin. We offer the easiest way to <strong>Backup</strong>, <strong>Restore</strong> and <strong>Migrate</strong> your WordPress website. You can backup and restore your WordPress files, database or both.
18
+
19
+ <p>Download <strong>BackupGuard Pro</strong> here: <a href="https://backup-guard.com/products/backup-wordpress">https://backup-guard.com/products/backup-wordpress</a></p>
20
+
21
+ https://www.youtube.com/watch?v=HCz4mkMMXos
22
+
23
+ <h4>Free backup features</h4>
24
+ <ul>
25
+ <li>Backup site - backup site as many times as you want</li>
26
+ <li>Backup files, database or both</li>
27
+ <li>Choose which folders to backup</li>
28
+ <li>Choose which database tables to backup</li>
29
+ <li>Restore site - restore backups whenever needed</li>
30
+ <li>Selective files or database restoration</li>
31
+ <li>Download backups - download your backups on your computer</li>
32
+ <li>Import backups - upload your backups to restore (no FTP required)</li>
33
+ <li>Multisite WordPress Network is supported</li>
34
+ <li>Backup cancellation - cancel the backup process</li>
35
+ <li>Explore backup or restore log files</li>
36
+ <li>Ability to specify custom exclude paths</li>
37
+ <li>Ability to exclude database tables</li>
38
+ <li>Live progress - precise progress of the current backup or restore</li>
39
+ <li>Upload to Dropbox</li>
40
+ <li>Scheduled site backups - setup automatic site backups</li>
41
+ </ul>
42
+
43
+ See <strong>BackupGuard Free</strong> in action here: <a href="https://www.youtube.com/watch?v=nt6XoP69c0M">https://www.youtube.com/watch?v=nt6XoP69c0M</a>
44
+
45
+ <h4>Pro backup features</h4>
46
+ <ul>
47
+ <li><strong>Migrate site</strong> - migrate site from one domain to another</li>
48
+ <li>Fully automatic migration - no any <strong>find & replace</strong> rules are required for migration</li>
49
+ <li>Multiple scheduled backups - schedule your database and files to backup with different frequencies</li>
50
+ <li>Upload to Dropbox, G Drive, Amazon S3, OneDrive & SFTP/FTP</li>
51
+ <li>Import from Dropbox, G Drive, Amazon S3, OneDrive & SFTP/FTP</li>
52
+ <li>Mail notifications - get email when backup or restore gets finished</li>
53
+ <li>Alert before updating - get an alert to backup the website before updating</li>
54
+ <li>Customize backup naming - specify your custom backup prefix</li>
55
+ <li>Backups retention - specify the number of backups you want to keep on your server</li>
56
+ <li>Backups cloud path - specify a custom cloud path where your site backups should be uploaded</li>
57
+ <li>Background backup mode - backup site in low priority mode</li>
58
+ <li>Emergency support - up to 24 hours</li>
59
+ </ul>
60
+
61
+ See <strong>BackupGuard Pro</strong> in action here: <a href="https://www.youtube.com/watch?v=TSPgmrSu-ls">https://www.youtube.com/watch?v=TSPgmrSu-ls</a>
62
+
63
+ <h4>A special note on WordPress migration</h4>
64
+
65
+ A WordPress site migration is an easy task if performed properly. There are three different migration scenarios:
66
+ <ul>
67
+ <li>Migrate site from a subdirectory of a domain to the root directory</li>
68
+ <li>Migrate site from a local installation to a remote installation</li>
69
+ <li>Migrate site between domains or hosts</li>
70
+ </ul>
71
+
72
+ Backup Guard Pro helps you to migrate in all of these cases in the smoothest possible way. You just have to Backup your site and Restore it in the new location. No additional work will be required, since we handle all changes for you.
73
+
74
+ The issues that users always deal with are: wrong site url, images don't load, dashboard not accessible, permalinks don't work and more.
75
+
76
+ Backup Guard Pro will help you to skip all these problems, because of its advanced refactoring and migrating engine.
77
+
78
+ <h4>Documentation</h4>
79
+ The documentation can be found here: <a href="https://backup-guard.com/products/backup-wordpress/doc">https://backup-guard.com/products/backup-wordpress/doc</a>
80
+
81
+ <h4>This is how backup operates</h4>
82
+ <ul>
83
+ <li>No extra libraries required</li>
84
+ <li>Support of large websites</li>
85
+ <li>New archive format: faster and smaller than Zip or Tar</li>
86
+ <li>Works in low memory & shared hosting environments</li>
87
+ <li>Serialized data refactoring for proper migration</li>
88
+ </ul>
89
+
90
+ <h4>Backup Guard min. requirements</h4>
91
+ <ul>
92
+ <li><strong>Free</strong> requires - PHP 5.3.3, zlib, WordPress 3.8</li>
93
+ <li><strong>Pro</strong> requires - PHP 5.3.3, zlib, curl, WordPress 3.8</li>
94
+ <li><strong>Note:</strong> Dropbox SDK requires 64-bit system. Backup Guard will also require 64-bit system if the website is larger than 2GB.</li>
95
+ </ul>
96
+
97
+ <p>More info at: <a href="https://backup-guard.com/products/backup-wordpress">https://backup-guard.com/products/backup-wordpress</a></p>
98
+
99
+ <h4>Support</h4>
100
+ <p><a href="https://backup-guard.com/products/backup-wordpress/support">https://backup-guard.com/products/backup-wordpress/support</a></p>
101
+
102
+ == Frequently Asked Questions ==
103
+
104
+ = How to install? =
105
+
106
+ <ul>
107
+ <li>Install <strong>Free</strong> version: <a href="https://backup-guard.com/products/backup-wordpress/doc/install-backupguard-free">here</a></li>
108
+ <li>Install <strong>Pro</strong> version: <a href="https://backup-guard.com/products/backup-wordpress/doc/install-backupguard-pro">here</a></li>
109
+ </ul>
110
+
111
+ = Can I use BackupGuard to migrate a website? =
112
+
113
+ The answer is Yes, you can! Backup Guard Pro supports advanced migration functionality which will help you easily migrate your website from one domain to another. All urls, images and other domain-dependent data will be properly refactored and deployed for the new domain.
114
+
115
+ = What is included in the basic (free) plan? =
116
+
117
+ Backup Guard Free gives you the ability to backup or restore your website as many times as you want. You can also download your backups and import them in other websites where Backup Guard is installed and running.
118
+
119
+ = Why should I purchase Backup Guard Pro? =
120
+
121
+ Although Backup Guard Free gives you the ability to backup and restore your website as many times as you want, your backups will only reside on your server. With our Pro plans you can upload your backups to the cloud of your preference, schedule your backups, receive notifications, and many other features.
122
+
123
+ That's not all, if you are a paid user, you will receive priority/emergency support and finally, only with our Platinum plan, you will receive "unlimited plans" license which will allow you to install Backup Guard on as many websites as you want.
124
+
125
+ <a href="https://backup-guard.com/products/backup-wordpress">Backup Guard PRO</a>
126
+
127
+ = How to fix “MySQL server has gone away” error? =
128
+
129
+ While restoring your database you may encounter “MySQL server has gone away” warning. There are generally two main causes for this error: 1) the server timed out and closed the connection and 2) server dropped an incorrect or too large packet.
130
+ To fix the issue you will have to contact your hosting provider and ask them increase the size of these two values: max_allowed_packet & wait_timeout
131
+
132
+ = How do I Restore my Backup? =
133
+
134
+ This documentation describes the basic steps you should follow for proper restoration: <a href="https://backup-guard.com/products/backup-wordpress/doc/restore-website">https://backup-guard.com/products/backup-wordpress/doc/restore-website</a>
135
+
136
+ = How do I download my Backup archive? =
137
+
138
+ This documentation describes the basic steps you should follow for downloading your backup archives: <a href="https://backup-guard.com/products/backup-wordpress/doc/download-backup">https://backup-guard.com/products/backup-wordpress/doc/download-backup</a>
139
+
140
+ = How do I extract my Backup archive? =
141
+
142
+ This documentation describes the basic steps you should follow for extracting your backup archives: <a href="https://backup-guard.com/products/backup-wordpress/doc/extract-sgbp">https://backup-guard.com/products/backup-wordpress/doc/extract-sgbp</a>
143
+
144
+ = Something is not working, what should I do? =
145
+
146
+ No software is perfect and we are not the exception. There are tons of different servers and configurations and something may go wrong in one of them.
147
+
148
+ When you are facing an issue of any kind with any of our products, the first thing to do is <a href="https://backup-guard.com/products/backup-wordpress/support">contacting us</a>. We are here to help you, give you tips, advices and even create fixes/patches or features whenever needed.
149
+
150
+ == Screenshots ==
151
+
152
+ 1. Backup WordPress
153
+ 2. Website backup and migration
154
+ 3. Schedule a site backup
155
+ 4. Backup cloud integrations
156
+ 5. Backup status mail notifications
157
+ 6. Site backup customization
158
+
159
+ == Changelog ==
160
+
161
+ = 1.1.90 =
162
+ * Halloween campaign
163
+
164
+ = 1.1.89 =
165
+ * Conflicts were resolved
166
+
167
+ = 1.1.88 =
168
+ * Issue with restore have been fixed
169
+
170
+ = 1.1.87 =
171
+ * Minor bug fixes and improvements
172
+
173
+ = 1.1.86 =
174
+ * Users now can specify custom name for manual backups
175
+ * PHP7 compatibility issues fixed
176
+
177
+ = 1.1.85 =
178
+ * Migration removed from free package
179
+ * Other minor bug fixes and improvements
180
+
181
+ = 1.1.84 =
182
+ * Now you can perform migration with free version
183
+
184
+ = 1.1.83 =
185
+ * Spanish translation added
186
+ * System information section added
187
+
188
+ = 1.1.82 =
189
+ * Bug fixes and improvements
190
+
191
+ = 1.1.81 =
192
+ * PHP7 compatibility issues fixed
193
+ * Other minor bug fixes and improvements
194
+
195
+ = 1.1.80 =
196
+ * Direct curl calls removed
197
+
198
+ = 1.1.79 =
199
+ * Christmas campaign
200
+
201
+ = 1.1.78 =
202
+ * Previous update bug fix
203
+
204
+ = 1.1.77 =
205
+ * Minor bug fixes and improvements
206
+ * Deactivation survey
207
+
208
+ = 1.1.76 =
209
+ * End Black Friday campaign
210
+
211
+ = 1.1.75 =
212
+ * Black Friday campaign
213
+
214
+ = 1.1.74 =
215
+ * Bug fixes & improvements
216
+
217
+ = 1.1.73 =
218
+ * Scheduling option added to free version
219
+ * Other bug fixes & improvements
220
+
221
+ = 1.1.72 =
222
+ * Discount notice removed
223
+
224
+ = 1.1.71 =
225
+ * Bug fixes & improvements
226
+
227
+ = 1.1.70 =
228
+ * Now user will see alert about not saved settings.
229
+ * Other bug fixes & improvements
230
+
231
+ = 1.1.69 =
232
+ * Issue with migration error notice solved
233
+
234
+ = 1.1.68 =
235
+ * Pro markers removed from plugin
236
+
237
+ = 1.1.67 =
238
+ * Bug fixes and improvements
239
+
240
+ = 1.1.66 =
241
+ * Minor bug fixes and improvements
242
+
243
+ = 1.1.65 =
244
+ * Now you can upload your backups to Dropbox with free version.
245
+
246
+ = 1.1.64 =
247
+ * Symlink folder backup issue fixed
248
+ * Other bug fixes & improvements
249
+
250
+ = 1.1.63 =
251
+ * Support link has been updated
252
+
253
+ = 1.1.62 =
254
+ * Minor bug fixes and improvements
255
+
256
+ = 1.1.61 =
257
+ * New exclude paths were added
258
+ * Minor bug fixes and improvements
259
+
260
+ = 1.1.60 =
261
+ * Minor bug fixes and improvements
262
+
263
+ = 1.1.59 =
264
+ * External restore detection improved
265
+ * Minor bug fixes and improvements
266
+
267
+ = 1.1.58 =
268
+ * Restore related bug was resolved
269
+ * Minor bug fixes and improvements
270
+
271
+ = 1.1.57 =
272
+ * UI improvements
273
+ * BackupGuard seal widget added
274
+
275
+ = 1.1.56 =
276
+ * BackupGuard UI improvements
277
+ * Minor bug fixes and improvements
278
+
279
+ = 1.1.55 =
280
+ * cURL & Stream supported for external restoration
281
+ * Conflicts were resolved with update checker
282
+ * New option to show/hide statistics
283
+ * Database restoration related bug resolved
284
+
285
+ = 1.1.54 =
286
+ * New option added to specify reload method
287
+
288
+ = 1.1.53 =
289
+ * WordPress dashboard widget added
290
+ * BackupGuard GUI improvements
291
+ * Other security & core improvements
292
+
293
+ = 1.1.52 =
294
+ * Selective restoration is supported for files or database
295
+ * Selective database tables backup is supported now
296
+ * External restoration improved
297
+ * Other UI improvements and fixes
298
+
299
+ = 1.1.51 =
300
+ * New option added in the settings to specify number of rows dumped at once
301
+
302
+ = 1.1.50 =
303
+ * Database Restore with reloads
304
+ * New option for excluding database tables
305
+ * Backup log was improved
306
+ * Other bug fixes & improvements
307
+
308
+ = 1.1.49 =
309
+ * External restoration related bugs resolved
310
+ * “wp-content” directory detection related bug resolved
311
+
312
+ = 1.1.48 =
313
+ * cURL & Sockets are supported for reloads
314
+ * Chunk by chunk import is supported
315
+ * New migration service is available now
316
+ * Alert about php migration
317
+
318
+ = 1.1.47 =
319
+ * XSS security issues were resolved
320
+ * Protocol detection related issues were resolved
321
+ * UI improvements
322
+
323
+ = 1.1.46 =
324
+ * Disk free space related issue resolved
325
+ * Archive size is being written in the backup/restore log files
326
+ * Tracking reloads and writing a respective log in case method is being changed
327
+ * Other minor improvements
328
+
329
+ = 1.1.45 =
330
+ * Disk free space detection detection related bug was resolved
331
+
332
+ = 1.1.44 =
333
+ * UI related bug fixes and improvements
334
+
335
+ = 1.1.43 =
336
+ * Bug fixes and improvements
337
+
338
+ = 1.1.42 =
339
+ * Restoration was improved to override the files which were successfully extracted
340
+ * The issue related to the root directory was resolved
341
+
342
+ = 1.1.41 =
343
+ * Custom exclude paths are supported
344
+ * The bug related to warning indicator was resolved
345
+ * Other improvements & fixes
346
+
347
+ = 1.1.40 =
348
+ * The blank page issue was resolved
349
+ * Other optimizations and improvements
350
+
351
+ = 1.1.39 =
352
+ * Uninstall related bug was resolved
353
+ * Upload path related bug was resolved
354
+ * Authentication related issues were resolved
355
+ * New exclude paths were added
356
+
357
+ = 1.1.38 =
358
+ * Security bug fixes
359
+ * Proper PHP version validation
360
+ * Fixed bug that reseted db after every update
361
+ * Removed restore method from backup log
362
+
363
+ = 1.1.37 =
364
+ * Database related bug was resolved for full backups
365
+ * New backup exclude paths were added
366
+
367
+ = 1.1.36 =
368
+ * Minor bug fixes and improvements
369
+
370
+ = 1.1.35 =
371
+ * Memory usage improved & optimized for restoration
372
+
373
+ = 1.1.34 =
374
+ * Memory usage improved & optimized for backup
375
+ * Database restoration improved
376
+
377
+ = 1.1.33 =
378
+ * Restore bug was resolved
379
+ * Other security fixes and optimizations
380
+
381
+ = 1.1.32 =
382
+ * External restore bug was resolved
383
+ * Infinite redirect bug was resolved
384
+ * The bug related to database backup with reloads was resolved
385
+
386
+ = 1.1.30 =
387
+ * Secure and reliable backup restoration
388
+ * Charset and collate migration
389
+ * LightSpeed web server support
390
+ * Active user won’t be dropped after restoration
391
+ * Plugin update logic was improved
392
+ * Other security fixes and optimizations
393
+
394
+ = 1.1.29 =
395
+ * Minor bug fixes
396
+ * UX improvements
397
+
398
+ = 1.1.28 =
399
+ * Database backup with reloads is supported
400
+ * Core improvements
401
+
402
+ = 1.1.27 =
403
+ * Backup restoration with reloads is supported
404
+ * Core improvements
405
+
406
+ = 1.1.26 =
407
+ * Backup reload logic has been updated
408
+
409
+ = 1.1.25 =
410
+ * Restore log was improved
411
+
412
+ = 1.1.24 =
413
+ * The bug related to restoration was resolved
414
+
415
+ = 1.1.23 =
416
+ * Bug fixes and improvements
417
+
418
+ = 1.1.22 =
419
+ * Backup migration logic was updated
420
+
421
+ = 1.1.21 =
422
+ * Archive related bugs were resolved
423
+
424
+ = 1.1.20 =
425
+ * New backup archive & backward capability support were implemented
426
+
427
+ = 1.1.19 =
428
+ * Security issues and some minor bugs were resolved
429
+
430
+ = 1.1.18 =
431
+ * Advanced migration as a Premium feature was implemented
432
+ * UI & UX improvements
433
+
434
+ = 1.1.17 =
435
+ * Execution timeout message was updated
436
+
437
+ = 1.1.16 =
438
+ * Migration logic improved & optimized
439
+ * Core/code improvements and cleanups
440
+
441
+ = 1.1.15 =
442
+ * Discount notice was added
443
+
444
+ = 1.1.14 =
445
+ * Code/core cleanup
446
+ * Other fixes & improvements
447
+
448
+ = 1.1.13 =
449
+ * Check added if backup reloads are possible
450
+ * Code/core cleanup
451
+ * Other fixes & improvements
452
+
453
+ = 1.1.12 =
454
+ * Setting/Option was add to control backup reloads
455
+
456
+ = 1.1.11 =
457
+ * Update related bugs were resolved
458
+
459
+ = 1.1.10 =
460
+ * Backup reloading logic was improved
461
+
462
+ = 1.1.9 =
463
+ * Backup reloading mechanism was implemented
464
+
465
+ = 1.1.8 =
466
+ * Conflicts with BBpress were resolved
467
+
468
+ = 1.1.7 =
469
+ * File read and write checks added
470
+
471
+ = 1.1.6 =
472
+ * Backup update related bug was resolved
473
+
474
+ = 1.1.5 =
475
+ * Code cleanup
476
+ * Backup and migration logic improvements
477
+
478
+ = 1.1.4 =
479
+ * Anonymous backup usage reporting was removed
480
+
481
+ = 1.1.3 =
482
+ * Backup core logic improvements
483
+
484
+ = 1.1.2 =
485
+ * The bug related to table names in the log file was resolved
486
+ * Database backup related bugs were resolved
487
+
488
+ = 1.1.0 =
489
+ * Migration related bug fixes
490
+
491
+ = 1.0.9 =
492
+ * Migration feature was implemented
493
+ * Backup download issue was resolved for IE
494
+
495
+ = 1.0.8 =
496
+ * The bug related calculating backup entires was resolved
497
+ * Backup status related bug was fixed
498
+ * UI related improvements
499
+
500
+ = 1.0.7 =
501
+ * Customized backups were improved
502
+ * Security bug resolved
503
+
504
+ = 1.0.6 =
505
+ * Bug fixes & other improvements
506
+
507
+ = 1.0.5 =
508
+ * Security issues were resolved
509
+ * Schema related bug was resolved
510
+
511
+ = 1.0.4 =
512
+ * Auto reloading mechanism was removed
513
+ * Backup logic was optimized
514
+
515
+ = 1.0.3 =
516
+ * Anonymous backup stats reporting
517
+ * Other fixes & improvements
518
+
519
+ = 1.0.2 =
520
+ * Symlinks related bug was resolved
521
+ * Other improvements
522
+
523
+ = 1.0.1 =
524
+ * UI improvements
525
+ * Minor backup related bug fixes
526
+
527
+ = 1.0 =
528
+ * Initial backup plugin was commit
backup.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Plugin Name: Backup
5
+ * Plugin URI: https://backup-guard.com/products/backup-wordpress
6
+ * Description: Backup Guard is the most complete site backup and restore plugin. We offer the easiest way to backup, restore or migrate your site. You can backup your files, database or both.
7
+ * Version: 1.1.90
8
+ * Author: BackupGuard
9
+ * Author URI: https://backup-guard.com/products/backup-wordpress
10
+ * License: GPL-2.0+
11
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
12
+ */
13
+
14
+ if (function_exists('activate_backup_guard')) {
15
+ die('Please deactivate any other BackupGuard version before activating this one.');
16
+ }
17
+
18
+ if (!defined('SG_BACKUP_GUARD_VERSION')) {
19
+ define('SG_BACKUP_GUARD_VERSION', '1.1.90');
20
+ }
21
+
22
+ if (!defined('SG_BACKUP_GUARD_MAIN_FILE')) {
23
+ define('SG_BACKUP_GUARD_MAIN_FILE', __FILE__);
24
+ }
25
+
26
+ if (!defined('SG_FORCE_DB_TABLES_RESET')) {
27
+ define('SG_FORCE_DB_TABLES_RESET', false);
28
+ }
29
+
30
+ //if this file is called directly, abort.
31
+ if (!defined('WPINC')) {
32
+ die;
33
+ }
34
+
35
+ require_once(plugin_dir_path(__FILE__).'public/boot.php');
36
+ require_once(plugin_dir_path(__FILE__).'BackupGuard.php');
com/.htaccess ADDED
@@ -0,0 +1 @@
 
1
+ deny from all
com/boot.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/config/config.wordpress.free.php');
3
+ require_once(dirname(__FILE__).'/config/config.wordpress.php');
4
+ require_once(SG_CORE_PATH.'SGBoot.php');
5
+
6
+ SGBoot::init();
com/config/config.php ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //Version
3
+ define('SG_ARCHIVE_VERSION', '5');
4
+
5
+ //Paths
6
+ define('SG_APP_PATH', realpath(dirname(__FILE__).'/../').'/');
7
+ define('SG_CONFIG_PATH', SG_APP_PATH.'config/');
8
+ define('SG_CORE_PATH', SG_APP_PATH.'core/');
9
+ define('SG_DATABASE_PATH', SG_CORE_PATH.'database/');
10
+ define('SG_LOG_PATH', SG_CORE_PATH.'log/');
11
+ define('SG_STORAGE_PATH', SG_CORE_PATH.'storage/');
12
+ define('SG_EXCEPTION_PATH', SG_CORE_PATH.'exception/');
13
+ define('SG_BACKUP_PATH', SG_CORE_PATH.'backup/');
14
+ define('SG_RESTORE_PATH', SG_CORE_PATH.'restore/');
15
+ define('SG_LIB_PATH', SG_APP_PATH.'lib/');
16
+ define('SG_MAIL_PATH', SG_CORE_PATH.'mail/');
17
+ define('SG_NOTICE_PATH', SG_CORE_PATH.'notice/');
18
+ define('SG_SCHEDULE_PATH', SG_CORE_PATH.'schedule/');
19
+ define('SG_WIDGET_PATH', SG_CORE_PATH.'widget/');
20
+ define('SG_EXTENSION_PATH', SG_CORE_PATH.'extension/');
21
+
22
+ define('SG_REQUEST_PATH', SG_LIB_PATH.'Request/');
23
+
24
+ // Seal themes
25
+ define('SG_SEAL_THEME_DARK', "dark");
26
+ define('SG_SEAL_THEME_GREEN', "green");
27
+ define('SG_SEAL_THEME_WHITE', "white");
28
+
29
+ // Free days in seconds
30
+ define('SG_PLUGIN_ACTIVE_INTERVAL', 259200);
31
+
32
+ //Log
33
+ define('SG_LOG_LEVEL_ALL', 0);
34
+ define('SG_LOG_LEVEL_HIGH', 1);
35
+ define('SG_LOG_LEVEL_MEDIUM', 2);
36
+ define('SG_LOG_LEVEL_LOW', 4);
37
+ define('SG_BACKUP_LOG_POS_START', 1);
38
+ define('SG_BACKUP_LOG_POS_END', 2);
39
+
40
+ //Notice
41
+ define('SG_NOTICE_SUCCESS', 'success');
42
+ define('SG_NOTICE_WARNING', 'warning');
43
+ define('SG_NOTICE_ERROR', 'error');
44
+
45
+ //Reload methods
46
+ define('SG_RELOAD_METHOD_NONE', 'none');
47
+ define('SG_RELOAD_METHOD_STREAM', 1);
48
+ define('SG_RELOAD_METHOD_CURL', 2);
49
+ define('SG_RELOAD_METHOD_SOCKET', 3);
50
+ define('SG_RELOAD_METHOD_AJAX', 4);
51
+
52
+ define('SG_SHCEDULE_STATUS_INACTIVE', 0);
53
+ define('SG_SHCEDULE_STATUS_PENDING', 1);
54
+
55
+ //Number of backups to keep on server by default
56
+ define('SG_NUMBER_OF_BACKUPS_TO_KEEP', 100);
57
+
58
+ //Backup timeout in seconds
59
+ define('SG_BACKUP_TIMEOUT', 180);
60
+ define('SG_RELOAD_TIMEOUT', 10);
61
+
62
+ //Ping data update frequency
63
+ define('SG_PING_DATE_UPDATE_FREQUENCY', 3);
64
+
65
+ //Backup file extension
66
+ define('SGBP_EXT', 'sgbp');
67
+
68
+ define('SG_NOTICE_EXECUTION_TIMEOUT', 'timeout_error');
69
+ define('SG_NOTICE_MIGRATION_ERROR', 'migration_error');
70
+ define('SG_NOTICE_NOT_WRITABLE_ERROR', 'restore_notwritable_error');
71
+
72
+ define('SG_WORDPRESS_CORE_TABLE', SG_ENV_DB_PREFIX.'options');
73
+ define('SG_MAGENTO_CORE_TABLE', SG_ENV_DB_PREFIX.'core_config_data');
74
+
75
+ //Backup file default prefix
76
+ define('SG_BACKUP_FILE_NAME_DEFAULT_PREFIX', 'sg_backup_');
77
+
78
+ //Default folder name for storage upload
79
+ define('SG_BACKUP_DEFAULT_FOLDER_NAME', 'sg_backups');
80
+
81
+ //Schedule action name prefix
82
+ define('SG_SCHEDULE_ACTION', 'backup_guard_schedule_action');
83
+
84
+ define('SG_SCHEDULER_DEFAULT_ID', 1);
85
+
86
+ //one day in seconds
87
+ define('SG_ONE_DAY_IN_SECONDS', 24*60*60);
88
+
89
+ define('SG_ENTRY_TYPE_FILE', 1);
90
+ define('SG_ENTRY_TYPE_CDR', 2);
91
+
92
+ define('SG_STATE_ACTION_PREPARING_STATE_FILE', 1);
93
+ define('SG_STATE_ACTION_LISTING_FILES', 2);
94
+ define('SG_STATE_ACTION_COMPRESSING_FILES', 3);
95
+ define('SG_STATE_ACTION_PREPARING_UPLOAD', 4);
96
+ define('SG_STATE_ACTION_UPLOADING_BACKUP', 5);
97
+ define('SG_STATE_ACTION_RESTORING_FILES', 6);
98
+ define('SG_STATE_ACTION_EXPORTING_SQL', 7);
99
+ define('SG_STATE_ACTION_RESTORING_DATABASE', 8);
100
+ define('SG_STATE_ACTION_MIGRATING_DATABASE', 9);
101
+
102
+ define('SG_STATE_TYPE_FILE', 1);
103
+ define('SG_STATE_TYPE_DB', 2);
104
+ define('SG_STATE_TYPE_UPLOAD', 3);
105
+ define('SG_STATE_TYPE_MIGRATE', 4);
106
+
107
+ define('SG_TREE_FILE_NAME', 'tree.json');
108
+ define('SG_STATE_FILE_NAME', 'state.json');
109
+
110
+ define('SG_RELOADER_STATE_FILE_NAME', 'reloaderState.json');
111
+
112
+ //File name to keep upload report for email notification
113
+ define('SG_REPORT_FILE_NAME', 'report.txt');
114
+
115
+ //2GB in bytes
116
+ define('SG_ARCHIVE_MAX_SIZE_32', 2000000000);
117
+
118
+ // Backup methods
119
+ define('SG_BACKUP_METHOD_MIGRATE', 1);
120
+ define('SG_BACKUP_METHOD_STANDARD', 2);
121
+
122
+ define('SG_MIN_SUPPORTED_ARCHIVE_VERSION', 5);
123
+ define('SG_MAX_SUPPORTED_ARCHIVE_VERSION', 5);
124
+
125
+ //Reloader status
126
+ define('SG_RELOADER_STATUS_IDLE', 1);
127
+ define('SG_RELOADER_STATUS_RUNNING', 2);
128
+
129
+ //External restore
130
+ define('SG_EXTERNAL_RESTORE_FILE', 'bg_restore.php');
131
+
132
+ //License
133
+ define('SG_LICENSE_CHECK_TIMEOUT', 86400); //1 day
134
+
135
+ //Mail
136
+ define('SG_MAIL_BACKUP_SUCCESS_SUBJECT', 'Backup Succeeded');
137
+ define('SG_MAIL_BACKUP_COMPLETED_WITH_WARNINGS_SUBJECT', 'Backup completed with warnings');
138
+ define('SG_MAIL_BACKUP_FAIL_SUBJECT', 'Backup Failed');
139
+ define('SG_MAIL_BACKUP_CANCELED_SUBJECT', 'Backup Canceled');
140
+ define('SG_MAIL_RESTORE_SUCCESS_SUBJECT', 'Restore Succeeded');
141
+ define('SG_MAIL_RESTORE_FAIL_SUBJECT', 'Restore Failed');
142
+
143
+ define('SG_MAIL_UPLOAD_FAIL_SUBJECT', 'Upload Failed');
144
+ define('SG_MAIL_UPLOAD_SUCCESS_SUBJECT', 'Upload Succeeded');
145
+
146
+ //BackupGurad
147
+ define('SG_ACTION_STATUS_CREATED', 0);
148
+ define('SG_ACTION_STATUS_IN_PROGRESS_DB', 1);
149
+ define('SG_ACTION_STATUS_IN_PROGRESS_FILES', 2);
150
+ define('SG_ACTION_STATUS_FINISHED', 3);
151
+ define('SG_ACTION_STATUS_FINISHED_WARNINGS', 4);
152
+ define('SG_ACTION_STATUS_CANCELLING', 5);
153
+ define('SG_ACTION_STATUS_CANCELLED', 6);
154
+ define('SG_ACTION_STATUS_ERROR', 7);
155
+ define('SG_ACTION_TYPE_BACKUP', 1);
156
+ define('SG_ACTION_TYPE_RESTORE', 2);
157
+ define('SG_ACTION_TYPE_UPLOAD', 3);
158
+ define('SG_ACTION_PROGRESS_UPDATE_INTERVAL', 3); //in %
159
+ define('SG_BACKUP_DATABASE_INSERT_LIMIT', 10000);
160
+ define('SG_BACKUP_DOWNLOAD_TYPE_SGBP', 1);
161
+ define('SG_BACKUP_DOWNLOAD_TYPE_BACKUP_LOG', 2);
162
+ define('SG_BACKUP_DOWNLOAD_TYPE_RESTORE_LOG', 3);
163
+
164
+ //The following constants can be modified at run-time
165
+ define('SG_ACTION_BACKUP_FILES_AVAILABLE', 1);
166
+ define('SG_ACTION_BACKUP_DATABASE_AVAILABLE', 1);
167
+ define('SG_BACKUP_IN_BACKGROUND_MODE', 0);
168
+ define('SG_BACKUP_UPLOAD_TO_STORAGES', ''); //list of storage ids separated by commas
169
+
170
+ //Database tables
171
+ define('SG_ACTION_TABLE_NAME', SG_ENV_DB_PREFIX.'sg_action');
172
+ define('SG_CONFIG_TABLE_NAME', SG_ENV_DB_PREFIX.'sg_config');
173
+ define('SG_SCHEDULE_TABLE_NAME', SG_ENV_DB_PREFIX.'sg_schedule');
174
+
175
+ define('SG_SSH_KEY_FILE_FOLDER_NAME', 'sshKeyFolder/');
176
+
177
+ define('SG_MIGRATION_SERVICE_URL', 'https://backup-guard.com/services/migrate-wordpress');
178
+ define('BACKUP_GUARD_PRIVACY_POLICY_URL', "https://backup-guard.com/privacy");
179
+ define('BACKUP_GUARD_TERMS_OF_SERVICE_URL', 'https://backup-guard.com/terms');
180
+
181
+ define('SG_RESTORE_MODE_FULL', 'full');
182
+ define('SG_RESTORE_MODE_FILES', 'files');
183
+ define('SG_RESTORE_MODE_DB', 'db');
184
+
185
+ define('SG_BADGE_SILVER_PLUS_TEXT', "Silver +");
186
+ define('SG_BADGE_GOLD_PLUS_TEXT', "Gold +");
187
+ define('SG_BADGE_PLATINUM_TEXT', "Platinum");
188
+
189
+ define('SG_SILVER_TOOLTIP_TEXT', "This is a pro feature and it’s available starting from the Silver version!");
190
+ define('SG_GOLD_TOOLTIP_TEXT', "This is a pro feature and it’s available starting from the Gold version!");
191
+ define('SG_PLATINUM_TOOLTIP_TEXT', "This is a pro feature and it’s available only in Platinum version!");
192
+
193
+ define('BACKUP_GUARD_CAPABILITIES_FREE', 1);
194
+ define('BACKUP_GUARD_CAPABILITIES_SILVER', 2);
195
+ define('BACKUP_GUARD_CAPABILITIES_GOLD', 3);
196
+ define('BACKUP_GUARD_CAPABILITIES_PLATINUM', 4);
197
+
198
+ define('BG_SCHEDULE_INTERVAL_HOURLY', 0);
199
+ define('BG_SCHEDULE_INTERVAL_DAILY', 1);
200
+ define('BG_SCHEDULE_INTERVAL_WEEKLY', 2);
201
+ define('BG_SCHEDULE_INTERVAL_MONTHLY', 3);
202
+ define('BG_SCHEDULE_INTERVAL_YEARLY', 4);
203
+
204
+ define("BACKUP_GUARD_TEXTDOMAIN", "backup-guard-pro");
com/config/config.wordpress.free.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ define('SG_FEATURE_DOWNLOAD_FROM_CLOUD', 0);
4
+ define('SG_FEATURE_STORAGE', 1);
5
+ define('SG_FEATURE_FTP', 0);
6
+ define('SG_FEATURE_AMAZON', 0);
7
+ define('SG_FEATURE_DROPBOX', 1);
8
+ define('SG_FEATURE_GOOGLE_DRIVE', 0);
9
+ define('SG_FEATURE_ONE_DRIVE', 0);
10
+ define('SG_FEATURE_SCHEDULE', 1);
11
+ define('SG_FEATURE_DELETE_LOCAL_BACKUP_AFTER_UPLOAD', 0);
12
+ define('SG_FEATURE_ALERT_BEFORE_UPDATE', 0);
13
+ define('SG_FEATURE_NUMBER_OF_BACKUPS_TO_KEEP', 0);
14
+ define('SG_FEATURE_CUSTOM_BACKUP_NAME', 0);
15
+ define('SG_FEATURE_SUBDIRECTORIES', 0);
16
+ define('SG_FEATURE_BACKGROUND_MODE', 0);
17
+ define('SG_FEATURE_NOTIFICATIONS', 0);
18
+ define('SG_FEATURE_MULTI_SCHEDULE', 0);
19
+ define('SG_FEATURE_SHOW_UPGRADE_PAGE', 1);
20
+ define('SG_FEATURE_BACKUP_WITH_MIGRATION', 0);
21
+ define('SG_FEATURE_NUMBER_OF_ROWS_TO_BACKUP', 1);
22
+ define('SG_FEATURE_BACKUP_DELETION_WILL_ALSO_DELETE_FROM_CLOUD', 0);
23
+ define('SG_FEATURE_SLECTIVE_RESTORE', 0);
24
+ define('SG_FEATURE_HIDE_ADS', 0);
25
+
26
+ //Storage
27
+ define('SG_STORAGE_FTP', 1);
28
+ define('SG_STORAGE_DROPBOX', 2);
29
+ define('SG_STORAGE_GOOGLE_DRIVE', 3);
30
+ define('SG_STORAGE_AMAZON', 4);
31
+ define('SG_STORAGE_ONE_DRIVE', 5);
32
+
33
+ define('SG_STORAGE_DROPBOX_KEY', 'n3yhajm64h88m9t');
34
+ define('SG_STORAGE_DROPBOX_SECRET', 's8crjkls7f9wqtd');
35
+ define('SG_STORAGE_DROPBOX_CLIENT_ID', 'backup-guard');
36
+ define('SG_STORAGE_DROPBOX_REDIRECT_URI', 'https://backup-guard.com/dropbox/');
37
+
38
+ define('SG_PRODUCT_IDENTIFIER', 'backup-guard-wp-free');
39
+
40
+ //BackupGuard Support URL
41
+ define('SG_BACKUP_SUPPORT_URL', 'https://backup-guard.com/products/backup-wordpress/support-free');
42
+ define('BG_UPGRADE_URL', 'https://backup-guard.com/products/backup-wordpress#pricing');
com/config/config.wordpress.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ global $wp_version, $wpdb;
4
+ define('SG_ENV_WORDPRESS', 'Wordpress');
5
+ define('SG_ENV_MAGENTO', 'Magento');
6
+ define('SG_ENV_VERSION', $wp_version);
7
+ define('SG_ENV_ADAPTER', SG_ENV_WORDPRESS);
8
+ define('SG_ENV_DB_PREFIX', $wpdb->prefix);
9
+
10
+ require_once(dirname(__FILE__).'/config.php');
11
+
12
+ define('SG_ENV_CORE_TABLE', SG_WORDPRESS_CORE_TABLE);
13
+ //Database
14
+ define('SG_DB_ADAPTER', SG_ENV_ADAPTER);
15
+ define('SG_DB_NAME', $wpdb->dbname);
16
+ define('SG_BACKUP_DATABASE_EXCLUDE', SG_ACTION_TABLE_NAME.','.SG_CONFIG_TABLE_NAME.','.SG_SCHEDULE_TABLE_NAME);
17
+
18
+ //Mail
19
+ define('SG_MAIL_TEMPLATES_PATH', realpath(SG_APP_PATH.'../public/templates').'/');
20
+ define('SG_MAIL_BACKUP_TEMPLATE', 'mail_backup.php');
21
+ define('SG_MAIL_RESTORE_TEMPLATE', 'mail_restore.php');
22
+ define('SG_MAIL_UPLOAD_TEMPLATE', 'mail_upload.php');
23
+
24
+ //Notice
25
+ define('SG_NOTICE_TEMPLATES_PATH', realpath(SG_APP_PATH.'../public/templates/notices').'/');
26
+
27
+ //BackupGuard SDK
28
+ define('SG_BACKUPGUARD_CLIENT_ID', 'wordpress');
29
+ define('SG_BACKUPGUARD_CLIENT_SECRET', 'AAPQEgsyQrt6wqDBk7fpa24NP6W43evtayxXmUqS');
30
+
31
+ //Backup
32
+ $wpContent = basename(WP_CONTENT_DIR);
33
+ $wpPlugins = basename(WP_PLUGIN_DIR);
34
+ $wpThemes = basename(get_theme_root());
35
+
36
+ $upload_dir = wp_upload_dir();
37
+ $wpUploads = basename($upload_dir['basedir']);
38
+
39
+ $dbCharset = 'utf8';
40
+ if (@constant("DB_CHARSET")) {
41
+ $dbCharset = DB_CHARSET;
42
+ }
43
+
44
+ //Define same constants in magento config file
45
+ define('SG_UPLOAD_PATH', $upload_dir['basedir']);
46
+ define('SG_UPLOAD_URL', $upload_dir['baseurl']);
47
+ define('SG_SITE_URL', get_site_url());
48
+ define('SG_HOME_URL', get_home_url());
49
+ define('SG_DB_CHARSET', $dbCharset);
50
+ define('SG_MYSQL_VERSION', $wpdb->db_version());
51
+
52
+ $type = "standard";
53
+
54
+ if (is_multisite()) {
55
+ $type = "multisite";
56
+ }
57
+
58
+ define('SG_SITE_TYPE', $type);
59
+
60
+ define('SG_PING_FILE_PATH', $upload_dir['basedir'].'/backup-guard/ping.json');
61
+
62
+ //Symlink download
63
+ define('SG_SYMLINK_PATH', $upload_dir['basedir'].'/sg_symlinks/');
64
+ define('SG_SYMLINK_URL', $upload_dir['baseurl'].'/sg_symlinks/');
65
+
66
+ define('SG_APP_ROOT_DIRECTORY', realpath(dirname(WP_CONTENT_DIR)."/")); //Wordpress Define
67
+
68
+ $sgBackupFilePathsExclude = array(
69
+ $wpContent.'/'.$wpPlugins.'/backup/',
70
+ $wpContent.'/'.$wpPlugins.'/backup-guard-pro/',
71
+ $wpContent.'/'.$wpPlugins.'/backup-guard-silver/',
72
+ $wpContent.'/'.$wpPlugins.'/backup-guard-gold/',
73
+ $wpContent.'/'.$wpPlugins.'/backup-guard-platinum/',
74
+ $wpContent.'/'.$wpUploads.'/backup-guard/',
75
+ $wpContent.'/'.$wpUploads.'/sg_symlinks/',
76
+ $wpContent.'/ai1wm-backups/',
77
+ $wpContent.'/aiowps_backups/',
78
+ $wpContent.'/Dropbox_Backup/',
79
+ $wpContent.'/updraft/',
80
+ $wpContent.'/upsupsystic/',
81
+ $wpContent.'/wpbackitup_backups/',
82
+ $wpContent.'/wpbackitup_restore/',
83
+ $wpContent.'/backups/',
84
+ $wpContent.'/cache/',
85
+ $wpContent.'/'.$wpUploads.'/wp-clone/',
86
+ $wpContent.'/'.$wpUploads.'/wp-staging/',
87
+ $wpContent.'/'.$wpUploads.'/wp-migrate-db/',
88
+ $wpContent.'/'.$wpUploads.'/db-backup/',
89
+ $wpContent.'/'.$wpPlugins.'/wordpress-move/backup/',
90
+ $wpContent.'/as3b_backups/',
91
+ $wpContent.'/'.$wpUploads.'/backupbuddy_backups/',
92
+ $wpContent.'/backups-dup-pro/',
93
+ $wpContent.'/managewp/backups/',
94
+ $wpContent.'/'.$wpUploads.'/backupbuddy_temp/',
95
+ $wpContent.'/'.$wpUploads.'/pb_backupbuddy/',
96
+ $wpContent.'/'.$wpUploads.'/snapshots/',
97
+ $wpContent.'/debug.log',
98
+ $wpContent.'/backup-db/'
99
+ );
100
+
101
+ define('SG_BACKUP_FILE_PATHS_EXCLUDE', implode(',', $sgBackupFilePathsExclude));
102
+ define('SG_BACKUP_DIRECTORY', $upload_dir['basedir'].'/backup-guard/'); //backups will be stored here
103
+ define('SG_BACKUP_DIRECTORY_URL', SG_UPLOAD_URL.'/backup-guard/');
104
+
105
+ //Storage
106
+ define('SG_STORAGE_UPLOAD_CRON', '');
107
+
108
+ define('SG_BACKUP_FILE_PATHS', $wpContent.','.$wpContent.'/'.$wpPlugins.','.$wpContent.'/'.$wpThemes.','.$wpContent.'/'.$wpUploads);
109
+
110
+ define('SG_WP_OPTIONS_MIGRATABLE_VALUES', 'user_roles');
111
+ define('SG_WP_USERMETA_MIGRATABLE_VALUES', 'capabilities,user_level,dashboard_quick_press_last_post_id,user-settings,user-settings-time');
112
+ define('SG_MISC_MIGRATABLE_TABLES', SG_ENV_DB_PREFIX.'options,'.SG_ENV_DB_PREFIX.'usermeta');
113
+ define('SG_MULTISITE_TABLES_TO_MIGRATE', SG_ENV_DB_PREFIX.'blogs,'.SG_ENV_DB_PREFIX.'site');
114
+ define('SG_SUBDOMAIN_INSTALL', defined('SUBDOMAIN_INSTALL')?SUBDOMAIN_INSTALL:false);
115
+
116
+
117
+ define('SG_BACKUP_PRODUCTS_URL', 'https://backup-guard.com/admin/products/view');
118
+
119
+ define('SG_BACKUP_GUARD_SECURITY_EXTENSION', 'backup-guard-security');
com/core/SGBoot.php ADDED
@@ -0,0 +1,284 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //check PHP version
3
+ if (version_compare(PHP_VERSION, '5.3.3', '<')) {
4
+ die('PHP >=5.3.3 version required.');
5
+ }
6
+
7
+ require_once(SG_EXCEPTION_PATH.'SGException.php');
8
+ require_once(SG_CORE_PATH.'functions.php');
9
+ @include_once(SG_CORE_PATH.'functions.silver.php');
10
+ @include_once(SG_CORE_PATH.'functions.gold.php');
11
+ @include_once(SG_CORE_PATH.'functions.platinum.php');
12
+ require_once(SG_CORE_PATH.'SGPing.php');
13
+ require_once(SG_DATABASE_PATH.'SGDatabase.php');
14
+ require_once(SG_CORE_PATH.'SGConfig.php');
15
+ require_once(SG_NOTICE_PATH.'SGNotice.php');
16
+ require_once(SG_NOTICE_PATH.'SGNoticeHandler.php');
17
+ @include_once(SG_BACKUP_PATH.'SGBackupSchedule.php');
18
+ @include_once(SG_EXTENSION_PATH.'SGExtension.php');
19
+
20
+ class SGBoot
21
+ {
22
+ public static $executionTimeLimit = 0;
23
+ public static $memoryLimit = 0;
24
+
25
+ public static function init()
26
+ {
27
+ //get current execution time limit
28
+ self::$executionTimeLimit = ini_get('max_execution_time');
29
+
30
+ //get current memory limit
31
+ self::$memoryLimit = ini_get('memory_limit');
32
+
33
+ //remove execution time limit
34
+ @set_time_limit(0);
35
+
36
+ //change initial memory limit
37
+ @ini_set('memory_limit', '512M');
38
+
39
+ //don't let server to abort scripts
40
+ @ignore_user_abort(true);
41
+
42
+ //load all config variables from database
43
+ SGConfig::getAll();
44
+
45
+ try {
46
+ //check minimum requirements
47
+ self::checkMinimumRequirements();
48
+
49
+ //prepare directory for backups
50
+ self::prepare();
51
+ }
52
+ catch (SGException $exception) {
53
+ die($exception);
54
+ }
55
+ }
56
+
57
+ public static function didInstallForFirstTime()
58
+ {
59
+ self::setPluginInstallUpdateDate();
60
+ }
61
+
62
+ public static function didUpdatePluginVersion()
63
+ {
64
+ self::setPluginInstallUpdateDate();
65
+ }
66
+
67
+ public static function setPluginInstallUpdateDate()
68
+ {
69
+ SGConfig::set('SG_PLUGIN_INSTALL_UPDATE_DATE', time());
70
+ }
71
+
72
+ private static function installConfigTable($sgdb)
73
+ {
74
+ //drop config table
75
+ $sgdb->query('DROP TABLE IF EXISTS `'.SG_CONFIG_TABLE_NAME.'`;');
76
+
77
+ //create config table
78
+ $res = $sgdb->query(
79
+ 'CREATE TABLE IF NOT EXISTS `'.SG_CONFIG_TABLE_NAME.'` (
80
+ `ckey` varchar(100) NOT NULL,
81
+ `cvalue` text NOT NULL,
82
+ PRIMARY KEY (`ckey`)
83
+ ) DEFAULT CHARSET=utf8;'
84
+ );
85
+ if ($res===false) {
86
+ return false;
87
+ }
88
+
89
+ //delete all content from config table (just in case if wasn't dropped)
90
+ $sgdb->query('DELETE FROM `'.SG_CONFIG_TABLE_NAME.'`;');
91
+
92
+ //populate config table
93
+ $res = $sgdb->query(
94
+ "INSERT INTO `".SG_CONFIG_TABLE_NAME."` VALUES
95
+ ('SG_BACKUP_GUARD_VERSION','".SG_BACKUP_GUARD_VERSION."'),
96
+ ('SG_BACKUP_WITH_RELOADINGS', '1'),
97
+ ('SG_BACKUP_SYNCHRONOUS_STORAGE_UPLOAD','1'),
98
+ ('SG_NOTIFICATIONS_ENABLED','0'),
99
+ ('SG_SHOW_STATISTICS_WIDGET','1'),
100
+ ('SG_NOTIFICATIONS_EMAIL_ADDRESS',''),
101
+ ('SG_STORAGE_BACKUPS_FOLDER_NAME','sg_backups');"
102
+ );
103
+ if ($res===false) {
104
+ return false;
105
+ }
106
+
107
+ return true;
108
+ }
109
+
110
+ private static function installScheduleTable($sgdb)
111
+ {
112
+ //drop schedule table
113
+ $sgdb->query('DROP TABLE IF EXISTS `'.SG_SCHEDULE_TABLE_NAME.'`;');
114
+
115
+ //create schedule table
116
+ $res = $sgdb->query(
117
+ 'CREATE TABLE IF NOT EXISTS `'.SG_SCHEDULE_TABLE_NAME.'` (
118
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
119
+ `label` varchar(255) NOT NULL,
120
+ `status` tinyint(3) unsigned NOT NULL,
121
+ `schedule_options` varchar(255) NOT NULL,
122
+ `backup_options` text NOT NULL,
123
+ PRIMARY KEY (`id`)
124
+ ) DEFAULT CHARSET=utf8;'
125
+ );
126
+ if ($res===false) {
127
+ return false;
128
+ }
129
+
130
+ return true;
131
+ }
132
+
133
+ private static function installActionTable($sgdb)
134
+ {
135
+ //drop action table
136
+ $sgdb->query('DROP TABLE IF EXISTS `'.SG_ACTION_TABLE_NAME.'`;');
137
+
138
+ //create action table
139
+ $res = $sgdb->query(
140
+ "CREATE TABLE IF NOT EXISTS `".SG_ACTION_TABLE_NAME."` (
141
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
142
+ `name` varchar(255) NOT NULL,
143
+ `type` tinyint(3) unsigned NOT NULL,
144
+ `subtype` tinyint(3) unsigned NOT NULL DEFAULT '0',
145
+ `status` tinyint(3) unsigned NOT NULL,
146
+ `progress` tinyint(3) unsigned NOT NULL DEFAULT '0',
147
+ `start_date` datetime NOT NULL,
148
+ `update_date` datetime DEFAULT NULL,
149
+ `options` text NOT NULL,
150
+ PRIMARY KEY (`id`)
151
+ ) DEFAULT CHARSET=utf8;"
152
+ );
153
+ if ($res===false) {
154
+ return false;
155
+ }
156
+
157
+ return true;
158
+ }
159
+
160
+ public static function install()
161
+ {
162
+ $sgdb = SGDatabase::getInstance();
163
+
164
+ try {
165
+ if (!self::installConfigTable($sgdb)) {
166
+ throw new SGExceptionDatabaseError('Could not install config table');
167
+ }
168
+
169
+ if (!self::installScheduleTable($sgdb)) {
170
+ throw new SGExceptionDatabaseError('Could not install schedule table');
171
+ }
172
+
173
+ if (!self::installActionTable($sgdb)) {
174
+ throw new SGExceptionDatabaseError('Could not install action table');
175
+ }
176
+ }
177
+ catch (SGException $exception) {
178
+ die($exception);
179
+ }
180
+ }
181
+
182
+ private static function cleanupSchedules()
183
+ {
184
+ $schedules = SGBackupSchedule::getAllSchedules();
185
+ foreach ($schedules as $schedule) {
186
+ SGBackupSchedule::remove($schedule['id']);
187
+ }
188
+ }
189
+
190
+ public static function uninstall($deleteBackups = false)
191
+ {
192
+ try {
193
+ @unlink(SG_PING_FILE_PATH);
194
+
195
+ if (self::isFeatureAvailable('SCHEDULE')) {
196
+ self::cleanupSchedules();
197
+ }
198
+
199
+ $sgdb = SGDatabase::getInstance();
200
+
201
+ //drop config table
202
+ $res = $sgdb->query('DROP TABLE IF EXISTS `'.SG_CONFIG_TABLE_NAME.'`;');
203
+ if ($res===false) {
204
+ throw new SGExceptionDatabaseError('Could not execute query');
205
+ }
206
+
207
+ //drop schedule table
208
+ $res = $sgdb->query('DROP TABLE IF EXISTS `'.SG_SCHEDULE_TABLE_NAME.'`;');
209
+ if ($res===false) {
210
+ throw new SGExceptionDatabaseError('Could not execute query');
211
+ }
212
+
213
+ //drop action table
214
+ $res = $sgdb->query('DROP TABLE IF EXISTS `'.SG_ACTION_TABLE_NAME.'`;');
215
+ if ($res===false) {
216
+ throw new SGExceptionDatabaseError('Could not execute query');
217
+ }
218
+
219
+ //delete directory of backups
220
+ if ($deleteBackups) {
221
+ $backupPath = SGConfig::get('SG_BACKUP_DIRECTORY');
222
+ backupGuardDeleteDirectory($backupPath);
223
+ }
224
+ }
225
+ catch (SGException $exception) {
226
+ die($exception);
227
+ }
228
+ }
229
+
230
+ public static function checkRequirement($requirement)
231
+ {
232
+ if ($requirement=='ftp' && !extension_loaded('ftp')) {
233
+ throw new SGExceptionNotFound('FTP extension is not loaded.');
234
+ }
235
+ else if ($requirement=='curl' && !function_exists('curl_version')) {
236
+ throw new SGExceptionNotFound('cURL extension is not loaded.');
237
+ }
238
+ else if ($requirement=='intSize' && PHP_INT_SIZE < 8) {
239
+ throw new SGExceptionIO("BackupGuard uses 64-bit integers, but it looks like we're running on a version of PHP that doesn't support 64-bit integers (PHP_INT_MAX=" . ((string) PHP_INT_MAX) . ")");
240
+ }
241
+ }
242
+
243
+ public static function isFeatureAvailable($feature)
244
+ {
245
+ return (SGConfig::get('SG_FEATURE_'.strtoupper($feature))===1?true:false);
246
+ }
247
+
248
+ private static function prepare()
249
+ {
250
+ $backupPath = SGConfig::get('SG_BACKUP_DIRECTORY');
251
+
252
+ //create directory for backups
253
+ if (!is_dir($backupPath)) {
254
+ if (!@mkdir($backupPath)) {
255
+ throw new SGExceptionMethodNotAllowed('Cannot create folder: '.$backupPath);
256
+ }
257
+
258
+ if (!@file_put_contents($backupPath.'.htaccess', 'deny from all')) {
259
+ throw new SGExceptionMethodNotAllowed('Cannot create htaccess file');
260
+ }
261
+
262
+ if (!@file_put_contents($backupPath.'index.php', "<?php\n// Silence is golden")) {
263
+ throw new SGExceptionMethodNotAllowed('Cannot create index file');
264
+ }
265
+ }
266
+
267
+ //check permissions of backups directory
268
+ if (!is_writable($backupPath)) {
269
+ throw new SGExceptionForbidden('Permission denied. Directory is not writable: '.$backupPath);
270
+ }
271
+
272
+ //prepare notices
273
+ $noticeHandler = new SGNoticeHandler();
274
+ $noticeHandler->run();
275
+ }
276
+
277
+ private static function checkMinimumRequirements()
278
+ {
279
+ //check ZLib library
280
+ if (!function_exists('gzdeflate')) {
281
+ throw new SGExceptionNotFound('ZLib extension is not loaded.');
282
+ }
283
+ }
284
+ }
com/core/SGConfig.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGConfig
4
+ {
5
+ private static $values = array();
6
+
7
+ public static function set($key, $value, $forced = true)
8
+ {
9
+ self::$values[$key] = $value;
10
+
11
+ if ($forced)
12
+ {
13
+ $sgdb = SGDatabase::getInstance();
14
+ $res = $sgdb->query('INSERT INTO '.SG_CONFIG_TABLE_NAME.' (ckey, cvalue) VALUES (%s, %s) ON DUPLICATE KEY UPDATE cvalue = %s', array($key, $value, $value));
15
+ return $res;
16
+ }
17
+
18
+ return true;
19
+ }
20
+
21
+ public static function get($key, $forced = false)
22
+ {
23
+ if (!$forced) {
24
+ if (isset(self::$values[$key])) {
25
+ return self::$values[$key];
26
+ }
27
+
28
+ if (defined($key)) {
29
+ return constant($key);
30
+ }
31
+ }
32
+
33
+ $sgdb = SGDatabase::getInstance();
34
+ $data = array();
35
+
36
+ $res = $sgdb->query("SHOW TABLES LIKE '".SG_CONFIG_TABLE_NAME."'");
37
+ if ($res) {
38
+ $data = $sgdb->query('SELECT cvalue, NOW() FROM '.SG_CONFIG_TABLE_NAME.' WHERE ckey = %s', array($key));
39
+ }
40
+
41
+ if (!count($data)) {
42
+ return null;
43
+ }
44
+
45
+ self::$values[$key] = $data[0]['cvalue'];
46
+ return $data[0]['cvalue'];
47
+ }
48
+
49
+ public static function getAll()
50
+ {
51
+ $sgdb = SGDatabase::getInstance();
52
+ $configs = array();
53
+
54
+ $res = $sgdb->query("SHOW TABLES LIKE '".SG_CONFIG_TABLE_NAME."'");
55
+ if ($res) {
56
+ $res = $sgdb->query('SELECT * FROM '.SG_CONFIG_TABLE_NAME);
57
+ if ($res) {
58
+ foreach ($res as $config) {
59
+ self::$values[$config['ckey']] = $config['cvalue'];
60
+ $configs[$config['ckey']] = $config['cvalue'];
61
+ }
62
+ }
63
+ }
64
+
65
+ return $configs;
66
+ }
67
+ }
com/core/SGPing.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGPing
4
+ {
5
+ public static $lastUpdateTs;
6
+
7
+ public static function shouldUpdate()
8
+ {
9
+ if ((int)time()-self::$lastUpdateTs < SG_PING_DATE_UPDATE_FREQUENCY) {
10
+ return false;
11
+ }
12
+
13
+ return true;
14
+ }
15
+
16
+ public static function ping()
17
+ {
18
+ $time = @file_get_contents(SG_PING_FILE_PATH);
19
+ $time = json_decode($time, true);
20
+
21
+ if (time()-$time['ts'] >= SG_BACKUP_TIMEOUT) {
22
+ return false;
23
+ }
24
+
25
+ return true;
26
+ }
27
+
28
+ public static function update()
29
+ {
30
+ if (self::shouldUpdate()) {
31
+ @file_put_contents(SG_PING_FILE_PATH, json_encode(array(
32
+ 'ts' => time()
33
+ )));
34
+ self::$lastUpdateTs = time();
35
+ }
36
+ }
37
+ }
com/core/backup/SGBackup.php ADDED
@@ -0,0 +1,1408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_BACKUP_PATH.'SGBackupLog.php');
3
+ require_once(SG_RESTORE_PATH.'SGExternalRestore.php');
4
+ require_once(SG_LIB_PATH.'SGState.php');
5
+ @include_once(SG_LIB_PATH.'SGBackgroundMode.php');
6
+ require_once(SG_BACKUP_PATH.'SGBackupFiles.php');
7
+ require_once(SG_BACKUP_PATH.'SGBackupDatabase.php');
8
+ @include_once(SG_BACKUP_PATH.'SGBackupStorage.php');
9
+ @include_once(SG_BACKUP_PATH.'SGBackupMailNotification.php');
10
+ require_once(SG_LOG_PATH.'SGFileLogHandler.php');
11
+ require_once(SG_LIB_PATH.'SGReloader.php');
12
+ require_once(SG_LIB_PATH.'SGCallback.php');
13
+
14
+ //close session for writing
15
+ @session_write_close();
16
+
17
+ class SGBackup implements SGIBackupDelegate
18
+ {
19
+ private $backupFiles = null;
20
+ private $backupDatabase = null;
21
+ private $actionId = null;
22
+ private $filesBackupAvailable = false;
23
+ private $databaseBackupAvailable = false;
24
+ private $actionStartTs = 0;
25
+ private $fileName = '';
26
+ private $filesBackupPath = '';
27
+ private $databaseBackupPath = '';
28
+ private $backupLogPath = '';
29
+ private $restoreLogPath = '';
30
+ private $backgroundMode = false;
31
+ private $pendingStorageUploads = array();
32
+ private $state = null;
33
+ private $token = '';
34
+ private $options = array();
35
+
36
+ public function __construct()
37
+ {
38
+ $this->backupFiles = new SGBackupFiles();
39
+ $this->backupFiles->setDelegate($this);
40
+
41
+ $this->backupDatabase = new SGBackupDatabase();
42
+ $this->backupDatabase->setDelegate($this);
43
+ }
44
+
45
+ public function getScheduleParamsById($id)
46
+ {
47
+ $sgdb = SGDatabase::getInstance();
48
+ $res = $sgdb->query('SELECT * FROM '.SG_SCHEDULE_TABLE_NAME.' WHERE id=%d', array($id));
49
+ if (empty($res)) {
50
+ return '';
51
+ }
52
+ return $res[0];
53
+ }
54
+
55
+ private function handleBackupExecutionTimeout()
56
+ {
57
+ $this->backupDatabase->setFilePath($this->databaseBackupPath);
58
+ $this->backupDatabase->cancel();
59
+
60
+ $this->backupFiles->setFilePath($this->filesBackupPath);
61
+ $this->backupFiles->cancel();
62
+
63
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS')) {
64
+ file_put_contents(dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME, 'Backup: failed', FILE_APPEND);
65
+ SGBackupMailNotification::sendBackupNotification(SG_ACTION_STATUS_ERROR, array(
66
+ 'flowFilePath' => dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME,
67
+ 'archiveName' => $this->fileName
68
+ ));
69
+ }
70
+ }
71
+
72
+ private function handleRestoreExecutionTimeout()
73
+ {
74
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS')) {
75
+ file_put_contents(dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME, 'Restore: failed', FILE_APPEND);
76
+ SGBackupMailNotification::sendRestoreNotification(false, array(
77
+ 'flowFilePath' => dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME,
78
+ 'archiveName' => $this->fileName
79
+ ));
80
+ }
81
+ }
82
+
83
+ private function handleUploadExecutionTimeout()
84
+ {
85
+ self::changeActionStatus($this->actionId, SG_ACTION_STATUS_FINISHED_WARNINGS);
86
+
87
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS')) {
88
+ file_put_contents(dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME, 'Upload: failed', FILE_APPEND);
89
+
90
+ SGBackupMailNotification::sendUploadNotification(false, array(
91
+ 'flowFilePath' => dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME,
92
+ 'archiveName' => $this->fileName
93
+ ));
94
+ }
95
+ }
96
+
97
+ public function handleExecutionTimeout($actionId)
98
+ {
99
+ $this->actionId = $actionId;
100
+ $action = self::getAction($actionId);
101
+ $this->fileName = $action['name'];
102
+ $actionType = $action['type'];
103
+ $backupPath = SG_BACKUP_DIRECTORY.$this->fileName;
104
+
105
+ $this->filesBackupPath = $backupPath.'/'.$this->fileName.'.sgbp';
106
+ $this->databaseBackupPath = $backupPath.'/'.$this->fileName.'.sql';
107
+
108
+ if ($actionType == SG_ACTION_TYPE_RESTORE) {
109
+ $this->handleRestoreExecutionTimeout();
110
+ $this->prepareRestoreLogFile($backupPath, true);
111
+ }
112
+ elseif ($actionType == SG_ACTION_TYPE_BACKUP) {
113
+ $this->handleBackupExecutionTimeout();
114
+ $this->prepareBackupLogFile($backupPath, true);
115
+ }
116
+ else{
117
+ $this->handleUploadExecutionTimeout();
118
+ $this->prepareBackupLogFile($backupPath, true);
119
+ }
120
+
121
+ //Stop all the running actions related to the specific backup, like backup, upload...
122
+ $allActions = self::getRunningActions();
123
+ foreach ($allActions as $action) {
124
+ self::changeActionStatus($action['id'], SG_ACTION_STATUS_ERROR);
125
+ }
126
+
127
+ $exception = new SGExceptionExecutionTimeError();
128
+ SGBackupLog::writeExceptionObject($exception);
129
+ SGConfig::set('SG_EXCEPTION_TIMEOUT_ERROR', '1', true);
130
+ }
131
+
132
+ public function listStorage($storage)
133
+ {
134
+ if (SGBoot::isFeatureAvailable('DOWNLOAD_FROM_CLOUD')) {
135
+ $listOfFiles = SGBackupStorage::getInstance()->listStorage($storage);
136
+ return $listOfFiles;
137
+ }
138
+
139
+ return array();
140
+ }
141
+
142
+ public function downloadBackupArchiveFromCloud($archive, $storage, $size)
143
+ {
144
+ $result = false;
145
+ if (SGBoot::isFeatureAvailable('DOWNLOAD_FROM_CLOUD')) {
146
+ $result = SGBackupStorage::getInstance()->downloadBackupArchiveFromCloud($storage, $archive, $size);
147
+ }
148
+
149
+ return $result;
150
+ }
151
+
152
+ public function getState()
153
+ {
154
+ return $this->state;
155
+ }
156
+
157
+ private function prepareFilesStateFile()
158
+ {
159
+ $this->state = new SGFileState();
160
+
161
+ $this->state->setRanges(array());
162
+ $this->state->setOffset(0);
163
+ $this->state->setToken($this->token);
164
+ $this->state->setAction(SG_STATE_ACTION_PREPARING_STATE_FILE);
165
+ $this->state->setType(SG_STATE_TYPE_FILE);
166
+ $this->state->setActionId($this->actionId);
167
+ $this->state->setActionStartTs($this->actionStartTs);
168
+ $this->state->setBackupFileName($this->fileName);
169
+ $this->state->setBackupFilePath($this->filesBackupPath);
170
+ $this->state->setPendingStorageUploads($this->pendingStorageUploads);
171
+ $this->state->setCdrCursor(0);
172
+ $this->state->setRestoreMode(@$this->restoreMode);
173
+ $this->state->setRestoreFiles(@$this->restoreFiles);
174
+ }
175
+
176
+ private function prepareDBStateFile()
177
+ {
178
+ $this->state = new SGDBState();
179
+ $this->state->setToken($this->token);
180
+ $this->state->setOffset(0);
181
+ $this->state->setAction(SG_STATE_ACTION_PREPARING_STATE_FILE);
182
+ $this->state->setType(SG_STATE_TYPE_DB);
183
+ $this->state->setActionId($this->actionId);
184
+ $this->state->setActionStartTs($this->actionStartTs);
185
+ $this->state->setBackupFileName($this->fileName);
186
+ $this->state->setBackupFilePath($this->filesBackupPath);
187
+ $this->state->setPendingStorageUploads($this->pendingStorageUploads);
188
+ $this->state->setBackedUpTables(array());
189
+ $this->state->setTablesToBackup(@$this->options['SG_BACKUP_TABLES_TO_BACKUP']);
190
+ }
191
+
192
+ private function prepareUploadStateFile()
193
+ {
194
+ $this->state = new SGUploadState();
195
+ $this->state->setOffset(0);
196
+ $this->state->setActiveDirectory('');
197
+ $this->state->setCurrentUploadChunksCount(0);
198
+ $this->state->setTotalUploadChunksCount(0);
199
+ $this->state->setUploadId(0);
200
+ $this->state->setParts(array());
201
+ $this->state->setToken($this->token);
202
+ $this->state->setAction(SG_STATE_ACTION_PREPARING_STATE_FILE);
203
+ $this->state->setType(SG_STATE_TYPE_UPLOAD);
204
+ $this->state->setActionId($this->actionId);
205
+ $this->state->setActionStartTs($this->actionStartTs);
206
+ $this->state->setBackupFileName($this->fileName);
207
+ $this->state->setBackupFilePath($this->filesBackupPath);
208
+ $this->state->setPendingStorageUploads($this->pendingStorageUploads);
209
+ }
210
+
211
+ public function prepareMigrateStateFile()
212
+ {
213
+ $this->state = new SGMigrateState();
214
+ $this->state->setActionId($this->actionId);
215
+ $this->state->setAction(SG_STATE_ACTION_PREPARING_STATE_FILE);
216
+ $this->state->setInprogress(false);
217
+ $this->state->setTableCursor(0);
218
+ $this->state->setColumnCursor(0);
219
+ $this->state->setToken($this->token);
220
+ }
221
+
222
+ public function getNoprivReloadAjaxUrl()
223
+ {
224
+ $url = @$_SERVER['REQUEST_URI'];
225
+
226
+ if (SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
227
+ if(strpos($url, 'wp-cron.php')) {
228
+ $url = substr($url, 0, strpos($url, 'wp-cron.php'));
229
+ $url .= 'wp-admin/admin-ajax.php';
230
+ }
231
+
232
+ $url = explode('?', $url);
233
+ $url = $url[0].'?action=backup_guard_awake&token='.$this->token;
234
+ }
235
+
236
+ return $url;
237
+ }
238
+
239
+ public function reload()
240
+ {
241
+ $url = $this->getNoprivReloadAjaxUrl();
242
+ $callback = new SGCallback("SGBackup", "reloadCallback");
243
+
244
+ SGReloader::didCompleteCallback();
245
+ SGReloader::registerCallback($callback);
246
+ SGReloader::reloadWithAjaxUrl($url);
247
+ die();
248
+ }
249
+
250
+ public function reloadCallback($params)
251
+ {
252
+ $actions = self::getRunningActions();
253
+ if (count($actions)) {
254
+ $action = $actions[0];
255
+ $method = $params['method'];
256
+
257
+ $this->state = backupGuardLoadStateData();
258
+ if ($action['type'] == SG_ACTION_TYPE_RESTORE) {
259
+ $this->restore($action['name']);
260
+ }
261
+ else {
262
+ $options = json_decode($action['options'], true);
263
+ $this->backup($options, $this->state, $method);
264
+ }
265
+ }
266
+ }
267
+
268
+ private function saveStateFile()
269
+ {
270
+ $this->state->save();
271
+ }
272
+
273
+ public function getToken()
274
+ {
275
+ return $this->token;
276
+ }
277
+
278
+ private function reloadMethodNameByMethodId($method)
279
+ {
280
+ $name = "none";
281
+ switch ($method) {
282
+ case SG_RELOAD_METHOD_STREAM:
283
+ $name = "stream";
284
+ break;
285
+ case SG_RELOAD_METHOD_CURL:
286
+ $name = "curl";
287
+ break;
288
+ case SG_RELOAD_METHOD_SOCKET:
289
+ $name = "socket";
290
+ break;
291
+ case SG_RELOAD_METHOD_AJAX:
292
+ $name = "ajax";
293
+ break;
294
+ default:
295
+ break;
296
+ }
297
+
298
+ return $name;
299
+ }
300
+
301
+ /* Backup implementation */
302
+ public function backup($options, $state = false, $reloadMethod = null)
303
+ {
304
+ SGPing::update();
305
+
306
+ $this->options = $options;
307
+ $this->token = backupGuardGenerateToken();
308
+
309
+ $this->filesBackupAvailable = isset($options['SG_ACTION_BACKUP_FILES_AVAILABLE'])?$options['SG_ACTION_BACKUP_FILES_AVAILABLE']:false;
310
+ $this->databaseBackupAvailable = isset($options['SG_ACTION_BACKUP_DATABASE_AVAILABLE'])?$options['SG_ACTION_BACKUP_DATABASE_AVAILABLE']:false;
311
+ $this->backgroundMode = isset($options['SG_BACKUP_IN_BACKGROUND_MODE'])?$options['SG_BACKUP_IN_BACKGROUND_MODE']:false;
312
+
313
+ if (!$state) {
314
+ $this->fileName = $this->getBackupFileName();
315
+ $this->prepareBackupFolder(SG_BACKUP_DIRECTORY.$this->fileName);
316
+ $this->prepareForBackup($options);
317
+ $this->prepareBackupReport();
318
+
319
+ SGBackupLog::write("Reload method set to ajax");
320
+ SGConfig::set('SG_RELOAD_METHOD', SG_RELOAD_METHOD_AJAX, true);
321
+
322
+ if ($this->databaseBackupAvailable) {
323
+ $this->prepareDBStateFile();
324
+ }
325
+ else {
326
+ $this->prepareFilesStateFile();
327
+ }
328
+
329
+ $this->saveStateFile();
330
+ SGReloader::reset();
331
+ if (backupGuardIsReloadEnabled()) {
332
+ $this->reload();
333
+ }
334
+ }
335
+ else {
336
+ $this->state = $state;
337
+ $this->fileName = $state->getBackupFileName();
338
+ $this->actionId = $state->getActionId();
339
+ $this->actionStartTs = $state->getActionStartTs();
340
+ $this->pendingStorageUploads = $state->getPendingStorageUploads();
341
+
342
+ $this->prepareBackupLogFile(SG_BACKUP_DIRECTORY.$this->fileName, true);
343
+ $this->setBackupPaths();
344
+ $this->prepareAdditionalConfigurations();
345
+
346
+ $method = SGConfig::get('SG_RELOAD_METHOD');
347
+ if ($method != $reloadMethod) {
348
+ SGConfig::set('SG_RELOAD_METHOD', $reloadMethod);
349
+ $reloadMethod = $this->reloadMethodNameByMethodId($reloadMethod);
350
+ SGBackupLog::write("Reload method changed to ".$reloadMethod);
351
+ }
352
+ }
353
+
354
+ SGPing::update();
355
+
356
+ try
357
+ {
358
+ if ($this->databaseBackupAvailable) {
359
+ $this->backupDatabase->setFilePath($this->databaseBackupPath);
360
+ $this->backupDatabase->setPendingStorageUploads($this->pendingStorageUploads);
361
+
362
+ if (!$this->filesBackupAvailable) {
363
+ $options['SG_BACKUP_FILE_PATHS'] = '';
364
+ }
365
+
366
+ if ($this->state->getType() == SG_STATE_TYPE_DB) {
367
+ $this->backupDatabase->backup($this->databaseBackupPath);
368
+ $this->prepareFilesStateFile();
369
+ $this->saveStateFile();
370
+ self::changeActionStatus($this->actionId, SG_ACTION_STATUS_IN_PROGRESS_FILES);
371
+
372
+ if (backupGuardIsReloadEnabled()) {
373
+ $this->reload();
374
+ }
375
+ }
376
+
377
+ $rootDirectory = rtrim(SGConfig::get('SG_APP_ROOT_DIRECTORY'), '/').'/';
378
+ $path = substr($this->databaseBackupPath, strlen($rootDirectory));
379
+ $this->backupFiles->addDontExclude($this->databaseBackupPath);
380
+ $backupItems = $options['SG_BACKUP_FILE_PATHS'];
381
+ $allItems = $backupItems?explode(',', $backupItems):array();
382
+ $allItems[] = $path;
383
+ $options['SG_BACKUP_FILE_PATHS'] = implode(',', $allItems);
384
+
385
+ if ($this->state->getType() == SG_STATE_TYPE_DB) {
386
+ $currentStatus = $this->getCurrentActionStatus();
387
+ if ($currentStatus==SG_ACTION_STATUS_CANCELLING || $currentStatus==SG_ACTION_STATUS_CANCELLED) {
388
+ // If action canceled during backup of database, cancelaion handling will happen here
389
+ // in other cases handling will happen in respective classes
390
+ $this->cancel();
391
+ }
392
+ }
393
+ }
394
+
395
+ if ($this->state->getType() == SG_STATE_TYPE_FILE) {
396
+ $this->backupFiles->setPendingStorageUploads($this->pendingStorageUploads);
397
+ $this->backupFiles->backup($this->filesBackupPath, $options, $this->state);
398
+ $this->didFinishBackup();
399
+
400
+ SGPing::update();
401
+
402
+ $this->prepareUploadStateFile();
403
+ $this->saveStateFile();
404
+ }
405
+
406
+ //continue uploading backup to storages
407
+ $this->backupUploadToStorages();
408
+
409
+ // Clear temporary files
410
+ $this->clear();
411
+ }
412
+ catch (SGException $exception)
413
+ {
414
+ if ($exception instanceof SGExceptionSkip)
415
+ {
416
+ $this->setCurrentActionStatusCancelled();
417
+ }
418
+ else
419
+ {
420
+ SGBackupLog::writeExceptionObject($exception);
421
+
422
+ if ($this->state->getType() != SG_STATE_TYPE_UPLOAD) {
423
+ if ($this->databaseBackupAvailable)
424
+ {
425
+ $this->backupDatabase->cancel();
426
+ }
427
+
428
+ $this->backupFiles->cancel();
429
+ }
430
+
431
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS')) {
432
+ //Writing backup status to report file
433
+ file_put_contents(dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME, 'Backup: failed', FILE_APPEND);
434
+ SGBackupMailNotification::sendBackupNotification(SG_ACTION_STATUS_ERROR, array(
435
+ 'flowFilePath' => dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME,
436
+ 'archiveName' => $this->fileName
437
+ ));
438
+ }
439
+
440
+ self::changeActionStatus($this->actionId, SG_ACTION_STATUS_ERROR);
441
+ }
442
+
443
+ // Clear temporary files
444
+ $this->clear();
445
+ }
446
+ }
447
+
448
+ private function prepareBackupReport()
449
+ {
450
+ file_put_contents(dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME, 'Report for: '.SG_SITE_URL."\n", FILE_APPEND);
451
+ }
452
+
453
+ private function shouldDeleteBackupAfterUpload()
454
+ {
455
+ return SGConfig::get('SG_DELETE_BACKUP_AFTER_UPLOAD')?true:false;
456
+ }
457
+
458
+ private function backupUploadToStorages()
459
+ {
460
+ //check list of storages to upload if any
461
+ $uploadToStorages = count($this->pendingStorageUploads)?true:false;
462
+
463
+ if (SGBoot::isFeatureAvailable('STORAGE') && $uploadToStorages)
464
+ {
465
+ while (count($this->pendingStorageUploads))
466
+ {
467
+ $storageId = $this->pendingStorageUploads[0];
468
+
469
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
470
+ // Create action for upload
471
+ $this->actionId = SGBackupStorage::queueBackupForUpload($this->fileName, $storageId, $this->options);
472
+ }
473
+ else {
474
+ // Get upload action id if it does not finished yet
475
+ $this->actionId = $this->state->getActionId();
476
+ }
477
+
478
+ $sgBackupStorage = SGBackupStorage::getInstance();
479
+ $sgBackupStorage->setDelegate($this);
480
+ $sgBackupStorage->setState($this->state);
481
+ $sgBackupStorage->setToken($this->token);
482
+ $sgBackupStorage->setPendingStorageUploads($this->pendingStorageUploads);
483
+ $sgBackupStorage->startUploadByActionId($this->actionId);
484
+
485
+ array_shift($this->pendingStorageUploads);
486
+ // Reset state file to defaults for next storage upload
487
+ $this->prepareUploadStateFile();
488
+ }
489
+
490
+ $this->didFinishUpload();
491
+ }
492
+ }
493
+
494
+ private function didFinishUpload()
495
+ {
496
+ //check if option is enabled
497
+ $isDeleteLocalBackupFeatureAvailable = SGBoot::isFeatureAvailable('DELETE_LOCAL_BACKUP_AFTER_UPLOAD');
498
+
499
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS')) {
500
+ SGBackupMailNotification::sendBackupNotification(SG_ACTION_STATUS_FINISHED, array(
501
+ 'flowFilePath' => dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME,
502
+ 'archiveName' => $this->fileName
503
+ ));
504
+ }
505
+
506
+ $status = SGBackup::getActionStatus($this->actionId);
507
+
508
+ if ($this->shouldDeleteBackupAfterUpload() && $isDeleteLocalBackupFeatureAvailable && $status == SG_ACTION_STATUS_FINISHED) {
509
+ @unlink(SG_BACKUP_DIRECTORY.$this->fileName.'/'.$this->fileName.'.'.SGBP_EXT);
510
+ }
511
+ }
512
+
513
+ // Delete state and flow files after upload
514
+ private function clear()
515
+ {
516
+ @unlink(dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME);
517
+
518
+ @unlink(SG_BACKUP_DIRECTORY.SG_STATE_FILE_NAME);
519
+ @unlink(SG_BACKUP_DIRECTORY.SG_RELOADER_STATE_FILE_NAME);
520
+ @unlink(SG_PING_FILE_PATH);
521
+ }
522
+
523
+ private function cleanUp()
524
+ {
525
+ //delete sql file
526
+ if ($this->databaseBackupAvailable) {
527
+ @unlink($this->databaseBackupPath);
528
+ }
529
+ }
530
+
531
+ private function getBackupFileName()
532
+ {
533
+ if (SGConfig::get("SG_CUSTOM_BACKUP_NAME")) {
534
+ return SGConfig::get("SG_CUSTOM_BACKUP_NAME");
535
+ }
536
+
537
+ $sgBackupPrefix = SG_BACKUP_FILE_NAME_DEFAULT_PREFIX;
538
+ if (function_exists('backupGuardGetCustomPrefix') && SGBoot::isFeatureAvailable('CUSTOM_BACKUP_NAME')) {
539
+ $sgBackupPrefix = backupGuardGetCustomPrefix();
540
+ }
541
+
542
+ $sgBackupPrefix .= backupGuardGetFilenameOptions($this->options);
543
+
544
+ $date = backupGuardConvertDateTimezone(@date('YmdHis'), 'YmdHis');
545
+ return $sgBackupPrefix.($date);
546
+ }
547
+
548
+ private function prepareBackupFolder($backupPath)
549
+ {
550
+ if (!is_writable(SG_BACKUP_DIRECTORY))
551
+ {
552
+ throw new SGExceptionForbidden('Permission denied. Directory is not writable: '.$backupPath);
553
+ }
554
+
555
+ //create backup folder
556
+ if (!@mkdir($backupPath))
557
+ {
558
+ throw new SGExceptionMethodNotAllowed('Cannot create folder: '.$backupPath);
559
+ }
560
+
561
+ if (!is_writable($backupPath))
562
+ {
563
+ throw new SGExceptionForbidden('Permission denied. Directory is not writable: '.$backupPath);
564
+ }
565
+
566
+ //create backup log file
567
+ $this->prepareBackupLogFile($backupPath);
568
+ }
569
+
570
+ private function prepareBackupLogFile($backupPath, $exists = false)
571
+ {
572
+ $file = $backupPath.'/'.$this->fileName.'_backup.log';
573
+ $this->backupLogPath = $file;
574
+
575
+ if (!$exists)
576
+ {
577
+ $content = self::getLogFileHeader(SG_ACTION_TYPE_BACKUP, $this->fileName);
578
+
579
+ $types = array();
580
+ if ($this->filesBackupAvailable)
581
+ {
582
+ $types[] = 'files';
583
+ }
584
+ if ($this->databaseBackupAvailable)
585
+ {
586
+ $types[] = 'database';
587
+ }
588
+
589
+ $content .= 'Backup type: '.implode(',', $types).PHP_EOL.PHP_EOL;
590
+
591
+ if (!file_put_contents($file, $content))
592
+ {
593
+ throw new SGExceptionMethodNotAllowed('Cannot create backup log file: '.$file);
594
+ }
595
+ }
596
+
597
+ //create file log handler
598
+ $fileLogHandler = new SGFileLogHandler($file);
599
+ SGLog::registerLogHandler($fileLogHandler, SG_LOG_LEVEL_LOW, true);
600
+ }
601
+
602
+ private function setBackupPaths()
603
+ {
604
+ $this->filesBackupPath = SG_BACKUP_DIRECTORY.$this->fileName.'/'.$this->fileName.'.sgbp';
605
+ $this->databaseBackupPath = SG_BACKUP_DIRECTORY.$this->fileName.'/'.$this->fileName.'.sql';
606
+ }
607
+
608
+ private function prepareUploadToStorages($options)
609
+ {
610
+ $uploadToStorages = $options['SG_BACKUP_UPLOAD_TO_STORAGES'];
611
+
612
+ if (SGBoot::isFeatureAvailable('STORAGE') && $uploadToStorages) {
613
+ $this->pendingStorageUploads = explode(',', $uploadToStorages);
614
+ }
615
+ }
616
+
617
+ private function prepareAdditionalConfigurations()
618
+ {
619
+ $this->backupFiles->setFilePath($this->filesBackupPath);
620
+ SGConfig::set('SG_RUNNING_ACTION', 1, true);
621
+ }
622
+
623
+ private function prepareForBackup($options)
624
+ {
625
+ //start logging
626
+ SGBackupLog::writeAction('backup', SG_BACKUP_LOG_POS_START);
627
+
628
+ //save timestamp for future use
629
+ $this->actionStartTs = time();
630
+
631
+ //create action inside db
632
+ $status = $this->databaseBackupAvailable?SG_ACTION_STATUS_IN_PROGRESS_DB:SG_ACTION_STATUS_IN_PROGRESS_FILES;
633
+ $this->actionId = self::createAction($this->fileName, SG_ACTION_TYPE_BACKUP, $status, 0, json_encode($options));
634
+
635
+ //set paths
636
+ $this->setBackupPaths();
637
+
638
+ //prepare sgbp file
639
+ @file_put_contents($this->filesBackupPath, '');
640
+
641
+ if (!is_writable($this->filesBackupPath))
642
+ {
643
+ throw new SGExceptionForbidden('Could not create backup file: '.$this->filesBackupPath);
644
+ }
645
+
646
+ //additional configuration
647
+ $this->prepareAdditionalConfigurations();
648
+
649
+ //check if upload to storages is needed
650
+ $this->prepareUploadToStorages($options);
651
+ }
652
+
653
+ public function cancel()
654
+ {
655
+ $dir = SG_BACKUP_DIRECTORY.$this->fileName;
656
+
657
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS')) {
658
+ //Writing backup status to report file
659
+ file_put_contents($dir.'/'.SG_REPORT_FILE_NAME, 'Backup: canceled', FILE_APPEND);
660
+ SGBackupMailNotification::sendBackupNotification(SG_ACTION_STATUS_CANCELLED, array(
661
+ 'flowFilePath' => dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME,
662
+ 'archiveName' => $this->fileName
663
+ ));
664
+ }
665
+
666
+ if ($dir != SG_BACKUP_DIRECTORY) {
667
+ backupGuardDeleteDirectory($dir);
668
+ }
669
+
670
+ $this->clear();
671
+ throw new SGExceptionSkip();
672
+ }
673
+
674
+ private function didFinishBackup()
675
+ {
676
+ if(SGConfig::get('SG_REVIEW_POPUP_STATE') != SG_NEVER_SHOW_REVIEW_POPUP)
677
+ {
678
+ SGConfig::set('SG_REVIEW_POPUP_STATE', SG_SHOW_REVIEW_POPUP);
679
+ }
680
+
681
+ $action = $this->didFindWarnings()?SG_ACTION_STATUS_FINISHED_WARNINGS:SG_ACTION_STATUS_FINISHED;
682
+ self::changeActionStatus($this->actionId, $action);
683
+
684
+ SGBackupLog::writeAction('backup', SG_BACKUP_LOG_POS_END);
685
+
686
+ $report = $this->didFindWarnings()?'completed with warnings':'completed';
687
+
688
+ //Writing backup status to report file
689
+ file_put_contents(dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME, 'Backup: '.$report."\n", FILE_APPEND);
690
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS') && !count($this->pendingStorageUploads)) {
691
+ SGBackupMailNotification::sendBackupNotification($action, array(
692
+ 'flowFilePath' => dirname($this->filesBackupPath).'/'.SG_REPORT_FILE_NAME,
693
+ 'archiveName' => $this->fileName
694
+ ));
695
+ }
696
+
697
+ SGBackupLog::write('Total duration: '.backupGuardFormattedDuration($this->actionStartTs, time()));
698
+
699
+ $archiveSizeInBytes = backupGuardRealFilesize($this->filesBackupPath);
700
+ $archiveSize = convertToReadableSize($archiveSizeInBytes);
701
+ SGBackupLog::write("Archive size: ".$archiveSize." (".$archiveSizeInBytes." bytes)");
702
+
703
+ $this->cleanUp();
704
+ if (SGBoot::isFeatureAvailable('NUMBER_OF_BACKUPS_TO_KEEP') && function_exists('backupGuardOutdatedBackupsCleanup')) {
705
+ backupGuardOutdatedBackupsCleanup(SG_BACKUP_DIRECTORY);
706
+ }
707
+ }
708
+
709
+ public function handleMigrationErrors($exception)
710
+ {
711
+ SGConfig::set('SG_BACKUP_SHOW_MIGRATION_ERROR', 1);
712
+ SGConfig::set('SG_BACKUP_MIGRATION_ERROR', (string)$exception);
713
+ }
714
+
715
+ public function getActionId()
716
+ {
717
+ return $this->actionId;
718
+ }
719
+
720
+ /* Restore implementation */
721
+
722
+ public function restore($backupName, $restoreMode=NULL, $restoreFiles = NULL)
723
+ {
724
+ try
725
+ {
726
+ SGPing::update();
727
+ $this->token = backupGuardGenerateToken();
728
+ if($restoreMode != NULL) {
729
+ $this->restoreMode = $restoreMode;
730
+ }
731
+ if($restoreFiles != NULL) {
732
+ $this->restoreFiles = $restoreFiles;
733
+ }
734
+ $this->prepareForRestore($backupName);
735
+
736
+ if ($this->state && ($this->state->getAction() == SG_STATE_ACTION_RESTORING_DATABASE || $this->state->getAction() == SG_STATE_ACTION_MIGRATING_DATABASE)) {
737
+ $this->didFinishFilesRestore();
738
+ }
739
+ else {
740
+ $this->backupFiles->setFileName($backupName);
741
+ $this->backupFiles->restore($this->filesBackupPath);
742
+
743
+ $this->prepareDBStateFile();
744
+ $this->didFinishFilesRestore();
745
+ }
746
+ }
747
+ catch (SGException $exception)
748
+ {
749
+ if (!$exception instanceof SGExceptionSkip)
750
+ {
751
+ SGBackupLog::writeExceptionObject($exception);
752
+
753
+ if ($exception instanceof SGExceptionMigrationError) {
754
+ $this->handleMigrationErrors($exception);
755
+ }
756
+
757
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS'))
758
+ {
759
+ SGBackupMailNotification::sendRestoreNotification(false);
760
+ }
761
+
762
+ self::changeActionStatus($this->actionId, SG_ACTION_STATUS_ERROR);
763
+ }
764
+ else
765
+ {
766
+ self::changeActionStatus($this->actionId, SG_ACTION_STATUS_CANCELLED);
767
+ }
768
+ }
769
+ }
770
+
771
+ private function prepareForRestore($backupName)
772
+ {
773
+ //prepare file name
774
+ $this->fileName = $backupName;
775
+
776
+ //set paths
777
+ $restorePath = SG_BACKUP_DIRECTORY.$this->fileName;
778
+ $this->filesBackupPath = $restorePath.'/'.$this->fileName.'.sgbp';
779
+ $this->databaseBackupPath = $restorePath.'/'.$this->fileName.'.sql';
780
+
781
+ if (!$this->state) {
782
+ //create action inside db
783
+ $this->actionId = self::createAction($this->fileName, SG_ACTION_TYPE_RESTORE, SG_ACTION_STATUS_IN_PROGRESS_FILES);
784
+
785
+ //save current user credentials
786
+ $this->backupDatabase->saveCurrentUser();
787
+
788
+ //check if we can run external restore
789
+ $externalRestoreEnabled = SGExternalRestore::getInstance()->prepare($this->actionId);
790
+
791
+ //prepare folder
792
+ $this->prepareRestoreFolder($restorePath);
793
+
794
+ SGConfig::set('SG_RUNNING_ACTION', 1, true);
795
+
796
+ //save timestamp for future use
797
+ $this->actionStartTs = time();
798
+
799
+ $this->prepareFilesStateFile();
800
+ $this->saveStateFile();
801
+ SGReloader::reset();
802
+
803
+ if ($externalRestoreEnabled) {
804
+ $this->reload();
805
+ }
806
+ }
807
+ else {
808
+ $this->actionId = $this->state->getActionId();
809
+ $this->actionStartTs = $this->state->getActionStartTs();
810
+ $this->prepareRestoreLogFile($restorePath, true);
811
+ }
812
+ }
813
+
814
+ private function prepareRestoreFolder($restorePath)
815
+ {
816
+ if (!is_writable($restorePath))
817
+ {
818
+ SGConfig::set('SG_BACKUP_NOT_WRITABLE_DIR_PATH', $restorePath);
819
+ SGConfig::set('SG_BACKUP_SHOW_NOT_WRITABLE_ERROR', 1);
820
+ throw new SGExceptionForbidden('Permission denied. Directory is not writable: '.$restorePath);
821
+ }
822
+
823
+ $this->filesBackupAvailable = file_exists($this->filesBackupPath);
824
+
825
+ //create restore log file
826
+ $this->prepareRestoreLogFile($restorePath);
827
+ }
828
+
829
+ private function prepareRestoreLogFile($backupPath, $exists = false)
830
+ {
831
+ $file = $backupPath.'/'.$this->fileName.'_restore.log';
832
+ $this->restoreLogPath = $file;
833
+
834
+ if (!$exists) {
835
+ $content = self::getLogFileHeader(SG_ACTION_TYPE_RESTORE, $this->fileName);
836
+
837
+ $content .= PHP_EOL;
838
+
839
+ if (!file_put_contents($file, $content)) {
840
+ throw new SGExceptionMethodNotAllowed('Cannot create restore log file: '.$file);
841
+ }
842
+ }
843
+
844
+ //create file log handler
845
+ $fileLogHandler = new SGFileLogHandler($file);
846
+ SGLog::registerLogHandler($fileLogHandler, SG_LOG_LEVEL_LOW, true);
847
+ }
848
+
849
+ private function didFinishRestore()
850
+ {
851
+ SGBackupLog::writeAction('restore', SG_BACKUP_LOG_POS_END);
852
+
853
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS')) {
854
+ SGBackupMailNotification::sendRestoreNotification(true);
855
+ }
856
+
857
+ SGBackupLog::write('Total duration: '.backupGuardFormattedDuration($this->actionStartTs, time()));
858
+
859
+ $this->cleanUp();
860
+ }
861
+
862
+ private function didFinishFilesRestore()
863
+ {
864
+ $this->databaseBackupAvailable = file_exists($this->databaseBackupPath);
865
+
866
+ if ($this->databaseBackupAvailable) {
867
+ if ($this->state->getAction() == SG_STATE_ACTION_RESTORING_DATABASE) {
868
+ self::changeActionStatus($this->actionId, SG_ACTION_STATUS_IN_PROGRESS_DB);
869
+ }
870
+
871
+ $this->backupDatabase->restore($this->databaseBackupPath);
872
+ }
873
+
874
+ $action = $this->didFindWarnings()?SG_ACTION_STATUS_FINISHED_WARNINGS:SG_ACTION_STATUS_FINISHED;
875
+
876
+ self::changeActionStatus($this->actionId, $action);
877
+
878
+ //we let the external restore to finalize the restore for itself
879
+ if (SGExternalRestore::isEnabled()) {
880
+ return;
881
+ }
882
+
883
+ $this->didFinishRestore();
884
+ }
885
+
886
+ public function finalizeExternalRestore($actionId)
887
+ {
888
+ $action = self::getAction($actionId);
889
+
890
+ $this->state = backupGuardLoadStateData();
891
+ $this->prepareForRestore($action['name']);
892
+
893
+ $this->databaseBackupAvailable = file_exists($this->databaseBackupPath);
894
+
895
+ if ($this->databaseBackupAvailable) {
896
+ $this->backupDatabase->finalizeRestore();
897
+ }
898
+
899
+ $this->didFinishRestore();
900
+ }
901
+
902
+ /* General methods */
903
+
904
+ public static function getLogFileHeader($actionType, $fileName)
905
+ {
906
+ $pluginCapabilities = backupGuardGetCapabilities();
907
+
908
+ $confs = array();
909
+ $confs['sg_backup_guard_version'] = SG_BACKUP_GUARD_VERSION;
910
+ $confs['sg_archive_version'] = SG_ARCHIVE_VERSION;
911
+ $confs['sg_user_mode'] = ($pluginCapabilities != BACKUP_GUARD_CAPABILITIES_FREE)?'pro':'free'; // Check if user is pro or free
912
+ $confs['os'] = PHP_OS;
913
+ $confs['server'] = @$_SERVER['SERVER_SOFTWARE'];
914
+ $confs['php_version'] = PHP_VERSION;
915
+ $confs['sapi'] = PHP_SAPI;
916
+ $confs['mysql_version'] = SG_MYSQL_VERSION;
917
+ $confs['int_size'] = PHP_INT_SIZE;
918
+ $confs['method'] = backupGuardIsReloadEnabled()?'reload':'standard';
919
+
920
+ $confs['dbprefix'] = SG_ENV_DB_PREFIX;
921
+ $confs['siteurl'] = SG_SITE_URL;
922
+ $confs['homeurl'] = SG_HOME_URL;
923
+ $confs['uploadspath'] = SG_UPLOAD_PATH;
924
+ $confs['installation'] = SG_SITE_TYPE;
925
+ $freeSpace = convertToReadableSize(@disk_free_space(SG_APP_ROOT_DIRECTORY));
926
+ $confs['free_space'] = $freeSpace==false?'unknown':$freeSpace;
927
+
928
+ if (extension_loaded('gmp')) $lib = 'gmp';
929
+ else if (extension_loaded('bcmath')) $lib = 'bcmath';
930
+ else $lib = 'BigInteger';
931
+
932
+ $confs['int_lib'] = $lib;
933
+ $confs['memory_limit'] = SGBoot::$memoryLimit;
934
+ $confs['max_execution_time'] = SGBoot::$executionTimeLimit;
935
+ $confs['env'] = SG_ENV_ADAPTER.' '.SG_ENV_VERSION;
936
+
937
+ $content = '';
938
+ $content .= 'Date: '.backupGuardConvertDateTimezone(@date('Y-m-d H:i')).PHP_EOL;
939
+ $content .= 'Backup Method: '.$confs['method'].PHP_EOL;
940
+
941
+ if ($actionType == SG_ACTION_TYPE_RESTORE) {
942
+ $confs['restore_method'] = SGExternalRestore::isEnabled()?'external':'standard';
943
+ $content .= 'Restore Method: '.$confs['restore_method'].PHP_EOL;
944
+ }
945
+
946
+ $content .= 'User Mode: '.$confs['sg_user_mode'].PHP_EOL;
947
+ $content .= 'BackupGuard version: '.$confs['sg_backup_guard_version'].PHP_EOL;
948
+ $content .= 'Supported archive version: '.$confs['sg_archive_version'].PHP_EOL;
949
+
950
+ $content .= 'Database prefix: '.$confs['dbprefix'].PHP_EOL;
951
+ $content .= 'Site URL: '.$confs['siteurl'].PHP_EOL;
952
+ $content .= 'Home URL: '.$confs['homeurl'].PHP_EOL;
953
+ $content .= 'Uploads path: '.$confs['uploadspath'].PHP_EOL;
954
+ $content .= 'Site installation: '.$confs['installation'].PHP_EOL;
955
+
956
+ $content .= 'OS: '.$confs['os'].PHP_EOL;
957
+ $content .= 'Server: '.$confs['server'].PHP_EOL;
958
+ $content .= 'User agent: '.@$_SERVER['HTTP_USER_AGENT'].PHP_EOL;
959
+ $content .= 'PHP version: '.$confs['php_version'].PHP_EOL;
960
+ $content .= 'SAPI: '.$confs['sapi'].PHP_EOL;
961
+ $content .= 'MySQL version: '.$confs['mysql_version'].PHP_EOL;
962
+ $content .= 'Int size: '.$confs['int_size'].PHP_EOL;
963
+ $content .= 'Int lib: '.$confs['int_lib'].PHP_EOL;
964
+ $content .= 'Memory limit: '.$confs['memory_limit'].PHP_EOL;
965
+ $content .= 'Max execution time: '.$confs['max_execution_time'].PHP_EOL;
966
+ $content .= 'Disk free space: '.$confs['free_space'].PHP_EOL;
967
+
968
+ if ($actionType == SG_ACTION_TYPE_RESTORE) {
969
+ $archivePath = SG_BACKUP_DIRECTORY.$fileName.'/'.$fileName.'.sgbp';
970
+ $archiveSizeInBytes = backupGuardRealFilesize($archivePath);
971
+ $confs['archiveSize'] = convertToReadableSize($archiveSizeInBytes);
972
+ $content .= 'Archive Size: '.$confs['archiveSize'].' ('.$archiveSizeInBytes.' bytes)'.PHP_EOL;
973
+ }
974
+
975
+ $content .= 'Environment: '.$confs['env'].PHP_EOL;
976
+
977
+ return $content;
978
+ }
979
+
980
+ private function didFindWarnings()
981
+ {
982
+ $warningsDatabase = $this->databaseBackupAvailable?$this->backupDatabase->didFindWarnings():false;
983
+ $warningsFiles = $this->backupFiles->didFindWarnings();
984
+ return ($warningsFiles||$warningsDatabase);
985
+ }
986
+
987
+ public static function createAction($name, $type, $status, $subtype = 0, $options = '')
988
+ {
989
+ $sgdb = SGDatabase::getInstance();
990
+
991
+ $date = backupGuardConvertDateTimezone(@date('Y-m-d H:i:s'));
992
+ $res = $sgdb->query('INSERT INTO '.SG_ACTION_TABLE_NAME.' (name, type, subtype, status, start_date, options) VALUES (%s, %d, %d, %d, %s, %s)', array($name, $type, $subtype, $status, $date, $options));
993
+
994
+ if (!$res) {
995
+ throw new SGExceptionDatabaseError('Could not create action');
996
+ }
997
+ return $sgdb->lastInsertId();
998
+ }
999
+
1000
+ private function getCurrentActionStatus()
1001
+ {
1002
+ return self::getActionStatus($this->actionId);
1003
+ }
1004
+
1005
+ private function setCurrentActionStatusCancelled()
1006
+ {
1007
+ $sgdb = SGDatabase::getInstance();
1008
+ $date = backupGuardConvertDateTimezone(@date('Y-m-d H:i:s'));
1009
+ $sgdb->query('UPDATE '.SG_ACTION_TABLE_NAME.' SET status=%d, update_date=%s WHERE name=%s', array(SG_ACTION_STATUS_CANCELLED, $date, $this->fileName));
1010
+ }
1011
+
1012
+ public static function changeActionStatus($actionId, $status)
1013
+ {
1014
+ $sgdb = SGDatabase::getInstance();
1015
+
1016
+ $progress = '';
1017
+ if ($status==SG_ACTION_STATUS_FINISHED || $status==SG_ACTION_STATUS_FINISHED_WARNINGS)
1018
+ {
1019
+ $progress = 100;
1020
+ }
1021
+ else if ($status==SG_ACTION_STATUS_CREATED || $status==SG_ACTION_STATUS_IN_PROGRESS_FILES || $status==SG_ACTION_STATUS_IN_PROGRESS_DB)
1022
+ {
1023
+ $progress = 0;
1024
+ }
1025
+
1026
+ if ($progress!=='')
1027
+ {
1028
+ $progress = ' progress='.$progress.',';
1029
+ }
1030
+
1031
+ $date = backupGuardConvertDateTimezone(@date('Y-m-d H:i:s'));
1032
+ $res = $sgdb->query('UPDATE '.SG_ACTION_TABLE_NAME.' SET status=%d,'.$progress.' update_date=%s WHERE id=%d', array($status, $date, $actionId));
1033
+ }
1034
+
1035
+ public static function changeActionProgress($actionId, $progress)
1036
+ {
1037
+ $sgdb = SGDatabase::getInstance();
1038
+ $date = backupGuardConvertDateTimezone(@date('Y-m-d H:i:s'));
1039
+ $sgdb->query('UPDATE '.SG_ACTION_TABLE_NAME.' SET progress=%d, update_date=%s WHERE id=%d', array($progress, $date, $actionId));
1040
+ }
1041
+
1042
+ /* Methods for frontend use */
1043
+
1044
+ public static function getAction($actionId)
1045
+ {
1046
+ $sgdb = SGDatabase::getInstance();
1047
+ $res = $sgdb->query('SELECT * FROM '.SG_ACTION_TABLE_NAME.' WHERE id=%d', array($actionId));
1048
+ if (empty($res))
1049
+ {
1050
+ return false;
1051
+ }
1052
+ return $res[0];
1053
+ }
1054
+
1055
+ public static function getActionByName($name)
1056
+ {
1057
+ $sgdb = SGDatabase::getInstance();
1058
+ $res = $sgdb->query('SELECT * FROM '.SG_ACTION_TABLE_NAME.' WHERE name=%s', array($name));
1059
+ if (empty($res)) {
1060
+ return false;
1061
+ }
1062
+ return $res[0];
1063
+ }
1064
+
1065
+ public static function getActionProgress($actionId)
1066
+ {
1067
+ $sgdb = SGDatabase::getInstance();
1068
+ $res = $sgdb->query('SELECT progress FROM '.SG_ACTION_TABLE_NAME.' WHERE id=%d', array($actionId));
1069
+ if (empty($res))
1070
+ {
1071
+ return false;
1072
+ }
1073
+ return (int)$res[0]['progress'];
1074
+ }
1075
+
1076
+ public static function getActionStatus($actionId)
1077
+ {
1078
+ $sgdb = SGDatabase::getInstance();
1079
+ $res = $sgdb->query('SELECT status FROM '.SG_ACTION_TABLE_NAME.' WHERE id=%d', array($actionId));
1080
+ if (empty($res))
1081
+ {
1082
+ return false;
1083
+ }
1084
+ return (int)$res[0]['status'];
1085
+ }
1086
+
1087
+ public static function getRunningActions()
1088
+ {
1089
+ $sgdb = SGDatabase::getInstance();
1090
+ $res = $sgdb->query('SELECT * FROM '.SG_ACTION_TABLE_NAME.' WHERE status=%d OR status=%d OR status=%d ORDER BY status DESC', array(SG_ACTION_STATUS_IN_PROGRESS_FILES, SG_ACTION_STATUS_IN_PROGRESS_DB, SG_ACTION_STATUS_CREATED));
1091
+ return $res;
1092
+ }
1093
+
1094
+ public static function getBackupFileInfo($file)
1095
+ {
1096
+ return pathinfo(SG_BACKUP_DIRECTORY.$file);
1097
+ }
1098
+
1099
+ public static function autodetectBackups()
1100
+ {
1101
+ $path = SG_BACKUP_DIRECTORY;
1102
+ $files = scandir(SG_BACKUP_DIRECTORY);
1103
+ $backupLogPostfix = "_backup.log";
1104
+ $restoreLogPostfix = "_restore.log";
1105
+
1106
+ foreach ($files as $file) {
1107
+ $fileInfo = self::getBackupFileInfo($file);
1108
+
1109
+ if (@$fileInfo['extension'] == SGBP_EXT) {
1110
+ @mkdir($path.$fileInfo['filename'], 0777);
1111
+
1112
+ if(file_exists($path.$fileInfo['filename'])) {
1113
+ rename($path.$file, $path.$fileInfo['filename'].'/'.$file);
1114
+ }
1115
+
1116
+ if(file_exists($path.$fileInfo['filename'].$backupLogPostfix)){
1117
+ rename($path.$fileInfo['filename'].$backupLogPostfix, $path.$fileInfo['filename'].'/'.$fileInfo['filename'].$backupLogPostfix);
1118
+ }
1119
+
1120
+ if (file_exists($path.$fileInfo['filename'].$restoreLogPostfix)) {
1121
+ rename($path.$fileInfo['filename'].$restoreLogPostfix, $path.$fileInfo['filename'].'/'.$fileInfo['filename'].$restoreLogPostfix);
1122
+ }
1123
+ }
1124
+ }
1125
+ }
1126
+
1127
+ public static function getAllBackups()
1128
+ {
1129
+ $backups = array();
1130
+
1131
+ $path = SG_BACKUP_DIRECTORY;
1132
+ self::autodetectBackups();
1133
+ clearstatcache();
1134
+
1135
+ $action = self::getRunningActions();
1136
+ if (SGBoot::isFeatureAvailable('NUMBER_OF_BACKUPS_TO_KEEP') && !count($action) && function_exists('backupGuardOutdatedBackupsCleanup')) {
1137
+ backupGuardOutdatedBackupsCleanup($path);
1138
+ }
1139
+
1140
+ //remove external restore file
1141
+ SGExternalRestore::getInstance()->cleanup();
1142
+
1143
+ if ($handle = @opendir($path)) {
1144
+ $sgdb = SGDatabase::getInstance();
1145
+ $data = $sgdb->query('SELECT id, name, type, subtype, status, progress, update_date, options FROM '.SG_ACTION_TABLE_NAME);
1146
+ $allBackups = array();
1147
+ foreach ($data as $row) {
1148
+ $allBackups[$row['name']][] = $row;
1149
+ }
1150
+
1151
+ while (($entry = readdir($handle)) !== false) {
1152
+ if ($entry === '.' || $entry === '..' || !is_dir($path.$entry)) {
1153
+ continue;
1154
+ }
1155
+
1156
+ $backup = array();
1157
+ $backup['name'] = $entry;
1158
+ $backup['id'] = '';
1159
+ $backup['status'] = '';
1160
+ $backup['files'] = file_exists($path.$entry.'/'.$entry.'.sgbp')?1:0;
1161
+ $backup['backup_log'] = file_exists($path.$entry.'/'.$entry.'_backup.log')?1:0;
1162
+ $backup['restore_log'] = file_exists($path.$entry.'/'.$entry.'_restore.log')?1:0;
1163
+ $backup['options'] = '';
1164
+ if (!$backup['files'] && !$backup['backup_log'] && !$backup['restore_log']) {
1165
+ continue;
1166
+ }
1167
+ $backupRow = null;
1168
+ if (isset($allBackups[$entry])) {
1169
+ $skip = false;
1170
+ foreach ($allBackups[$entry] as $row) {
1171
+ if ($row['status']==SG_ACTION_STATUS_IN_PROGRESS_FILES || $row['status']==SG_ACTION_STATUS_IN_PROGRESS_DB) {
1172
+ $backupRow = $row;
1173
+ break;
1174
+ }
1175
+ else if (($row['status']==SG_ACTION_STATUS_CANCELLING || $row['status']==SG_ACTION_STATUS_CANCELLED) && $row['type']!=SG_ACTION_TYPE_UPLOAD) {
1176
+ $skip = true;
1177
+ break;
1178
+ }
1179
+
1180
+ $backupRow = $row;
1181
+
1182
+ if ($row['status']==SG_ACTION_STATUS_FINISHED_WARNINGS || $row['status']==SG_ACTION_STATUS_ERROR) {
1183
+ if ($row['type'] == SG_ACTION_TYPE_UPLOAD && file_exists(SG_BACKUP_DIRECTORY.$entry.'/'.$entry.'.sgbp')) {
1184
+ $backupRow['status'] = SG_ACTION_STATUS_FINISHED_WARNINGS;
1185
+ }
1186
+ }
1187
+ }
1188
+
1189
+ if ($skip===true) {
1190
+ continue;
1191
+ }
1192
+ }
1193
+
1194
+ if ($backupRow) {
1195
+ $backup['active'] = ($backupRow['status']==SG_ACTION_STATUS_IN_PROGRESS_FILES||
1196
+ $backupRow['status']==SG_ACTION_STATUS_IN_PROGRESS_DB||
1197
+ $backupRow['status']==SG_ACTION_STATUS_CREATED)?1:0;
1198
+
1199
+ $backup['status'] = $backupRow['status'];
1200
+ $backup['type'] = (int)$backupRow['type'];
1201
+ $backup['subtype'] = (int)$backupRow['subtype'];
1202
+ $backup['progress'] = (int)$backupRow['progress'];
1203
+ $backup['id'] = (int)$backupRow['id'];
1204
+ $backup['options'] = $backupRow['options'];
1205
+ }
1206
+ else {
1207
+ $backup['active'] = 0;
1208
+ }
1209
+
1210
+ $size = '';
1211
+ if ($backup['files']) {
1212
+ $size = number_format(backupGuardRealFilesize($path.$entry.'/'.$entry.'.sgbp')/1000.0/1000.0, 2, '.', '').' MB';
1213
+ }
1214
+
1215
+ $backup['size'] = $size;
1216
+
1217
+ $modifiedTime = filemtime($path.$entry.'/.');
1218
+ $date = backupGuardConvertDateTimezone(@date('Y-m-d H:i', $modifiedTime));
1219
+ $backup['date'] = $date;
1220
+ $backup['modifiedTime'] = $modifiedTime;
1221
+ $backups[] = $backup;
1222
+ }
1223
+ closedir($handle);
1224
+ }
1225
+
1226
+ usort($backups, array('SGBackup', 'sort'));
1227
+ return array_values($backups);
1228
+ }
1229
+
1230
+ public static function sort($arg1, $arg2)
1231
+ {
1232
+ return $arg1['modifiedTime']>$arg2['modifiedTime']?-1:1;
1233
+ }
1234
+
1235
+ public static function deleteBackup($backupName, $deleteAction = true)
1236
+ {
1237
+ $isDeleteBackupFromCloudEnabled = SGConfig::get('SG_DELETE_BACKUP_FROM_CLOUD');
1238
+ if($isDeleteBackupFromCloudEnabled) {
1239
+ $backupRow = self::getActionByName($backupName);
1240
+ if ($backupRow) {
1241
+ $options = $backupRow['options'];
1242
+ if ($options) {
1243
+ $options = json_decode($options, true);
1244
+
1245
+ if (!empty($options['SG_BACKUP_UPLOAD_TO_STORAGES'])) {
1246
+ $storages = explode(',', $options['SG_BACKUP_UPLOAD_TO_STORAGES']);
1247
+ self::deleteBackupFromCloud($storages, $backupName);
1248
+ }
1249
+ }
1250
+ }
1251
+ }
1252
+
1253
+ backupGuardDeleteDirectory(SG_BACKUP_DIRECTORY.$backupName);
1254
+
1255
+ if ($deleteAction) {
1256
+ $sgdb = SGDatabase::getInstance();
1257
+ $sgdb->query('DELETE FROM '.SG_ACTION_TABLE_NAME.' WHERE name=%s', array($backupName));
1258
+ }
1259
+ }
1260
+
1261
+ private static function deleteBackupFromCloud($storages, $backupName)
1262
+ {
1263
+ foreach ($storages as $storage) {
1264
+ $storageId = 0;
1265
+ $storage = (int)$storage;
1266
+ switch ($storage) {
1267
+ case SG_STORAGE_FTP:
1268
+ $ftp = SGConfig::get('SG_STORAGE_FTP_CONNECTED');
1269
+ if ($ftp) {
1270
+ $storageId = SG_STORAGE_FTP;
1271
+ }
1272
+ break;
1273
+ case SG_STORAGE_DROPBOX:
1274
+ $dropbox = SGConfig::get('SG_DROPBOX_ACCESS_TOKEN');
1275
+ if ($dropbox) {
1276
+ $storageId = SG_STORAGE_DROPBOX;
1277
+ }
1278
+ break;
1279
+ case SG_STORAGE_GOOGLE_DRIVE:
1280
+ $gdrive = SGConfig::get('SG_GOOGLE_DRIVE_REFRESH_TOKEN');
1281
+ if ($gdrive) {
1282
+ $storageId = SG_STORAGE_GOOGLE_DRIVE;
1283
+ }
1284
+ break;
1285
+ case SG_STORAGE_AMAZON:
1286
+ $amazon = SGConfig::get('SG_STORAGE_AMAZON_CONNECTED');
1287
+ if ($amazon) {
1288
+ $storageId = SG_STORAGE_AMAZON;
1289
+ }
1290
+ break;
1291
+ case SG_STORAGE_ONE_DRIVE:
1292
+ $oneDrive = SGConfig::get('SG_ONE_DRIVE_REFRESH_TOKEN');
1293
+ if ($oneDrive) {
1294
+ $storageId = SG_STORAGE_ONE_DRIVE;
1295
+ }
1296
+ break;
1297
+ default:
1298
+ return;
1299
+ }
1300
+
1301
+ $sgBackupStorage = SGBackupStorage::getInstance();
1302
+ $sgBackupStorage->deleteBackupFromStorage($storageId, $backupName);
1303
+ }
1304
+ }
1305
+
1306
+ public static function cancelAction($actionId)
1307
+ {
1308
+ self::changeActionStatus($actionId, SG_ACTION_STATUS_CANCELLING);
1309
+ }
1310
+
1311
+ public static function importKeyFile($sgSshKeyFile)
1312
+ {
1313
+ $filename = $sgSshKeyFile['name'];
1314
+ $uploadPath = SG_BACKUP_DIRECTORY.SG_SSH_KEY_FILE_FOLDER_NAME;
1315
+ $filename = $uploadPath.$filename;
1316
+
1317
+ if (!@file_exists($uploadPath)) {
1318
+ if (!@mkdir($uploadPath)) {
1319
+ throw new SGExceptionForbidden('SSH key file folder is not accessible');
1320
+ }
1321
+ }
1322
+
1323
+ if (!empty($sgSshKeyFile) && $sgSshKeyFile['name'] != '') {
1324
+ if (!@move_uploaded_file($sgSshKeyFile['tmp_name'], $filename)) {
1325
+ throw new SGExceptionForbidden('Error while uploading ssh key file');
1326
+ }
1327
+ }
1328
+ }
1329
+
1330
+ public static function upload($filesUploadSgbp)
1331
+ {
1332
+ $filename = str_replace('.sgbp', '', $filesUploadSgbp['name']);
1333
+ $backupDirectory = $filename.'/';
1334
+ $uploadPath = SG_BACKUP_DIRECTORY.$backupDirectory;
1335
+ $filename = $uploadPath.$filename;
1336
+
1337
+ if (!@file_exists($uploadPath))
1338
+ {
1339
+ if (!@mkdir($uploadPath))
1340
+ {
1341
+ throw new SGExceptionForbidden('Upload folder is not accessible');
1342
+ }
1343
+ }
1344
+
1345
+ if (!empty($filesUploadSgbp) && $filesUploadSgbp['name'] != '')
1346
+ {
1347
+ if ($filesUploadSgbp['type'] != 'application/octet-stream')
1348
+ {
1349
+ throw new SGExceptionBadRequest('Not a valid backup file');
1350
+ }
1351
+ if (!@move_uploaded_file($filesUploadSgbp['tmp_name'], $filename.'.sgbp'))
1352
+ {
1353
+ throw new SGExceptionForbidden('Error while uploading file');
1354
+ }
1355
+ }
1356
+ }
1357
+
1358
+ public static function download($filename, $type)
1359
+ {
1360
+ $backupDirectory = SG_BACKUP_DIRECTORY.$filename.'/';
1361
+
1362
+ switch ($type)
1363
+ {
1364
+ case SG_BACKUP_DOWNLOAD_TYPE_SGBP:
1365
+ $filename .= '.sgbp';
1366
+ backupGuardDownloadFileSymlink($backupDirectory, $filename);
1367
+ break;
1368
+ case SG_BACKUP_DOWNLOAD_TYPE_BACKUP_LOG:
1369
+ $filename .= '_backup.log';
1370
+ backupGuardDownloadFile($backupDirectory.$filename, 'text/plain');
1371
+ break;
1372
+ case SG_BACKUP_DOWNLOAD_TYPE_RESTORE_LOG:
1373
+ $filename .= '_restore.log';
1374
+ backupGuardDownloadFile($backupDirectory.$filename, 'text/plain');
1375
+ break;
1376
+ }
1377
+
1378
+ exit;
1379
+ }
1380
+
1381
+ /* SGIBackupDelegate implementation */
1382
+
1383
+ public function isCancelled()
1384
+ {
1385
+ $status = $this->getCurrentActionStatus();
1386
+
1387
+ if ($status==SG_ACTION_STATUS_CANCELLING)
1388
+ {
1389
+ $this->cancel();
1390
+ return true;
1391
+ }
1392
+
1393
+ return false;
1394
+ }
1395
+
1396
+ public function didUpdateProgress($progress)
1397
+ {
1398
+ $progress = max($progress, 0);
1399
+ $progress = min($progress, 100);
1400
+
1401
+ self::changeActionProgress($this->actionId, $progress);
1402
+ }
1403
+
1404
+ public function isBackgroundMode()
1405
+ {
1406
+ return $this->backgroundMode;
1407
+ }
1408
+ }
com/core/backup/SGBackupDatabase.php ADDED
@@ -0,0 +1,643 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(SG_BACKUP_PATH.'SGIBackupDelegate.php');
4
+ require_once(SG_LIB_PATH.'SGDBState.php');
5
+ require_once(SG_LIB_PATH.'SGMysqldump.php');
6
+ require_once(SG_LIB_PATH.'SGCharsetHandler.php');
7
+ @include_once(SG_LIB_PATH.'SGMigrate.php');
8
+
9
+ class SGBackupDatabase implements SGIMysqldumpDelegate
10
+ {
11
+ private $sgdb = null;
12
+ private $backupFilePath = '';
13
+ private $delegate = null;
14
+ private $cancelled = false;
15
+ private $nextProgressUpdate = 0;
16
+ private $totalRowCount = 0;
17
+ private $currentRowCount = 0;
18
+ private $warningsFound = false;
19
+ private $pendingStorageUploads = array();
20
+ private $state = null;
21
+ private $reloadStartTs = null;
22
+ private $progressUpdateInterval;
23
+ private $migrationAvailable = null;
24
+ private $oldDbPrefix = null;
25
+ private $backedUpTables = null;
26
+ private $newTableNames = null;
27
+ private $migrateObj = null;
28
+ private $charsetHanlder = null;
29
+
30
+ public function __construct()
31
+ {
32
+ $this->sgdb = SGDatabase::getInstance();
33
+ $this->progressUpdateInterval = SGConfig::get('SG_ACTION_PROGRESS_UPDATE_INTERVAL');
34
+ }
35
+
36
+ public function setDelegate(SGIBackupDelegate $delegate)
37
+ {
38
+ $this->delegate = $delegate;
39
+ }
40
+
41
+ public function setFilePath($filePath)
42
+ {
43
+ $this->backupFilePath = $filePath;
44
+ }
45
+
46
+ public function isMigrationAvailable()
47
+ {
48
+ if ($this->migrationAvailable === null) {
49
+ $this->migrationAvailable = SGBoot::isFeatureAvailable('BACKUP_WITH_MIGRATION');
50
+ }
51
+
52
+ return $this->migrationAvailable;
53
+ }
54
+
55
+ public function getOldDbPrefix()
56
+ {
57
+ if ($this->oldDbPrefix === null) {
58
+ $this->oldDbPrefix = SGConfig::get('SG_OLD_DB_PREFIX');
59
+ }
60
+
61
+ return $this->oldDbPrefix;
62
+ }
63
+
64
+ public function getBackedUpTables()
65
+ {
66
+ if ($this->backedUpTables === null) {
67
+ $tableNames = SGConfig::get('SG_BACKUPED_TABLES');
68
+ if ($tableNames) {
69
+ $tableNames = json_decode($tableNames, true);
70
+ }
71
+ else {
72
+ $tableNames = array();
73
+ }
74
+ $this->backedUpTables = $tableNames;
75
+ }
76
+
77
+ return $this->backedUpTables;
78
+ }
79
+
80
+ public function getNewTableNames()
81
+ {
82
+ if ($this->newTableNames === null) {
83
+ $oldDbPrefix = $this->getOldDbPrefix();
84
+ $tableNames = $this->getBackedUpTables();
85
+
86
+ $newTableNames = array();
87
+ foreach ($tableNames as $tableName) {
88
+ $newTableNames[] = str_replace($oldDbPrefix, SG_ENV_DB_PREFIX, $tableName);
89
+ }
90
+ $this->newTableNames = $newTableNames;
91
+ }
92
+
93
+ return $this->newTableNames;
94
+ }
95
+
96
+ public function getMigrateObj()
97
+ {
98
+ if ($this->migrateObj === null) {
99
+ $this->migrateObj = new SGMigrate();
100
+ }
101
+
102
+ return $this->migrateObj;
103
+ }
104
+
105
+ public function getCharsetHandler()
106
+ {
107
+ if ($this->charsetHanlder === null) {
108
+ $this->charsetHanlder = new SGCharsetHandler();
109
+ }
110
+
111
+ return $this->charsetHanlder;
112
+ }
113
+
114
+ public function didFindWarnings()
115
+ {
116
+ return $this->warningsFound;
117
+ }
118
+
119
+ public function setPendingStorageUploads($pendingStorageUploads)
120
+ {
121
+ $this->pendingStorageUploads = $pendingStorageUploads;
122
+ }
123
+
124
+ public function saveStateData($offset, $cursor, $inprogress, $lineSize, $backedUpTables)
125
+ {
126
+ $sgDBState = $this->getState();
127
+ $token = $this->delegate->getToken();
128
+
129
+ $sgDBState->setLineSize($lineSize);
130
+ $sgDBState->setNumberOfEntries($this->totalRowCount);
131
+ $sgDBState->setAction(SG_STATE_ACTION_EXPORTING_SQL);
132
+ $sgDBState->setInprogress($inprogress);
133
+ $sgDBState->setCursor($cursor);
134
+ $sgDBState->setProgressCursor($this->currentRowCount);
135
+ $sgDBState->setOffset($offset);
136
+ $sgDBState->setToken($token);
137
+ $sgDBState->setProgress($this->nextProgressUpdate);
138
+ $sgDBState->setWarningsFound($this->warningsFound);
139
+ $sgDBState->setPendingStorageUploads($this->pendingStorageUploads);
140
+ $sgDBState->setBackedUpTables($backedUpTables);
141
+ $sgDBState->save();
142
+ }
143
+
144
+ public function getState()
145
+ {
146
+ return $this->delegate->getState();
147
+ }
148
+
149
+ public function shouldReload()
150
+ {
151
+ $currentTime = time();
152
+
153
+ if (($currentTime - $this->reloadStartTs) >= SG_RELOAD_TIMEOUT) {
154
+ return true;
155
+ }
156
+
157
+ return false;
158
+ }
159
+
160
+ public function reload()
161
+ {
162
+ $this->delegate->reload();
163
+ }
164
+
165
+ public function backup($filePath)
166
+ {
167
+ $this->reloadStartTs = time();
168
+ $this->state = $this->delegate->getState();
169
+
170
+ if ($this->state && $this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
171
+ SGBackupLog::writeAction('backup database', SG_BACKUP_LOG_POS_START);
172
+ $this->resetBackupProgress();
173
+ }
174
+ else {
175
+ $this->totalRowCount = $this->state->getNumberOfEntries();
176
+ $this->currentRowCount = $this->state->getProgressCursor();
177
+ }
178
+
179
+ $this->backupFilePath = $filePath;
180
+
181
+ $this->export();
182
+
183
+ SGBackupLog::writeAction('backup database', SG_BACKUP_LOG_POS_END);
184
+ }
185
+
186
+ public function restore($filePath)
187
+ {
188
+ $this->reloadStartTs = time();
189
+ $this->backupFilePath = $filePath;
190
+
191
+ $sgDBState = $this->getState();
192
+ if ($sgDBState && $sgDBState->getType() == SG_STATE_TYPE_DB) {
193
+ if ($sgDBState->getAction() != SG_STATE_ACTION_RESTORING_DATABASE) {
194
+ SGBackupLog::writeAction('restore database', SG_BACKUP_LOG_POS_START);
195
+ //prepare for restore (reset variables)
196
+ $this->resetRestoreProgress();
197
+ }
198
+ //import all db tables
199
+ $this->import();
200
+ }
201
+
202
+ //run migration logic
203
+ if ($this->isMigrationAvailable()) {
204
+ if ($sgDBState->getAction() != SG_STATE_ACTION_MIGRATING_DATABASE) {
205
+ $this->delegate->prepareMigrateStateFile();
206
+ }
207
+
208
+ $this->processMigration();
209
+ }
210
+
211
+ //external restore file doesn't have the wordpress functions
212
+ //so we cannot do anything here
213
+ //it will finalize the restore for itself
214
+ if (!SGExternalRestore::isEnabled()) {
215
+ $this->finalizeRestore();
216
+ }
217
+
218
+ SGBackupLog::writeAction('restore database', SG_BACKUP_LOG_POS_END);
219
+ }
220
+
221
+ private function processMigration()
222
+ {
223
+ $sgMigrateState = $this->getState();
224
+ if ($sgMigrateState && $sgMigrateState->getAction() != SG_STATE_ACTION_MIGRATING_DATABASE) {
225
+ SGBackupLog::writeAction('migration', SG_BACKUP_LOG_POS_START);
226
+ }
227
+
228
+ $sgMigrate = new SGMigrate($this->sgdb);
229
+ $sgMigrate->setDelegate($this);
230
+
231
+ $tables = $this->getTables();
232
+
233
+ $oldSiteUrl = SGConfig::get('SG_OLD_SITE_URL');
234
+
235
+ // Find and replace old urls with new ones
236
+ $sgMigrate->migrate($oldSiteUrl, SG_SITE_URL, $tables);
237
+
238
+ // Find and replace old db prefixes with new ones
239
+ $sgMigrate->migrateDBPrefix();
240
+
241
+ $isMultisite = backupGuardIsMultisite();
242
+ if ($isMultisite) {
243
+ $tables = explode(',', SG_MULTISITE_TABLES_TO_MIGRATE);
244
+
245
+ $oldPath = SGConfig::get('SG_MULTISITE_OLD_PATH');
246
+ $newPath = PATH_CURRENT_SITE;
247
+ $newDomain = DOMAIN_CURRENT_SITE;
248
+
249
+ $sgMigrate->migrateMultisite($newDomain, $newPath, $oldPath, $tables);
250
+ }
251
+
252
+ SGBackupLog::writeAction('migration', SG_BACKUP_LOG_POS_END);
253
+ }
254
+
255
+ public function finalizeRestore()
256
+ {
257
+ if (SG_ENV_ADAPTER != SG_ENV_WORDPRESS) {
258
+ return;
259
+ }
260
+
261
+ //recreate current user (to be able to login with it)
262
+ $this->restoreCurrentUser();
263
+
264
+ //setting the following options will tell WordPress that the db is already updated
265
+ global $wp_db_version;
266
+ update_option('db_version', $wp_db_version);
267
+ update_option('db_upgraded', true);
268
+
269
+ //fix invalid upload path inserted in db
270
+ update_option("upload_path", "");
271
+ }
272
+
273
+ private function export()
274
+ {
275
+ if ($this->state && $this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
276
+ if (!$this->isWritable($this->backupFilePath)) {
277
+ throw new SGExceptionForbidden('Permission denied. File is not writable: '.$this->backupFilePath);
278
+ }
279
+ }
280
+
281
+ $customTablesToExclude = str_replace(' ', '', SGConfig::get('SG_TABLES_TO_EXCLUDE'));
282
+ $tablesToExclude = explode(',', SGConfig::get('SG_BACKUP_DATABASE_EXCLUDE').','.$customTablesToExclude);
283
+
284
+ $tablesToBackup = $this->state->getTablesToBackup() ? explode(',', $this->state->getTablesToBackup()) : array();
285
+ $dump = new SGMysqldump($this->sgdb, SG_DB_NAME, 'mysql', array(
286
+ 'exclude-tables'=>$tablesToExclude,
287
+ 'include-tables'=>$tablesToBackup,
288
+ 'skip-dump-date'=>true,
289
+ 'skip-comments'=>true,
290
+ 'skip-tz-utz'=>true,
291
+ 'add-drop-table'=>true,
292
+ 'no-autocommit'=>false,
293
+ 'single-transaction'=>false,
294
+ 'lock-tables'=>false,
295
+ 'default-character-set'=>SG_DB_CHARSET,
296
+ 'add-locks'=>false
297
+ ));
298
+
299
+ $dump->setDelegate($this);
300
+
301
+ $dump->start($this->backupFilePath);
302
+ }
303
+
304
+ private function prepareQueryToExec($query)
305
+ {
306
+ $query = $this->replaceInvalidCharacters($query);
307
+ $query = $this->replaceInvalidEngineTypeInQuery($query);
308
+
309
+ if ($this->isMigrationAvailable()) {
310
+ $tableNames = $this->getBackedUpTables();
311
+ $newTableNames = $this->getNewTableNames();
312
+ $query = $this->getMigrateObj()->replaceValuesInQuery($tableNames, $newTableNames, $query);
313
+ }
314
+
315
+ $query = $this->getCharsetHandler()->replaceInvalidCharsets($query);
316
+
317
+ $query = rtrim(trim($query), "/*SGEnd*/");
318
+
319
+ return $query;
320
+ }
321
+
322
+ private function replaceInvalidEngineTypeInQuery($query)
323
+ {
324
+ if (version_compare(SG_MYSQL_VERSION, '5.1', '>=')) {
325
+ return str_replace("TYPE=InnoDB", "ENGINE=InnoDB", $query);
326
+ }
327
+ else {
328
+ return str_replace("ENGINE=InnoDB", "TYPE=InnoDB", $query);
329
+ }
330
+ }
331
+
332
+ private function replaceInvalidCharacters($str)
333
+ {
334
+ return preg_replace('/\x00/', '', $str);;
335
+ }
336
+
337
+ private function getDatabaseHeaders()
338
+ {
339
+ return "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;/*SGEnd*/".PHP_EOL.
340
+ "/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;/*SGEnd*/".PHP_EOL.
341
+ "/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;/*SGEnd*/".PHP_EOL.
342
+ "/*!40101 SET NAMES ".SG_DB_CHARSET." */;/*SGEnd*/".PHP_EOL.
343
+ "/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;/*SGEnd*/".PHP_EOL.
344
+ "/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;/*SGEnd*/".PHP_EOL.
345
+ "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;/*SGEnd*/".PHP_EOL.
346
+ "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;/*SGEnd*/".PHP_EOL;
347
+ }
348
+
349
+ private function import()
350
+ {
351
+ $fileHandle = @fopen($this->backupFilePath, 'r');
352
+ if (!is_resource($fileHandle)) {
353
+ throw new SGExceptionForbidden('Could not open file: '.$this->backupFilePath);
354
+ }
355
+
356
+ $importQuery = '';
357
+ $sgDBState = $this->getState();
358
+ if ($sgDBState && $sgDBState->getAction() == SG_STATE_ACTION_RESTORING_DATABASE) {
359
+ $offset = $sgDBState->getOffset();
360
+ fseek($fileHandle, $offset);
361
+
362
+ $this->totalRowCount = $sgDBState->getNumberOfEntries();
363
+ $this->currentRowCount = $sgDBState->getProgressCursor();
364
+ $this->nextProgressUpdate = $sgDBState->getProgress();
365
+ $this->warningsFound = $sgDBState->getWarningsFound();
366
+ }
367
+
368
+ while (($row = @fgets($fileHandle)) !== false) {
369
+ $importQuery .= $row;
370
+ $trimmedRow = trim($row);
371
+
372
+ if (strpos($trimmedRow, 'CREATE TABLE') !== false) {
373
+ $strLength = strlen($trimmedRow);
374
+ $strCtLength = strlen('CREATE TABLE ');
375
+ $length = $strLength - $strCtLength - 2;
376
+ $tableName = substr($trimmedRow, $strCtLength, $length);
377
+
378
+ SGBackupLog::write('Importing table: '.$tableName);
379
+ }
380
+
381
+ if ($trimmedRow && substr($trimmedRow, -9) == "/*SGEnd*/") {
382
+ $queries = explode("/*SGEnd*/".PHP_EOL, $this->getDatabaseHeaders().$importQuery);
383
+ foreach ($queries as $query) {
384
+ if (!$query) {
385
+ continue;
386
+ }
387
+
388
+ $importQuery = $this->prepareQueryToExec($query);
389
+
390
+ SGPing::update();
391
+ $res = $this->sgdb->execRaw($importQuery);
392
+ if ($res === false) {
393
+ //continue restoring database if any query fails
394
+ //we will just show a warning inside the log
395
+
396
+ if (isset($tableName)) {
397
+ $this->warn('Could not import table: '.$tableName);
398
+ }
399
+
400
+ $this->warn('Error: '.$this->sgdb->getLastError());
401
+ }
402
+
403
+ $shouldReload = $this->shouldReload();
404
+ $isReloadEnabled = backupGuardIsReloadEnabled();
405
+ if ($shouldReload && $isReloadEnabled && SGExternalRestore::isEnabled()) {
406
+ $offset = ftell($fileHandle);
407
+ $token = $this->delegate->getToken();
408
+
409
+ $sgDBState = $this->getState();
410
+
411
+ $sgDBState->setToken($token);
412
+ $sgDBState->setOffset($offset);
413
+ $sgDBState->setProgress($this->nextProgressUpdate);
414
+ $sgDBState->setWarningsFound($this->warningsFound);
415
+ $sgDBState->setNumberOfEntries($this->totalRowCount);
416
+ $sgDBState->setProgressCursor($this->currentRowCount);
417
+ $sgDBState->setActionId($this->delegate->getActionId());
418
+ $sgDBState->setAction(SG_STATE_ACTION_RESTORING_DATABASE);
419
+
420
+ $sgDBState->save();
421
+
422
+ SGPing::update();
423
+ @fclose($fileHandle);
424
+
425
+ $this->reload();
426
+ }
427
+ }
428
+
429
+ $importQuery = '';
430
+ }
431
+
432
+ $this->currentRowCount++;
433
+ SGPing::update();
434
+ $this->updateProgress();
435
+ }
436
+
437
+ @fclose($fileHandle);
438
+ }
439
+
440
+ public function saveCurrentUser()
441
+ {
442
+ if (SG_ENV_ADAPTER != SG_ENV_WORDPRESS) {
443
+ return;
444
+ }
445
+
446
+ $user = wp_get_current_user();
447
+
448
+ $currentUser = serialize(array(
449
+ 'login' => $user->user_login,
450
+ 'pass' => $user->user_pass,
451
+ 'email' => $user->user_email,
452
+ ));
453
+
454
+ SGConfig::set('SG_CURRENT_USER', $currentUser);
455
+ }
456
+
457
+ private function restoreCurrentUser()
458
+ {
459
+ $currentUser = SGConfig::get('SG_CURRENT_USER');
460
+ $user = unserialize($currentUser);
461
+
462
+ //erase user data from the config table
463
+ SGConfig::set('SG_CURRENT_USER', '');
464
+
465
+ //if a user is found, it means it's cache, because we have dropped wp_users already
466
+ $cachedUser = get_user_by('login', $user['login']);
467
+ if ($cachedUser) {
468
+ clean_user_cache($cachedUser); //delete user from cache
469
+ }
470
+
471
+ //create a user (it will be a subscriber)
472
+ $id = wp_create_user($user['login'], $user['pass'], $user['email']);
473
+ if (is_wp_error($id)) {
474
+ SGBackupLog::write('User not recreated: '.$id->get_error_message());
475
+ return false; //user was not created for some reason
476
+ }
477
+
478
+ //get the newly created user
479
+ $newUser = get_user_by('id', $id);
480
+
481
+ //remove its role of subscriber
482
+ $newUser->remove_role('subscriber');
483
+ $isMultisite = backupGuardIsMultisite();
484
+
485
+ if ($isMultisite) {
486
+ // add super adminn role
487
+ grant_super_admin($id);
488
+ }
489
+ else {
490
+ //add admin role
491
+ $newUser->add_role('administrator');
492
+ }
493
+
494
+ //update password to set the correct (old) password
495
+ $this->sgdb->query(
496
+ 'UPDATE '.SG_ENV_DB_PREFIX.'users SET user_pass=%s WHERE ID=%d',
497
+ array(
498
+ $user['pass'],
499
+ $id
500
+ )
501
+ );
502
+
503
+ //clean cache, so new password can take effect
504
+ clean_user_cache($newUser);
505
+
506
+ SGBackupLog::write('User recreated: '.$user['login']);
507
+ }
508
+
509
+ public function warn($message)
510
+ {
511
+ $this->warningsFound = true;
512
+ SGBackupLog::writeWarning($message);
513
+ }
514
+
515
+ public function didExportRow()
516
+ {
517
+ $this->currentRowCount++;
518
+ SGPing::update();
519
+
520
+ if ($this->updateProgress())
521
+ {
522
+ if ($this->delegate && $this->delegate->isCancelled())
523
+ {
524
+ $this->cancelled = true;
525
+ return;
526
+ }
527
+ }
528
+
529
+ if (SGBoot::isFeatureAvailable('BACKGROUND_MODE') && $this->delegate->isBackgroundMode())
530
+ {
531
+ SGBackgroundMode::next();
532
+ }
533
+ }
534
+
535
+ public function cancel()
536
+ {
537
+ @unlink($this->filePath);
538
+ }
539
+
540
+ private function resetBackupProgress()
541
+ {
542
+ $this->totalRowCount = 0;
543
+ $this->currentRowCount = 0;
544
+ $tableNames = $this->getTables();
545
+ foreach ($tableNames as $table)
546
+ {
547
+ $this->totalRowCount += $this->getTableRowsCount($table);
548
+ }
549
+ $this->nextProgressUpdate = $this->progressUpdateInterval;
550
+ SGBackupLog::write('Total tables to backup: '.count($tableNames));
551
+ SGBackupLog::write('Total rows to backup: '.$this->totalRowCount);
552
+ }
553
+
554
+ private function resetRestoreProgress()
555
+ {
556
+ $this->totalRowCount = $this->getFileLinesCount($this->backupFilePath);
557
+ $this->currentRowCount = 0;
558
+ $this->progressUpdateInterval = SGConfig::get('SG_ACTION_PROGRESS_UPDATE_INTERVAL');
559
+ $this->nextProgressUpdate = $this->progressUpdateInterval;
560
+ }
561
+
562
+ private function getTables()
563
+ {
564
+ $tableNames = array();
565
+ $tables = $this->sgdb->query('SHOW TABLES FROM `'.SG_DB_NAME.'`');
566
+ if (!$tables)
567
+ {
568
+ throw new SGExceptionDatabaseError('Could not get tables of database: '.SG_DB_NAME);
569
+ }
570
+ foreach ($tables as $table)
571
+ {
572
+ $tableName = $table['Tables_in_'.SG_DB_NAME];
573
+ $tablesToExclude = explode(',', SGConfig::get('SG_BACKUP_DATABASE_EXCLUDE'));
574
+ if (in_array($tableName, $tablesToExclude))
575
+ {
576
+ continue;
577
+ }
578
+ $tableNames[] = $tableName;
579
+ }
580
+ return $tableNames;
581
+ }
582
+
583
+ private function getTableRowsCount($tableName)
584
+ {
585
+ $count = 0;
586
+ $tableRowsNum = $this->sgdb->query('SELECT COUNT(*) AS total FROM '.$tableName);
587
+ $count = @$tableRowsNum[0]['total'];
588
+ return $count;
589
+ }
590
+
591
+ private function getFileLinesCount($filePath)
592
+ {
593
+ $fileHandle = @fopen($filePath, 'rb');
594
+ if (!is_resource($fileHandle))
595
+ {
596
+ throw new SGExceptionForbidden('Could not open file: '.$filePath);
597
+ }
598
+
599
+ $linecount = 0;
600
+ while (!feof($fileHandle))
601
+ {
602
+ $linecount += substr_count(fread($fileHandle, 8192), "\n");
603
+ }
604
+
605
+ @fclose($fileHandle);
606
+ return $linecount;
607
+ }
608
+
609
+ private function updateProgress()
610
+ {
611
+ $progress = round($this->currentRowCount*100.0/$this->totalRowCount);
612
+
613
+ if ($progress>=$this->nextProgressUpdate)
614
+ {
615
+ $this->nextProgressUpdate += $this->progressUpdateInterval;
616
+
617
+ if ($this->delegate)
618
+ {
619
+ $this->delegate->didUpdateProgress($progress);
620
+ }
621
+
622
+ return true;
623
+ }
624
+
625
+ return false;
626
+ }
627
+
628
+ /* Helper Functions */
629
+
630
+ private function isWritable($filePath)
631
+ {
632
+ if (!file_exists($filePath))
633
+ {
634
+ $fp = @fopen($filePath, 'wb');
635
+ if (!$fp)
636
+ {
637
+ throw new SGExceptionForbidden('Could not open file: '.$filePath);
638
+ }
639
+ @fclose($fp);
640
+ }
641
+ return is_writable($filePath);
642
+ }
643
+ }
com/core/backup/SGBackupFiles.php ADDED
@@ -0,0 +1,510 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_BACKUP_PATH.'SGIBackupDelegate.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+ require_once(SG_LIB_PATH.'SGArchive.php');
5
+ require_once(SG_LIB_PATH.'SGReloadHandler.php');
6
+ require_once(SG_LIB_PATH.'SGFileState.php');
7
+
8
+ require_once(SG_LIB_PATH.'SGFileEntry.php');
9
+ require_once(SG_LIB_PATH.'SGCdrEntry.php');
10
+
11
+ class SGBackupFiles implements SGArchiveDelegate
12
+ {
13
+ const BUFFER_SIZE = 1000; // max files count to keep in buffer before writing to file tree
14
+ private $rootDirectory = '';
15
+ private $excludeFilePaths = array();
16
+ private $filePath = '';
17
+ private $sgbp = null;
18
+ private $delegate = null;
19
+ private $nextProgressUpdate = 0;
20
+ private $progressUpdateInterval = 0;
21
+ private $warningsFound = false;
22
+ private $dontExclude = array();
23
+ private $cdrSize = 0;
24
+ private $pendingStorageUploads = array();
25
+ private $fileName = '';
26
+ private $progressCursor = 0;
27
+ private $numberOfEntries = 0;
28
+ private $cursor = 0;
29
+ private $reloadStartTs;
30
+
31
+ public function __construct()
32
+ {
33
+ $this->rootDirectory = rtrim(SGConfig::get('SG_APP_ROOT_DIRECTORY'), '/').'/';
34
+ $this->progressUpdateInterval = SGConfig::get('SG_ACTION_PROGRESS_UPDATE_INTERVAL');
35
+ }
36
+
37
+ public function setDelegate(SGIBackupDelegate $delegate)
38
+ {
39
+ $this->delegate = $delegate;
40
+ }
41
+
42
+ public function setFilePath($filePath)
43
+ {
44
+ $this->filePath = $filePath;
45
+ }
46
+
47
+ public function setFileName($fileName)
48
+ {
49
+ $this->fileName = $fileName;
50
+ }
51
+
52
+ public function setPendingStorageUploads($pendingStorageUploads)
53
+ {
54
+ $this->pendingStorageUploads = $pendingStorageUploads;
55
+ }
56
+
57
+ public function addDontExclude($ex)
58
+ {
59
+ $this->dontExclude[] = $ex;
60
+ }
61
+
62
+ public function didExtractArchiveMeta($meta)
63
+ {
64
+ $file = dirname($this->filePath).'/'.$this->fileName.'_restore.log';
65
+
66
+ if (file_exists($file)) {
67
+ $archiveVersion = SGConfig::get('SG_CURRENT_ARCHIVE_VERSION');
68
+
69
+ $content = '';
70
+ $content .= '---'.PHP_EOL;
71
+ $content .= 'Archive version: '.$archiveVersion.PHP_EOL;
72
+ $content .= 'Archive database prefix: '.$meta['dbPrefix'].PHP_EOL;
73
+ $content .= 'Archive site URL: '.$meta['siteUrl'].PHP_EOL.PHP_EOL;
74
+
75
+ file_put_contents($file, $content, FILE_APPEND);
76
+ }
77
+ }
78
+
79
+ public function didFindWarnings()
80
+ {
81
+ return $this->warningsFound;
82
+ }
83
+
84
+ private function addEntriesInFileTree($entries)
85
+ {
86
+ foreach ($entries as $entry) {
87
+ file_put_contents(dirname($this->filePath).'/'.SG_TREE_FILE_NAME, serialize($entry)."\n", FILE_APPEND);
88
+ }
89
+ }
90
+
91
+ private function loadFileTree()
92
+ {
93
+ $allItems = file_get_contents(dirname($this->filePath).'/'.SG_TREE_FILE_NAME);
94
+ return unserialize($allItems);
95
+ }
96
+
97
+ public function shouldReload()
98
+ {
99
+ $currentTime = time();
100
+
101
+ if (($currentTime - $this->reloadStartTs) >= SG_RELOAD_TIMEOUT) {
102
+ return true;
103
+ }
104
+
105
+ return false;
106
+ }
107
+
108
+ public function getState()
109
+ {
110
+ return $this->delegate->getState();
111
+ }
112
+
113
+ public function backup($filePath, $options, $state)
114
+ {
115
+ $this->reloadStartTs = time();
116
+ if ($state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
117
+ SGBackupLog::writeAction('backup files', SG_BACKUP_LOG_POS_START);
118
+ }
119
+
120
+ if (strlen($options['SG_BACKUP_FILE_PATHS_EXCLUDE'])) {
121
+ $excludePaths = $options['SG_BACKUP_FILE_PATHS_EXCLUDE'];
122
+ $userCustomExcludes = SGConfig::get('SG_PATHS_TO_EXCLUDE');
123
+ if (!empty($userCustomExcludes)) {
124
+ $excludePaths .= ','.$userCustomExcludes;
125
+ }
126
+
127
+ $this->excludeFilePaths = explode(',', $excludePaths);
128
+ }
129
+ else{
130
+ $this->excludeFilePaths = array();
131
+ }
132
+
133
+ $this->filePath = $filePath;
134
+ $backupItems = $options['SG_BACKUP_FILE_PATHS'];
135
+ $allItems = explode(',', $backupItems);
136
+
137
+ if (!is_writable($filePath)) {
138
+ throw new SGExceptionForbidden('Could not create backup file: '.$filePath);
139
+ }
140
+
141
+ if ($state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
142
+ SGBackupLog::write('Backup files: '.$backupItems);
143
+
144
+ $this->resetProgress();
145
+ $this->prepareFileTree($allItems);
146
+
147
+ $this->saveStateData(SG_STATE_ACTION_LISTING_FILES, array(), 0, 0, false, 0);
148
+
149
+ SGBackupLog::write('Number of files to backup: '.$this->numberOfEntries);
150
+
151
+ if (backupGuardIsReloadEnabled()) {
152
+ $this->reload();
153
+ }
154
+ }
155
+ else {
156
+ $this->nextProgressUpdate = $state->getProgress();
157
+ $this->warningsFound = $state->getWarningsFound();
158
+
159
+ $this->numberOfEntries = $state->getNumberOfEntries();
160
+ $this->progressCursor = $state->getProgressCursor();
161
+ }
162
+
163
+ $this->cdrSize = $state->getCdrSize();
164
+ $this->sgbp = new SGArchive($filePath, 'a', $this->cdrSize);
165
+ $this->sgbp->setDelegate($this);
166
+
167
+ $this->cursor = $state->getCursor();
168
+
169
+ if (file_exists(dirname($this->filePath).'/'.SG_TREE_FILE_NAME)) {
170
+ $fileTreeHandle = fopen(dirname($this->filePath).'/'.SG_TREE_FILE_NAME, 'r');
171
+ if ($fileTreeHandle) {
172
+ fseek($fileTreeHandle, $this->cursor);
173
+ while (($fileTreeLine = fgets($fileTreeHandle)) !== false) {
174
+ $file = unserialize($fileTreeLine);
175
+
176
+ if (!$state->getInprogress()) {
177
+ SGBackupLog::writeAction('backup file: '.$file['path'], SG_BACKUP_LOG_POS_START);
178
+ }
179
+
180
+ $path = $file['path'];
181
+ $this->addFileToArchive($path);
182
+ SGBackupLog::writeAction('backup file: '.$file['path'], SG_BACKUP_LOG_POS_END);
183
+
184
+ $this->cursor = ftell($fileTreeHandle);
185
+ $this->cdrSize = $this->sgbp->getCdrFilesCount();
186
+ $this->saveStateData(SG_STATE_ACTION_COMPRESSING_FILES, array(), 0, 0, false, $state->getFileOffsetInArchive());
187
+ }
188
+ }
189
+ }
190
+
191
+ $this->sgbp->finalize();
192
+ $this->clear();
193
+
194
+ SGBackupLog::writeAction('backup files', SG_BACKUP_LOG_POS_END);
195
+ }
196
+
197
+ private function clear()
198
+ {
199
+ @unlink(dirname($this->filePath).'/'.SG_TREE_FILE_NAME);
200
+ }
201
+
202
+ public function reload()
203
+ {
204
+ $this->delegate->reload();
205
+ }
206
+
207
+ public function getToken()
208
+ {
209
+ return $this->delegate->getToken();
210
+ }
211
+
212
+ public function getProgress()
213
+ {
214
+ return $this->nextProgressUpdate;
215
+ }
216
+
217
+ public function saveStateData($action, $ranges = array(), $offset = 0, $headerSize = 0, $inprogress = false, $fileOfssetInArchive = 0)
218
+ {
219
+ $sgFileState = $this->delegate->getState();
220
+ $token = $this->getToken();
221
+
222
+ $sgFileState->setInprogress($inprogress);
223
+ $sgFileState->setHeaderSize($headerSize);
224
+ $sgFileState->setRanges($ranges);
225
+ $sgFileState->setOffset($offset);
226
+ $sgFileState->setToken($token);
227
+ $sgFileState->setAction($action);
228
+ $sgFileState->setProgress($this->nextProgressUpdate);
229
+ $sgFileState->setWarningsFound($this->warningsFound);
230
+ $sgFileState->setCdrSize($this->cdrSize);
231
+ $sgFileState->setPendingStorageUploads($this->pendingStorageUploads);
232
+ $sgFileState->setNumberOfEntries($this->numberOfEntries);
233
+ $sgFileState->setCursor($this->cursor);
234
+ $sgFileState->setFileOffsetInArchive($fileOfssetInArchive);
235
+ $sgFileState->setProgressCursor($this->progressCursor);
236
+
237
+ $sgFileState->save();
238
+ }
239
+
240
+ public function didStartRestoreFiles()
241
+ {
242
+ //start logging
243
+ SGBackupLog::writeAction('restore', SG_BACKUP_LOG_POS_START);
244
+ SGBackupLog::writeAction('restore files', SG_BACKUP_LOG_POS_START);
245
+ }
246
+
247
+ public function restore($filePath)
248
+ {
249
+ $this->reloadStartTs = time();
250
+ $state = $this->getState();
251
+ $this->filePath = $filePath;
252
+ $this->resetProgress();
253
+ $this->warningsFound = false;
254
+
255
+ if ($state) {
256
+ $this->nextProgressUpdate = $state->getProgress();
257
+ $this->warningsFound = $state->getWarningsFound();
258
+ $this->progressCursor = $state->getCursor();
259
+ $this->numberOfEntries = $state->getCdrSize();
260
+ }
261
+
262
+ $this->extractArchive($filePath);
263
+ SGBackupLog::writeAction('restore files', SG_BACKUP_LOG_POS_END);
264
+ }
265
+
266
+ private function extractArchive($filePath)
267
+ {
268
+ $restorePath = $this->rootDirectory;
269
+
270
+ $state = $this->getState();
271
+ $sgbp = new SGArchive($filePath, 'r');
272
+ $sgbp->setDelegate($this);
273
+ $sgbp->extractTo($restorePath, $state);
274
+ }
275
+
276
+ public function getCorrectCdrFilename($filename)
277
+ {
278
+ $backupsPath = $this->pathWithoutRootDirectory(realpath(SG_BACKUP_DIRECTORY));
279
+
280
+ if (strpos($filename, $backupsPath)===0)
281
+ {
282
+ $newPath = dirname($this->pathWithoutRootDirectory(realpath($this->filePath)));
283
+ $filename = substr(basename(trim($this->filePath)), 0, -4); //remove sgbp extension
284
+ return $newPath.'/'.$filename.'sql';
285
+ }
286
+
287
+ return $filename;
288
+ }
289
+
290
+ public function didStartExtractFile($filePath)
291
+ {
292
+ SGBackupLog::write('Start restore file: '.$filePath);
293
+ }
294
+
295
+ public function didExtractFile($filePath)
296
+ {
297
+ //update progress
298
+ $this->progressCursor++;
299
+ $this->updateProgress();
300
+
301
+ SGBackupLog::write('End restore file: '.$filePath);
302
+ }
303
+
304
+ public function didFindExtractError($error)
305
+ {
306
+ $this->warn($error);
307
+ }
308
+
309
+ public function didCountFilesInsideArchive($count)
310
+ {
311
+ $this->numberOfEntries = $count;
312
+ SGBackupLog::write('Number of files to restore: '.$count);
313
+ }
314
+
315
+ private function prepareFileTree($allItems)
316
+ {
317
+ $entries = array();
318
+
319
+ foreach ($allItems as $item) {
320
+ $path = $this->rootDirectory.$item;
321
+ $this->addDirectoryEntriesInFileTree($path, $entries);
322
+ }
323
+
324
+ if (count($entries)) {
325
+ $this->addEntriesInFileTree($entries);
326
+ }
327
+ }
328
+
329
+ private function resetProgress()
330
+ {
331
+ $this->progressCursor = 0;
332
+ $this->nextProgressUpdate = $this->progressUpdateInterval;
333
+ }
334
+
335
+ private function pathWithoutRootDirectory($path)
336
+ {
337
+ return substr($path, strlen($this->rootDirectory));
338
+ }
339
+
340
+ private function shouldExcludeFile($path)
341
+ {
342
+ if (in_array($path, $this->dontExclude)) {
343
+ return false;
344
+ }
345
+
346
+ //get the name of the file/directory removing the root directory
347
+ $file = $this->pathWithoutRootDirectory($path);
348
+
349
+ //check if file/directory must be excluded
350
+ foreach ($this->excludeFilePaths as $exPath) {
351
+ $exPath = trim($exPath);
352
+ $exPath = trim($exPath, '/');
353
+ if (strpos($file, $exPath)===0) {
354
+ return true;
355
+ }
356
+ }
357
+
358
+ return false;
359
+ }
360
+
361
+ private function addDirectoryEntriesInFileTree($path, &$entries = array())
362
+ {
363
+ if ($this->shouldExcludeFile($path)) return;
364
+ SGPing::update();
365
+ if (is_dir($path)) {
366
+ if ($handle = @opendir($path)) {
367
+ while (($file = readdir($handle)) !== false) {
368
+ if ($file === '.' || $file === '..') {
369
+ continue;
370
+ }
371
+
372
+ if (SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
373
+ if (($path == $this->rootDirectory || $path == $this->rootDirectory.'wp-content') && strpos($file, 'backup') !== false) {
374
+ continue;
375
+ }
376
+ }
377
+
378
+ $this->addDirectoryEntriesInFileTree($path.'/'.$file, $entries);
379
+ }
380
+
381
+ closedir($handle);
382
+ }
383
+ else {
384
+ $this->warn('Could not read directory (skipping): '.$path);
385
+ }
386
+ }
387
+ else {
388
+ if (is_readable($path)) {
389
+ $fileEntry = new SGFileEntry();
390
+ $fileEntry->setName(basename($path));
391
+ $fileEntry->setPath($path);
392
+
393
+ $this->numberOfEntries++;
394
+ array_push($entries, $fileEntry->toArray());
395
+
396
+ if (count($entries) > self::BUFFER_SIZE) {
397
+ $this->addEntriesInFileTree($entries);
398
+ $entries = array();
399
+ }
400
+ }
401
+ else {
402
+ $this->warn('Path is not readable (skipping): '.$path);
403
+ }
404
+ }
405
+ }
406
+
407
+ public function cancel()
408
+ {
409
+ @unlink($this->filePath);
410
+ }
411
+
412
+ private function addFileToArchive($path)
413
+ {
414
+ if ($this->shouldExcludeFile($path)) return true;
415
+
416
+ //check if it is a directory
417
+ if (is_dir($path))
418
+ {
419
+ $this->backupDirectory($path);
420
+ return;
421
+ }
422
+
423
+ //it is a file, try to add it to archive
424
+ if (is_readable($path))
425
+ {
426
+ $file = substr($path, strlen($this->rootDirectory));
427
+ $file = str_replace('\\', '/', $file);
428
+ $this->sgbp->addFileFromPath($file, $path);
429
+ }
430
+ else
431
+ {
432
+ $this->warn('Could not read file (skipping): '.$path);
433
+ }
434
+
435
+ //update progress and check cancellation
436
+ $this->progressCursor++;
437
+ if ($this->updateProgress())
438
+ {
439
+ if ($this->delegate && $this->delegate->isCancelled())
440
+ {
441
+ return;
442
+ }
443
+ }
444
+
445
+ if (SGBoot::isFeatureAvailable('BACKGROUND_MODE') && $this->delegate->isBackgroundMode())
446
+ {
447
+ SGBackgroundMode::next();
448
+ }
449
+ }
450
+
451
+ private function backupDirectory($path)
452
+ {
453
+ if ($handle = @opendir($path))
454
+ {
455
+ $filesFound = false;
456
+ while (($file = readdir($handle)) !== false)
457
+ {
458
+ if ($file === '.')
459
+ {
460
+ continue;
461
+ }
462
+ if ($file === '..')
463
+ {
464
+ continue;
465
+ }
466
+
467
+ $filesFound = true;
468
+ $this->addFileToArchive($path.'/'.$file);
469
+ }
470
+
471
+ if (!$filesFound)
472
+ {
473
+ $file = substr($path, strlen($this->rootDirectory));
474
+ $file = str_replace('\\', '/', $file);
475
+ $this->sgbp->addFile($file.'/', ''); //create empty directory
476
+ }
477
+
478
+ closedir($handle);
479
+ }
480
+ else
481
+ {
482
+ $this->warn('Could not read directory (skipping): '.$path);
483
+ }
484
+ }
485
+
486
+ public function warn($message)
487
+ {
488
+ $this->warningsFound = true;
489
+ SGBackupLog::writeWarning($message);
490
+ }
491
+
492
+ private function updateProgress()
493
+ {
494
+ $progress = round($this->progressCursor*100.0/$this->numberOfEntries);
495
+
496
+ if ($progress>=$this->nextProgressUpdate)
497
+ {
498
+ $this->nextProgressUpdate += $this->progressUpdateInterval;
499
+
500
+ if ($this->delegate)
501
+ {
502
+ $this->delegate->didUpdateProgress($progress);
503
+ }
504
+
505
+ return true;
506
+ }
507
+
508
+ return false;
509
+ }
510
+ }
com/core/backup/SGBackupLog.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_LOG_PATH.'SGLog.php');
3
+
4
+ class SGBackupLog
5
+ {
6
+ public static function writeAction($action, $position = SG_BACKUP_LOG_POS_START, $level = SG_LOG_LEVEL_LOW)
7
+ {
8
+ $logPos = 'Start';
9
+ if ($position == SG_BACKUP_LOG_POS_END)
10
+ {
11
+ $logPos = 'End';
12
+ }
13
+ $logMsg = $logPos.' '.$action;
14
+ $res = self::write($logMsg, $level);
15
+ return $res;
16
+ }
17
+
18
+ public static function writeException($exception, $message, $file, $line, $level = SG_LOG_LEVEL_LOW)
19
+ {
20
+ $logMsg = $exception.': '.$message.' ';
21
+ $logMsg .= '[File: '.$file.', Line: '.$line;
22
+ if (isset($_SERVER['REQUEST_URI']))
23
+ {
24
+ $logMsg .= ', URL: '.$_SERVER['REQUEST_URI'];
25
+ }
26
+ $logMsg .= ']';
27
+ $res = self::write($logMsg, $level);
28
+ return $res;
29
+ }
30
+
31
+ public static function writeExceptionObject($exception, $level = SG_LOG_LEVEL_LOW)
32
+ {
33
+ return self::writeException(get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine(), $level);
34
+ }
35
+
36
+ public static function writeWarning($message, $level = SG_LOG_LEVEL_LOW)
37
+ {
38
+ $logMsg = 'Warning: '.$message;
39
+ $res = self::write($logMsg, $level);
40
+ return $res;
41
+ }
42
+
43
+ public static function write($message, $level = SG_LOG_LEVEL_LOW)
44
+ {
45
+ $res = SGLog::write($message, $level);
46
+ return $res;
47
+ }
48
+
49
+ public static function readAll()
50
+ {
51
+ return SGLog::readAll();
52
+ }
53
+
54
+ public static function clear($level = SG_LOG_LEVEL_LOW)
55
+ {
56
+ SGLog::clear($level);
57
+ }
58
+ }
com/core/backup/SGBackupSchedule.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_SCHEDULE_PATH.'SGSchedule.php');
3
+
4
+ class SGBackupSchedule
5
+ {
6
+ public static function create($cron, $options, $label)
7
+ {
8
+ $sgdb = SGDatabase::getInstance();
9
+ $params = array();
10
+ $query = '';
11
+
12
+ if (!SGBoot::isFeatureAvailable('MULTI_SCHEDULE')) {
13
+ self::remove();
14
+ $query = 'INSERT INTO '.SG_SCHEDULE_TABLE_NAME.' (id, label, status, schedule_options, backup_options) VALUES (%d, %s, %d, %s, %s) ON DUPLICATE KEY UPDATE label=%s, schedule_options=%s, backup_options=%s';
15
+
16
+ $params = array(
17
+ SG_SCHEDULER_DEFAULT_ID,
18
+ $label,
19
+ SG_SHCEDULE_STATUS_PENDING,
20
+ json_encode($cron),
21
+ json_encode($options),
22
+ $label,
23
+ json_encode($cron),
24
+ json_encode($options)
25
+ );
26
+ }
27
+ else {
28
+ $query = 'INSERT INTO '.SG_SCHEDULE_TABLE_NAME.' (label, status, schedule_options, backup_options) VALUES (%s, %d, %s, %s)';
29
+
30
+ $params = array(
31
+ $label,
32
+ SG_SHCEDULE_STATUS_PENDING,
33
+ json_encode($cron),
34
+ json_encode($options)
35
+ );
36
+ }
37
+
38
+ $res = $sgdb->query($query, $params);
39
+
40
+ if ($res) {
41
+ $id = $sgdb->lastInsertId();
42
+ SGSchedule::create($cron, $id);
43
+ }
44
+ }
45
+
46
+ public static function remove($id = SG_SCHEDULER_DEFAULT_ID)
47
+ {
48
+ $sgdb = SGDatabase::getInstance();
49
+ $sgdb->query('DELETE FROM '.SG_SCHEDULE_TABLE_NAME.' WHERE id=%d', array($id));
50
+ SGSchedule::remove($id);
51
+ }
52
+
53
+ public static function getCronExecutionData($cron)
54
+ {
55
+ $cron = json_decode($cron, true);
56
+ return SGSchedule::getCronExecutionData($cron);
57
+ }
58
+
59
+ public static function getAllSchedules()
60
+ {
61
+ $sgdb = SGDatabase::getInstance();
62
+ $results = $sgdb->query('SELECT id, label, status, schedule_options, backup_options FROM '.SG_SCHEDULE_TABLE_NAME);
63
+ $schedules = array();
64
+ foreach ($results as $key => $row) {
65
+ $schedules[$key]['id'] = $row['id'];
66
+ $schedules[$key]['label'] = $row['label'];
67
+ $schedules[$key]['status'] = $row['status'];
68
+ $cronExecutionData = self::getCronExecutionData($row['schedule_options']);
69
+
70
+ $schedules[$key]['recurrence'] = ucfirst($cronExecutionData['recurrence']);
71
+ $schedules[$key]['executionDate'] = $cronExecutionData['time'];
72
+ $schedules[$key]['backup_options'] = $row['backup_options'];
73
+ }
74
+
75
+ return $schedules;
76
+ }
77
+ }
com/core/backup/SGBackupStorage.php ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
3
+ @include_once(SG_STORAGE_PATH.'SGGoogleDriveStorage.php');
4
+ @include_once(SG_STORAGE_PATH.'SGDropboxStorage.php');
5
+ @include_once(SG_STORAGE_PATH.'SGOneDriveStorage.php');
6
+ @include_once(SG_STORAGE_PATH.'SGFTPManager.php');
7
+ @include_once(SG_STORAGE_PATH.'SGAmazonStorage.php');
8
+
9
+ class SGBackupStorage implements SGIStorageDelegate
10
+ {
11
+ private static $instance = null;
12
+ private $actionId = null;
13
+ private $currentUploadChunksCount = 0;
14
+ private $totalUploadChunksCount = 0;
15
+ private $progressUpdateInterval = 0;
16
+ private $nextProgressUpdate = 0;
17
+ private $backgroundMode = false;
18
+ private $delegate = null;
19
+ private $state = null;
20
+ private $token = null;
21
+ private $pendingStorageUploads = array();
22
+ private $reloadStartTs;
23
+
24
+ private function __construct()
25
+ {
26
+ $this->backgroundMode = SGConfig::get('SG_BACKUP_IN_BACKGROUND_MODE');
27
+ $this->progressUpdateInterval = SGConfig::get('SG_ACTION_PROGRESS_UPDATE_INTERVAL');
28
+ }
29
+
30
+ private function __clone()
31
+ {
32
+
33
+ }
34
+
35
+ public function setPendingStorageUploads($pendingStorageUploads)
36
+ {
37
+ $this->pendingStorageUploads = $pendingStorageUploads;
38
+ }
39
+
40
+ public function setToken($token)
41
+ {
42
+ $this->token = $token;
43
+ }
44
+
45
+ public function setState($state)
46
+ {
47
+ $this->state = $state;
48
+ }
49
+
50
+ public function setDelegate($delegate)
51
+ {
52
+ $this->delegate = $delegate;
53
+ }
54
+
55
+ public function getPendingStorageUploads()
56
+ {
57
+ return $this->pendingStorageUploads;
58
+ }
59
+
60
+ public function getState()
61
+ {
62
+ return $this->state;
63
+ }
64
+
65
+ public function getActionId()
66
+ {
67
+ return $this->actionId;
68
+ }
69
+
70
+ public function getCurrentUploadChunksCount()
71
+ {
72
+ return $this->currentUploadChunksCount;
73
+ }
74
+
75
+ public function reload()
76
+ {
77
+ $this->delegate->reload();
78
+ }
79
+
80
+ public function getToken()
81
+ {
82
+ return $this->token;
83
+ }
84
+
85
+ public static function getInstance()
86
+ {
87
+ if (!self::$instance)
88
+ {
89
+ self::$instance = new self();
90
+ }
91
+
92
+ return self::$instance;
93
+ }
94
+
95
+ public function deleteBackupFromStorage($storageId, $backupName)
96
+ {
97
+ try {
98
+ $uploadFolder = trim(SGConfig::get('SG_STORAGE_BACKUPS_FOLDER_NAME'), '/');
99
+
100
+ $storage = $this->storageObjectById($storageId);
101
+ $path = "/".$uploadFolder."/".$backupName.".sgbp";
102
+
103
+ if ($storage) {
104
+ $storage->deleteFile($path);
105
+ }
106
+ }
107
+ catch(Exception $e) {
108
+ }
109
+ }
110
+
111
+ public function listStorage($storageId)
112
+ {
113
+ $storage = $this->storageObjectById($storageId, $storageName);
114
+ $listOfFiles = $storage->getListOfFiles();
115
+
116
+ return $listOfFiles;
117
+ }
118
+
119
+ public function downloadBackupArchiveFromCloud($storageId, $archive, $size)
120
+ {
121
+ $storage = $this->storageObjectById($storageId, $storageName);
122
+ $result = $storage->downloadFile($archive, $size);
123
+
124
+ return $result?true:false;
125
+ }
126
+
127
+ public static function queueBackupForUpload($backupName, $storageId, $options)
128
+ {
129
+ return SGBackup::createAction($backupName, SG_ACTION_TYPE_UPLOAD, SG_ACTION_STATUS_CREATED, $storageId, json_encode($options));
130
+ }
131
+
132
+ public function startUploadByActionId($actionId)
133
+ {
134
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
135
+ $sgdb = SGDatabase::getInstance();
136
+
137
+ $res = $sgdb->query('SELECT * FROM '.SG_ACTION_TABLE_NAME.' WHERE id=%d LIMIT 1', array($actionId));
138
+
139
+ if (!count($res))
140
+ {
141
+ return false;
142
+ }
143
+
144
+ $row = $res[0];
145
+
146
+ if ($row['type']!=SG_ACTION_TYPE_UPLOAD)
147
+ {
148
+ return false;
149
+ }
150
+
151
+ $this->actionId = $actionId;
152
+ $type = $row['subtype'];
153
+ $backupName = $row['name'];
154
+ }
155
+ else{
156
+ $this->actionId = $this->state->getActionId();
157
+ $this->currentUploadChunksCount = $this->state->getCurrentUploadChunksCount();
158
+ $type = $this->state->getStorageType();
159
+ $backupName = $this->state->getBackupFileName();
160
+ }
161
+
162
+ $storage = $this->storageObjectById($type, $storageName);
163
+ $this->startBackupUpload($backupName, $storage, $storageName);
164
+
165
+ return true;
166
+ }
167
+
168
+ public function startDownloadByActionId($actionId)
169
+ {
170
+ $sgdb = SGDatabase::getInstance();
171
+
172
+ $res = $sgdb->query('SELECT * FROM '.SG_ACTION_TABLE_NAME.' WHERE id=%d LIMIT 1', array($actionId));
173
+
174
+ if (!count($res))
175
+ {
176
+ return false;
177
+ }
178
+
179
+ $row = $res[0];
180
+
181
+ if ($row['type']!=SG_ACTION_TYPE_UPLOAD)
182
+ {
183
+ return false;
184
+ }
185
+
186
+ $this->actionId = $actionId;
187
+ $storage = $this->storageObjectById($row['subtype'], $storageName);
188
+
189
+ return true;
190
+ }
191
+
192
+ private function storageObjectById($storageId, &$storageName = '')
193
+ {
194
+ $storageClassName = "";
195
+ $storageId = (int)$storageId;
196
+ switch ($storageId) {
197
+ case SG_STORAGE_FTP:
198
+ if (SGBoot::isFeatureAvailable('FTP')) {
199
+ $connectionMethod = SGConfig::get('SG_STORAGE_CONNECTION_METHOD');
200
+ $storage = null;
201
+
202
+ if($connectionMethod == 'ftp') {
203
+ $storageName = 'FTP';
204
+ }
205
+ else {
206
+ $storageName = 'SFTP';
207
+ }
208
+
209
+ $storageClassName = "SGFTPManager";
210
+ }
211
+ break;
212
+ case SG_STORAGE_DROPBOX:
213
+ if (SGBoot::isFeatureAvailable('DROPBOX')) {
214
+ $storageName = 'Dropbox';
215
+ $storageClassName = "SGDropboxStorage";
216
+ }
217
+ break;
218
+ case SG_STORAGE_GOOGLE_DRIVE:
219
+ if (SGBoot::isFeatureAvailable('GOOGLE_DRIVE')) {
220
+ $storageName = 'Google Drive';
221
+ $storageClassName = "SGGoogleDriveStorage";
222
+ }
223
+ break;
224
+ case SG_STORAGE_AMAZON:
225
+ if (SGBoot::isFeatureAvailable('AMAZON')) {
226
+ $storageName = 'Amazon S3';
227
+ $storageClassName = "SGAmazonStorage";
228
+ }
229
+ break;
230
+ case SG_STORAGE_ONE_DRIVE:
231
+ if (SGBoot::isFeatureAvailable('ONE_DRIVE')) {
232
+ $storageName = 'One Drive';
233
+ $storageClassName = "SGOneDriveStorage";
234
+ }
235
+ break;
236
+ }
237
+
238
+ if (!$storageClassName) {
239
+ throw new SGExceptionNotFound('Unknown storage');
240
+ }
241
+
242
+ return new $storageClassName();
243
+ }
244
+
245
+ public function shouldUploadNextChunk()
246
+ {
247
+ if (SGBoot::isFeatureAvailable('BACKGROUND_MODE') && $this->backgroundMode)
248
+ {
249
+ SGBackgroundMode::next();
250
+ }
251
+
252
+ $this->currentUploadChunksCount++;
253
+ if ($this->updateProgress())
254
+ {
255
+ $this->checkCancellation();
256
+ }
257
+ return true;
258
+ }
259
+
260
+ public function willStartUpload($chunksCount)
261
+ {
262
+ $this->totalUploadChunksCount = $chunksCount;
263
+
264
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
265
+ $this->resetProgress();
266
+ }
267
+ }
268
+
269
+ public function updateProgressManually($progress)
270
+ {
271
+ if (SGBoot::isFeatureAvailable('BACKGROUND_MODE') && $this->backgroundMode)
272
+ {
273
+ SGBackgroundMode::next();
274
+ }
275
+
276
+ if ($this->updateProgress($progress))
277
+ {
278
+ $this->checkCancellation();
279
+ }
280
+ }
281
+
282
+ private function updateProgress($progress = null)
283
+ {
284
+ if (!$progress)
285
+ {
286
+ $progress = $this->currentUploadChunksCount*100.0/$this->totalUploadChunksCount;
287
+ }
288
+
289
+ if ($progress>=$this->nextProgressUpdate)
290
+ {
291
+ $this->nextProgressUpdate += $this->progressUpdateInterval;
292
+
293
+ $progress = max($progress, 0);
294
+ $progress = min($progress, 100);
295
+ SGBackup::changeActionProgress($this->actionId, $progress);
296
+
297
+ return true;
298
+ }
299
+
300
+ return false;
301
+ }
302
+
303
+ private function resetProgress()
304
+ {
305
+ $this->currentUploadChunksCount = 0;
306
+ $this->nextProgressUpdate = $this->progressUpdateInterval;
307
+ }
308
+
309
+ private function checkCancellation()
310
+ {
311
+ $status = SGBackup::getActionStatus($this->actionId);
312
+ if ($status==SG_ACTION_STATUS_CANCELLING)
313
+ {
314
+ SGBackupLog::write('Upload cancelled');
315
+ throw new SGExceptionSkip();
316
+ }
317
+ elseif ($status==SG_ACTION_STATUS_ERROR) {
318
+ SGBackupLog::write('Upload timeout error');
319
+ throw new SGExceptionExecutionTimeError();
320
+ }
321
+ }
322
+
323
+ public function shouldReload()
324
+ {
325
+ $currentTime = time();
326
+
327
+ if (($currentTime - $this->reloadStartTs) >= SG_RELOAD_TIMEOUT) {
328
+ return true;
329
+ }
330
+
331
+ return false;
332
+ }
333
+
334
+ private function startBackupUpload($backupName, SGStorage $storage, $storageName)
335
+ {
336
+ $this->reloadStartTs = time();
337
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
338
+ $actionStartTs = time();
339
+ }
340
+ else {
341
+ $actionStartTs = $this->state->getActionStartTs();
342
+ }
343
+
344
+ SGPing::update();
345
+
346
+ $backupPath = SG_BACKUP_DIRECTORY.$backupName;
347
+ $filesBackupPath = $backupPath.'/'.$backupName.'.sgbp';
348
+
349
+ if (!is_readable($filesBackupPath)) {
350
+ SGBackup::changeActionStatus($this->actionId, SG_ACTION_STATUS_ERROR);
351
+ throw new SGExceptionNotFound('Backup not found');
352
+ }
353
+
354
+ try {
355
+ @session_write_close();
356
+
357
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
358
+ SGBackup::changeActionStatus($this->actionId, SG_ACTION_STATUS_IN_PROGRESS_FILES);
359
+
360
+ SGBackupLog::write('-');
361
+ SGBackupLog::writeAction('upload to '.$storageName, SG_BACKUP_LOG_POS_START);
362
+ SGBackupLog::write('Authenticating');
363
+ }
364
+
365
+ $storage->setDelegate($this);
366
+ $storage->loadState();
367
+ $storage->connectOffline();
368
+
369
+ //get backups container folder
370
+ $backupsFolder = $this->state->getActiveDirectory();
371
+
372
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
373
+ SGBackupLog::write('Preparing folder');
374
+
375
+ $folderTree = SG_BACKUP_DEFAULT_FOLDER_NAME;
376
+
377
+ if (SGBoot::isFeatureAvailable('SUBDIRECTORIES')){
378
+ $folderTree = SGConfig::get('SG_STORAGE_BACKUPS_FOLDER_NAME');
379
+ }
380
+
381
+ //create backups container folder, if needed
382
+ $backupsFolder = $storage->createFolder($folderTree);
383
+ }
384
+
385
+ $storage->setActiveDirectory($backupsFolder);
386
+
387
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
388
+ SGBackupLog::write('Uploading file');
389
+ }
390
+
391
+ $storage->uploadFile($filesBackupPath);
392
+
393
+ SGBackupLog::writeAction('upload to '.$storageName, SG_BACKUP_LOG_POS_END);
394
+
395
+ //Writing upload status to report file
396
+ file_put_contents($backupPath.'/'.SG_REPORT_FILE_NAME, 'Uploaded to '.$storageName.": completed\n", FILE_APPEND);
397
+ SGBackupLog::write('Total duration: '.backupGuardFormattedDuration($actionStartTs, time()));
398
+
399
+ SGBackup::changeActionStatus($this->actionId, SG_ACTION_STATUS_FINISHED);
400
+ }
401
+ catch (Exception $exception) {
402
+ if ($exception instanceof SGExceptionSkip) {
403
+ SGBackup::changeActionStatus($this->actionId, SG_ACTION_STATUS_CANCELLED);
404
+ //Writing upload status to report file
405
+ file_put_contents($backupPath.'/'.SG_REPORT_FILE_NAME, 'Uploaded to '.$storageName.': canceled', FILE_APPEND);
406
+ SGBackupMailNotification::sendBackupNotification(SG_ACTION_STATUS_CANCELLED, array(
407
+ 'flowFilePath' => $backupPath.'/'.SG_REPORT_FILE_NAME,
408
+ 'archiveName' => $backupName
409
+ ));
410
+ }
411
+ else {
412
+ SGBackup::changeActionStatus($this->actionId, SG_ACTION_STATUS_FINISHED_WARNINGS);
413
+
414
+ if (!$exception instanceof SGExceptionExecutionTimeError) {//to prevent log duplication for timeout exception
415
+ SGBackupLog::writeExceptionObject($exception);
416
+ }
417
+
418
+ if (SGBoot::isFeatureAvailable('NOTIFICATIONS')) {
419
+ //Writing upload status to report file
420
+ file_put_contents($backupPath.'/'.SG_REPORT_FILE_NAME, 'Uploaded to '.$storageName.': failed', FILE_APPEND);
421
+ SGBackupMailNotification::sendBackupNotification(SG_ACTION_STATUS_ERROR, array(
422
+ 'flowFilePath' => $backupPath.'/'.SG_REPORT_FILE_NAME,
423
+ 'archiveName' => $backupName
424
+ ));
425
+ }
426
+ }
427
+
428
+ //delete file inside storage
429
+ $storageId = $this->state->getStorageType();
430
+ $this->deleteBackupFromStorage($storageId, $backupName);
431
+
432
+ //delete report file in case of error
433
+ @unlink($backupPath.'/'.SG_REPORT_FILE_NAME);
434
+ }
435
+ }
436
+ }
com/core/backup/SGIBackupDelegate.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface SGIBackupDelegate
4
+ {
5
+ public function isCancelled();
6
+ public function didUpdateProgress($progress);
7
+ public function isBackgroundMode();
8
+ }
com/core/database/SGDatabase.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGDatabase
4
+ {
5
+ private static $instance = null;
6
+
7
+ public static function getInstance()
8
+ {
9
+ if (!self::$instance)
10
+ {
11
+ self::$instance = self::createAdapterInstance();
12
+ }
13
+
14
+ return self::$instance;
15
+ }
16
+
17
+ private static function createAdapterInstance()
18
+ {
19
+ $className = 'SGDatabaseAdapter'.SG_DB_ADAPTER;
20
+ require_once(SG_DATABASE_PATH.$className.'.php');
21
+ $adapter = new $className();
22
+ return $adapter;
23
+ }
24
+
25
+ private function __construct()
26
+ {
27
+
28
+ }
29
+
30
+ private function __clone()
31
+ {
32
+
33
+ }
34
+ }
com/core/database/SGDatabaseAdapterWordpress.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_DATABASE_PATH.'SGIDatabaseAdapter.php');
3
+
4
+ class SGDatabaseAdapterWordpress implements SGIDatabaseAdapter
5
+ {
6
+ private $fetchRowIndex = 0;
7
+ private $lastResult = array();
8
+ private $connection = null;
9
+ private $mysqliAvailable = false;
10
+
11
+ public function __construct()
12
+ {
13
+ $this->mysqliAvailable = $this->isMysqliAvailable();
14
+ }
15
+
16
+ public function query($query, $params=array(), $resultType = ARRAY_A)
17
+ {
18
+ global $wpdb;
19
+
20
+ $op = strtoupper(substr(trim($query), 0, 6));
21
+ if ($op!='INSERT' && $op!='UPDATE' && $op!='DELETE')
22
+ {
23
+ if(!empty($params))
24
+ {
25
+ return @$wpdb->get_results($wpdb->prepare($query, $params), $resultType);
26
+ }
27
+ return @$wpdb->get_results($query, $resultType);
28
+ }
29
+ else
30
+ {
31
+ if(!empty($params))
32
+ {
33
+ return $wpdb->query($wpdb->prepare($query, $params));
34
+ }
35
+ return $wpdb->query($query);
36
+ }
37
+ }
38
+
39
+ public function exec($query)
40
+ {
41
+ //as wpdb doesn't work with statements, this function will just return true or false
42
+
43
+ global $wpdb;
44
+
45
+ $this->fetchRowIndex = 0;
46
+ $res = $wpdb->query($query);
47
+
48
+ if ($res === false) {
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+
54
+ public function execRaw($query)
55
+ {
56
+ //if mysqli is not available, run the query using wpdb
57
+ if (!$this->mysqliAvailable) {
58
+ return $this->exec($query);
59
+ }
60
+
61
+ //mysqli is available
62
+ if (!$this->connection) { //but there isn't any active connection
63
+ if (!$this->connectOverMysqli()) { //try to connect
64
+ $this->mysqliAvailable = false;
65
+ return $this->exec($query); //could not connect; continue using wpdb.
66
+ }
67
+ }
68
+
69
+ //mysqli is already connected, use it
70
+ return mysqli_real_query($this->connection, $query);
71
+ }
72
+
73
+ private function connectOverMysqli()
74
+ {
75
+ $this->connection = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
76
+
77
+ //set charset just in case if set names (inside sql file) doesn't work
78
+ if ($this->connection) {
79
+ mysqli_set_charset($this->connection, SG_DB_CHARSET);
80
+ }
81
+
82
+ return $this->connection;
83
+ }
84
+
85
+ private function isMysqliAvailable()
86
+ {
87
+ return function_exists('mysqli_connect');
88
+ }
89
+
90
+ public function fetch($st)
91
+ {
92
+ global $wpdb;
93
+
94
+ if ($this->fetchRowIndex==0) {
95
+ $this->lastResult = $wpdb->last_result;
96
+ }
97
+
98
+ $res = @$this->lastResult[$this->fetchRowIndex];
99
+ if (!$res) return false;
100
+
101
+ $this->fetchRowIndex++;
102
+ return get_object_vars($res);
103
+ }
104
+
105
+ public function lastInsertId()
106
+ {
107
+ global $wpdb;
108
+ return $wpdb->insert_id;
109
+ }
110
+
111
+ public function getLastError()
112
+ {
113
+ if ($this->mysqliAvailable && $this->connection) {
114
+ return mysqli_error($this->connection);
115
+ }
116
+
117
+ global $wpdb;
118
+ return $wpdb->last_error;
119
+ }
120
+
121
+ public function flush()
122
+ {
123
+ global $wpdb;
124
+ $wpdb->flush();
125
+ }
126
+
127
+ public function escapeSql($value)
128
+ {
129
+ return esc_sql($value);
130
+ }
131
+ }
com/core/database/SGIDatabaseAdapter.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface SGIDatabaseAdapter
4
+ {
5
+ /*
6
+ The query may contain any of the following placeholders: %s, %d and %f
7
+ The number of given parameters must be equal to the number of placeholders.
8
+ This method must return the fetched results if the query is fetchable.
9
+ */
10
+ public function query($query, $params=array());
11
+
12
+ /*
13
+ Execute a query and return the statement object.
14
+ */
15
+ public function exec($query);
16
+
17
+ /*
18
+ Execute raw query. This function doesn't prepare the query, neither returns a statement object.
19
+ Perfect for executing fast insert queries without doing cleanup or escaping.
20
+ Returns true or false.
21
+ */
22
+ public function execRaw($query);
23
+
24
+ /*
25
+ Fetch a row from a previously executed query.
26
+ */
27
+ public function fetch($st);
28
+
29
+ /*
30
+ Return the last insert id.
31
+ */
32
+ public function lastInsertId();
33
+
34
+ /*
35
+ Get the error (if any) generated by the most recent query.
36
+ */
37
+ public function getLastError();
38
+
39
+ /*
40
+ Kill cached query results.
41
+ */
42
+ public function flush();
43
+
44
+ /*
45
+ Escape value for sql query
46
+ */
47
+ public function escapeSql($value);
48
+ }
com/core/exception/SGException.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGException extends Exception
4
+ {
5
+ public function __toString()
6
+ {
7
+ return get_class($this).": {$this->message}";
8
+ }
9
+ }
10
+
11
+ class SGExceptionNotFound extends SGException
12
+ {
13
+ public function __construct($msg = 'Not found')
14
+ {
15
+ parent::__construct($msg, 404, null);
16
+ }
17
+ }
18
+
19
+ class SGExceptionForbidden extends SGException
20
+ {
21
+ public function __construct($msg = 'Forbidden')
22
+ {
23
+ parent::__construct($msg, 403, null);
24
+ }
25
+ }
26
+
27
+ class SGExceptionBadRequest extends SGException
28
+ {
29
+ public function __construct($msg = 'Bad request')
30
+ {
31
+ parent::__construct($msg, 400, null);
32
+ }
33
+ }
34
+
35
+ class SGExceptionMethodNotAllowed extends SGException
36
+ {
37
+ public function __construct($msg = 'Method not allowed')
38
+ {
39
+ parent::__construct($msg, 405, null);
40
+ }
41
+ }
42
+
43
+ class SGExceptionDatabaseError extends SGException
44
+ {
45
+ public function __construct($msg = 'Database error')
46
+ {
47
+ parent::__construct($msg, 500, null);
48
+ }
49
+ }
50
+
51
+ class SGExceptionServerError extends SGException
52
+ {
53
+ public function __construct($msg = 'Internal server error')
54
+ {
55
+ parent::__construct($msg, 500, null);
56
+ }
57
+ }
58
+
59
+ class SGExceptionSkip extends SGException
60
+ {
61
+ public function __construct($msg = 'Skip exception')
62
+ {
63
+ parent::__construct($msg, 1, null);
64
+ }
65
+ }
66
+
67
+ class SGExceptionExecutionTimeError extends SGException
68
+ {
69
+ public function __construct($msg = 'Execution timeout error')
70
+ {
71
+ parent::__construct($msg, 2, null);
72
+ }
73
+ }
74
+
75
+
76
+ class SGExceptionIO extends SGException
77
+ {
78
+ public function __construct($msg = 'IO read/write error')
79
+ {
80
+ parent::__construct($msg, 3, null);
81
+ }
82
+ }
83
+
84
+ class SGExceptionMigrationError extends SGException
85
+ {
86
+ public function __construct($msg = 'Migration error')
87
+ {
88
+ parent::__construct($msg, 4, null);
89
+ }
90
+ }
com/core/extension/SGExtension.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGExtension
4
+ {
5
+ private static $instance = null;
6
+
7
+ public static function getInstance()
8
+ {
9
+ if (!self::$instance) {
10
+ self::$instance = self::createAdapterInstance();
11
+ }
12
+
13
+ return self::$instance;
14
+ }
15
+
16
+ private static function createAdapterInstance()
17
+ {
18
+ $className = 'SGExtensionAdapter'.SG_ENV_ADAPTER;
19
+ require_once(dirname(__FILE__).'/'.$className.'.php');
20
+ $adapter = new $className();
21
+ return $adapter;
22
+ }
23
+
24
+ private function __construct()
25
+ {
26
+
27
+ }
28
+
29
+ private function __clone()
30
+ {
31
+
32
+ }
33
+ }
com/core/extension/SGExtensionAdapterWordpress.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/SGIExtensionAdapter.php');
4
+
5
+ class SGExtensionAdapterWordpress implements SGIExtensionAdapter
6
+ {
7
+ public function isExtensionActive($extension)
8
+ {
9
+ return is_plugin_active($extension."/".$extension.".php");
10
+ }
11
+
12
+ public function isExtensionAvailable($extension)
13
+ {
14
+ return file_exists(SG_EXTENSIONS_FOLDER_PATH.$extension);
15
+ }
16
+
17
+ public function isExtensionAlreadyInPluginsFolder($extension)
18
+ {
19
+ return file_exists(WP_PLUGIN_DIR."/".$extension);
20
+ }
21
+
22
+ public function installExtension($extension)
23
+ {
24
+ if (!$this->isExtensionAlreadyInPluginsFolder($extension)) {
25
+ return $this->copyExtensionFilesToPLuginsFolder($extension);
26
+ }
27
+
28
+ return false;
29
+ }
30
+
31
+ public function activateExtension($extension)
32
+ {
33
+ SGConfig::set($extension, 1);
34
+ if (!$this->isExtensionActive($extension)) {
35
+ activate_plugin($extension."/".$extension.".php");
36
+ }
37
+ }
38
+
39
+ public function copyExtensionFilesToPLuginsFolder($extension)
40
+ {
41
+ $extensionsDirectoryPath = SG_EXTENSIONS_FOLDER_PATH.$extension;
42
+ if (!$this->isExtensionAvailable($extension)) {
43
+ return false;
44
+ }
45
+
46
+ $pluginsDirectoryPath = WP_PLUGIN_DIR."/".$extension;
47
+ @mkdir($pluginsDirectoryPath, 0755, true);
48
+
49
+ $it = new RecursiveIteratorIterator(
50
+ new RecursiveDirectoryIterator($extensionsDirectoryPath, RecursiveDirectoryIterator::SKIP_DOTS),
51
+ RecursiveIteratorIterator::SELF_FIRST,
52
+ RecursiveIteratorIterator::CATCH_GET_CHILD
53
+ );
54
+
55
+ foreach ($it as $path => $fileInfo) {
56
+ $filename = $fileInfo->getFilename();
57
+ if ($filename == '.DS_Store') {
58
+ continue;
59
+ }
60
+
61
+ $relativePath = substr($path, strlen($extensionsDirectoryPath));
62
+
63
+ if (substr($relativePath, 0, 4) == '.git') {
64
+ continue;
65
+ }
66
+
67
+ if ($fileInfo->isDir()) {
68
+ @mkdir($pluginsDirectoryPath.$relativePath, 0755, true);
69
+ }
70
+ else {
71
+ if (!@copy($path, $pluginsDirectoryPath.$relativePath)) {
72
+ return false;
73
+ }
74
+ }
75
+ }
76
+
77
+ return true;
78
+ }
79
+ }
com/core/extension/SGIExtensionAdapter.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface SGIExtensionAdapter
4
+ {
5
+ public function isExtensionActive($extension);
6
+ public function isExtensionAvailable($extension);
7
+ public function activateExtension($extensions);
8
+ public function installExtension($extension);
9
+ public function isExtensionAlreadyInPluginsFolder($extension);
10
+ public function copyExtensionFilesToPLuginsFolder($extension);
11
+ }
com/core/functions.php ADDED
@@ -0,0 +1,692 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ function backupGuardGetCapabilities()
4
+ {
5
+ switch (SG_PRODUCT_IDENTIFIER) {
6
+ case 'backup-guard-en':
7
+ case 'backup-guard-wp-platinum':
8
+ case 'backup-guard-en-regular':
9
+ case 'backup-guard-en-extended':
10
+ return BACKUP_GUARD_CAPABILITIES_PLATINUM;
11
+ case 'backup-guard-wp-gold':
12
+ return BACKUP_GUARD_CAPABILITIES_GOLD;
13
+ case 'backup-guard-wp-silver':
14
+ return BACKUP_GUARD_CAPABILITIES_SILVER;
15
+ case 'backup-guard-wp-free':
16
+ return BACKUP_GUARD_CAPABILITIES_FREE;
17
+ }
18
+ }
19
+
20
+ function convertToReadableSize($size)
21
+ {
22
+ if (!$size) {
23
+ return '';
24
+ }
25
+
26
+ $base = log($size) / log(1000);
27
+ $suffix = array("", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB");
28
+ $f_base = floor($base);
29
+
30
+ return round(pow(1000, $base - floor($base)), 1) . $suffix[$f_base];
31
+ }
32
+
33
+ function backupGuardgetSealPopup()
34
+ {
35
+ $currentDate = time();
36
+ $sgShouldShowPopup = SGConfig::get('SG_SHOULD_SHOW_POPUP') == null ? true : SGConfig::get('SG_SHOULD_SHOW_POPUP');
37
+ $sgPluginInstallUpdateDate = SGConfig::get('SG_PLUGIN_INSTALL_UPDATE_DATE') == null ? time() : SGConfig::get('SG_PLUGIN_INSTALL_UPDATE_DATE');
38
+
39
+ // check ig plugin is active for free days show poup
40
+ if (($currentDate - $sgPluginInstallUpdateDate >= SG_PLUGIN_ACTIVE_INTERVAL) && $sgShouldShowPopup) {
41
+ ?>
42
+ <script>
43
+ window.SGPMPopupLoader=window.SGPMPopupLoader||{ids:[],popups:{},call:function(w,d,s,l,id){
44
+ w['sgp']=w['sgp']||function(){(w['sgp'].q=w['sgp'].q||[]).push(arguments[0]);};
45
+ var sg1=d.createElement(s),sg0=d.getElementsByTagName(s)[0];
46
+ if(SGPMPopupLoader && SGPMPopupLoader.ids && SGPMPopupLoader.ids.length > 0){SGPMPopupLoader.ids.push(id); return;}
47
+ SGPMPopupLoader.ids.push(id);
48
+ sg1.onload = function(){SGPMPopup.openSGPMPopup();}; sg1.async=true; sg1.src=l;
49
+ sg0.parentNode.insertBefore(sg1,sg0);
50
+ return {};
51
+ }};
52
+ SGPMPopupLoader.call(window,document,'script','https://popupmaker.com/assets/lib/SGPMPopup.min.js','7c685e17');
53
+ </script>
54
+ <?php
55
+ SGConfig::set('SG_SHOULD_SHOW_POPUP', 0);
56
+ }
57
+
58
+ return;
59
+ }
60
+
61
+ function backupGuardConvertDateTimezone($date, $dateFormat = "Y-m-d H:i:s", $timezone = "UTC")
62
+ {
63
+ if (in_array($timezone, timezone_identifiers_list())) {
64
+ $date = date_create($date);
65
+ $timezone = timezone_open($timezone);
66
+ date_timezone_set($date, $timezone);
67
+
68
+ if (!$dateFormat) {
69
+ $dateFormat = "Y-m-d H:i:s";
70
+ }
71
+
72
+ return date_format($date, $dateFormat);
73
+ }
74
+
75
+ return $date;
76
+ }
77
+
78
+ function backupGuardRemoveSlashes($value)
79
+ {
80
+ if (SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
81
+ return wp_unslash($value);
82
+ }
83
+ else {
84
+ if (is_array($value)) {
85
+ return array_map('stripslashes', $value);
86
+ }
87
+
88
+ return stripslashes($value);
89
+ }
90
+ }
91
+
92
+ function backupGuardSanitizeTextField($value)
93
+ {
94
+ if (SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
95
+ if (is_array($value)) {
96
+ return array_map('sanitize_text_field', $value);
97
+ }
98
+
99
+ return sanitize_text_field($value);
100
+ }
101
+ else {
102
+ if (is_array($value)) {
103
+ return array_map('strip_tags', $value);
104
+ }
105
+
106
+ return strip_tags($value);
107
+ }
108
+ }
109
+
110
+ function backupGuardIsMultisite()
111
+ {
112
+ if (SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
113
+ return defined('BG_IS_MULTISITE')?BG_IS_MULTISITE:is_multisite();
114
+ }
115
+ else {
116
+ return false;
117
+ }
118
+ }
119
+
120
+ function backupGuardGetBanner($env, $type="plugin", $userType = null)
121
+ {
122
+ require_once(SG_LIB_PATH.'BackupGuard/Client.php');
123
+ $client = new BackupGuard\Client();
124
+ return $client->getBanner(strtolower($env), $type, $userType);
125
+ }
126
+
127
+ function backupGuardGetFilenameOptions($options)
128
+ {
129
+ $selectedPaths = explode(',', $options['SG_BACKUP_FILE_PATHS']);
130
+ $pathsToExclude = explode(',', $options['SG_BACKUP_FILE_PATHS_EXCLUDE']);
131
+
132
+ $opt = '';
133
+
134
+ if (SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
135
+ $opt .= 'opt(';
136
+
137
+ if ($options['SG_BACKUP_TYPE'] == SG_BACKUP_TYPE_CUSTOM) {
138
+ if ($options['SG_ACTION_BACKUP_DATABASE_AVAILABLE']) {
139
+ $opt .= 'db_';
140
+ }
141
+
142
+ if ($options['SG_ACTION_BACKUP_FILES_AVAILABLE']) {
143
+ if (in_array('wp-content', $selectedPaths)) {
144
+ $opt .= 'wpc_';
145
+ }
146
+ if (!in_array('wp-content/plugins', $pathsToExclude)) {
147
+ $opt .= 'plg_';
148
+ }
149
+ if (!in_array('wp-content/themes', $pathsToExclude)) {
150
+ $opt .= 'thm_';
151
+ }
152
+ if (!in_array('wp-content/uploads', $pathsToExclude)) {
153
+ $opt .= 'upl_';
154
+ }
155
+ }
156
+
157
+
158
+ }
159
+ else {
160
+ $opt .= 'full';
161
+ }
162
+
163
+ $opt = trim($opt, "_");
164
+ $opt .= ')_';
165
+ }
166
+
167
+ return $opt;
168
+ }
169
+
170
+ function backupGuardGenerateToken()
171
+ {
172
+ return md5(time());
173
+ }
174
+
175
+ // Parse a URL and return its components
176
+ function backupGuardParseUrl($url)
177
+ {
178
+ $urlComponents = parse_url($url);
179
+ $domain = $urlComponents['host'];
180
+ $port = '';
181
+
182
+ if (isset($urlComponents['port']) && strlen($urlComponents['port'])) {
183
+ $port = ":".$urlComponents['port'];
184
+ }
185
+
186
+ $domain = preg_replace("/(www|\dww|w\dw|ww\d)\./", "", $domain);
187
+
188
+ $path = "";
189
+ if (isset($urlComponents['path'])) {
190
+ $path = $urlComponents['path'];
191
+ }
192
+
193
+ return $domain.$port.$path;
194
+ }
195
+
196
+ function backupGuardIsReloadEnabled()
197
+ {
198
+ // Check if reloads option is turned on
199
+ return SGConfig::get('SG_BACKUP_WITH_RELOADINGS')?true:false;
200
+ }
201
+
202
+ function backupGuardGetBackupOptions($options)
203
+ {
204
+ $backupOptions = array(
205
+ 'SG_BACKUP_UPLOAD_TO_STORAGES' => '',
206
+ 'SG_BACKUP_FILE_PATHS_EXCLUDE' => '',
207
+ 'SG_BACKUP_FILE_PATHS' => ''
208
+ );
209
+
210
+ if (isset($options['sg-custom-backup-name']) && $options['sg-custom-backup-name']) {
211
+ SGConfig::set("SG_CUSTOM_BACKUP_NAME", $options['sg-custom-backup-name']);
212
+ }
213
+ else {
214
+ SGConfig::set("SG_CUSTOM_BACKUP_NAME", '');
215
+ }
216
+
217
+ //If background mode
218
+ $isBackgroundMode = !empty($options['backgroundMode']) ? 1 : 0;
219
+
220
+ if ($isBackgroundMode) {
221
+ $backupOptions['SG_BACKUP_IN_BACKGROUND_MODE'] = $isBackgroundMode;
222
+ }
223
+
224
+ //If cloud backup
225
+ if (!empty($options['backupCloud']) && count($options['backupStorages'])) {
226
+ $clouds = $options['backupStorages'];
227
+ $backupOptions['SG_BACKUP_UPLOAD_TO_STORAGES'] = implode(',', $clouds);
228
+ }
229
+
230
+ $backupOptions['SG_BACKUP_TYPE'] = $options['backupType'];
231
+
232
+ if ($options['backupType'] == SG_BACKUP_TYPE_FULL) {
233
+ $backupOptions['SG_ACTION_BACKUP_DATABASE_AVAILABLE']= 1;
234
+ $backupOptions['SG_ACTION_BACKUP_FILES_AVAILABLE'] = 1;
235
+ $backupOptions['SG_BACKUP_FILE_PATHS_EXCLUDE'] = SG_BACKUP_FILE_PATHS_EXCLUDE;
236
+ $backupOptions['SG_BACKUP_FILE_PATHS'] = 'wp-content';
237
+ }
238
+ else if ($options['backupType'] == SG_BACKUP_TYPE_CUSTOM) {
239
+ //If database backup
240
+ $isDatabaseBackup = !empty($options['backupDatabase']) ? 1 : 0;
241
+ $backupOptions['SG_ACTION_BACKUP_DATABASE_AVAILABLE'] = $isDatabaseBackup;
242
+
243
+ //If db backup
244
+ if($options['backupDBType']){
245
+ $tablesToBackup = implode(',', $options['table']);
246
+ $backupOptions['SG_BACKUP_TABLES_TO_BACKUP'] = $tablesToBackup;
247
+ }
248
+
249
+ //If files backup
250
+ if (!empty($options['backupFiles']) && count($options['directory'])) {
251
+ $backupFiles = explode(',', SG_BACKUP_FILE_PATHS);
252
+ $filesToExclude = @array_diff($backupFiles, $options['directory']);
253
+
254
+ if (in_array('wp-content', $options['directory'])) {
255
+ $options['directory'] = array('wp-content');
256
+ }
257
+ else {
258
+ $filesToExclude = array_diff($filesToExclude, array('wp-content'));
259
+ }
260
+
261
+ $filesToExclude = implode(',', $filesToExclude);
262
+ if (strlen($filesToExclude)) {
263
+ $filesToExclude = ','.$filesToExclude;
264
+ }
265
+
266
+ $backupOptions['SG_BACKUP_FILE_PATHS_EXCLUDE'] = SG_BACKUP_FILE_PATHS_EXCLUDE.$filesToExclude;
267
+ $options['directory'] = backupGuardSanitizeTextField($options['directory']);
268
+ $backupOptions['SG_BACKUP_FILE_PATHS'] = implode(',', $options['directory']);
269
+ $backupOptions['SG_ACTION_BACKUP_FILES_AVAILABLE'] = 1;
270
+ }
271
+ else {
272
+ $backupOptions['SG_ACTION_BACKUP_FILES_AVAILABLE'] = 0;
273
+ $backupOptions['SG_BACKUP_FILE_PATHS'] = 0;
274
+ }
275
+ }
276
+ return $backupOptions;
277
+ }
278
+
279
+ function backupGuardLoadStateData()
280
+ {
281
+ if (file_exists(SG_BACKUP_DIRECTORY.SG_STATE_FILE_NAME)) {
282
+ $sgState = new SGState();
283
+ $stateFile = file_get_contents(SG_BACKUP_DIRECTORY.SG_STATE_FILE_NAME);
284
+ $sgState = $sgState->factory($stateFile);
285
+ return $sgState;
286
+ }
287
+
288
+ return false;
289
+ }
290
+
291
+ function backupGuardValidateApiCall($token)
292
+ {
293
+ if (!strlen($token)) {
294
+ exit();
295
+ }
296
+
297
+ $statePath = SG_BACKUP_DIRECTORY.SG_STATE_FILE_NAME;
298
+
299
+ if (!file_exists($statePath)) {
300
+ exit();
301
+ }
302
+
303
+ $state = file_get_contents($statePath);
304
+ $state = json_decode($state, true);
305
+ $stateToken = $state['token'];
306
+
307
+ if ($stateToken != $token) {
308
+ exit();
309
+ }
310
+
311
+ return true;
312
+ }
313
+
314
+ function backupGuardScanBackupsDirectory($path)
315
+ {
316
+ $backups = scandir($path);
317
+ $backupFolders = array();
318
+ foreach ($backups as $key => $backup) {
319
+ if ($backup == "." || $backup == "..") {
320
+ continue;
321
+ }
322
+
323
+ if (is_dir($path.$backup)) {
324
+ $backupFolders[$backup] = filemtime($path.$backup);
325
+ }
326
+ }
327
+ // Sort(from low to high) backups by creation date
328
+ asort($backupFolders);
329
+ return $backupFolders;
330
+ }
331
+
332
+ function backupGuardSymlinksCleanup($dir)
333
+ {
334
+ if (is_dir($dir)) {
335
+ $objects = scandir($dir);
336
+ foreach ($objects as $object) {
337
+ if ($object == "." || $object == "..") {
338
+ continue;
339
+ }
340
+
341
+ if (filetype($dir.$object) != "dir") {
342
+ @unlink($dir.$object);
343
+ }
344
+ else {
345
+ backupGuardSymlinksCleanup($dir.$object.'/');
346
+ @rmdir($dir.$object);
347
+ }
348
+ }
349
+ }
350
+ else {
351
+ @unlink($dir);
352
+ }
353
+ return;
354
+ }
355
+
356
+ function backupGuardRealFilesize($filename)
357
+ {
358
+ $fp = fopen($filename, 'r');
359
+ $return = false;
360
+ if (is_resource($fp))
361
+ {
362
+ if (PHP_INT_SIZE < 8) // 32 bit
363
+ {
364
+ if (0 === fseek($fp, 0, SEEK_END))
365
+ {
366
+ $return = 0.0;
367
+ $step = 0x7FFFFFFF;
368
+ while ($step > 0)
369
+ {
370
+ if (0 === fseek($fp, - $step, SEEK_CUR))
371
+ {
372
+ $return += floatval($step);
373
+ }
374
+ else
375
+ {
376
+ $step >>= 1;
377
+ }
378
+ }
379
+ }
380
+ }
381
+ else if (0 === fseek($fp, 0, SEEK_END)) // 64 bit
382
+ {
383
+ $return = ftell($fp);
384
+ }
385
+ }
386
+
387
+ return $return;
388
+ }
389
+
390
+ function backupGuardFormattedDuration($startTs, $endTs)
391
+ {
392
+ $unit = 'seconds';
393
+ $duration = $endTs-$startTs;
394
+ if ($duration>=60 && $duration<3600)
395
+ {
396
+ $duration /= 60.0;
397
+ $unit = 'minutes';
398
+ }
399
+ else if ($duration>=3600)
400
+ {
401
+ $duration /= 3600.0;
402
+ $unit = 'hours';
403
+ }
404
+ $duration = number_format($duration, 2, '.', '');
405
+
406
+ return $duration.' '.$unit;
407
+ }
408
+
409
+ function backupGuardDeleteDirectory($dirName)
410
+ {
411
+ $dirHandle = null;
412
+ if (is_dir($dirName))
413
+ {
414
+ $dirHandle = opendir($dirName);
415
+ }
416
+
417
+ if (!$dirHandle)
418
+ {
419
+ return false;
420
+ }
421
+
422
+ while ($file = readdir($dirHandle))
423
+ {
424
+ if ($file != "." && $file != "..")
425
+ {
426
+ if (!is_dir($dirName."/".$file))
427
+ {
428
+ @unlink($dirName."/".$file);
429
+ }
430
+ else
431
+ {
432
+ backupGuardDeleteDirectory($dirName.'/'.$file);
433
+ }
434
+ }
435
+ }
436
+
437
+ closedir($dirHandle);
438
+ return @rmdir($dirName);
439
+ }
440
+
441
+ function backupGuardDownloadFile($file, $type = 'application/octet-stream')
442
+ {
443
+ $file = backupGuardRemoveSlashes($file);
444
+ if (file_exists($file)) {
445
+ header('Content-Description: File Transfer');
446
+ header('Content-Type: '.$type);
447
+ header('Content-Disposition: attachment; filename="'.basename($file).'";');
448
+ header('Expires: 0');
449
+ header('Cache-Control: must-revalidate');
450
+ header('Pragma: public');
451
+ header('Content-Length: ' . filesize($file));
452
+ readfile($file);
453
+ }
454
+
455
+ exit;
456
+ }
457
+
458
+ function backupGuardDownloadFileSymlink($safedir, $filename)
459
+ {
460
+ $safedir = backupGuardRemoveSlashes($safedir);
461
+ $filename = backupGuardRemoveSlashes($filename);
462
+
463
+ $downloaddir = SG_SYMLINK_PATH;
464
+ $downloadURL = SG_SYMLINK_URL;
465
+
466
+ if (!file_exists($downloaddir)) {
467
+ mkdir($downloaddir, 0777);
468
+ }
469
+
470
+ $letters = 'abcdefghijklmnopqrstuvwxyz';
471
+ srand((double) microtime() * 1000000);
472
+ $string = '';
473
+
474
+ for ($i = 1; $i <= rand(4,12); $i++) {
475
+ $q = rand(1,24);
476
+ $string = $string.$letters[$q];
477
+ }
478
+
479
+ $handle = opendir($downloaddir);
480
+ while ($dir = readdir($handle)) {
481
+ if ($dir == "." || $dir == "..") {
482
+ continue;
483
+ }
484
+
485
+ if (is_dir($downloaddir.$dir)) {
486
+ @unlink($downloaddir . $dir . "/" . $filename);
487
+ @rmdir($downloaddir . $dir);
488
+ }
489
+ }
490
+
491
+ closedir($handle);
492
+
493
+ mkdir($downloaddir . $string, 0777);
494
+ $res = @symlink($safedir . $filename, $downloaddir . $string . "/" . $filename);
495
+ if ($res) {
496
+ header('Content-Description: File Transfer');
497
+ header('Content-Type: application/octet-stream');
498
+ header('Content-Disposition: attachment;filename="'.$filename.'"');
499
+ header('Content-Transfer-Encoding: binary');
500
+ header("Location: " . $downloadURL . $string . "/" . $filename);
501
+ }
502
+ else{
503
+ wp_die(_backupGuardT("Symlink / shortcut creation failed! Seems your server configurations don't allow symlink creation, so we're unable to provide you the direct download url. You can download your backup using any FTP client. All backups and related stuff we locate '/wp-content/uploads/backup-guard' directory. If you need this functionality, you should check out your server configurations and make sure you don't have any limitation related to symlink creation.", true));
504
+ }
505
+ exit;
506
+ }
507
+
508
+ function backupGuardGetCurrentUrlScheme()
509
+ {
510
+ return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')?'https':'http';
511
+ }
512
+
513
+ function backupGuardValidateLicense()
514
+ {
515
+ $pluginCapabilities = backupGuardGetCapabilities();
516
+ if ($pluginCapabilities == BACKUP_GUARD_CAPABILITIES_FREE) {
517
+ return true;
518
+ }
519
+
520
+ //only check once per day
521
+ $ts = (int)SGConfig::get('SG_LICENSE_CHECK_TS');
522
+ if (time() - $ts < SG_LICENSE_CHECK_TIMEOUT) {
523
+ return true;
524
+ }
525
+
526
+ require_once(SG_LIB_PATH.'SGAuthClient.php');
527
+
528
+ $url = site_url();
529
+
530
+ $auth = SGAuthClient::getInstance();
531
+ $res = $auth->validateUrl($url);
532
+
533
+ if ($res === -1) { //login is required
534
+ backup_guard_login_page();
535
+ return false;
536
+ }
537
+ else if ($res === false) { //invalid license
538
+ backup_guard_link_license_page();
539
+ return false;
540
+ }
541
+ else {
542
+ SGConfig::set('SG_LICENSE_CHECK_TS', time(), true);
543
+ SGConfig::set('SG_LICENSE_KEY', $res, true);
544
+ }
545
+
546
+ return true;
547
+ }
548
+
549
+ //returns true if string $haystack ends with string $needle or $needle is an empty string
550
+ function backupGuardStringEndsWith($haystack, $needle)
551
+ {
552
+ $length = strlen($needle);
553
+
554
+ return $length === 0 ||
555
+ (substr($haystack, -$length) === $needle);
556
+ }
557
+ //returns true if string $haystack starts with string $needle
558
+ function backupGuardStringStartsWith($haystack, $needle)
559
+ {
560
+ $length = strlen($needle);
561
+ return (substr($haystack, 0, $length) === $needle);
562
+ }
563
+
564
+ function backupGuardGetDbTables(){
565
+ $sgdb = SGDatabase::getInstance();
566
+ $tables = $sgdb->query("SHOW TABLES");
567
+ $tablesKey = 'Tables_in_'.SG_DB_NAME;
568
+ $tableNames = array();
569
+ $customTablesToExclude = str_replace(' ', '', SGConfig::get('SG_TABLES_TO_EXCLUDE'));
570
+ $tablesToExclude = explode(',', $customTablesToExclude);
571
+ foreach ($tables as $table):
572
+ $tableName = $table[$tablesKey];
573
+ if($tableName != SG_ACTION_TABLE_NAME && $tableName != SG_CONFIG_TABLE_NAME && $tableName != SG_SCHEDULE_TABLE_NAME){
574
+ array_push($tableNames, array('name'=>$tableName,
575
+ 'current'=> backupGuardStringStartsWith($tableName, SG_ENV_DB_PREFIX)? 'true':'false',
576
+ 'disabled'=>in_array($tableName,$tablesToExclude)? 'disabled':''
577
+ ));
578
+ }
579
+ endforeach;
580
+ usort($tableNames, function ($name1, $name2){
581
+ if(backupGuardStringStartsWith($name1['name'], SG_ENV_DB_PREFIX)){
582
+ if(backupGuardStringStartsWith($name2['name'], SG_ENV_DB_PREFIX)){
583
+ return 0;
584
+ }
585
+ return -1;
586
+ }
587
+ return 1;
588
+ });
589
+ return $tableNames;
590
+ }
591
+
592
+ function backupGuardGetBackupTablesHTML($defaultChecked = false){
593
+ $tables = backupGuardGetDbTables();
594
+ ?>
595
+
596
+ <div class="checkbox">
597
+ <label for="custombackupdb-chbx">
598
+ <input type="checkbox" class="sg-custom-option" name="backupDatabase" id="custombackupdb-chbx" <?php echo $defaultChecked?'checked':'' ?>>
599
+ <?php _backupGuardT('Backup database'); ?>
600
+ </label>
601
+ <div class="col-md-12 sg-checkbox sg-backup-db-options">
602
+ <div class="checkbox">
603
+ <label for="custombackupdbfull-radio" class="sg-backup-db-mode" title="<?php _backupGuardT('Backup all tables found in the database')?>">
604
+ <input type="radio" name="backupDBType" id="custombackupdbfull-radio" value="0" checked>
605
+ <?php _backupGuardT('Full'); ?>
606
+ </label>
607
+ <label for="custombackupdbcurent-radio" class="sg-backup-db-mode" title="<?php echo _backupGuardT('Backup tables related to the current WordPress installation. Only tables with', true).' '.SG_ENV_DB_PREFIX.' '._backupGuardT('will be backed up', true)?>">
608
+ <input type="radio" name="backupDBType" id="custombackupdbcurent-radio" value="1">
609
+ <?php _backupGuardT('Only WordPress'); ?>
610
+ </label>
611
+ <label for="custombackupdbcustom-radio" class="sg-backup-db-mode" title="<?php _backupGuardT('Select tables you want to include in your backup') ?>">
612
+ <input type="radio" name="backupDBType" id="custombackupdbcustom-radio" value="2">
613
+ <?php _backupGuardT('Custom'); ?>
614
+ </label>
615
+ <!--Tables-->
616
+ <div class="col-md-12 sg-custom-backup-tables">
617
+ <?php foreach ($tables as $table): ?>
618
+ <div class="checkbox">
619
+ <label for="<?php echo $table['name']?>">
620
+ <input type="checkbox" name="table[]" current="<?php echo $table['current'] ?>" <?php echo $table['disabled'] ?> id="<?php echo $table['name']?>" value="<?php echo $table['name'];?>">
621
+ <?php echo basename($table['name']);?>
622
+ <?php if($table['disabled']) {?>
623
+ <span class="sg-disableText"><?php _backupGuardT('(excluded from settings)') ?></span>
624
+ <?php } ?>
625
+ </label>
626
+ </div>
627
+ <?php endforeach;?>
628
+ </div>
629
+ </div>
630
+ </div>
631
+
632
+ </div>
633
+
634
+ <?php
635
+
636
+ }
637
+
638
+ function backupGuardIsAccountGold()
639
+ {
640
+ return strpos("gold", SG_PRODUCT_IDENTIFIER)!== false;
641
+ }
642
+
643
+ function backupGuardGetProductName()
644
+ {
645
+ $name = '';
646
+ switch (SG_PRODUCT_IDENTIFIER) {
647
+ case 'backup-guard-wp-silver':
648
+ $name = 'Silver';
649
+ break;
650
+ case 'backup-guard-wp-platinum':
651
+ $name = 'Platinum';
652
+ break;
653
+ case 'backup-guard-en':
654
+ case 'backup-guard-en-regular':
655
+ $name = 'Regular';
656
+ break;
657
+ case 'backup-guard-en-extended':
658
+ $name = 'Extended';
659
+ break;
660
+ case 'backup-guard-wp-gold':
661
+ $name = 'Gold';
662
+ break;
663
+ case 'backup-guard-wp-free':
664
+ $name = 'Free';
665
+ break;
666
+ }
667
+
668
+ return $name;
669
+ }
670
+
671
+ function backupGuardGetFileSelectiveRestore()
672
+ {
673
+ ?>
674
+ <div class="col-md-12 sg-checkbox sg-restore-files-options">
675
+ <div class="checkbox">
676
+ <label for="restorefilesfull-radio" class="sg-restore-files-mode" >
677
+ <input type="radio" name="restoreFilesType" checked id="restorefilesfull-radio" value="0">
678
+ <?php _backupGuardT('Full'); ?>
679
+ </label>
680
+
681
+ <label for="restorefilescustom-radio" class="sg-restore-files-mode">
682
+ <input type="radio" name="restoreFilesType" id="restorefilescustom-radio" value="1">
683
+ <?php _backupGuardT('Custom'); ?>
684
+ </label>
685
+ <!--Files-->
686
+ <div class="col-md-12 sg-file-selective-restore">
687
+ <div id="fileSystemTreeContainer"></div>
688
+ </div>
689
+ </div>
690
+ </div>
691
+ <?php
692
+ }
com/core/log/SGFileLogHandler.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_LOG_PATH.'SGILogHandler.php');
3
+
4
+ class SGFileLogHandler implements SGILogHandler
5
+ {
6
+ protected $filePath = '';
7
+
8
+ public function __construct($filePath)
9
+ {
10
+ $this->filePath = $filePath;
11
+ }
12
+
13
+ public function canBeCleared()
14
+ {
15
+ return true;
16
+ }
17
+
18
+ public function isWritable()
19
+ {
20
+ if (!file_exists($this->filePath))
21
+ {
22
+ $fp = fopen($this->filePath, 'wb');
23
+ if (!$fp)
24
+ {
25
+ return false;
26
+ }
27
+
28
+ fclose($fp);
29
+ }
30
+
31
+ return is_writable($this->filePath);
32
+ }
33
+
34
+ public function write($message)
35
+ {
36
+ if (!self::isWritable())
37
+ {
38
+ return false;
39
+ }
40
+
41
+ $date = backupGuardConvertDateTimezone(@date('Y-m-d H:i'));
42
+ $content = $date.': '.$message.PHP_EOL;
43
+ if (file_put_contents($this->filePath, $content, FILE_APPEND))
44
+ {
45
+ return true;
46
+ }
47
+
48
+ return false;
49
+ }
50
+
51
+ public function readAll()
52
+ {
53
+ if (!is_readable($this->filePath))
54
+ {
55
+ return false;
56
+ }
57
+
58
+ $content = file_get_contents($this->filePath);
59
+ return $content;
60
+ }
61
+
62
+ public function clear()
63
+ {
64
+ if (!self::isWritable())
65
+ {
66
+ return false;
67
+ }
68
+
69
+ return @unlink($this->filePath);
70
+ }
71
+ }
com/core/log/SGILogHandler.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface SGILogHandler {
4
+ public function canBeCleared();
5
+ public function isWritable();
6
+ public function write($message);
7
+ public function readAll();
8
+ public function clear();
9
+ }
10
+ ?>
com/core/log/SGLog.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGLog
4
+ {
5
+ private static $logHandlers = array();
6
+
7
+ public static function registerLogHandler(SGILogHandler $logHandler, $level = 0, $mainHandler = false)
8
+ {
9
+ if ($logHandler instanceof SGILogHandler)
10
+ {
11
+ self::$logHandlers[] = array('logHandler' => $logHandler, 'level' => $level, 'mainHandler' => $mainHandler);
12
+ return true;
13
+ }
14
+ return false;
15
+ }
16
+
17
+ public static function removeAllHandlers($level = 0)
18
+ {
19
+ if ($level == 0)
20
+ {
21
+ self::$logHandlers = array();
22
+ return;
23
+ }
24
+
25
+ $handlers = array();
26
+ foreach (self::$logHandlers as $logHandler)
27
+ {
28
+ if (!self::levelBelongsToLevel($level, $logHandler['level']))
29
+ {
30
+ $handlers[] = $logHandler;
31
+ }
32
+ }
33
+ self::$logHandlers = $handlers;
34
+ }
35
+
36
+ private static function levelBelongsToLevel($level, $levelToBelong)
37
+ {
38
+ if ((($levelToBelong|SG_LOG_LEVEL_HIGH) == $level) ||
39
+ (($levelToBelong|SG_LOG_LEVEL_LOW) == $level) ||
40
+ (($levelToBelong|SG_LOG_LEVEL_MEDIUM) == $level) ||
41
+ (($levelToBelong|SG_LOG_LEVEL_MEDIUM|SG_LOG_LEVEL_LOW) == $level) ||
42
+ (($levelToBelong|SG_LOG_LEVEL_MEDIUM|SG_LOG_LEVEL_HIGH) == $level) ||
43
+ (($levelToBelong|SG_LOG_LEVEL_LOW|SG_LOG_LEVEL_HIGH) == $level))
44
+ {
45
+ return true;
46
+ }
47
+
48
+ return false;
49
+ }
50
+
51
+ public static function write($message, $level = 0)
52
+ {
53
+ foreach(self::$logHandlers as $logHandler)
54
+ {
55
+ if ($level)
56
+ {
57
+ if (self::levelBelongsToLevel($level, $logHandler['level']))
58
+ {
59
+ $logHandler['logHandler']->write($message);
60
+ }
61
+ continue;
62
+ }
63
+ $logHandler['logHandler']->write($message);
64
+ }
65
+ }
66
+
67
+ public static function readAll()
68
+ {
69
+ foreach(self::$logHandlers as $logHandler)
70
+ {
71
+ if ($logHandler['mainHandler'])
72
+ {
73
+ return $logHandler['logHandler']->readAll();
74
+ }
75
+ }
76
+ return array();
77
+ }
78
+
79
+ public static function clear($level = 0)
80
+ {
81
+ foreach(self::$logHandlers as $logHandler)
82
+ {
83
+ if ($level)
84
+ {
85
+ if (self::levelBelongsToLevel($level, $logHandler['level']))
86
+ {
87
+ $logHandler['logHandler']->clear();
88
+ }
89
+ continue;
90
+ }
91
+ $logHandler['logHandler']->clear();
92
+ }
93
+ }
94
+ }
com/core/notice/SGINoticeAdapter.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface SGINoticeAdapter
4
+ {
5
+ public function addNotice($notice, $type);
6
+ public function addNoticeFromTemplate($template, $type);
7
+ public function renderAll();
8
+ }
com/core/notice/SGNotice.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGNotice
4
+ {
5
+ private static $instance = null;
6
+
7
+ public static function getInstance()
8
+ {
9
+ if (!self::$instance) {
10
+ self::$instance = self::createAdapterInstance();
11
+ }
12
+
13
+ return self::$instance;
14
+ }
15
+
16
+ private static function createAdapterInstance()
17
+ {
18
+ $className = 'SGNoticeAdapter'.SG_ENV_ADAPTER;
19
+ require_once(dirname(__FILE__).'/'.$className.'.php');
20
+ $adapter = new $className();
21
+ return $adapter;
22
+ }
23
+
24
+ private function __construct()
25
+ {
26
+
27
+ }
28
+
29
+ private function __clone()
30
+ {
31
+
32
+ }
33
+ }
com/core/notice/SGNoticeAdapterWordpress.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/SGINoticeAdapter.php');
3
+
4
+ class SGNoticeAdapterWordpress implements SGINoticeAdapter
5
+ {
6
+ protected $notices = array();
7
+
8
+ public function __construct()
9
+ {
10
+ $this->notices = array(
11
+ SG_NOTICE_SUCCESS => array(),
12
+ SG_NOTICE_WARNING => array(),
13
+ SG_NOTICE_ERROR => array()
14
+ );
15
+ }
16
+
17
+ public function addNotice($notice, $type, $dismissible = false, $id = '')
18
+ {
19
+ $this->notices[$type][] = array(
20
+ 'message' => $notice,
21
+ 'dismissible' => $dismissible,
22
+ 'id' => $id
23
+ );
24
+ }
25
+
26
+ public function addNoticeFromTemplate($template, $type, $dismissible = false)
27
+ {
28
+ $path = SG_NOTICE_TEMPLATES_PATH.$template.'.php';
29
+
30
+ ob_start();
31
+ @include($path);
32
+ $content = ob_get_clean();
33
+
34
+ $this->addNotice($content, $type, $dismissible, $template);
35
+ }
36
+
37
+ public function renderAll()
38
+ {
39
+ foreach ($this->notices as $type => $notices) {
40
+ foreach ($notices as $notice) {
41
+ $class = 'notice notice-'.$type;
42
+ if ($notice['dismissible']) {
43
+ $class .= ' is-dismissible';
44
+ }
45
+ echo '<div data-notice-id="'.$notice['id'].'" class="'.$class.'"><p>'.$notice['message'].'</p></div>';
46
+ }
47
+ }
48
+
49
+ }
50
+ }
com/core/notice/SGNoticeHandler.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGNoticeHandler
4
+ {
5
+ public function run()
6
+ {
7
+ $this->checkTimeoutError();
8
+ $this->checkMigrationError();
9
+ $this->checkRestoreNotWritableError();
10
+ $this->checkLiteSpeedWarning();
11
+ }
12
+
13
+ private function checkTimeoutError()
14
+ {
15
+ if (SGConfig::get('SG_EXCEPTION_TIMEOUT_ERROR')) {
16
+ SGNotice::getInstance()->addNoticeFromTemplate('timeout_error', SG_NOTICE_ERROR, true);
17
+ }
18
+ }
19
+
20
+ private function checkMigrationError()
21
+ {
22
+ if (SGConfig::get('SG_BACKUP_SHOW_MIGRATION_ERROR')) {
23
+ SGNotice::getInstance()->addNoticeFromTemplate('migration_error', SG_NOTICE_ERROR, true);
24
+ }
25
+ }
26
+
27
+ private function checkRestoreNotWritableError()
28
+ {
29
+ if (SGConfig::get('SG_BACKUP_SHOW_NOT_WRITABLE_ERROR')) {
30
+ SGNotice::getInstance()->addNoticeFromTemplate('restore_notwritable_error', SG_NOTICE_ERROR, true);
31
+ }
32
+ }
33
+
34
+ private function checkLiteSpeedWarning()
35
+ {
36
+ $server = '';
37
+ if (isset($_SERVER['SERVER_SOFTWARE'])) {
38
+ $server = strtolower($_SERVER['SERVER_SOFTWARE']);
39
+ }
40
+
41
+ //check if LiteSpeed server is running
42
+ if (strpos($server, 'litespeed') !== false) {
43
+ $htaccessContent = '';
44
+ if (is_readable(ABSPATH.'.htaccess')) {
45
+ $htaccessContent = @file_get_contents(ABSPATH.'.htaccess');
46
+ if (!$htaccessContent) {
47
+ $htaccessContent = '';
48
+ }
49
+ }
50
+
51
+ if (!$htaccessContent || !preg_match('/noabort/i', $htaccessContent)) {
52
+ SGNotice::getInstance()->addNoticeFromTemplate('litespeed_warning', SG_NOTICE_WARNING);
53
+ }
54
+ }
55
+ }
56
+ }
com/core/restore/SGExternalRestore.php ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ abstract class SGExternalRestore
4
+ {
5
+ private static $instance = null;
6
+
7
+ public static function getInstance()
8
+ {
9
+ if (!self::$instance) {
10
+ self::$instance = self::createChildInstance();
11
+ }
12
+
13
+ return self::$instance;
14
+ }
15
+
16
+ private static function createChildInstance()
17
+ {
18
+ $className = 'SGExternalRestore'.SG_ENV_ADAPTER;
19
+ require_once(dirname(__FILE__).'/'.$className.'.php');
20
+ $child = new $className();
21
+ return $child;
22
+ }
23
+
24
+ protected function __construct()
25
+ {
26
+
27
+ }
28
+
29
+ private function __clone()
30
+ {
31
+
32
+ }
33
+
34
+ public function getSourceFilePath()
35
+ {
36
+ return SG_PUBLIC_PATH.'restore_'.strtolower(SG_ENV_ADAPTER).'.php';
37
+ }
38
+
39
+ public function getDestinationFilePath()
40
+ {
41
+ //get already saved restore path
42
+ $path = SGConfig::get('SG_EXTERNAL_RESTORE_PATH', true);
43
+
44
+ if (!$path) {
45
+ $path = $this->getDestinationPath().SG_EXTERNAL_RESTORE_FILE;
46
+ SGConfig::set('SG_EXTERNAL_RESTORE_PATH', $path, true);
47
+ }
48
+
49
+ return $path;
50
+ }
51
+
52
+ public function getDestinationFileUrl(&$key = '')
53
+ {
54
+ //we use this key to deny direct access to the file
55
+ $key = SGConfig::get('SG_BACKUP_CURRENT_KEY', true);
56
+
57
+ //get already saved restore url
58
+ $url = SGConfig::get('SG_EXTERNAL_RESTORE_URL', true);
59
+
60
+ if (!$url) {
61
+ $url = $this->getDestinationUrl().SG_EXTERNAL_RESTORE_FILE.'?k='.$key;
62
+ SGConfig::set('SG_EXTERNAL_RESTORE_URL', $url, true);
63
+ }
64
+
65
+ return $url;
66
+ }
67
+
68
+ public static function isEnabled()
69
+ {
70
+ return SGConfig::get('SG_EXTERNAL_RESTORE_ENABLED')?true:false;
71
+ }
72
+
73
+ protected static function setEnabled($enabled)
74
+ {
75
+ SGConfig::set('SG_EXTERNAL_RESTORE_ENABLED', ($enabled?1:0), true);
76
+ }
77
+
78
+ private function getConstants($actionId)
79
+ {
80
+ $key = '';
81
+ $destinationUrl = $this->getDestinationFileUrl($key);
82
+ $isMultisite = backupGuardIsMultisite();
83
+
84
+ return array(
85
+ 'SG_ACTION_ID' => $actionId,
86
+ 'SG_PLUGIN_NAME' => SG_PLUGIN_NAME,
87
+ 'SG_ENV_DB_PREFIX' => SG_ENV_DB_PREFIX,
88
+ 'SG_SITE_URL' => SG_SITE_URL,
89
+ 'SG_BACKUP_SITE_URL' => SG_BACKUP_SITE_URL,
90
+ 'SG_PUBLIC_URL' => SG_PUBLIC_URL,
91
+ 'SG_BACKUP_DIRECTORY' => SG_BACKUP_DIRECTORY,
92
+ 'SG_PING_FILE_PATH' => SG_PING_FILE_PATH,
93
+ 'BG_PLUGIN_URL' => SG_PUBLIC_BACKUPS_URL,
94
+ 'BG_RESTORE_KEY' => $key,
95
+ 'BG_RESTORE_URL' => $destinationUrl,
96
+ 'BG_IS_MULTISITE' => $isMultisite,
97
+ 'SG_MISC_MIGRATABLE_TABLES' => SG_MISC_MIGRATABLE_TABLES,
98
+ 'SG_MULTISITE_TABLES_TO_MIGRATE' => SG_MULTISITE_TABLES_TO_MIGRATE,
99
+ 'SG_DB_NAME' => SG_DB_NAME,
100
+ 'DOMAIN_CURRENT_SITE' => defined('DOMAIN_CURRENT_SITE')?DOMAIN_CURRENT_SITE:'',
101
+ 'PATH_CURRENT_SITE' => defined('PATH_CURRENT_SITE')?PATH_CURRENT_SITE:'',
102
+ 'SG_SUBDOMAIN_INSTALL' => SG_SUBDOMAIN_INSTALL,
103
+ 'WP_CONTENT_DIR' => WP_CONTENT_DIR,
104
+ 'SG_BACKUP_DATABASE_EXCLUDE' => SG_BACKUP_DATABASE_EXCLUDE,
105
+ 'SG_MYSQL_VERSION' => SG_MYSQL_VERSION,
106
+ 'SG_WP_OPTIONS_MIGRATABLE_VALUES' => SG_WP_OPTIONS_MIGRATABLE_VALUES,
107
+ 'SG_WP_USERMETA_MIGRATABLE_VALUES' => SG_WP_USERMETA_MIGRATABLE_VALUES
108
+ );
109
+ }
110
+
111
+ public function prepare($actionId)
112
+ {
113
+ $res = false;
114
+
115
+ //reset everything
116
+ self::setEnabled(false);
117
+ SGConfig::set('SG_EXTERNAL_RESTORE_URL', '', true);
118
+ SGConfig::set('SG_EXTERNAL_RESTORE_PATH', '', true);
119
+
120
+ if ($this->canPrepare()) {
121
+ $contents = @file_get_contents($this->getSourceFilePath());
122
+ if ($contents) {
123
+ $constants = $this->getConstants($actionId);
124
+ $customConstants = $this->getCustomConstants();
125
+ $allConstants = array_merge($constants, $customConstants);
126
+
127
+ $defines = '';
128
+ foreach ($allConstants as $key => $val) {
129
+ $defines .= "define('$key', '$val');\n";
130
+ }
131
+
132
+ //put all defines inside the file
133
+ $contents = str_replace('#SG_DYNAMIC_DEFINES#', $defines, $contents);
134
+
135
+ //create new copy
136
+ $res = (bool)@file_put_contents($this->getDestinationFilePath(), $contents);
137
+ }
138
+ }
139
+
140
+ self::setEnabled($res);
141
+
142
+ return $res;
143
+ }
144
+
145
+ public function cleanup()
146
+ {
147
+ if (file_exists($this->getDestinationFilePath())) {
148
+ $actions = SGBackup::getRunningActions();
149
+ if (empty($actions)) {
150
+ @unlink($this->getDestinationFilePath());
151
+ }
152
+ }
153
+ }
154
+
155
+ abstract protected function canPrepare();
156
+
157
+ abstract protected function getCustomConstants();
158
+
159
+ abstract public function getDestinationPath();
160
+
161
+ abstract public function getDestinationUrl();
162
+ }
com/core/restore/SGExternalRestoreWordpress.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGExternalRestoreWordpress extends SGExternalRestore
4
+ {
5
+ private $destinationPath = '';
6
+ private $destinationUrl = '';
7
+
8
+ protected function canPrepare()
9
+ {
10
+ //please lets try to check if it can work in the root directory
11
+ $this->destinationUrl = rtrim(SG_SITE_URL, '/').'/';
12
+ $this->destinationPath = ABSPATH;
13
+ if ($this->testUrlAvailability($this->destinationUrl, $this->destinationPath)) {
14
+ return true;
15
+ }
16
+
17
+ //then we check for the uploads directory
18
+ $this->destinationUrl = SG_UPLOAD_URL.'/';
19
+ $this->destinationPath = SG_UPLOAD_PATH.'/';
20
+ if ($this->testUrlAvailability($this->destinationUrl, $this->destinationPath)) {
21
+ return true;
22
+ }
23
+
24
+ return false;
25
+ }
26
+
27
+ protected function getCustomConstants()
28
+ {
29
+ return array(
30
+ 'ABSPATH' => ABSPATH,
31
+ 'DB_NAME' => DB_NAME,
32
+ 'DB_USER' => DB_USER,
33
+ 'DB_PASSWORD' => DB_PASSWORD,
34
+ 'DB_HOST' => DB_HOST,
35
+ 'DB_CHARSET' => DB_CHARSET,
36
+ 'DB_COLLATE' => DB_COLLATE
37
+ );
38
+ }
39
+
40
+ public function getDestinationPath()
41
+ {
42
+ return $this->destinationPath;
43
+ }
44
+
45
+ public function getDestinationUrl()
46
+ {
47
+ return $this->destinationUrl;
48
+ }
49
+
50
+ private function testUrlAvailability($url, $path)
51
+ {
52
+ $path .= 'bg_test.php';
53
+ $url .= 'bg_test.php';
54
+
55
+ if (@file_put_contents($path, '<?php echo "ok"; ?>')) {
56
+ $headers = @wp_remote_get($url, array(
57
+ 'sslverify' => false
58
+ ));
59
+ $isWpError = is_wp_error($headers);
60
+ if (!$isWpError && !empty($headers) && $headers['response']['code'] == '200') {
61
+ @unlink($path);
62
+ return true;
63
+ }
64
+ else {
65
+ $headers = @wp_remote_get($url, array(
66
+ 'sslverify' => false,
67
+ 'stream' => true
68
+ ));
69
+ $isWpError = is_wp_error($headers);
70
+ if (!$isWpError && !empty($headers) && $headers['response']['code'] == '200') {
71
+ @unlink($path);
72
+ return true;
73
+ }
74
+ }
75
+ @unlink($path);
76
+ }
77
+
78
+ return false;
79
+ }
80
+ }
com/core/schedule/SGIScheduleAdapter.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface SGIScheduleAdapter
4
+ {
5
+ public static function create($cron, $id);
6
+ public static function remove($cron);
7
+ public static function isCronAvailable();
8
+ }
com/core/schedule/SGSchedule.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGSchedule
4
+ {
5
+ public static function create($cron, $id)
6
+ {
7
+ $className = self::getCurrentScheduleClassName();
8
+ require_once(SG_SCHEDULE_PATH.$className.'.php');
9
+ $className::create($cron, $id);
10
+ }
11
+
12
+ public static function getCronExecutionData($cron)
13
+ {
14
+ $className = self::getCurrentScheduleClassName();
15
+ require_once(SG_SCHEDULE_PATH.$className.'.php');
16
+ return $className::getCronExecutionData($cron);
17
+ }
18
+
19
+ public static function remove($id)
20
+ {
21
+ $className = self::getCurrentScheduleClassName();
22
+ require_once(SG_SCHEDULE_PATH.$className.'.php');
23
+ $className::remove($id);
24
+ }
25
+
26
+ public static function isCronAvailable()
27
+ {
28
+ $className = self::getCurrentScheduleClassName();
29
+ require_once(SG_SCHEDULE_PATH.$className.'.php');
30
+ return $className::isCronAvailable();
31
+ }
32
+
33
+ private static function getCurrentScheduleClassName()
34
+ {
35
+ return 'SGScheduleAdapter'.SG_ENV_ADAPTER;
36
+ }
37
+ }
com/core/schedule/SGScheduleAdapterWordpress.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_SCHEDULE_PATH.'SGIScheduleAdapter.php');
3
+
4
+ class SGScheduleAdapterWordpress implements SGIScheduleAdapter
5
+ {
6
+ public static function create($cron, $id = SG_SCHEDULER_DEFAULT_ID)
7
+ {
8
+ if (!self::isCronAvailable()) {
9
+ return false;
10
+ }
11
+
12
+ $cronExecutionData = self::getCronExecutionData($cron);
13
+ $time = $cronExecutionData['time'];
14
+ $recurrence = $cronExecutionData['recurrence'];
15
+
16
+ $args = array((int)$id);
17
+
18
+ $dateString = backupGuardConvertDateTimezone(@date("Y-m-d H:i:s", $time));
19
+ $time = strtotime($dateString);
20
+ $res = wp_schedule_event($time, $recurrence, SG_SCHEDULE_ACTION, $args);
21
+ }
22
+
23
+ public static function getCronExecutionData($cron)
24
+ {
25
+ $recurrence = '';
26
+ $tmpTime = self::getTmpTime($cron['intervalHour']);
27
+
28
+ if ($cron['interval'] == BG_SCHEDULE_INTERVAL_HOURLY) {
29
+ $recurrence = 'hourly';
30
+ $time = time() + 3600;
31
+ }
32
+ else if ($cron['interval'] == BG_SCHEDULE_INTERVAL_DAILY) {
33
+ $recurrence = 'daily';
34
+
35
+ if ($tmpTime < time()) {
36
+ $time = strtotime('Next day '.sprintf("%02d:00", $cron['intervalHour']));
37
+ }
38
+ else {
39
+ $time = $tmpTime;
40
+ }
41
+ }
42
+ else if ($cron['interval'] == BG_SCHEDULE_INTERVAL_WEEKLY) {
43
+ $recurrence = 'weekly';
44
+ $dayOfInterval = $cron['dayOfInterval'];
45
+
46
+ switch ($dayOfInterval) {
47
+ case 1:
48
+ $dayOfInterval = 'Monday';
49
+ break;
50
+ case 2:
51
+ $dayOfInterval = 'Tuesday';
52
+ break;
53
+ case 3:
54
+ $dayOfInterval = 'Wednesday';
55
+ break;
56
+ case 4:
57
+ $dayOfInterval = 'Thursday';
58
+ break;
59
+ case 5:
60
+ $dayOfInterval = 'Friday';
61
+ break;
62
+ case 6:
63
+ $dayOfInterval = 'Saturday';
64
+ break;
65
+ case 7:
66
+ $dayOfInterval = 'Sunday';
67
+ break;
68
+ default:
69
+ $dayOfInterval = 'Monday';
70
+ break;
71
+ }
72
+
73
+ if ($tmpTime < time()) {
74
+ $time = strtotime('Next '.$dayOfInterval.' '.sprintf("%02d:00", $cron['intervalHour']));
75
+ }
76
+ else {
77
+ $time = strtotime('this '.$dayOfInterval.' '.sprintf("%02d:00", $cron['intervalHour']));
78
+ }
79
+ }
80
+ else if ($cron['interval'] == BG_SCHEDULE_INTERVAL_MONTHLY) {
81
+ $recurrence = 'monthly';
82
+ $dayOfInterval = $cron['dayOfInterval'];
83
+ $today = (int)date('d');
84
+
85
+ if ($today < $dayOfInterval) {
86
+ $time = $tmpTime + ($dayOfInterval - $today) * SG_ONE_DAY_IN_SECONDS;
87
+ }
88
+ else {
89
+ if ($tmpTime > time() && $today == $dayOfInterval) {
90
+ $time = $tmpTime;
91
+ }
92
+ else {
93
+ $time = strtotime('first day of next month '.sprintf("%02d:00", $cron['intervalHour']));
94
+ $time += ($dayOfInterval - 1) * SG_ONE_DAY_IN_SECONDS;
95
+ }
96
+ }
97
+ }
98
+ else {
99
+ $recurrence = 'yearly';
100
+ $time = strtotime('Next year today '.sprintf("%02d:00", $cron['intervalHour']));
101
+ }
102
+
103
+ return array(
104
+ 'time' => $time,
105
+ 'recurrence' => $recurrence
106
+ );
107
+ }
108
+
109
+ public static function remove($id = SG_SCHEDULER_DEFAULT_ID)
110
+ {
111
+ $args = array((int)$id);
112
+ wp_clear_scheduled_hook(SG_SCHEDULE_ACTION, $args);
113
+ }
114
+
115
+ public static function getTmpTime($hours)
116
+ {
117
+ return strtotime('Today '.sprintf("%02d:00", $hours));
118
+ }
119
+
120
+ public static function isCronAvailable()
121
+ {
122
+ return defined('DISABLE_WP_CRON')?DISABLE_WP_CRON:true;
123
+ }
124
+ }
com/core/storage/SGDropbox.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_LIB_PATH.'Dropbox/Exception.php');
3
+ require_once(SG_LIB_PATH.'Dropbox/Exception/ProtocolError.php');
4
+ require_once(SG_LIB_PATH.'Dropbox/Exception/BadRequest.php');
5
+ require_once(SG_LIB_PATH.'Dropbox/Exception/BadResponse.php');
6
+ require_once(SG_LIB_PATH.'Dropbox/Exception/BadResponseCode.php');
7
+ require_once(SG_LIB_PATH.'Dropbox/Exception/InvalidAccessToken.php');
8
+ require_once(SG_LIB_PATH.'Dropbox/Exception/NetworkIO.php');
9
+ require_once(SG_LIB_PATH.'Dropbox/Exception/RetryLater.php');
10
+ require_once(SG_LIB_PATH.'Dropbox/Exception/ServerError.php');
11
+ require_once(SG_LIB_PATH.'Dropbox/StreamReadException.php');
12
+ require_once(SG_LIB_PATH.'Dropbox/WebAuthException/BadState.php');
13
+ require_once(SG_LIB_PATH.'Dropbox/WebAuthException/Csrf.php');
14
+ require_once(SG_LIB_PATH.'Dropbox/WebAuthException/BadRequest.php');
15
+ require_once(SG_LIB_PATH.'Dropbox/WebAuthException/Provider.php');
16
+ require_once(SG_LIB_PATH.'Dropbox/WebAuthException/NotApproved.php');
17
+ require_once(SG_LIB_PATH.'Dropbox/AppInfoLoadException.php');
18
+ require_once(SG_LIB_PATH.'Dropbox/AuthInfoLoadException.php');
19
+ require_once(SG_LIB_PATH.'Dropbox/DeserializeException.php');
20
+ require_once(SG_LIB_PATH.'Dropbox/Checker.php');
21
+ require_once(SG_LIB_PATH.'Dropbox/ValueStore.php');
22
+ require_once(SG_LIB_PATH.'Dropbox/ArrayEntryStore.php');
23
+ require_once(SG_LIB_PATH.'Dropbox/Host.php');
24
+ require_once(SG_LIB_PATH.'Dropbox/Util.php');
25
+ require_once(SG_LIB_PATH.'Dropbox/RootCertificates.php');
26
+ require_once(SG_LIB_PATH.'Dropbox/Curl.php');
27
+ require_once(SG_LIB_PATH.'Dropbox/CurlStreamRelay.php');
28
+ require_once(SG_LIB_PATH.'Dropbox/HttpResponse.php');
29
+ require_once(SG_LIB_PATH.'Dropbox/AppInfo.php');
30
+ require_once(SG_LIB_PATH.'Dropbox/WriteMode.php');
31
+ require_once(SG_LIB_PATH.'Dropbox/RequestUtil.php');
32
+ require_once(SG_LIB_PATH.'Dropbox/DropboxMetadataHeaderCatcher.php');
33
+ require_once(SG_LIB_PATH.'Dropbox/Path.php');
34
+ require_once(SG_LIB_PATH.'Dropbox/Client.php');
35
+ require_once(SG_LIB_PATH.'Dropbox/AuthBase.php');
36
+ require_once(SG_LIB_PATH.'Dropbox/WebAuthBase.php');
37
+ require_once(SG_LIB_PATH.'Dropbox/WebAuth.php');
38
+ require_once(SG_LIB_PATH.'Dropbox/Security.php');
com/core/storage/SGDropboxStorage.php ADDED
@@ -0,0 +1,371 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(SG_STORAGE_PATH.'SGStorage.php');
3
+
4
+ use \Dropbox as dbx;
5
+
6
+ class SGDropboxStorage extends SGStorage
7
+ {
8
+ private $client = null;
9
+
10
+ public function init()
11
+ {
12
+ //check if curl extension is loaded
13
+ SGBoot::checkRequirement('curl');
14
+
15
+ // Dropbox api 2
16
+ $this->setActiveDirectory('');
17
+
18
+ @set_exception_handler(array('SGDropboxStorage', 'exceptionHandler'));
19
+ require_once(SG_STORAGE_PATH.'SGDropbox.php');
20
+ }
21
+
22
+ public static function exceptionHandler($exception)
23
+ {
24
+ if(SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
25
+ wp_die($exception->getMessage());
26
+ }
27
+ elseif (SG_ENV_ADAPTER == SG_ENV_MAGENTO) {
28
+ die($exception->getMessage());
29
+ }
30
+ }
31
+
32
+ public function connect()
33
+ {
34
+ if ($this->isConnected()) {
35
+ return;
36
+ }
37
+
38
+ $authCode = $this->getAuthCodeFromURL($cancel);
39
+
40
+ if ($cancel) {
41
+ throw new SGExceptionMethodNotAllowed('User did not allow access');
42
+ }
43
+
44
+ $this->auth($authCode);
45
+ }
46
+
47
+ private function auth($authCode = '')
48
+ {
49
+ if ($authCode) {
50
+ try {
51
+ //exchange authorization code for access token
52
+ parse_str($_SERVER['QUERY_STRING'], $arr);
53
+ list($accessToken, $userId, $urlState) = $this->getWebAuth()->finish($arr);
54
+
55
+ $this->setAccessToken($accessToken);
56
+ $accountInfo = $this->getClient()->getAccountInfo();
57
+ SGConfig::set('SG_DROPBOX_CONNECTION_STRING', $accountInfo['email']);
58
+
59
+ $this->connected = true;
60
+ return;
61
+ }
62
+ catch (Exception $ex) {
63
+ }
64
+ }
65
+
66
+ $refUrl = base64_encode($this->getRefURL());
67
+ $authorizeUrl = $this->getWebAuth()->start($refUrl);
68
+ header("Location: $authorizeUrl");
69
+ exit;
70
+ }
71
+
72
+ public function connectOffline()
73
+ {
74
+ if ($this->isConnected()) {
75
+ return;
76
+ }
77
+
78
+ if (!$this->getClient()) {
79
+ throw new SGExceptionNotFound('Access token not found');
80
+ }
81
+
82
+ $this->connected = true;
83
+ }
84
+
85
+ public function checkConnected()
86
+ {
87
+ $accessToken = $this->getAccessToken();
88
+ $this->connected = $accessToken?true:false;
89
+ }
90
+
91
+ public function getListOfFiles()
92
+ {
93
+ if (!$this->isConnected()) {
94
+ throw new SGExceptionForbidden('Permission denied. Authentication required.');
95
+ }
96
+
97
+ $listOfFiles = array();
98
+ $activeDirectory = rtrim($this->getActiveDirectory()).'/';
99
+ $metaData = $this->getClient()->getMetadataWithChildren($activeDirectory.SGConfig::get('SG_STORAGE_BACKUPS_FOLDER_NAME'));
100
+
101
+ foreach($metaData['entries'] as $file) {
102
+ $size = $file['size'];
103
+ $date = $this->standardizeFileCreationDate($file['client_modified']);
104
+ $name = basename($file['path_display']);
105
+
106
+ $listOfFiles[$name] = array(
107
+ 'name' => $name,
108
+ 'size' => $size,
109
+ 'date' => $date,
110
+ 'path' => $file['path_display'],
111
+ );
112
+ }
113
+
114
+ krsort($listOfFiles);
115
+ return $listOfFiles;
116
+ }
117
+
118
+ public function createFolder($folderName)
119
+ {
120
+ if (!$this->isConnected()) {
121
+ throw new SGExceptionForbidden('Permission denied. Authentication required.');
122
+ }
123
+
124
+ $path = rtrim($this->getActiveDirectory(), '/').'/'.$folderName;
125
+ $this->getClient()->createFolder($path);
126
+
127
+ return $path;
128
+ }
129
+
130
+ private $fd = null;
131
+ private $filePath = '';
132
+
133
+ public function downloadFile($file, $size)
134
+ {
135
+ if (!$file) {
136
+ return false;
137
+ }
138
+
139
+ $this->filePath = SG_BACKUP_DIRECTORY.basename($file);
140
+ $this->fd = fopen(SG_BACKUP_DIRECTORY.basename($file), "wb");
141
+
142
+ $client = $this->getClient();
143
+
144
+ $url = "https://content.dropboxapi.com/2/files/download";
145
+ $params = array (
146
+ "path" => $file
147
+ );
148
+
149
+ $curl = $client->mkCurl($url);
150
+ $curl->set(CURLOPT_CUSTOMREQUEST, "POST");
151
+ $curl->addHeader("Dropbox-API-Arg: ".json_encode($params));
152
+ $curl->set(CURLOPT_WRITEFUNCTION, array($this, 'callback'));
153
+
154
+ $response = $curl->exec();
155
+
156
+ fclose($this->fd);
157
+
158
+ if ($response->statusCode !== 200) return false;
159
+
160
+ return true;
161
+ }
162
+
163
+ public function callback ($ch, $data)
164
+ {
165
+ if (!file_exists($this->filePath)) {
166
+ return -1;
167
+ }
168
+
169
+ fwrite($this->fd, $data);
170
+ return strlen($data);
171
+ }
172
+
173
+ private function saveStateData($uploadId, $offset)
174
+ {
175
+ $token = $this->delegate->getToken();
176
+ $actionId = $this->delegate->getActionId();
177
+ $pendingStorageUploads = $this->delegate->getPendingStorageUploads();
178
+ $currentUploadChunksCount = $this->delegate->getCurrentUploadChunksCount();
179
+
180
+ $this->state->setCurrentUploadChunksCount($currentUploadChunksCount);
181
+ $this->state->setStorageType(SG_STORAGE_DROPBOX);
182
+ $this->state->setPendingStorageUploads($pendingStorageUploads);
183
+ $this->state->setToken($token);
184
+ $this->state->setUploadId($uploadId);
185
+ $this->state->setOffset($offset);
186
+ $this->state->setAction(SG_STATE_ACTION_UPLOADING_BACKUP);
187
+ $this->state->setActiveDirectory($this->getActiveDirectory());
188
+ $this->state->setActionId($actionId);
189
+ $this->state->save();
190
+ }
191
+
192
+ public function uploadFile($filePath)
193
+ {
194
+ if (!$this->isConnected()) {
195
+ throw new SGExceptionForbidden('Permission denied. Authentication required.');
196
+ }
197
+
198
+ if (!file_exists($filePath) || !is_readable($filePath)) {
199
+ throw new SGExceptionNotFound('File does not exist or is not readable: '.$filePath);
200
+ }
201
+
202
+ $client = $this->getClient();
203
+ $chunkSizeBytes = 2.0 * 1024 * 1024;
204
+
205
+ //Note: Because PHP's integer type is signed and many platforms use 32bit integers,
206
+ //some filesystem functions may return unexpected results for files which are larger than 2GB.
207
+ $fileSize = backupGuardRealFilesize($filePath);
208
+
209
+ $this->delegate->willStartUpload((int)ceil($fileSize/$chunkSizeBytes));
210
+
211
+ $handle = fopen($filePath, "rb");
212
+ $byteOffset = $this->state->getOffset();
213
+ fseek($handle, $byteOffset);
214
+
215
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
216
+ $data = fread($handle, $chunkSizeBytes);
217
+ $uploadId = $client->chunkedUploadStart($data);
218
+ $byteOffset += strlen($data);
219
+ }
220
+ else {
221
+ $uploadId = $this->state->getUploadId();
222
+ }
223
+
224
+ SGPing::update();
225
+
226
+ while ($byteOffset < $fileSize) {
227
+ $data = fread($handle, $chunkSizeBytes);
228
+ $client->chunkedUploadContinue($uploadId, $byteOffset, $data);
229
+ $byteOffset += strlen($data);
230
+
231
+ if (!$this->delegate->shouldUploadNextChunk()) {
232
+ fclose($handle);
233
+ return;
234
+ }
235
+
236
+ SGPing::update();
237
+
238
+ $shouldReload = $this->shouldReload();
239
+ if ($shouldReload && backupGuardIsReloadEnabled()) {
240
+ $this->saveStateData($uploadId, $byteOffset);
241
+ @fclose($handle);
242
+ $this->reload();
243
+ }
244
+ }
245
+
246
+ $activeDirectory = $this->getActiveDirectory();
247
+
248
+ $path = rtrim($activeDirectory, '/').'/'.basename($filePath);
249
+
250
+ $result = $client->chunkedUploadFinish($uploadId, $path, $byteOffset);
251
+ fclose($handle);
252
+
253
+ return $result;
254
+ }
255
+
256
+ public function fileExists($path)
257
+ {
258
+ $this->connectOffline();
259
+ if (!$this->isConnected()) {
260
+ throw new SGExceptionForbidden('Permission denied. Authentication required.');
261
+ }
262
+
263
+ $client = $this->getClient();
264
+ try {
265
+ $result = $client->searchFileNames(dirname($path), basename($path));
266
+ }
267
+ catch (Exception $e) {
268
+ return false;
269
+ }
270
+
271
+ return $result;
272
+ }
273
+
274
+ public function deleteFile($path)
275
+ {
276
+ $this->connectOffline();
277
+ if (!$this->isConnected()) {
278
+ throw new SGExceptionForbidden('Permission denied. Authentication required.');
279
+ }
280
+
281
+ return $this->getClient()->delete($path);
282
+ }
283
+
284
+ public function deleteFolder($folderName)
285
+ {
286
+ return $this->deleteFile($folderName);
287
+ }
288
+
289
+ private function getAppInfo()
290
+ {
291
+ $key = SG_STORAGE_DROPBOX_KEY;
292
+ $secret = SG_STORAGE_DROPBOX_SECRET;
293
+
294
+ $appInfo = new dbx\AppInfo($key, $secret);
295
+ return $appInfo;
296
+ }
297
+
298
+ private function getAccessToken()
299
+ {
300
+ return SGConfig::get('SG_DROPBOX_ACCESS_TOKEN');
301
+ }
302
+
303
+ private function setAccessToken($accessToken)
304
+ {
305
+ SGConfig::set('SG_DROPBOX_ACCESS_TOKEN', $accessToken, true);
306
+ }
307
+
308
+ private function getClient()
309
+ {
310
+ if (!$this->client) {
311
+ $accessToken = $this->getAccessToken();
312
+ if (!$accessToken) {
313
+ return false;
314
+ }
315
+
316
+ $appInfo = $this->getAppInfo();
317
+ return new dbx\Client($accessToken, SG_STORAGE_DROPBOX_CLIENT_ID, null, $appInfo->getHost());
318
+ }
319
+
320
+ return $this->client;
321
+ }
322
+
323
+ private function getWebAuth()
324
+ {
325
+ $appInfo = $this->getAppInfo();
326
+ $redirectUri = SG_STORAGE_DROPBOX_REDIRECT_URI;
327
+ $csrfTokenStore = new dbx\ArrayEntryStore($_SESSION, 'dropbox-auth-csrf-token');
328
+ return new dbx\WebAuth($appInfo, SG_STORAGE_DROPBOX_CLIENT_ID, $redirectUri, $csrfTokenStore, null);
329
+ }
330
+
331
+ private function getCurrentURL()
332
+ {
333
+ $http = backupGuardGetCurrentUrlScheme();
334
+ $url = $http.'://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
335
+ return $url;
336
+ }
337
+
338
+ private function getRefURL()
339
+ {
340
+ $refUrl = $this->getCurrentURL();
341
+ if (!$_SERVER['QUERY_STRING']) {
342
+ $refUrl .= '?';
343
+ }
344
+ else {
345
+ $refUrl .= '&';
346
+ }
347
+
348
+ return $refUrl;
349
+ }
350
+
351
+ private function getAuthCodeFromURL(&$cancel = false)
352
+ {
353
+ $query = $_SERVER['QUERY_STRING'];
354
+ if (!$query) return '';
355
+
356
+ $query = explode('&', $query);
357
+ $code = '';
358
+ foreach ($query as $q) {
359
+ $q = explode('=', $q);
360
+ if ($q[0]=='code') {
361
+ $code = $q[1];
362
+ }
363
+ else if ($q[0]=='cancel' && $q[1]=='1') {
364
+ $cancel = true;
365
+ break;
366
+ }
367
+ }
368
+
369
+ return $code;
370
+ }
371
+ }
com/core/storage/SGStorage.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(SG_LIB_PATH.'SGReloadHandler.php');
4
+ require_once(SG_LIB_PATH.'SGState.php');
5
+ require_once(SG_LIB_PATH.'SGUploadState.php');
6
+
7
+ interface SGIStorageDelegate
8
+ {
9
+ public function willStartUpload($chunksCount);
10
+ public function updateProgressManually($progress);
11
+ public function shouldUploadNextChunk();
12
+ }
13
+
14
+ abstract class SGStorage
15
+ {
16
+ protected $connected = false;
17
+ protected $activeDirectory = '';
18
+ protected $delegate = null;
19
+ protected $state = null;
20
+
21
+ /* Make all initializations here */
22
+ abstract public function init();
23
+
24
+ /* Connect to the Storage */
25
+ abstract public function connect();
26
+
27
+ /* Connect offline. This will ensure that redirections to other pages won't be made */
28
+ abstract public function connectOffline();
29
+
30
+ /* Check if it is already connected */
31
+ abstract public function checkConnected();
32
+
33
+ /* Get list of files inside the active directory */
34
+ abstract public function getListOfFiles();
35
+
36
+ /* Create a folder inside the active directory. If folder already exists, do nothing. */
37
+ abstract public function createFolder($folderName);
38
+
39
+ /* Download file from Storage*/
40
+ abstract public function downloadFile($filePath, $size);
41
+
42
+ /* Upload local file to Storage */
43
+ abstract public function uploadFile($filePath);
44
+
45
+ /* Delete file from active directory */
46
+ abstract public function deleteFile($fileName);
47
+
48
+ /* Delete folder and it's contents from active directory */
49
+ abstract public function deleteFolder($folderName);
50
+
51
+ /* Search if file or folder exists in given path */
52
+ abstract public function fileExists($path);
53
+
54
+ public function __construct()
55
+ {
56
+ @session_write_close();
57
+ @session_start();
58
+ $this->init();
59
+ $this->checkConnected();
60
+ }
61
+
62
+ /* NOTE: Depending on the storage type, $directory could be the ID of the directory and not the name. */
63
+ public function setActiveDirectory($directory)
64
+ {
65
+ $this->activeDirectory = $directory;
66
+ }
67
+
68
+ public function getActiveDirectory()
69
+ {
70
+ return $this->activeDirectory;
71
+ }
72
+
73
+ public function isConnected()
74
+ {
75
+ return $this->connected;
76
+ }
77
+
78
+ public function setDelegate(SGIStorageDelegate $delegate)
79
+ {
80
+ $this->delegate = $delegate;
81
+ }
82
+
83
+ public function loadState()
84
+ {
85
+ $this->state = $this->delegate->getState();
86
+ }
87
+
88
+ public function reload()
89
+ {
90
+ $this->delegate->reload();
91
+ }
92
+
93
+ public function shouldReload()
94
+ {
95
+ return $this->delegate->shouldReload();
96
+ }
97
+
98
+ public function standardizeFileCreationDate($date)
99
+ {
100
+ $time = strtotime($date);
101
+ return backupGuardConvertDateTimezone(date('Y-m-d H:i:s', $time));
102
+ }
103
+ }
com/core/widget/SGWordPressWidget.php ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Adds Foo_Widget widget.
5
+ */
6
+ class SGWordPressWidget extends WP_Widget
7
+ {
8
+ private $widgetIndex = 0;
9
+
10
+ /**
11
+ * Register widget with WordPress.
12
+ */
13
+
14
+ function __construct()
15
+ {
16
+ $widgetOptions = array(
17
+ 'classname' => 'sg_wordpress_widget',
18
+ 'description' => 'Widget for BackupGuard seal',
19
+ );
20
+ parent::__construct(
21
+ 'sg_wordpress_widget',
22
+ esc_html__('BackupGuard Seal', 'text_domain'),
23
+ $widgetOptions
24
+ );
25
+ }
26
+
27
+ /**
28
+ * Front-end display of widget.
29
+ *
30
+ * @see WP_Widget::widget()
31
+ *
32
+ * @param array $args Widget arguments.
33
+ * @param array $instance Saved values from database.
34
+ */
35
+ public function widget($args, $instance)
36
+ {
37
+ $sgSealTheme = isset($instance['theme']) ? $instance['theme'] : '';
38
+ $sgSealImage = isset($instance['theme-'.$sgSealTheme.'-image']) ? strip_tags($instance['theme-'.$sgSealTheme.'-image']) : '';
39
+
40
+ if ($sgSealImage) {
41
+ echo '<a href="https://backup-guard.com" style="text-decoration:none;" target="_blank"><img src="https://backup-guard.com/seal/'.$sgSealImage.'" alt="BackupGuard - backup your website in the cloud"></a>';
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Back-end widget form.
47
+ *
48
+ * @see WP_Widget::form()
49
+ *
50
+ * @param array $instance Previously saved values from database.
51
+ */
52
+ public function form($instance)
53
+ {
54
+ $sgSealTheme = isset($instance['theme']) ? $instance['theme'] : SG_SEAL_THEME_DARK;
55
+ $sgSealImage = isset($instance['theme-'.$sgSealTheme.'-image']) ? $instance['theme-'.$sgSealTheme.'-image'] : '1';
56
+ if ($this->number != "__i__") {
57
+ $this->widgetIndex = $this->number;
58
+ }
59
+ else {
60
+ $this->widgetIndex += 1;
61
+ }
62
+
63
+ ?>
64
+ <div class="backup-gaurd-seal-widget-option-container">
65
+ <div style="margin-top: 13px;">
66
+ <label for="<?php echo esc_attr($this->get_field_id('theme').'-'.$this->widgetIndex); ?>"><?php esc_attr_e('Theme:', 'text_domain'); ?></label>
67
+ <select id="<?php echo esc_attr($this->get_field_id('theme').'-'.$this->widgetIndex); ?>" name="<?php echo esc_attr($this->get_field_name('theme')); ?>">
68
+ <option value="<?php echo SG_SEAL_THEME_DARK ?>" <?php echo $sgSealTheme == SG_SEAL_THEME_DARK ? "selected" : "" ?>>Dark</option>
69
+ <option value="<?php echo SG_SEAL_THEME_GREEN ?>" <?php echo $sgSealTheme == SG_SEAL_THEME_GREEN ? "selected" : "" ?>>Green</option>
70
+ <option value="<?php echo SG_SEAL_THEME_WHITE ?>" <?php echo $sgSealTheme == SG_SEAL_THEME_WHITE ? "selected" : "" ?>>White</option>
71
+ </select>
72
+ </div>
73
+ <div id="<?php echo esc_attr($this->get_field_id('theme-dark').'-'.$this->widgetIndex) ?>" <?php echo $sgSealTheme == SG_SEAL_THEME_DARK ? "" : "hidden" ?> style="margin-bottom: 13px; margin-top: 13px;">
74
+ <div style="margin-bottom: 5px;">
75
+ <input type="radio" name="<?php echo esc_attr($this->get_field_name('theme-dark-image')); ?>" value="1" checked>
76
+ <img src="<?php echo SG_IMAGE_URL.'1.png' ?>">
77
+ </div>
78
+ <div style="margin-bottom: 5px;">
79
+ <input type="radio" name="<?php echo esc_attr($this->get_field_name('theme-dark-image')); ?>" value="4" <?php echo ($sgSealImage == "4") ? "checked":""; ?>>
80
+ <img src="<?php echo SG_IMAGE_URL.'4.png' ?>">
81
+ </div>
82
+ <div style="margin-bottom: 5px;">
83
+ <input type="radio" name="<?php echo esc_attr($this->get_field_name('theme-dark-image')); ?>" value="5" <?php echo ($sgSealImage == "5") ? "checked":""; ?>>
84
+ <img src="<?php echo SG_IMAGE_URL.'5.png' ?>">
85
+ </div>
86
+ <div style="margin-bottom: 5px;">
87
+ <input type="radio" name="<?php echo esc_attr($this->get_field_name('theme-dark-image')); ?>" value="8" <?php echo ($sgSealImage == "8") ? "checked":""; ?>>
88
+ <img src="<?php echo SG_IMAGE_URL.'8.png' ?>">
89
+ </div>
90
+ </div>
91
+ <div id="<?php echo esc_attr($this->get_field_id('theme-green').'-'.$this->widgetIndex) ?>" <?php echo $sgSealTheme == SG_SEAL_THEME_GREEN ? "" : "hidden" ?> style="margin-bottom: 13px; margin-top: 13px;">
92
+ <div style="margin-bottom: 5px;">
93
+ <input type="radio" name="<?php echo esc_attr($this->get_field_name('theme-green-image')); ?>" value="2" checked>
94
+ <img src="<?php echo SG_IMAGE_URL.'2.png' ?>">
95
+ </div>
96
+ <div style="margin-bottom: 5px;">
97
+ <input type="radio" name="<?php echo esc_attr($this->get_field_name('theme-green-image')); ?>" value="6" <?php echo ($sgSealImage == "6") ? "checked":""; ?>>
98
+ <img src="<?php echo SG_IMAGE_URL.'6.png' ?>">
99
+ </div>
100
+ </div>
101
+ <div id="<?php echo esc_attr($this->get_field_id('theme-white').'-'.$this->widgetIndex) ?>" <?php echo $sgSealTheme == SG_SEAL_THEME_WHITE ? "" : "hidden" ?> style="margin-bottom: 13px; margin-top: 13px;">
102
+ <div style="margin-bottom: 5px;">
103
+ <input type="radio" name="<?php echo esc_attr($this->get_field_name('theme-white-image')); ?>" value="3" checked>
104
+ <img src="<?php echo SG_IMAGE_URL.'3.png' ?>">
105
+ </div>
106
+ <div style="margin-bottom: 5px;">
107
+ <input type="radio" name="<?php echo esc_attr($this->get_field_name('theme-white-image')); ?>" value="7" <?php echo ($sgSealImage == "7") ? "checked":""; ?>>
108
+ <img src="<?php echo SG_IMAGE_URL.'7.png' ?>">
109
+ </div>
110
+ </div>
111
+ </div>
112
+
113
+ <style type="text/css">
114
+ .backup-gaurd-seal-widget-option-container input, img {
115
+ vertical-align: middle;
116
+ }
117
+ </style>
118
+
119
+ <script type="text/javascript">
120
+ jQuery("select[id*='theme-<?php echo $this->widgetIndex ?>']").on("change", function () {
121
+ var theme = jQuery(this).val();
122
+
123
+ if (theme == "dark") {
124
+ jQuery( "div[id*='theme-dark-<?php echo $this->widgetIndex ?>']" ).show();
125
+ jQuery( "div[id*='theme-green-<?php echo $this->widgetIndex ?>']" ).hide();
126
+ jQuery( "div[id*='theme-white-<?php echo $this->widgetIndex ?>']" ).hide();
127
+ }
128
+ else if (theme == "green") {
129
+ jQuery( "div[id*='theme-green-<?php echo $this->widgetIndex ?>']" ).show();
130
+ jQuery( "div[id*='theme-dark-<?php echo $this->widgetIndex ?>']" ).hide();
131
+ jQuery( "div[id*='theme-white-<?php echo $this->widgetIndex ?>']" ).hide();
132
+ }
133
+ else {
134
+ jQuery( "div[id*='theme-white-<?php echo $this->widgetIndex ?>']" ).show();
135
+ jQuery( "div[id*='theme-dark-<?php echo $this->widgetIndex ?>']" ).hide();
136
+ jQuery( "div[id*='theme-green-<?php echo $this->widgetIndex ?>']" ).hide();
137
+ }
138
+ });
139
+ </script>
140
+ <?php
141
+ }
142
+
143
+ /**
144
+ * Sanitize widget form values as they are saved.
145
+ *
146
+ * @see WP_Widget::update()
147
+ *
148
+ * @param array $new_instance Values just sent to be saved.
149
+ * @param array $old_instance Previously saved values from database.
150
+ *
151
+ * @return array Updated safe values to be saved.
152
+ */
153
+ public function update($new_instance, $old_instance)
154
+ {
155
+ $instance = array();
156
+ $instance['theme'] = isset($new_instance['theme']) ? strip_tags($new_instance['theme']) : '';
157
+ $instance['theme-'.$instance['theme'].'-image'] = isset($new_instance['theme-'.$instance['theme'].'-image']) ? strip_tags($new_instance['theme-'.$instance['theme'].'-image']) : '';
158
+
159
+ if (!$instance['theme-'.$instance['theme'].'-image']) {
160
+ return false;
161
+ }
162
+
163
+ return $instance;
164
+ }
165
+
166
+ }
com/lib/BackupGuard/Client.php ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/Helper.php');
6
+
7
+ class Client
8
+ {
9
+ private $accessToken = null;
10
+
11
+ public function __construct($accessToken = null)
12
+ {
13
+ $this->setAccessToken($accessToken);
14
+ }
15
+
16
+ public function getAccessToken()
17
+ {
18
+ return $this->accessToken;
19
+ }
20
+
21
+ public function setAccessToken($accessToken)
22
+ {
23
+ $this->accessToken = $accessToken;
24
+ }
25
+
26
+ public function createAccessToken($clientId, $clientSecret, $email, $password)
27
+ {
28
+ $response = Helper::sendPostRequest(
29
+ '/token',
30
+ array(
31
+ 'grant_type' => 'password',
32
+ 'client_id' => $clientId,
33
+ 'client_secret' => $clientSecret,
34
+ 'email' => $email,
35
+ 'password' => $password
36
+ )
37
+ );
38
+
39
+ Helper::validateResponse($response);
40
+
41
+ $accessToken = $response->getBodyParam('access_token');
42
+ $refreshToken = $response->getBodyParam('refresh_token');
43
+
44
+ return array(
45
+ 'access_token' => $accessToken,
46
+ 'refresh_token' => $refreshToken
47
+ );
48
+ }
49
+
50
+ public function refreshAccessToken($clientId, $clientSecret, $refreshToken)
51
+ {
52
+ $response = Helper::sendPostRequest(
53
+ '/token',
54
+ array(
55
+ 'grant_type' => 'refresh_token',
56
+ 'client_id' => $clientId,
57
+ 'client_secret' => $clientSecret,
58
+ 'refresh_token' => $refreshToken
59
+ )
60
+ );
61
+
62
+ Helper::validateResponse($response);
63
+
64
+ $accessToken = $response->getBodyParam('access_token');
65
+ $refreshToken = $response->getBodyParam('refresh_token');
66
+
67
+ return array(
68
+ 'access_token' => $accessToken,
69
+ 'refresh_token' => $refreshToken
70
+ );
71
+ }
72
+
73
+ public function getCurrentUser()
74
+ {
75
+ Helper::requiredParam('access_token', $this->getAccessToken());
76
+
77
+ $response = Helper::sendGetRequest(
78
+ '/users',
79
+ array(),
80
+ array(
81
+ 'access_token' => $this->getAccessToken()
82
+ )
83
+ );
84
+
85
+ Helper::validateResponse($response);
86
+
87
+ return $response->getBody();
88
+ }
89
+
90
+ public function createUser($userInfo)
91
+ {
92
+ Helper::requiredParam('access_token', $this->getAccessToken());
93
+ Helper::requiredParamInArray($userInfo, 'email');
94
+ Helper::requiredParamInArray($userInfo, 'password');
95
+ Helper::requiredParamInArray($userInfo, 'firstname');
96
+ Helper::requiredParamInArray($userInfo, 'lastname');
97
+
98
+ $params = array(
99
+ 'email' => $userInfo['email'],
100
+ 'password' => $userInfo['password'],
101
+ 'firstname' => $userInfo['firstname'],
102
+ 'lastname' => $userInfo['lastname']
103
+ );
104
+
105
+ if (!empty($userInfo['package'])) {
106
+ $params['package'] = $userInfo['package'];
107
+ }
108
+
109
+ $response = Helper::sendPostRequest(
110
+ '/users',
111
+ $params,
112
+ array(
113
+ 'access_token' => $this->getAccessToken()
114
+ )
115
+ );
116
+
117
+ Helper::validateResponse($response);
118
+
119
+ return $response->getBodyParam('user_id');
120
+ }
121
+
122
+ public function getBanner($env, $type, $userType = null)
123
+ {
124
+ Helper::requiredParam('environment', $env);
125
+
126
+ $params = array(
127
+ 'environment' => $env,
128
+ 'type' => $type
129
+ );
130
+
131
+ if ($userType) {
132
+ $params['user_type'] = $userType;
133
+ }
134
+
135
+ $response = Helper::sendGetRequest(
136
+ '/banners',
137
+ $params
138
+ );
139
+
140
+ try {
141
+ Helper::validateResponse($response);
142
+ }
143
+ catch (Exception $e) {
144
+ return '';
145
+ }
146
+
147
+ return $response->getBodyParam('html');
148
+ }
149
+
150
+ public function validateUrl($url, $productName)
151
+ {
152
+ Helper::requiredParam('access_token', $this->getAccessToken());
153
+ Helper::requiredParam('url', $url);
154
+ Helper::requiredParam('product', $productName);
155
+
156
+ $params = array(
157
+ 'url' => $url,
158
+ 'product' => $productName
159
+ );
160
+
161
+ $response = Helper::sendPostRequest(
162
+ '/products/validateUrl',
163
+ $params,
164
+ array(
165
+ 'access_token' => $this->getAccessToken()
166
+ )
167
+ );
168
+
169
+ Helper::validateResponse($response);
170
+
171
+ return $response->getBodyParam('license');
172
+ }
173
+
174
+ public function getAllUserProducts($productName = '')
175
+ {
176
+ Helper::requiredParam('access_token', $this->getAccessToken());
177
+
178
+ $params = array();
179
+
180
+ if ($productName) {
181
+ $params['product'] = $productName;
182
+ }
183
+
184
+ $response = Helper::sendGetRequest(
185
+ '/products',
186
+ $params,
187
+ array(
188
+ 'access_token' => $this->getAccessToken()
189
+ )
190
+ );
191
+
192
+ Helper::validateResponse($response);
193
+
194
+ return $response->getBodyParam('products');
195
+ }
196
+
197
+ public function linkUrlToProduct($url, $userProductId)
198
+ {
199
+ Helper::requiredParam('access_token', $this->getAccessToken());
200
+ Helper::requiredParam('url', $url);
201
+ Helper::requiredParam('product_id', $userProductId);
202
+
203
+ $params = array(
204
+ 'url' => $url,
205
+ 'id' => $userProductId
206
+ );
207
+
208
+ $response = Helper::sendPostRequest(
209
+ '/products/link',
210
+ $params,
211
+ array(
212
+ 'access_token' => $this->getAccessToken()
213
+ )
214
+ );
215
+
216
+ Helper::validateResponse($response);
217
+
218
+ return $response->getBodyParam('link_id');
219
+ }
220
+
221
+ //Added by Nerses
222
+ public function getMerchantOrderId($productName)
223
+ {
224
+ Helper::requiredParam('access_token', $this->getAccessToken());
225
+ Helper::requiredParam('product', $productName);
226
+
227
+ $params = array(
228
+ 'product' => $productName
229
+ );
230
+
231
+ $response = Helper::sendGetRequest(
232
+ '/products/merchant',
233
+ $params,
234
+ array(
235
+ 'access_token' => $this->getAccessToken()
236
+ )
237
+ );
238
+
239
+ Helper::validateResponse($response);
240
+
241
+ return $response->getBodyParam('id');
242
+ }
243
+
244
+ public function storeSubscriberInfo($url, $fname, $lname, $email, $priority)
245
+ {
246
+ Helper::requiredParam('url', $url);
247
+ Helper::requiredParam('fname', $fname);
248
+ Helper::requiredParam('lname', $lname);
249
+ Helper::requiredParam('email', $email);
250
+ Helper::requiredParam('priority', $priority);
251
+
252
+ $params = array(
253
+ 'url' => $url,
254
+ 'fname' => $fname,
255
+ 'lname' => $lname,
256
+ 'email' => $email,
257
+ 'priority' => $priority,
258
+ 'referrer' => 'wordpress-backup-free'
259
+ );
260
+
261
+ $response = Helper::sendPostRequest(
262
+ '/products/subscriber',
263
+ $params
264
+ );
265
+
266
+ Helper::validateResponse($response);
267
+
268
+ return $response->getBodyParam('subscriber');
269
+ }
270
+
271
+ public function storeSurveyResult($url, $firstname, $lastname, $email, $response)
272
+ {
273
+ Helper::requiredParam('url', $url);
274
+ Helper::requiredParam('firstname', $firstname);
275
+ Helper::requiredParam('lastname', $lastname);
276
+ Helper::requiredParam('email', $email);
277
+ Helper::requiredParam('response', $response);
278
+
279
+ $params = array(
280
+ 'url' => $url,
281
+ 'firstname' => $firstname,
282
+ 'lastname' => $lastname,
283
+ 'email' => $email,
284
+ 'response' => $response,
285
+ 'name' => SG_PRODUCT_IDENTIFIER.'-deactivation'
286
+ );
287
+
288
+ $response = Helper::sendPostRequest(
289
+ '/products/survey',
290
+ $params
291
+ );
292
+
293
+ Helper::validateResponse($response);
294
+
295
+ return $response->getBodyParam('survey');
296
+ }
297
+ }
com/lib/BackupGuard/Config.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ class Config
6
+ {
7
+ const URL = 'https://backup-guard.com/admin/api/v1';
8
+ const TOKEN_EXPIRES = 3600;
9
+ }
com/lib/BackupGuard/Curl.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/RequestHandler.php');
6
+
7
+ class Curl extends RequestHandler
8
+ {
9
+ private $handle = null;
10
+
11
+ public function __construct($url)
12
+ {
13
+ parent::__construct($url);
14
+
15
+ $this->handle = curl_init();
16
+
17
+ $this->set(CURLOPT_SSL_VERIFYPEER, false);
18
+ $this->set(CURLOPT_SSL_VERIFYHOST, 0);
19
+ $this->set(CURLOPT_SSLVERSION, 1);
20
+ $this->set(CURLOPT_RETURNTRANSFER, true);
21
+ $this->set(CURLOPT_CONNECTTIMEOUT, 10);
22
+ $this->set(CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0');
23
+
24
+ $this->addHeader('Content-type: application/x-www-form-urlencoded');
25
+ }
26
+
27
+ public function post()
28
+ {
29
+ $this->set(CURLOPT_POST, true);
30
+
31
+ if (count($this->params)) {
32
+ $this->set(CURLOPT_POSTFIELDS, http_build_query($this->params, '', '&'));
33
+ }
34
+
35
+ return $this->sendRequest('POST');
36
+ }
37
+
38
+ public function get()
39
+ {
40
+ $this->set(CURLOPT_HTTPGET, true);
41
+ return $this->sendRequest('GET');
42
+ }
43
+
44
+ private function sendRequest($type)
45
+ {
46
+ $url = $this->url;
47
+
48
+ //prepare url for get request
49
+ if ($type == 'GET' && count($this->params)) {
50
+ $url = rtrim($url, '/').'/';
51
+
52
+ if ($this->getWithQueryParams) { //standard get url, with query params
53
+ $url .= '?'.http_build_query($this->params, '', '&');
54
+ }
55
+ else { //mvs-styled get url
56
+ $url .= implode('/', array_values($this->params));
57
+ }
58
+ }
59
+
60
+ $this->set(CURLOPT_URL, $url);
61
+ if (!empty($this->headers)) {
62
+ $this->set(CURLOPT_HTTPHEADER, $this->headers);
63
+ }
64
+
65
+ $body = curl_exec($this->handle);
66
+
67
+ if ($body !== false) {
68
+ $this->body = $body;
69
+ $info = curl_getinfo($this->handle);
70
+ $this->setResponseInfo($info);
71
+ return $this->parseResponse();
72
+ }
73
+
74
+ return false;
75
+ }
76
+
77
+ public function set($option, $value)
78
+ {
79
+ curl_setopt($this->handle, $option, $value);
80
+ }
81
+
82
+ public function __destruct()
83
+ {
84
+ if ($this->handle) {
85
+ curl_close($this->handle);
86
+ }
87
+ }
88
+
89
+ private function setResponseInfo($info)
90
+ {
91
+ if (isset($info['http_code'])) {
92
+ $this->httpCode = $info['http_code'];
93
+ }
94
+
95
+ if (isset($info['content_type'])) {
96
+ $this->contentType = $info['content_type'];
97
+ }
98
+ }
99
+ }
com/lib/BackupGuard/Exception/BadRequest.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/Exception.php');
6
+
7
+ class BadRequestException extends Exception
8
+ {
9
+
10
+ }
com/lib/BackupGuard/Exception/Exception.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ class Exception extends \Exception
6
+ {
7
+
8
+ }
com/lib/BackupGuard/Exception/Forbidden.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/Exception.php');
6
+
7
+ class ForbiddenException extends Exception
8
+ {
9
+
10
+ }
com/lib/BackupGuard/Exception/InternalServerError.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/Exception.php');
6
+
7
+ class InternalServerErrorException extends Exception
8
+ {
9
+
10
+ }
com/lib/BackupGuard/Exception/MethodNotAllowed.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/Exception.php');
6
+
7
+ class MethodNotAllowedException extends Exception
8
+ {
9
+
10
+ }
com/lib/BackupGuard/Exception/NotFound.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/Exception.php');
6
+
7
+ class NotFoundException extends Exception
8
+ {
9
+
10
+ }
com/lib/BackupGuard/Exception/Unauthorized.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/Exception.php');
6
+
7
+ class UnauthorizedException extends Exception
8
+ {
9
+
10
+ }
com/lib/BackupGuard/Helper.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/Exception/BadRequest.php');
6
+ require_once(dirname(__FILE__).'/Exception/Forbidden.php');
7
+ require_once(dirname(__FILE__).'/Exception/InternalServerError.php');
8
+ require_once(dirname(__FILE__).'/Exception/MethodNotAllowed.php');
9
+ require_once(dirname(__FILE__).'/Exception/NotFound.php');
10
+ require_once(dirname(__FILE__).'/Exception/Unauthorized.php');
11
+ require_once(dirname(__FILE__).'/Config.php');
12
+ require_once(dirname(__FILE__).'/RequestHandler.php');
13
+ require_once(dirname(__FILE__).'/Response.php');
14
+
15
+ require_once(SG_REQUEST_PATH.'SGRequest.php');
16
+ require_once(SG_REQUEST_PATH.'SGResponse.php');
17
+
18
+ class Helper
19
+ {
20
+ public static function requiredParam($name, $var)
21
+ {
22
+ if (empty($var)) {
23
+ throw new BadRequestException("Missing required argument: ".$name, 400);
24
+ }
25
+ }
26
+
27
+ public static function requiredParamInArray($arr, $key)
28
+ {
29
+ $var = null;
30
+
31
+ if (is_array($arr) && isset($arr[$key])) {
32
+ $var = $arr[$key];
33
+ }
34
+
35
+ self::requiredParam($key, $var);
36
+ }
37
+
38
+ private static function prepareRequest($path, $params = array(), $headers = array())
39
+ {
40
+ $url = Config::URL.$path;
41
+ $request = RequestHandler::createRequest($url);
42
+ $request->setParams($params);
43
+ $request->setHeaders($headers);
44
+ return $request;
45
+ }
46
+
47
+ public static function sendPostRequest($path, $params = array(), $headers = array())
48
+ {
49
+ // $request = self::prepareRequest($path, $params, $headers);
50
+ // return $request->post();
51
+ $url = Config::URL.$path;
52
+
53
+ $request = \SGRequest::getInstance();
54
+ $request->setUrl($url);
55
+ $request->setHeaders($headers);
56
+ $request->setParams($params);
57
+ $request->setGetWithQueryParams(false);
58
+ return $request->sendPostRequest();
59
+ }
60
+
61
+ public static function sendGetRequest($path, $params = array(), $headers = array())
62
+ {
63
+ // $request = self::prepareRequest($path, $params, $headers);
64
+ // return $request->get();
65
+ $url = Config::URL.$path;
66
+
67
+ $request = \SGRequest::getInstance();
68
+ $request->setUrl($url);
69
+ $request->setHeaders($headers);
70
+ $request->setParams($params);
71
+ $request->setGetWithQueryParams(false);
72
+ return $request->sendGetRequest();
73
+ }
74
+
75
+ public static function validateResponse($response)
76
+ {
77
+ if (!$response instanceof \SGResponse) {
78
+ throw new MethodNotAllowedException();
79
+ }
80
+
81
+ $code = (int)$response->getHttpStatus();
82
+ $error = $response->getBodyParam('error');
83
+ $errorMessage = $error&&isset($error['message'])?$error['message']:null;
84
+
85
+ //sometimes 'error' is just a string
86
+ if ($error && !$errorMessage) {
87
+ $errorMessage = $error;
88
+ }
89
+
90
+ switch ($code) {
91
+ case 405:
92
+ throw new MethodNotAllowedException($errorMessage, $code);
93
+ case 400:
94
+ throw new BadRequestException($errorMessage, $code);
95
+ case 404:
96
+ throw new NotFoundException($errorMessage, $code);
97
+ case 500:
98
+ throw new InternalServerErrorException($errorMessage, $code);
99
+ case 403:
100
+ throw new ForbiddenException($errorMessage, $code);
101
+ case 401:
102
+ throw new UnauthorizedException($errorMessage, $code);
103
+ }
104
+ }
105
+ }
com/lib/BackupGuard/RequestHandler.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/Curl.php');
6
+ require_once(dirname(__FILE__).'/Stream.php');
7
+
8
+ abstract class RequestHandler
9
+ {
10
+ protected $url = '';
11
+ protected $params = array();
12
+ protected $headers = array();
13
+ protected $httpCode = false;
14
+ protected $contentType = false;
15
+ protected $body = false;
16
+ protected $getWithQueryParams = false;
17
+
18
+ public function __construct($url)
19
+ {
20
+ $this->url = $url;
21
+ }
22
+
23
+ abstract public function post();
24
+
25
+ abstract public function get();
26
+
27
+ public static function createRequest($url)
28
+ {
29
+ //if curl is available, use it
30
+ if (function_exists('curl_version')) {
31
+ return new Curl($url);
32
+ }
33
+
34
+ return new Stream($url);
35
+ }
36
+
37
+ public function addHeader($header)
38
+ {
39
+ $this->headers[] = $header;
40
+ }
41
+
42
+ public function setHeaders($headers)
43
+ {
44
+ $this->headers = $headers;
45
+ }
46
+
47
+ public function addParam($key, $value)
48
+ {
49
+ $this->params[$key] = $value;
50
+ }
51
+
52
+ public function setParams($params)
53
+ {
54
+ $this->params = $params;
55
+ }
56
+
57
+ protected function parseResponse()
58
+ {
59
+ $response = new Response();
60
+ $response->setBody($this->body);
61
+ $response->setHttpStatus($this->httpCode);
62
+ $response->setContentType($this->contentType);
63
+
64
+ //if the response is in json format, decode it
65
+ if ($this->contentType == 'application/json') {
66
+ $response->parseJsonBody();
67
+ }
68
+
69
+ return $response;
70
+ }
71
+ }
com/lib/BackupGuard/Response.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ class Response
6
+ {
7
+ private $httpStatus = false;
8
+ private $contentType = false;
9
+ private $body = false;
10
+
11
+ public function getHttpStatus()
12
+ {
13
+ return $this->httpStatus;
14
+ }
15
+
16
+ public function setHttpStatus($httpStatus)
17
+ {
18
+ $this->httpStatus = $httpStatus;
19
+ }
20
+
21
+ public function getContentType()
22
+ {
23
+ return $this->contentType;
24
+ }
25
+
26
+ public function setContentType($contentType)
27
+ {
28
+ $this->contentType = $contentType;
29
+ }
30
+
31
+ public function getBody()
32
+ {
33
+ return $this->body;
34
+ }
35
+
36
+ public function setBody($body)
37
+ {
38
+ $this->body = $body;
39
+ }
40
+
41
+ public function parseJsonBody()
42
+ {
43
+ if ($this->body) {
44
+ $this->body = json_decode($this->body, true);
45
+ }
46
+ }
47
+
48
+ public function getBodyParam($key)
49
+ {
50
+ if (is_array($this->body) && isset($this->body[$key])) {
51
+ return $this->body[$key];
52
+ }
53
+
54
+ return null;
55
+ }
56
+ }
com/lib/BackupGuard/Stream.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard;
4
+
5
+ require_once(dirname(__FILE__).'/RequestHandler.php');
6
+
7
+ class Stream extends RequestHandler
8
+ {
9
+ public function __construct($url)
10
+ {
11
+ parent::__construct($url);
12
+
13
+ $this->addHeader('Content-type: application/x-www-form-urlencoded');
14
+ }
15
+
16
+ public function post()
17
+ {
18
+ return $this->sendRequest('POST');
19
+ }
20
+
21
+ public function get()
22
+ {
23
+ return $this->sendRequest('GET');
24
+ }
25
+
26
+ private function sendRequest($type)
27
+ {
28
+ //prepare headers
29
+ $headers = '';
30
+ if (count($this->headers)) {
31
+ $headers = implode("\r\n", $this->headers);
32
+ $headers .= "\r\n";
33
+ }
34
+
35
+ //set http request method
36
+ $opts = array(
37
+ 'http' => array(
38
+ 'method' => $type,
39
+ 'user_agent' => 'Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0',
40
+ 'ignore_errors' => '1'
41
+ )
42
+ );
43
+
44
+ //set headers
45
+ if ($headers) {
46
+ $opts['http']['header'] = $headers;
47
+ }
48
+
49
+ $url = $this->url;
50
+
51
+ //set params
52
+ if (count($this->params)) {
53
+ $data = http_build_query($this->params, '', '&');
54
+
55
+ if ($type == 'GET') { //set params inside url
56
+ $url = rtrim($url, '/').'/';
57
+
58
+ if ($this->getWithQueryParams) { //standard get url, with query params
59
+ $url .= '?'.http_build_query($this->params, '', '&');
60
+ }
61
+ else { //mvs-styled get url
62
+ $url .= implode('/', array_values($this->params));
63
+ }
64
+ }
65
+ else if ($type == 'POST') {
66
+ $opts['http']['content'] = $data;
67
+ }
68
+ }
69
+
70
+ $context = @stream_context_create($opts);
71
+ $fp = @fopen($url, 'r', false, $context);
72
+
73
+ if (isset($http_response_header)) {
74
+ $this->setResponseInfo($http_response_header);
75
+ }
76
+
77
+ if ($fp) {
78
+ $this->body = @stream_get_contents($fp);
79
+ @fclose($fp);
80
+ }
81
+
82
+ return $this->parseResponse();
83
+ }
84
+
85
+ private function parseHTTPHeaders($headers)
86
+ {
87
+ $head = array();
88
+ foreach($headers as $k => $v) {
89
+ $t = explode(':', $v, 2);
90
+ if (isset($t[1])) {
91
+ $head[trim($t[0])] = trim($t[1]);
92
+ }
93
+ else {
94
+ $head[] = $v;
95
+ if (preg_match("#HTTP/[0-9\.]+\s+([0-9]+)#", $v, $out)) {
96
+ $head['reponse_code'] = intval($out[1]);
97
+ }
98
+ }
99
+ }
100
+ return $head;
101
+ }
102
+
103
+ private function setResponseInfo($info)
104
+ {
105
+ $info = $this->parseHTTPHeaders($info);
106
+
107
+ if (isset($info['reponse_code'])) {
108
+ $this->httpCode = $info['reponse_code'];
109
+ }
110
+
111
+ if (isset($info['Content-Type'])) {
112
+ $this->contentType = $info['Content-Type'];
113
+ }
114
+ }
115
+ }
com/lib/Dropbox/AppInfo.php ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Your app's API key and secret.
6
+ */
7
+ final class AppInfo
8
+ {
9
+ /**
10
+ * Your Dropbox <em>app key</em> (OAuth calls this the <em>consumer key</em>). You can
11
+ * create an app key and secret on the <a href="http://dropbox.com/developers/apps">Dropbox developer website</a>.
12
+ *
13
+ * @return string
14
+ */
15
+ function getKey() { return $this->key; }
16
+
17
+ /** @var string */
18
+ private $key;
19
+
20
+ /**
21
+ * Your Dropbox <em>app secret</em> (OAuth calls this the <em>consumer secret</em>). You can
22
+ * create an app key and secret on the <a href="http://dropbox.com/developers/apps">Dropbox developer website</a>.
23
+ *
24
+ * Make sure that this is kept a secret. Someone with your app secret can impesonate your
25
+ * application. People sometimes ask for help on the Dropbox API forums and
26
+ * copy/paste code that includes their app secret. Do not do that.
27
+ *
28
+ * @return string
29
+ */
30
+ function getSecret() { return $this->secret; }
31
+
32
+ /** @var string */
33
+ private $secret;
34
+
35
+ /**
36
+ * The set of servers your app will use. This defaults to the standard Dropbox servers
37
+ * {@link Host::getDefault}.
38
+ *
39
+ * @return Host
40
+ *
41
+ * @internal
42
+ */
43
+ function getHost() { return $this->host; }
44
+
45
+ /** @var Host */
46
+ private $host;
47
+
48
+ /**
49
+ * Constructor.
50
+ *
51
+ * @param string $key
52
+ * See {@link getKey()}
53
+ * @param string $secret
54
+ * See {@link getSecret()}
55
+ */
56
+ function __construct($key, $secret)
57
+ {
58
+ self::checkKeyArg($key);
59
+ self::checkSecretArg($secret);
60
+
61
+ $this->key = $key;
62
+ $this->secret = $secret;
63
+
64
+ // The $host parameter is sort of internal. We don't include it in the param list because
65
+ // we don't want it to be included in the documentation. Use PHP arg list hacks to get at
66
+ // it.
67
+ $host = null;
68
+ if (\func_num_args() == 3) {
69
+ $host = \func_get_arg(2);
70
+ Host::checkArgOrNull("host", $host);
71
+ }
72
+ if ($host === null) {
73
+ $host = Host::getDefault();
74
+ }
75
+ $this->host = $host;
76
+ }
77
+
78
+ /**
79
+ * Loads a JSON file containing information about your app. At a minimum, the file must include
80
+ * the "key" and "secret" fields. Run 'php authorize.php' in the examples directory
81
+ * for details about what this file should look like.
82
+ *
83
+ * @param string $path
84
+ * Path to a JSON file
85
+ *
86
+ * @return AppInfo
87
+ *
88
+ * @throws AppInfoLoadException
89
+ */
90
+ static function loadFromJsonFile($path)
91
+ {
92
+ list($rawJson, $appInfo) = self::loadFromJsonFileWithRaw($path);
93
+ return $appInfo;
94
+ }
95
+
96
+ /**
97
+ * Loads a JSON file containing information about your app. At a minimum, the file must include
98
+ * the "key" and "secret" fields. Run 'php authorize.php' in the examples directory
99
+ * for details about what this file should look like.
100
+ *
101
+ * @param string $path
102
+ * Path to a JSON file
103
+ *
104
+ * @return array
105
+ * A list of two items. The first is a PHP array representation of the raw JSON, the second
106
+ * is an AppInfo object that is the parsed version of the JSON.
107
+ *
108
+ * @throws AppInfoLoadException
109
+ *
110
+ * @internal
111
+ */
112
+ static function loadFromJsonFileWithRaw($path)
113
+ {
114
+ if (!file_exists($path)) {
115
+ throw new AppInfoLoadException("File doesn't exist: \"$path\"");
116
+ }
117
+
118
+ $str = Util::stripUtf8Bom(file_get_contents($path));
119
+ $jsonArr = json_decode($str, true, 10);
120
+
121
+ if (is_null($jsonArr)) {
122
+ throw new AppInfoLoadException("JSON parse error: \"$path\"");
123
+ }
124
+
125
+ $appInfo = self::loadFromJson($jsonArr);
126
+
127
+ return array($jsonArr, $appInfo);
128
+ }
129
+
130
+ /**
131
+ * Parses a JSON object to build an AppInfo object. If you would like to load this from a file,
132
+ * use the loadFromJsonFile() method.
133
+ *
134
+ * @param array $jsonArr Output from json_decode($str, true)
135
+ *
136
+ * @return AppInfo
137
+ *
138
+ * @throws AppInfoLoadException
139
+ */
140
+ static function loadFromJson($jsonArr)
141
+ {
142
+ if (!is_array($jsonArr)) {
143
+ throw new AppInfoLoadException("Expecting JSON object, got something else");
144
+ }
145
+
146
+ $requiredKeys = array("key", "secret");
147
+ foreach ($requiredKeys as $key) {
148
+ if (!array_key_exists($key, $jsonArr)) {
149
+ throw new AppInfoLoadException("Missing field \"$key\"");
150
+ }
151
+
152
+ if (!is_string($jsonArr[$key])) {
153
+ throw new AppInfoLoadException("Expecting field \"$key\" to be a string");
154
+ }
155
+ }
156
+
157
+ // Check app_key and app_secret
158
+ $appKey = $jsonArr["key"];
159
+ $appSecret = $jsonArr["secret"];
160
+
161
+ $tokenErr = self::getTokenPartError($appKey);
162
+ if (!is_null($tokenErr)) {
163
+ throw new AppInfoLoadException("Field \"key\" doesn't look like a valid app key: $tokenErr");
164
+ }
165
+
166
+ $tokenErr = self::getTokenPartError($appSecret);
167
+ if (!is_null($tokenErr)) {
168
+ throw new AppInfoLoadException("Field \"secret\" doesn't look like a valid app secret: $tokenErr");
169
+ }
170
+
171
+ // Check for the optional 'host' field
172
+ if (!array_key_exists('host', $jsonArr)) {
173
+ $host = null;
174
+ }
175
+ else {
176
+ $baseHost = $jsonArr["host"];
177
+ if (!is_string($baseHost)) {
178
+ throw new AppInfoLoadException("Optional field \"host\" must be a string");
179
+ }
180
+
181
+ $api = "api-$baseHost";
182
+ $content = "api-content-$baseHost";
183
+ $web = "meta-$baseHost";
184
+
185
+ $host = new Host($api, $content, $web);
186
+ }
187
+
188
+ return new AppInfo($appKey, $appSecret, $host);
189
+ }
190
+
191
+ /**
192
+ * Use this to check that a function argument is of type <code>AppInfo</code>
193
+ *
194
+ * @internal
195
+ */
196
+ static function checkArg($argName, $argValue)
197
+ {
198
+ if (!($argValue instanceof self)) Checker::throwError($argName, $argValue, __CLASS__);
199
+ }
200
+
201
+ /**
202
+ * Use this to check that a function argument is either <code>null</code> or of type
203
+ * <code>AppInfo</code>.
204
+ *
205
+ * @internal
206
+ */
207
+ static function checkArgOrNull($argName, $argValue)
208
+ {
209
+ if ($argValue === null) return;
210
+ if (!($argValue instanceof self)) Checker::throwError($argName, $argValue, __CLASS__);
211
+ }
212
+
213
+ /** @internal */
214
+ static function getTokenPartError($s)
215
+ {
216
+ if ($s === null) return "can't be null";
217
+ if (strlen($s) === 0) return "can't be empty";
218
+ if (strstr($s, ' ')) return "can't contain a space";
219
+ return null; // 'null' means "no error"
220
+ }
221
+
222
+ /** @internal */
223
+ static function checkKeyArg($key)
224
+ {
225
+ $error = self::getTokenPartError($key);
226
+ if ($error === null) return;
227
+ throw new \InvalidArgumentException("Bad 'key': \"$key\": $error.");
228
+ }
229
+
230
+ /** @internal */
231
+ static function checkSecretArg($secret)
232
+ {
233
+ $error = self::getTokenPartError($secret);
234
+ if ($error === null) return;
235
+ throw new \InvalidArgumentException("Bad 'secret': \"$secret\": $error.");
236
+ }
237
+
238
+ }
com/lib/Dropbox/AppInfoLoadException.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown by the <code>AppInfo::loadXXX</code> methods if something goes wrong.
6
+ */
7
+ final class AppInfoLoadException extends \Exception
8
+ {
9
+ /**
10
+ * @param string $message
11
+ *
12
+ * @internal
13
+ */
14
+ function __construct($message)
15
+ {
16
+ parent::__construct($message);
17
+ }
18
+ }
com/lib/Dropbox/ArrayEntryStore.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * A class that gives get/put/clear access to a single entry in an array.
6
+ */
7
+ class ArrayEntryStore implements ValueStore
8
+ {
9
+ /** @var array */
10
+ private $array;
11
+
12
+ /** @var mixed */
13
+ private $key;
14
+
15
+ /**
16
+ * Constructor.
17
+ *
18
+ * @param array $array
19
+ * The array that we'll be accessing.
20
+ *
21
+ * @param mixed $key
22
+ * The key for the array element we'll be accessing.
23
+ */
24
+ function __construct(&$array, $key)
25
+ {
26
+ $this->array = &$array;
27
+ $this->key = $key;
28
+ }
29
+
30
+ /**
31
+ * Returns the entry's current value or <code>null</code> if nothing is set.
32
+ *
33
+ * @return object
34
+ */
35
+ function get()
36
+ {
37
+ if (isset($this->array[$this->key])) {
38
+ return $this->array[$this->key];
39
+ } else {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Set the array entry to the given value.
46
+ *
47
+ * @param object $value
48
+ */
49
+ function set($value)
50
+ {
51
+ $this->array[$this->key] = $value;
52
+ }
53
+
54
+ /**
55
+ * Clear the entry.
56
+ */
57
+ function clear()
58
+ {
59
+ unset($this->array[$this->key]);
60
+ }
61
+ }
com/lib/Dropbox/AuthBase.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Base class for API authorization-related classes.
6
+ */
7
+ class AuthBase
8
+ {
9
+ /**
10
+ * Whatever AppInfo was passed into the constructor.
11
+ *
12
+ * @return AppInfo
13
+ */
14
+ function getAppInfo() { return $this->appInfo; }
15
+
16
+ /** @var AppInfo */
17
+ protected $appInfo;
18
+
19
+ /**
20
+ * An identifier for the API client, typically of the form "Name/Version".
21
+ * This is used to set the HTTP <code>User-Agent</code> header when making API requests.
22
+ * Example: <code>"PhotoEditServer/1.3"</code>
23
+ *
24
+ * If you're the author a higher-level library on top of the basic SDK, and the
25
+ * "Photo Edit" app's server code is using your library to access Dropbox, you should append
26
+ * your library's name and version to form the full identifier. For example,
27
+ * if your library is called "File Picker", you might set this field to:
28
+ * <code>"PhotoEditServer/1.3 FilePicker/0.1-beta"</code>
29
+ *
30
+ * The exact format of the <code>User-Agent</code> header is described in
31
+ * <a href="http://tools.ietf.org/html/rfc2616#section-3.8">section 3.8 of the HTTP specification</a>.
32
+ *
33
+ * Note that underlying HTTP client may append other things to the <code>User-Agent</code>, such as
34
+ * the name of the library being used to actually make the HTTP request (such as cURL).
35
+ *
36
+ * @return string
37
+ */
38
+ function getClientIdentifier() { return $this->clientIdentifier; }
39
+
40
+ /** @var string */
41
+ protected $clientIdentifier;
42
+
43
+ /**
44
+ * The locale of the user of your application. Some API calls return localized
45
+ * data and error messages; this "user locale" setting determines which locale
46
+ * the server should use to localize those strings.
47
+ *
48
+ * @return null|string
49
+ */
50
+ function getUserLocale() { return $this->userLocale; }
51
+
52
+ /** @var string */
53
+ protected $userLocale;
54
+
55
+ /**
56
+ * Constructor.
57
+ *
58
+ * @param AppInfo $appInfo
59
+ * See {@link getAppInfo()}
60
+ * @param string $clientIdentifier
61
+ * See {@link getClientIdentifier()}
62
+ * @param null|string $userLocale
63
+ * See {@link getUserLocale()}
64
+ */
65
+ function __construct($appInfo, $clientIdentifier, $userLocale = null)
66
+ {
67
+ AppInfo::checkArg("appInfo", $appInfo);
68
+ Client::checkClientIdentifierArg("clientIdentifier", $clientIdentifier);
69
+ Checker::argStringNonEmptyOrNull("userLocale", $userLocale);
70
+
71
+ $this->appInfo = $appInfo;
72
+ $this->clientIdentifier = $clientIdentifier;
73
+ $this->userLocale = $userLocale;
74
+ }
75
+ }
com/lib/Dropbox/AuthInfo.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * This class contains methods to load an AppInfo and AccessToken from a JSON file.
6
+ * This can help simplify simple scripts (such as the example programs that come with the
7
+ * SDK) but is probably not useful in typical Dropbox API apps.
8
+ *
9
+ */
10
+ final class AuthInfo
11
+ {
12
+ /**
13
+ * Loads a JSON file containing authorization information for your app. 'php authorize.php'
14
+ * in the examples directory for details about what this file should look like.
15
+ *
16
+ * @param string $path
17
+ * Path to a JSON file
18
+ * @return array
19
+ * A <code>list(string $accessToken, Host $host)</code>.
20
+ *
21
+ * @throws AuthInfoLoadException
22
+ */
23
+ static function loadFromJsonFile($path)
24
+ {
25
+ if (!file_exists($path)) {
26
+ throw new AuthInfoLoadException("File doesn't exist: \"$path\"");
27
+ }
28
+
29
+ $str = Util::stripUtf8Bom(file_get_contents($path));
30
+ $jsonArr = json_decode($str, true, 10);
31
+
32
+ if (is_null($jsonArr)) {
33
+ throw new AuthInfoLoadException("JSON parse error: \"$path\"");
34
+ }
35
+
36
+ return self::loadFromJson($jsonArr);
37
+ }
38
+
39
+ /**
40
+ * Parses a JSON object to build an AuthInfo object. If you would like to load this from a file,
41
+ * please use the @see loadFromJsonFile method.
42
+ *
43
+ * @param array $jsonArr
44
+ * A parsed JSON object, typcally the result of json_decode(..., true).
45
+ * @return array
46
+ * A <code>list(string $accessToken, Host $host)</code>.
47
+ *
48
+ * @throws AuthInfoLoadException
49
+ */
50
+ private static function loadFromJson($jsonArr)
51
+ {
52
+ if (!is_array($jsonArr)) {
53
+ throw new AuthInfoLoadException("Expecting JSON object, found something else");
54
+ }
55
+
56
+ // Check access_token
57
+ if (!array_key_exists('access_token', $jsonArr)) {
58
+ throw new AuthInfoLoadException("Missing field \"access_token\"");
59
+ }
60
+
61
+ $accessToken = $jsonArr['access_token'];
62
+ if (!is_string($accessToken)) {
63
+ throw new AuthInfoLoadException("Expecting field \"access_token\" to be a string");
64
+ }
65
+
66
+ // Check for the optional 'host' field
67
+ if (!array_key_exists('host', $jsonArr)) {
68
+ $host = null;
69
+ }
70
+ else {
71
+ $baseHost = $jsonArr["host"];
72
+ if (!is_string($baseHost)) {
73
+ throw new AuthInfoLoadException("Optional field \"host\" must be a string");
74
+ }
75
+
76
+ $api = "api-$baseHost";
77
+ $content = "api-content-$baseHost";
78
+ $web = "meta-$baseHost";
79
+
80
+ $host = new Host($api, $content, $web);
81
+ }
82
+
83
+ return array($accessToken, $host);
84
+ }
85
+ }
com/lib/Dropbox/AuthInfoLoadException.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown by the <code>AuthInfo::loadXXX</code> methods if something goes wrong.
6
+ */
7
+ final class AuthInfoLoadException extends \Exception
8
+ {
9
+ /**
10
+ * @param string $message
11
+ *
12
+ * @internal
13
+ */
14
+ function __construct($message)
15
+ {
16
+ parent::__construct($message);
17
+ }
18
+ }
com/lib/Dropbox/Checker.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Helper functions to validate arguments.
6
+ *
7
+ * @internal
8
+ */
9
+ class Checker
10
+ {
11
+ static function throwError($argName, $argValue, $expectedTypeName)
12
+ {
13
+ if ($argValue === null) throw new \InvalidArgumentException("'$argName' must not be null");
14
+
15
+ if (is_object($argValue)) {
16
+ // Class type.
17
+ $argTypeName = get_class($argValue);
18
+ } else {
19
+ // Built-in type.
20
+ $argTypeName = gettype($argValue);
21
+ }
22
+
23
+ throw new \InvalidArgumentException("'$argName' has bad type; expecting $expectedTypeName, got $argTypeName");
24
+ }
25
+
26
+ static function argResource($argName, $argValue)
27
+ {
28
+ if (!is_resource($argValue)) self::throwError($argName, $argValue, "resource");
29
+ }
30
+
31
+ static function argCallable($argName, $argValue)
32
+ {
33
+ if (!is_callable($argValue)) self::throwError($argName, $argValue, "callable");
34
+ }
35
+
36
+ static function argBool($argName, $argValue)
37
+ {
38
+ if (!is_bool($argValue)) self::throwError($argName, $argValue, "boolean");
39
+ }
40
+
41
+ static function argArray($argName, $argValue)
42
+ {
43
+ if (!is_array($argValue)) self::throwError($argName, $argValue, "array");
44
+ }
45
+
46
+ static function argString($argName, $argValue)
47
+ {
48
+ if (!is_string($argValue)) self::throwError($argName, $argValue, "string");
49
+ }
50
+
51
+ static function argStringOrNull($argName, $argValue)
52
+ {
53
+ if ($argValue === null) return;
54
+ if (!is_string($argValue)) self::throwError($argName, $argValue, "string");
55
+ }
56
+
57
+ static function argStringNonEmpty($argName, $argValue)
58
+ {
59
+ if (!is_string($argValue)) self::throwError($argName, $argValue, "string");
60
+ if (strlen($argValue) === 0) throw new \InvalidArgumentException("'$argName' must be non-empty");
61
+ }
62
+
63
+ static function argStringNonEmptyOrNull($argName, $argValue)
64
+ {
65
+ if ($argValue === null) return;
66
+ if (!is_string($argValue)) self::throwError($argName, $argValue, "string");
67
+ if (strlen($argValue) === 0) throw new \InvalidArgumentException("'$argName' must be non-empty");
68
+ }
69
+
70
+ static function argNat($argName, $argValue)
71
+ {
72
+ if (!is_int($argValue)) self::throwError($argName, $argValue, "int");
73
+ if ($argValue < 0) throw new \InvalidArgumentException("'$argName' must be non-negative (you passed in $argValue)");
74
+ }
75
+
76
+ static function argNatOrNull($argName, $argValue)
77
+ {
78
+ if ($argValue === null) return;
79
+ if (!is_int($argValue)) self::throwError($argName, $argValue, "int");
80
+ if ($argValue < 0) throw new \InvalidArgumentException("'$argName' must be non-negative (you passed in $argValue)");
81
+ }
82
+
83
+ static function argIntPositive($argName, $argValue)
84
+ {
85
+ if (!is_int($argValue)) self::throwError($argName, $argValue, "int");
86
+ if ($argValue < 1) throw new \InvalidArgumentException("'$argName' must be positive (you passed in $argValue)");
87
+ }
88
+
89
+ static function argIntPositiveOrNull($argName, $argValue)
90
+ {
91
+ if ($argValue === null) return;
92
+ if (!is_int($argValue)) self::throwError($argName, $argValue, "int");
93
+ if ($argValue < 1) throw new \InvalidArgumentException("'$argName' must be positive (you passed in $argValue)");
94
+ }
95
+ }
com/lib/Dropbox/Client.php ADDED
@@ -0,0 +1,1700 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * The class used to make most Dropbox API calls. You can use this once you've gotten an
6
+ * {@link AccessToken} via {@link WebAuth}.
7
+ *
8
+ * This class is stateless so it can be shared/reused.
9
+ */
10
+ class Client
11
+ {
12
+ /**
13
+ * The access token used by this client to make authenticated API calls. You can get an
14
+ * access token via {@link WebAuth}.
15
+ *
16
+ * @return AccessToken
17
+ */
18
+ function getAccessToken() { return $this->accessToken; }
19
+
20
+ /** @var AccessToken */
21
+ private $accessToken;
22
+
23
+ /**
24
+ * An identifier for the API client, typically of the form "Name/Version".
25
+ * This is used to set the HTTP <code>User-Agent</code> header when making API requests.
26
+ * Example: <code>"PhotoEditServer/1.3"</code>
27
+ *
28
+ * If you're the author a higher-level library on top of the basic SDK, and the
29
+ * "Photo Edit" app's server code is using your library to access Dropbox, you should append
30
+ * your library's name and version to form the full identifier. For example,
31
+ * if your library is called "File Picker", you might set this field to:
32
+ * <code>"PhotoEditServer/1.3 FilePicker/0.1-beta"</code>
33
+ *
34
+ * The exact format of the <code>User-Agent</code> header is described in
35
+ * <a href="http://tools.ietf.org/html/rfc2616#section-3.8">section 3.8 of the HTTP specification</a>.
36
+ *
37
+ * Note that underlying HTTP client may append other things to the <code>User-Agent</code>, such as
38
+ * the name of the library being used to actually make the HTTP request (such as cURL).
39
+ *
40
+ * @return string
41
+ */
42
+ function getClientIdentifier() { return $this->clientIdentifier; }
43
+
44
+ /** @var string */
45
+ private $clientIdentifier;
46
+
47
+ /**
48
+ * The locale of the user of your application. Some API calls return localized
49
+ * data and error messages; this "user locale" setting determines which locale
50
+ * the server should use to localize those strings.
51
+ *
52
+ * @return null|string
53
+ */
54
+ function getUserLocale() { return $this->userLocale; }
55
+
56
+ /** @var null|string */
57
+ private $userLocale;
58
+
59
+ /**
60
+ * The {@link Host} object that determines the hostnames we make requests to.
61
+ *
62
+ * @return Host
63
+ */
64
+ function getHost() { return $this->host; }
65
+
66
+ /**
67
+ * Constructor.
68
+ *
69
+ * @param string $accessToken
70
+ * See {@link getAccessToken()}
71
+ * @param string $clientIdentifier
72
+ * See {@link getClientIdentifier()}
73
+ * @param null|string $userLocale
74
+ * See {@link getUserLocale()}
75
+ */
76
+ function __construct($accessToken, $clientIdentifier, $userLocale = null)
77
+ {
78
+ self::checkAccessTokenArg("accessToken", $accessToken);
79
+ self::checkClientIdentifierArg("clientIdentifier", $clientIdentifier);
80
+ Checker::argStringNonEmptyOrNull("userLocale", $userLocale);
81
+
82
+ $this->accessToken = $accessToken;
83
+ $this->clientIdentifier = $clientIdentifier;
84
+ $this->userLocale = $userLocale;
85
+
86
+ // The $host parameter is sort of internal. We don't include it in the param list because
87
+ // we don't want it to be included in the documentation. Use PHP arg list hacks to get at
88
+ // it.
89
+ $host = null;
90
+ if (\func_num_args() == 4) {
91
+ $host = \func_get_arg(3);
92
+ Host::checkArgOrNull("host", $host);
93
+ }
94
+ if ($host === null) {
95
+ $host = Host::getDefault();
96
+ }
97
+ $this->host = $host;
98
+
99
+ // These fields are redundant, but it makes these values a little more convenient
100
+ // to access.
101
+ $this->apiHost = $host->getApi();
102
+ $this->contentHost = $host->getContent();
103
+ }
104
+
105
+ /** @var string */
106
+ private $apiHost;
107
+ /** @var string */
108
+ public $contentHost;
109
+
110
+ /**
111
+ * Given a <code>$base</code> path for an API endpoint (for example, "/files"), append
112
+ * a Dropbox API file path to the end of that URL. Special characters in the file will
113
+ * be encoded properly.
114
+ *
115
+ * This is for endpoints like "/files" takes the path on the URL and not as a separate
116
+ * query or POST parameter.
117
+ *
118
+ * @param string $base
119
+ * @param string $path
120
+ * @return string
121
+ */
122
+ function appendFilePath($base, $path)
123
+ {
124
+ return $base . "/auto/" . rawurlencode(substr($path, 1));
125
+ }
126
+
127
+ /**
128
+ * Make an API call to disable the access token that you constructed this <code>Client</code>
129
+ * with. After calling this, API calls made with this <code>Client</code> will fail.
130
+ *
131
+ * See <a href="https://www.dropbox.com/developers/core/docs#disable-token">/disable_access_token</a>.
132
+ *
133
+ * @throws Exception
134
+ */
135
+ // function disableAccessToken()
136
+ // {
137
+ // $response = $this->doPost($this->apiHost, "1/disable_access_token");
138
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
139
+ // }
140
+
141
+ /*Dropbox api 2*/
142
+ function disableAccessToken()
143
+ {
144
+ $response = $this->doPost($this->apiHost, "2/auth/token/revoke");
145
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
146
+ }
147
+
148
+ /**
149
+ * Make an API call to get basic account and quota information.
150
+ *
151
+ * <code>
152
+ * $client = ...
153
+ * $accountInfo = $client->getAccountInfo();
154
+ * print_r($accountInfo);
155
+ * </code>
156
+ *
157
+ * @return array
158
+ * See <a href="https://www.dropbox.com/developers/core/docs#account-info">/account/info</a>.
159
+ *
160
+ * @throws Exception
161
+ */
162
+ // function getAccountInfo()
163
+ // {
164
+ // $response = $this->doGet($this->apiHost, "1/account/info");
165
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
166
+ // return RequestUtil::parseResponseJson($response->body);
167
+ // }
168
+
169
+ /*Dropbox api 2*/
170
+ function getAccountInfo()
171
+ {
172
+ $response = $this->doPost(
173
+ $this->apiHost,
174
+ "2/users/get_current_account",
175
+ null,
176
+ "Content-Type: application/json"
177
+ );
178
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
179
+ return RequestUtil::parseResponseJson($response->body);
180
+ }
181
+
182
+ /**
183
+ * Downloads a file from Dropbox. The file's contents are written to the
184
+ * given <code>$outStream</code> and the file's metadata is returned.
185
+ *
186
+ * <code>
187
+ * $client = ...;
188
+ * $fd = fopen("./Frog.jpeg", "wb");
189
+ * $metadata = $client->getFile("/Photos/Frog.jpeg", $fd);
190
+ * fclose($fd);
191
+ * print_r($metadata);
192
+ * </code>
193
+ *
194
+ * @param string $path
195
+ * The path to the file on Dropbox (UTF-8).
196
+ *
197
+ * @param resource $outStream
198
+ * If the file exists, the file contents will be written to this stream.
199
+ *
200
+ * @param string|null $rev
201
+ * If you want the latest revision of the file at the given path, pass in <code>null</code>.
202
+ * If you want a specific version of a file, pass in value of the file metadata's "rev" field.
203
+ *
204
+ * @return null|array
205
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata
206
+ * object</a> for the file at the given $path and $rev, or <code>null</code> if the file
207
+ * doesn't exist,
208
+ *
209
+ * @throws Exception
210
+ */
211
+ function getFile($path, $outStream, $rev = null)
212
+ {
213
+ Path::checkArgNonRoot("path", $path);
214
+ Checker::argResource("outStream", $outStream);
215
+ Checker::argStringNonEmptyOrNull("rev", $rev);
216
+
217
+ $url = $this->buildUrlForGetOrPut(
218
+ $this->contentHost,
219
+ $this->appendFilePath("1/files", $path),
220
+ array("rev" => $rev));
221
+
222
+ $curl = $this->mkCurl($url);
223
+ $metadataCatcher = new DropboxMetadataHeaderCatcher($curl->handle);
224
+ $streamRelay = new CurlStreamRelay($curl->handle, $outStream);
225
+
226
+ $response = $curl->exec();
227
+
228
+ if ($response->statusCode === 404) return null;
229
+
230
+ if ($response->statusCode !== 200) {
231
+ $response->body = $streamRelay->getErrorBody();
232
+ throw RequestUtil::unexpectedStatus($response);
233
+ }
234
+
235
+ return $metadataCatcher->getMetadata();
236
+ }
237
+
238
+ /**
239
+ * Calling 'uploadFile' with <code>$numBytes</code> less than this value, will cause this SDK
240
+ * to use the standard /files_put endpoint. When <code>$numBytes</code> is greater than this
241
+ * value, we'll use the /chunked_upload endpoint.
242
+ *
243
+ * @var int
244
+ */
245
+ private static $AUTO_CHUNKED_UPLOAD_THRESHOLD = 9863168; // 8 MB
246
+
247
+ /**
248
+ * @var int
249
+ */
250
+ private static $DEFAULT_CHUNK_SIZE = 4194304; // 4 MB
251
+
252
+ /**
253
+ * Creates a file on Dropbox, using the data from <code>$inStream</code> for the file contents.
254
+ *
255
+ * <code>
256
+ * use \Dropbox as dbx;
257
+ * $client = ...;
258
+ * $fd = fopen("./frog.jpeg", "rb");
259
+ * $md1 = $client->uploadFile("/Photos/Frog.jpeg",
260
+ * dbx\WriteMode::add(), $fd);
261
+ * fclose($fd);
262
+ * print_r($md1);
263
+ * $rev = $md1["rev"];
264
+ *
265
+ * // Re-upload with WriteMode::update(...), which will overwrite the
266
+ * // file if it hasn't been modified from our original upload.
267
+ * $fd = fopen("./frog-new.jpeg", "rb");
268
+ * $md2 = $client->uploadFile("/Photos/Frog.jpeg",
269
+ * dbx\WriteMode::update($rev), $fd);
270
+ * fclose($fd);
271
+ * print_r($md2);
272
+ * </code>
273
+ *
274
+ * @param string $path
275
+ * The Dropbox path to save the file to (UTF-8).
276
+ *
277
+ * @param WriteMode $writeMode
278
+ * What to do if there's already a file at the given path.
279
+ *
280
+ * @param resource $inStream
281
+ * The data to use for the file contents.
282
+ *
283
+ * @param int|null $numBytes
284
+ * You can pass in <code>null</code> if you don't know. If you do provide the size, we can
285
+ * perform a slightly more efficient upload (fewer network round-trips) for files smaller
286
+ * than 8 MB.
287
+ *
288
+ * @return mixed
289
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details>metadata
290
+ * object</a> for the newly-added file.
291
+ *
292
+ * @throws Exception
293
+ */
294
+ function uploadFile($path, $writeMode, $inStream, $numBytes = null)
295
+ {
296
+ Path::checkArgNonRoot("path", $path);
297
+ WriteMode::checkArg("writeMode", $writeMode);
298
+ Checker::argResource("inStream", $inStream);
299
+ Checker::argNatOrNull("numBytes", $numBytes);
300
+
301
+ // If we don't know how many bytes are coming, we have to use chunked upload.
302
+ // If $numBytes is large, we elect to use chunked upload.
303
+ // In all other cases, use regular upload.
304
+ if ($numBytes === null || $numBytes > self::$AUTO_CHUNKED_UPLOAD_THRESHOLD) {
305
+ $metadata = $this->_uploadFileChunked($path, $writeMode, $inStream, $numBytes,
306
+ self::$DEFAULT_CHUNK_SIZE);
307
+ } else {
308
+ $metadata = $this->_uploadFile($path, $writeMode,
309
+ function(Curl $curl) use ($inStream, $numBytes) {
310
+ $curl->set(CURLOPT_PUT, true);
311
+ $curl->set(CURLOPT_INFILE, $inStream);
312
+ $curl->set(CURLOPT_INFILESIZE, $numBytes);
313
+ });
314
+ }
315
+
316
+ return $metadata;
317
+ }
318
+
319
+ /**
320
+ * Creates a file on Dropbox, using the given $data string as the file contents.
321
+ *
322
+ * <code>
323
+ * use \Dropbox as dbx;
324
+ * $client = ...;
325
+ * $md = $client->uploadFileFromString("/Grocery List.txt",
326
+ * dbx\WriteMode::add(),
327
+ * "1. Coke\n2. Popcorn\n3. Toothpaste\n");
328
+ * print_r($md);
329
+ * </code>
330
+ *
331
+ * @param string $path
332
+ * The Dropbox path to save the file to (UTF-8).
333
+ *
334
+ * @param WriteMode $writeMode
335
+ * What to do if there's already a file at the given path.
336
+ *
337
+ * @param string $data
338
+ * The data to use for the contents of the file.
339
+ *
340
+ * @return mixed
341
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details>metadata
342
+ * object</a> for the newly-added file.
343
+ *
344
+ * @throws Exception
345
+ */
346
+ function uploadFileFromString($path, $writeMode, $data)
347
+ {
348
+ Path::checkArgNonRoot("path", $path);
349
+ WriteMode::checkArg("writeMode", $writeMode);
350
+ Checker::argString("data", $data);
351
+
352
+ return $this->_uploadFile($path, $writeMode, function(Curl $curl) use ($data) {
353
+ $curl->set(CURLOPT_CUSTOMREQUEST, "PUT");
354
+ $curl->set(CURLOPT_POSTFIELDS, $data);
355
+ $curl->addHeader("Content-Type: application/octet-stream");
356
+ });
357
+ }
358
+
359
+ /**
360
+ * Creates a file on Dropbox, using the data from $inStream as the file contents.
361
+ *
362
+ * This version of <code>uploadFile</code> splits uploads the file ~4MB chunks at a time and
363
+ * will retry a few times if one chunk fails to upload. Uses {@link chunkedUploadStart()},
364
+ * {@link chunkedUploadContinue()}, and {@link chunkedUploadFinish()}.
365
+ *
366
+ * @param string $path
367
+ * The Dropbox path to save the file to (UTF-8).
368
+ *
369
+ * @param WriteMode $writeMode
370
+ * What to do if there's already a file at the given path.
371
+ *
372
+ * @param resource $inStream
373
+ * The data to use for the file contents.
374
+ *
375
+ * @param int|null $numBytes
376
+ * The number of bytes available from $inStream.
377
+ * You can pass in <code>null</code> if you don't know.
378
+ *
379
+ * @param int|null $chunkSize
380
+ * The number of bytes to upload in each chunk. You can omit this (or pass in
381
+ * <code>null</code> and the library will use a reasonable default.
382
+ *
383
+ * @return mixed
384
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details>metadata
385
+ * object</a> for the newly-added file.
386
+ *
387
+ * @throws Exception
388
+ */
389
+ function uploadFileChunked($path, $writeMode, $inStream, $numBytes = null, $chunkSize = null)
390
+ {
391
+ if ($chunkSize === null) {
392
+ $chunkSize = self::$DEFAULT_CHUNK_SIZE;
393
+ }
394
+
395
+ Path::checkArgNonRoot("path", $path);
396
+ WriteMode::checkArg("writeMode", $writeMode);
397
+ Checker::argResource("inStream", $inStream);
398
+ Checker::argNatOrNull("numBytes", $numBytes);
399
+ Checker::argIntPositive("chunkSize", $chunkSize);
400
+
401
+ return $this->_uploadFileChunked($path, $writeMode, $inStream, $numBytes, $chunkSize);
402
+ }
403
+
404
+ /**
405
+ * @param string $path
406
+ *
407
+ * @param WriteMode $writeMode
408
+ * What to do if there's already a file at the given path (UTF-8).
409
+ *
410
+ * @param resource $inStream
411
+ * The source of data to upload.
412
+ *
413
+ * @param int|null $numBytes
414
+ * You can pass in <code>null</code>. But if you know how many bytes you expect, pass in
415
+ * that value and this function will do a sanity check at the end to make sure the number of
416
+ * bytes read from $inStream matches up.
417
+ *
418
+ * @param int $chunkSize
419
+ *
420
+ * @return array
421
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details>metadata
422
+ * object</a> for the newly-added file.
423
+ */
424
+ private function _uploadFileChunked($path, $writeMode, $inStream, $numBytes, $chunkSize)
425
+ {
426
+ Path::checkArg("path", $path);
427
+ WriteMode::checkArg("writeMode", $writeMode);
428
+ Checker::argResource("inStream", $inStream);
429
+ Checker::argNatOrNull("numBytes", $numBytes);
430
+ Checker::argNat("chunkSize", $chunkSize);
431
+
432
+ // NOTE: This function performs 3 retries on every call. This is maybe not the right
433
+ // layer to make retry decisions. It's also awkward because none of the other calls
434
+ // perform retries.
435
+
436
+ assert($chunkSize > 0);
437
+
438
+ $data = self::readFully($inStream, $chunkSize);
439
+ $len = strlen($data);
440
+
441
+ $client = $this;
442
+ $uploadId = RequestUtil::runWithRetry(3, function() use ($data, $client) {
443
+ return $client->chunkedUploadStart($data);
444
+ });
445
+
446
+ $byteOffset = $len;
447
+
448
+ while (!feof($inStream)) {
449
+ $data = self::readFully($inStream, $chunkSize);
450
+ $len = strlen($data);
451
+
452
+ while (true) {
453
+ $r = RequestUtil::runWithRetry(3,
454
+ function() use ($client, $uploadId, $byteOffset, $data) {
455
+ return $client->chunkedUploadContinue($uploadId, $byteOffset, $data);
456
+ });
457
+
458
+ if ($r === true) { // Chunk got uploaded!
459
+ $byteOffset += $len;
460
+ break;
461
+ }
462
+ if ($r === false) { // Server didn't recognize our upload ID
463
+ // This is very unlikely since we're uploading all the chunks in sequence.
464
+ throw new Exception_BadResponse("Server forgot our uploadId");
465
+ }
466
+
467
+ // Otherwise, the server is at a different byte offset from us.
468
+ $serverByteOffset = $r;
469
+ assert($serverByteOffset !== $byteOffset); // chunkedUploadContinue ensures this.
470
+ // An earlier byte offset means the server has lost data we sent earlier.
471
+ if ($serverByteOffset < $byteOffset) throw new Exception_BadResponse(
472
+ "Server is at an ealier byte offset: us=$byteOffset, server=$serverByteOffset");
473
+ $diff = $serverByteOffset - $byteOffset;
474
+ // If the server is past where we think it could possibly be, something went wrong.
475
+ if ($diff > $len) throw new Exception_BadResponse(
476
+ "Server is more than a chunk ahead: us=$byteOffset, server=$serverByteOffset");
477
+ // The normal case is that the server is a bit further along than us because of a
478
+ // partially-uploaded chunk. Finish it off.
479
+ $byteOffset += $diff;
480
+ if ($diff === $len) break; // If the server is at the end, we're done.
481
+ $data = substr($data, $diff);
482
+ }
483
+ }
484
+
485
+ if ($numBytes !== null && $byteOffset !== $numBytes) throw new \InvalidArgumentException(
486
+ "You passed numBytes=$numBytes but the stream had $byteOffset bytes.");
487
+
488
+ $metadata = RequestUtil::runWithRetry(3,
489
+ function() use ($client, $uploadId, $path, $writeMode) {
490
+ return $client->chunkedUploadFinish($uploadId, $path, $writeMode);
491
+ });
492
+
493
+ return $metadata;
494
+ }
495
+
496
+ /**
497
+ * Sometimes fread() returns less than the request number of bytes (for example, when reading
498
+ * from network streams). This function repeatedly calls fread until the requested number of
499
+ * bytes have been read or we've reached EOF.
500
+ *
501
+ * @param resource $inStream
502
+ * @param int $numBytes
503
+ * @throws StreamReadException
504
+ * @return string
505
+ */
506
+ private static function readFully($inStream, $numBytes)
507
+ {
508
+ Checker::argNat("numBytes", $numBytes);
509
+
510
+ $full = '';
511
+ $bytesRemaining = $numBytes;
512
+ while (!feof($inStream) && $bytesRemaining > 0) {
513
+ $part = fread($inStream, $bytesRemaining);
514
+ if ($part === false) throw new StreamReadException("Error reading from \$inStream.");
515
+ $full .= $part;
516
+ $bytesRemaining -= strlen($part);
517
+ }
518
+ return $full;
519
+ }
520
+
521
+ /**
522
+ * @param string $path
523
+ * @param WriteMode $writeMode
524
+ * @param callable $curlConfigClosure
525
+ * @return array
526
+ */
527
+ private function _uploadFile($path, $writeMode, $curlConfigClosure)
528
+ {
529
+ Path::checkArg("path", $path);
530
+ WriteMode::checkArg("writeMode", $writeMode);
531
+ Checker::argCallable("curlConfigClosure", $curlConfigClosure);
532
+
533
+ $url = $this->buildUrlForGetOrPut(
534
+ $this->contentHost,
535
+ $this->appendFilePath("1/files_put", $path),
536
+ $writeMode->getExtraParams());
537
+
538
+ $curl = $this->mkCurl($url);
539
+
540
+ $curlConfigClosure($curl);
541
+
542
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
543
+ $response = $curl->exec();
544
+
545
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
546
+
547
+ return RequestUtil::parseResponseJson($response->body);
548
+ }
549
+
550
+ /**
551
+ * Start a new chunked upload session and upload the first chunk of data.
552
+ *
553
+ * @param string $data
554
+ * The data to start off the chunked upload session.
555
+ *
556
+ * @return array
557
+ * A pair of <code>(string $uploadId, int $byteOffset)</code>. <code>$uploadId</code>
558
+ * is a unique identifier for this chunked upload session. You pass this in to
559
+ * {@link chunkedUploadContinue} and {@link chuunkedUploadFinish}. <code>$byteOffset</code>
560
+ * is the number of bytes that were successfully uploaded.
561
+ *
562
+ * @throws Exception
563
+ */
564
+ function chunkedUploadStart($data)
565
+ {
566
+ Checker::argString("data", $data);
567
+
568
+ $response = $this->_chunkedUpload(array(), $data);
569
+
570
+ if ($response->statusCode === 404) {
571
+ throw new Exception_BadResponse("Got a 404, but we didn't send up an 'session_id'");
572
+ }
573
+
574
+ $correction = self::_chunkedUploadCheckForOffsetCorrection($response);
575
+ if ($correction !== null) throw new Exception_BadResponse(
576
+ "Got an offset-correcting 400 response, but we didn't send an offset");
577
+
578
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
579
+
580
+ $uploadId = self::_chunkedUploadParse200Response($response->body);
581
+ $len = strlen($data);
582
+
583
+ return $uploadId;
584
+ }
585
+
586
+ /**
587
+ * Append another chunk data to a previously-started chunked upload session.
588
+ *
589
+ * @param string $uploadId
590
+ * The unique identifier for the chunked upload session. This is obtained via
591
+ * {@link chunkedUploadStart}.
592
+ *
593
+ * @param int $byteOffset
594
+ * The number of bytes you think you've already uploaded to the given chunked upload
595
+ * session. The server will append the new chunk of data after that point.
596
+ *
597
+ * @param string $data
598
+ * The data to append to the existing chunked upload session.
599
+ *
600
+ * @return int|bool
601
+ * If <code>false</code>, it means the server didn't know about the given
602
+ * <code>$uploadId</code>. This may be because the chunked upload session has expired
603
+ * (they last around 24 hours).
604
+ * If <code>true</code>, the chunk was successfully uploaded. If an integer, it means
605
+ * you and the server don't agree on the current <code>$byteOffset</code>. The returned
606
+ * integer is the server's internal byte offset for the chunked upload session. You need
607
+ * to adjust your input to match.
608
+ *
609
+ * @throws Exception
610
+ */
611
+ // function chunkedUploadContinue($uploadId, $byteOffset, $data)
612
+ // {
613
+ // Checker::argStringNonEmpty("uploadId", $uploadId);
614
+ // Checker::argNat("byteOffset", $byteOffset);
615
+ // Checker::argString("data", $data);
616
+
617
+ // $response = $this->_chunkedUpload(
618
+ // array("upload_id" => $uploadId, "offset" => $byteOffset), $data);
619
+
620
+ // if ($response->statusCode === 404) {
621
+ // // The server doesn't know our upload ID. Maybe it expired?
622
+ // return false;
623
+ // }
624
+
625
+ // $correction = self::_chunkedUploadCheckForOffsetCorrection($response);
626
+ // if ($correction !== null) {
627
+ // list($correctedUploadId, $correctedByteOffset) = $correction;
628
+ // if ($correctedUploadId !== $uploadId) throw new Exception_BadResponse(
629
+ // "Corrective 400 upload_id mismatch: us=".
630
+ // Util::q($uploadId)." server=".Util::q($correctedUploadId));
631
+ // if ($correctedByteOffset === $byteOffset) throw new Exception_BadResponse(
632
+ // "Corrective 400 offset is the same as ours: $byteOffset");
633
+ // return $correctedByteOffset;
634
+ // }
635
+
636
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
637
+ // list($retUploadId, $retByteOffset) = self::_chunkedUploadParse200Response($response->body);
638
+
639
+ // $nextByteOffset = $byteOffset + strlen($data);
640
+ // if ($uploadId !== $retUploadId) throw new Exception_BadResponse(
641
+ // "upload_id mismatch: us=".Util::q($uploadId) .", server=".Util::q($uploadId));
642
+ // if ($nextByteOffset !== $retByteOffset) throw new Exception_BadResponse(
643
+ // "next-offset mismatch: us=$nextByteOffset, server=$retByteOffset");
644
+
645
+ // return true;
646
+ // }
647
+
648
+ /*Dropbox api 2*/
649
+ function chunkedUploadContinue($uploadId, $byteOffset, $data)
650
+ {
651
+ Checker::argStringNonEmpty("session_id", $uploadId);
652
+ Checker::argNat("byteOffset", $byteOffset);
653
+ Checker::argString("data", $data);
654
+
655
+ $response = $this->_chunkedUploadContinue(
656
+ array(
657
+ "cursor" => array(
658
+ "session_id" => $uploadId,
659
+ "offset" => $byteOffset
660
+ ),
661
+ "close" => false
662
+ ),
663
+ $data
664
+ );
665
+
666
+ if ($response->statusCode === 404) {
667
+ // The server doesn't know our upload ID. Maybe it expired?
668
+ return false;
669
+ }
670
+
671
+ return true;
672
+ }
673
+
674
+ protected function _chunkedUploadContinue($params, $data)
675
+ {
676
+ $url = "https://content.dropboxapi.com/2/files/upload_session/append_v2";
677
+
678
+ $curl = $this->mkCurl($url);
679
+
680
+ $curl->set(CURLOPT_CUSTOMREQUEST, "POST");
681
+ $curl->set(CURLOPT_POSTFIELDS, $data);
682
+ $curl->addHeader("Content-Type: application/octet-stream");
683
+ $curl->addHeader("Dropbox-API-Arg: ".json_encode($params));
684
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
685
+
686
+ return $curl->exec();
687
+ }
688
+
689
+ /**
690
+ * @param string $body
691
+ * @return array
692
+ */
693
+ private static function _chunkedUploadParse200Response($body)
694
+ {
695
+ $j = RequestUtil::parseResponseJson($body);
696
+ $uploadId = self::getField($j, "session_id");
697
+ return $uploadId;
698
+ }
699
+
700
+ /**
701
+ * @param HttpResponse $response
702
+ * @return array|null
703
+ */
704
+ private static function _chunkedUploadCheckForOffsetCorrection($response)
705
+ {
706
+ if ($response->statusCode !== 400) return null;
707
+ $j = json_decode($response->body, true, 10);
708
+ if ($j === null) return null;
709
+ if (!array_key_exists("session_id", $j)) return null;
710
+ $uploadId = $j["session_id"];
711
+ return $uploadId;
712
+ }
713
+
714
+ /**
715
+ * Creates a file on Dropbox using the accumulated contents of the given chunked upload session.
716
+ *
717
+ * See <a href="https://www.dropbox.com/developers/core/docs#commit-chunked-upload">/commit_chunked_upload</a>.
718
+ *
719
+ * @param string $uploadId
720
+ * The unique identifier for the chunked upload session. This is obtained via
721
+ * {@link chunkedUploadStart}.
722
+ *
723
+ * @param string $path
724
+ * The Dropbox path to save the file to ($path).
725
+ *
726
+ * @param WriteMode $writeMode
727
+ * What to do if there's already a file at the given path.
728
+ *
729
+ * @return array|null
730
+ * If <code>null</code>, it means the Dropbox server wasn't aware of the
731
+ * <code>$uploadId</code> you gave it.
732
+ * Otherwise, you get back the
733
+ * <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata object</a>
734
+ * for the newly-created file.
735
+ *
736
+ * @throws Exception
737
+ */
738
+ // function chunkedUploadFinish($uploadId, $path, $writeMode)
739
+ // {
740
+ // Checker::argStringNonEmpty("uploadId", $uploadId);
741
+ // Path::checkArgNonRoot("path", $path);
742
+ // WriteMode::checkArg("writeMode", $writeMode);
743
+
744
+ // $params = array_merge(array("upload_id" => $uploadId), $writeMode->getExtraParams());
745
+
746
+ // $response = $this->doPost(
747
+ // $this->contentHost,
748
+ // $this->appendFilePath("1/commit_chunked_upload", $path),
749
+ // $params);
750
+
751
+ // if ($response->statusCode === 404) return null;
752
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
753
+
754
+ // return RequestUtil::parseResponseJson($response->body);
755
+ // }
756
+
757
+ /*Dropbox api 2*/
758
+ function chunkedUploadFinish($uploadId, $path, $offset)
759
+ {
760
+ Checker::argStringNonEmpty("session_id", $uploadId);
761
+ Path::checkArgNonRoot("path", $path);
762
+
763
+ $url = "https://content.dropboxapi.com/2/files/upload_session/finish";
764
+ $params = array(
765
+ "cursor" => array(
766
+ "session_id" => $uploadId,
767
+ "offset" => $offset
768
+ ),
769
+ "commit" => array(
770
+ "path" => $path,
771
+ "mode" => "add",
772
+ "autorename" => false,
773
+ "mute" => false
774
+ )
775
+ );
776
+
777
+ $curl = $this->mkCurl($url);
778
+
779
+ $curl->set(CURLOPT_CUSTOMREQUEST, "POST");
780
+ $curl->addHeader("Content-Type: application/octet-stream");
781
+ $curl->addHeader("Dropbox-API-Arg: ".json_encode($params));
782
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
783
+
784
+ $response = $curl->exec();
785
+
786
+ if ($response->statusCode === 404) return null;
787
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
788
+
789
+ return RequestUtil::parseResponseJson($response->body);
790
+ }
791
+
792
+ /**
793
+ * @param array $params
794
+ * @param string $data
795
+ * @return HttpResponse
796
+ */
797
+ // protected function _chunkedUpload($params, $data)
798
+ // // Marked 'protected' so I can override it in testing.
799
+ // {
800
+ // $url = $this->buildUrlForGetOrPut(
801
+ // $this->contentHost, "1/chunked_upload", $params);
802
+
803
+ // $curl = $this->mkCurl($url);
804
+
805
+ // // We can't use CURLOPT_PUT because it wants a stream, but we already have $data in memory.
806
+ // $curl->set(CURLOPT_CUSTOMREQUEST, "PUT");
807
+ // $curl->set(CURLOPT_POSTFIELDS, $data);
808
+ // $curl->addHeader("Content-Type: application/octet-stream");
809
+
810
+ // $curl->set(CURLOPT_RETURNTRANSFER, true);
811
+ // return $curl->exec();
812
+ // }
813
+
814
+ /*Dropbox api 2*/
815
+ // Marked 'protected' so I can override it in testing.
816
+ protected function _chunkedUpload($params, $data)
817
+ {
818
+ $url = "https://content.dropboxapi.com/2/files/upload_session/start";
819
+
820
+ $curl = $this->mkCurl($url);
821
+
822
+ $curl->set(CURLOPT_CUSTOMREQUEST, "POST");
823
+ $curl->set(CURLOPT_POSTFIELDS, $data);
824
+ $curl->addHeader("Content-Type: application/octet-stream");
825
+
826
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
827
+ $response = $curl->exec();
828
+
829
+ return $response;
830
+ }
831
+
832
+ /**
833
+ * Returns the metadata for whatever file or folder is at the given path.
834
+ *
835
+ * <code>
836
+ * $client = ...;
837
+ * $md = $client->getMetadata("/Photos/Frog.jpeg");
838
+ * print_r($md);
839
+ * </code>
840
+ *
841
+ * @param string $path
842
+ * The Dropbox path to a file or folder (UTF-8).
843
+ *
844
+ * @return array|null
845
+ * If there is a file or folder at the given path, you'll get back the
846
+ * <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata object</a>
847
+ * for that file or folder. If not, you'll get back <code>null</code>.
848
+ *
849
+ * @throws Exception
850
+ */
851
+ function getMetadata($path)
852
+ {
853
+ Path::checkArg("path", $path);
854
+
855
+ return $this->_getMetadata($path, array("list" => "false"));
856
+ }
857
+
858
+ /**
859
+ * Returns the metadata for whatever file or folder is at the given path and, if it's a folder,
860
+ * also include the metadata for all the immediate children of that folder.
861
+ *
862
+ * <code>
863
+ * $client = ...;
864
+ * $md = $client->getMetadataWithChildren("/Photos");
865
+ * print_r($md);
866
+ * </code>
867
+ *
868
+ * @param string $path
869
+ * The Dropbox path to a file or folder (UTF-8).
870
+ *
871
+ * @return array|null
872
+ * If there is a file or folder at the given path, you'll get back the
873
+ * <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata object</a>
874
+ * for that file or folder, along with all immediate children if it's a folder. If not,
875
+ * you'll get back <code>null</code>.
876
+ *
877
+ * @throws Exception
878
+ */
879
+ // function getMetadataWithChildren($path)
880
+ // {
881
+ // Path::checkArg("path", $path);
882
+
883
+ // return $this->_getMetadata($path, array("list" => "true", "file_limit" => "25000"));
884
+ // }
885
+
886
+ /*Dropbox api 2*/
887
+ function getMetadataWithChildren($path)
888
+ {
889
+ Path::checkArg("path", $path);
890
+
891
+ $params = array(
892
+ "path" => $path,
893
+ "recursive" => false,
894
+ "include_media_info" => false,
895
+ "include_deleted" => false,
896
+ "include_has_explicit_shared_members" => false
897
+ );
898
+ return $this->_getMetadata($params);
899
+ }
900
+
901
+ /**
902
+ * @param string $path
903
+ * @param array $params
904
+ * @return array
905
+ */
906
+ // private function _getMetadata($path, $params)
907
+ // {
908
+ // $response = $this->doGet(
909
+ // $this->apiHost,
910
+ // $this->appendFilePath("1/metadata", $path),
911
+ // $params);
912
+
913
+ // if ($response->statusCode === 404) return null;
914
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
915
+
916
+ // $metadata = RequestUtil::parseResponseJson($response->body);
917
+ // if (array_key_exists("is_deleted", $metadata) && $metadata["is_deleted"]) return null;
918
+ // return $metadata;
919
+ // }
920
+
921
+ /*Dropbox api 2*/
922
+ private function _getMetadata($params)
923
+ {
924
+ $response = $this->doPost($this->apiHost, "2/files/list_folder", $params, "Content-Type: application/json");
925
+
926
+ if ($response->statusCode === 404) return null;
927
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
928
+
929
+ $metadata = RequestUtil::parseResponseJson($response->body);
930
+ if (array_key_exists("is_deleted", $metadata) && $metadata["is_deleted"]) return null;
931
+ return $metadata;
932
+ }
933
+ /**
934
+ * If you've previously retrieved the metadata for a folder and its children, this method will
935
+ * retrieve updated metadata only if something has changed. This is more efficient than
936
+ * calling {@link getMetadataWithChildren} if you have a cache of previous results.
937
+ *
938
+ * <code>
939
+ * $client = ...;
940
+ * $md = $client->getMetadataWithChildren("/Photos");
941
+ * print_r($md);
942
+ * assert($md["is_dir"], "expecting \"/Photos\" to be a folder");
943
+ *
944
+ * sleep(10);
945
+ *
946
+ * // Now see if anything changed...
947
+ * list($changed, $new_md) = $client->getMetadataWithChildrenIfChanged(
948
+ * "/Photos", $md["hash"]);
949
+ * if ($changed) {
950
+ * echo "Folder changed.\n";
951
+ * print_r($new_md);
952
+ * } else {
953
+ * echo "Folder didn't change.\n";
954
+ * }
955
+ * </code>
956
+ *
957
+ * @param string $path
958
+ * The Dropbox path to a folder (UTF-8).
959
+ *
960
+ * @param string $previousFolderHash
961
+ * The "hash" field from the previously retrieved folder metadata.
962
+ *
963
+ * @return array
964
+ * A <code>list(boolean $changed, array $metadata)</code>. If the metadata hasn't changed,
965
+ * you'll get <code>list(false, null)</code>. If the metadata of the folder or any of its
966
+ * children has changed, you'll get <code>list(true, $newMetadata)</code>. $metadata is a
967
+ * <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata object</a>.
968
+ *
969
+ * @throws Exception
970
+ */
971
+ function getMetadataWithChildrenIfChanged($path, $previousFolderHash)
972
+ {
973
+ Path::checkArg("path", $path);
974
+ Checker::argStringNonEmpty("previousFolderHash", $previousFolderHash);
975
+
976
+ $params = array("list" => "true", "file_limit" => "25000", "hash" => $previousFolderHash);
977
+
978
+ $response = $this->doGet(
979
+ $this->apiHost,
980
+ $this->appendFilePath("1/metadata", $path),
981
+ $params);
982
+
983
+ if ($response->statusCode === 304) return array(false, null);
984
+ if ($response->statusCode === 404) return array(true, null);
985
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
986
+
987
+ $metadata = RequestUtil::parseResponseJson($response->body);
988
+ if (array_key_exists("is_deleted", $metadata) && $metadata["is_deleted"]) {
989
+ return array(true, null);
990
+ }
991
+ return array(true, $metadata);
992
+ }
993
+
994
+ /**
995
+ * A way of letting you keep up with changes to files and folders in a user's Dropbox.
996
+ *
997
+ * @param string|null $cursor
998
+ * If this is the first time you're calling this, pass in <code>null</code>. Otherwise,
999
+ * pass in whatever cursor was returned by the previous call.
1000
+ *
1001
+ * @param string|null $pathPrefix
1002
+ * If <code>null</code>, you'll get results for the entire folder (either the user's
1003
+ * entire Dropbox or your App Folder). If you set <code>$path_prefix</code> to
1004
+ * "/Photos/Vacation", you'll only get results for that path and any files and folders
1005
+ * under it.
1006
+ *
1007
+ * @return array
1008
+ * A <a href="https://www.dropbox.com/developers/core/docs#delta">delta page</a>, which
1009
+ * contains a list of changes to apply along with a new "cursor" that should be passed into
1010
+ * future <code>getDelta</code> calls. If the "reset" field is <code>true</code>, you
1011
+ * should clear your local state before applying the changes. If the "has_more" field is
1012
+ * <code>true</code>, call <code>getDelta</code> immediately to get more results, otherwise
1013
+ * wait a while (at least 5 minutes) before calling <code>getDelta</code> again.
1014
+ *
1015
+ * @throws Exception
1016
+ */
1017
+ function getDelta($cursor = null, $pathPrefix = null)
1018
+ {
1019
+ Checker::argStringNonEmptyOrNull("cursor", $cursor);
1020
+ Path::checkArgOrNull("pathPrefix", $pathPrefix);
1021
+
1022
+ $response = $this->doPost($this->apiHost, "1/delta", array(
1023
+ "cursor" => $cursor,
1024
+ "path_prefix" => $pathPrefix));
1025
+
1026
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1027
+
1028
+ return RequestUtil::parseResponseJson($response->body);
1029
+ }
1030
+
1031
+ /**
1032
+ * Gets the metadata for all the file revisions (up to a limit) for a given path.
1033
+ *
1034
+ * See <a href="https://www.dropbox.com/developers/core/docs#revisions">/revisions</a>.
1035
+ *
1036
+ * @param string path
1037
+ * The Dropbox path that you want file revision metadata for (UTF-8).
1038
+ *
1039
+ * @param int|null limit
1040
+ * The maximum number of revisions to return.
1041
+ *
1042
+ * @return array|null
1043
+ * A list of <a href="https://www.dropbox.com/developers/core/docs#metadata-details>metadata
1044
+ * objects</a>, one for each file revision. The later revisions appear first in the list.
1045
+ * If <code>null</code>, then there were too many revisions at that path.
1046
+ *
1047
+ * @throws Exception
1048
+ */
1049
+ function getRevisions($path, $limit = null)
1050
+ {
1051
+ Path::checkArgNonRoot("path", $path);
1052
+ Checker::argIntPositiveOrNull("limit", $limit);
1053
+
1054
+ $response = $this->doGet(
1055
+ $this->apiHost,
1056
+ $this->appendFilePath("1/revisions", $path),
1057
+ array("rev_limit" => $limit));
1058
+
1059
+ if ($response->statusCode === 406) return null;
1060
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1061
+
1062
+ return RequestUtil::parseResponseJson($response->body);
1063
+ }
1064
+
1065
+ /**
1066
+ * Takes a copy of the file at the given revision and saves it over the current copy. This
1067
+ * will create a new revision, but the file contents will match the revision you specified.
1068
+ *
1069
+ * See <a href="https://www.dropbox.com/developers/core/docs#restore">/restore</a>.
1070
+ *
1071
+ * @param string $path
1072
+ * The Dropbox path of the file to restore (UTF-8).
1073
+ *
1074
+ * @param string $rev
1075
+ * The revision to restore the contents to.
1076
+ *
1077
+ * @return mixed
1078
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata
1079
+ * object</a>
1080
+ *
1081
+ * @throws Exception
1082
+ */
1083
+ function restoreFile($path, $rev)
1084
+ {
1085
+ Path::checkArgNonRoot("path", $path);
1086
+ Checker::argStringNonEmpty("rev", $rev);
1087
+
1088
+ $response = $this->doPost(
1089
+ $this->apiHost,
1090
+ $this->appendFilePath("1/restore", $path),
1091
+ array("rev" => $rev));
1092
+
1093
+ if ($response->statusCode === 404) return null;
1094
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1095
+
1096
+ return RequestUtil::parseResponseJson($response->body);
1097
+ }
1098
+
1099
+ /**
1100
+ * Returns metadata for all files and folders whose filename matches the query string.
1101
+ *
1102
+ * See <a href="https://www.dropbox.com/developers/core/docs#search">/search</a>.
1103
+ *
1104
+ * @param string $basePath
1105
+ * The path to limit the search to (UTF-8). Pass in "/" to search everything.
1106
+ *
1107
+ * @param string $query
1108
+ * A space-separated list of substrings to search for. A file matches only if it contains
1109
+ * all the substrings.
1110
+ *
1111
+ * @param int|null $limit
1112
+ * The maximum number of results to return.
1113
+ *
1114
+ * @param bool $includeDeleted
1115
+ * Whether to include deleted files in the results.
1116
+ *
1117
+ * @return mixed
1118
+ * A list of <a href="https://www.dropbox.com/developers/core/docs#metadata-details>metadata
1119
+ * objects</a> of files that match the search query.
1120
+ *
1121
+ * @throws Exception
1122
+ */
1123
+ // function searchFileNames($basePath, $query, $limit = null, $includeDeleted = false)
1124
+ // {
1125
+ // Path::checkArg("basePath", $basePath);
1126
+ // Checker::argStringNonEmpty("query", $query);
1127
+ // Checker::argNatOrNull("limit", $limit);
1128
+ // Checker::argBool("includeDeleted", $includeDeleted);
1129
+
1130
+ // $response = $this->doPost(
1131
+ // $this->apiHost,
1132
+ // $this->appendFilePath("1/search", $basePath),
1133
+ // array(
1134
+ // "query" => $query,
1135
+ // "file_limit" => $limit,
1136
+ // "include_deleted" => $includeDeleted,
1137
+ // ));
1138
+
1139
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1140
+
1141
+ // return RequestUtil::parseResponseJson($response->body);
1142
+ // }
1143
+
1144
+ /*Dropbox api 2*/
1145
+ function searchFileNames($basePath, $query, $limit = null, $includeDeleted = false)
1146
+ {
1147
+ Path::checkArg("basePath", $basePath);
1148
+ Checker::argStringNonEmpty("query", $query);
1149
+ Checker::argNatOrNull("limit", $limit);
1150
+ Checker::argBool("includeDeleted", $includeDeleted);
1151
+
1152
+ $response = $this->doPost(
1153
+ $this->apiHost,
1154
+ "2/files/search",
1155
+ array(
1156
+ "path" => $basePath,
1157
+ "query" => $query,
1158
+ "start" => 0,
1159
+ "max_results" => 200,
1160
+ "mode" => "filename"
1161
+ ),
1162
+ "Content-Type: application/json"
1163
+ );
1164
+
1165
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1166
+
1167
+ return RequestUtil::parseResponseJson($response->body);
1168
+ }
1169
+
1170
+ /**
1171
+ * Creates and returns a public link to a file or folder's "preview page". This link can be
1172
+ * used without authentication. The preview page may contain a thumbnail or some other
1173
+ * preview of the file, along with a download link to download the actual file.
1174
+ *
1175
+ * See <a href="https://www.dropbox.com/developers/core/docs#shares">/shares</a>.
1176
+ *
1177
+ * @param string $path
1178
+ * The Dropbox path to the file or folder you want to create a shareable link to (UTF-8).
1179
+ *
1180
+ * @return string
1181
+ * The URL of the preview page.
1182
+ *
1183
+ * @throws Exception
1184
+ */
1185
+ function createShareableLink($path)
1186
+ {
1187
+ Path::checkArg("path", $path);
1188
+
1189
+ $response = $this->doPost(
1190
+ $this->apiHost,
1191
+ $this->appendFilePath("1/shares", $path),
1192
+ array(
1193
+ "short_url" => "false",
1194
+ ));
1195
+
1196
+ if ($response->statusCode === 404) return null;
1197
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1198
+
1199
+ $j = RequestUtil::parseResponseJson($response->body);
1200
+ return self::getField($j, "url");
1201
+ }
1202
+
1203
+ /**
1204
+ * Creates and returns a direct link to a file. This link can be used without authentication.
1205
+ * This link will expire in a few hours.
1206
+ *
1207
+ * See <a href="https://www.dropbox.com/developers/core/docs#media">/media</a>.
1208
+ *
1209
+ * @param string $path
1210
+ * The Dropbox path to a file or folder (UTF-8).
1211
+ *
1212
+ * @return array
1213
+ * A <code>list(string $url, \DateTime $expires)</code> where <code>$url</code> is a direct
1214
+ * link to the requested file and <code>$expires</code> is a standard PHP
1215
+ * <code>\DateTime</code> representing when <code>$url</code> will stop working.
1216
+ *
1217
+ * @throws Exception
1218
+ */
1219
+ function createTemporaryDirectLink($path)
1220
+ {
1221
+ Path::checkArgNonRoot("path", $path);
1222
+
1223
+ $response = $this->doPost(
1224
+ $this->apiHost,
1225
+ $this->appendFilePath("1/media", $path));
1226
+
1227
+ if ($response->statusCode === 404) return null;
1228
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1229
+
1230
+ $j = RequestUtil::parseResponseJson($response->body);
1231
+ $url = self::getField($j, "url");
1232
+ $expires = self::parseDateTime(self::getField($j, "expires"));
1233
+ return array($url, $expires);
1234
+ }
1235
+
1236
+ /**
1237
+ * Creates and returns a "copy ref" to a file. A copy ref can be used to copy a file across
1238
+ * different Dropbox accounts without downloading and re-uploading.
1239
+ *
1240
+ * For example: Create a <code>Client</code> using the access token from one account and call
1241
+ * <code>createCopyRef</code>. Then, create a <code>Client</code> using the access token for
1242
+ * another account and call <code>copyFromCopyRef</code> using the copy ref. (You need to use
1243
+ * the same app key both times.)
1244
+ *
1245
+ * See <a href="https://www.dropbox.com/developers/core/docs#copy_ref">/copy_ref</a>.
1246
+ *
1247
+ * @param string path
1248
+ * The Dropbox path of the file or folder you want to create a copy ref for (UTF-8).
1249
+ *
1250
+ * @return string
1251
+ * The copy ref (just a string that you keep track of).
1252
+ *
1253
+ * @throws Exception
1254
+ */
1255
+ function createCopyRef($path)
1256
+ {
1257
+ Path::checkArg("path", $path);
1258
+
1259
+ $response = $this->doGet(
1260
+ $this->apiHost,
1261
+ $this->appendFilePath("1/copy_ref", $path));
1262
+
1263
+ if ($response->statusCode === 404) return null;
1264
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1265
+
1266
+ $j = RequestUtil::parseResponseJson($response->body);
1267
+ return self::getField($j, "copy_ref");
1268
+ }
1269
+
1270
+ /**
1271
+ * Gets a thumbnail image representation of the file at the given path.
1272
+ *
1273
+ * See <a href="https://www.dropbox.com/developers/core/docs#thumbnails">/thumbnails</a>.
1274
+ *
1275
+ * @param string $path
1276
+ * The path to the file you want a thumbnail for (UTF-8).
1277
+ *
1278
+ * @param string $format
1279
+ * One of the two image formats: "jpeg" or "png".
1280
+ *
1281
+ * @param string $size
1282
+ * One of the predefined image size names, as a string:
1283
+ * <ul>
1284
+ * <li>"xs" - 32x32</li>
1285
+ * <li>"s" - 64x64</li>
1286
+ * <li>"m" - 128x128</li>
1287
+ * <li>"l" - 640x480</li>
1288
+ * <li>"xl" - 1024x768</li>
1289
+ * </ul>
1290
+ *
1291
+ * @return array|null
1292
+ * If the file exists, you'll get <code>list(array $metadata, string $data)</code> where
1293
+ * <code>$metadata</code> is the file's
1294
+ * <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata object</a>
1295
+ * and $data is the raw data for the thumbnail image. If the file doesn't exist, you'll
1296
+ * get <code>null</code>.
1297
+ *
1298
+ * @throws Exception
1299
+ */
1300
+ function getThumbnail($path, $format, $size)
1301
+ {
1302
+ Path::checkArgNonRoot("path", $path);
1303
+ Checker::argString("format", $format);
1304
+ Checker::argString("size", $size);
1305
+ if (!in_array($format, array("jpeg", "png"))) {
1306
+ throw new \InvalidArgumentException("Invalid 'format': ".Util::q($format));
1307
+ }
1308
+ if (!in_array($size, array("xs", "s", "m", "l", "xl"))) {
1309
+ throw new \InvalidArgumentException("Invalid 'size': ".Util::q($format));
1310
+ }
1311
+
1312
+ $url = $this->buildUrlForGetOrPut(
1313
+ $this->contentHost,
1314
+ $this->appendFilePath("1/thumbnails", $path),
1315
+ array("size" => $size, "format" => $format));
1316
+
1317
+ $curl = $this->mkCurl($url);
1318
+ $metadataCatcher = new DropboxMetadataHeaderCatcher($curl->handle);
1319
+
1320
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
1321
+ $response = $curl->exec();
1322
+
1323
+ if ($response->statusCode === 404) return null;
1324
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1325
+
1326
+ $metadata = $metadataCatcher->getMetadata();
1327
+ return array($metadata, $response->body);
1328
+ }
1329
+
1330
+ /**
1331
+ * Copies a file or folder to a new location
1332
+ *
1333
+ * See <a href="https://www.dropbox.com/developers/core/docs#fileops-copy">/fileops/copy</a>.
1334
+ *
1335
+ * @param string $fromPath
1336
+ * The Dropbox path of the file or folder you want to copy (UTF-8).
1337
+ *
1338
+ * @param string $toPath
1339
+ * The destination Dropbox path (UTF-8).
1340
+ *
1341
+ * @return mixed
1342
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata
1343
+ * object</a> for the new file or folder.
1344
+ *
1345
+ * @throws Exception
1346
+ */
1347
+ function copy($fromPath, $toPath)
1348
+ {
1349
+ Path::checkArg("fromPath", $fromPath);
1350
+ Path::checkArgNonRoot("toPath", $toPath);
1351
+
1352
+ $response = $this->doPost(
1353
+ $this->apiHost,
1354
+ "1/fileops/copy",
1355
+ array(
1356
+ "root" => "auto",
1357
+ "from_path" => $fromPath,
1358
+ "to_path" => $toPath,
1359
+ ));
1360
+
1361
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1362
+
1363
+ return RequestUtil::parseResponseJson($response->body);
1364
+ }
1365
+
1366
+ /**
1367
+ * Creates a file or folder based on an existing copy ref (possibly from a different Dropbox
1368
+ * account).
1369
+ *
1370
+ * See <a href="https://www.dropbox.com/developers/core/docs#fileops-copy">/fileops/copy</a>.
1371
+ *
1372
+ * @param string $copyRef
1373
+ * A copy ref obtained via the {@link createCopyRef()} call.
1374
+ *
1375
+ * @param string $toPath
1376
+ * The Dropbox path you want to copy the file or folder to (UTF-8).
1377
+ *
1378
+ * @return mixed
1379
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata
1380
+ * object</a> for the new file or folder.
1381
+ *
1382
+ * @throws Exception
1383
+ */
1384
+ function copyFromCopyRef($copyRef, $toPath)
1385
+ {
1386
+ Checker::argStringNonEmpty("copyRef", $copyRef);
1387
+ Path::checkArgNonRoot("toPath", $toPath);
1388
+
1389
+ $response = $this->doPost(
1390
+ $this->apiHost,
1391
+ "1/fileops/copy",
1392
+ array(
1393
+ "root" => "auto",
1394
+ "from_copy_ref" => $copyRef,
1395
+ "to_path" => $toPath,
1396
+ )
1397
+ );
1398
+
1399
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1400
+
1401
+ return RequestUtil::parseResponseJson($response->body);
1402
+ }
1403
+
1404
+ /**
1405
+ * Creates a folder.
1406
+ *
1407
+ * See <a href="https://www.dropbox.com/developers/core/docs#fileops-create-folder">/fileops/create_folder</a>.
1408
+ *
1409
+ * @param string $path
1410
+ * The Dropbox path at which to create the folder (UTF-8).
1411
+ *
1412
+ * @return array|null
1413
+ * If successful, you'll get back the
1414
+ * <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata object</a>
1415
+ * for the newly-created folder. If not successful, you'll get <code>null</code>.
1416
+ *
1417
+ * @throws Exception
1418
+ */
1419
+ // function createFolder($path)
1420
+ // {
1421
+ // Path::checkArgNonRoot("path", $path);
1422
+
1423
+ // $response = $this->doPost(
1424
+ // $this->apiHost,
1425
+ // "1/fileops/create_folder",
1426
+ // array(
1427
+ // "root" => "auto",
1428
+ // "path" => $path,
1429
+ // ));
1430
+
1431
+ // if ($response->statusCode === 403) return null;
1432
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1433
+
1434
+ // return RequestUtil::parseResponseJson($response->body);
1435
+ // }
1436
+
1437
+ /*Dropbox api 2*/
1438
+ function createFolder($path)
1439
+ {
1440
+ Path::checkArgNonRoot("path", $path);
1441
+
1442
+ $response = $this->doPost(
1443
+ $this->apiHost,
1444
+ "2/files/create_folder",
1445
+ array(
1446
+ "autorename" => false,
1447
+ "path" => $path,
1448
+ ),
1449
+ "Content-Type: application/json"
1450
+ );
1451
+
1452
+ if ($response->statusCode == 409) {
1453
+ return;
1454
+ }
1455
+
1456
+ if ($response->statusCode === 403) return null;
1457
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1458
+
1459
+ return RequestUtil::parseResponseJson($response->body);
1460
+ }
1461
+ /**
1462
+ * Deletes a file or folder
1463
+ *
1464
+ * See <a href="https://www.dropbox.com/developers/core/docs#fileops-delete">/fileops/delete</a>.
1465
+ *
1466
+ * @param string $path
1467
+ * The Dropbox path of the file or folder to delete (UTF-8).
1468
+ *
1469
+ * @return mixed
1470
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata
1471
+ * object</a> for the deleted file or folder.
1472
+ *
1473
+ * @throws Exception
1474
+ */
1475
+ // function delete($path)
1476
+ // {
1477
+ // Path::checkArgNonRoot("path", $path);
1478
+
1479
+ // $response = $this->doPost(
1480
+ // $this->apiHost,
1481
+ // "1/fileops/delete",
1482
+ // array(
1483
+ // "root" => "auto",
1484
+ // "path" => $path,
1485
+ // ));
1486
+
1487
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1488
+
1489
+ // return RequestUtil::parseResponseJson($response->body);
1490
+ // }
1491
+
1492
+ /*Dropbox api 2*/
1493
+ function delete($path)
1494
+ {
1495
+ Path::checkArgNonRoot("path", $path);
1496
+
1497
+ $response = $this->doPost(
1498
+ $this->apiHost,
1499
+ "2/files/delete",
1500
+ array(
1501
+ "path" => $path
1502
+ ),
1503
+ "Content-Type: application/json"
1504
+ );
1505
+
1506
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1507
+
1508
+ return RequestUtil::parseResponseJson($response->body);
1509
+ }
1510
+
1511
+ /**
1512
+ * Moves a file or folder to a new location.
1513
+ *
1514
+ * See <a href="https://www.dropbox.com/developers/core/docs#fileops-move">/fileops/move</a>.
1515
+ *
1516
+ * @param string $fromPath
1517
+ * The source Dropbox path (UTF-8).
1518
+ *
1519
+ * @param string $toPath
1520
+ * The destination Dropbox path (UTF-8).
1521
+ *
1522
+ * @return mixed
1523
+ * The <a href="https://www.dropbox.com/developers/core/docs#metadata-details">metadata
1524
+ * object</a> for the destination file or folder.
1525
+ *
1526
+ * @throws Exception
1527
+ */
1528
+ function move($fromPath, $toPath)
1529
+ {
1530
+ Path::checkArgNonRoot("fromPath", $fromPath);
1531
+ Path::checkArgNonRoot("toPath", $toPath);
1532
+
1533
+ $response = $this->doPost(
1534
+ $this->apiHost,
1535
+ "1/fileops/move",
1536
+ array(
1537
+ "root" => "auto",
1538
+ "from_path" => $fromPath,
1539
+ "to_path" => $toPath,
1540
+ ));
1541
+
1542
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
1543
+
1544
+ return RequestUtil::parseResponseJson($response->body);
1545
+ }
1546
+
1547
+ /**
1548
+ * Build a URL for making a GET or PUT request. Will add the "locale"
1549
+ * parameter.
1550
+ *
1551
+ * @param string $host
1552
+ * Either the "API" or "API content" hostname from {@link getHost()}.
1553
+ * @param string $path
1554
+ * The "path" part of the URL. For example, "/account/info".
1555
+ * @param array|null $params
1556
+ * URL parameters. For POST requests, do not put the parameters here.
1557
+ * Include them in the request body instead.
1558
+ *
1559
+ * @return string
1560
+ */
1561
+ function buildUrlForGetOrPut($host, $path, $params = null)
1562
+ {
1563
+ return RequestUtil::buildUrlForGetOrPut($this->userLocale, $host, $path, $params);
1564
+ }
1565
+
1566
+ /**
1567
+ * Perform an OAuth-2-authorized GET request to the Dropbox API. Will automatically
1568
+ * fill in "User-Agent" and "locale" as well.
1569
+ *
1570
+ * @param string $host
1571
+ * Either the "API" or "API content" hostname from {@link getHost()}.
1572
+ * @param string $path
1573
+ * The "path" part of the URL. For example, "/account/info".
1574
+ * @param array|null $params
1575
+ * GET parameters.
1576
+ * @return HttpResponse
1577
+ *
1578
+ * @throws Exception
1579
+ */
1580
+ function doGet($host, $path, $params = null)
1581
+ {
1582
+ Checker::argString("host", $host);
1583
+ Checker::argString("path", $path);
1584
+ return RequestUtil::doGet($this->clientIdentifier, $this->accessToken, $this->userLocale,
1585
+ $host, $path, $params);
1586
+ }
1587
+
1588
+ /**
1589
+ * Perform an OAuth-2-authorized POST request to the Dropbox API. Will automatically
1590
+ * fill in "User-Agent" and "locale" as well.
1591
+ *
1592
+ * @param string $host
1593
+ * Either the "API" or "API content" hostname from {@link getHost()}.
1594
+ * @param string $path
1595
+ * The "path" part of the URL. For example, "/commit_chunked_upload".
1596
+ * @param array|null $params
1597
+ * POST parameters.
1598
+ * @return HttpResponse
1599
+ *
1600
+ * @throws Exception
1601
+ */
1602
+ function doPost($host, $path, $params = null, $headers = null)
1603
+ {
1604
+ Checker::argString("host", $host);
1605
+ Checker::argString("path", $path);
1606
+ return RequestUtil::doPost($this->clientIdentifier, $this->accessToken, $this->userLocale, $host, $path, $params, $headers);
1607
+ }
1608
+
1609
+ /**
1610
+ * Create a {@link Curl} object that is pre-configured with {@link getClientIdentifier()},
1611
+ * and the proper OAuth 2 "Authorization" header.
1612
+ *
1613
+ * @param string $url
1614
+ * Generate this URL using {@link buildUrl()}.
1615
+ *
1616
+ * @return Curl
1617
+ */
1618
+ function mkCurl($url)
1619
+ {
1620
+ return RequestUtil::mkCurlWithOAuth($this->clientIdentifier, $url, $this->accessToken);
1621
+ }
1622
+
1623
+ /**
1624
+ * Parses date/time strings returned by the Dropbox API. The Dropbox API returns date/times
1625
+ * formatted like: <code>"Sat, 21 Aug 2010 22:31:20 +0000"</code>.
1626
+ *
1627
+ * @param string $apiDateTimeString
1628
+ * A date/time string returned by the API.
1629
+ *
1630
+ * @return \DateTime
1631
+ * A standard PHP <code>\DateTime</code> instance.
1632
+ *
1633
+ * @throws Exception_BadResponse
1634
+ * Thrown if <code>$apiDateTimeString</code> isn't correctly formatted.
1635
+ */
1636
+ static function parseDateTime($apiDateTimeString)
1637
+ {
1638
+ $dt = \DateTime::createFromFormat(self::$dateTimeFormat, $apiDateTimeString);
1639
+ if ($dt === false) throw new Exception_BadResponse(
1640
+ "Bad date/time from server: ".Util::q($apiDateTimeString));
1641
+ return $dt;
1642
+ }
1643
+
1644
+ private static $dateTimeFormat = "D, d M Y H:i:s T";
1645
+
1646
+ /**
1647
+ * @internal
1648
+ */
1649
+ static function getField($j, $fieldName)
1650
+ {
1651
+ if (!array_key_exists($fieldName, $j)) throw new Exception_BadResponse(
1652
+ "missing field \"$fieldName\" in ".Util::q($j));
1653
+ return $j[$fieldName];
1654
+ }
1655
+
1656
+ /**
1657
+ * Given an OAuth 2 access token, returns <code>null</code> if it is well-formed (though
1658
+ * not necessarily valid). Otherwise, returns a string describing what's wrong with it.
1659
+ *
1660
+ * @param string $s
1661
+ *
1662
+ * @return string
1663
+ */
1664
+ static function getAccessTokenError($s)
1665
+ {
1666
+ if ($s === null) return "can't be null";
1667
+ if (strlen($s) === 0) return "can't be empty";
1668
+ if (preg_match('@[^-=_~/A-Za-z0-9\.\+]@', $s) === 1) return "contains invalid character";
1669
+ return null;
1670
+ }
1671
+
1672
+ /**
1673
+ * @internal
1674
+ */
1675
+ static function checkAccessTokenArg($argName, $accessToken)
1676
+ {
1677
+ $error = self::getAccessTokenError($accessToken);
1678
+ if ($error !== null) throw new \InvalidArgumentException("'$argName' invalid: $error");
1679
+ }
1680
+
1681
+ /**
1682
+ * @internal
1683
+ */
1684
+ static function getClientIdentifierError($s)
1685
+ {
1686
+ if ($s === null) return "can't be null";
1687
+ if (strlen($s) === 0) return "can't be empty";
1688
+ if (preg_match('@[\x00-\x1f\x7f]@', $s) === 1) return "contains control character";
1689
+ return null;
1690
+ }
1691
+
1692
+ /**
1693
+ * @internal
1694
+ */
1695
+ static function checkClientIdentifierArg($argName, $accessToken)
1696
+ {
1697
+ $error = self::getClientIdentifierError($accessToken);
1698
+ if ($error !== null) throw new \InvalidArgumentException("'$argName' invalid: $error");
1699
+ }
1700
+ }
com/lib/Dropbox/Curl.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * A minimal wrapper around a cURL handle.
6
+ *
7
+ * @internal
8
+ */
9
+ final class Curl
10
+ {
11
+ /** @var resource */
12
+ public $handle;
13
+
14
+ /** @var string[] */
15
+ private $headers = array();
16
+
17
+ /**
18
+ * @param string $url
19
+ */
20
+ function __construct($url)
21
+ {
22
+ // Make sure there aren't any spaces in the URL (i.e. the caller forgot to URL-encode).
23
+ if (strpos($url, ' ') !== false) {
24
+ throw new \InvalidArgumentException("Found space in \$url; it should be encoded");
25
+ }
26
+
27
+ $this->handle = curl_init($url);
28
+
29
+ // NOTE: Though we turn on all the correct SSL settings, many PHP installations
30
+ // don't respect these settings. Run "examples/test-ssl.php" to run some basic
31
+ // SSL tests to see how well your PHP implementation behaves.
32
+
33
+ // Use our own certificate list.
34
+ $this->set(CURLOPT_SSL_VERIFYPEER, true); // Enforce certificate validation
35
+ $this->set(CURLOPT_SSL_VERIFYHOST, 2); // Enforce hostname validation
36
+
37
+ // Force the use of TLS (SSL v2 and v3 are not secure).
38
+ // TODO: Use "CURL_SSLVERSION_TLSv1" instead of "1" once we can rely on PHP 5.5+.
39
+ $this->set(CURLOPT_SSLVERSION, 1);
40
+
41
+ // Limit the set of ciphersuites used.
42
+ global $sslCiphersuiteList;
43
+ if ($sslCiphersuiteList !== null) {
44
+ $this->set(CURLOPT_SSL_CIPHER_LIST, $sslCiphersuiteList);
45
+ }
46
+
47
+ list($rootCertsFilePath, $rootCertsFolderPath) = RootCertificates::getPaths();
48
+ // Certificate file.
49
+ $this->set(CURLOPT_CAINFO, $rootCertsFilePath);
50
+ // Certificate folder. If not specified, some PHP installations will use
51
+ // the system default, even when CURLOPT_CAINFO is specified.
52
+ $this->set(CURLOPT_CAPATH, $rootCertsFolderPath);
53
+
54
+ // Limit vulnerability surface area. Supported in cURL 7.19.4+
55
+ if (defined('CURLOPT_PROTOCOLS')) $this->set(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
56
+ if (defined('CURLOPT_REDIR_PROTOCOLS')) $this->set(CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
57
+ }
58
+
59
+ /**
60
+ * @param string $header
61
+ */
62
+ function addHeader($header)
63
+ {
64
+ if (is_array($header)) {
65
+ $this->headers = array_merge($this->headers, $header);
66
+ }
67
+ else {
68
+ $this->headers[] = $header;
69
+ }
70
+ }
71
+
72
+ function exec()
73
+ {
74
+ $this->set(CURLOPT_HTTPHEADER, $this->headers);
75
+
76
+ $body = curl_exec($this->handle);
77
+ if ($body === false) {
78
+ throw new Exception_NetworkIO("Error executing HTTP request: " . curl_error($this->handle));
79
+ }
80
+
81
+ $statusCode = curl_getinfo($this->handle, CURLINFO_HTTP_CODE);
82
+
83
+ return new HttpResponse($statusCode, $body);
84
+ }
85
+
86
+ /**
87
+ * @param int $option
88
+ * @param mixed $value
89
+ */
90
+ function set($option, $value)
91
+ {
92
+ curl_setopt($this->handle, $option, $value);
93
+ }
94
+
95
+ function __destruct()
96
+ {
97
+ curl_close($this->handle);
98
+ }
99
+ }
100
+
101
+ // Different cURL SSL backends use different names for ciphersuites.
102
+ $curlVersion = \curl_version();
103
+ $curlSslBackend = $curlVersion['ssl_version'];
104
+ if (\substr_compare($curlSslBackend, "NSS/", 0, strlen("NSS/")) === 0) {
105
+ // Can't figure out how to reliably set ciphersuites for NSS.
106
+ $sslCiphersuiteList = null;
107
+ }
108
+ else {
109
+ // Use the OpenSSL names for all other backends. We may have to
110
+ // refine this if users report errors.
111
+ $sslCiphersuiteList =
112
+ 'ECDHE-RSA-AES256-GCM-SHA384:'.
113
+ 'ECDHE-RSA-AES128-GCM-SHA256:'.
114
+ 'ECDHE-RSA-AES256-SHA384:'.
115
+ 'ECDHE-RSA-AES128-SHA256:'.
116
+ 'ECDHE-RSA-AES256-SHA:'.
117
+ 'ECDHE-RSA-AES128-SHA:'.
118
+ 'ECDHE-RSA-RC4-SHA:'.
119
+ 'DHE-RSA-AES256-GCM-SHA384:'.
120
+ 'DHE-RSA-AES128-GCM-SHA256:'.
121
+ 'DHE-RSA-AES256-SHA256:'.
122
+ 'DHE-RSA-AES128-SHA256:'.
123
+ 'DHE-RSA-AES256-SHA:'.
124
+ 'DHE-RSA-AES128-SHA:'.
125
+ 'AES256-GCM-SHA384:'.
126
+ 'AES128-GCM-SHA256:'.
127
+ 'AES256-SHA256:'.
128
+ 'AES128-SHA256:'.
129
+ 'AES256-SHA:'.
130
+ 'AES128-SHA';
131
+ }
com/lib/Dropbox/CurlStreamRelay.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * A CURLOPT_WRITEFUNCTION that will write HTTP response data to $outStream if
6
+ * it's an HTTP 200 response. For all other HTTP status codes, it'll save the
7
+ * output in a string, which you can retrieve it via {@link getErrorBody}.
8
+ *
9
+ * @internal
10
+ */
11
+ class CurlStreamRelay
12
+ {
13
+ var $outStream;
14
+ var $errorData;
15
+ var $isError;
16
+
17
+ function __construct($ch, $outStream)
18
+ {
19
+ $this->outStream = $outStream;
20
+ $this->errorData = array();
21
+ $isError = null;
22
+ curl_setopt($ch, CURLOPT_WRITEFUNCTION, array($this, 'writeData'));
23
+ }
24
+
25
+ function writeData($ch, $data)
26
+ {
27
+ if ($this->isError === null) {
28
+ $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
29
+ $this->isError = ($statusCode !== 200);
30
+ }
31
+
32
+ if ($this->isError) {
33
+ $this->errorData[] = $data;
34
+ } else {
35
+ fwrite($this->outStream, $data);
36
+ }
37
+
38
+ return strlen($data);
39
+ }
40
+
41
+ function getErrorBody()
42
+ {
43
+ return implode($this->errorData);
44
+ }
45
+ }
com/lib/Dropbox/DeserializeException.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * If, when loading a serialized {@link RequestToken} or {@link AccessToken}, the input string is
6
+ * malformed, this exception will be thrown.
7
+ */
8
+ final class DeserializeException extends \Exception
9
+ {
10
+ /**
11
+ * @param string $message
12
+ *
13
+ * @internal
14
+ */
15
+ function __construct($message)
16
+ {
17
+ parent::__construct($message);
18
+ }
19
+ }
com/lib/Dropbox/DropboxMetadataHeaderCatcher.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * @internal
6
+ */
7
+ final class DropboxMetadataHeaderCatcher
8
+ {
9
+ /**
10
+ * @var mixed
11
+ */
12
+ var $metadata = null;
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ var $error = null;
18
+
19
+ /**
20
+ * @var bool
21
+ */
22
+ var $skippedFirstLine = false;
23
+
24
+ /**
25
+ * @param resource $ch
26
+ */
27
+ function __construct($ch)
28
+ {
29
+ curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, 'headerFunction'));
30
+ }
31
+
32
+ /**
33
+ * @param resource $ch
34
+ * @param string $header
35
+ * @return int
36
+ * @throws Exception_BadResponse
37
+ */
38
+ function headerFunction($ch, $header)
39
+ {
40
+ // The first line is the HTTP status line (Ex: "HTTP/1.1 200 OK").
41
+ if (!$this->skippedFirstLine) {
42
+ $this->skippedFirstLine = true;
43
+ return strlen($header);
44
+ }
45
+
46
+ // If we've encountered an error on a previous callback, then there's nothing left to do.
47
+ if ($this->error !== null) {
48
+ return strlen($header);
49
+ }
50
+
51
+ // case-insensitive starts-with check.
52
+ if (\substr_compare($header, "x-dropbox-metadata:", 0, 19, true) !== 0) {
53
+ return strlen($header);
54
+ }
55
+
56
+ if ($this->metadata !== null) {
57
+ $this->error = "Duplicate X-Dropbox-Metadata header";
58
+ return strlen($header);
59
+ }
60
+
61
+ $headerValue = substr($header, 19);
62
+ $parsed = json_decode($headerValue, true, 10);
63
+
64
+ if ($parsed === null) {
65
+ $this->error = "Bad JSON in X-Dropbox-Metadata header";
66
+ return strlen($header);
67
+ }
68
+
69
+ $this->metadata = $parsed;
70
+ return strlen($header);
71
+ }
72
+
73
+ function getMetadata()
74
+ {
75
+ if ($this->error !== null) {
76
+ throw new Exception_BadResponse($this->error);
77
+ }
78
+ if ($this->metadata === null) {
79
+ throw new Exception_BadResponse("Missing X-Dropbox-Metadata header");
80
+ }
81
+ return $this->metadata;
82
+ }
83
+ }
com/lib/Dropbox/Exception.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * The base class for all API call exceptions.
6
+ */
7
+ class Exception extends \Exception
8
+ {
9
+ /**
10
+ * @internal
11
+ */
12
+ function __construct($message, $cause = null)
13
+ {
14
+ parent::__construct($message, 0, $cause);
15
+ }
16
+ }
com/lib/Dropbox/Exception/BadRequest.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown when the server tells us that our request was invalid. This is typically due to an
6
+ * HTTP 400 response from the server.
7
+ */
8
+ final class Exception_BadRequest extends Exception_ProtocolError
9
+ {
10
+ /**
11
+ * @internal
12
+ */
13
+ function __construct($message = "")
14
+ {
15
+ parent::__construct($message);
16
+ }
17
+ }
com/lib/Dropbox/Exception/BadResponse.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * When this SDK can't understand the response from the server. This could be due to a bug in this
6
+ * SDK or a buggy response from the Dropbox server.
7
+ */
8
+ class Exception_BadResponse extends Exception_ProtocolError
9
+ {
10
+ /**
11
+ * @internal
12
+ */
13
+ function __construct($message)
14
+ {
15
+ parent::__construct($message);
16
+ }
17
+ }
com/lib/Dropbox/Exception/BadResponseCode.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown when the the Dropbox server responds with an HTTP status code we didn't expect.
6
+ */
7
+ final class Exception_BadResponseCode extends Exception_BadResponse
8
+ {
9
+ /** @var int */
10
+ private $statusCode;
11
+
12
+ /**
13
+ * @param string $message
14
+ * @param int $statusCode
15
+ *
16
+ * @internal
17
+ */
18
+ function __construct($message, $statusCode)
19
+ {
20
+ parent::__construct($message);
21
+ $this->statusCode = $statusCode;
22
+ }
23
+
24
+ /**
25
+ * The HTTP status code returned by the Dropbox server.
26
+ *
27
+ * @return int
28
+ */
29
+ public function getStatusCode()
30
+ {
31
+ return $this->statusCode;
32
+ }
33
+ }
com/lib/Dropbox/Exception/InvalidAccessToken.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * The Dropbox server said that the access token you used is invalid or expired. You should
6
+ * probably ask the user to go through the OAuth authorization flow again to get a new access
7
+ * token.
8
+ */
9
+ final class Exception_InvalidAccessToken extends Exception
10
+ {
11
+ /**
12
+ * @internal
13
+ */
14
+ function __construct($message = "")
15
+ {
16
+ parent::__construct($message);
17
+ }
18
+ }
com/lib/Dropbox/Exception/NetworkIO.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * There was a network I/O error when making the request.
6
+ */
7
+ final class Exception_NetworkIO extends Exception
8
+ {
9
+ /**
10
+ * @internal
11
+ */
12
+ function __construct($message, $cause = null)
13
+ {
14
+ parent::__construct($message, $cause);
15
+ }
16
+ }
com/lib/Dropbox/Exception/ProtocolError.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * There was an protocol misunderstanding between this SDK and the server. One of us didn't
6
+ * understand what the other one was saying.
7
+ */
8
+ class Exception_ProtocolError extends Exception
9
+ {
10
+ /**
11
+ * @internal
12
+ */
13
+ function __construct($message)
14
+ {
15
+ parent::__construct($message);
16
+ }
17
+ }
com/lib/Dropbox/Exception/RetryLater.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * The Dropbox server said it couldn't fulfil our request right now, but that we should try
6
+ * again later.
7
+ */
8
+ final class Exception_RetryLater extends Exception
9
+ {
10
+ /**
11
+ * @internal
12
+ */
13
+ function __construct($message)
14
+ {
15
+ parent::__construct($message);
16
+ }
17
+ }
com/lib/Dropbox/Exception/ServerError.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * The Dropbox server said that there was an internal error when trying to fulfil our request.
6
+ * This usually corresponds to an HTTP 500 response.
7
+ */
8
+ final class Exception_ServerError extends Exception
9
+ {
10
+ /** @internal */
11
+ function __construct($message = "")
12
+ {
13
+ parent::__construct($message);
14
+ }
15
+ }
com/lib/Dropbox/Host.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * The Dropbox web API accesses three hosts; this structure holds the
6
+ * names of those three hosts. This is primarily for mocking things out
7
+ * during testing. Most of the time you won't have to deal with this class
8
+ * directly, and even when you do, you'll just use the default
9
+ * value: {@link Host::getDefault()}.
10
+ *
11
+ * @internal
12
+ */
13
+ final class Host
14
+ {
15
+ /**
16
+ * Returns a Host object configured with the three standard Dropbox host: "api.dropbox.com",
17
+ * "api-content.dropbox.com", and "www.dropbox.com"
18
+ *
19
+ * @return Host
20
+ */
21
+ static function getDefault()
22
+ {
23
+ if (!self::$defaultValue) {
24
+ //self::$defaultValue = new Host("api.dropbox.com", "api-content.dropbox.com", "www.dropbox.com");
25
+ self::$defaultValue = new Host("api.dropboxapi.com", "content.dropboxapi.com", "www.dropbox.com");
26
+ }
27
+ return self::$defaultValue;
28
+ }
29
+ private static $defaultValue;
30
+
31
+ /** @var string */
32
+ private $api;
33
+ /** @var string */
34
+ private $content;
35
+ /** @var string */
36
+ private $web;
37
+
38
+ /**
39
+ * Constructor.
40
+ *
41
+ * @param string $api
42
+ * See {@link getApi()}
43
+ * @param string $content
44
+ * See {@link getContent()}
45
+ * @param string $web
46
+ * See {@link getWeb()}
47
+ */
48
+ function __construct($api, $content, $web)
49
+ {
50
+ $this->api = $api;
51
+ $this->content = $content;
52
+ $this->web = $web;
53
+ }
54
+
55
+ /**
56
+ * Returns the host name of the main Dropbox API server.
57
+ * The default is "api.dropbox.com".
58
+ *
59
+ * @return string
60
+ */
61
+ function getApi() { return $this->api; }
62
+
63
+ /**
64
+ * Returns the host name of the Dropbox API content server.
65
+ * The default is "api-content.dropbox.com".
66
+ *
67
+ * @return string
68
+ */
69
+ function getContent() { return $this->content; }
70
+
71
+ /**
72
+ * Returns the host name of the Dropbox web server. Used during user authorization.
73
+ * The default is "www.dropbox.com".
74
+ *
75
+ * @return string
76
+ */
77
+ function getWeb() { return $this->web; }
78
+
79
+ /**
80
+ * Check that a function argument is of type <code>Host</code>.
81
+ *
82
+ * @internal
83
+ */
84
+ static function checkArg($argName, $argValue)
85
+ {
86
+ if (!($argValue instanceof self)) Checker::throwError($argName, $argValue, __CLASS__);
87
+ }
88
+
89
+ /**
90
+ * Check that a function argument is either <code>null</code> or of type
91
+ * <code>Host</code>.
92
+ *
93
+ * @internal
94
+ */
95
+ static function checkArgOrNull($argName, $argValue)
96
+ {
97
+ if ($argValue === null) return;
98
+ if (!($argValue instanceof self)) Checker::throwError($argName, $argValue, __CLASS__);
99
+ }
100
+ }
com/lib/Dropbox/HttpResponse.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * @internal
6
+ */
7
+ final class HttpResponse
8
+ {
9
+ public $statusCode;
10
+ public $body;
11
+
12
+ function __construct($statusCode, $body)
13
+ {
14
+ $this->statusCode = $statusCode;
15
+ $this->body = $body;
16
+ }
17
+ }
com/lib/Dropbox/OAuth1AccessToken.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Use with {@link OAuth1Upgrader} to convert old OAuth 1 access tokens
6
+ * to OAuth 2 access tokens. This SDK doesn't support using OAuth 1
7
+ * access tokens for regular API calls.
8
+ */
9
+ class OAuth1AccessToken
10
+ {
11
+ /**
12
+ * The OAuth 1 access token key.
13
+ *
14
+ * @return string
15
+ */
16
+ function getKey() { return $this->key; }
17
+
18
+ /** @var string */
19
+ private $key;
20
+
21
+ /**
22
+ * The OAuth 1 access token secret.
23
+ *
24
+ * Make sure that this is kept a secret. Someone with your app secret can impesonate your
25
+ * application. People sometimes ask for help on the Dropbox API forums and
26
+ * copy/paste code that includes their app secret. Do not do that.
27
+ *
28
+ * @return string
29
+ */
30
+ function getSecret() { return $this->secret; }
31
+
32
+ /** @var secret */
33
+ private $secret;
34
+
35
+ /**
36
+ * Constructor.
37
+ *
38
+ * @param string $key
39
+ * {@link getKey()}
40
+ * @param string $secret
41
+ * {@link getSecret()}
42
+ */
43
+ function __construct($key, $secret)
44
+ {
45
+ AppInfo::checkKeyArg($key);
46
+ AppInfo::checkSecretArg($secret);
47
+
48
+ $this->key = $key;
49
+ $this->secret = $secret;
50
+ }
51
+
52
+ /**
53
+ * Use this to check that a function argument is of type <code>AppInfo</code>
54
+ *
55
+ * @internal
56
+ */
57
+ static function checkArg($argName, $argValue)
58
+ {
59
+ if (!($argValue instanceof self)) Checker::throwError($argName, $argValue, __CLASS__);
60
+ }
61
+ }
com/lib/Dropbox/OAuth1Upgrader.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Lets you convert OAuth 1 access tokens to OAuth 2 access tokens. First call {@link
6
+ * OAuth1AccessTokenUpgrader::createOAuth2AccessToken()} to get an OAuth 2 access token.
7
+ * If that succeeds, call {@link OAuth1AccessTokenUpgrader::disableOAuth1AccessToken()}
8
+ * to disable the OAuth 1 access token.
9
+ *
10
+ * <code>
11
+ * use \Dropbox as dbx;
12
+ * $appInfo = dbx\AppInfo::loadFromJsonFile(...);
13
+ * $clientIdentifier = "my-app/1.0";
14
+ * $oauth1AccessToken = dbx\OAuth1AccessToken(...);
15
+ *
16
+ * $upgrader = new dbx\OAuth1AccessTokenUpgrader($appInfo, $clientIdentifier, ...);
17
+ * $oauth2AccessToken = $upgrader->getOAuth2AccessToken($oauth1AccessToken);
18
+ * $upgrader->disableOAuth1AccessToken($oauth1AccessToken);
19
+ * </code>
20
+ */
21
+ class OAuth1Upgrader extends AuthBase
22
+ {
23
+ /**
24
+ * Given an existing active OAuth 1 access token, make a Dropbox API call to get a new OAuth 2
25
+ * access token that represents the same user and app.
26
+ *
27
+ * See <a href="https://www.dropbox.com/developers/core/docs#oa1-from-oa1">/oauth2/token_from_oauth1</a>.
28
+ *
29
+ * @param OAuth1AccessToken $oauth1AccessToken
30
+ *
31
+ * @return string
32
+ * The OAuth 2 access token.
33
+ *
34
+ * @throws Exception
35
+ */
36
+ // function createOAuth2AccessToken($oauth1AccessToken)
37
+ // {
38
+ // OAuth1AccessToken::checkArg("oauth1AccessToken", $oauth1AccessToken);
39
+
40
+ // $response = self::doPost($oauth1AccessToken, "1/oauth2/token_from_oauth1");
41
+
42
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
43
+
44
+ // $parts = RequestUtil::parseResponseJson($response->body);
45
+
46
+ // if (!array_key_exists('token_type', $parts) || !is_string($parts['token_type'])) {
47
+ // throw new Exception_BadResponse("Missing \"token_type\" field.");
48
+ // }
49
+ // $tokenType = $parts['token_type'];
50
+ // if (!array_key_exists('access_token', $parts) || !is_string($parts['access_token'])) {
51
+ // throw new Exception_BadResponse("Missing \"access_token\" field.");
52
+ // }
53
+ // $accessToken = $parts['access_token'];
54
+
55
+ // if ($tokenType !== "Bearer" && $tokenType !== "bearer") {
56
+ // throw new Exception_BadResponse("Unknown \"token_type\"; expecting \"Bearer\", got "
57
+ // . Util::q($tokenType));
58
+ // }
59
+
60
+ // return $accessToken;
61
+ // }
62
+
63
+ /*Dropbox api 2*/
64
+ function createOAuth2AccessToken($oauth1AccessToken)
65
+ {
66
+ OAuth1AccessToken::checkArg("oauth1AccessToken", $oauth1AccessToken);
67
+
68
+ $response = self::doPost($oauth1AccessToken, "2/auth/token/from_oauth1");
69
+
70
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
71
+
72
+ $parts = RequestUtil::parseResponseJson($response->body);
73
+
74
+ if (!array_key_exists('token_type', $parts) || !is_string($parts['token_type'])) {
75
+ throw new Exception_BadResponse("Missing \"token_type\" field.");
76
+ }
77
+ $tokenType = $parts['token_type'];
78
+ if (!array_key_exists('access_token', $parts) || !is_string($parts['access_token'])) {
79
+ throw new Exception_BadResponse("Missing \"access_token\" field.");
80
+ }
81
+ $accessToken = $parts['access_token'];
82
+
83
+ if ($tokenType !== "Bearer" && $tokenType !== "bearer") {
84
+ throw new Exception_BadResponse("Unknown \"token_type\"; expecting \"Bearer\", got "
85
+ . Util::q($tokenType));
86
+ }
87
+
88
+ return $accessToken;
89
+ }
90
+
91
+ /**
92
+ * Make a Dropbox API call to disable the given OAuth 1 access token.
93
+ *
94
+ * See <a href="https://www.dropbox.com/developers/core/docs#disable-token">/disable_access_token</a>.
95
+ *
96
+ * @param OAuth1AccessToken $oauth1AccessToken
97
+ *
98
+ * @throws Exception
99
+ */
100
+ // function disableOAuth1AccessToken($oauth1AccessToken)
101
+ // {
102
+ // OAuth1AccessToken::checkArg("oauth1AccessToken", $oauth1AccessToken);
103
+
104
+ // $response = self::doPost($oauth1AccessToken, "1/disable_access_token");
105
+
106
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
107
+ // }
108
+
109
+ /*Dropbox api 2*/
110
+ function disableOAuth1AccessToken($oauth1AccessToken)
111
+ {
112
+ OAuth1AccessToken::checkArg("oauth1AccessToken", $oauth1AccessToken);
113
+
114
+ $response = self::doPost($oauth1AccessToken, "2/auth/token/revoke");
115
+
116
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
117
+ }
118
+
119
+ /**
120
+ * @param OAuth1AccessToken $oauth1AccessToken
121
+ * @param string $path
122
+ *
123
+ * @return HttpResponse
124
+ *
125
+ * @throws Exception
126
+ */
127
+ private function doPost($oauth1AccessToken, $path)
128
+ {
129
+ // Construct the OAuth 1 header.
130
+ $signature = rawurlencode($this->appInfo->getSecret()) . "&" . rawurlencode($oauth1AccessToken->getSecret());
131
+ $authHeaderValue = "OAuth oauth_signature_method=\"PLAINTEXT\""
132
+ . ", oauth_consumer_key=\"" . rawurlencode($this->appInfo->getKey()) . "\""
133
+ . ", oauth_token=\"" . rawurlencode($oauth1AccessToken->getKey()) . "\""
134
+ . ", oauth_signature=\"" . $signature . "\"";
135
+
136
+ return RequestUtil::doPostWithSpecificAuth(
137
+ $this->clientIdentifier, $authHeaderValue, $this->userLocale,
138
+ $this->appInfo->getHost()->getApi(),
139
+ $path,
140
+ null);
141
+ }
142
+ }
com/lib/Dropbox/Path.php ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Path validation functions.
6
+ */
7
+ final class Path
8
+ {
9
+ /**
10
+ * Return whether the given path is a valid Dropbox path.
11
+ *
12
+ * @param string $path
13
+ * The path you want to check for validity.
14
+ *
15
+ * @return bool
16
+ * Whether the path was valid or not.
17
+ */
18
+ static function isValid($path)
19
+ {
20
+ $error = self::findError($path);
21
+ return ($error === null);
22
+ }
23
+
24
+ /**
25
+ * Return whether the given path is a valid non-root Dropbox path.
26
+ * This is the same as {@link isValid} except <code>"/"</code> is not allowed.
27
+ *
28
+ * @param string $path
29
+ * The path you want to check for validity.
30
+ *
31
+ * @return bool
32
+ * Whether the path was valid or not.
33
+ */
34
+ static function isValidNonRoot($path)
35
+ {
36
+ $error = self::findErrorNonRoot($path);
37
+ return ($error === null);
38
+ }
39
+
40
+ /**
41
+ * If the given path is a valid Dropbox path, return <code>null</code>,
42
+ * otherwise return an English string error message describing what is wrong with the path.
43
+ *
44
+ * @param string $path
45
+ * The path you want to check for validity.
46
+ *
47
+ * @return string|null
48
+ * If the path was valid, return <code>null</code>. Otherwise, returns
49
+ * an English string describing the problem.
50
+ */
51
+ static function findError($path)
52
+ {
53
+ Checker::argString("path", $path);
54
+
55
+ $matchResult = preg_match('%^(?:
56
+ [\x09\x0A\x0D\x20-\x7E] # ASCII
57
+ | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
58
+ | \xE0[\xA0-\xBF][\x80-\xBD] # excluding overlongs, FFFE, and FFFF
59
+ | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
60
+ | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
61
+ )*$%xs', $path);
62
+
63
+ if ($matchResult !== 1) {
64
+ return "must be valid UTF-8; BMP only, no surrogates, no U+FFFE or U+FFFF";
65
+ }
66
+
67
+ if (\substr_compare($path, "/", 0, 1) !== 0) return "must start with \"/\"";
68
+ $l = strlen($path);
69
+ if ($l === 1) return null; // Special case for "/"
70
+
71
+ if ($path[$l-1] === "/") return "must not end with \"/\"";
72
+
73
+ // TODO: More checks.
74
+
75
+ return null;
76
+ }
77
+
78
+ /**
79
+ * If the given path is a valid non-root Dropbox path, return <code>null</code>,
80
+ * otherwise return an English string error message describing what is wrong with the path.
81
+ * This is the same as {@link findError} except <code>"/"</code> will yield an error message.
82
+ *
83
+ * @param string $path
84
+ * The path you want to check for validity.
85
+ *
86
+ * @return string|null
87
+ * If the path was valid, return <code>null</code>. Otherwise, returns
88
+ * an English string describing the problem.
89
+ */
90
+ static function findErrorNonRoot($path)
91
+ {
92
+ if ($path == "/") return "root path not allowed";
93
+ return self::findError($path);
94
+ }
95
+
96
+ /**
97
+ * Return the last component of a path (the file or folder name).
98
+ *
99
+ * <code>
100
+ * Path::getName("/Misc/Notes.txt") // "Notes.txt"
101
+ * Path::getName("/Misc") // "Misc"
102
+ * Path::getName("/") // null
103
+ * </code>
104
+ *
105
+ * @param string $path
106
+ * The full path you want to get the last component of.
107
+ *
108
+ * @return null|string
109
+ * The last component of <code>$path</code> or <code>null</code> if the given
110
+ * <code>$path</code> was <code>"/"<code>.
111
+ */
112
+ static function getName($path)
113
+ {
114
+ Checker::argString("path", $path);
115
+
116
+ if (\substr_compare($path, "/", 0, 1) !== 0) {
117
+ throw new \InvalidArgumentException("'path' must start with \"/\"");
118
+ }
119
+ $l = strlen($path);
120
+ if ($l === 1) return null;
121
+ if ($path[$l-1] === "/") {
122
+ throw new \InvalidArgumentException("'path' must not end with \"/\"");
123
+ }
124
+
125
+ $lastSlash = strrpos($path, "/");
126
+ return substr($path, $lastSlash+1);
127
+ }
128
+
129
+ /**
130
+ * @internal
131
+ *
132
+ * @param string $argName
133
+ * @param mixed $value
134
+ * @throws \InvalidArgumentException
135
+ */
136
+ static function checkArg($argName, $value)
137
+ {
138
+ if ($value === null) throw new \InvalidArgumentException("'$argName' must not be null");
139
+ if (!is_string($value)) throw new \InvalidArgumentException("'$argName' must be a string");
140
+ $error = self::findError($value);
141
+ if ($error !== null) throw new \InvalidArgumentException("'$argName'': bad path: $error: ".var_export($value, true));
142
+ }
143
+
144
+ /**
145
+ * @internal
146
+ *
147
+ * @param string $argName
148
+ * @param mixed $value
149
+ * @throws \InvalidArgumentException
150
+ */
151
+ static function checkArgOrNull($argName, $value)
152
+ {
153
+ if ($value === null) return;
154
+ self::checkArg($argName, $value);
155
+ }
156
+
157
+ /**
158
+ * @internal
159
+ *
160
+ * @param string $argName
161
+ * @param mixed $value
162
+ * @throws \InvalidArgumentException
163
+ */
164
+ static function checkArgNonRoot($argName, $value)
165
+ {
166
+ if ($value === null) throw new \InvalidArgumentException("'$argName' must not be null");
167
+ if (!is_string($value)) throw new \InvalidArgumentException("'$argName' must be a string");
168
+ $error = self::findErrorNonRoot($value);
169
+ if ($error !== null) throw new \InvalidArgumentException("'$argName'': bad path: $error: ".var_export($value, true));
170
+ }
171
+ }
com/lib/Dropbox/RequestUtil.php ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ if (!function_exists('curl_init')) {
5
+ throw new \Exception("The Dropbox SDK requires the cURL PHP extension, but it looks like you don't have it (couldn't find function \"curl_init\"). Library: \"" . __FILE__ . "\".");
6
+ }
7
+
8
+ if (!function_exists('json_decode')) {
9
+ throw new \Exception("The Dropbox SDK requires the JSON PHP extension, but it looks like you don't have it (couldn't find function \"json_decode\"). Library: \"" . __FILE__ . "\".");
10
+ }
11
+
12
+ // If mbstring.func_overload is set, it changes the behavior of the standard string functions in
13
+ // ways that makes this library break.
14
+ $mbstring_func_overload = ini_get("mbstring.func_overload");
15
+ if ($mbstring_func_overload & 2 == 2) {
16
+ throw new \Exception("The Dropbox SDK doesn't work when mbstring.func_overload is set to overload the standard string functions (value = ".var_export($mbstring_func_overload, true)."). Library: \"" . __FILE__ . "\".");
17
+ }
18
+
19
+ if (strlen((string) PHP_INT_MAX) < 19) {
20
+ // Looks like we're running on a 32-bit build of PHP. This could cause problems because some of the numbers
21
+ // we use (file sizes, quota, etc) can be larger than 32-bit ints can handle.
22
+ throw new \Exception("The Dropbox SDK uses 64-bit integers, but it looks like we're running on a version of PHP that doesn't support 64-bit integers (PHP_INT_MAX=" . ((string) PHP_INT_MAX) . "). Library: \"" . __FILE__ . "\"");
23
+ }
24
+
25
+ /**
26
+ * @internal
27
+ */
28
+ final class RequestUtil
29
+ {
30
+ /**
31
+ * @param string $userLocale
32
+ * @param string $host
33
+ * @param string $path
34
+ * @param array $params
35
+ * @return string
36
+ */
37
+ // static function buildUrlForGetOrPut($userLocale, $host, $path, $params = null)
38
+ // {
39
+ // $url = self::buildUri($host, $path);
40
+ // $url .= "?locale=" . rawurlencode($userLocale);
41
+
42
+ // if ($params !== null) {
43
+ // foreach ($params as $key => $value) {
44
+ // Checker::argStringNonEmpty("key in 'params'", $key);
45
+ // if ($value !== null) {
46
+ // if (is_bool($value)) {
47
+ // $value = $value ? "true" : "false";
48
+ // }
49
+ // else if (is_int($value)) {
50
+ // $value = (string) $value;
51
+ // }
52
+ // else if (!is_string($value)) {
53
+ // throw new \InvalidArgumentException("params['$key'] is not a string, int, or bool");
54
+ // }
55
+ // $url .= "&" . rawurlencode($key) . "=" . rawurlencode($value);
56
+ // }
57
+ // }
58
+ // }
59
+ // return $url;
60
+ // }
61
+
62
+ /*Dropbox api 2*/
63
+ static function buildUrlForGetOrPut($userLocale, $host, $path, $params = null)
64
+ {
65
+ $url = self::buildUri($host, $path);
66
+
67
+ if ($params !== null) {
68
+ $url .= "?";
69
+ foreach ($params as $key => $value) {
70
+ Checker::argStringNonEmpty("key in 'params'", $key);
71
+ if ($value !== null) {
72
+ if (is_bool($value)) {
73
+ $value = $value ? "true" : "false";
74
+ }
75
+ else if (is_int($value)) {
76
+ $value = (string) $value;
77
+ }
78
+ else if (!is_string($value)) {
79
+ throw new \InvalidArgumentException("params['$key'] is not a string, int, or bool");
80
+ }
81
+ $url .= "&" . rawurlencode($key) . "=" . rawurlencode($value);
82
+ }
83
+ }
84
+ }
85
+ return $url;
86
+ }
87
+
88
+ /**
89
+ * @param string $host
90
+ * @param string $path
91
+ * @return string
92
+ */
93
+ static function buildUri($host, $path)
94
+ {
95
+ Checker::argStringNonEmpty("host", $host);
96
+ Checker::argStringNonEmpty("path", $path);
97
+ return "https://" . $host . "/" . $path;
98
+ }
99
+
100
+ /**
101
+ * @param string $clientIdentifier
102
+ * @param string $url
103
+ * @return Curl
104
+ */
105
+ static function mkCurl($clientIdentifier, $url)
106
+ {
107
+ $curl = new Curl($url);
108
+
109
+ $curl->set(CURLOPT_CONNECTTIMEOUT, 10);
110
+
111
+ // If the transfer speed is below 1kB/sec for 10 sec, abort.
112
+ $curl->set(CURLOPT_LOW_SPEED_LIMIT, 0);
113
+ $curl->set(CURLOPT_LOW_SPEED_TIME, 0);
114
+
115
+ //$curl->set(CURLOPT_VERBOSE, true); // For debugging.
116
+ // TODO: Figure out how to encode clientIdentifier (urlencode?)
117
+ $curl->addHeader("User-Agent: ".$clientIdentifier." Dropbox-PHP-SDK");
118
+
119
+ return $curl;
120
+ }
121
+
122
+ /**
123
+ * @param string $clientIdentifier
124
+ * @param string $url
125
+ * @param string $authHeaderValue
126
+ * @return Curl
127
+ */
128
+ static function mkCurlWithAuth($clientIdentifier, $url, $authHeaderValue)
129
+ {
130
+ $curl = self::mkCurl($clientIdentifier, $url);
131
+ $curl->addHeader("Authorization: $authHeaderValue");
132
+ return $curl;
133
+ }
134
+
135
+ /**
136
+ * @param string $clientIdentifier
137
+ * @param string $url
138
+ * @param string $accessToken
139
+ * @return Curl
140
+ */
141
+ static function mkCurlWithOAuth($clientIdentifier, $url, $accessToken)
142
+ {
143
+ return self::mkCurlWithAuth($clientIdentifier, $url, "Bearer $accessToken");
144
+ }
145
+
146
+ static function buildPostBody($params)
147
+ {
148
+ if ($params === null) return "";
149
+
150
+ $pairs = array();
151
+ foreach ($params as $key => $value) {
152
+ Checker::argStringNonEmpty("key in 'params'", $key);
153
+ if ($value !== null) {
154
+ if (is_bool($value)) {
155
+ $value = $value ? "true" : "false";
156
+ }
157
+ else if (is_int($value)) {
158
+ $value = (string) $value;
159
+ }
160
+ else if (!is_string($value)) {
161
+ throw new \InvalidArgumentException("params['$key'] is not a string, int, or bool");
162
+ }
163
+ $pairs[] = rawurlencode($key) . "=" . rawurlencode((string) $value);
164
+ }
165
+ }
166
+ return implode("&", $pairs);
167
+ }
168
+
169
+ /**
170
+ * @param string $clientIdentifier
171
+ * @param string $accessToken
172
+ * @param string $userLocale
173
+ * @param string $host
174
+ * @param string $path
175
+ * @param array|null $params
176
+ *
177
+ * @return HttpResponse
178
+ *
179
+ * @throws Exception
180
+ */
181
+ // static function doPost($clientIdentifier, $accessToken, $userLocale, $host, $path, $params = null)
182
+ // {
183
+ // Checker::argStringNonEmpty("accessToken", $accessToken);
184
+
185
+ // $url = self::buildUri($host, $path);
186
+
187
+ // if ($params === null) $params = array();
188
+ // $params['locale'] = $userLocale;
189
+
190
+ // $curl = self::mkCurlWithOAuth($clientIdentifier, $url, $accessToken);
191
+ // $curl->set(CURLOPT_POST, true);
192
+ // $curl->set(CURLOPT_POSTFIELDS, self::buildPostBody($params));
193
+
194
+ // $curl->set(CURLOPT_RETURNTRANSFER, true);
195
+
196
+ // return $curl->exec();
197
+ // }
198
+
199
+ /*Dropbox api 2*/
200
+ static function doPost($clientIdentifier, $accessToken, $userLocale, $host, $path, $params = null, $headers = null)
201
+ {
202
+ Checker::argStringNonEmpty("accessToken", $accessToken);
203
+
204
+ $url = self::buildUri($host, $path);
205
+
206
+ $curl = self::mkCurlWithOAuth($clientIdentifier, $url, $accessToken);
207
+ $curl->set(CURLOPT_POST, true);
208
+ $curl->set(CURLOPT_POSTFIELDS, json_encode($params));
209
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
210
+
211
+ if ($headers) {
212
+ $curl->addHeader($headers);
213
+ }
214
+
215
+ return $curl->exec();
216
+ }
217
+
218
+ /**
219
+ * @param string $clientIdentifier
220
+ * @param string $authHeaderValue
221
+ * @param string $userLocale
222
+ * @param string $host
223
+ * @param string $path
224
+ * @param array|null $params
225
+ *
226
+ * @return HttpResponse
227
+ *
228
+ * @throws Exception
229
+ */
230
+ static function doPostWithSpecificAuth($clientIdentifier, $authHeaderValue, $userLocale, $host, $path, $params = null)
231
+ {
232
+ Checker::argStringNonEmpty("authHeaderValue", $authHeaderValue);
233
+
234
+ $url = self::buildUri($host, $path);
235
+
236
+ if ($params === null) $params = array();
237
+ $params['locale'] = $userLocale;
238
+
239
+ $curl = self::mkCurlWithAuth($clientIdentifier, $url, $authHeaderValue);
240
+ $curl->set(CURLOPT_POST, true);
241
+ $curl->set(CURLOPT_POSTFIELDS, self::buildPostBody($params));
242
+
243
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
244
+ return $curl->exec();
245
+ }
246
+
247
+ /**
248
+ * @param string $clientIdentifier
249
+ * @param string $accessToken
250
+ * @param string $userLocale
251
+ * @param string $host
252
+ * @param string $path
253
+ * @param array|null $params
254
+ *
255
+ * @return HttpResponse
256
+ *
257
+ * @throws Exception
258
+ */
259
+ static function doGet($clientIdentifier, $accessToken, $userLocale, $host, $path, $params = null)
260
+ {
261
+ Checker::argStringNonEmpty("accessToken", $accessToken);
262
+
263
+ $url = self::buildUrlForGetOrPut($userLocale, $host, $path, $params);
264
+
265
+ $curl = self::mkCurlWithOAuth($clientIdentifier, $url, $accessToken);
266
+ $curl->set(CURLOPT_HTTPGET, true);
267
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
268
+
269
+ return $curl->exec();
270
+ }
271
+
272
+ /**
273
+ * @param string $responseBody
274
+ * @return mixed
275
+ * @throws Exception_BadResponse
276
+ */
277
+ static function parseResponseJson($responseBody)
278
+ {
279
+ $obj = json_decode($responseBody, true, 10);
280
+ if ($obj === null) {
281
+ throw new Exception_BadResponse("Got bad JSON from server: $responseBody");
282
+ }
283
+ return $obj;
284
+ }
285
+
286
+ static function unexpectedStatus($httpResponse)
287
+ {
288
+ $sc = $httpResponse->statusCode;
289
+
290
+ $message = "HTTP status $sc";
291
+ if (is_string($httpResponse->body)) {
292
+ // TODO: Maybe only include the first ~200 chars of the body?
293
+ $message .= "\n".$httpResponse->body;
294
+ }
295
+
296
+ if ($sc === 400) return new Exception_BadRequest($message);
297
+ if ($sc === 401) return new Exception_InvalidAccessToken($message);
298
+ if ($sc === 500 || $sc === 502) return new Exception_ServerError($message);
299
+ if ($sc === 503) return new Exception_RetryLater($message);
300
+
301
+ return new Exception_BadResponseCode("Unexpected $message", $sc);
302
+ }
303
+
304
+ /**
305
+ * @param int $maxRetries
306
+ * The number of times to retry it the action if it fails with one of the transient
307
+ * API errors. A value of 1 means we'll try the action once and if it fails, we
308
+ * will retry once.
309
+ *
310
+ * @param callable $action
311
+ * The the action you want to retry.
312
+ *
313
+ * @return mixed
314
+ * Whatever is returned by the $action callable.
315
+ */
316
+ static function runWithRetry($maxRetries, $action)
317
+ {
318
+ Checker::argNat("maxRetries", $maxRetries);
319
+
320
+ $retryDelay = 1;
321
+ $numRetries = 0;
322
+ while (true) {
323
+ try {
324
+ return $action();
325
+ }
326
+ // These exception types are the ones we think are possibly transient errors.
327
+ catch (Exception_NetworkIO $ex) {
328
+ $savedEx = $ex;
329
+ }
330
+ catch (Exception_ServerError $ex) {
331
+ $savedEx = $ex;
332
+ }
333
+ catch (Exception_RetryLater $ex) {
334
+ $savedEx = $ex;
335
+ }
336
+
337
+ // We maxed out our retries. Propagate the last exception we got.
338
+ if ($numRetries >= $maxRetries) throw $savedEx;
339
+
340
+ $numRetries++;
341
+ sleep($retryDelay);
342
+ $retryDelay *= 2; // Exponential back-off.
343
+ }
344
+ throw new \RuntimeException("unreachable");
345
+ }
346
+
347
+ }
com/lib/Dropbox/RootCertificates.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * See: {@link RootCertificates::useExternalPaths()}
6
+ */
7
+ class RootCertificates
8
+ {
9
+ /* @var boolean */
10
+ private static $useExternalFile = false;
11
+
12
+ /* @var string[]|null */
13
+ private static $paths = null; // A tuple of (rootCertsFilePath, rootCertsFolderPath)
14
+
15
+ /**
16
+ * If you're running within a PHAR, call this method before you use the SDK
17
+ * to make any network requests.
18
+ *
19
+ * Normally, the SDK tells cURL to look in the "certs" folder for root certificate
20
+ * information. But this won't work if this SDK is running from within a PHAR because
21
+ * cURL won't read files that are packaged in a PHAR.
22
+ */
23
+ static function useExternalPaths()
24
+ {
25
+ if (!self::$useExternalFile and self::$paths !== null) {
26
+ throw new \Exception("You called \"useExternalFile\" too late. The SDK already used the root ".
27
+ "certificate file (probably to make an API call).");
28
+ }
29
+
30
+ self::$useExternalFile = true;
31
+ }
32
+
33
+ private static $originalPath = '/certs/trusted-certs.crt';
34
+
35
+ /**
36
+ * @internal
37
+ *
38
+ * @return string[]
39
+ * A tuple of (rootCertsFilePath, rootCertsFolderPath). To be used with cURL options CAINFO and CAPATH.
40
+ */
41
+ static function getPaths()
42
+ {
43
+ if (self::$paths === null) {
44
+ if (self::$useExternalFile) {
45
+ try {
46
+ $baseFolder = sys_get_temp_dir();
47
+ $file = self::createExternalCaFile($baseFolder);
48
+ $folder = self::createExternalCaFolder($baseFolder);
49
+ }
50
+ catch (\Exception $ex) {
51
+ throw new \Exception("Unable to create external root certificate file and folder: ".$ex->getMessage());
52
+ }
53
+ }
54
+ else {
55
+ if (substr(__DIR__, 0, 7) === 'phar://') {
56
+ throw new \Exception("The code appears to be running in a PHAR. You need to call \\Dropbox\\RootCertificates\\useExternalPaths() before making any API calls.");
57
+ }
58
+ $file = __DIR__.self::$originalPath;
59
+ $folder = \dirname($file);
60
+ }
61
+ self::$paths = array($file, $folder);
62
+ }
63
+
64
+ return self::$paths;
65
+ }
66
+
67
+ /**
68
+ * @param string $baseFolder
69
+ *
70
+ * @return string
71
+ */
72
+ private static function createExternalCaFolder($baseFolder)
73
+ {
74
+ // This is hacky, but I can't find a simple way to do this.
75
+
76
+ // This process isn't atomic, so give it three tries.
77
+ for ($i = 0; $i < 3; $i++) {
78
+ $path = \tempnam($baseFolder, "dropbox-php-sdk-trusted-certs-empty-dir");
79
+ if ($path === false) {
80
+ throw new \Exception("Couldn't create temp file in folder ".Util::q($baseFolder).".");
81
+ }
82
+ if (!\unlink($path)) {
83
+ throw new \Exception("Couldn't remove temp file to make way for temp dir: ".Util::q($path));
84
+ }
85
+ // TODO: Figure out how to make the folder private on Windows. The '700' only works on Unix.
86
+ if (!\mkdir($path, 700)) {
87
+ // Someone snuck in between the unlink() and the mkdir() and stole our path.
88
+ throw new \Exception("Couldn't create temp dir: ".Util::q($path));
89
+ }
90
+ \register_shutdown_function(function() use ($path) {
91
+ \rmdir($path);
92
+ });
93
+ return $path;
94
+ }
95
+
96
+ throw new \Exception("Unable to create temp dir in ".Util::q($baseFolder).", there's always something in the way.");
97
+ }
98
+
99
+ /**
100
+ * @param string $baseFolder
101
+ *
102
+ * @return string
103
+ */
104
+ private static function createExternalCaFile($baseFolder)
105
+ {
106
+ $path = \tempnam($baseFolder, "dropbox-php-sdk-trusted-certs");
107
+ if ($path === false) {
108
+ throw new \Exception("Couldn't create temp file in folder ".Util::q($baseFolder).".");
109
+ }
110
+ \register_shutdown_function(function() use ($path) {
111
+ \unlink($path);
112
+ });
113
+
114
+ // NOTE: Can't use the standard PHP copy(). That would clobber the locked-down
115
+ // permissions set by tempnam().
116
+ self::copyInto(__DIR__.self::$originalPath, $path);
117
+
118
+ return $path;
119
+ }
120
+
121
+ /**
122
+ * @param string $src
123
+ * @param string $dest
124
+ */
125
+ private static function copyInto($src, $dest)
126
+ {
127
+ $srcFd = \fopen($src, "r");
128
+ if ($srcFd === false) {
129
+ throw new \Exception("Couldn't open " . Util::q($src) . " for reading.");
130
+ }
131
+ $destFd = \fopen($dest, "w");
132
+ if ($destFd === false) {
133
+ \fclose($srcFd);
134
+ throw new \Exception("Couldn't open " . Util::q($dest) . " for writing.");
135
+ }
136
+
137
+ \stream_copy_to_stream($srcFd, $destFd);
138
+
139
+ fclose($srcFd);
140
+ if (!\fclose($destFd)) {
141
+ throw new \Exception("Error closing file ".Util::q($dest).".");
142
+ }
143
+ }
144
+ }
com/lib/Dropbox/SSLTester.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Dropbox;
4
+
5
+ /**
6
+ * Call the <code>test()</code> method.
7
+ */
8
+ class SSLTester
9
+ {
10
+ /**
11
+ * Peforms a few basic tests of your PHP installation's SSL implementation to see
12
+ * if it insecure in an obvious way. Results are written with "echo" and the output
13
+ * is HTML-safe.
14
+ *
15
+ * @return bool
16
+ * Returns <code>true</code> if all the tests passed.
17
+ */
18
+ static function test()
19
+ {
20
+ $hostOs = php_uname('s').' '.php_uname('r');
21
+ $phpVersion = phpversion();
22
+ $curlVersionInfo = \curl_version();
23
+ $curlVersion = $curlVersionInfo['version'];
24
+ $curlSslBackend = $curlVersionInfo['ssl_version'];
25
+
26
+ echo "-----------------------------------------------------------------------------\n";
27
+ echo "Testing your PHP installation's SSL implementation for a few obvious problems...\n";
28
+ echo "-----------------------------------------------------------------------------\n";
29
+ echo "- Host OS: $hostOs\n";
30
+ echo "- PHP version: $phpVersion\n";
31
+ echo "- cURL version: $curlVersion\n";
32
+ echo "- cURL SSL backend: $curlSslBackend\n";
33
+
34
+ echo "Basic SSL tests\n";
35
+ $basicFailures = self::testMulti(array(
36
+ array("www.dropbox.com", 'testAllowed'),
37
+ array("www.digicert.com", 'testAllowed'),
38
+ array("www.v.dropbox.com", 'testHostnameMismatch'),
39
+ array("testssl-expire.disig.sk", 'testUntrustedCert'),
40
+ ));
41
+
42
+ echo "Pinned certificate tests\n";
43
+ $pinnedCertFailures = self::testMulti(array(
44
+ array("www.verisign.com", 'testUntrustedCert'),
45
+ array("www.globalsign.fr", 'testUntrustedCert'),
46
+ ));
47
+
48
+ if ($basicFailures) {
49
+ echo "-----------------------------------------------------------------------------\n";
50
+ echo "WARNING: Your PHP installation's SSL support is COMPLETELY INSECURE.\n";
51
+ echo "Your app's communication with the Dropbox API servers can be viewed and\n";
52
+ echo "manipulated by others. Try upgrading your version of PHP.\n";
53
+ echo "-----------------------------------------------------------------------------\n";
54
+ return false;
55
+ }
56
+ else if ($pinnedCertFailures) {
57
+ echo "-----------------------------------------------------------------------------\n";
58
+ echo "WARNING: Your PHP installation's cURL module doesn't support SSL certificate\n";
59
+ echo "pinning, which is an important security feature of the Dropbox SDK.\n";
60
+ echo "\n";
61
+ echo "This SDK uses CURLOPT_CAINFO and CURLOPT_CAPATH to tell PHP cURL to only trust\n";
62
+ echo "our custom certificate list. But your PHP installation's cURL module seems to\n";
63
+ echo "trust certificates that aren't on that list.\n";
64
+ echo "\n";
65
+ echo "More information on SSL certificate pinning:\n";
66
+ echo "https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#What_Is_Pinning.3F\n";
67
+ echo "-----------------------------------------------------------------------------\n";
68
+ return false;
69
+ }
70
+ else {
71
+ return true;
72
+ }
73
+ }
74
+
75
+ private static function testMulti($tests)
76
+ {
77
+ $anyFailed = false;
78
+ foreach ($tests as $test) {
79
+ list($host, $testType) = $test;
80
+
81
+ echo " - ".str_pad("$testType ($host) ", 50, ".");
82
+ $url = "https://$host/";
83
+ $passed = self::$testType($url);
84
+ if ($passed) {
85
+ echo " ok\n";
86
+ } else {
87
+ echo " FAILED\n";
88
+ $anyFailed = true;
89
+ }
90
+ }
91
+ return $anyFailed;
92
+ }
93
+
94
+ private static function testAllowed($url)
95
+ {
96
+ $curl = RequestUtil::mkCurl("test-ssl", $url);
97
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
98
+ $curl->exec();
99
+ return true;
100
+ }
101
+
102
+ private static function testUntrustedCert($url)
103
+ {
104
+ return self::testDisallowed($url, 'Error executing HTTP request: SSL certificate problem, verify that the CA cert is OK');
105
+ }
106
+
107
+ private static function testHostnameMismatch($url)
108
+ {
109
+ return self::testDisallowed($url, 'Error executing HTTP request: SSL certificate problem: Invalid certificate chain');
110
+ }
111
+
112
+ private static function testDisallowed($url, $expectedExceptionMessage)
113
+ {
114
+ $curl = RequestUtil::mkCurl("test-ssl", $url);
115
+ $curl->set(CURLOPT_RETURNTRANSFER, true);
116
+ try {
117
+ $curl->exec();
118
+ }
119
+ catch (Exception_NetworkIO $ex) {
120
+ if (strpos($ex->getMessage(), $expectedExceptionMessage) == 0) {
121
+ return true;
122
+ } else {
123
+ throw $ex;
124
+ }
125
+ }
126
+ return false;
127
+ }
128
+ }
com/lib/Dropbox/Security.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Helper functions for security-related things.
6
+ */
7
+ class Security
8
+ {
9
+ /**
10
+ * A string equality function that compares strings in a way that isn't suceptible to timing
11
+ * attacks. An attacker can figure out the length of the string, but not the string's value.
12
+ *
13
+ * Use this when comparing two strings where:
14
+ * - one string could be influenced by an attacker
15
+ * - the other string contains data an attacker shouldn't know
16
+ *
17
+ * @param string $a
18
+ * @param string $b
19
+ * @return bool
20
+ */
21
+ static function stringEquals($a, $b)
22
+ {
23
+ // Be strict with arguments. PHP's liberal types could get us pwned.
24
+ if (func_num_args() !== 2) {
25
+ throw new \InvalidArgumentException("Expecting 2 args, got ".func_num_args().".");
26
+ }
27
+ Checker::argString("a", $a);
28
+ Checker::argString("b", $b);
29
+
30
+ $len = strlen($a);
31
+ if (strlen($b) !== $len) return false;
32
+
33
+ $result = 0;
34
+ for ($i = 0; $i < $len; $i++) {
35
+ $result |= ord($a[$i]) ^ ord($b[$i]);
36
+ }
37
+ return $result === 0;
38
+ }
39
+
40
+ /**
41
+ * Returns cryptographically strong secure random bytes (as a PHP string).
42
+ *
43
+ * @param int $numBytes
44
+ * The number of bytes of random data to return.
45
+ *
46
+ * @return string
47
+ */
48
+ static function getRandomBytes($numBytes)
49
+ {
50
+ Checker::argIntPositive("numBytes", $numBytes);
51
+
52
+ // openssl_random_pseudo_bytes had some issues prior to PHP 5.3.4
53
+ if (function_exists('openssl_random_pseudo_bytes')
54
+ && version_compare(PHP_VERSION, '5.3.4') >= 0) {
55
+ $s = openssl_random_pseudo_bytes($numBytes, $isCryptoStrong);
56
+ if ($isCryptoStrong) return $s;
57
+ }
58
+
59
+ if (function_exists('mcrypt_create_iv')) {
60
+ return mcrypt_create_iv($numBytes);
61
+ }
62
+
63
+ // Hopefully the above two options cover all our users. But if not, there are
64
+ // other platform-specific options we could add.
65
+ throw new \Exception("no suitable random number source available");
66
+ }
67
+ }
com/lib/Dropbox/StreamReadException.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown when there's an error reading from a stream that was passed in by the caller.
6
+ */
7
+ class StreamReadException extends \Exception
8
+ {
9
+ /**
10
+ * @internal
11
+ */
12
+ function __construct($message, $cause = null)
13
+ {
14
+ parent::__construct($message, 0, $cause);
15
+ }
16
+ }
com/lib/Dropbox/Util.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ class Util
5
+ {
6
+ /**
7
+ * @internal
8
+ */
9
+ public static function q($object)
10
+ {
11
+ return var_export($object, true);
12
+ }
13
+
14
+ /**
15
+ * If the given string begins with the UTF-8 BOM (byte order mark), remove it and
16
+ * return whatever is left. Otherwise, return the original string untouched.
17
+ *
18
+ * Though it's not recommended for UTF-8 to have a BOM, the standard allows it to
19
+ * support software that isn't Unicode-aware.
20
+ *
21
+ * @param string $string
22
+ * A UTF-8 encoded string.
23
+ *
24
+ * @return string
25
+ */
26
+ public static function stripUtf8Bom($string)
27
+ {
28
+ if (\substr_compare($string, "\xEF\xBB\xBF", 0, 3) === 0) {
29
+ $string = \substr($string, 3);
30
+ }
31
+ return $string;
32
+ }
33
+ }
com/lib/Dropbox/ValueStore.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * A contract for a class which provides simple get/set/clear access to a single string
6
+ * value. {@link ArrayEntryStore} provides an implementation of this for storing a value
7
+ * in a single array element.
8
+ *
9
+ * Example implementation for a Memcache-based backing store:
10
+ *
11
+ * <code>
12
+ * class MemcacheValueStore implements ValueStore
13
+ * {
14
+ * private $key;
15
+ * private $memcache;
16
+ *
17
+ * function __construct($memcache, $key)
18
+ * {
19
+ * $this->memcache = $memcache;
20
+ * $this->key = $key;
21
+ * }
22
+ *
23
+ * function get()
24
+ * {
25
+ * $value = $this->memcache->get($this->getKey());
26
+ * return $value === false ? null : base64_decode($value);
27
+ * }
28
+ *
29
+ * function set($value)
30
+ * {
31
+ * $this->memcache->set($this->key, base64_encode($value));
32
+ * }
33
+ *
34
+ * function clear()
35
+ * {
36
+ * $this->memcache->delete($this->key);
37
+ * }
38
+ * }
39
+ * </code>
40
+ */
41
+ interface ValueStore
42
+ {
43
+ /**
44
+ * Returns the entry's current value or <code>null</code> if nothing is set.
45
+ *
46
+ * @return string
47
+ */
48
+ function get();
49
+
50
+ /**
51
+ * Set the entry to the given value.
52
+ *
53
+ * @param string $value
54
+ */
55
+ function set($value);
56
+
57
+ /**
58
+ * Remove the value.
59
+ */
60
+ function clear();
61
+ }
com/lib/Dropbox/WebAuth.php ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * OAuth 2 "authorization code" flow. (This SDK does not support the "token" flow.)
6
+ *
7
+ * Use {@link WebAuth::start()} and {@link WebAuth::finish()} to guide your
8
+ * user through the process of giving your app access to their Dropbox account.
9
+ * At the end, you will have an access token, which you can pass to {@link Client}
10
+ * and start making API calls.
11
+ *
12
+ * Example:
13
+ *
14
+ * <code>
15
+ * use \Dropbox as dbx;
16
+ *
17
+ * function getWebAuth()
18
+ * {
19
+ * $appInfo = dbx\AppInfo::loadFromJsonFile(...);
20
+ * $clientIdentifier = "my-app/1.0";
21
+ * $redirectUri = "https://example.org/dropbox-auth-finish";
22
+ * $csrfTokenStore = new dbx\ArrayEntryStore($_SESSION, 'dropbox-auth-csrf-token');
23
+ * return new dbx\WebAuth($appInfo, $clientIdentifier, $redirectUri, $csrfTokenStore, ...);
24
+ * }
25
+ *
26
+ * // ----------------------------------------------------------
27
+ * // In the URL handler for "/dropbox-auth-start"
28
+ *
29
+ * $authorizeUrl = getWebAuth()->start();
30
+ * header("Location: $authorizeUrl");
31
+ *
32
+ * // ----------------------------------------------------------
33
+ * // In the URL handler for "/dropbox-auth-finish"
34
+ *
35
+ * try {
36
+ * list($accessToken, $userId, $urlState) = getWebAuth()->finish($_GET);
37
+ * assert($urlState === null); // Since we didn't pass anything in start()
38
+ * }
39
+ * catch (dbx\WebAuthException_BadRequest $ex) {
40
+ * error_log("/dropbox-auth-finish: bad request: " . $ex->getMessage());
41
+ * // Respond with an HTTP 400 and display error page...
42
+ * }
43
+ * catch (dbx\WebAuthException_BadState $ex) {
44
+ * // Auth session expired. Restart the auth process.
45
+ * header('Location: /dropbox-auth-start');
46
+ * }
47
+ * catch (dbx\WebAuthException_Csrf $ex) {
48
+ * error_log("/dropbox-auth-finish: CSRF mismatch: " . $ex->getMessage());
49
+ * // Respond with HTTP 403 and display error page...
50
+ * }
51
+ * catch (dbx\WebAuthException_NotApproved $ex) {
52
+ * error_log("/dropbox-auth-finish: not approved: " . $ex->getMessage());
53
+ * }
54
+ * catch (dbx\WebAuthException_Provider $ex) {
55
+ * error_log("/dropbox-auth-finish: error redirect from Dropbox: " . $ex->getMessage());
56
+ * }
57
+ * catch (dbx\Exception $ex) {
58
+ * error_log("/dropbox-auth-finish: error communicating with Dropbox API: " . $ex->getMessage());
59
+ * }
60
+ *
61
+ * // We can now use $accessToken to make API requests.
62
+ * $client = dbx\Client($accessToken, ...);
63
+ * </code>
64
+ *
65
+ */
66
+ class WebAuth extends WebAuthBase
67
+ {
68
+ /**
69
+ * The URI that the Dropbox server will redirect the user to after the user finishes
70
+ * authorizing your app. This URI must be HTTPS-based and
71
+ * <a href="https://www.dropbox.com/developers/apps">pre-registered with Dropbox</a>,
72
+ * though "localhost"-based and "127.0.0.1"-based URIs are allowed without pre-registration
73
+ * and can be either HTTP or HTTPS.
74
+ *
75
+ * @return string
76
+ */
77
+ function getRedirectUri() { return $this->redirectUri; }
78
+
79
+ /** @var string */
80
+ private $redirectUri;
81
+
82
+ /**
83
+ * A object that lets us save CSRF token string to the user's session. If you're using the
84
+ * standard PHP <code>$_SESSION</code>, you can pass in something like
85
+ * <code>new ArrayEntryStore($_SESSION, 'dropbox-auth-csrf-token')</code>.
86
+ *
87
+ * If you're not using $_SESSION, you might have to create your own class that provides
88
+ * the same <code>get()</code>/<code>set()</code>/<code>clear()</code> methods as
89
+ * {@link ArrayEntryStore}.
90
+ *
91
+ * @return ValueStore
92
+ */
93
+ function getCsrfTokenStore() { return $this->csrfTokenStore; }
94
+
95
+ /** @var object */
96
+ private $csrfTokenStore;
97
+
98
+ /**
99
+ * Constructor.
100
+ *
101
+ * @param AppInfo $appInfo
102
+ * See {@link getAppInfo()}
103
+ * @param string $clientIdentifier
104
+ * See {@link getClientIdentifier()}
105
+ * @param null|string $redirectUri
106
+ * See {@link getRedirectUri()}
107
+ * @param null|ValueStore $csrfTokenStore
108
+ * See {@link getCsrfTokenStore()}
109
+ * @param null|string $userLocale
110
+ * See {@link getUserLocale()}
111
+ */
112
+ function __construct($appInfo, $clientIdentifier, $redirectUri, $csrfTokenStore, $userLocale = null)
113
+ {
114
+ parent::__construct($appInfo, $clientIdentifier, $userLocale);
115
+
116
+ Checker::argStringNonEmpty("redirectUri", $redirectUri);
117
+
118
+ $this->csrfTokenStore = $csrfTokenStore;
119
+ $this->redirectUri = $redirectUri;
120
+ }
121
+
122
+ /**
123
+ * Starts the OAuth 2 authorization process, which involves redirecting the user to the
124
+ * returned authorization URL (a URL on the Dropbox website). When the user then
125
+ * either approves or denies your app access, Dropbox will redirect them to the
126
+ * <code>$redirectUri</code> given to constructor, at which point you should
127
+ * call {@link finish()} to complete the authorization process.
128
+ *
129
+ * This function will also save a CSRF token using the <code>$csrfTokenStore</code> given to
130
+ * the constructor. This CSRF token will be checked on {@link finish()} to prevent
131
+ * request forgery.
132
+ *
133
+ * See <a href="https://www.dropbox.com/developers/core/docs#oa2-authorize">/oauth2/authorize</a>.
134
+ *
135
+ * @param string|null $urlState
136
+ * Any data you would like to keep in the URL through the authorization process.
137
+ * This exact state will be returned to you by {@link finish()}.
138
+ *
139
+ * @return array
140
+ * The URL to redirect the user to.
141
+ *
142
+ * @throws Exception
143
+ */
144
+ function start($urlState = null)
145
+ {
146
+ Checker::argStringOrNull("urlState", $urlState);
147
+
148
+ $csrfToken = self::encodeCsrfToken(Security::getRandomBytes(16));
149
+ $state = $csrfToken;
150
+ if ($urlState !== null) {
151
+ $state .= "|";
152
+ $state .= $urlState;
153
+ }
154
+ $this->csrfTokenStore->set($csrfToken);
155
+
156
+ return $this->_getAuthorizeUrl($this->redirectUri, $state);
157
+ }
158
+
159
+ private static function encodeCsrfToken($string)
160
+ {
161
+ return strtr(base64_encode($string), '+/', '-_');
162
+ }
163
+
164
+ /**
165
+ * Call this after the user has visited the authorize URL ({@link start()}), approved your app,
166
+ * and was redirected to your redirect URI.
167
+ *
168
+ * See <a href="https://www.dropbox.com/developers/core/docs#oa2-token">/oauth2/token</a>.
169
+ *
170
+ * @param array $queryParams
171
+ * The query parameters on the GET request to your redirect URI.
172
+ *
173
+ * @return array
174
+ * A <code>list(string $accessToken, string $userId, string $urlState)</code>, where
175
+ * <code>$accessToken</code> can be used to construct a {@link Client}, <code>$userId</code>
176
+ * is the user ID of the user's Dropbox account, and <code>$urlState</code> is the
177
+ * value you originally passed in to {@link start()}.
178
+ *
179
+ * @throws Exception
180
+ * Thrown if there's an error getting the access token from Dropbox.
181
+ * @throws WebAuthException_BadRequest
182
+ * @throws WebAuthException_BadState
183
+ * @throws WebAuthException_Csrf
184
+ * @throws WebAuthException_NotApproved
185
+ * @throws WebAuthException_Provider
186
+ */
187
+ function finish($queryParams)
188
+ {
189
+ Checker::argArray("queryParams", $queryParams);
190
+
191
+ $csrfTokenFromSession = $this->csrfTokenStore->get();
192
+ Checker::argStringOrNull("this->csrfTokenStore->get()", $csrfTokenFromSession);
193
+
194
+ // Check well-formedness of request.
195
+
196
+ if (!isset($queryParams['state'])) {
197
+ throw new WebAuthException_BadRequest("Missing query parameter 'state'.");
198
+ }
199
+ $state = $queryParams['state'];
200
+ Checker::argString("queryParams['state']", $state);
201
+
202
+ $error = null;
203
+ $errorDescription = null;
204
+ if (isset($queryParams['error'])) {
205
+ $error = $queryParams['error'];
206
+ Checker::argString("queryParams['error']", $error);
207
+ if (isset($queryParams['error_description'])) {
208
+ $errorDescription = $queryParams['error_description'];
209
+ Checker::argString("queryParams['error_description']", $errorDescription);
210
+ }
211
+ }
212
+
213
+ $code = null;
214
+ if (isset($queryParams['code'])) {
215
+ $code = $queryParams['code'];
216
+ Checker::argString("queryParams['code']", $code);
217
+ }
218
+
219
+ if ($code !== null && $error !== null) {
220
+ throw new WebAuthException_BadRequest("Query parameters 'code' and 'error' are both set;".
221
+ " only one must be set.");
222
+ }
223
+ if ($code === null && $error === null) {
224
+ throw new WebAuthException_BadRequest("Neither query parameter 'code' or 'error' is set.");
225
+ }
226
+
227
+ // Check CSRF token
228
+
229
+ if ($csrfTokenFromSession === null) {
230
+ throw new WebAuthException_BadState();
231
+ }
232
+
233
+ $splitPos = strpos($state, "|");
234
+ if ($splitPos === false) {
235
+ $givenCsrfToken = $state;
236
+ $urlState = null;
237
+ } else {
238
+ $givenCsrfToken = substr($state, 0, $splitPos);
239
+ $urlState = substr($state, $splitPos + 1);
240
+ }
241
+ if (!Security::stringEquals($csrfTokenFromSession, $givenCsrfToken)) {
242
+ throw new WebAuthException_Csrf("Expected ".Util::q($csrfTokenFromSession) .
243
+ ", got ".Util::q($givenCsrfToken) .".");
244
+ }
245
+ $this->csrfTokenStore->clear();
246
+
247
+ // Check for error identifier
248
+
249
+ if ($error !== null) {
250
+ if ($error === 'access_denied') {
251
+ // When the user clicks "Deny".
252
+ if ($errorDescription === null) {
253
+ throw new WebAuthException_NotApproved("No additional description from Dropbox.");
254
+ } else {
255
+ throw new WebAuthException_NotApproved("Additional description from Dropbox: $errorDescription");
256
+ }
257
+ } else {
258
+ // All other errors.
259
+ $fullMessage = $error;
260
+ if ($errorDescription !== null) {
261
+ $fullMessage .= ": ";
262
+ $fullMessage .= $errorDescription;
263
+ }
264
+ throw new WebAuthException_Provider($fullMessage);
265
+ }
266
+ }
267
+
268
+ // If everything went ok, make the network call to get an access token.
269
+
270
+ list($accessToken, $userId) = $this->_finish($code, $this->redirectUri);
271
+ return array($accessToken, $userId, $urlState);
272
+ }
273
+ }
com/lib/Dropbox/WebAuthBase.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * The base class for the two auth options.
6
+ */
7
+ class WebAuthBase extends AuthBase
8
+ {
9
+ // protected function _getAuthorizeUrl($redirectUri, $state)
10
+ // {
11
+ // return RequestUtil::buildUrlForGetOrPut(
12
+ // $this->userLocale,
13
+ // $this->appInfo->getHost()->getWeb(),
14
+ // "1/oauth2/authorize",
15
+ // array(
16
+ // "client_id" => $this->appInfo->getKey(),
17
+ // "response_type" => "code",
18
+ // "redirect_uri" => $redirectUri,
19
+ // "state" => $state,
20
+ // ));
21
+ // }
22
+
23
+ /* Dropbox api 2*/
24
+ protected function _getAuthorizeUrl($redirectUri, $state)
25
+ {
26
+ return RequestUtil::buildUrlForGetOrPut(
27
+ $this->userLocale,
28
+ $this->appInfo->getHost()->getWeb(),
29
+ "oauth2/authorize",
30
+ array(
31
+ "client_id" => $this->appInfo->getKey(),
32
+ "response_type" => "code",
33
+ "redirect_uri" => $redirectUri,
34
+ "state" => $state,
35
+ ));
36
+ }
37
+
38
+ protected function _finish($code, $originalRedirectUri)
39
+ {
40
+ // This endpoint requires "Basic" auth.
41
+ $clientCredentials = $this->appInfo->getKey().":".$this->appInfo->getSecret();
42
+ $authHeaderValue = "Basic ".base64_encode($clientCredentials);
43
+
44
+ $response = RequestUtil::doPostWithSpecificAuth(
45
+ $this->clientIdentifier, $authHeaderValue, $this->userLocale,
46
+ $this->appInfo->getHost()->getApi(),
47
+ "oauth2/token",
48
+ array(
49
+ "grant_type" => "authorization_code",
50
+ "code" => $code,
51
+ "redirect_uri" => $originalRedirectUri,
52
+ ));
53
+
54
+ if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
55
+
56
+ $parts = RequestUtil::parseResponseJson($response->body);
57
+
58
+ if (!array_key_exists('token_type', $parts) || !is_string($parts['token_type'])) {
59
+ throw new Exception_BadResponse("Missing \"token_type\" field.");
60
+ }
61
+ $tokenType = $parts['token_type'];
62
+ if (!array_key_exists('access_token', $parts) || !is_string($parts['access_token'])) {
63
+ throw new Exception_BadResponse("Missing \"access_token\" field.");
64
+ }
65
+ $accessToken = $parts['access_token'];
66
+ if (!array_key_exists('uid', $parts) || !is_string($parts['uid'])) {
67
+ throw new Exception_BadResponse("Missing \"uid\" string field.");
68
+ }
69
+ $userId = $parts['uid'];
70
+
71
+ if ($tokenType !== "Bearer" && $tokenType !== "bearer") {
72
+ throw new Exception_BadResponse("Unknown \"token_type\"; expecting \"Bearer\", got "
73
+ .Util::q($tokenType));
74
+ }
75
+
76
+ return array($accessToken, $userId);
77
+ }
78
+
79
+ // protected function _finish($code, $originalRedirectUri)
80
+ // {
81
+ // // This endpoint requires "Basic" auth.
82
+ // $clientCredentials = $this->appInfo->getKey().":".$this->appInfo->getSecret();
83
+ // $authHeaderValue = "Basic ".base64_encode($clientCredentials);
84
+
85
+ // $response = RequestUtil::doPostWithSpecificAuth(
86
+ // $this->clientIdentifier, $authHeaderValue, $this->userLocale,
87
+ // $this->appInfo->getHost()->getApi(),
88
+ // "1/oauth2/token",
89
+ // array(
90
+ // "grant_type" => "authorization_code",
91
+ // "code" => $code,
92
+ // "redirect_uri" => $originalRedirectUri,
93
+ // ));
94
+
95
+ // if ($response->statusCode !== 200) throw RequestUtil::unexpectedStatus($response);
96
+
97
+ // $parts = RequestUtil::parseResponseJson($response->body);
98
+
99
+ // if (!array_key_exists('token_type', $parts) || !is_string($parts['token_type'])) {
100
+ // throw new Exception_BadResponse("Missing \"token_type\" field.");
101
+ // }
102
+ // $tokenType = $parts['token_type'];
103
+ // if (!array_key_exists('access_token', $parts) || !is_string($parts['access_token'])) {
104
+ // throw new Exception_BadResponse("Missing \"access_token\" field.");
105
+ // }
106
+ // $accessToken = $parts['access_token'];
107
+ // if (!array_key_exists('uid', $parts) || !is_string($parts['uid'])) {
108
+ // throw new Exception_BadResponse("Missing \"uid\" string field.");
109
+ // }
110
+ // $userId = $parts['uid'];
111
+
112
+ // if ($tokenType !== "Bearer" && $tokenType !== "bearer") {
113
+ // throw new Exception_BadResponse("Unknown \"token_type\"; expecting \"Bearer\", got "
114
+ // .Util::q($tokenType));
115
+ // }
116
+
117
+ // return array($accessToken, $userId);
118
+ // }
119
+ }
com/lib/Dropbox/WebAuthException/BadRequest.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown if the redirect URL was missing parameters or if the given parameters were not valid.
6
+ *
7
+ * The recommended action is to show an HTTP 400 error page.
8
+ */
9
+ class WebAuthException_BadRequest extends \Exception
10
+ {
11
+ /**
12
+ * @param string $message
13
+ *
14
+ * @internal
15
+ */
16
+ function __construct($message)
17
+ {
18
+ parent::__construct($message);
19
+ }
20
+ }
com/lib/Dropbox/WebAuthException/BadState.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown if all the parameters are correct, but there's no CSRF token in the session. This
6
+ * probably means that the session expired.
7
+ *
8
+ * The recommended action is to redirect the user's browser to try the approval process again.
9
+ */
10
+ class WebAuthException_BadState extends \Exception
11
+ {
12
+ /**
13
+ * @internal
14
+ */
15
+ function __construct()
16
+ {
17
+ parent::__construct("Missing CSRF token in session.");
18
+ }
19
+ }
com/lib/Dropbox/WebAuthException/Csrf.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown if the given 'state' parameter doesn't contain the CSRF token from the user's session.
6
+ * This is blocked to prevent CSRF attacks.
7
+ *
8
+ * The recommended action is to respond with an HTTP 403 error page.
9
+ */
10
+ class WebAuthException_Csrf extends \Exception
11
+ {
12
+ /**
13
+ * @param string $message
14
+ *
15
+ * @internal
16
+ */
17
+ function __construct($message)
18
+ {
19
+ parent::__construct($message);
20
+ }
21
+ }
com/lib/Dropbox/WebAuthException/NotApproved.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown if the user chose not to grant your app access to their Dropbox account.
6
+ */
7
+ class WebAuthException_NotApproved extends \Exception
8
+ {
9
+ /**
10
+ * @param string $message
11
+ *
12
+ * @internal
13
+ */
14
+ function __construct($message)
15
+ {
16
+ parent::__construct($message);
17
+ }
18
+ }
com/lib/Dropbox/WebAuthException/Provider.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Thrown if Dropbox returns some other error about the authorization request.
6
+ */
7
+ class WebAuthException_Provider extends \Exception
8
+ {
9
+ /**
10
+ * @param string $message
11
+ *
12
+ * @internal
13
+ */
14
+ function __construct($message)
15
+ {
16
+ parent::__construct($message);
17
+ }
18
+ }
com/lib/Dropbox/WebAuthNoRedirect.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * OAuth 2 code-based authorization for apps that can't provide a redirect URI, typically
6
+ * command-line example apps.
7
+ *
8
+ * Use {@link WebAuth::start()} and {@link WebAuth::getToken()} to guide your
9
+ * user through the process of giving your app access to their Dropbox account. At the end, you
10
+ * will have an {@link AccessToken}, which you can pass to {@link Client} and start making
11
+ * API calls.
12
+ *
13
+ * Example:
14
+ *
15
+ * <code>
16
+ * use \Dropbox as dbx;
17
+ * $appInfo = dbx\AppInfo::loadFromJsonFile(...);
18
+ * $clientIdentifier = "my-app/1.0";
19
+ * $webAuth = new dbx\WebAuthNoRedirect($appInfo, $clientIdentifier, ...);
20
+ *
21
+ * $authorizeUrl = $webAuth->start();
22
+ *
23
+ * print("1. Go to: $authorizeUrl\n");
24
+ * print("2. Click "Allow" (you might have to log in first).\n");
25
+ * print("3. Copy the authorization code.\n");
26
+ * print("Enter the authorization code here: ");
27
+ * $code = \trim(\fgets(STDIN));
28
+ *
29
+ * try {
30
+ * list($accessToken, $userId) = $webAuth->finish($code);
31
+ * }
32
+ * catch (dbx\Exception $ex) {
33
+ * print("Error communicating with Dropbox API: " . $ex->getMessage() . "\n");
34
+ * }
35
+ *
36
+ * $client = dbx\Client($accessToken, $clientIdentifier, ...);
37
+ * </code>
38
+ */
39
+ class WebAuthNoRedirect extends WebAuthBase
40
+ {
41
+ /**
42
+ * Returns the URL of the authorization page the user must visit. If the user approves
43
+ * your app, they will be shown the authorization code on the web page. They will need to
44
+ * copy/paste that code into your application so your app can pass it to
45
+ * {@link finish}.
46
+ *
47
+ * See <a href="https://www.dropbox.com/developers/core/docs#oa2-authorize">/oauth2/authorize</a>.
48
+ *
49
+ * @return string
50
+ * An authorization URL. Direct the user's browser to this URL. After the user decides
51
+ * whether to authorize your app or not, Dropbox will show the user an authorization code,
52
+ * which the user will need to give to your application (e.g. via copy/paste).
53
+ */
54
+ function start()
55
+ {
56
+ return $this->_getAuthorizeUrl(null, null);
57
+ }
58
+
59
+ /**
60
+ * Call this after the user has visited the authorize URL returned by {@link start()},
61
+ * approved your app, was presented with an authorization code by Dropbox, and has copy/paste'd
62
+ * that authorization code into your app.
63
+ *
64
+ * See <a href="https://www.dropbox.com/developers/core/docs#oa2-token">/oauth2/token</a>.
65
+ *
66
+ * @param string $code
67
+ * The authorization code provided to the user by Dropbox.
68
+ *
69
+ * @return array
70
+ * A <code>list(string $accessToken, string $userId)</code>, where
71
+ * <code>$accessToken</code> can be used to construct a {@link Client} and
72
+ * <code>$userId</code> is the user ID of the user's Dropbox account.
73
+ *
74
+ * @throws Exception
75
+ * Thrown if there's an error getting the access token from Dropbox.
76
+ */
77
+ function finish($code)
78
+ {
79
+ Checker::argStringNonEmpty("code", $code);
80
+ return $this->_finish($code, null);
81
+ }
82
+ }
com/lib/Dropbox/WriteMode.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ /**
5
+ * Describes how a file should be saved when it is written to Dropbox.
6
+ */
7
+ final class WriteMode
8
+ {
9
+ /**
10
+ * The URL parameters to pass to the file uploading endpoint to achieve the
11
+ * desired write mode.
12
+ *
13
+ * @var array
14
+ */
15
+ private $extraParams;
16
+
17
+ /**
18
+ * @internal
19
+ */
20
+ private function __construct($extraParams)
21
+ {
22
+ $this->extraParams = $extraParams;
23
+ }
24
+
25
+ /**
26
+ * @internal
27
+ */
28
+ function getExtraParams()
29
+ {
30
+ return $this->extraParams;
31
+ }
32
+
33
+ /**
34
+ * Returns a {@link WriteMode} for adding a new file. If a file at the specified path already
35
+ * exists, the new file will be renamed automatically.
36
+ *
37
+ * For example, if you're trying to upload a file to "/Notes/Groceries.txt", but there's
38
+ * already a file there, your file will be written to "/Notes/Groceries (1).txt".
39
+ *
40
+ * You can determine whether your file was renamed by checking the "path" field of the
41
+ * metadata object returned by the API call.
42
+ *
43
+ * @return WriteMode
44
+ */
45
+ static function add()
46
+ {
47
+ if (self::$addInstance === null) {
48
+ self::$addInstance = new WriteMode(array("overwrite" => "false"));
49
+ }
50
+ return self::$addInstance;
51
+ }
52
+ private static $addInstance = null;
53
+
54
+ /**
55
+ * Returns a {@link WriteMode} for forcing a file to be at a certain path. If there's already
56
+ * a file at that path, the existing file will be overwritten. If there's a folder at that
57
+ * path, however, it will not be overwritten and the API call will fail.
58
+ *
59
+ * @return WriteMode
60
+ */
61
+ static function force()
62
+ {
63
+ if (self::$forceInstance === null) {
64
+ self::$forceInstance = new WriteMode(array("overwrite" => "true"));
65
+ }
66
+ return self::$forceInstance;
67
+ }
68
+ private static $forceInstance = null;
69
+
70
+ /**
71
+ * Returns a {@link WriteMode} for updating an existing file. This is useful for when you
72
+ * have downloaded a file, made modifications, and want to save your modifications back to
73
+ * Dropbox. You need to specify the revision of the copy of the file you downloaded (it's
74
+ * the "rev" parameter of the file's metadata object).
75
+ *
76
+ * If, when you attempt to save, the revision of the file currently on Dropbox matches
77
+ * $revToReplace, the file on Dropbox will be overwritten with the new contents you provide.
78
+ *
79
+ * If the revision of the file currently on Dropbox doesn't match $revToReplace, Dropbox will
80
+ * create a new file and save your contents to that file. For example, if the original file
81
+ * path is "/Notes/Groceries.txt", the new file's path might be
82
+ * "/Notes/Groceries (conflicted copy).txt".
83
+ *
84
+ * You can determine whether your file was renamed by checking the "path" field of the
85
+ * metadata object returned by the API call.
86
+ *
87
+ * @param string $revToReplace
88
+ * @return WriteMode
89
+ */
90
+ static function update($revToReplace)
91
+ {
92
+ return new WriteMode(array("parent_rev" => $revToReplace));
93
+ }
94
+
95
+ /**
96
+ * Check that a function argument is of type <code>WriteMode</code>.
97
+ *
98
+ * @internal
99
+ */
100
+ static function checkArg($argName, $argValue)
101
+ {
102
+ if (!($argValue instanceof self)) Checker::throwError($argName, $argValue, __CLASS__);
103
+ }
104
+
105
+ /**
106
+ * Check that a function argument is either <code>null</code> or of type
107
+ * <code>WriteMode</code>.
108
+ *
109
+ * @internal
110
+ */
111
+ static function checkArgOrNull($argName, $argValue)
112
+ {
113
+ if ($argValue === null) return;
114
+ if (!($argValue instanceof self)) Checker::throwError($argName, $argValue, __CLASS__);
115
+ }
116
+ }
com/lib/Dropbox/autoload.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Dropbox;
3
+
4
+ // The Dropbox SDK autoloader. You probably shouldn't be using this. Instead,
5
+ // use a global autoloader, like the Composer autoloader.
6
+ //
7
+ // But if you really don't want to use a global autoloader, do this:
8
+ //
9
+ // require_once "<path-to-here>/Dropbox/autoload.php"
10
+
11
+ /**
12
+ * @internal
13
+ */
14
+ function autoload($name)
15
+ {
16
+ // If the name doesn't start with "Dropbox\", then its not once of our classes.
17
+ if (\substr_compare($name, "Dropbox\\", 0, 8) !== 0) return;
18
+
19
+ // Take the "Dropbox\" prefix off.
20
+ $stem = \substr($name, 8);
21
+
22
+ // Convert "\" and "_" to path separators.
23
+ $pathified_stem = \str_replace(array("\\", "_"), '/', $stem);
24
+
25
+ $path = __DIR__ . "/" . $pathified_stem . ".php";
26
+
27
+ if (\is_file($path)) {
28
+ require_once $path;
29
+ }
30
+ }
31
+
32
+ \spl_autoload_register('Dropbox\autoload');
com/lib/Dropbox/certs/trusted-certs.crt ADDED
@@ -0,0 +1,1396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # DigiCert Assured ID Root CA.pem
2
+ # Certificate:
3
+ # Data:
4
+ # Version: 3 (0x2)
5
+ # Serial Number:
6
+ # 0c:e7:e0:e5:17:d8:46:fe:8f:e5:60:fc:1b:f0:30:39
7
+ # Signature Algorithm: sha1WithRSAEncryption
8
+ # Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root CA
9
+ # Validity
10
+ # Not Before: Nov 10 00:00:00 2006 GMT
11
+ # Not After : Nov 10 00:00:00 2031 GMT
12
+ # Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root CA
13
+ # Subject Public Key Info:
14
+ # Public Key Algorithm: rsaEncryption
15
+ # Public-Key: (2048 bit)
16
+ # Modulus:
17
+ # 00:ad:0e:15:ce:e4:43:80:5c:b1:87:f3:b7:60:f9:
18
+ # 71:12:a5:ae:dc:26:94:88:aa:f4:ce:f5:20:39:28:
19
+ # 58:60:0c:f8:80:da:a9:15:95:32:61:3c:b5:b1:28:
20
+ # 84:8a:8a:dc:9f:0a:0c:83:17:7a:8f:90:ac:8a:e7:
21
+ # 79:53:5c:31:84:2a:f6:0f:98:32:36:76:cc:de:dd:
22
+ # 3c:a8:a2:ef:6a:fb:21:f2:52:61:df:9f:20:d7:1f:
23
+ # e2:b1:d9:fe:18:64:d2:12:5b:5f:f9:58:18:35:bc:
24
+ # 47:cd:a1:36:f9:6b:7f:d4:b0:38:3e:c1:1b:c3:8c:
25
+ # 33:d9:d8:2f:18:fe:28:0f:b3:a7:83:d6:c3:6e:44:
26
+ # c0:61:35:96:16:fe:59:9c:8b:76:6d:d7:f1:a2:4b:
27
+ # 0d:2b:ff:0b:72:da:9e:60:d0:8e:90:35:c6:78:55:
28
+ # 87:20:a1:cf:e5:6d:0a:c8:49:7c:31:98:33:6c:22:
29
+ # e9:87:d0:32:5a:a2:ba:13:82:11:ed:39:17:9d:99:
30
+ # 3a:72:a1:e6:fa:a4:d9:d5:17:31:75:ae:85:7d:22:
31
+ # ae:3f:01:46:86:f6:28:79:c8:b1:da:e4:57:17:c4:
32
+ # 7e:1c:0e:b0:b4:92:a6:56:b3:bd:b2:97:ed:aa:a7:
33
+ # f0:b7:c5:a8:3f:95:16:d0:ff:a1:96:eb:08:5f:18:
34
+ # 77:4f
35
+ # Exponent: 65537 (0x10001)
36
+ # X509v3 extensions:
37
+ # X509v3 Key Usage: critical
38
+ # Digital Signature, Certificate Sign, CRL Sign
39
+ # X509v3 Basic Constraints: critical
40
+ # CA:TRUE
41
+ # X509v3 Subject Key Identifier:
42
+ # 45:EB:A2:AF:F4:92:CB:82:31:2D:51:8B:A7:A7:21:9D:F3:6D:C8:0F
43
+ # X509v3 Authority Key Identifier:
44
+ # keyid:45:EB:A2:AF:F4:92:CB:82:31:2D:51:8B:A7:A7:21:9D:F3:6D:C8:0F
45
+ #
46
+ # Signature Algorithm: sha1WithRSAEncryption
47
+ # a2:0e:bc:df:e2:ed:f0:e3:72:73:7a:64:94:bf:f7:72:66:d8:
48
+ # 32:e4:42:75:62:ae:87:eb:f2:d5:d9:de:56:b3:9f:cc:ce:14:
49
+ # 28:b9:0d:97:60:5c:12:4c:58:e4:d3:3d:83:49:45:58:97:35:
50
+ # 69:1a:a8:47:ea:56:c6:79:ab:12:d8:67:81:84:df:7f:09:3c:
51
+ # 94:e6:b8:26:2c:20:bd:3d:b3:28:89:f7:5f:ff:22:e2:97:84:
52
+ # 1f:e9:65:ef:87:e0:df:c1:67:49:b3:5d:eb:b2:09:2a:eb:26:
53
+ # ed:78:be:7d:3f:2b:f3:b7:26:35:6d:5f:89:01:b6:49:5b:9f:
54
+ # 01:05:9b:ab:3d:25:c1:cc:b6:7f:c2:f1:6f:86:c6:fa:64:68:
55
+ # eb:81:2d:94:eb:42:b7:fa:8c:1e:dd:62:f1:be:50:67:b7:6c:
56
+ # bd:f3:f1:1f:6b:0c:36:07:16:7f:37:7c:a9:5b:6d:7a:f1:12:
57
+ # 46:60:83:d7:27:04:be:4b:ce:97:be:c3:67:2a:68:11:df:80:
58
+ # e7:0c:33:66:bf:13:0d:14:6e:f3:7f:1f:63:10:1e:fa:8d:1b:
59
+ # 25:6d:6c:8f:a5:b7:61:01:b1:d2:a3:26:a1:10:71:9d:ad:e2:
60
+ # c3:f9:c3:99:51:b7:2b:07:08:ce:2e:e6:50:b2:a7:fa:0a:45:
61
+ # 2f:a2:f0:f2
62
+ -----BEGIN CERTIFICATE-----
63
+ MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
64
+ MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
65
+ d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
66
+ b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
67
+ EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
68
+ cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
69
+ MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
70
+ JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
71
+ mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
72
+ wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
73
+ VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
74
+ AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
75
+ AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
76
+ BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
77
+ pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
78
+ dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
79
+ fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
80
+ NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
81
+ H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
82
+ +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
83
+ -----END CERTIFICATE-----
84
+ # DigiCert Global Root CA.pem
85
+ # Certificate:
86
+ # Data:
87
+ # Version: 3 (0x2)
88
+ # Serial Number:
89
+ # 08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a
90
+ # Signature Algorithm: sha1WithRSAEncryption
91
+ # Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
92
+ # Validity
93
+ # Not Before: Nov 10 00:00:00 2006 GMT
94
+ # Not After : Nov 10 00:00:00 2031 GMT
95
+ # Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
96
+ # Subject Public Key Info:
97
+ # Public Key Algorithm: rsaEncryption
98
+ # Public-Key: (2048 bit)
99
+ # Modulus:
100
+ # 00:e2:3b:e1:11:72:de:a8:a4:d3:a3:57:aa:50:a2:
101
+ # 8f:0b:77:90:c9:a2:a5:ee:12:ce:96:5b:01:09:20:
102
+ # cc:01:93:a7:4e:30:b7:53:f7:43:c4:69:00:57:9d:
103
+ # e2:8d:22:dd:87:06:40:00:81:09:ce:ce:1b:83:bf:
104
+ # df:cd:3b:71:46:e2:d6:66:c7:05:b3:76:27:16:8f:
105
+ # 7b:9e:1e:95:7d:ee:b7:48:a3:08:da:d6:af:7a:0c:
106
+ # 39:06:65:7f:4a:5d:1f:bc:17:f8:ab:be:ee:28:d7:
107
+ # 74:7f:7a:78:99:59:85:68:6e:5c:23:32:4b:bf:4e:
108
+ # c0:e8:5a:6d:e3:70:bf:77:10:bf:fc:01:f6:85:d9:
109
+ # a8:44:10:58:32:a9:75:18:d5:d1:a2:be:47:e2:27:
110
+ # 6a:f4:9a:33:f8:49:08:60:8b:d4:5f:b4:3a:84:bf:
111
+ # a1:aa:4a:4c:7d:3e:cf:4f:5f:6c:76:5e:a0:4b:37:
112
+ # 91:9e:dc:22:e6:6d:ce:14:1a:8e:6a:cb:fe:cd:b3:
113
+ # 14:64:17:c7:5b:29:9e:32:bf:f2:ee:fa:d3:0b:42:
114
+ # d4:ab:b7:41:32:da:0c:d4:ef:f8:81:d5:bb:8d:58:
115
+ # 3f:b5:1b:e8:49:28:a2:70:da:31:04:dd:f7:b2:16:
116
+ # f2:4c:0a:4e:07:a8:ed:4a:3d:5e:b5:7f:a3:90:c3:
117
+ # af:27
118
+ # Exponent: 65537 (0x10001)
119
+ # X509v3 extensions:
120
+ # X509v3 Key Usage: critical
121
+ # Digital Signature, Certificate Sign, CRL Sign
122
+ # X509v3 Basic Constraints: critical
123
+ # CA:TRUE
124
+ # X509v3 Subject Key Identifier:
125
+ # 03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55
126
+ # X509v3 Authority Key Identifier:
127
+ # keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55
128
+ #
129
+ # Signature Algorithm: sha1WithRSAEncryption
130
+ # cb:9c:37:aa:48:13:12:0a:fa:dd:44:9c:4f:52:b0:f4:df:ae:
131
+ # 04:f5:79:79:08:a3:24:18:fc:4b:2b:84:c0:2d:b9:d5:c7:fe:
132
+ # f4:c1:1f:58:cb:b8:6d:9c:7a:74:e7:98:29:ab:11:b5:e3:70:
133
+ # a0:a1:cd:4c:88:99:93:8c:91:70:e2:ab:0f:1c:be:93:a9:ff:
134
+ # 63:d5:e4:07:60:d3:a3:bf:9d:5b:09:f1:d5:8e:e3:53:f4:8e:
135
+ # 63:fa:3f:a7:db:b4:66:df:62:66:d6:d1:6e:41:8d:f2:2d:b5:
136
+ # ea:77:4a:9f:9d:58:e2:2b:59:c0:40:23:ed:2d:28:82:45:3e:
137
+ # 79:54:92:26:98:e0:80:48:a8:37:ef:f0:d6:79:60:16:de:ac:
138
+ # e8:0e:cd:6e:ac:44:17:38:2f:49:da:e1:45:3e:2a:b9:36:53:
139
+ # cf:3a:50:06:f7:2e:e8:c4:57:49:6c:61:21:18:d5:04:ad:78:
140
+ # 3c:2c:3a:80:6b:a7:eb:af:15:14:e9:d8:89:c1:b9:38:6c:e2:
141
+ # 91:6c:8a:ff:64:b9:77:25:57:30:c0:1b:24:a3:e1:dc:e9:df:
142
+ # 47:7c:b5:b4:24:08:05:30:ec:2d:bd:0b:bf:45:bf:50:b9:a9:
143
+ # f3:eb:98:01:12:ad:c8:88:c6:98:34:5f:8d:0a:3c:c6:e9:d5:
144
+ # 95:95:6d:de
145
+ -----BEGIN CERTIFICATE-----
146
+ MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
147
+ MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
148
+ d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
149
+ QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
150
+ MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
151
+ b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
152
+ 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
153
+ CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
154
+ nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
155
+ 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
156
+ T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
157
+ gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
158
+ BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
159
+ TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
160
+ DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
161
+ hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
162
+ 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
163
+ PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
164
+ YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
165
+ CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
166
+ -----END CERTIFICATE-----
167
+ # DigiCert High Assurance EV Root CA.pem
168
+ # Certificate:
169
+ # Data:
170
+ # Version: 3 (0x2)
171
+ # Serial Number:
172
+ # 02:ac:5c:26:6a:0b:40:9b:8f:0b:79:f2:ae:46:25:77
173
+ # Signature Algorithm: sha1WithRSAEncryption
174
+ # Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
175
+ # Validity
176
+ # Not Before: Nov 10 00:00:00 2006 GMT
177
+ # Not After : Nov 10 00:00:00 2031 GMT
178
+ # Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
179
+ # Subject Public Key Info:
180
+ # Public Key Algorithm: rsaEncryption
181
+ # Public-Key: (2048 bit)
182
+ # Modulus:
183
+ # 00:c6:cc:e5:73:e6:fb:d4:bb:e5:2d:2d:32:a6:df:
184
+ # e5:81:3f:c9:cd:25:49:b6:71:2a:c3:d5:94:34:67:
185
+ # a2:0a:1c:b0:5f:69:a6:40:b1:c4:b7:b2:8f:d0:98:
186
+ # a4:a9:41:59:3a:d3:dc:94:d6:3c:db:74:38:a4:4a:
187
+ # cc:4d:25:82:f7:4a:a5:53:12:38:ee:f3:49:6d:71:
188
+ # 91:7e:63:b6:ab:a6:5f:c3:a4:84:f8:4f:62:51:be:
189
+ # f8:c5:ec:db:38:92:e3:06:e5:08:91:0c:c4:28:41:
190
+ # 55:fb:cb:5a:89:15:7e:71:e8:35:bf:4d:72:09:3d:
191
+ # be:3a:38:50:5b:77:31:1b:8d:b3:c7:24:45:9a:a7:
192
+ # ac:6d:00:14:5a:04:b7:ba:13:eb:51:0a:98:41:41:
193
+ # 22:4e:65:61:87:81:41:50:a6:79:5c:89:de:19:4a:
194
+ # 57:d5:2e:e6:5d:1c:53:2c:7e:98:cd:1a:06:16:a4:
195
+ # 68:73:d0:34:04:13:5c:a1:71:d3:5a:7c:55:db:5e:
196
+ # 64:e1:37:87:30:56:04:e5:11:b4:29:80:12:f1:79:
197
+ # 39:88:a2:02:11:7c:27:66:b7:88:b7:78:f2:ca:0a:
198
+ # a8:38:ab:0a:64:c2:bf:66:5d:95:84:c1:a1:25:1e:
199
+ # 87:5d:1a:50:0b:20:12:cc:41:bb:6e:0b:51:38:b8:
200
+ # 4b:cb
201
+ # Exponent: 65537 (0x10001)
202
+ # X509v3 extensions:
203
+ # X509v3 Key Usage: critical
204
+ # Digital Signature, Certificate Sign, CRL Sign
205
+ # X509v3 Basic Constraints: critical
206
+ # CA:TRUE
207
+ # X509v3 Subject Key Identifier:
208
+ # B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3
209
+ # X509v3 Authority Key Identifier:
210
+ # keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3
211
+ #
212
+ # Signature Algorithm: sha1WithRSAEncryption
213
+ # 1c:1a:06:97:dc:d7:9c:9f:3c:88:66:06:08:57:21:db:21:47:
214
+ # f8:2a:67:aa:bf:18:32:76:40:10:57:c1:8a:f3:7a:d9:11:65:
215
+ # 8e:35:fa:9e:fc:45:b5:9e:d9:4c:31:4b:b8:91:e8:43:2c:8e:
216
+ # b3:78:ce:db:e3:53:79:71:d6:e5:21:94:01:da:55:87:9a:24:
217
+ # 64:f6:8a:66:cc:de:9c:37:cd:a8:34:b1:69:9b:23:c8:9e:78:
218
+ # 22:2b:70:43:e3:55:47:31:61:19:ef:58:c5:85:2f:4e:30:f6:
219
+ # a0:31:16:23:c8:e7:e2:65:16:33:cb:bf:1a:1b:a0:3d:f8:ca:
220
+ # 5e:8b:31:8b:60:08:89:2d:0c:06:5c:52:b7:c4:f9:0a:98:d1:
221
+ # 15:5f:9f:12:be:7c:36:63:38:bd:44:a4:7f:e4:26:2b:0a:c4:
222
+ # 97:69:0d:e9:8c:e2:c0:10:57:b8:c8:76:12:91:55:f2:48:69:
223
+ # d8:bc:2a:02:5b:0f:44:d4:20:31:db:f4:ba:70:26:5d:90:60:
224
+ # 9e:bc:4b:17:09:2f:b4:cb:1e:43:68:c9:07:27:c1:d2:5c:f7:
225
+ # ea:21:b9:68:12:9c:3c:9c:bf:9e:fc:80:5c:9b:63:cd:ec:47:
226
+ # aa:25:27:67:a0:37:f3:00:82:7d:54:d7:a9:f8:e9:2e:13:a3:
227
+ # 77:e8:1f:4a
228
+ -----BEGIN CERTIFICATE-----
229
+ MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
230
+ MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
231
+ d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
232
+ ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
233
+ MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
234
+ LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
235
+ RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
236
+ +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
237
+ PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
238
+ xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
239
+ Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
240
+ hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
241
+ EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
242
+ MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
243
+ FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
244
+ nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
245
+ eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
246
+ hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
247
+ Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
248
+ vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
249
+ +OkuE6N36B9K
250
+ -----END CERTIFICATE-----
251
+ # Entrust Root Certification Authority - EC1.pem
252
+ # Certificate:
253
+ # Data:
254
+ # Version: 3 (0x2)
255
+ # Serial Number:
256
+ # a6:8b:79:29:00:00:00:00:50:d0:91:f9
257
+ # Signature Algorithm: ecdsa-with-SHA384
258
+ # Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - EC1
259
+ # Validity
260
+ # Not Before: Dec 18 15:25:36 2012 GMT
261
+ # Not After : Dec 18 15:55:36 2037 GMT
262
+ # Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - EC1
263
+ # Subject Public Key Info:
264
+ # Public Key Algorithm: id-ecPublicKey
265
+ # Public-Key: (384 bit)
266
+ # pub:
267
+ # 04:84:13:c9:d0:ba:6d:41:7b:e2:6c:d0:eb:55:5f:
268
+ # 66:02:1a:24:f4:5b:89:69:47:e3:b8:c2:7d:f1:f2:
269
+ # 02:c5:9f:a0:f6:5b:d5:8b:06:19:86:4f:53:10:6d:
270
+ # 07:24:27:a1:a0:f8:d5:47:19:61:4c:7d:ca:93:27:
271
+ # ea:74:0c:ef:6f:96:09:fe:63:ec:70:5d:36:ad:67:
272
+ # 77:ae:c9:9d:7c:55:44:3a:a2:63:51:1f:f5:e3:62:
273
+ # d4:a9:47:07:3e:cc:20
274
+ # ASN1 OID: secp384r1
275
+ # X509v3 extensions:
276
+ # X509v3 Key Usage: critical
277
+ # Certificate Sign, CRL Sign
278
+ # X509v3 Basic Constraints: critical
279
+ # CA:TRUE
280
+ # X509v3 Subject Key Identifier:
281
+ # B7:63:E7:1A:DD:8D:E9:08:A6:55:83:A4:E0:6A:50:41:65:11:42:49
282
+ # Signature Algorithm: ecdsa-with-SHA384
283
+ # 30:64:02:30:61:79:d8:e5:42:47:df:1c:ae:53:99:17:b6:6f:
284
+ # 1c:7d:e1:bf:11:94:d1:03:88:75:e4:8d:89:a4:8a:77:46:de:
285
+ # 6d:61:ef:02:f5:fb:b5:df:cc:fe:4e:ff:fe:a9:e6:a7:02:30:
286
+ # 5b:99:d7:85:37:06:b5:7b:08:fd:eb:27:8b:4a:94:f9:e1:fa:
287
+ # a7:8e:26:08:e8:7c:92:68:6d:73:d8:6f:26:ac:21:02:b8:99:
288
+ # b7:26:41:5b:25:60:ae:d0:48:1a:ee:06
289
+ -----BEGIN CERTIFICATE-----
290
+ MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG
291
+ A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3
292
+ d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu
293
+ dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq
294
+ RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy
295
+ MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD
296
+ VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0
297
+ L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g
298
+ Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD
299
+ ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi
300
+ A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt
301
+ ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH
302
+ Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
303
+ BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC
304
+ R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX
305
+ hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
306
+ -----END CERTIFICATE-----
307
+ # Entrust Root Certification Authority - G2.pem
308
+ # Certificate:
309
+ # Data:
310
+ # Version: 3 (0x2)
311
+ # Serial Number: 1246989352 (0x4a538c28)
312
+ # Signature Algorithm: sha256WithRSAEncryption
313
+ # Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2
314
+ # Validity
315
+ # Not Before: Jul 7 17:25:54 2009 GMT
316
+ # Not After : Dec 7 17:55:54 2030 GMT
317
+ # Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2
318
+ # Subject Public Key Info:
319
+ # Public Key Algorithm: rsaEncryption
320
+ # Public-Key: (2048 bit)
321
+ # Modulus:
322
+ # 00:ba:84:b6:72:db:9e:0c:6b:e2:99:e9:30:01:a7:
323
+ # 76:ea:32:b8:95:41:1a:c9:da:61:4e:58:72:cf:fe:
324
+ # f6:82:79:bf:73:61:06:0a:a5:27:d8:b3:5f:d3:45:
325
+ # 4e:1c:72:d6:4e:32:f2:72:8a:0f:f7:83:19:d0:6a:
326
+ # 80:80:00:45:1e:b0:c7:e7:9a:bf:12:57:27:1c:a3:
327
+ # 68:2f:0a:87:bd:6a:6b:0e:5e:65:f3:1c:77:d5:d4:
328
+ # 85:8d:70:21:b4:b3:32:e7:8b:a2:d5:86:39:02:b1:
329
+ # b8:d2:47:ce:e4:c9:49:c4:3b:a7:de:fb:54:7d:57:
330
+ # be:f0:e8:6e:c2:79:b2:3a:0b:55:e2:50:98:16:32:
331
+ # 13:5c:2f:78:56:c1:c2:94:b3:f2:5a:e4:27:9a:9f:
332
+ # 24:d7:c6:ec:d0:9b:25:82:e3:cc:c2:c4:45:c5:8c:
333
+ # 97:7a:06:6b:2a:11:9f:a9:0a:6e:48:3b:6f:db:d4:
334
+ # 11:19:42:f7:8f:07:bf:f5:53:5f:9c:3e:f4:17:2c:
335
+ # e6:69:ac:4e:32:4c:62:77:ea:b7:e8:e5:bb:34:bc:
336
+ # 19:8b:ae:9c:51:e7:b7:7e:b5:53:b1:33:22:e5:6d:
337
+ # cf:70:3c:1a:fa:e2:9b:67:b6:83:f4:8d:a5:af:62:
338
+ # 4c:4d:e0:58:ac:64:34:12:03:f8:b6:8d:94:63:24:
339
+ # a4:71
340
+ # Exponent: 65537 (0x10001)
341
+ # X509v3 extensions:
342
+ # X509v3 Key Usage: critical
343
+ # Certificate Sign, CRL Sign
344
+ # X509v3 Basic Constraints: critical
345
+ # CA:TRUE
346
+ # X509v3 Subject Key Identifier:
347
+ # 6A:72:26:7A:D0:1E:EF:7D:E7:3B:69:51:D4:6C:8D:9F:90:12:66:AB
348
+ # Signature Algorithm: sha256WithRSAEncryption
349
+ # 79:9f:1d:96:c6:b6:79:3f:22:8d:87:d3:87:03:04:60:6a:6b:
350
+ # 9a:2e:59:89:73:11:ac:43:d1:f5:13:ff:8d:39:2b:c0:f2:bd:
351
+ # 4f:70:8c:a9:2f:ea:17:c4:0b:54:9e:d4:1b:96:98:33:3c:a8:
352
+ # ad:62:a2:00:76:ab:59:69:6e:06:1d:7e:c4:b9:44:8d:98:af:
353
+ # 12:d4:61:db:0a:19:46:47:f3:eb:f7:63:c1:40:05:40:a5:d2:
354
+ # b7:f4:b5:9a:36:bf:a9:88:76:88:04:55:04:2b:9c:87:7f:1a:
355
+ # 37:3c:7e:2d:a5:1a:d8:d4:89:5e:ca:bd:ac:3d:6c:d8:6d:af:
356
+ # d5:f3:76:0f:cd:3b:88:38:22:9d:6c:93:9a:c4:3d:bf:82:1b:
357
+ # 65:3f:a6:0f:5d:aa:fc:e5:b2:15:ca:b5:ad:c6:bc:3d:d0:84:
358
+ # e8:ea:06:72:b0:4d:39:32:78:bf:3e:11:9c:0b:a4:9d:9a:21:
359
+ # f3:f0:9b:0b:30:78:db:c1:dc:87:43:fe:bc:63:9a:ca:c5:c2:
360
+ # 1c:c9:c7:8d:ff:3b:12:58:08:e6:b6:3d:ec:7a:2c:4e:fb:83:
361
+ # 96:ce:0c:3c:69:87:54:73:a4:73:c2:93:ff:51:10:ac:15:54:
362
+ # 01:d8:fc:05:b1:89:a1:7f:74:83:9a:49:d7:dc:4e:7b:8a:48:
363
+ # 6f:8b:45:f6
364
+ -----BEGIN CERTIFICATE-----
365
+ MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC
366
+ VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50
367
+ cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs
368
+ IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz
369
+ dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy
370
+ NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu
371
+ dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt
372
+ dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0
373
+ aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj
374
+ YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
375
+ AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T
376
+ RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN
377
+ cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW
378
+ wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1
379
+ U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0
380
+ jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP
381
+ BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN
382
+ BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/
383
+ jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
384
+ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v
385
+ 1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R
386
+ nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH
387
+ VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==
388
+ -----END CERTIFICATE-----
389
+ # Entrust Root Certification Authority.pem
390
+ # Certificate:
391
+ # Data:
392
+ # Version: 3 (0x2)
393
+ # Serial Number: 1164660820 (0x456b5054)
394
+ # Signature Algorithm: sha1WithRSAEncryption
395
+ # Issuer: C=US, O=Entrust, Inc., OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority
396
+ # Validity
397
+ # Not Before: Nov 27 20:23:42 2006 GMT
398
+ # Not After : Nov 27 20:53:42 2026 GMT
399
+ # Subject: C=US, O=Entrust, Inc., OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority
400
+ # Subject Public Key Info:
401
+ # Public Key Algorithm: rsaEncryption
402
+ # Public-Key: (2048 bit)
403
+ # Modulus:
404
+ # 00:b6:95:b6:43:42:fa:c6:6d:2a:6f:48:df:94:4c:
405
+ # 39:57:05:ee:c3:79:11:41:68:36:ed:ec:fe:9a:01:
406
+ # 8f:a1:38:28:fc:f7:10:46:66:2e:4d:1e:1a:b1:1a:
407
+ # 4e:c6:d1:c0:95:88:b0:c9:ff:31:8b:33:03:db:b7:
408
+ # 83:7b:3e:20:84:5e:ed:b2:56:28:a7:f8:e0:b9:40:
409
+ # 71:37:c5:cb:47:0e:97:2a:68:c0:22:95:62:15:db:
410
+ # 47:d9:f5:d0:2b:ff:82:4b:c9:ad:3e:de:4c:db:90:
411
+ # 80:50:3f:09:8a:84:00:ec:30:0a:3d:18:cd:fb:fd:
412
+ # 2a:59:9a:23:95:17:2c:45:9e:1f:6e:43:79:6d:0c:
413
+ # 5c:98:fe:48:a7:c5:23:47:5c:5e:fd:6e:e7:1e:b4:
414
+ # f6:68:45:d1:86:83:5b:a2:8a:8d:b1:e3:29:80:fe:
415
+ # 25:71:88:ad:be:bc:8f:ac:52:96:4b:aa:51:8d:e4:
416
+ # 13:31:19:e8:4e:4d:9f:db:ac:b3:6a:d5:bc:39:54:
417
+ # 71:ca:7a:7a:7f:90:dd:7d:1d:80:d9:81:bb:59:26:
418
+ # c2:11:fe:e6:93:e2:f7:80:e4:65:fb:34:37:0e:29:
419
+ # 80:70:4d:af:38:86:2e:9e:7f:57:af:9e:17:ae:eb:
420
+ # 1c:cb:28:21:5f:b6:1c:d8:e7:a2:04:22:f9:d3:da:
421
+ # d8:cb
422
+ # Exponent: 65537 (0x10001)
423
+ # X509v3 extensions:
424
+ # X509v3 Key Usage: critical
425
+ # Certificate Sign, CRL Sign
426
+ # X509v3 Basic Constraints: critical
427
+ # CA:TRUE
428
+ # X509v3 Private Key Usage Period:
429
+ # Not Before: Nov 27 20:23:42 2006 GMT, Not After: Nov 27 20:53:42 2026 GMT
430
+ # X509v3 Authority Key Identifier:
431
+ # keyid:68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D
432
+ #
433
+ # X509v3 Subject Key Identifier:
434
+ # 68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D
435
+ # 1.2.840.113533.7.65.0:
436
+ # 0...V7.1:4.0....
437
+ # Signature Algorithm: sha1WithRSAEncryption
438
+ # 93:d4:30:b0:d7:03:20:2a:d0:f9:63:e8:91:0c:05:20:a9:5f:
439
+ # 19:ca:7b:72:4e:d4:b1:db:d0:96:fb:54:5a:19:2c:0c:08:f7:
440
+ # b2:bc:85:a8:9d:7f:6d:3b:52:b3:2a:db:e7:d4:84:8c:63:f6:
441
+ # 0f:cb:26:01:91:50:6c:f4:5f:14:e2:93:74:c0:13:9e:30:3a:
442
+ # 50:e3:b4:60:c5:1c:f0:22:44:8d:71:47:ac:c8:1a:c9:e9:9b:
443
+ # 9a:00:60:13:ff:70:7e:5f:11:4d:49:1b:b3:15:52:7b:c9:54:
444
+ # da:bf:9d:95:af:6b:9a:d8:9e:e9:f1:e4:43:8d:e2:11:44:3a:
445
+ # bf:af:bd:83:42:73:52:8b:aa:bb:a7:29:cf:f5:64:1c:0a:4d:
446
+ # d1:bc:aa:ac:9f:2a:d0:ff:7f:7f:da:7d:ea:b1:ed:30:25:c1:
447
+ # 84:da:34:d2:5b:78:83:56:ec:9c:36:c3:26:e2:11:f6:67:49:
448
+ # 1d:92:ab:8c:fb:eb:ff:7a:ee:85:4a:a7:50:80:f0:a7:5c:4a:
449
+ # 94:2e:5f:05:99:3c:52:41:e0:cd:b4:63:cf:01:43:ba:9c:83:
450
+ # dc:8f:60:3b:f3:5a:b4:b4:7b:ae:da:0b:90:38:75:ef:81:1d:
451
+ # 66:d2:f7:57:70:36:b3:bf:fc:28:af:71:25:85:5b:13:fe:1e:
452
+ # 7f:5a:b4:3c
453
+ -----BEGIN CERTIFICATE-----
454
+ MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
455
+ VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
456
+ Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
457
+ KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
458
+ cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
459
+ NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
460
+ NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
461
+ ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
462
+ BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
463
+ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
464
+ Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
465
+ 4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
466
+ KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
467
+ rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
468
+ 94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
469
+ sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
470
+ gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
471
+ kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
472
+ vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
473
+ A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
474
+ O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
475
+ AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
476
+ 9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
477
+ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
478
+ 0vdXcDazv/wor3ElhVsT/h5/WrQ8
479
+ -----END CERTIFICATE-----
480
+ # Entrust.net Certification Authority (2048).pem
481
+ # Certificate:
482
+ # Data:
483
+ # Version: 3 (0x2)
484
+ # Serial Number: 946069240 (0x3863def8)
485
+ # Signature Algorithm: sha1WithRSAEncryption
486
+ # Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
487
+ # Validity
488
+ # Not Before: Dec 24 17:50:51 1999 GMT
489
+ # Not After : Jul 24 14:15:12 2029 GMT
490
+ # Subject: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
491
+ # Subject Public Key Info:
492
+ # Public Key Algorithm: rsaEncryption
493
+ # Public-Key: (2048 bit)
494
+ # Modulus:
495
+ # 00:ad:4d:4b:a9:12:86:b2:ea:a3:20:07:15:16:64:
496
+ # 2a:2b:4b:d1:bf:0b:4a:4d:8e:ed:80:76:a5:67:b7:
497
+ # 78:40:c0:73:42:c8:68:c0:db:53:2b:dd:5e:b8:76:
498
+ # 98:35:93:8b:1a:9d:7c:13:3a:0e:1f:5b:b7:1e:cf:
499
+ # e5:24:14:1e:b1:81:a9:8d:7d:b8:cc:6b:4b:03:f1:
500
+ # 02:0c:dc:ab:a5:40:24:00:7f:74:94:a1:9d:08:29:
501
+ # b3:88:0b:f5:87:77:9d:55:cd:e4:c3:7e:d7:6a:64:
502
+ # ab:85:14:86:95:5b:97:32:50:6f:3d:c8:ba:66:0c:
503
+ # e3:fc:bd:b8:49:c1:76:89:49:19:fd:c0:a8:bd:89:
504
+ # a3:67:2f:c6:9f:bc:71:19:60:b8:2d:e9:2c:c9:90:
505
+ # 76:66:7b:94:e2:af:78:d6:65:53:5d:3c:d6:9c:b2:
506
+ # cf:29:03:f9:2f:a4:50:b2:d4:48:ce:05:32:55:8a:
507
+ # fd:b2:64:4c:0e:e4:98:07:75:db:7f:df:b9:08:55:
508
+ # 60:85:30:29:f9:7b:48:a4:69:86:e3:35:3f:1e:86:
509
+ # 5d:7a:7a:15:bd:ef:00:8e:15:22:54:17:00:90:26:
510
+ # 93:bc:0e:49:68:91:bf:f8:47:d3:9d:95:42:c1:0e:
511
+ # 4d:df:6f:26:cf:c3:18:21:62:66:43:70:d6:d5:c0:
512
+ # 07:e1
513
+ # Exponent: 65537 (0x10001)
514
+ # X509v3 extensions:
515
+ # X509v3 Key Usage: critical
516
+ # Certificate Sign, CRL Sign
517
+ # X509v3 Basic Constraints: critical
518
+ # CA:TRUE
519
+ # X509v3 Subject Key Identifier:
520
+ # 55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70
521
+ # Signature Algorithm: sha1WithRSAEncryption
522
+ # 3b:9b:8f:56:9b:30:e7:53:99:7c:7a:79:a7:4d:97:d7:19:95:
523
+ # 90:fb:06:1f:ca:33:7c:46:63:8f:96:66:24:fa:40:1b:21:27:
524
+ # ca:e6:72:73:f2:4f:fe:31:99:fd:c8:0c:4c:68:53:c6:80:82:
525
+ # 13:98:fa:b6:ad:da:5d:3d:f1:ce:6e:f6:15:11:94:82:0c:ee:
526
+ # 3f:95:af:11:ab:0f:d7:2f:de:1f:03:8f:57:2c:1e:c9:bb:9a:
527
+ # 1a:44:95:eb:18:4f:a6:1f:cd:7d:57:10:2f:9b:04:09:5a:84:
528
+ # b5:6e:d8:1d:3a:e1:d6:9e:d1:6c:79:5e:79:1c:14:c5:e3:d0:
529
+ # 4c:93:3b:65:3c:ed:df:3d:be:a6:e5:95:1a:c3:b5:19:c3:bd:
530
+ # 5e:5b:bb:ff:23:ef:68:19:cb:12:93:27:5c:03:2d:6f:30:d0:
531
+ # 1e:b6:1a:ac:de:5a:f7:d1:aa:a8:27:a6:fe:79:81:c4:79:99:
532
+ # 33:57:ba:12:b0:a9:e0:42:6c:93:ca:56:de:fe:6d:84:0b:08:
533
+ # 8b:7e:8d:ea:d7:98:21:c6:f3:e7:3c:79:2f:5e:9c:d1:4c:15:
534
+ # 8d:e1:ec:22:37:cc:9a:43:0b:97:dc:80:90:8d:b3:67:9b:6f:
535
+ # 48:08:15:56:cf:bf:f1:2b:7c:5e:9a:76:e9:59:90:c5:7c:83:
536
+ # 35:11:65:51
537
+ -----BEGIN CERTIFICATE-----
538
+ MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
539
+ RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
540
+ bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
541
+ IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
542
+ ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3
543
+ MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
544
+ LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
545
+ YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
546
+ A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
547
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
548
+ K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
549
+ sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
550
+ MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
551
+ XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
552
+ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
553
+ 4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
554
+ HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub
555
+ j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo
556
+ U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
557
+ zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b
558
+ u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+
559
+ bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er
560
+ fF6adulZkMV8gzURZVE=
561
+ -----END CERTIFICATE-----
562
+ # GeoTrust Global CA.pem
563
+ # Certificate:
564
+ # Data:
565
+ # Version: 3 (0x2)
566
+ # Serial Number: 144470 (0x23456)
567
+ # Signature Algorithm: sha1WithRSAEncryption
568
+ # Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
569
+ # Validity
570
+ # Not Before: May 21 04:00:00 2002 GMT
571
+ # Not After : May 21 04:00:00 2022 GMT
572
+ # Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
573
+ # Subject Public Key Info:
574
+ # Public Key Algorithm: rsaEncryption
575
+ # Public-Key: (2048 bit)
576
+ # Modulus:
577
+ # 00:da:cc:18:63:30:fd:f4:17:23:1a:56:7e:5b:df:
578
+ # 3c:6c:38:e4:71:b7:78:91:d4:bc:a1:d8:4c:f8:a8:
579
+ # 43:b6:03:e9:4d:21:07:08:88:da:58:2f:66:39:29:
580
+ # bd:05:78:8b:9d:38:e8:05:b7:6a:7e:71:a4:e6:c4:
581
+ # 60:a6:b0:ef:80:e4:89:28:0f:9e:25:d6:ed:83:f3:
582
+ # ad:a6:91:c7:98:c9:42:18:35:14:9d:ad:98:46:92:
583
+ # 2e:4f:ca:f1:87:43:c1:16:95:57:2d:50:ef:89:2d:
584
+ # 80:7a:57:ad:f2:ee:5f:6b:d2:00:8d:b9:14:f8:14:
585
+ # 15:35:d9:c0:46:a3:7b:72:c8:91:bf:c9:55:2b:cd:
586
+ # d0:97:3e:9c:26:64:cc:df:ce:83:19:71:ca:4e:e6:
587
+ # d4:d5:7b:a9:19:cd:55:de:c8:ec:d2:5e:38:53:e5:
588
+ # 5c:4f:8c:2d:fe:50:23:36:fc:66:e6:cb:8e:a4:39:
589
+ # 19:00:b7:95:02:39:91:0b:0e:fe:38:2e:d1:1d:05:
590
+ # 9a:f6:4d:3e:6f:0f:07:1d:af:2c:1e:8f:60:39:e2:
591
+ # fa:36:53:13:39:d4:5e:26:2b:db:3d:a8:14:bd:32:
592
+ # eb:18:03:28:52:04:71:e5:ab:33:3d:e1:38:bb:07:
593
+ # 36:84:62:9c:79:ea:16:30:f4:5f:c0:2b:e8:71:6b:
594
+ # e4:f9
595
+ # Exponent: 65537 (0x10001)
596
+ # X509v3 extensions:
597
+ # X509v3 Basic Constraints: critical
598
+ # CA:TRUE
599
+ # X509v3 Subject Key Identifier:
600
+ # C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E
601
+ # X509v3 Authority Key Identifier:
602
+ # keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E
603
+ #
604
+ # Signature Algorithm: sha1WithRSAEncryption
605
+ # 35:e3:29:6a:e5:2f:5d:54:8e:29:50:94:9f:99:1a:14:e4:8f:
606
+ # 78:2a:62:94:a2:27:67:9e:d0:cf:1a:5e:47:e9:c1:b2:a4:cf:
607
+ # dd:41:1a:05:4e:9b:4b:ee:4a:6f:55:52:b3:24:a1:37:0a:eb:
608
+ # 64:76:2a:2e:2c:f3:fd:3b:75:90:bf:fa:71:d8:c7:3d:37:d2:
609
+ # b5:05:95:62:b9:a6:de:89:3d:36:7b:38:77:48:97:ac:a6:20:
610
+ # 8f:2e:a6:c9:0c:c2:b2:99:45:00:c7:ce:11:51:22:22:e0:a5:
611
+ # ea:b6:15:48:09:64:ea:5e:4f:74:f7:05:3e:c7:8a:52:0c:db:
612
+ # 15:b4:bd:6d:9b:e5:c6:b1:54:68:a9:e3:69:90:b6:9a:a5:0f:
613
+ # b8:b9:3f:20:7d:ae:4a:b5:b8:9c:e4:1d:b6:ab:e6:94:a5:c1:
614
+ # c7:83:ad:db:f5:27:87:0e:04:6c:d5:ff:dd:a0:5d:ed:87:52:
615
+ # b7:2b:15:02:ae:39:a6:6a:74:e9:da:c4:e7:bc:4d:34:1e:a9:
616
+ # 5c:4d:33:5f:92:09:2f:88:66:5d:77:97:c7:1d:76:13:a9:d5:
617
+ # e5:f1:16:09:11:35:d5:ac:db:24:71:70:2c:98:56:0b:d9:17:
618
+ # b4:d1:e3:51:2b:5e:75:e8:d5:d0:dc:4f:34:ed:c2:05:66:80:
619
+ # a1:cb:e6:33
620
+ -----BEGIN CERTIFICATE-----
621
+ MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
622
+ MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
623
+ YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
624
+ EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
625
+ R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
626
+ 9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
627
+ fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
628
+ iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
629
+ 1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
630
+ bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
631
+ MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
632
+ ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
633
+ uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
634
+ Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
635
+ tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
636
+ PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
637
+ hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
638
+ 5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
639
+ -----END CERTIFICATE-----
640
+ # GeoTrust Primary Certification Authority - G2.pem
641
+ # Certificate:
642
+ # Data:
643
+ # Version: 3 (0x2)
644
+ # Serial Number:
645
+ # 3c:b2:f4:48:0a:00:e2:fe:eb:24:3b:5e:60:3e:c3:6b
646
+ # Signature Algorithm: ecdsa-with-SHA384
647
+ # Issuer: C=US, O=GeoTrust Inc., OU=(c) 2007 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G2
648
+ # Validity
649
+ # Not Before: Nov 5 00:00:00 2007 GMT
650
+ # Not After : Jan 18 23:59:59 2038 GMT
651
+ # Subject: C=US, O=GeoTrust Inc., OU=(c) 2007 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G2
652
+ # Subject Public Key Info:
653
+ # Public Key Algorithm: id-ecPublicKey
654
+ # Public-Key: (384 bit)
655
+ # pub:
656
+ # 04:15:b1:e8:fd:03:15:43:e5:ac:eb:87:37:11:62:
657
+ # ef:d2:83:36:52:7d:45:57:0b:4a:8d:7b:54:3b:3a:
658
+ # 6e:5f:15:02:c0:50:a6:cf:25:2f:7d:ca:48:b8:c7:
659
+ # 50:63:1c:2a:21:08:7c:9a:36:d8:0b:fe:d1:26:c5:
660
+ # 58:31:30:28:25:f3:5d:5d:a3:b8:b6:a5:b4:92:ed:
661
+ # 6c:2c:9f:eb:dd:43:89:a2:3c:4b:48:91:1d:50:ec:
662
+ # 26:df:d6:60:2e:bd:21
663
+ # ASN1 OID: secp384r1
664
+ # X509v3 extensions:
665
+ # X509v3 Basic Constraints: critical
666
+ # CA:TRUE
667
+ # X509v3 Key Usage: critical
668
+ # Certificate Sign, CRL Sign
669
+ # X509v3 Subject Key Identifier:
670
+ # 15:5F:35:57:51:55:FB:25:B2:AD:03:69:FC:01:A3:FA:BE:11:55:D5
671
+ # Signature Algorithm: ecdsa-with-SHA384
672
+ # 30:64:02:30:64:96:59:a6:e8:09:de:8b:ba:fa:5a:88:88:f0:
673
+ # 1f:91:d3:46:a8:f2:4a:4c:02:63:fb:6c:5f:38:db:2e:41:93:
674
+ # a9:0e:e6:9d:dc:31:1c:b2:a0:a7:18:1c:79:e1:c7:36:02:30:
675
+ # 3a:56:af:9a:74:6c:f6:fb:83:e0:33:d3:08:5f:a1:9c:c2:5b:
676
+ # 9f:46:d6:b6:cb:91:06:63:a2:06:e7:33:ac:3e:a8:81:12:d0:
677
+ # cb:ba:d0:92:0b:b6:9e:96:aa:04:0f:8a
678
+ -----BEGIN CERTIFICATE-----
679
+ MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
680
+ MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
681
+ KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
682
+ MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
683
+ eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
684
+ BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
685
+ NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
686
+ BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
687
+ MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
688
+ So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
689
+ tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
690
+ BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
691
+ CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
692
+ qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
693
+ rD6ogRLQy7rQkgu2npaqBA+K
694
+ -----END CERTIFICATE-----
695
+ # GeoTrust Primary Certification Authority - G3.pem
696
+ # Certificate:
697
+ # Data:
698
+ # Version: 3 (0x2)
699
+ # Serial Number:
700
+ # 15:ac:6e:94:19:b2:79:4b:41:f6:27:a9:c3:18:0f:1f
701
+ # Signature Algorithm: sha256WithRSAEncryption
702
+ # Issuer: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3
703
+ # Validity
704
+ # Not Before: Apr 2 00:00:00 2008 GMT
705
+ # Not After : Dec 1 23:59:59 2037 GMT
706
+ # Subject: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3
707
+ # Subject Public Key Info:
708
+ # Public Key Algorithm: rsaEncryption
709
+ # Public-Key: (2048 bit)
710
+ # Modulus:
711
+ # 00:dc:e2:5e:62:58:1d:33:57:39:32:33:fa:eb:cb:
712
+ # 87:8c:a7:d4:4a:dd:06:88:ea:64:8e:31:98:a5:38:
713
+ # 90:1e:98:cf:2e:63:2b:f0:46:bc:44:b2:89:a1:c0:
714
+ # 28:0c:49:70:21:95:9f:64:c0:a6:93:12:02:65:26:
715
+ # 86:c6:a5:89:f0:fa:d7:84:a0:70:af:4f:1a:97:3f:
716
+ # 06:44:d5:c9:eb:72:10:7d:e4:31:28:fb:1c:61:e6:
717
+ # 28:07:44:73:92:22:69:a7:03:88:6c:9d:63:c8:52:
718
+ # da:98:27:e7:08:4c:70:3e:b4:c9:12:c1:c5:67:83:
719
+ # 5d:33:f3:03:11:ec:6a:d0:53:e2:d1:ba:36:60:94:
720
+ # 80:bb:61:63:6c:5b:17:7e:df:40:94:1e:ab:0d:c2:
721
+ # 21:28:70:88:ff:d6:26:6c:6c:60:04:25:4e:55:7e:
722
+ # 7d:ef:bf:94:48:de:b7:1d:dd:70:8d:05:5f:88:a5:
723
+ # 9b:f2:c2:ee:ea:d1:40:41:6d:62:38:1d:56:06:c5:
724
+ # 03:47:51:20:19:fc:7b:10:0b:0e:62:ae:76:55:bf:
725
+ # 5f:77:be:3e:49:01:53:3d:98:25:03:76:24:5a:1d:
726
+ # b4:db:89:ea:79:e5:b6:b3:3b:3f:ba:4c:28:41:7f:
727
+ # 06:ac:6a:8e:c1:d0:f6:05:1d:7d:e6:42:86:e3:a5:
728
+ # d5:47
729
+ # Exponent: 65537 (0x10001)
730
+ # X509v3 extensions:
731
+ # X509v3 Basic Constraints: critical
732
+ # CA:TRUE
733
+ # X509v3 Key Usage: critical
734
+ # Certificate Sign, CRL Sign
735
+ # X509v3 Subject Key Identifier:
736
+ # C4:79:CA:8E:A1:4E:03:1D:1C:DC:6B:DB:31:5B:94:3E:3F:30:7F:2D
737
+ # Signature Algorithm: sha256WithRSAEncryption
738
+ # 2d:c5:13:cf:56:80:7b:7a:78:bd:9f:ae:2c:99:e7:ef:da:df:
739
+ # 94:5e:09:69:a7:e7:6e:68:8c:bd:72:be:47:a9:0e:97:12:b8:
740
+ # 4a:f1:64:d3:39:df:25:34:d4:c1:cd:4e:81:f0:0f:04:c4:24:
741
+ # b3:34:96:c6:a6:aa:30:df:68:61:73:d7:f9:8e:85:89:ef:0e:
742
+ # 5e:95:28:4a:2a:27:8f:10:8e:2e:7c:86:c4:02:9e:da:0c:77:
743
+ # 65:0e:44:0d:92:fd:fd:b3:16:36:fa:11:0d:1d:8c:0e:07:89:
744
+ # 6a:29:56:f7:72:f4:dd:15:9c:77:35:66:57:ab:13:53:d8:8e:
745
+ # c1:40:c5:d7:13:16:5a:72:c7:b7:69:01:c4:7a:b1:83:01:68:
746
+ # 7d:8d:41:a1:94:18:c1:25:5c:fc:f0:fe:83:02:87:7c:0d:0d:
747
+ # cf:2e:08:5c:4a:40:0d:3e:ec:81:61:e6:24:db:ca:e0:0e:2d:
748
+ # 07:b2:3e:56:dc:8d:f5:41:85:07:48:9b:0c:0b:cb:49:3f:7d:
749
+ # ec:b7:fd:cb:8d:67:89:1a:ab:ed:bb:1e:a3:00:08:08:17:2a:
750
+ # 82:5c:31:5d:46:8a:2d:0f:86:9b:74:d9:45:fb:d4:40:b1:7a:
751
+ # aa:68:2d:86:b2:99:22:e1:c1:2b:c7:9c:f8:f3:5f:a8:82:12:
752
+ # eb:19:11:2d
753
+ -----BEGIN CERTIFICATE-----
754
+ MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
755
+ mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
756
+ MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
757
+ eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
758
+ cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ
759
+ BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
760
+ MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0
761
+ BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
762
+ LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz
763
+ +uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm
764
+ hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn
765
+ 5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W
766
+ JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL
767
+ DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC
768
+ huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
769
+ HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB
770
+ AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB
771
+ zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN
772
+ kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
773
+ AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
774
+ SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
775
+ spki4cErx5z481+oghLrGREt
776
+ -----END CERTIFICATE-----
777
+ # GeoTrust Primary Certification Authority.pem
778
+ # Certificate:
779
+ # Data:
780
+ # Version: 3 (0x2)
781
+ # Serial Number:
782
+ # 18:ac:b5:6a:fd:69:b6:15:3a:63:6c:af:da:fa:c4:a1
783
+ # Signature Algorithm: sha1WithRSAEncryption
784
+ # Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority
785
+ # Validity
786
+ # Not Before: Nov 27 00:00:00 2006 GMT
787
+ # Not After : Jul 16 23:59:59 2036 GMT
788
+ # Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority
789
+ # Subject Public Key Info:
790
+ # Public Key Algorithm: rsaEncryption
791
+ # Public-Key: (2048 bit)
792
+ # Modulus:
793
+ # 00:be:b8:15:7b:ff:d4:7c:7d:67:ad:83:64:7b:c8:
794
+ # 42:53:2d:df:f6:84:08:20:61:d6:01:59:6a:9c:44:
795
+ # 11:af:ef:76:fd:95:7e:ce:61:30:bb:7a:83:5f:02:
796
+ # bd:01:66:ca:ee:15:8d:6f:a1:30:9c:bd:a1:85:9e:
797
+ # 94:3a:f3:56:88:00:31:cf:d8:ee:6a:96:02:d9:ed:
798
+ # 03:8c:fb:75:6d:e7:ea:b8:55:16:05:16:9a:f4:e0:
799
+ # 5e:b1:88:c0:64:85:5c:15:4d:88:c7:b7:ba:e0:75:
800
+ # e9:ad:05:3d:9d:c7:89:48:e0:bb:28:c8:03:e1:30:
801
+ # 93:64:5e:52:c0:59:70:22:35:57:88:8a:f1:95:0a:
802
+ # 83:d7:bc:31:73:01:34:ed:ef:46:71:e0:6b:02:a8:
803
+ # 35:72:6b:97:9b:66:e0:cb:1c:79:5f:d8:1a:04:68:
804
+ # 1e:47:02:e6:9d:60:e2:36:97:01:df:ce:35:92:df:
805
+ # be:67:c7:6d:77:59:3b:8f:9d:d6:90:15:94:bc:42:
806
+ # 34:10:c1:39:f9:b1:27:3e:7e:d6:8a:75:c5:b2:af:
807
+ # 96:d3:a2:de:9b:e4:98:be:7d:e1:e9:81:ad:b6:6f:
808
+ # fc:d7:0e:da:e0:34:b0:0d:1a:77:e7:e3:08:98:ef:
809
+ # 58:fa:9c:84:b7:36:af:c2:df:ac:d2:f4:10:06:70:
810
+ # 71:35
811
+ # Exponent: 65537 (0x10001)
812
+ # X509v3 extensions:
813
+ # X509v3 Basic Constraints: critical
814
+ # CA:TRUE
815
+ # X509v3 Key Usage: critical
816
+ # Certificate Sign, CRL Sign
817
+ # X509v3 Subject Key Identifier:
818
+ # 2C:D5:50:41:97:15:8B:F0:8F:36:61:5B:4A:FB:6B:D9:99:C9:33:92
819
+ # Signature Algorithm: sha1WithRSAEncryption
820
+ # 5a:70:7f:2c:dd:b7:34:4f:f5:86:51:a9:26:be:4b:b8:aa:f1:
821
+ # 71:0d:dc:61:c7:a0:ea:34:1e:7a:77:0f:04:35:e8:27:8f:6c:
822
+ # 90:bf:91:16:24:46:3e:4a:4e:ce:2b:16:d5:0b:52:1d:fc:1f:
823
+ # 67:a2:02:45:31:4f:ce:f3:fa:03:a7:79:9d:53:6a:d9:da:63:
824
+ # 3a:f8:80:d7:d3:99:e1:a5:e1:be:d4:55:71:98:35:3a:be:93:
825
+ # ea:ae:ad:42:b2:90:6f:e0:fc:21:4d:35:63:33:89:49:d6:9b:
826
+ # 4e:ca:c7:e7:4e:09:00:f7:da:c7:ef:99:62:99:77:b6:95:22:
827
+ # 5e:8a:a0:ab:f4:b8:78:98:ca:38:19:99:c9:72:9e:78:cd:4b:
828
+ # ac:af:19:a0:73:12:2d:fc:c2:41:ba:81:91:da:16:5a:31:b7:
829
+ # f9:b4:71:80:12:48:99:72:73:5a:59:53:c1:63:52:33:ed:a7:
830
+ # c9:d2:39:02:70:fa:e0:b1:42:66:29:aa:9b:51:ed:30:54:22:
831
+ # 14:5f:d9:ab:1d:c1:e4:94:f0:f8:f5:2b:f7:ea:ca:78:46:d6:
832
+ # b8:91:fd:a6:0d:2b:1a:14:01:3e:80:f0:42:a0:95:07:5e:6d:
833
+ # cd:cc:4b:a4:45:8d:ab:12:e8:b3:de:5a:e5:a0:7c:e8:0f:22:
834
+ # 1d:5a:e9:59
835
+ -----BEGIN CERTIFICATE-----
836
+ MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
837
+ MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
838
+ R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
839
+ MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
840
+ Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
841
+ ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
842
+ AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
843
+ AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
844
+ ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
845
+ 7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
846
+ kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
847
+ mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
848
+ A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
849
+ KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
850
+ 6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
851
+ 4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
852
+ oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
853
+ UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
854
+ AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
855
+ -----END CERTIFICATE-----
856
+ # Go Daddy Class 2 Certification Authority.pem
857
+ # Certificate:
858
+ # Data:
859
+ # Version: 3 (0x2)
860
+ # Serial Number: 0 (0x0)
861
+ # Signature Algorithm: sha1WithRSAEncryption
862
+ # Issuer: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
863
+ # Validity
864
+ # Not Before: Jun 29 17:06:20 2004 GMT
865
+ # Not After : Jun 29 17:06:20 2034 GMT
866
+ # Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
867
+ # Subject Public Key Info:
868
+ # Public Key Algorithm: rsaEncryption
869
+ # Public-Key: (2048 bit)
870
+ # Modulus:
871
+ # 00:de:9d:d7:ea:57:18:49:a1:5b:eb:d7:5f:48:86:
872
+ # ea:be:dd:ff:e4:ef:67:1c:f4:65:68:b3:57:71:a0:
873
+ # 5e:77:bb:ed:9b:49:e9:70:80:3d:56:18:63:08:6f:
874
+ # da:f2:cc:d0:3f:7f:02:54:22:54:10:d8:b2:81:d4:
875
+ # c0:75:3d:4b:7f:c7:77:c3:3e:78:ab:1a:03:b5:20:
876
+ # 6b:2f:6a:2b:b1:c5:88:7e:c4:bb:1e:b0:c1:d8:45:
877
+ # 27:6f:aa:37:58:f7:87:26:d7:d8:2d:f6:a9:17:b7:
878
+ # 1f:72:36:4e:a6:17:3f:65:98:92:db:2a:6e:5d:a2:
879
+ # fe:88:e0:0b:de:7f:e5:8d:15:e1:eb:cb:3a:d5:e2:
880
+ # 12:a2:13:2d:d8:8e:af:5f:12:3d:a0:08:05:08:b6:
881
+ # 5c:a5:65:38:04:45:99:1e:a3:60:60:74:c5:41:a5:
882
+ # 72:62:1b:62:c5:1f:6f:5f:1a:42:be:02:51:65:a8:
883
+ # ae:23:18:6a:fc:78:03:a9:4d:7f:80:c3:fa:ab:5a:
884
+ # fc:a1:40:a4:ca:19:16:fe:b2:c8:ef:5e:73:0d:ee:
885
+ # 77:bd:9a:f6:79:98:bc:b1:07:67:a2:15:0d:dd:a0:
886
+ # 58:c6:44:7b:0a:3e:62:28:5f:ba:41:07:53:58:cf:
887
+ # 11:7e:38:74:c5:f8:ff:b5:69:90:8f:84:74:ea:97:
888
+ # 1b:af
889
+ # Exponent: 3 (0x3)
890
+ # X509v3 extensions:
891
+ # X509v3 Subject Key Identifier:
892
+ # D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3
893
+ # X509v3 Authority Key Identifier:
894
+ # keyid:D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3
895
+ # DirName:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
896
+ # serial:00
897
+ #
898
+ # X509v3 Basic Constraints:
899
+ # CA:TRUE
900
+ # Signature Algorithm: sha1WithRSAEncryption
901
+ # 32:4b:f3:b2:ca:3e:91:fc:12:c6:a1:07:8c:8e:77:a0:33:06:
902
+ # 14:5c:90:1e:18:f7:08:a6:3d:0a:19:f9:87:80:11:6e:69:e4:
903
+ # 96:17:30:ff:34:91:63:72:38:ee:cc:1c:01:a3:1d:94:28:a4:
904
+ # 31:f6:7a:c4:54:d7:f6:e5:31:58:03:a2:cc:ce:62:db:94:45:
905
+ # 73:b5:bf:45:c9:24:b5:d5:82:02:ad:23:79:69:8d:b8:b6:4d:
906
+ # ce:cf:4c:ca:33:23:e8:1c:88:aa:9d:8b:41:6e:16:c9:20:e5:
907
+ # 89:9e:cd:3b:da:70:f7:7e:99:26:20:14:54:25:ab:6e:73:85:
908
+ # e6:9b:21:9d:0a:6c:82:0e:a8:f8:c2:0c:fa:10:1e:6c:96:ef:
909
+ # 87:0d:c4:0f:61:8b:ad:ee:83:2b:95:f8:8e:92:84:72:39:eb:
910
+ # 20:ea:83:ed:83:cd:97:6e:08:bc:eb:4e:26:b6:73:2b:e4:d3:
911
+ # f6:4c:fe:26:71:e2:61:11:74:4a:ff:57:1a:87:0f:75:48:2e:
912
+ # cf:51:69:17:a0:02:12:61:95:d5:d1:40:b2:10:4c:ee:c4:ac:
913
+ # 10:43:a6:a5:9e:0a:d5:95:62:9a:0d:cf:88:82:c5:32:0c:e4:
914
+ # 2b:9f:45:e6:0d:9f:28:9c:b1:b9:2a:5a:57:ad:37:0f:af:1d:
915
+ # 7f:db:bd:9f
916
+ -----BEGIN CERTIFICATE-----
917
+ MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
918
+ MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
919
+ YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
920
+ MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
921
+ ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
922
+ MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
923
+ ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
924
+ PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
925
+ wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
926
+ EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
927
+ avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
928
+ YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
929
+ sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
930
+ /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
931
+ IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
932
+ YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
933
+ ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
934
+ OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
935
+ TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
936
+ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
937
+ dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
938
+ ReYNnyicsbkqWletNw+vHX/bvZ8=
939
+ -----END CERTIFICATE-----
940
+ # Go Daddy Root Certificate Authority - G2.pem
941
+ # Certificate:
942
+ # Data:
943
+ # Version: 3 (0x2)
944
+ # Serial Number: 0 (0x0)
945
+ # Signature Algorithm: sha256WithRSAEncryption
946
+ # Issuer: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2
947
+ # Validity
948
+ # Not Before: Sep 1 00:00:00 2009 GMT
949
+ # Not After : Dec 31 23:59:59 2037 GMT
950
+ # Subject: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2
951
+ # Subject Public Key Info:
952
+ # Public Key Algorithm: rsaEncryption
953
+ # Public-Key: (2048 bit)
954
+ # Modulus:
955
+ # 00:bf:71:62:08:f1:fa:59:34:f7:1b:c9:18:a3:f7:
956
+ # 80:49:58:e9:22:83:13:a6:c5:20:43:01:3b:84:f1:
957
+ # e6:85:49:9f:27:ea:f6:84:1b:4e:a0:b4:db:70:98:
958
+ # c7:32:01:b1:05:3e:07:4e:ee:f4:fa:4f:2f:59:30:
959
+ # 22:e7:ab:19:56:6b:e2:80:07:fc:f3:16:75:80:39:
960
+ # 51:7b:e5:f9:35:b6:74:4e:a9:8d:82:13:e4:b6:3f:
961
+ # a9:03:83:fa:a2:be:8a:15:6a:7f:de:0b:c3:b6:19:
962
+ # 14:05:ca:ea:c3:a8:04:94:3b:46:7c:32:0d:f3:00:
963
+ # 66:22:c8:8d:69:6d:36:8c:11:18:b7:d3:b2:1c:60:
964
+ # b4:38:fa:02:8c:ce:d3:dd:46:07:de:0a:3e:eb:5d:
965
+ # 7c:c8:7c:fb:b0:2b:53:a4:92:62:69:51:25:05:61:
966
+ # 1a:44:81:8c:2c:a9:43:96:23:df:ac:3a:81:9a:0e:
967
+ # 29:c5:1c:a9:e9:5d:1e:b6:9e:9e:30:0a:39:ce:f1:
968
+ # 88:80:fb:4b:5d:cc:32:ec:85:62:43:25:34:02:56:
969
+ # 27:01:91:b4:3b:70:2a:3f:6e:b1:e8:9c:88:01:7d:
970
+ # 9f:d4:f9:db:53:6d:60:9d:bf:2c:e7:58:ab:b8:5f:
971
+ # 46:fc:ce:c4:1b:03:3c:09:eb:49:31:5c:69:46:b3:
972
+ # e0:47
973
+ # Exponent: 65537 (0x10001)
974
+ # X509v3 extensions:
975
+ # X509v3 Basic Constraints: critical
976
+ # CA:TRUE
977
+ # X509v3 Key Usage: critical
978
+ # Certificate Sign, CRL Sign
979
+ # X509v3 Subject Key Identifier:
980
+ # 3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE
981
+ # Signature Algorithm: sha256WithRSAEncryption
982
+ # 99:db:5d:79:d5:f9:97:59:67:03:61:f1:7e:3b:06:31:75:2d:
983
+ # a1:20:8e:4f:65:87:b4:f7:a6:9c:bc:d8:e9:2f:d0:db:5a:ee:
984
+ # cf:74:8c:73:b4:38:42:da:05:7b:f8:02:75:b8:fd:a5:b1:d7:
985
+ # ae:f6:d7:de:13:cb:53:10:7e:8a:46:d1:97:fa:b7:2e:2b:11:
986
+ # ab:90:b0:27:80:f9:e8:9f:5a:e9:37:9f:ab:e4:df:6c:b3:85:
987
+ # 17:9d:3d:d9:24:4f:79:91:35:d6:5f:04:eb:80:83:ab:9a:02:
988
+ # 2d:b5:10:f4:d8:90:c7:04:73:40:ed:72:25:a0:a9:9f:ec:9e:
989
+ # ab:68:12:99:57:c6:8f:12:3a:09:a4:bd:44:fd:06:15:37:c1:
990
+ # 9b:e4:32:a3:ed:38:e8:d8:64:f3:2c:7e:14:fc:02:ea:9f:cd:
991
+ # ff:07:68:17:db:22:90:38:2d:7a:8d:d1:54:f1:69:e3:5f:33:
992
+ # ca:7a:3d:7b:0a:e3:ca:7f:5f:39:e5:e2:75:ba:c5:76:18:33:
993
+ # ce:2c:f0:2f:4c:ad:f7:b1:e7:ce:4f:a8:c4:9b:4a:54:06:c5:
994
+ # 7f:7d:d5:08:0f:e2:1c:fe:7e:17:b8:ac:5e:f6:d4:16:b2:43:
995
+ # 09:0c:4d:f6:a7:6b:b4:99:84:65:ca:7a:88:e2:e2:44:be:5c:
996
+ # f7:ea:1c:f5
997
+ -----BEGIN CERTIFICATE-----
998
+ MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
999
+ EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
1000
+ EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
1001
+ ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
1002
+ NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
1003
+ EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
1004
+ AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
1005
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
1006
+ E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
1007
+ /PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
1008
+ DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
1009
+ GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
1010
+ tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
1011
+ AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
1012
+ FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
1013
+ WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
1014
+ 9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
1015
+ gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
1016
+ 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
1017
+ LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
1018
+ 4uJEvlz36hz1
1019
+ -----END CERTIFICATE-----
1020
+ # Go Daddy Secure Certification Authority serialNumber=07969287.pem
1021
+ # Certificate:
1022
+ # Data:
1023
+ # Version: 3 (0x2)
1024
+ # Serial Number: 769 (0x301)
1025
+ # Signature Algorithm: sha1WithRSAEncryption
1026
+ # Issuer: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
1027
+ # Validity
1028
+ # Not Before: Nov 16 01:54:37 2006 GMT
1029
+ # Not After : Nov 16 01:54:37 2026 GMT
1030
+ # Subject: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., OU=http://certificates.godaddy.com/repository, CN=Go Daddy Secure Certification Authority/serialNumber=07969287
1031
+ # Subject Public Key Info:
1032
+ # Public Key Algorithm: rsaEncryption
1033
+ # Public-Key: (2048 bit)
1034
+ # Modulus:
1035
+ # 00:c4:2d:d5:15:8c:9c:26:4c:ec:32:35:eb:5f:b8:
1036
+ # 59:01:5a:a6:61:81:59:3b:70:63:ab:e3:dc:3d:c7:
1037
+ # 2a:b8:c9:33:d3:79:e4:3a:ed:3c:30:23:84:8e:b3:
1038
+ # 30:14:b6:b2:87:c3:3d:95:54:04:9e:df:99:dd:0b:
1039
+ # 25:1e:21:de:65:29:7e:35:a8:a9:54:eb:f6:f7:32:
1040
+ # 39:d4:26:55:95:ad:ef:fb:fe:58:86:d7:9e:f4:00:
1041
+ # 8d:8c:2a:0c:bd:42:04:ce:a7:3f:04:f6:ee:80:f2:
1042
+ # aa:ef:52:a1:69:66:da:be:1a:ad:5d:da:2c:66:ea:
1043
+ # 1a:6b:bb:e5:1a:51:4a:00:2f:48:c7:98:75:d8:b9:
1044
+ # 29:c8:ee:f8:66:6d:0a:9c:b3:f3:fc:78:7c:a2:f8:
1045
+ # a3:f2:b5:c3:f3:b9:7a:91:c1:a7:e6:25:2e:9c:a8:
1046
+ # ed:12:65:6e:6a:f6:12:44:53:70:30:95:c3:9c:2b:
1047
+ # 58:2b:3d:08:74:4a:f2:be:51:b0:bf:87:d0:4c:27:
1048
+ # 58:6b:b5:35:c5:9d:af:17:31:f8:0b:8f:ee:ad:81:
1049
+ # 36:05:89:08:98:cf:3a:af:25:87:c0:49:ea:a7:fd:
1050
+ # 67:f7:45:8e:97:cc:14:39:e2:36:85:b5:7e:1a:37:
1051
+ # fd:16:f6:71:11:9a:74:30:16:fe:13:94:a3:3f:84:
1052
+ # 0d:4f
1053
+ # Exponent: 65537 (0x10001)
1054
+ # X509v3 extensions:
1055
+ # X509v3 Subject Key Identifier:
1056
+ # FD:AC:61:32:93:6C:45:D6:E2:EE:85:5F:9A:BA:E7:76:99:68:CC:E7
1057
+ # X509v3 Authority Key Identifier:
1058
+ # keyid:D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3
1059
+ #
1060
+ # X509v3 Basic Constraints: critical
1061
+ # CA:TRUE, pathlen:0
1062
+ # Authority Information Access:
1063
+ # OCSP - URI:http://ocsp.godaddy.com
1064
+ #
1065
+ # X509v3 CRL Distribution Points:
1066
+ #
1067
+ # Full Name:
1068
+ # URI:http://certificates.godaddy.com/repository/gdroot.crl
1069
+ #
1070
+ # X509v3 Certificate Policies:
1071
+ # Policy: X509v3 Any Policy
1072
+ # CPS: http://certificates.godaddy.com/repository
1073
+ #
1074
+ # X509v3 Key Usage: critical
1075
+ # Certificate Sign, CRL Sign
1076
+ # Signature Algorithm: sha1WithRSAEncryption
1077
+ # d2:86:c0:ec:bd:f9:a1:b6:67:ee:66:0b:a2:06:3a:04:50:8e:
1078
+ # 15:72:ac:4a:74:95:53:cb:37:cb:44:49:ef:07:90:6b:33:d9:
1079
+ # 96:f0:94:56:a5:13:30:05:3c:85:32:21:7b:c9:c7:0a:a8:24:
1080
+ # a4:90:de:46:d3:25:23:14:03:67:c2:10:d6:6f:0f:5d:7b:7a:
1081
+ # cc:9f:c5:58:2a:c1:c4:9e:21:a8:5a:f3:ac:a4:46:f3:9e:e4:
1082
+ # 63:cb:2f:90:a4:29:29:01:d9:72:2c:29:df:37:01:27:bc:4f:
1083
+ # ee:68:d3:21:8f:c0:b3:e4:f5:09:ed:d2:10:aa:53:b4:be:f0:
1084
+ # cc:59:0b:d6:3b:96:1c:95:24:49:df:ce:ec:fd:a7:48:91:14:
1085
+ # 45:0e:3a:36:6f:da:45:b3:45:a2:41:c9:d4:d7:44:4e:3e:b9:
1086
+ # 74:76:d5:a2:13:55:2c:c6:87:a3:b5:99:ac:06:84:87:7f:75:
1087
+ # 06:fc:bf:14:4c:0e:cc:6e:c4:df:3d:b7:12:71:f4:e8:f1:51:
1088
+ # 40:22:28:49:e0:1d:4b:87:a8:34:cc:06:a2:dd:12:5a:d1:86:
1089
+ # 36:64:03:35:6f:6f:77:6e:eb:f2:85:50:98:5e:ab:03:53:ad:
1090
+ # 91:23:63:1f:16:9c:cd:b9:b2:05:63:3a:e1:f4:68:1b:17:05:
1091
+ # 35:95:53:ee
1092
+ -----BEGIN CERTIFICATE-----
1093
+ MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx
1094
+ ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
1095
+ RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw
1096
+ MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH
1097
+ QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j
1098
+ b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j
1099
+ b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj
1100
+ YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN
1101
+ AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H
1102
+ KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm
1103
+ VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR
1104
+ SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT
1105
+ cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ
1106
+ 6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu
1107
+ MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS
1108
+ kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB
1109
+ BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f
1110
+ BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv
1111
+ c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH
1112
+ AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO
1113
+ BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG
1114
+ OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU
1115
+ A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o
1116
+ 0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX
1117
+ RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH
1118
+ qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV
1119
+ U+4=
1120
+ -----END CERTIFICATE-----
1121
+ # Thawte Premium Server CA.pem
1122
+ # Certificate:
1123
+ # Data:
1124
+ # Version: 3 (0x2)
1125
+ # Serial Number: 1 (0x1)
1126
+ # Signature Algorithm: md5WithRSAEncryption
1127
+ # Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
1128
+ # Validity
1129
+ # Not Before: Aug 1 00:00:00 1996 GMT
1130
+ # Not After : Dec 31 23:59:59 2020 GMT
1131
+ # Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
1132
+ # Subject Public Key Info:
1133
+ # Public Key Algorithm: rsaEncryption
1134
+ # Public-Key: (1024 bit)
1135
+ # Modulus:
1136
+ # 00:d2:36:36:6a:8b:d7:c2:5b:9e:da:81:41:62:8f:
1137
+ # 38:ee:49:04:55:d6:d0:ef:1c:1b:95:16:47:ef:18:
1138
+ # 48:35:3a:52:f4:2b:6a:06:8f:3b:2f:ea:56:e3:af:
1139
+ # 86:8d:9e:17:f7:9e:b4:65:75:02:4d:ef:cb:09:a2:
1140
+ # 21:51:d8:9b:d0:67:d0:ba:0d:92:06:14:73:d4:93:
1141
+ # cb:97:2a:00:9c:5c:4e:0c:bc:fa:15:52:fc:f2:44:
1142
+ # 6e:da:11:4a:6e:08:9f:2f:2d:e3:f9:aa:3a:86:73:
1143
+ # b6:46:53:58:c8:89:05:bd:83:11:b8:73:3f:aa:07:
1144
+ # 8d:f4:42:4d:e7:40:9d:1c:37
1145
+ # Exponent: 65537 (0x10001)
1146
+ # X509v3 extensions:
1147
+ # X509v3 Basic Constraints: critical
1148
+ # CA:TRUE
1149
+ # Signature Algorithm: md5WithRSAEncryption
1150
+ # 26:48:2c:16:c2:58:fa:e8:16:74:0c:aa:aa:5f:54:3f:f2:d7:
1151
+ # c9:78:60:5e:5e:6e:37:63:22:77:36:7e:b2:17:c4:34:b9:f5:
1152
+ # 08:85:fc:c9:01:38:ff:4d:be:f2:16:42:43:e7:bb:5a:46:fb:
1153
+ # c1:c6:11:1f:f1:4a:b0:28:46:c9:c3:c4:42:7d:bc:fa:ab:59:
1154
+ # 6e:d5:b7:51:88:11:e3:a4:85:19:6b:82:4c:a4:0c:12:ad:e9:
1155
+ # a4:ae:3f:f1:c3:49:65:9a:8c:c5:c8:3e:25:b7:94:99:bb:92:
1156
+ # 32:71:07:f0:86:5e:ed:50:27:a6:0d:a6:23:f9:bb:cb:a6:07:
1157
+ # 14:42
1158
+ -----BEGIN CERTIFICATE-----
1159
+ MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
1160
+ FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
1161
+ VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
1162
+ biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
1163
+ dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
1164
+ MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
1165
+ MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
1166
+ A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
1167
+ b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
1168
+ cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
1169
+ bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
1170
+ VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
1171
+ ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
1172
+ uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
1173
+ 9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
1174
+ hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
1175
+ pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
1176
+ -----END CERTIFICATE-----
1177
+ # Thawte Primary Root CA - G2.pem
1178
+ # Certificate:
1179
+ # Data:
1180
+ # Version: 3 (0x2)
1181
+ # Serial Number:
1182
+ # 35:fc:26:5c:d9:84:4f:c9:3d:26:3d:57:9b:ae:d7:56
1183
+ # Signature Algorithm: ecdsa-with-SHA384
1184
+ # Issuer: C=US, O=thawte, Inc., OU=(c) 2007 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G2
1185
+ # Validity
1186
+ # Not Before: Nov 5 00:00:00 2007 GMT
1187
+ # Not After : Jan 18 23:59:59 2038 GMT
1188
+ # Subject: C=US, O=thawte, Inc., OU=(c) 2007 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G2
1189
+ # Subject Public Key Info:
1190
+ # Public Key Algorithm: id-ecPublicKey
1191
+ # Public-Key: (384 bit)
1192
+ # pub:
1193
+ # 04:a2:d5:9c:82:7b:95:9d:f1:52:78:87:fe:8a:16:
1194
+ # bf:05:e6:df:a3:02:4f:0d:07:c6:00:51:ba:0c:02:
1195
+ # 52:2d:22:a4:42:39:c4:fe:8f:ea:c9:c1:be:d4:4d:
1196
+ # ff:9f:7a:9e:e2:b1:7c:9a:ad:a7:86:09:73:87:d1:
1197
+ # e7:9a:e3:7a:a5:aa:6e:fb:ba:b3:70:c0:67:88:a2:
1198
+ # 35:d4:a3:9a:b1:fd:ad:c2:ef:31:fa:a8:b9:f3:fb:
1199
+ # 08:c6:91:d1:fb:29:95
1200
+ # ASN1 OID: secp384r1
1201
+ # X509v3 extensions:
1202
+ # X509v3 Basic Constraints: critical
1203
+ # CA:TRUE
1204
+ # X509v3 Key Usage: critical
1205
+ # Certificate Sign, CRL Sign
1206
+ # X509v3 Subject Key Identifier:
1207
+ # 9A:D8:00:30:00:E7:6B:7F:85:18:EE:8B:B6:CE:8A:0C:F8:11:E1:BB
1208
+ # Signature Algorithm: ecdsa-with-SHA384
1209
+ # 30:66:02:31:00:dd:f8:e0:57:47:5b:a7:e6:0a:c3:bd:f5:80:
1210
+ # 8a:97:35:0d:1b:89:3c:54:86:77:28:ca:a1:f4:79:de:b5:e6:
1211
+ # 38:b0:f0:65:70:8c:7f:02:54:c2:bf:ff:d8:a1:3e:d9:cf:02:
1212
+ # 31:00:c4:8d:94:fc:dc:53:d2:dc:9d:78:16:1f:15:33:23:53:
1213
+ # 52:e3:5a:31:5d:9d:ca:ae:bd:13:29:44:0d:27:5b:a8:e7:68:
1214
+ # 9c:12:f7:58:3f:2e:72:02:57:a3:8f:a1:14:2e
1215
+ -----BEGIN CERTIFICATE-----
1216
+ MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
1217
+ MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
1218
+ IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
1219
+ BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
1220
+ MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
1221
+ d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
1222
+ YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
1223
+ dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
1224
+ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
1225
+ papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
1226
+ BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
1227
+ DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
1228
+ KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
1229
+ XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
1230
+ -----END CERTIFICATE-----
1231
+ # Thawte Primary Root CA - G3.pem
1232
+ # Certificate:
1233
+ # Data:
1234
+ # Version: 3 (0x2)
1235
+ # Serial Number:
1236
+ # 60:01:97:b7:46:a7:ea:b4:b4:9a:d6:4b:2f:f7:90:fb
1237
+ # Signature Algorithm: sha256WithRSAEncryption
1238
+ # Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2008 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G3
1239
+ # Validity
1240
+ # Not Before: Apr 2 00:00:00 2008 GMT
1241
+ # Not After : Dec 1 23:59:59 2037 GMT
1242
+ # Subject: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2008 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G3
1243
+ # Subject Public Key Info:
1244
+ # Public Key Algorithm: rsaEncryption
1245
+ # Public-Key: (2048 bit)
1246
+ # Modulus:
1247
+ # 00:b2:bf:27:2c:fb:db:d8:5b:dd:78:7b:1b:9e:77:
1248
+ # 66:81:cb:3e:bc:7c:ae:f3:a6:27:9a:34:a3:68:31:
1249
+ # 71:38:33:62:e4:f3:71:66:79:b1:a9:65:a3:a5:8b:
1250
+ # d5:8f:60:2d:3f:42:cc:aa:6b:32:c0:23:cb:2c:41:
1251
+ # dd:e4:df:fc:61:9c:e2:73:b2:22:95:11:43:18:5f:
1252
+ # c4:b6:1f:57:6c:0a:05:58:22:c8:36:4c:3a:7c:a5:
1253
+ # d1:cf:86:af:88:a7:44:02:13:74:71:73:0a:42:59:
1254
+ # 02:f8:1b:14:6b:42:df:6f:5f:ba:6b:82:a2:9d:5b:
1255
+ # e7:4a:bd:1e:01:72:db:4b:74:e8:3b:7f:7f:7d:1f:
1256
+ # 04:b4:26:9b:e0:b4:5a:ac:47:3d:55:b8:d7:b0:26:
1257
+ # 52:28:01:31:40:66:d8:d9:24:bd:f6:2a:d8:ec:21:
1258
+ # 49:5c:9b:f6:7a:e9:7f:55:35:7e:96:6b:8d:93:93:
1259
+ # 27:cb:92:bb:ea:ac:40:c0:9f:c2:f8:80:cf:5d:f4:
1260
+ # 5a:dc:ce:74:86:a6:3e:6c:0b:53:ca:bd:92:ce:19:
1261
+ # 06:72:e6:0c:5c:38:69:c7:04:d6:bc:6c:ce:5b:f6:
1262
+ # f7:68:9c:dc:25:15:48:88:a1:e9:a9:f8:98:9c:e0:
1263
+ # f3:d5:31:28:61:11:6c:67:96:8d:39:99:cb:c2:45:
1264
+ # 24:39
1265
+ # Exponent: 65537 (0x10001)
1266
+ # X509v3 extensions:
1267
+ # X509v3 Basic Constraints: critical
1268
+ # CA:TRUE
1269
+ # X509v3 Key Usage: critical
1270
+ # Certificate Sign, CRL Sign
1271
+ # X509v3 Subject Key Identifier:
1272
+ # AD:6C:AA:94:60:9C:ED:E4:FF:FA:3E:0A:74:2B:63:03:F7:B6:59:BF
1273
+ # Signature Algorithm: sha256WithRSAEncryption
1274
+ # 1a:40:d8:95:65:ac:09:92:89:c6:39:f4:10:e5:a9:0e:66:53:
1275
+ # 5d:78:de:fa:24:91:bb:e7:44:51:df:c6:16:34:0a:ef:6a:44:
1276
+ # 51:ea:2b:07:8a:03:7a:c3:eb:3f:0a:2c:52:16:a0:2b:43:b9:
1277
+ # 25:90:3f:70:a9:33:25:6d:45:1a:28:3b:27:cf:aa:c3:29:42:
1278
+ # 1b:df:3b:4c:c0:33:34:5b:41:88:bf:6b:2b:65:af:28:ef:b2:
1279
+ # f5:c3:aa:66:ce:7b:56:ee:b7:c8:cb:67:c1:c9:9c:1a:18:b8:
1280
+ # c4:c3:49:03:f1:60:0e:50:cd:46:c5:f3:77:79:f7:b6:15:e0:
1281
+ # 38:db:c7:2f:28:a0:0c:3f:77:26:74:d9:25:12:da:31:da:1a:
1282
+ # 1e:dc:29:41:91:22:3c:69:a7:bb:02:f2:b6:5c:27:03:89:f4:
1283
+ # 06:ea:9b:e4:72:82:e3:a1:09:c1:e9:00:19:d3:3e:d4:70:6b:
1284
+ # ba:71:a6:aa:58:ae:f4:bb:e9:6c:b6:ef:87:cc:9b:bb:ff:39:
1285
+ # e6:56:61:d3:0a:a7:c4:5c:4c:60:7b:05:77:26:7a:bf:d8:07:
1286
+ # 52:2c:62:f7:70:63:d9:39:bc:6f:1c:c2:79:dc:76:29:af:ce:
1287
+ # c5:2c:64:04:5e:88:36:6e:31:d4:40:1a:62:34:36:3f:35:01:
1288
+ # ae:ac:63:a0
1289
+ -----BEGIN CERTIFICATE-----
1290
+ MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
1291
+ rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
1292
+ Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
1293
+ MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
1294
+ BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
1295
+ Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
1296
+ LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
1297
+ MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
1298
+ ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
1299
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
1300
+ gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
1301
+ YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
1302
+ b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
1303
+ 9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
1304
+ zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
1305
+ OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
1306
+ HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
1307
+ 2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
1308
+ oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
1309
+ t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
1310
+ KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
1311
+ m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
1312
+ MdRAGmI0Nj81Aa6sY6A=
1313
+ -----END CERTIFICATE-----
1314
+ # Thawte Primary Root CA.pem
1315
+ # Certificate:
1316
+ # Data:
1317
+ # Version: 3 (0x2)
1318
+ # Serial Number:
1319
+ # 34:4e:d5:57:20:d5:ed:ec:49:f4:2f:ce:37:db:2b:6d
1320
+ # Signature Algorithm: sha1WithRSAEncryption
1321
+ # Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA
1322
+ # Validity
1323
+ # Not Before: Nov 17 00:00:00 2006 GMT
1324
+ # Not After : Jul 16 23:59:59 2036 GMT
1325
+ # Subject: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA
1326
+ # Subject Public Key Info:
1327
+ # Public Key Algorithm: rsaEncryption
1328
+ # Public-Key: (2048 bit)
1329
+ # Modulus:
1330
+ # 00:ac:a0:f0:fb:80:59:d4:9c:c7:a4:cf:9d:a1:59:
1331
+ # 73:09:10:45:0c:0d:2c:6e:68:f1:6c:5b:48:68:49:
1332
+ # 59:37:fc:0b:33:19:c2:77:7f:cc:10:2d:95:34:1c:
1333
+ # e6:eb:4d:09:a7:1c:d2:b8:c9:97:36:02:b7:89:d4:
1334
+ # 24:5f:06:c0:cc:44:94:94:8d:02:62:6f:eb:5a:dd:
1335
+ # 11:8d:28:9a:5c:84:90:10:7a:0d:bd:74:66:2f:6a:
1336
+ # 38:a0:e2:d5:54:44:eb:1d:07:9f:07:ba:6f:ee:e9:
1337
+ # fd:4e:0b:29:f5:3e:84:a0:01:f1:9c:ab:f8:1c:7e:
1338
+ # 89:a4:e8:a1:d8:71:65:0d:a3:51:7b:ee:bc:d2:22:
1339
+ # 60:0d:b9:5b:9d:df:ba:fc:51:5b:0b:af:98:b2:e9:
1340
+ # 2e:e9:04:e8:62:87:de:2b:c8:d7:4e:c1:4c:64:1e:
1341
+ # dd:cf:87:58:ba:4a:4f:ca:68:07:1d:1c:9d:4a:c6:
1342
+ # d5:2f:91:cc:7c:71:72:1c:c5:c0:67:eb:32:fd:c9:
1343
+ # 92:5c:94:da:85:c0:9b:bf:53:7d:2b:09:f4:8c:9d:
1344
+ # 91:1f:97:6a:52:cb:de:09:36:a4:77:d8:7b:87:50:
1345
+ # 44:d5:3e:6e:29:69:fb:39:49:26:1e:09:a5:80:7b:
1346
+ # 40:2d:eb:e8:27:85:c9:fe:61:fd:7e:e6:7c:97:1d:
1347
+ # d5:9d
1348
+ # Exponent: 65537 (0x10001)
1349
+ # X509v3 extensions:
1350
+ # X509v3 Basic Constraints: critical
1351
+ # CA:TRUE
1352
+ # X509v3 Key Usage: critical
1353
+ # Certificate Sign, CRL Sign
1354
+ # X509v3 Subject Key Identifier:
1355
+ # 7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50
1356
+ # Signature Algorithm: sha1WithRSAEncryption
1357
+ # 79:11:c0:4b:b3:91:b6:fc:f0:e9:67:d4:0d:6e:45:be:55:e8:
1358
+ # 93:d2:ce:03:3f:ed:da:25:b0:1d:57:cb:1e:3a:76:a0:4c:ec:
1359
+ # 50:76:e8:64:72:0c:a4:a9:f1:b8:8b:d6:d6:87:84:bb:32:e5:
1360
+ # 41:11:c0:77:d9:b3:60:9d:eb:1b:d5:d1:6e:44:44:a9:a6:01:
1361
+ # ec:55:62:1d:77:b8:5c:8e:48:49:7c:9c:3b:57:11:ac:ad:73:
1362
+ # 37:8e:2f:78:5c:90:68:47:d9:60:60:e6:fc:07:3d:22:20:17:
1363
+ # c4:f7:16:e9:c4:d8:72:f9:c8:73:7c:df:16:2f:15:a9:3e:fd:
1364
+ # 6a:27:b6:a1:eb:5a:ba:98:1f:d5:e3:4d:64:0a:9d:13:c8:61:
1365
+ # ba:f5:39:1c:87:ba:b8:bd:7b:22:7f:f6:fe:ac:40:79:e5:ac:
1366
+ # 10:6f:3d:8f:1b:79:76:8b:c4:37:b3:21:18:84:e5:36:00:eb:
1367
+ # 63:20:99:b9:e9:fe:33:04:bb:41:c8:c1:02:f9:44:63:20:9e:
1368
+ # 81:ce:42:d3:d6:3f:2c:76:d3:63:9c:59:dd:8f:a6:e1:0e:a0:
1369
+ # 2e:41:f7:2e:95:47:cf:bc:fd:33:f3:f6:0b:61:7e:7e:91:2b:
1370
+ # 81:47:c2:27:30:ee:a7:10:5d:37:8f:5c:39:2b:e4:04:f0:7b:
1371
+ # 8d:56:8c:68
1372
+ -----BEGIN CERTIFICATE-----
1373
+ MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
1374
+ qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
1375
+ Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
1376
+ MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
1377
+ BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
1378
+ NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
1379
+ LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
1380
+ A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
1381
+ IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
1382
+ SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
1383
+ W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
1384
+ 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
1385
+ 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
1386
+ Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
1387
+ NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
1388
+ MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
1389
+ r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
1390
+ DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
1391
+ YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
1392
+ xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
1393
+ /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
1394
+ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
1395
+ jVaMaA==
1396
+ -----END CERTIFICATE-----
com/lib/Dropbox/strict.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Throw exceptions on all PHP errors/warnings/notices.
3
+ // We'd like to do this in all situations (and not just when running tests), but
4
+ // this is a global setting and other code might not be ready for it.
5
+ /** @internal */
6
+ function error_to_exception($errno, $errstr, $errfile, $errline, $context)
7
+ {
8
+ // If the error is being suppressed with '@', don't throw an exception.
9
+ if (error_reporting() === 0) return;
10
+
11
+ throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
12
+ }
13
+ set_error_handler('error_to_exception');
com/lib/Request/SGIRequestAdapter.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface SGIRequestAdapter
4
+ {
5
+ public function sendPostRequest();
6
+ public function sendGetRequest();
7
+ public function sendRequest($type);
8
+ public function setHeaders($headers);
9
+ public function setUrl($url);
10
+ public function setParams($params);
11
+ public function addHeader($header);
12
+ public function setGetWithQueryParams($getWithQueryParams);
13
+ public function parseResponse();
14
+ }
com/lib/Request/SGRequest.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGRequest
4
+ {
5
+ private static $instance = null;
6
+
7
+ public static function getInstance()
8
+ {
9
+ if (!self::$instance) {
10
+ self::$instance = self::createAdapterInstance();
11
+ }
12
+
13
+ return self::$instance;
14
+ }
15
+
16
+ private static function createAdapterInstance()
17
+ {
18
+ $className = 'SGRequestAdapter'.SG_ENV_ADAPTER;
19
+ require_once(SG_REQUEST_PATH.$className.'.php');
20
+ $adapter = new $className();
21
+ return $adapter;
22
+ }
23
+
24
+ private function __construct()
25
+ {
26
+
27
+ }
28
+
29
+ private function __clone()
30
+ {
31
+
32
+ }
33
+ }
com/lib/Request/SGRequestAdapterWordpress.php ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(SG_REQUEST_PATH.'SGIRequestAdapter.php');
4
+ require_once(SG_REQUEST_PATH.'SGResponse.php');
5
+
6
+ class SGRequestAdapterWordpress implements SGIRequestAdapter
7
+ {
8
+ private $headers = array();
9
+ private $params = array();
10
+ private $url;
11
+ private $getWithQueryParams = true;
12
+
13
+ private $body;
14
+ private $httpCode;
15
+ private $contentType;
16
+
17
+ private $stream = false;
18
+
19
+ public function __construct()
20
+ {
21
+ $reloadMethod = SGConfig::get('SG_BACKGROUND_RELOAD_METHOD');
22
+ if ($reloadMethod == SG_RELOAD_METHOD_STREAM) {
23
+ $this->stream = true;
24
+ }
25
+ }
26
+
27
+ public function setGetWithQueryParams($getWithQueryParams)
28
+ {
29
+ $this->getWithQueryParams = $getWithQueryParams;
30
+ }
31
+
32
+ public function addHeader($header)
33
+ {
34
+ $this->headers[] = $header;
35
+ }
36
+
37
+ public function setHeaders($headers)
38
+ {
39
+ $this->headers = $headers;
40
+ }
41
+
42
+ public function setUrl($url)
43
+ {
44
+ $this->url = $url;
45
+ }
46
+
47
+ public function setParams($params)
48
+ {
49
+ $this->params = $params;
50
+ }
51
+
52
+ public function sendPostRequest()
53
+ {
54
+ $body = null;
55
+
56
+ if (count($this->params)) {
57
+ // $body = http_build_query($this->params, '', '&');
58
+ $body = $this->params;
59
+ }
60
+
61
+ $args = array(
62
+ 'headers' => $this->headers,
63
+ 'sslverify' => false,
64
+ 'body' => $body,
65
+ 'stream' => $this->stream
66
+ );
67
+
68
+ $response = wp_remote_post($this->url, $args);
69
+ if ($this->stream && !($response instanceof WP_Error)) {
70
+ $this->body = file_get_contents($response['filename']);
71
+ }
72
+ else {
73
+ $this->body = wp_remote_retrieve_body($response);
74
+ }
75
+ $this->httpCode = wp_remote_retrieve_response_code($response);
76
+
77
+ $headers = wp_remote_retrieve_headers($response);
78
+ if ($headers && $headers instanceof Requests_Utility_CaseInsensitiveDictionary) {
79
+ $data = $headers->getAll();
80
+ $this->contentType = $data['content-type'];
81
+ }
82
+ else if ($headers && is_array($headers)) {
83
+ $this->contentType = $headers['content-type'];
84
+ }
85
+ else {
86
+ $this->contentType = '';
87
+ }
88
+
89
+ return $this->parseResponse();
90
+ }
91
+
92
+ public function sendGetRequest()
93
+ {
94
+ $args = array(
95
+ 'headers' => $this->headers,
96
+ 'sslverify' => false,
97
+ 'stream' => $this->stream
98
+ );
99
+
100
+ if (count($this->params)) {
101
+ $this->url = rtrim($this->url, '/').'/';
102
+
103
+ if ($this->getWithQueryParams) { //standard get url, with query params
104
+ $this->url .= '?'.http_build_query($this->params, '', '&');
105
+ }
106
+ else { //mvs-styled get url
107
+ $this->url .= implode('/', array_values($this->params));
108
+ }
109
+ }
110
+
111
+ $response = wp_remote_get($this->url, $args);
112
+ if ($this->stream && !($response instanceof WP_Error)) {
113
+ $this->body = file_get_contents($response['filename']);
114
+ }
115
+ else {
116
+ $this->body = wp_remote_retrieve_body($response);
117
+ }
118
+ $this->httpCode = wp_remote_retrieve_response_code($response);
119
+
120
+ $headers = wp_remote_retrieve_headers($response);
121
+ if ($headers && $headers instanceof Requests_Utility_CaseInsensitiveDictionary) {
122
+ $data = $headers->getAll();
123
+ $this->contentType = $data['content-type'];
124
+ }
125
+ else if ($headers && is_array($headers)) {
126
+ $this->contentType = $headers['content-type'];
127
+ }
128
+ else {
129
+ $this->contentType = '';
130
+ }
131
+
132
+ return $this->parseResponse();
133
+ }
134
+
135
+ public function sendRequest($type)
136
+ {
137
+ $body = null;
138
+
139
+ if (count($this->params)) {
140
+ // $body = http_build_query($this->params, '', '&');
141
+ $body = $this->params;
142
+ }
143
+
144
+ $args = array(
145
+ 'headers' => $this->headers,
146
+ 'sslverify' => false,
147
+ 'method' => $type,
148
+ 'body' => $body,
149
+ 'stream' => $this->stream
150
+ );
151
+
152
+ $response = wp_remote_request($this->url, $args);
153
+ if ($this->stream && !($response instanceof WP_Error)) {
154
+ $this->body = file_get_contents($response['filename']);
155
+ }
156
+ else {
157
+ $this->body = wp_remote_retrieve_body($response);
158
+ }
159
+ $this->httpCode = wp_remote_retrieve_response_code($response);
160
+
161
+ $headers = wp_remote_retrieve_headers($response);
162
+ if ($headers && $headers instanceof Requests_Utility_CaseInsensitiveDictionary) {
163
+ $data = $headers->getAll();
164
+ $this->contentType = $data['content-type'];
165
+ }
166
+ else if ($headers && is_array($headers)) {
167
+ $this->contentType = $headers['content-type'];
168
+ }
169
+ else {
170
+ $this->contentType = '';
171
+ }
172
+
173
+ return $this->parseResponse();
174
+ }
175
+
176
+ public function parseResponse()
177
+ {
178
+ $response = new SGResponse();
179
+ $response->setBody($this->body);
180
+ $response->setHttpStatus($this->httpCode);
181
+ $response->setContentType($this->contentType);
182
+
183
+ //if the response is in json format, decode it
184
+ if ($this->contentType == 'application/json') {
185
+ $response->parseJsonBody();
186
+ }
187
+
188
+ return $response;
189
+ }
190
+ }
com/lib/Request/SGResponse.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGResponse
4
+ {
5
+ private $httpStatus = false;
6
+ private $contentType = false;
7
+ private $body = false;
8
+
9
+ public function getHttpStatus()
10
+ {
11
+ return $this->httpStatus;
12
+ }
13
+
14
+ public function setHttpStatus($httpStatus)
15
+ {
16
+ $this->httpStatus = $httpStatus;
17
+ }
18
+
19
+ public function getContentType()
20
+ {
21
+ return $this->contentType;
22
+ }
23
+
24
+ public function setContentType($contentType)
25
+ {
26
+ $this->contentType = $contentType;
27
+ }
28
+
29
+ public function getBody()
30
+ {
31
+ return $this->body;
32
+ }
33
+
34
+ public function setBody($body)
35
+ {
36
+ $this->body = $body;
37
+ }
38
+
39
+ public function parseJsonBody()
40
+ {
41
+ if ($this->body) {
42
+ $this->body = json_decode($this->body, true);
43
+ }
44
+ }
45
+
46
+ public function getBodyParam($key)
47
+ {
48
+ if (is_array($this->body) && isset($this->body[$key])) {
49
+ return $this->body[$key];
50
+ }
51
+
52
+ return null;
53
+ }
54
+ }
com/lib/SGArchive.php ADDED
@@ -0,0 +1,793 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface SGArchiveDelegate
4
+ {
5
+ public function getCorrectCdrFilename($filename);
6
+ public function didExtractFile($filePath);
7
+ public function didCountFilesInsideArchive($count);
8
+ public function didFindExtractError($error);
9
+ public function warn($message);
10
+ public function didExtractArchiveMeta($meta);
11
+ public function didStartRestoreFiles();
12
+ }
13
+
14
+ class SGArchive
15
+ {
16
+ const VERSION = 5;
17
+ const CHUNK_SIZE = 1048576; //1mb
18
+ private $filePath = '';
19
+ private $mode = '';
20
+ private $fileHandle = null;
21
+ private $cdrFileHandle = null;
22
+ private $cdrFilesCount = 0;
23
+ private $cdr = array();
24
+ private $fileOffset = 0;
25
+ private $delegate;
26
+ private $ranges = array();
27
+ private $state = null;
28
+ private $rangeCursor = 0;
29
+
30
+ private $cdrOffset = 0;
31
+
32
+ public function __construct($filePath, $mode, $cdrSize = 0)
33
+ {
34
+ $this->filePath = $filePath;
35
+ $this->mode = $mode;
36
+ $this->fileHandle = @fopen($filePath, $mode.'b');
37
+ $this->clear();
38
+
39
+ if ($cdrSize) {
40
+ $this->cdrFilesCount = $cdrSize;
41
+ }
42
+
43
+ if ($mode == 'a') {
44
+
45
+ $cdrPath = $filePath.'.cdr';
46
+
47
+ $this->cdrFileHandle = @fopen($cdrPath, $mode.'b');
48
+ }
49
+ }
50
+
51
+ public function setDelegate(SGArchiveDelegate $delegate)
52
+ {
53
+ $this->delegate = $delegate;
54
+ }
55
+
56
+ public function getCdrFilesCount()
57
+ {
58
+ return $this->cdrFilesCount;
59
+ }
60
+
61
+ public function addFileFromPath($filename, $path)
62
+ {
63
+ $headerSize = 0;
64
+ $len = 0;
65
+ $zlen = 0;
66
+ $start = 0;
67
+
68
+ $fp = fopen($path, 'rb');
69
+ $fileSize = backupGuardRealFilesize($path);
70
+
71
+ $state = $this->delegate->getState();
72
+ $offset = $state->getOffset();
73
+
74
+ if (!$state->getInprogress()) {
75
+ $headerSize = $this->addFileHeader();
76
+ }
77
+ else{
78
+ $headerSize = $state->getHeaderSize();
79
+ $this->fileOffset = $state->getFileOffsetInArchive();
80
+ }
81
+
82
+ $this->ranges = $state->getRanges();
83
+ if (count($this->ranges)) {
84
+ $range = end($this->ranges); //get last range of file
85
+
86
+ $start += $range['start'] + $range['size'];
87
+ $zlen = $start; // get file compressed size before reload
88
+ }
89
+
90
+ fseek($fp, $offset); // move to point before reload
91
+ //read file in small chunks
92
+ while ($offset < $fileSize)
93
+ {
94
+ $data = fread($fp, self::CHUNK_SIZE);
95
+ if ($data === '') {
96
+ //When fread fails to read and compress on fly
97
+ if ($zlen == 0 && $fileSize != 0 && strlen($data) == 0) {
98
+ $this->delegate->warn('Failed to read file: '.basename($filename));
99
+ }
100
+ break;
101
+ }
102
+
103
+ $data = gzdeflate($data);
104
+ $zlen += strlen($data);
105
+ $sgArchiveSize = backupGuardRealFilesize($this->filePath);
106
+ $sgArchiveSize += strlen($data);
107
+
108
+ if($sgArchiveSize > SG_ARCHIVE_MAX_SIZE_32) {
109
+ SGBoot::checkRequirement('intSize');
110
+ }
111
+
112
+ $this->write($data);
113
+
114
+ array_push($this->ranges, array(
115
+ 'start' => $start,
116
+ 'size' => strlen($data)
117
+ ));
118
+ $offset = ftell($fp);
119
+
120
+ $start += strlen($data);
121
+
122
+ SGPing::update();
123
+ $shouldReload = $this->delegate->shouldReload();
124
+ if ($shouldReload) {
125
+ $this->delegate->saveStateData(SG_STATE_ACTION_COMPRESSING_FILES, $this->ranges, $offset, $headerSize, true, $this->fileOffset);
126
+
127
+ if (backupGuardIsReloadEnabled()) {
128
+ @fclose($fp);
129
+ @fclose($this->fileHandle);
130
+ @fclose($this->cdrFileHandle);
131
+
132
+ $this->delegate->reload();
133
+ }
134
+ }
135
+ }
136
+
137
+ if ($state->getInprogress()) {
138
+ $headerSize = $state->getHeaderSize();
139
+ }
140
+
141
+ SGPing::update();
142
+
143
+ fclose($fp);
144
+
145
+ $this->addFileToCdr($filename, $zlen, $len, $headerSize);
146
+ }
147
+
148
+ public function addFile($filename, $data)
149
+ {
150
+ $headerSize = $this->addFileHeader();
151
+
152
+ if ($data)
153
+ {
154
+ $data = gzdeflate($data);
155
+ $this->write($data);
156
+ }
157
+
158
+ $zlen = strlen($data);
159
+ $len = 0;
160
+
161
+ $this->addFileToCdr($filename, $zlen, $len, $headerSize);
162
+ }
163
+
164
+ private function addFileHeader()
165
+ {
166
+ //save extra
167
+ $extra = '';
168
+
169
+ $extraLengthInBytes = 4;
170
+ $this->write($this->packToLittleEndian(strlen($extra), $extraLengthInBytes).$extra);
171
+
172
+ return $extraLengthInBytes+strlen($extra);
173
+ }
174
+
175
+ private function addFileToCdr($filename, $zlen, $len, $headerSize)
176
+ {
177
+ //store cdr data for later use
178
+ $this->addToCdr($filename, $zlen, $len);
179
+
180
+ $this->fileOffset += $headerSize + $zlen;
181
+ }
182
+
183
+ public function finalize()
184
+ {
185
+ $this->addFooter();
186
+
187
+ fclose($this->fileHandle);
188
+
189
+ $this->clear();
190
+ }
191
+
192
+ private function addFooter()
193
+ {
194
+ $footer = '';
195
+
196
+ //save version
197
+ $footer .= $this->packToLittleEndian(self::VERSION, 1);
198
+
199
+ $tables = SGConfig::get('SG_BACKUPED_TABLES');
200
+
201
+ if ($tables) {
202
+ $table = json_encode($tables);
203
+ }
204
+ else {
205
+ $tables = "";
206
+ }
207
+
208
+ $multisitePath = "";
209
+ $multisiteDomain = "";
210
+
211
+ if (SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
212
+ // in case of multisite save old path and domain for later usage
213
+ if (is_multisite()) {
214
+ $multisitePath = PATH_CURRENT_SITE;
215
+ $multisiteDomain = DOMAIN_CURRENT_SITE;
216
+ }
217
+ }
218
+
219
+ //save db prefix, site and home url for later use
220
+ $extra = json_encode(array(
221
+ 'siteUrl' => get_site_url(),
222
+ 'home' => get_home_url(),
223
+ 'dbPrefix' => SG_ENV_DB_PREFIX,
224
+ 'tables' => $tables,
225
+ 'method' => SGConfig::get('SG_BACKUP_TYPE'),
226
+ 'multisitePath' => $multisitePath,
227
+ 'multisiteDomain' => $multisiteDomain,
228
+ 'selectivRestoreable' => true,
229
+ 'phpVersion' => phpversion()
230
+ ));
231
+
232
+ //extra size
233
+ $footer .= $this->packToLittleEndian(strlen($extra), 4).$extra;
234
+
235
+ //save cdr size
236
+ $footer .= $this->packToLittleEndian($this->cdrFilesCount, 4);
237
+
238
+ $this->write($footer);
239
+
240
+ //save cdr
241
+ $cdrLen = $this->writeCdr();
242
+
243
+ //save offset to the start of footer
244
+ $len = $cdrLen+strlen($extra)+13;
245
+ $this->write($this->packToLittleEndian($len, 4));
246
+ }
247
+
248
+ private function writeCdr()
249
+ {
250
+ @fclose($this->cdrFileHandle);
251
+
252
+ $cdrLen = 0;
253
+ $fp = @fopen($this->filePath.'.cdr', 'rb');
254
+
255
+ while (!feof($fp))
256
+ {
257
+ $data = fread($fp, self::CHUNK_SIZE);
258
+ $cdrLen += strlen($data);
259
+ $this->write($data);
260
+ }
261
+
262
+ @fclose($fp);
263
+ @unlink($this->filePath.'.cdr');
264
+
265
+ return $cdrLen;
266
+ }
267
+
268
+ private function clear()
269
+ {
270
+ $this->cdr = array();
271
+ $this->fileOffset = 0;
272
+ $this->cdrFilesCount = 0;
273
+ }
274
+
275
+ private function addToCdr($filename, $compressedLength, $uncompressedLength)
276
+ {
277
+ $rec = $this->packToLittleEndian(0, 4); //crc (not used in this version)
278
+ $rec .= $this->packToLittleEndian(strlen($filename), 2);
279
+ $rec .= $filename;
280
+ // file offset, compressed length, uncompressed length all are writen in 8 bytes to cover big integer size
281
+ $rec .= $this->packToLittleEndian($this->fileOffset, 8);
282
+ $rec .= $this->packToLittleEndian($compressedLength, 8);
283
+ $rec .= $this->packToLittleEndian($uncompressedLength, 8); //uncompressed size (not used in this version)
284
+ $rec .= $this->packToLittleEndian(count($this->ranges), 4);
285
+
286
+ foreach ($this->ranges as $range) {
287
+ // start and size all are writen in 8 bytes to cover big integer size
288
+ $rec .= $this->packToLittleEndian($range['start'], 8);
289
+ $rec .= $this->packToLittleEndian($range['size'], 8);
290
+ }
291
+
292
+ fwrite($this->cdrFileHandle, $rec);
293
+ fflush($this->cdrFileHandle);
294
+
295
+ $this->cdrFilesCount++;
296
+ }
297
+
298
+ private function isEnoughFreeSpaceOnDisk($dataSize)
299
+ {
300
+ $freeSpace = @disk_free_space(SG_APP_ROOT_DIRECTORY);
301
+
302
+ if ($freeSpace === false || $freeSpace === null) {
303
+ return true;
304
+ }
305
+
306
+ if ($freeSpace < $dataSize) {
307
+ return false;
308
+ }
309
+
310
+ return true;
311
+ }
312
+
313
+ private function write($data)
314
+ {
315
+ $isEnoughFreeSpaceOnDisk = $this->isEnoughFreeSpaceOnDisk(strlen($data));
316
+ if (!$isEnoughFreeSpaceOnDisk) {
317
+ throw new SGExceptionIO('Failed to write in the archive due to not sufficient disk free space.');
318
+ }
319
+
320
+ $result = fwrite($this->fileHandle, $data);
321
+ if ($result === FALSE) {
322
+ throw new SGExceptionIO('Failed to write in archive');
323
+ }
324
+ fflush($this->fileHandle);
325
+ }
326
+
327
+ private function read($length)
328
+ {
329
+ $result = fread($this->fileHandle, $length);
330
+ if ($result === FALSE) {
331
+ throw new SGExceptionIO('Failed to read from archive');
332
+ }
333
+ return $result;
334
+ }
335
+
336
+ private function packToLittleEndian($value, $size = 4)
337
+ {
338
+ if (is_int($value))
339
+ {
340
+ $size *= 2; //2 characters for each byte
341
+ $value = str_pad(dechex($value), $size, '0', STR_PAD_LEFT);
342
+ return strrev(pack('H'.$size, $value));
343
+ }
344
+
345
+ $hex = str_pad($value->toHex(), 16, '0', STR_PAD_LEFT);
346
+
347
+ $high = substr($hex, 0, 8);
348
+ $low = substr($hex, 8, 8);
349
+
350
+ $high = strrev(pack('H8', $high));
351
+ $low = strrev(pack('H8', $low));
352
+
353
+ return $low.$high;
354
+ }
355
+
356
+ public function getArchiveHeaders()
357
+ {
358
+ return $this->extractHeaders();
359
+ }
360
+
361
+ public function getFilesList()
362
+ {
363
+ $list = array();
364
+ $cdrSize = hexdec($this->unpackLittleEndian($this->read(4), 4));
365
+ $this->cdrOffset = ftell($this->fileHandle);
366
+
367
+ for($i = 0; $i < $cdrSize; $i++) {
368
+ $el = $this->getNextCdrElement($this->cdrOffset);
369
+ array_push($list, $el[0]);
370
+ }
371
+ return $list;
372
+ }
373
+
374
+ public function getTreefromList($list, $limit = "")
375
+ {
376
+ $tree = array();
377
+ if(end($list) == "./sql") {
378
+ array_pop($list);
379
+ }
380
+ for($i=0; $i < count($list); $i++) {
381
+ if(!backupGuardStringStartsWith($list[$i], $limit)) {
382
+ continue;
383
+ }
384
+ $path = substr($list[$i], strlen($limit));
385
+ $path = explode(DIRECTORY_SEPARATOR, $path);
386
+ $exists = false;
387
+ foreach($tree as $el) {
388
+ if ($path[0] == $el->name) {
389
+ $exists = true;
390
+ break;
391
+ }
392
+ }
393
+ if(!$exists) {
394
+ $node = new stdClass();
395
+ $node->name = $path[0];
396
+ if(count($path) > 1){
397
+ $node->type = "folder";
398
+ }else{
399
+ $node->type = "file";
400
+ }
401
+ array_push($tree,$node);
402
+ }
403
+
404
+ }
405
+ return $tree;
406
+ }
407
+
408
+ public function extractTo($destinationPath, $state = null)
409
+ {
410
+ $this->state = $state;
411
+ $action = $state->getAction();
412
+
413
+ if ($action == SG_STATE_ACTION_PREPARING_STATE_FILE) {
414
+ $this->extract($destinationPath);
415
+ }
416
+ else {
417
+ $this->continueExtract($destinationPath);
418
+ }
419
+ }
420
+
421
+ private function extractHeaders()
422
+ {
423
+ //read offset
424
+ fseek($this->fileHandle, -4, SEEK_END);
425
+ $offset = hexdec($this->unpackLittleEndian($this->read(4), 4));
426
+
427
+ //read version
428
+ fseek($this->fileHandle, -$offset, SEEK_END);
429
+ $version = hexdec($this->unpackLittleEndian($this->read(1), 1));
430
+ SGConfig::set('SG_CURRENT_ARCHIVE_VERSION', $version);
431
+
432
+ //read extra size (not used in this version)
433
+ $extraSize = hexdec($this->unpackLittleEndian($this->read(4), 4));
434
+
435
+ //read extra
436
+ $extra = array();
437
+ if ($extraSize > 0) {
438
+ $extra = $this->read($extraSize);
439
+ $extra = json_decode($extra, true);
440
+
441
+ SGConfig::set('SG_OLD_SITE_URL', $extra['siteUrl']);
442
+ SGConfig::set('SG_OLD_DB_PREFIX', $extra['dbPrefix']);
443
+
444
+ if (isset($extra['phpVersion'])) {
445
+ SGConfig::set('SG_OLD_PHP_VERSION', $extra['phpVersion']);
446
+ }
447
+
448
+ SGConfig::set('SG_BACKUPED_TABLES', $extra['tables']);
449
+ SGConfig::set('SG_BACKUP_TYPE', $extra['method']);
450
+
451
+ SGConfig::set('SG_MULTISITE_OLD_PATH', $extra['multisitePath']);
452
+ SGConfig::set('SG_MULTISITE_OLD_DOMAIN', $extra['multisiteDomain']);
453
+ }
454
+
455
+ $extra['version'] = $version;
456
+ return $extra;
457
+ }
458
+
459
+ private function extract($destinationPath)
460
+ {
461
+ $extra = $this->extractHeaders();
462
+ $version = $extra['version'];
463
+
464
+ $this->delegate->didExtractArchiveMeta($extra);
465
+
466
+ $isMultisite = backupGuardIsMultisite();
467
+ $archiveIsMultisite = $extra['multisitePath'] != '' || $extra['multisiteDomain'] != '';
468
+
469
+ if (SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
470
+ if ($archiveIsMultisite && !$isMultisite) {
471
+ throw new SGExceptionMigrationError("In order to restore this archive you should set up Multisite WordPress!");
472
+ }
473
+ elseif (!$archiveIsMultisite && $isMultisite) {
474
+ throw new SGExceptionMigrationError("In order to restore this archive you should set up a Standard instead of Multisite WordPress!");
475
+ }
476
+ }
477
+
478
+ if ($version >= SG_MIN_SUPPORTED_ARCHIVE_VERSION && $version <= SG_MAX_SUPPORTED_ARCHIVE_VERSION) {
479
+ if( !SGBoot::isFeatureAvailable('BACKUP_WITH_MIGRATION') ) {
480
+ if ($extra['method'] != SG_BACKUP_METHOD_MIGRATE) {
481
+ if ($extra['siteUrl'] == SG_SITE_URL) {
482
+ if ($extra['dbPrefix'] != SG_ENV_DB_PREFIX) {
483
+ throw new SGException("Seems you have changed database prefix. You should keep it constant to be able to restore this backup. Setup your WordPress installation with ".$extra['dbPrefix']." datbase prefix.");
484
+ }
485
+ }
486
+ else {
487
+ throw new SGExceptionMigrationError("You should install <b>BackupGuard Pro</b> to be able to migrate the website. More detailed information regarding features included in <b>Free</b> and <b>Pro</b> versions you can find here: <a href='".SG_BACKUP_SITE_URL."'>".SG_BACKUP_SITE_URL."</a>");
488
+ }
489
+ }
490
+ else {
491
+ throw new SGExceptionMigrationError("You should install <b>BackupGuard Pro</b> to be able to restore a package designed for migration.More detailed information regarding features included in <b>Free</b> and <b>Pro</b> versions you can find here: <a href='".SG_BACKUP_SITE_URL."'>".SG_BACKUP_SITE_URL."</a>");
492
+ }
493
+ }
494
+ }
495
+ else {
496
+ throw new SGExceptionBadRequest('Invalid SGArchive file');
497
+ }
498
+
499
+ //read cdr size
500
+ $this->cdrFilesCount = hexdec($this->unpackLittleEndian($this->read(4), 4));
501
+
502
+ $this->delegate->didStartRestoreFiles();
503
+ $this->delegate->didCountFilesInsideArchive($this->cdrFilesCount);
504
+
505
+ // $this->extractCdr($cdrSize, $destinationPath);
506
+ $this->cdrOffset = ftell($this->fileHandle);
507
+ $this->extractFiles($destinationPath);
508
+ }
509
+
510
+ private function continueExtract($destinationPath)
511
+ {
512
+ $this->fileOffset = $this->state->getOffset();
513
+ fseek($this->fileHandle, $this->fileOffset);
514
+ $this->extractFiles($destinationPath);
515
+ }
516
+
517
+ private function getNextCdrElement($offset)
518
+ {
519
+ fseek($this->fileHandle, $this->cdrOffset);
520
+ //read crc (not used in this version)
521
+ $this->read(4);
522
+
523
+ //read filename
524
+ $filenameLen = hexdec($this->unpackLittleEndian($this->read(2), 2));
525
+ $filename = $this->read($filenameLen);
526
+ $filename = $this->delegate->getCorrectCdrFilename($filename);
527
+
528
+ //read file offset
529
+ $fileOffsetInArchive = $this->unpackLittleEndian($this->read(8), 8);
530
+ $fileOffsetInArchive = hexdec($fileOffsetInArchive);
531
+
532
+ //read compressed length
533
+ $zlen = $this->unpackLittleEndian($this->read(8), 8);
534
+ $zlen = hexdec($zlen);
535
+
536
+ //read uncompressed length (not used in this version)
537
+ $this->read(8);
538
+
539
+ $rangeLen = hexdec($this->unpackLittleEndian($this->read(4), 4));
540
+
541
+ $ranges = array();
542
+ for ($i=0; $i < $rangeLen; $i++) {
543
+ $start = $this->unpackLittleEndian($this->read(8), 8);
544
+ $start = hexdec($start);
545
+
546
+ $size = $this->unpackLittleEndian($this->read(8), 8);
547
+ $size = hexdec($size);
548
+
549
+ $ranges[] = array(
550
+ 'start' => $start,
551
+ 'size' => $size
552
+ );
553
+ }
554
+
555
+ $this->cdrOffset = ftell($this->fileHandle);
556
+ return array($filename, $zlen, $ranges, $fileOffsetInArchive);
557
+ }
558
+
559
+ private function extractFiles($destinationPath)
560
+ {
561
+ $action = $this->state->getAction();
562
+ if ($action == SG_STATE_ACTION_PREPARING_STATE_FILE) {
563
+ $inprogress = false;
564
+ fseek($this->fileHandle, 0, SEEK_SET);
565
+ }
566
+ else {
567
+ $inprogress = $this->state->getInprogress();
568
+ $this->cdrFilesCount = $this->state->getCdrSize();
569
+ $this->cdrOffset = $this->state->getCdrCursor();
570
+ }
571
+
572
+ $sqlFileEnding = $this->state->getBackupFileName().'/'.$this->state->getBackupFileName().'.sql';
573
+ $restoreMode = $this->state->getRestoreMode();
574
+ $restoreFiles = $this->state->getRestoreFiles();
575
+
576
+ while ($this->cdrFilesCount) {
577
+
578
+ $warningFoundDuringExtract = false;
579
+
580
+ if ($inprogress) {
581
+ $row = $this->state->getCdr();
582
+ }
583
+ else {
584
+ $row = $this->getNextCdrElement($this->cdrOffset);
585
+
586
+ fseek($this->fileHandle, $this->fileOffset);
587
+
588
+ //read extra (not used in this version)
589
+ $this->read(4);
590
+ }
591
+
592
+ $path = $destinationPath . $row[0];
593
+ $path = str_replace('\\', '/', $path);
594
+ $restoreCurrentFile = false;
595
+
596
+ if ($restoreMode == SG_RESTORE_MODE_FILES && $restoreFiles != NULL && count($restoreFiles) > 0) {
597
+ for ($j = 0; $j < count($restoreFiles); $j++) {
598
+ if ($restoreFiles[$j] == "/" || backupGuardStringStartsWith($row[0], $restoreFiles[$j])) {
599
+ $restoreCurrentFile = true;
600
+ break;
601
+ }
602
+ }
603
+ }
604
+
605
+ // check if file should be restored according restore mode selected by user
606
+ if($restoreMode == SG_RESTORE_MODE_FULL || ($restoreMode == SG_RESTORE_MODE_DB && backupGuardStringEndsWith($path,$sqlFileEnding)) || ($restoreMode == SG_RESTORE_MODE_FILES && !backupGuardStringEndsWith($path,$sqlFileEnding) && $restoreCurrentFile)) {
607
+
608
+ if ($path[strlen($path) - 1] != '/') {//it's not an empty directory
609
+ $path = dirname($path);
610
+ }
611
+
612
+ if (!$inprogress) {
613
+ if (!$this->createPath($path)) {
614
+ $ranges = $row[2];
615
+
616
+ //get last range of file
617
+ $range = end($ranges);
618
+ $offset = $range['start'] + $range['size'];
619
+
620
+ // skip file and continue
621
+ fseek($this->fileHandle, $offset, SEEK_CUR);
622
+ $this->delegate->didFindExtractError('Could not create directory: ' . dirname($path));
623
+ continue;
624
+ }
625
+ }
626
+
627
+ $path = $destinationPath . $row[0];
628
+ $tmpPath = $path . ".sgbpTmpFile";
629
+
630
+ if (!$inprogress) {
631
+ $this->delegate->didStartExtractFile($path);
632
+
633
+ if (!is_writable(dirname($tmpPath))) {
634
+ $this->delegate->didFindExtractError('Destination path is not writable: ' . dirname($path));
635
+ }
636
+ }
637
+
638
+ if (!$inprogress) {
639
+ $tmpFp = @fopen($tmpPath, 'wb');
640
+ }
641
+ else {
642
+ $tmpFp = @fopen($tmpPath, 'ab');
643
+ }
644
+
645
+ $zlen = $row[1];
646
+ SGPing::update();
647
+ $ranges = $row[2];
648
+
649
+ if ($inprogress) {
650
+ $this->rangeCursor = $this->state->getRangeCursor();
651
+ }
652
+ else {
653
+ $this->rangeCursor = 0;
654
+ }
655
+
656
+ for ($i = $this->rangeCursor; $i < count($ranges); $i++) {
657
+ $start = $ranges[$i]['start'];
658
+ $size = $ranges[$i]['size'];
659
+
660
+ $data = $this->read($size);
661
+ $data = gzinflate($data);
662
+
663
+ //If gzinflate() failed to uncompress, skip the current file and continue extraction
664
+ if (!$data) {
665
+ $warningFoundDuringExtract = true;
666
+ $this->delegate->didFindExtractError('Failed to extract path: ' . $path);
667
+
668
+ //Assume we've extracted the current file
669
+ for ($idx = $i + 1; $idx < count($ranges); $idx++) {
670
+ $start = $ranges[$idx]['start'];
671
+ $size = $ranges[$idx]['size'];
672
+
673
+ fseek($this->fileHandle, $size, SEEK_CUR);
674
+ }
675
+
676
+ $inprogress = false;
677
+ @fclose($tmpFp);
678
+
679
+ SGPing::update();
680
+
681
+ break;
682
+ }
683
+ else {
684
+ $inprogress = true;
685
+ if (($i + 1) == count($ranges)) {
686
+ $inprogress = false;
687
+ }
688
+ if (is_resource($tmpFp)) {
689
+ $isEnoughFreeSpaceOnDisk = $this->isEnoughFreeSpaceOnDisk(strlen($data));
690
+ if (!$isEnoughFreeSpaceOnDisk) {
691
+ throw new SGExceptionIO('Failed to write in the archive due to not sufficient disk free space.');
692
+ }
693
+
694
+ fwrite($tmpFp, $data);
695
+ fflush($tmpFp);
696
+
697
+ $shouldReload = $this->delegate->shouldReload();
698
+
699
+ //restore with reloads will only work in external mode
700
+ if ($shouldReload && SGExternalRestore::isEnabled()) {
701
+
702
+ if (!$inprogress) {
703
+ $this->cdrFilesCount--;
704
+
705
+ @rename($tmpPath, $path);
706
+ $this->delegate->didExtractFile($path);
707
+ }
708
+
709
+ $token = $this->delegate->getToken();
710
+ $progress = $this->delegate->getProgress();
711
+
712
+ $this->fileOffset = ftell($this->fileHandle);
713
+
714
+ $this->state->setRestoreMode($restoreMode);
715
+ $this->state->setOffset($this->fileOffset);
716
+ $this->state->setInprogress($inprogress);
717
+ $this->state->setToken($token);
718
+ $this->state->setProgress($progress);
719
+ $this->state->setAction(SG_STATE_ACTION_RESTORING_FILES);
720
+ $this->state->setRangeCursor($i + 1);
721
+
722
+ $this->state->setCdr($row);
723
+ $this->state->setCdrSize($this->cdrFilesCount);
724
+ $this->state->setCdrCursor($this->cdrOffset);
725
+ $this->state->save();
726
+
727
+ SGPing::update();
728
+
729
+ @fclose($tmpFp);
730
+ @fclose($this->fileHandle);
731
+
732
+ $this->delegate->reload();
733
+ }
734
+ }
735
+ }
736
+ SGPing::update();
737
+ }
738
+
739
+ if (is_resource($tmpFp)) {
740
+ @fclose($tmpFp);
741
+ }
742
+
743
+ if (!$warningFoundDuringExtract) {
744
+ @rename($tmpPath, $path);
745
+ }
746
+ else {
747
+ @unlink($tmpPath);
748
+ }
749
+
750
+ $this->delegate->didExtractFile($path);
751
+ $this->fileOffset = ftell($this->fileHandle);
752
+ }
753
+ else {
754
+ //if file should not be restored skip it and go to the next file
755
+ $ranges = $row[2];
756
+
757
+ for ($idx = 0; $idx < count($ranges); $idx++) {
758
+
759
+ $size = $ranges[$idx]['size'];
760
+
761
+ fseek($this->fileHandle, $size, SEEK_CUR);
762
+ }
763
+ $this->fileOffset = ftell($this->fileHandle);
764
+ }
765
+
766
+ $this->cdrFilesCount--;
767
+ }
768
+ }
769
+
770
+ private function unpackLittleEndian($data, $size)
771
+ {
772
+ $size *= 2; //2 characters for each byte
773
+
774
+ $data = unpack('H'.$size, strrev($data));
775
+ return $data[1];
776
+ }
777
+
778
+ private function createPath($path)
779
+ {
780
+ if (is_dir($path)) return true;
781
+ $prev_path = substr($path, 0, strrpos($path, '/', -2) + 1);
782
+ $return = $this->createPath($prev_path);
783
+ if ($return && is_writable($prev_path))
784
+ {
785
+ if (!@mkdir($path)) return false;
786
+
787
+ @chmod($path, 0777);
788
+ return true;
789
+ }
790
+
791
+ return false;
792
+ }
793
+ }
com/lib/SGAuthClient.php ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/BackupGuard/Client.php');
4
+
5
+ class SGAuthClient
6
+ {
7
+ private static $instance = null;
8
+ private $client = null;
9
+ private $accessToken = '';
10
+ private $accessTokenExpires = 0;
11
+
12
+ private function __construct()
13
+ {
14
+ $this->accessToken = SGConfig::get('SG_BACKUPGUARD_ACCESS_TOKEN', true);
15
+ $this->accessTokenExpires = SGConfig::get('SG_BACKUPGUARD_ACCESS_TOKEN_EXPIRES', true);
16
+
17
+ $this->client = new BackupGuard\Client($this->accessToken);
18
+ }
19
+
20
+ private function __clone()
21
+ {
22
+
23
+ }
24
+
25
+ public static function getInstance()
26
+ {
27
+ if (!self::$instance) {
28
+ self::$instance = new self();
29
+ }
30
+
31
+ return self::$instance;
32
+ }
33
+
34
+ public function getAccessToken()
35
+ {
36
+ return $this->accessToken;
37
+ }
38
+
39
+ public function login($email, $password)
40
+ {
41
+ try {
42
+ $accessToken = $this->createAccessToken($email, $password);
43
+ }
44
+ catch (BackupGuard\Exception $ex) {
45
+ return false;
46
+ }
47
+
48
+ $this->client->setAccessToken($accessToken);
49
+
50
+ return true;
51
+ }
52
+
53
+ public function logout()
54
+ {
55
+ $this->setTokens(); //reset all tokens
56
+ $this->client->setAccessToken(null);
57
+ return true;
58
+ }
59
+
60
+ public function getCurrentUser()
61
+ {
62
+ try {
63
+ $user = $this->client->getCurrentUser();
64
+ }
65
+ catch (BackupGuard\Exception $ex) {
66
+ return false;
67
+ }
68
+
69
+ return $user;
70
+ }
71
+
72
+ public function validateUrl($url)
73
+ {
74
+ if (!$this->prepareAuthorizedRequest()) {
75
+ return -1;
76
+ }
77
+
78
+ try {
79
+ $result = $this->client->validateUrl($url, SG_PRODUCT_IDENTIFIER);
80
+ }
81
+ catch (BackupGuard\Exception $ex) {
82
+ $result = $this->handleUnauthorizedException($ex);
83
+ if ($result === true) { //we can try again
84
+ $result = $this->validateUrl($url);
85
+ }
86
+ }
87
+
88
+ return $result;
89
+ }
90
+
91
+ public function getAllUserProducts()
92
+ {
93
+ if (!$this->prepareAuthorizedRequest()) {
94
+ return -1;
95
+ }
96
+
97
+ try {
98
+ $result = $this->client->getAllUserProducts(SG_PRODUCT_IDENTIFIER);
99
+ }
100
+ catch (BackupGuard\Exception $ex) {
101
+ $result = $this->handleUnauthorizedException($ex);
102
+ if ($result === true) { //we can try again
103
+ $result = $this->getAllUserProducts();
104
+ }
105
+ }
106
+
107
+ return $result;
108
+ }
109
+
110
+ public function isAnyLicenseAvailable($products)
111
+ {
112
+ foreach ($products as $product) {
113
+ if (!$product['licenses']) {
114
+ return true;
115
+ }
116
+ $availableLicenses = $product['licenses']-$product['used_licenses'];
117
+ if ($availableLicenses > 0) {
118
+ return true;
119
+ }
120
+ }
121
+
122
+ return false;
123
+ }
124
+
125
+ public function linkUrlToProduct($url, $userProductId, &$error)
126
+ {
127
+ if (!$this->prepareAuthorizedRequest()) {
128
+ return -1;
129
+ }
130
+
131
+ try {
132
+ $result = $this->client->linkUrlToProduct($url, $userProductId);
133
+ }
134
+ catch (BackupGuard\Exception $ex) {
135
+ $result = $this->handleUnauthorizedException($ex);
136
+ if ($result === true) { //we can try again
137
+ $result = $this->linkUrlToProduct($url, $userProductId);
138
+ }
139
+
140
+ $error = $ex->getMessage();
141
+ }
142
+
143
+ return $result;
144
+ }
145
+
146
+ public function filterUpdateChecks($options)
147
+ {
148
+ //we need to be sure that access token is fresh before checking for updates
149
+ $this->prepareAuthorizedRequest();
150
+
151
+ $options['headers']['access_token'] = $this->getAccessToken();
152
+
153
+ return $options;
154
+ }
155
+
156
+ private function handleUnauthorizedException($ex)
157
+ {
158
+ if ($ex instanceof BackupGuard\UnauthorizedException) {
159
+ //access token has expired or is invalid, refresh it
160
+ if ($this->refreshAccessToken()) {
161
+ return true;
162
+ }
163
+ else {
164
+ return -1; //could not refresh token, login is required
165
+ }
166
+ }
167
+
168
+ return false;
169
+ }
170
+
171
+ private function prepareAuthorizedRequest()
172
+ {
173
+ //no access token found, login is required
174
+ if (!$this->accessToken) {
175
+ return false;
176
+ }
177
+
178
+ //access token is expired, try to refresh it
179
+ if (time() > $this->accessTokenExpires) {
180
+ if (!$this->refreshAccessToken()) {
181
+ return false;
182
+ }
183
+ }
184
+
185
+ return true;
186
+ }
187
+
188
+ private function setTokens($accessToken = '', $accessTokenExpires = 0, $refreshToken = '')
189
+ {
190
+ $this->accessToken = $accessToken;
191
+ $this->accessTokenExpires = $accessTokenExpires;
192
+ $this->client->setAccessToken($accessToken);
193
+
194
+ SGConfig::set('SG_BACKUPGUARD_ACCESS_TOKEN', $accessToken, true);
195
+ SGConfig::set('SG_BACKUPGUARD_ACCESS_TOKEN_EXPIRES', $accessTokenExpires, true);
196
+
197
+ SGConfig::set('SG_BACKUPGUARD_REFRESH_TOKEN', $refreshToken, true);
198
+ }
199
+
200
+ private function createAccessToken($email, $password)
201
+ {
202
+ $tokens = $this->client->createAccessToken(
203
+ SG_BACKUPGUARD_CLIENT_ID,
204
+ SG_BACKUPGUARD_CLIENT_SECRET,
205
+ $email,
206
+ $password
207
+ );
208
+
209
+ $this->setTokens(
210
+ $tokens['access_token'],
211
+ time()+BackupGuard\Config::TOKEN_EXPIRES,
212
+ $tokens['refresh_token']
213
+ );
214
+
215
+ return $tokens['access_token'];
216
+ }
217
+
218
+ private function refreshAccessToken()
219
+ {
220
+ $refreshToken = SGConfig::get('SG_BACKUPGUARD_REFRESH_TOKEN', true);
221
+ if (!$refreshToken) {
222
+ $this->logout();
223
+ return false;
224
+ }
225
+
226
+ try {
227
+ $tokens = $this->client->refreshAccessToken(
228
+ SG_BACKUPGUARD_CLIENT_ID,
229
+ SG_BACKUPGUARD_CLIENT_SECRET,
230
+ $refreshToken
231
+ );
232
+ }
233
+ catch (BackupGuard\Exception $ex) { //for some reason the refresh token doesn't work
234
+ $this->logout();
235
+ return false;
236
+ }
237
+
238
+ $this->setTokens(
239
+ $tokens['access_token'],
240
+ time()+BackupGuard\Config::TOKEN_EXPIRES,
241
+ $tokens['refresh_token']
242
+ );
243
+
244
+ return $tokens['access_token'];
245
+ }
246
+
247
+ // Added by Nerses
248
+ public function getMerchantOrderId()
249
+ {
250
+ if (!$this->prepareAuthorizedRequest()) {
251
+ return -1;
252
+ }
253
+
254
+ try {
255
+ $result = $this->client->getMerchantOrderId(SG_PRODUCT_IDENTIFIER);
256
+ }
257
+ catch (BackupGuard\Exception $ex) {
258
+ $result = $this->handleUnauthorizedException($ex);
259
+ if ($result === true) { //we can try again
260
+ $result = $this->getMerchantOrderId();
261
+ }
262
+
263
+ $error = $ex->getMessage();
264
+ }
265
+
266
+ return $result;
267
+ }
268
+ }
com/lib/SGCallback.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ */
6
+ class SGCallback
7
+ {
8
+ private $className;
9
+ private $methodName;
10
+ private $params;
11
+
12
+ function __construct($className, $methodName, $params = array())
13
+ {
14
+ $this->className = $className;
15
+ $this->methodName = $methodName;
16
+ $this->params = $params;
17
+ }
18
+
19
+ public function canPerform()
20
+ {
21
+ if (class_exists($this->className)) {
22
+
23
+ $callbackClass = $this->className;
24
+ $sgCallback = new $callbackClass();
25
+
26
+ if (method_exists($sgCallback, $this->methodName)) {
27
+ return true;
28
+ }
29
+
30
+ return false;
31
+ }
32
+
33
+ return false;
34
+ }
35
+
36
+ public function perform()
37
+ {
38
+ $callbackClass = $this->className;
39
+ $methodName = $this->methodName;
40
+
41
+ $obj = new $callbackClass();
42
+ $obj->$methodName($this->params);
43
+ }
44
+
45
+ public function toString()
46
+ {
47
+ return json_encode(array(
48
+ 'class' => $this->className,
49
+ 'method' => $this->methodName,
50
+ 'params' => $this->params
51
+ ));
52
+ }
53
+ }
com/lib/SGCdrEntry.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/SGEntry.php');
4
+
5
+ /**
6
+ *
7
+ */
8
+ class SGCdrEntry implements SGEntry
9
+ {
10
+ private $name;
11
+ private $offset;
12
+ private $path;
13
+ private $type;
14
+ private $size;
15
+
16
+ public function __construct()
17
+ {
18
+ $this->type = SG_ENTRY_TYPE_CDR;
19
+ }
20
+
21
+ public function getName()
22
+ {
23
+ return $this->name;
24
+ }
25
+
26
+ public function getOffset()
27
+ {
28
+ return $this->offset;
29
+ }
30
+
31
+ public function getPath()
32
+ {
33
+ return $this->path;
34
+ }
35
+
36
+ public function getSize()
37
+ {
38
+ return $this->size;
39
+ }
40
+
41
+ public function getType()
42
+ {
43
+ return $this->type;
44
+ }
45
+
46
+ public function setName($name)
47
+ {
48
+ $this->name = $name;
49
+ }
50
+
51
+ public function setOffset($offset)
52
+ {
53
+ $this->offset = $offset;
54
+ }
55
+
56
+ public function setPath($path)
57
+ {
58
+ $this->path = $path;
59
+ }
60
+
61
+ public function setSize($size)
62
+ {
63
+ $this->size = $size;
64
+ }
65
+
66
+ public function toArray()
67
+ {
68
+ $cdrEntry = array(
69
+ 'name' => $this->getName(),
70
+ 'offset' => $this->getOffset(),
71
+ 'path' => $this->getPath(),
72
+ 'type' => $this->getType(),
73
+ 'size' => $this->getSize()
74
+ );
75
+
76
+ return $cdrEntry;
77
+ }
78
+ }
com/lib/SGCharsetHandler.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGCharsetHandler
4
+ {
5
+ private $utf8mb4Available = false;
6
+ private $utf8mb4520Available = false;
7
+
8
+ public function __construct()
9
+ {
10
+ $this->utf8mb4Available = $this->mysqlHasCapability('utf8mb4');
11
+ $this->utf8mb4520Available = $this->mysqlHasCapability('utf8mb4_520');
12
+ }
13
+
14
+ public function replaceInvalidCharsets($query)
15
+ {
16
+ $search = array();
17
+ $replace = array();
18
+
19
+ //check for utf8mb4_520 support first
20
+ if (!$this->utf8mb4520Available) {
21
+ $search[] = 'COLLATE=utf8mb4_unicode_520_ci';
22
+ $replace[] = $this->utf8mb4Available?'COLLATE=utf8mb4_unicode_ci':'COLLATE=utf8_general_ci';
23
+
24
+ $search[] = 'COLLATE utf8mb4_unicode_520_ci';
25
+ $replace[] = $this->utf8mb4Available?'COLLATE utf8mb4_unicode_ci':'COLLATE utf8_general_ci';
26
+ }
27
+
28
+ //then check for utf8mb4 support
29
+ if (!$this->utf8mb4Available) {
30
+ $search[] = 'COLLATE=utf8mb4_unicode_ci';
31
+ $replace[] = 'COLLATE=utf8_general_ci';
32
+
33
+ $search[] = 'COLLATE utf8mb4_unicode_ci';
34
+ $replace[] = 'COLLATE utf8_general_ci';
35
+
36
+ $search[] = 'CHARACTER SET utf8mb4';
37
+ $replace[] = 'CHARACTER SET utf8';
38
+
39
+ $search[] = 'CHARSET=utf8mb4';
40
+ $replace[] = 'CHARSET=utf8';
41
+
42
+ $search[] = 'character_set_client = utf8mb4';
43
+ $replace[] = 'character_set_client = utf8';
44
+
45
+ $search[] = 'SET NAMES utf8mb4';
46
+ $replace[] = 'SET NAMES utf8';
47
+ }
48
+
49
+ if (count($search) && count($replace)) {
50
+ $query = str_replace($search, $replace, $query);
51
+ }
52
+
53
+ return $query;
54
+ }
55
+
56
+ public function getMysqlClientInfo()
57
+ {
58
+ if (function_exists('mysqli_connect')) {
59
+ if (version_compare(phpversion(), '5.5', '>=') || !function_exists('mysql_connect')) {
60
+ return @mysqli_get_client_info();
61
+ }
62
+ }
63
+
64
+ return SG_MYSQL_VERSION;
65
+ }
66
+
67
+ public function mysqlHasCapability($cap)
68
+ {
69
+ if ($cap == 'utf8mb4') {
70
+ if (version_compare(SG_MYSQL_VERSION, '5.5.3', '<')) {
71
+ return false;
72
+ }
73
+
74
+ $clientVersion = $this->getMysqlClientInfo();
75
+ /*
76
+ * libmysql has supported utf8mb4 since 5.5.3, same as the MySQL server.
77
+ * mysqlnd has supported utf8mb4 since 5.0.9.
78
+ */
79
+ if (false !== strpos($clientVersion, 'mysqlnd')) {
80
+ $clientVersion = preg_replace('/^\D+([\d.]+).*/', '$1', $clientVersion);
81
+ return version_compare($clientVersion, '5.0.9', '>=');
82
+ }
83
+ else {
84
+ return version_compare($clientVersion, '5.5.3', '>=');
85
+ }
86
+ }
87
+ else if ($cap == 'utf8mb4_520') {
88
+ return version_compare(SG_MYSQL_VERSION, '5.6', '>=');
89
+ }
90
+
91
+ return false;
92
+ }
93
+ }
com/lib/SGDBState.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/SGState.php');
4
+
5
+ class SGDBState extends SGState
6
+ {
7
+ private $progressCursor = 0;
8
+ private $cursor = 0;
9
+ private $numberOfEntries = 0;
10
+ private $lineSize = 0;
11
+ private $backedUpTables = array();
12
+ private $tablesToBackup = array();
13
+
14
+ function __construct()
15
+ {
16
+ $this->type = SG_STATE_TYPE_DB;
17
+ }
18
+
19
+ public function setBackedUpTables($backedUpTables)
20
+ {
21
+ $this->backedUpTables = $backedUpTables;
22
+ }
23
+
24
+ public function getBackedUpTables()
25
+ {
26
+ return $this->backedUpTables;
27
+ }
28
+
29
+ public function getTablesToBackup(){
30
+ return $this->tablesToBackup;
31
+ }
32
+
33
+ public function setTablesToBackup($tablesToBackup){
34
+ $this->tablesToBackup = $tablesToBackup;
35
+ }
36
+
37
+ public function setLineSize($lineSize)
38
+ {
39
+ $this->lineSize = $lineSize;
40
+ }
41
+
42
+ public function getLineSize()
43
+ {
44
+ return $this->lineSize;
45
+ }
46
+
47
+ public function setNumberOfEntries($numberOfEntries)
48
+ {
49
+ $this->numberOfEntries = $numberOfEntries;
50
+ }
51
+
52
+ public function getNumberOfEntries()
53
+ {
54
+ return $this->numberOfEntries;
55
+ }
56
+
57
+ public function setCursor($cursor)
58
+ {
59
+ $this->cursor = $cursor;
60
+ }
61
+
62
+ public function getCursor()
63
+ {
64
+ return $this->cursor;
65
+ }
66
+
67
+ public function setProgressCursor($progressCursor)
68
+ {
69
+ $this->progressCursor = $progressCursor;
70
+ }
71
+
72
+ public function getProgressCursor()
73
+ {
74
+ return $this->progressCursor;
75
+ }
76
+
77
+ public function init($stateJson)
78
+ {
79
+ $this->lineSize = $stateJson['lineSize'];
80
+ $this->numberOfEntries = $stateJson['numberOfEntries'];
81
+ $this->inprogress = $stateJson['inprogress'];
82
+ $this->cursor = $stateJson['cursor'];
83
+ $this->progressCursor = $stateJson['progressCursor'];
84
+ $this->offset = $stateJson['offset'];
85
+ $this->action = $stateJson['action'];
86
+ $this->actionId = $stateJson['actionId'];
87
+ $this->actionStartTs = $stateJson['actionStartTs'];
88
+ $this->backupFileName = $stateJson['backupFileName'];
89
+ $this->backupFilePath = $stateJson['backupFilePath'];
90
+ $this->progress = $stateJson['progress'];
91
+ $this->warningsFound = $stateJson['warningsFound'];
92
+ $this->pendingStorageUploads = $stateJson['pendingStorageUploads'];
93
+ $this->backedUpTables = $stateJson['backedUpTables'];
94
+ $this->tablesToBackup = $stateJson['tablesToBackup'];
95
+
96
+ return $this;
97
+ }
98
+
99
+ public function save()
100
+ {
101
+ file_put_contents(SG_BACKUP_DIRECTORY.SG_STATE_FILE_NAME, json_encode(array(
102
+ 'lineSize' => $this->lineSize,
103
+ 'numberOfEntries' => $this->numberOfEntries,
104
+ 'inprogress' => $this->inprogress,
105
+ 'cursor' => $this->cursor,
106
+ 'progressCursor' => $this->progressCursor,
107
+ 'offset' => $this->offset,
108
+ 'type' => $this->type,
109
+ 'token' => $this->token,
110
+ 'action' => $this->action,
111
+ 'actionId' => $this->actionId,
112
+ 'actionStartTs' => $this->actionStartTs,
113
+ 'backupFileName' => $this->backupFileName,
114
+ 'backupFilePath' => $this->backupFilePath,
115
+ 'progress' => $this->progress,
116
+ 'warningsFound' => $this->warningsFound,
117
+ 'pendingStorageUploads' => $this->pendingStorageUploads,
118
+ 'backedUpTables' => $this->backedUpTables,
119
+ 'tablesToBackup' => $this->tablesToBackup
120
+ )));
121
+ }
122
+ }
com/lib/SGEntry.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ */
6
+ interface SGEntry
7
+ {
8
+ public function getType();
9
+ public function getPath();
10
+ public function setPath($path);
11
+ public function toArray();
12
+ }
com/lib/SGFileEntry.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/SGEntry.php');
4
+
5
+ /**
6
+ *
7
+ */
8
+ class SGFileEntry implements SGEntry
9
+ {
10
+ private $name;
11
+ private $type;
12
+ private $path;
13
+
14
+ public function __construct()
15
+ {
16
+ $this->type = SG_ENTRY_TYPE_FILE;
17
+ }
18
+
19
+ public function getName()
20
+ {
21
+ return $this->name;
22
+ }
23
+
24
+ public function getPath()
25
+ {
26
+ return $this->path;
27
+ }
28
+
29
+ public function getType()
30
+ {
31
+ return $this->type;
32
+ }
33
+
34
+ public function setName($name)
35
+ {
36
+ $this->name = $name;
37
+ }
38
+
39
+ public function setPath($path)
40
+ {
41
+ $this->path = $path;
42
+ }
43
+
44
+ public function toArray()
45
+ {
46
+ $fileEntry = array(
47
+ 'name' => $this->getName(),
48
+ 'path' => $this->getPath(),
49
+ 'type' => $this->getType()
50
+ );
51
+
52
+ return $fileEntry;
53
+ }
54
+ }
com/lib/SGFileState.php ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/SGState.php');
4
+
5
+ class SGFileState extends SGState
6
+ {
7
+ private $cdrSize = 0;
8
+ private $ranges = array();
9
+ private $fileOffsetInArchive = 0;
10
+ private $headerSize = 0;
11
+ private $cdr = array();
12
+ private $cursor = 0;
13
+ private $rangeCursor = 0;
14
+ private $numberOfEntries = 0;
15
+
16
+ private $progressCursor = 0;
17
+ private $cdrCursor = 0;
18
+
19
+ function __construct()
20
+ {
21
+ $this->type = SG_STATE_TYPE_FILE;
22
+ }
23
+
24
+ public function setCdrCursor($cdrCursor)
25
+ {
26
+ $this->cdrCursor = $cdrCursor;
27
+ }
28
+
29
+ public function getCdrCursor()
30
+ {
31
+ return $this->cdrCursor;
32
+ }
33
+
34
+ public function getProgressCursor()
35
+ {
36
+ return $this->progressCursor;
37
+ }
38
+
39
+ public function setProgressCursor($progressCursor)
40
+ {
41
+ $this->progressCursor = $progressCursor;
42
+ }
43
+
44
+ public function setCursor($cursor)
45
+ {
46
+ $this->cursor = $cursor;
47
+ }
48
+
49
+ public function setRangeCursor($rangeCursor)
50
+ {
51
+ $this->rangeCursor = $rangeCursor;
52
+ }
53
+
54
+ public function setNumberOfEntries($numberOfEntries)
55
+ {
56
+ $this->numberOfEntries = $numberOfEntries;
57
+ }
58
+
59
+ public function getCursor()
60
+ {
61
+ return $this->cursor;
62
+ }
63
+
64
+ public function getRangeCursor()
65
+ {
66
+ return $this->rangeCursor;
67
+ }
68
+
69
+ public function getNumberOfEntries()
70
+ {
71
+ return $this->numberOfEntries;
72
+ }
73
+
74
+ public function setCdr($cdr = array())
75
+ {
76
+ $this->cdr = $cdr;
77
+ }
78
+
79
+ public function getCdr()
80
+ {
81
+ return $this->cdr;
82
+ }
83
+
84
+ public function setCdrSize($cdrSize)
85
+ {
86
+ $this->cdrSize = $cdrSize;
87
+ }
88
+
89
+ public function setRanges($ranges)
90
+ {
91
+ $this->ranges = $ranges;
92
+ }
93
+
94
+ public function setHeaderSize($headerSize)
95
+ {
96
+ $this->headerSize = $headerSize;
97
+ }
98
+
99
+ public function getHeaderSize()
100
+ {
101
+ return $this->headerSize;
102
+ }
103
+
104
+ public function getRanges()
105
+ {
106
+ return $this->ranges;
107
+ }
108
+
109
+ public function getCdrSize()
110
+ {
111
+ return $this->cdrSize;
112
+ }
113
+
114
+ public function getFileOffsetInArchive()
115
+ {
116
+ return $this->fileOffsetInArchive;
117
+ }
118
+
119
+ public function setFileOffsetInArchive($fileOffsetInArchive)
120
+ {
121
+ $this->fileOffsetInArchive = $fileOffsetInArchive;
122
+ }
123
+
124
+ public function init($stateJson)
125
+ {
126
+ $this->cdrSize = $stateJson['cdrSize'];
127
+ $this->ranges = $stateJson['ranges'];
128
+ $this->offset = $stateJson['offset'];
129
+ $this->headerSize = $stateJson['headerSize'];
130
+ $this->inprogress = $stateJson['inprogress'];
131
+ $this->cdr = $stateJson['cdr'];
132
+ $this->action = $stateJson['action'];
133
+ $this->actionId = $stateJson['actionId'];
134
+ $this->actionStartTs = $stateJson['actionStartTs'];
135
+ $this->backupFileName = $stateJson['backupFileName'];
136
+ $this->backupFilePath = $stateJson['backupFilePath'];
137
+ $this->progress = $stateJson['progress'];
138
+ $this->warningsFound = $stateJson['warningsFound'];
139
+ $this->pendingStorageUploads = $stateJson['pendingStorageUploads'];
140
+ $this->numberOfEntries = $stateJson['numberOfEntries'];
141
+ $this->cursor = $stateJson['cursor'];
142
+ $this->rangeCursor = $stateJson['rangeCursor'];
143
+ $this->fileOffsetInArchive = $stateJson['fileOffsetInArchive'];
144
+ $this->progressCursor = $stateJson['progressCursor'];
145
+ $this->cdrCursor = $stateJson['cdrCursor'];
146
+ $this->restoreMode = $stateJson['restoreMode'];
147
+ $this->restoreFiles = $stateJson['restoreFiles'];
148
+
149
+ return $this;
150
+ }
151
+
152
+ public function save()
153
+ {
154
+ file_put_contents(SG_BACKUP_DIRECTORY.SG_STATE_FILE_NAME, json_encode(array(
155
+ 'inprogress' => $this->inprogress,
156
+ 'headerSize' => $this->headerSize,
157
+ 'offset' => $this->offset,
158
+ 'ranges' => $this->ranges,
159
+ 'type' => $this->type,
160
+ 'token' => $this->token,
161
+ 'action' => $this->action,
162
+ 'actionId' => $this->actionId,
163
+ 'actionStartTs' => $this->actionStartTs,
164
+ 'backupFileName' => $this->backupFileName,
165
+ 'backupFilePath' => $this->backupFilePath,
166
+ 'progress' => $this->progress,
167
+ 'warningsFound' => $this->warningsFound,
168
+ 'cdrSize' => $this->cdrSize,
169
+ 'pendingStorageUploads' => $this->pendingStorageUploads,
170
+ 'cdr' => $this->cdr,
171
+ 'numberOfEntries' => $this->numberOfEntries,
172
+ 'cursor' => $this->cursor,
173
+ 'rangeCursor' => $this->rangeCursor,
174
+ 'fileOffsetInArchive' => $this->fileOffsetInArchive,
175
+ 'progressCursor' => $this->progressCursor,
176
+ 'cdrCursor' => $this->cdrCursor,
177
+ 'restoreMode' => $this->restoreMode,
178
+ 'restoreFiles' => $this->restoreFiles
179
+ )));
180
+ }
181
+ }
com/lib/SGMigrateState.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/SGState.php');
4
+
5
+ class SGMigrateState extends SGState
6
+ {
7
+ private $tableCursor = 0;
8
+ private $columnCursor = 0;
9
+
10
+ function __construct()
11
+ {
12
+ $this->type = SG_STATE_TYPE_MIGRATE;
13
+ }
14
+
15
+ public function setTableCursor($tableCursor)
16
+ {
17
+ $this->tableCursor = $tableCursor;
18
+ }
19
+
20
+ public function getTableCursor()
21
+ {
22
+ return $this->tableCursor;
23
+ }
24
+
25
+ public function setColumnCursor($columnCursor)
26
+ {
27
+ $this->columnCursor = $columnCursor;
28
+ }
29
+
30
+ public function getColumnCursor()
31
+ {
32
+ return $this->columnCursor;
33
+ }
34
+
35
+ public function init($stateJson)
36
+ {
37
+ $this->tableCursor = $stateJson['tableCursor'];
38
+ $this->columnCursor = $stateJson['columnCursor'];
39
+ $this->inprogress = $stateJson['inprogress'];
40
+ $this->action = $stateJson['action'];
41
+ $this->actionId = $stateJson['actionId'];
42
+
43
+ return $this;
44
+ }
45
+
46
+ public function save()
47
+ {
48
+ file_put_contents(SG_BACKUP_DIRECTORY.SG_STATE_FILE_NAME, json_encode(array(
49
+ 'inprogress' => $this->inprogress,
50
+ 'type' => $this->type,
51
+ 'token' => $this->token,
52
+ 'action' => $this->action,
53
+ 'actionId' => $this->actionId,
54
+ 'tableCursor' => $this->tableCursor,
55
+ 'columnCursor' => $this->columnCursor,
56
+ )));
57
+ }
58
+ }
com/lib/SGMysqldump.php ADDED
@@ -0,0 +1,1558 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SGMysqldump Class Doc Comment
4
+ *
5
+ * @category Library
6
+ * @package Ifsnop\Mysqldump
7
+ * @author Michael J. Calkins <clouddueling@github.com>
8
+ * @author Diego Torres <ifsnop@github.com>
9
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
10
+ * @link https://github.com/ifsnop/mysqldump-php
11
+ *
12
+ */
13
+
14
+ interface SGIMysqldumpDelegate
15
+ {
16
+ public function didExportRow();
17
+ }
18
+
19
+ class SGMysqldump
20
+ {
21
+
22
+ // Same as mysqldump
23
+ const MAXLINESIZE = 1000000;
24
+
25
+ // Available compression methods as constants
26
+ const GZIP = 'Gzip';
27
+ const BZIP2 = 'Bzip2';
28
+ const NONE = 'None';
29
+
30
+ // Available connection strings
31
+ const UTF8 = 'utf8';
32
+ const UTF8MB4 = 'utf8mb4';
33
+
34
+ // This can be set both on constructor or manually
35
+ public $db;
36
+ public $fileName;
37
+
38
+ // Internal stuff
39
+ private $tables = array();
40
+ private $views = array();
41
+ private $triggers = array();
42
+ private $dbHandler;
43
+ private $dbType;
44
+ private $compressManager;
45
+ private $typeAdapter;
46
+ private $dumpSettings = array();
47
+ private $version;
48
+ private $tableColumnTypes = array();
49
+ private $delegate = null;
50
+ private $excludeTables = array();
51
+
52
+ private $cursor = 0;
53
+ private $state = null;
54
+ private $inprogress = false;
55
+ private $backedUpTables = array();
56
+
57
+ /**
58
+ * Constructor of SGMysqldump. Note that in the case of an SQLite database
59
+ * connection, the filename must be in the $db parameter.
60
+ *
61
+ * @param string $db Database name
62
+ * @param string $type SQL database type
63
+ * @param array $dumpSettings SQL database settings
64
+ */
65
+ public function __construct(
66
+ $dbHandler,
67
+ $db = '',
68
+ $type = 'mysql',
69
+ $dumpSettings = array()
70
+ ) {
71
+ $dumpSettingsDefault = array(
72
+ 'include-tables' => array(),
73
+ 'exclude-tables' => array(),
74
+ 'compress' => SGMysqldump::NONE,
75
+ 'no-data' => false,
76
+ 'add-drop-table' => false,
77
+ 'single-transaction' => true,
78
+ 'lock-tables' => true,
79
+ 'add-locks' => true,
80
+ 'extended-insert' => true,
81
+ 'disable-keys' => true,
82
+ 'where' => '',
83
+ 'no-create-info' => false,
84
+ 'skip-triggers' => false,
85
+ 'add-drop-trigger' => true,
86
+ 'hex-blob' => true,
87
+ 'databases' => false,
88
+ 'add-drop-database' => false,
89
+ 'skip-tz-utz' => false,
90
+ 'no-autocommit' => true,
91
+ 'default-character-set' => SGMysqldump::UTF8,
92
+ 'skip-comments' => false,
93
+ 'skip-dump-date' => false,
94
+ /* deprecated */
95
+ 'disable-foreign-keys-check' => true
96
+ );
97
+
98
+ $this->db = $db;
99
+ $this->dbHandler = $dbHandler;
100
+ $this->dbType = strtolower($type);
101
+ $this->dumpSettings = self::array_replace_recursive($dumpSettingsDefault, $dumpSettings);
102
+ $this->excludeTables = $dumpSettings['exclude-tables'];
103
+
104
+ $diff = array_diff(array_keys($this->dumpSettings), array_keys($dumpSettingsDefault));
105
+ if (count($diff)>0) {
106
+ throw new Exception("Unexpected value in dumpSettings: (" . implode(",", $diff) . ")");
107
+ }
108
+
109
+ // Create a new compressManager to manage compressed output
110
+ $this->compressManager = CompressManagerFactory::create($this->dumpSettings['compress']);
111
+ }
112
+
113
+ public function setDelegate(SGIMysqldumpDelegate $delegate)
114
+ {
115
+ $this->delegate = $delegate;
116
+ }
117
+
118
+ private function getState()
119
+ {
120
+ return $this->delegate->getState();
121
+ }
122
+
123
+ private function shouldReload()
124
+ {
125
+ return $this->delegate->shouldReload();
126
+ }
127
+
128
+ /**
129
+ * Custom array_replace_recursive to be used if PHP < 5.3
130
+ * Replaces elements from passed arrays into the first array recursively
131
+ *
132
+ * @param array $array1 The array in which elements are replaced
133
+ * @param array $array2 The array from which elements will be extracted
134
+ *
135
+ * @return array Returns an array, or NULL if an error occurs.
136
+ */
137
+ public static function array_replace_recursive($array1, $array2)
138
+ {
139
+ if (function_exists('array_replace_recursive')) {
140
+ return array_replace_recursive($array1, $array2);
141
+ }
142
+
143
+ foreach ($array2 as $key => $value) {
144
+ if (is_array($value)) {
145
+ $array1[$key] = self::array_replace_recursive($array1[$key], $value);
146
+ } else {
147
+ $array1[$key] = $value;
148
+ }
149
+ }
150
+ return $array1;
151
+ }
152
+
153
+ /**
154
+ * Connect with PDO
155
+ *
156
+ * @return null
157
+ */
158
+ private function connect()
159
+ {
160
+ $this->dbHandler->query("SET NAMES " . $this->dumpSettings['default-character-set']);
161
+ $this->typeAdapter = TypeAdapterFactory::create($this->dbType, $this->dbHandler);
162
+ }
163
+
164
+ /**
165
+ * Main call
166
+ *
167
+ * @param string $filename Name of file to write sql dump to
168
+ * @return null
169
+ */
170
+ public function start($filename)
171
+ {
172
+ $this->state = $this->getState();
173
+ $this->fileName = $filename;
174
+
175
+ // Connect to database
176
+ $this->connect();
177
+
178
+ // Create output file
179
+ $this->compressManager->open($this->fileName);
180
+
181
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
182
+ // Write some basic info to output file
183
+ $this->compressManager->write($this->getDumpFileHeader());
184
+
185
+ // Store server settings and use sanner defaults to dump
186
+ $this->compressManager->write(
187
+ $this->typeAdapter->backup_parameters($this->dumpSettings)
188
+ );
189
+
190
+ if ($this->dumpSettings['databases']) {
191
+ $this->compressManager->write(
192
+ $this->typeAdapter->getDatabaseHeader($this->db)
193
+ );
194
+ if ($this->dumpSettings['add-drop-database']) {
195
+ $this->compressManager->write(
196
+ $this->typeAdapter->add_drop_database($this->db)
197
+ );
198
+ }
199
+ }
200
+ }
201
+
202
+ // Get table, view and trigger structures from database
203
+ $this->getDatabaseStructure();
204
+
205
+ if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
206
+ if ($this->dumpSettings['databases']) {
207
+ $this->compressManager->write(
208
+ $this->typeAdapter->databases($this->db)
209
+ );
210
+ }
211
+
212
+ // If there still are some tables/views in include-tables array,
213
+ // that means that some tables or views weren't found.
214
+ // Give proper error and exit.
215
+ if (0 < count($this->dumpSettings['include-tables'])) {
216
+ $name = implode(",", $this->dumpSettings['include-tables']);
217
+ throw new SGException("Table or View (" . $name . ") not found in database");
218
+ }
219
+ }
220
+
221
+ $this->exportTables();
222
+ $this->exportViews();
223
+ $this->exportTriggers();
224
+
225
+ // Restore saved parameters
226
+ $this->compressManager->write(
227
+ $this->typeAdapter->restore_parameters($this->dumpSettings)
228
+ );
229
+ // Write some stats to output file
230
+ $this->compressManager->write($this->getDumpFileFooter());
231
+ // Close output file
232
+ $this->compressManager->close();
233
+ }
234
+
235
+ /**
236
+ * Returns header for dump file
237
+ *
238
+ * @return string
239
+ */
240
+ private function getDumpFileHeader()
241
+ {
242
+ $header = '';
243
+ if (!$this->dumpSettings['skip-comments']) {
244
+ // Some info about software, source and time
245
+ $header = '';
246
+
247
+ if (!empty($this->version)) {
248
+ $header .= "-- Server version \t" . $this->version . PHP_EOL;
249
+ }
250
+
251
+ $header .= "-- Date: " . @date('r') . PHP_EOL . PHP_EOL;
252
+ }
253
+ return $header;
254
+ }
255
+
256
+ /**
257
+ * Returns footer for dump file
258
+ *
259
+ * @return string
260
+ */
261
+ private function getDumpFileFooter()
262
+ {
263
+ $footer = '';
264
+ if (!$this->dumpSettings['skip-comments']) {
265
+ $footer .= '-- Dump completed';
266
+ if (!$this->dumpSettings['skip-dump-date']) {
267
+ $footer .= ' on: ' . @date('r');
268
+ }
269
+ $footer .= PHP_EOL;
270
+ }
271
+
272
+ return $footer;
273
+ }
274
+
275
+ /**
276
+ * Reads table and views names from database.
277
+ * Fills $this->tables array so they will be dumped later.
278
+ *
279
+ * @return null
280
+ */
281
+ private function getDatabaseStructure()
282
+ {
283
+ // Listing all tables from database
284
+ if (empty($this->dumpSettings['include-tables'])) {
285
+ // include all tables for now, blacklisting happens later
286
+ $arr = $this->dbHandler->query($this->typeAdapter->show_tables($this->db));
287
+ foreach ($arr as $row) {
288
+ // Push wp_options table to front to solve restore related bug
289
+ if ($row['tbl_name'] != SG_ENV_DB_PREFIX.'options') {
290
+ array_push($this->tables, $row['tbl_name']);
291
+ }
292
+ else {
293
+ array_unshift($this->tables, $row['tbl_name']);
294
+ }
295
+ }
296
+ } else {
297
+ // include only the tables mentioned in include-tables
298
+ $arr = $this->dbHandler->query($this->typeAdapter->show_tables($this->db));
299
+ foreach ($arr as $row) {
300
+ if (in_array($row['tbl_name'], $this->dumpSettings['include-tables'], true)) {
301
+ array_push($this->tables, $row['tbl_name']);
302
+ $elem = array_search(
303
+ $row['tbl_name'],
304
+ $this->dumpSettings['include-tables']
305
+ );
306
+ unset($this->dumpSettings['include-tables'][$elem]);
307
+ }
308
+ }
309
+ }
310
+
311
+ // Listing all views from database
312
+ if (empty($this->dumpSettings['include-tables'])) {
313
+ // include all views for now, blacklisting happens later
314
+ $arr = $this->dbHandler->query($this->typeAdapter->show_views($this->db));
315
+ foreach ($arr as $row) {
316
+ array_push($this->views, $row['tbl_name']);
317
+ }
318
+ } else {
319
+ // include only the tables mentioned in include-tables
320
+ $arr = $this->dbHandler->query($this->typeAdapter->show_views($this->db));
321
+ foreach ($arr as $row) {
322
+ if (in_array($row['tbl_name'], $this->dumpSettings['include-tables'], true)) {
323
+ array_push($this->views, $row['tbl_name']);
324
+ $elem = array_search(
325
+ $row['tbl_name'],
326
+ $this->dumpSettings['include-tables']
327
+ );
328
+ unset($this->dumpSettings['include-tables'][$elem]);
329
+ }
330
+ }
331
+ }
332
+
333
+ // Listing all triggers from database
334
+ if (false === $this->dumpSettings['skip-triggers']) {
335
+ $arr = $this->dbHandler->query($this->typeAdapter->show_triggers($this->db));
336
+ foreach ($arr as $row) {
337
+ array_push($this->triggers, $row['Trigger']);
338
+ }
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Exports all the tables selected from database
344
+ *
345
+ * @return null
346
+ */
347
+ private function exportTables()
348
+ {
349
+ if ($this->state->getAction() != SG_STATE_ACTION_PREPARING_STATE_FILE) {
350
+ $this->cursor = $this->state->getCursor();
351
+ $this->inprogress = $this->state->getInprogress();
352
+ $this->backedUpTables = $this->state->getBackedUpTables();
353
+ }
354
+ else {
355
+ $this->cursor = 0;
356
+ $this->inprogress = false;
357
+ $this->backedUpTables = array();
358
+ }
359
+
360
+ // Exporting tables one by one
361
+ for($i = $this->cursor; $i < count($this->tables); $i++) {
362
+ $table = $this->tables[$i];
363
+ if (in_array($table, $this->dumpSettings['exclude-tables'], true)) {
364
+ $this->cursor += 1;
365
+ continue;
366
+ }
367
+
368
+ if (!$this->inprogress) {
369
+ SGBackupLog::writeAction('backup table: '.$table, SG_BACKUP_LOG_POS_START);
370
+ $this->getTableStructure($table, false);
371
+ }
372
+ else {
373
+ $this->getTableStructure($table, true);
374
+ }
375
+
376
+ if (false === $this->dumpSettings['no-data']) {
377
+ $this->listValues($table);
378
+ }
379
+
380
+ $this->backedUpTables[] = $table;
381
+ SGBackupLog::writeAction('backup table: '.$table, SG_BACKUP_LOG_POS_END);
382
+ }
383
+
384
+ SGConfig::set('SG_BACKUPED_TABLES', json_encode($this->backedUpTables));
385
+ }
386
+
387
+ /**
388
+ * Exports all the views found in database
389
+ *
390
+ * @return null
391
+ */
392
+ private function exportViews()
393
+ {
394
+ if (false === $this->dumpSettings['no-create-info']) {
395
+ // Exporting views one by one
396
+ foreach ($this->views as $view) {
397
+ if (in_array($view, $this->dumpSettings['exclude-tables'], true)) {
398
+ continue;
399
+ }
400
+ $this->getViewStructure($view);
401
+ }
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Exports all the triggers found in database
407
+ *
408
+ * @return null
409
+ */
410
+ private function exportTriggers()
411
+ {
412
+ // Exporting triggers one by one
413
+ foreach ($this->triggers as $trigger) {
414
+ $this->getTriggerStructure($trigger);
415
+ }
416
+ }
417
+
418
+ /**
419
+ * Table structure extractor
420
+ *
421
+ * @todo move specific mysql code to typeAdapter
422
+ * @param string $tableName Name of table to export
423
+ * @return null
424
+ */
425
+ private function getTableStructure($tableName, $skipCreate = false)
426
+ {
427
+ if (!$skipCreate && !$this->dumpSettings['no-create-info']) {
428
+ $ret = '';
429
+ if (!$this->dumpSettings['skip-comments']) {
430
+ $ret = "--" . PHP_EOL .
431
+ "-- Table structure for table `$tableName`" . PHP_EOL .
432
+ "--" . PHP_EOL . PHP_EOL;
433
+ }
434
+ $stmt = $this->typeAdapter->show_create_table($tableName);
435
+ $arr = $this->dbHandler->query($stmt);
436
+ foreach ($arr as $r) {
437
+ $this->compressManager->write($ret);
438
+ if ($this->dumpSettings['add-drop-table']) {
439
+ $this->compressManager->write(
440
+ $this->typeAdapter->drop_table($tableName)
441
+ );
442
+ }
443
+ $this->compressManager->write(
444
+ $this->typeAdapter->create_table($r, $this->dumpSettings)
445
+ );
446
+ break;
447
+ }
448
+ }
449
+
450
+ $columnTypes = array();
451
+ $columns = $this->dbHandler->query(
452
+ $this->typeAdapter->show_columns($tableName)
453
+ );
454
+
455
+ foreach($columns as $key => $col) {
456
+ $types = $this->typeAdapter->parseColumnType($col);
457
+ $columnTypes[$col['Field']] = array(
458
+ 'is_numeric'=> $types['is_numeric'],
459
+ 'is_blob' => $types['is_blob'],
460
+ 'type' => $types['type']
461
+ );
462
+ }
463
+ $this->tableColumnTypes[$tableName] = $columnTypes;
464
+ return;
465
+ }
466
+
467
+ /**
468
+ * View structure extractor
469
+ *
470
+ * @todo move mysql specific code to typeAdapter
471
+ * @param string $viewName Name of view to export
472
+ * @return null
473
+ */
474
+ private function getViewStructure($viewName)
475
+ {
476
+ $ret = '';
477
+ if (!$this->dumpSettings['skip-comments']) {
478
+ $ret = "--" . PHP_EOL .
479
+ "-- Table structure for view `${viewName}`" . PHP_EOL .
480
+ "--" . PHP_EOL . PHP_EOL;
481
+ }
482
+ $this->compressManager->write($ret);
483
+ $stmt = $this->typeAdapter->show_create_view($viewName);
484
+ $arr = $this->dbHandler->query($stmt);
485
+ foreach ($arr as $r) {
486
+ if ($this->dumpSettings['add-drop-table']) {
487
+ $this->compressManager->write(
488
+ $this->typeAdapter->drop_view($viewName)
489
+ );
490
+ }
491
+ $this->compressManager->write(
492
+ $this->typeAdapter->create_view($r)
493
+ );
494
+ break;
495
+ }
496
+ }
497
+
498
+ /**
499
+ * Trigger structure extractor
500
+ *
501
+ * @param string $triggerName Name of trigger to export
502
+ * @return null
503
+ */
504
+ private function getTriggerStructure($triggerName)
505
+ {
506
+ $stmt = $this->typeAdapter->show_create_trigger($triggerName);
507
+ $arr = $this->dbHandler->query($stmt);
508
+ foreach ($arr as $r) {
509
+ if ($this->dumpSettings['add-drop-trigger']) {
510
+ $this->compressManager->write(
511
+ $this->typeAdapter->add_drop_trigger($triggerName)
512
+ );
513
+ }
514
+ $this->compressManager->write(
515
+ $this->typeAdapter->create_trigger($r)
516
+ );
517
+ return;
518
+ }
519
+
520
+ }
521
+
522
+
523
+ /**
524
+ * Escape values with quotes when needed
525
+ *
526
+ * @param string $tableName Name of table which contains rows
527
+ * @param array $row Associative array of column names and values to be quoted
528
+ *
529
+ * @return string
530
+ */
531
+ private function escape($tableName, $row)
532
+ {
533
+ $ret = array();
534
+ $columnTypes = $this->tableColumnTypes[$tableName];
535
+ foreach ($row as $colName => $colValue) {
536
+ if (is_null($colValue)) {
537
+ $ret[] = "NULL";
538
+ } elseif ($this->dumpSettings['hex-blob'] && $columnTypes[$colName]['is_blob']) {
539
+ if ($columnTypes[$colName]['type'] == 'bit' || !empty($colValue)) {
540
+ $ret[] = "0x${colValue}";
541
+ } else {
542
+ $ret[] = "''";
543
+ }
544
+ } elseif ($columnTypes[$colName]['is_numeric']) {
545
+ $ret[] = $colValue;
546
+ } else {
547
+ $str = "'".str_replace("'", "''", $colValue)."'";
548
+ $str = str_replace("\\", "\\\\", $str);
549
+ $ret[] = $str;
550
+ }
551
+ }
552
+ return $ret;
553
+ }
554
+
555
+ /**
556
+ * Table rows extractor
557
+ *
558
+ * @param string $tableName Name of table to export
559
+ *
560
+ * @return null
561
+ */
562
+ private function listValues($tableName)
563
+ {
564
+ if (!$this->state->getInprogress()) {
565
+ $this->prepareListValues($tableName);
566
+ }
567
+
568
+ $onlyOnce = true;
569
+ $lineSize = 0;
570
+ $offset = 0;
571
+ if ($this->state->getInprogress()) {
572
+ $onlyOnce = false;
573
+ $offset = $this->state->getOffset();
574
+ $lineSize = $this->state->getLineSize();
575
+ }
576
+
577
+ $colStmt = $this->getColumnStmt($tableName);
578
+ $stmt = "SELECT $colStmt FROM `$tableName`";
579
+
580
+ if ($this->dumpSettings['where']) {
581
+ $stmt .= " WHERE {$this->dumpSettings['where']}";
582
+ }
583
+
584
+ $limit = SGConfig::get('SG_BACKUP_DATABASE_INSERT_LIMIT')?SGConfig::get('SG_BACKUP_DATABASE_INSERT_LIMIT'):SG_BACKUP_DATABASE_INSERT_LIMIT;
585
+
586
+ while (true) {
587
+ $st = $this->dbHandler->exec($stmt.' LIMIT '.$offset.','.$limit);
588
+
589
+ $row = $this->dbHandler->fetch($st);
590
+
591
+ $this->inprogress = true;
592
+ if (!$row) {
593
+ $this->inprogress = false;
594
+ $this->cursor += 1;
595
+ $this->delegate->saveStateData(0, $this->cursor, $this->inprogress, 0, $this->backedUpTables);
596
+ break;
597
+ }
598
+
599
+ while ($row) {
600
+ $vals = $this->escape($tableName, $row);
601
+
602
+ if ($onlyOnce) {
603
+ $lineSize += $this->compressManager->write(
604
+ "INSERT INTO `$tableName` VALUES (" . implode(",", $vals) . ")"
605
+ );
606
+ $onlyOnce = false;
607
+ }
608
+ else {
609
+ $lineSize += $this->compressManager->write(",(" . implode(",", $vals) . ")");
610
+ }
611
+ if ($lineSize > self::MAXLINESIZE) {
612
+ $onlyOnce = true;
613
+ $this->compressManager->write(";/*SGEnd*/" . PHP_EOL);
614
+ $lineSize = 0;
615
+ }
616
+
617
+ if ($this->delegate) {
618
+ $this->delegate->didExportRow();
619
+ }
620
+
621
+ $row = $this->dbHandler->fetch($st);
622
+ }
623
+
624
+ $offset += $limit;
625
+ if ($this->shouldReload()) {
626
+ $this->delegate->saveStateData($offset, $this->cursor, $this->inprogress, $lineSize, $this->backedUpTables);
627
+
628
+ if (backupGuardIsReloadEnabled()) {
629
+ $this->delegate->reload();
630
+ }
631
+ }
632
+ }
633
+
634
+ if (!$onlyOnce) {
635
+ $this->compressManager->write(";/*SGEnd*/" . PHP_EOL);
636
+ }
637
+
638
+ $this->endListValues($tableName);
639
+ }
640
+
641
+ /**
642
+ * Table rows extractor, append information prior to dump
643
+ *
644
+ * @param string $tableName Name of table to export
645
+ *
646
+ * @return null
647
+ */
648
+ function prepareListValues($tableName)
649
+ {
650
+ if (!$this->dumpSettings['skip-comments']) {
651
+ $this->compressManager->write(
652
+ "--" . PHP_EOL .
653
+ "-- Dumping data for table `$tableName`" . PHP_EOL .
654
+ "--" . PHP_EOL . PHP_EOL
655
+ );
656
+ }
657
+
658
+ if ($this->dumpSettings['single-transaction']) {
659
+ $this->dbHandler->query($this->typeAdapter->setup_transaction());
660
+ $this->dbHandler->query($this->typeAdapter->start_transaction());
661
+ }
662
+
663
+ if ($this->dumpSettings['lock-tables']) {
664
+ $this->typeAdapter->lock_table($tableName);
665
+ }
666
+
667
+ if ($this->dumpSettings['add-locks']) {
668
+ $this->compressManager->write(
669
+ $this->typeAdapter->start_add_lock_table($tableName)
670
+ );
671
+ }
672
+
673
+ if ($this->dumpSettings['disable-keys']) {
674
+ $this->compressManager->write(
675
+ $this->typeAdapter->start_add_disable_keys($tableName)
676
+ );
677
+ }
678
+
679
+ // Disable autocommit for faster reload
680
+ if ($this->dumpSettings['no-autocommit']) {
681
+ $this->compressManager->write(
682
+ $this->typeAdapter->start_disable_autocommit()
683
+ );
684
+ }
685
+
686
+ return;
687
+ }
688
+
689
+ /**
690
+ * Table rows extractor, close locks and commits after dump
691
+ *
692
+ * @param string $tableName Name of table to export
693
+ *
694
+ * @return null
695
+ */
696
+ function endListValues($tableName)
697
+ {
698
+ if ($this->dumpSettings['disable-keys']) {
699
+ $this->compressManager->write(
700
+ $this->typeAdapter->end_add_disable_keys($tableName)
701
+ );
702
+ }
703
+
704
+ if ($this->dumpSettings['add-locks']) {
705
+ $this->compressManager->write(
706
+ $this->typeAdapter->end_add_lock_table($tableName)
707
+ );
708
+ }
709
+
710
+ if ($this->dumpSettings['single-transaction']) {
711
+ $this->dbHandler->query($this->typeAdapter->commit_transaction());
712
+ }
713
+
714
+ if ($this->dumpSettings['lock-tables']) {
715
+ $this->typeAdapter->unlock_table($tableName);
716
+ }
717
+
718
+ // Commit to enable autocommit
719
+ if ($this->dumpSettings['no-autocommit']) {
720
+ $this->compressManager->write(
721
+ $this->typeAdapter->end_disable_autocommit()
722
+ );
723
+ }
724
+
725
+ $this->compressManager->write(PHP_EOL);
726
+
727
+ return;
728
+ }
729
+
730
+ /**
731
+ * Build SQL List of all columns on current table
732
+ *
733
+ * @param string $tableName Name of table to get columns
734
+ *
735
+ * @return string SQL sentence with columns
736
+ */
737
+ function getColumnStmt($tableName)
738
+ {
739
+ $colStmt = array();
740
+ foreach($this->tableColumnTypes[$tableName] as $colName => $colType) {
741
+ if ($colType['type'] == 'bit' && $this->dumpSettings['hex-blob']) {
742
+ $colStmt[] = "LPAD(HEX(`${colName}`),2,'0') AS `${colName}`";
743
+ } else if ($colType['is_blob'] && $this->dumpSettings['hex-blob']) {
744
+ $colStmt[] = "HEX(`${colName}`) AS `${colName}`";
745
+ } else {
746
+ $colStmt[] = "`${colName}`";
747
+ }
748
+ }
749
+ $colStmt = implode($colStmt, ",");
750
+
751
+ return $colStmt;
752
+ }
753
+ }
754
+
755
+ /**
756
+ * Enum with all available compression methods
757
+ *
758
+ */
759
+ abstract class CompressMethod
760
+ {
761
+ public static $enums = array(
762
+ "None",
763
+ "Gzip",
764
+ "Bzip2"
765
+ );
766
+
767
+ /**
768
+ * @param string $c
769
+ * @return boolean
770
+ */
771
+ public static function isValid($c)
772
+ {
773
+ return in_array($c, self::$enums);
774
+ }
775
+ }
776
+
777
+ abstract class CompressManagerFactory
778
+ {
779
+ /**
780
+ * @param string $c
781
+ * @return CompressBzip2|CompressGzip|CompressNone
782
+ */
783
+ public static function create($c)
784
+ {
785
+ $c = ucfirst(strtolower($c));
786
+ if (! CompressMethod::isValid($c)) {
787
+ throw new Exception("Compression method ($c) is not defined yet");
788
+ }
789
+
790
+ $method = __NAMESPACE__ . "\\" . "Compress" . $c;
791
+
792
+ return new $method;
793
+ }
794
+
795
+ public static function prepareToWrite($str)
796
+ {
797
+ return $str;
798
+ }
799
+ }
800
+
801
+ class CompressBzip2 extends CompressManagerFactory
802
+ {
803
+ private $fileHandler = null;
804
+
805
+ public function __construct()
806
+ {
807
+ if (! function_exists("bzopen")) {
808
+ throw new Exception("Compression is enabled, but bzip2 lib is not installed or configured properly");
809
+ }
810
+ }
811
+
812
+ public function open($filename)
813
+ {
814
+ $this->fileHandler = bzopen($filename, 'a');
815
+ if (false === $this->fileHandler) {
816
+ throw new Exception("Output file is not writable");
817
+ }
818
+
819
+ return true;
820
+ }
821
+
822
+ public function write($str)
823
+ {
824
+ $str = self::prepareToWrite($str);
825
+
826
+ if (false === ($bytesWritten = bzwrite($this->fileHandler, $str))) {
827
+ throw new Exception("Writting to file failed! Probably, there is no more free space left?");
828
+ }
829
+ return $bytesWritten;
830
+ }
831
+
832
+ public function close()
833
+ {
834
+ return bzclose($this->fileHandler);
835
+ }
836
+ }
837
+
838
+ class CompressGzip extends CompressManagerFactory
839
+ {
840
+ private $fileHandler = null;
841
+
842
+ public function __construct()
843
+ {
844
+ if (! function_exists("gzopen")) {
845
+ throw new Exception("Compression is enabled, but gzip lib is not installed or configured properly");
846
+ }
847
+ }
848
+
849
+ public function open($filename)
850
+ {
851
+ $this->fileHandler = gzopen($filename, "ab");
852
+ if (false === $this->fileHandler) {
853
+ throw new Exception("Output file is not writable");
854
+ }
855
+
856
+ return true;
857
+ }
858
+
859
+ public function write($str)
860
+ {
861
+ $str = self::prepareToWrite($str);
862
+ if (false === ($bytesWritten = gzwrite($this->fileHandler, $str))) {
863
+ throw new Exception("Writting to file failed! Probably, there is no more free space left?");
864
+ }
865
+ return $bytesWritten;
866
+ }
867
+
868
+ public function close()
869
+ {
870
+ return gzclose($this->fileHandler);
871
+ }
872
+ }
873
+
874
+ class CompressNone extends CompressManagerFactory
875
+ {
876
+ private $fileHandler = null;
877
+
878
+ public function open($filename)
879
+ {
880
+ $this->fileHandler = fopen($filename, "ab");
881
+
882
+ if (false === $this->fileHandler) {
883
+ throw new Exception("Output file is not writable");
884
+ }
885
+
886
+ return true;
887
+ }
888
+
889
+ public function write($str)
890
+ {
891
+ $str = self::prepareToWrite($str);
892
+ if (false === ($bytesWritten = fwrite($this->fileHandler, $str))) {
893
+ throw new Exception("Writting to file failed! Probably, there is no more free space left?");
894
+ }
895
+ return $bytesWritten;
896
+ }
897
+
898
+ public function close()
899
+ {
900
+ return fclose($this->fileHandler);
901
+ }
902
+ }
903
+
904
+ /**
905
+ * Enum with all available TypeAdapter implementations
906
+ *
907
+ */
908
+ abstract class TypeAdapter
909
+ {
910
+ public static $enums = array(
911
+ "Sqlite",
912
+ "Mysql"
913
+ );
914
+
915
+ /**
916
+ * @param string $c
917
+ * @return boolean
918
+ */
919
+ public static function isValid($c)
920
+ {
921
+ return in_array($c, self::$enums);
922
+ }
923
+ }
924
+
925
+ /**
926
+ * TypeAdapter Factory
927
+ *
928
+ */
929
+ abstract class TypeAdapterFactory
930
+ {
931
+ /**
932
+ * @param string $c Type of database factory to create (Mysql, Sqlite,...)
933
+ * @param PDO $dbHandler
934
+ */
935
+ public static function create($c, $dbHandler = null)
936
+ {
937
+ $c = ucfirst(strtolower($c));
938
+ if (! TypeAdapter::isValid($c)) {
939
+ throw new Exception("Database type support for ($c) not yet available");
940
+ }
941
+ $method = __NAMESPACE__ . "\\" . "TypeAdapter" . $c;
942
+ return new $method($dbHandler);
943
+ }
944
+
945
+ /**
946
+ * function databases Add sql to create and use database
947
+ * @todo make it do something with sqlite
948
+ */
949
+ public function databases()
950
+ {
951
+ return "";
952
+ }
953
+
954
+ public function show_create_table($tableName)
955
+ {
956
+ return "SELECT tbl_name as 'Table', sql as 'Create Table' " .
957
+ "FROM sqlite_master " .
958
+ "WHERE type='table' AND tbl_name='$tableName'";
959
+ }
960
+
961
+ /**
962
+ * function create_table Get table creation code from database
963
+ * @todo make it do something with sqlite
964
+ */
965
+ public function create_table($row, $dumpSettings)
966
+ {
967
+ return "";
968
+ }
969
+
970
+ public function show_create_view($viewName)
971
+ {
972
+ return "SELECT tbl_name as 'View', sql as 'Create View' " .
973
+ "FROM sqlite_master " .
974
+ "WHERE type='view' AND tbl_name='$viewName'";
975
+ }
976
+
977
+ /**
978
+ * function create_view Get view creation code from database
979
+ * @todo make it do something with sqlite
980
+ */
981
+ public function create_view($row)
982
+ {
983
+ return "";
984
+ }
985
+
986
+ /**
987
+ * function show_create_trigger Get trigger creation code from database
988
+ * @todo make it do something with sqlite
989
+ */
990
+ public function show_create_trigger($triggerName)
991
+ {
992
+ return "";
993
+ }
994
+
995
+ /**
996
+ * function create_trigger Modify trigger code, add delimiters, etc
997
+ * @todo make it do something with sqlite
998
+ */
999
+ public function create_trigger($triggerName)
1000
+ {
1001
+ return "";
1002
+ }
1003
+
1004
+ public function show_tables()
1005
+ {
1006
+ return "SELECT tbl_name FROM sqlite_master WHERE type='table'";
1007
+ }
1008
+
1009
+ public function show_views()
1010
+ {
1011
+ return "SELECT tbl_name FROM sqlite_master WHERE type='view'";
1012
+ }
1013
+
1014
+ public function show_triggers()
1015
+ {
1016
+ return "SELECT Trigger FROM sqlite_master WHERE type='trigger'";
1017
+ }
1018
+
1019
+ public function show_columns()
1020
+ {
1021
+ if (func_num_args() != 1) {
1022
+ return "";
1023
+ }
1024
+
1025
+ $args = func_get_args();
1026
+
1027
+ return "pragma table_info(${args[0]})";
1028
+ }
1029
+
1030
+ public function setup_transaction()
1031
+ {
1032
+ return "";
1033
+ }
1034
+
1035
+ public function start_transaction()
1036
+ {
1037
+ return "BEGIN EXCLUSIVE";
1038
+ }
1039
+
1040
+ public function commit_transaction()
1041
+ {
1042
+ return "COMMIT";
1043
+ }
1044
+
1045
+ public function lock_table()
1046
+ {
1047
+ return "";
1048
+ }
1049
+
1050
+ public function unlock_table()
1051
+ {
1052
+ return "";
1053
+ }
1054
+
1055
+ public function start_add_lock_table()
1056
+ {
1057
+ return PHP_EOL;
1058
+ }
1059
+
1060
+ public function end_add_lock_table()
1061
+ {
1062
+ return PHP_EOL;
1063
+ }
1064
+
1065
+ public function start_add_disable_keys()
1066
+ {
1067
+ return PHP_EOL;
1068
+ }
1069
+
1070
+ public function end_add_disable_keys()
1071
+ {
1072
+ return PHP_EOL;
1073
+ }
1074
+
1075
+ public function start_disable_foreign_keys_check()
1076
+ {
1077
+ return PHP_EOL;
1078
+ }
1079
+
1080
+ public function end_disable_foreign_keys_check()
1081
+ {
1082
+ return PHP_EOL;
1083
+ }
1084
+
1085
+ public function add_drop_database()
1086
+ {
1087
+ return PHP_EOL;
1088
+ }
1089
+
1090
+ public function add_drop_trigger()
1091
+ {
1092
+ return PHP_EOL;
1093
+ }
1094
+
1095
+ public function drop_table()
1096
+ {
1097
+ return PHP_EOL;
1098
+ }
1099
+
1100
+ public function drop_view()
1101
+ {
1102
+ return PHP_EOL;
1103
+ }
1104
+
1105
+ /**
1106
+ * Decode column metadata and fill info structure.
1107
+ * type, is_numeric and is_blob will always be available.
1108
+ *
1109
+ * @param array $colType Array returned from "SHOW COLUMNS FROM tableName"
1110
+ * @return array
1111
+ */
1112
+ public function parseColumnType($colType)
1113
+ {
1114
+ return array();
1115
+ }
1116
+
1117
+ public function backup_parameters()
1118
+ {
1119
+ return PHP_EOL;
1120
+ }
1121
+
1122
+ public function restore_parameters()
1123
+ {
1124
+ return PHP_EOL;
1125
+ }
1126
+ }
1127
+
1128
+ class TypeAdapterPgsql extends TypeAdapterFactory
1129
+ {
1130
+ }
1131
+
1132
+ class TypeAdapterDblib extends TypeAdapterFactory
1133
+ {
1134
+ }
1135
+
1136
+ class TypeAdapterSqlite extends TypeAdapterFactory
1137
+ {
1138
+ }
1139
+
1140
+ class TypeAdapterMysql extends TypeAdapterFactory
1141
+ {
1142
+
1143
+ private $dbHandler = null;
1144
+
1145
+ // Numerical Mysql types
1146
+ public $mysqlTypes = array(
1147
+ 'numerical' => array(
1148
+ 'bit',
1149
+ 'tinyint',
1150
+ 'smallint',
1151
+ 'mediumint',
1152
+ 'int',
1153
+ 'integer',
1154
+ 'bigint',
1155
+ 'real',
1156
+ 'double',
1157
+ 'float',
1158
+ 'decimal',
1159
+ 'numeric'
1160
+ ),
1161
+ 'blob' => array(
1162
+ 'tinyblob',
1163
+ 'blob',
1164
+ 'mediumblob',
1165
+ 'longblob',
1166
+ 'binary',
1167
+ 'varbinary',
1168
+ 'bit'
1169
+ )
1170
+ );
1171
+
1172
+ public function __construct ($dbHandler)
1173
+ {
1174
+ $this->dbHandler = $dbHandler;
1175
+ }
1176
+
1177
+ public function databases()
1178
+ {
1179
+ if (func_num_args() != 1) {
1180
+ throw new Exception("Unexpected parameter passed to " . __METHOD__);
1181
+ }
1182
+
1183
+ $args = func_get_args();
1184
+ $databaseName = $args[0];
1185
+
1186
+ $resultSet = $this->dbHandler->query("SHOW VARIABLES LIKE 'character_set_database';");
1187
+ $characterSet = $resultSet[0]['Value'];
1188
+
1189
+ $resultSet = $this->dbHandler->query("SHOW VARIABLES LIKE 'collation_database';");
1190
+ $collationDb = $resultSet[0]['Value'];
1191
+ $ret = "";
1192
+
1193
+ $ret .= "CREATE DATABASE /*!32312 IF NOT EXISTS*/ `${databaseName}`".
1194
+ " /*!40100 DEFAULT CHARACTER SET ${characterSet} " .
1195
+ " COLLATE ${collationDb} */;/*SGEnd*/" . PHP_EOL . PHP_EOL .
1196
+ "USE `${databaseName}`;/*SGEnd*/" . PHP_EOL . PHP_EOL;
1197
+
1198
+ return $ret;
1199
+ }
1200
+
1201
+ public function show_create_table($tableName)
1202
+ {
1203
+ return "SHOW CREATE TABLE `$tableName`";
1204
+ }
1205
+
1206
+ public function show_create_view($viewName)
1207
+ {
1208
+ return "SHOW CREATE VIEW `$viewName`";
1209
+ }
1210
+
1211
+ public function show_create_trigger($triggerName)
1212
+ {
1213
+ return "SHOW CREATE TRIGGER `$triggerName`";
1214
+ }
1215
+
1216
+ public function create_table($row, $dumpSettings)
1217
+ {
1218
+ if (!isset($row['Create Table'])) {
1219
+ throw new Exception("Error getting table code, unknown output");
1220
+ }
1221
+
1222
+ $ret = "/*!40101 SET @saved_cs_client = @@character_set_client */;/*SGEnd*/" . PHP_EOL .
1223
+ "/*!40101 SET character_set_client = " . $dumpSettings['default-character-set'] . " */;/*SGEnd*/" . PHP_EOL .
1224
+ $row['Create Table'] . ";/*SGEnd*/" . PHP_EOL .
1225
+ "/*!40101 SET character_set_client = @saved_cs_client */;/*SGEnd*/" . PHP_EOL .
1226
+ PHP_EOL;
1227
+ return $ret;
1228
+ }
1229
+
1230
+ public function create_view($row)
1231
+ {
1232
+ $ret = "";
1233
+ if (!isset($row['Create View'])) {
1234
+ throw new Exception("Error getting view structure, unknown output");
1235
+ }
1236
+
1237
+ $triggerStmt = $row['Create View'];
1238
+ $triggerStmtReplaced1 = str_replace(
1239
+ "CREATE ALGORITHM",
1240
+ "/*!50001 CREATE ALGORITHM",
1241
+ $triggerStmt
1242
+ );
1243
+ $triggerStmtReplaced2 = str_replace(
1244
+ " DEFINER=",
1245
+ " */" . PHP_EOL . "/*!50013 DEFINER=",
1246
+ $triggerStmtReplaced1
1247
+ );
1248
+ $triggerStmtReplaced3 = str_replace(
1249
+ " VIEW ",
1250
+ " */" . PHP_EOL . "/*!50001 VIEW ",
1251
+ $triggerStmtReplaced2
1252
+ );
1253
+ if (false === $triggerStmtReplaced1 ||
1254
+ false === $triggerStmtReplaced2 ||
1255
+ false === $triggerStmtReplaced3) {
1256
+ $triggerStmtReplaced = $triggerStmt;
1257
+ } else {
1258
+ $triggerStmtReplaced = $triggerStmtReplaced3 . " */;/*SGEnd*/";
1259
+ }
1260
+
1261
+ $ret .= $triggerStmtReplaced . PHP_EOL . PHP_EOL;
1262
+ return $ret;
1263
+ }
1264
+
1265
+ public function create_trigger($row)
1266
+ {
1267
+ $ret = "";
1268
+ if (!isset($row['SQL Original Statement'])) {
1269
+ throw new Exception("Error getting trigger code, unknown output");
1270
+ }
1271
+
1272
+ $triggerStmt = $row['SQL Original Statement'];
1273
+ $triggerStmtReplaced = str_replace(
1274
+ "CREATE DEFINER",
1275
+ "/*!50003 CREATE*/ /*!50017 DEFINER",
1276
+ $triggerStmt
1277
+ );
1278
+ $triggerStmtReplaced = str_replace(
1279
+ " TRIGGER",
1280
+ "*/ /*!50003 TRIGGER",
1281
+ $triggerStmtReplaced
1282
+ );
1283
+ if ( false === $triggerStmtReplaced ) {
1284
+ $triggerStmtReplaced = $triggerStmt;
1285
+ }
1286
+
1287
+ $ret .= "DELIMITER ;;/*SGEnd*/" . PHP_EOL .
1288
+ $triggerStmtReplaced . "*/;;/*SGEnd*/" . PHP_EOL .
1289
+ "DELIMITER ;/*SGEnd*/" . PHP_EOL . PHP_EOL;
1290
+ return $ret;
1291
+ }
1292
+
1293
+ public function show_tables()
1294
+ {
1295
+ if (func_num_args() != 1) {
1296
+ return "";
1297
+ }
1298
+
1299
+ $args = func_get_args();
1300
+
1301
+ return "SELECT TABLE_NAME AS tbl_name " .
1302
+ "FROM INFORMATION_SCHEMA.TABLES " .
1303
+ "WHERE TABLE_TYPE='BASE TABLE' AND TABLE_SCHEMA='${args[0]}'";
1304
+ }
1305
+
1306
+ public function show_views()
1307
+ {
1308
+ if (func_num_args() != 1) {
1309
+ return "";
1310
+ }
1311
+
1312
+ $args = func_get_args();
1313
+
1314
+ return "SELECT TABLE_NAME AS tbl_name " .
1315
+ "FROM INFORMATION_SCHEMA.TABLES " .
1316
+ "WHERE TABLE_TYPE='VIEW' AND TABLE_SCHEMA='${args[0]}'";
1317
+ }
1318
+
1319
+ public function show_triggers()
1320
+ {
1321
+ if (func_num_args() != 1) {
1322
+ return "";
1323
+ }
1324
+
1325
+ $args = func_get_args();
1326
+
1327
+ return "SHOW TRIGGERS FROM `${args[0]}`;";
1328
+ }
1329
+
1330
+
1331
+ public function show_columns()
1332
+ {
1333
+ if (func_num_args() != 1) {
1334
+ return "";
1335
+ }
1336
+
1337
+ $args = func_get_args();
1338
+
1339
+ return "SHOW COLUMNS FROM `${args[0]}`;";
1340
+ }
1341
+
1342
+ public function setup_transaction()
1343
+ {
1344
+ return "SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ";
1345
+ }
1346
+
1347
+ public function start_transaction()
1348
+ {
1349
+ return "START TRANSACTION";
1350
+ }
1351
+
1352
+ public function commit_transaction()
1353
+ {
1354
+ return "COMMIT";
1355
+ }
1356
+
1357
+ public function lock_table()
1358
+ {
1359
+ if (func_num_args() != 1) {
1360
+ return "";
1361
+ }
1362
+
1363
+ $args = func_get_args();
1364
+ //$tableName = $args[0];
1365
+ //return "LOCK TABLES `$tableName` READ LOCAL";
1366
+ return $this->dbHandler->query("LOCK TABLES `${args[0]}` READ LOCAL");
1367
+
1368
+ }
1369
+
1370
+ public function unlock_table()
1371
+ {
1372
+ return $this->dbHandler->query("UNLOCK TABLES");
1373
+ }
1374
+
1375
+ public function start_add_lock_table()
1376
+ {
1377
+ if (func_num_args() != 1) {
1378
+ return "";
1379
+ }
1380
+
1381
+ $args = func_get_args();
1382
+
1383
+ return "LOCK TABLES `${args[0]}` WRITE;/*SGEnd*/" . PHP_EOL;
1384
+ }
1385
+
1386
+ public function end_add_lock_table()
1387
+ {
1388
+ return "UNLOCK TABLES;/*SGEnd*/" . PHP_EOL;
1389
+ }
1390
+
1391
+ public function start_add_disable_keys()
1392
+ {
1393
+ if (func_num_args() != 1) {
1394
+ return "";
1395
+ }
1396
+ $args = func_get_args();
1397
+ return "/*!40000 ALTER TABLE `${args[0]}` DISABLE KEYS */;/*SGEnd*/" .
1398
+ PHP_EOL;
1399
+ }
1400
+
1401
+ public function end_add_disable_keys()
1402
+ {
1403
+ if (func_num_args() != 1) {
1404
+ return "";
1405
+ }
1406
+ $args = func_get_args();
1407
+ return "/*!40000 ALTER TABLE `${args[0]}` ENABLE KEYS */;/*SGEnd*/" .
1408
+ PHP_EOL;
1409
+ }
1410
+
1411
+ public function start_disable_autocommit()
1412
+ {
1413
+ return "SET autocommit=0;/*SGEnd*/" . PHP_EOL;
1414
+ }
1415
+
1416
+ public function end_disable_autocommit()
1417
+ {
1418
+ return "COMMIT;/*SGEnd*/" . PHP_EOL;
1419
+ }
1420
+
1421
+ public function add_drop_database()
1422
+ {
1423
+ if (func_num_args() != 1) {
1424
+ return "";
1425
+ }
1426
+
1427
+ $args = func_get_args();
1428
+
1429
+ return "/*!40000 DROP DATABASE IF EXISTS `${args[0]}`*/;/*SGEnd*/" .
1430
+ PHP_EOL . PHP_EOL;
1431
+ }
1432
+
1433
+ public function add_drop_trigger()
1434
+ {
1435
+ if (func_num_args() != 1) {
1436
+ return "";
1437
+ }
1438
+
1439
+ $args = func_get_args();
1440
+
1441
+ return "DROP TRIGGER IF EXISTS `${args[0]}`;/*SGEnd*/" . PHP_EOL;
1442
+ }
1443
+
1444
+ public function drop_table()
1445
+ {
1446
+ if (func_num_args() != 1) {
1447
+ return "";
1448
+ }
1449
+
1450
+ $args = func_get_args();
1451
+
1452
+ return "DROP TABLE IF EXISTS `${args[0]}`;/*SGEnd*/" . PHP_EOL;
1453
+ }
1454
+
1455
+ public function drop_view()
1456
+ {
1457
+ if (func_num_args() != 1) {
1458
+ return "";
1459
+ }
1460
+
1461
+ $args = func_get_args();
1462
+
1463
+ return "DROP TABLE IF EXISTS `${args[0]}`;/*SGEnd*/" . PHP_EOL .
1464
+ "/*!50001 DROP VIEW IF EXISTS `${args[0]}`*/;/*SGEnd*/" . PHP_EOL;
1465
+ }
1466
+
1467
+ public function getDatabaseHeader()
1468
+ {
1469
+ if (func_num_args() != 1) {
1470
+ return "";
1471
+ }
1472
+
1473
+ $args = func_get_args();
1474
+
1475
+ return "--" . PHP_EOL .
1476
+ "-- Current Database: `${args[0]}`" . PHP_EOL .
1477
+ "--" . PHP_EOL . PHP_EOL;
1478
+ }
1479
+
1480
+ /**
1481
+ * Decode column metadata and fill info structure.
1482
+ * type, is_numeric and is_blob will always be available.
1483
+ *
1484
+ * @param array $colType Array returned from "SHOW COLUMNS FROM tableName"
1485
+ * @return array
1486
+ */
1487
+ public function parseColumnType($colType)
1488
+ {
1489
+ $colInfo = array();
1490
+ $colParts = explode(" ", $colType['Type']);
1491
+
1492
+ if($fparen = strpos($colParts[0], "("))
1493
+ {
1494
+ $colInfo['type'] = substr($colParts[0], 0, $fparen);
1495
+ $colInfo['length'] = str_replace(")", "", substr($colParts[0], $fparen+1));
1496
+ $colInfo['attributes'] = isset($colParts[1]) ? $colParts[1] : NULL;
1497
+ }
1498
+ else
1499
+ {
1500
+ $colInfo['type'] = $colParts[0];
1501
+ }
1502
+ $colInfo['is_numeric'] = in_array($colInfo['type'], $this->mysqlTypes['numerical']);
1503
+ $colInfo['is_blob'] = in_array($colInfo['type'], $this->mysqlTypes['blob']);
1504
+
1505
+ return $colInfo;
1506
+ }
1507
+
1508
+ public function backup_parameters()
1509
+ {
1510
+ if (func_num_args() != 1) {
1511
+ throw new Exception("Unexpected parameter passed to " . __METHOD__);
1512
+ }
1513
+
1514
+ $args = func_get_args();
1515
+ $dumpSettings = $args[0];
1516
+ $ret = "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;/*SGEnd*/" . PHP_EOL .
1517
+ "/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;/*SGEnd*/" . PHP_EOL .
1518
+ "/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;/*SGEnd*/" . PHP_EOL .
1519
+ "/*!40101 SET NAMES " . $dumpSettings['default-character-set'] . " */;/*SGEnd*/" . PHP_EOL;
1520
+
1521
+ if (false === $dumpSettings['skip-tz-utz']) {
1522
+ $ret .= "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;/*SGEnd*/" . PHP_EOL .
1523
+ "/*!40103 SET TIME_ZONE='+00:00' */;/*SGEnd*/" . PHP_EOL;
1524
+ }
1525
+
1526
+ $ret .= "/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;/*SGEnd*/" . PHP_EOL .
1527
+ "/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;/*SGEnd*/" . PHP_EOL .
1528
+ "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;/*SGEnd*/" . PHP_EOL .
1529
+ "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;/*SGEnd*/" . PHP_EOL .PHP_EOL;
1530
+
1531
+ return $ret;
1532
+ }
1533
+
1534
+ public function restore_parameters()
1535
+ {
1536
+ if (func_num_args() != 1) {
1537
+ throw new Exception("Unexpected parameter passed to " . __METHOD__);
1538
+ }
1539
+
1540
+ $args = func_get_args();
1541
+ $dumpSettings = $args[0];
1542
+ $ret = "";
1543
+
1544
+ if (false === $dumpSettings['skip-tz-utz']) {
1545
+ $ret .= "/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;/*SGEnd*/" . PHP_EOL;
1546
+ }
1547
+
1548
+ $ret .= "/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;/*SGEnd*/" . PHP_EOL .
1549
+ "/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;/*SGEnd*/" . PHP_EOL .
1550
+ "/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;/*SGEnd*/" . PHP_EOL .
1551
+ "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;/*SGEnd*/" . PHP_EOL .
1552
+ "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;/*SGEnd*/" . PHP_EOL .
1553
+ "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;/*SGEnd*/" . PHP_EOL .
1554
+ "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;/*SGEnd*/" . PHP_EOL . PHP_EOL;
1555
+
1556
+ return $ret;
1557
+ }
1558
+ }
com/lib/SGReloadHandler.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(SG_REQUEST_PATH.'SGRequest.php');
4
+
5
+ class SGReloadHandler
6
+ {
7
+ private $host;
8
+ private $uri;
9
+ private $scheme;
10
+ private $port;
11
+
12
+ public function __construct($url)
13
+ {
14
+ $this->host = @$_SERVER['HTTP_HOST'];
15
+ $this->url = $url;
16
+ $this->port = @$_SERVER['SERVER_PORT'];
17
+ $this->scheme = backupGuardGetCurrentUrlScheme();
18
+
19
+ if (!$this->port) {
20
+ $this->port = 80;
21
+ }
22
+ }
23
+
24
+ public function reload()
25
+ {
26
+ $selectedReloadMethod = SGConfig::get('SG_BACKGROUND_RELOAD_METHOD');
27
+ $url = $this->scheme.'://'.$this->host.$this->url."&method=".$selectedReloadMethod;
28
+
29
+ $request = SGRequest::getInstance();
30
+ $request->setUrl($url);
31
+ $request->setParams(array());
32
+ $request->setHeaders(array());
33
+ $request->sendGetRequest();
34
+ }
35
+ }
com/lib/SGReloader.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+ require_once(SG_LIB_PATH.'SGReloaderState.php');
5
+ require_once(SG_LIB_PATH.'SGReloadHandler.php');
6
+ require_once(SG_LIB_PATH.'SGCallback.php');
7
+
8
+ class SGReloader
9
+ {
10
+ public static function awake($method = null)
11
+ {
12
+ $reloaderState = SGReloaderState::loadState();
13
+ if ($reloaderState['callback'] != "" && $reloaderState['state'] == SG_RELOADER_STATUS_IDLE) {
14
+
15
+ $callbackJson = json_decode($reloaderState['callback']);
16
+ $callbackJson->params['method'] = $method;
17
+ $callback = new SGCallback($callbackJson->class, $callbackJson->method, $callbackJson->params);
18
+
19
+ if ($callback->canPerform()) {
20
+ self::saveState('', SG_RELOADER_STATUS_RUNNING);
21
+ $callback->perform();
22
+ }
23
+ }
24
+
25
+ return;
26
+ }
27
+
28
+ private static function saveState($callback, $state = SG_RELOADER_STATUS_IDLE)
29
+ {
30
+ $sgReloaderState = new SGReloaderState();
31
+ $sgReloaderState->setCallback($callback);
32
+ $sgReloaderState->setState($state);
33
+ $sgReloaderState->update();
34
+ }
35
+
36
+ public static function didCompleteCallback()
37
+ {
38
+ self::saveState('', SG_RELOADER_STATUS_IDLE);
39
+ }
40
+
41
+ public static function registerCallback(SGCallback $callback)
42
+ {
43
+ self::saveState($callback->toString());
44
+ }
45
+
46
+ public static function reset()
47
+ {
48
+ SGReloaderState::reset();
49
+ }
50
+
51
+ public static function reloadWithAjaxUrl($awakeURL)
52
+ {
53
+ //external restore works only with ajax requests
54
+ if (defined('BG_EXTERNAL_RESTORE_RUNNING') && BG_EXTERNAL_RESTORE_RUNNING) {
55
+ return;
56
+ }
57
+
58
+ // awake frequency in miliseconds
59
+ $sgAwakeFrequency = SGConfig::get('SG_AJAX_REQUEST_FREQUENCY')?SGConfig::get('SG_AJAX_REQUEST_FREQUENCY'):SG_AJAX_DEFAULT_REQUEST_FREQUENCY;
60
+ $sgAwakeFrequency = $sgAwakeFrequency/1000; // awake frequency in seconds
61
+
62
+ // add 3 seconds to awake frequency
63
+ $timeout = $sgAwakeFrequency + 3;
64
+ while ($timeout) {
65
+
66
+ $reloaderState = SGReloaderState::loadState();
67
+ $state = $reloaderState['state'];
68
+
69
+ if ($state == SG_RELOADER_STATUS_RUNNING) {
70
+ return;
71
+ }
72
+
73
+ sleep(1);
74
+ $timeout--;
75
+ }
76
+
77
+ self::reload($awakeURL);
78
+ }
79
+
80
+ private static function reload($awakeURL)
81
+ {
82
+ $sgReloadHandler = new SGReloadHandler($awakeURL);
83
+ $sgReloadHandler->reload();
84
+ return;
85
+ }
86
+ }
com/lib/SGReloaderState.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SGReloaderState
4
+ {
5
+ private $state;
6
+ private $callback;
7
+
8
+ public function __construct($callback = '', $state = SG_RELOADER_STATUS_IDLE)
9
+ {
10
+ $this->state = $state;
11
+ $this->callback = $callback;
12
+ }
13
+
14
+ public function setCallback($callback)
15
+ {
16
+ $this->callback = $callback;
17
+ }
18
+
19
+ public function setState($state)
20
+ {
21
+ $this->state = $state;
22
+ }
23
+
24
+ public function update()
25
+ {
26
+ //save state file
27
+ $sgReloaderState = array(
28
+ 'state' => $this->state,
29
+ 'callback' => $this->callback
30
+ );
31
+
32
+ file_put_contents(SG_BACKUP_DIRECTORY.SG_RELOADER_STATE_FILE_NAME, json_encode($sgReloaderState));
33
+ }
34
+
35
+ public static function reset()
36
+ {
37
+ $sgReloaderState = array(
38
+ 'state' => SG_RELOADER_STATUS_IDLE,
39
+ 'callback' => ''
40
+ );
41
+
42
+ file_put_contents(SG_BACKUP_DIRECTORY.SG_RELOADER_STATE_FILE_NAME, json_encode($sgReloaderState));
43
+ }
44
+
45
+ public static function loadState()
46
+ {
47
+ $sgReloaderState = array(
48
+ 'state' => SG_RELOADER_STATUS_IDLE,
49
+ 'callback' => ''
50
+ );
51
+
52
+ if (file_exists(SG_BACKUP_DIRECTORY.SG_RELOADER_STATE_FILE_NAME)) {
53
+ $sgReloaderState = file_get_contents(SG_BACKUP_DIRECTORY.SG_RELOADER_STATE_FILE_NAME);
54
+ $sgReloaderState = json_decode($sgReloaderState, true);
55
+ }
56
+
57
+ return $sgReloaderState;
58
+ }
59
+ }
com/lib/SGState.php ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(SG_LIB_PATH.'SGFileState.php');
4
+ require_once(SG_LIB_PATH.'SGDBState.php');
5
+ require_once(SG_LIB_PATH.'SGUploadState.php');
6
+ require_once(SG_LIB_PATH.'SGMigrateState.php');
7
+
8
+ class SGState
9
+ {
10
+ public $inprogress = false;
11
+ public $type = '';
12
+ public $token = '';
13
+ public $action = '';
14
+ public $actionId = null;
15
+ public $actionStartTs = 0;
16
+ public $backupFileName = '';
17
+ public $backupFilePath = '';
18
+ public $progress = 0;
19
+ public $warningsFound = false;
20
+ public $pendingStorageUploads = array();
21
+ public $restoreMode = '';
22
+ public $restoreFiles = array();
23
+ public $offset = 0;
24
+
25
+ function __construct()
26
+ {
27
+ }
28
+
29
+ public function setInprogress($inprogress)
30
+ {
31
+ $this->inprogress = $inprogress;
32
+ }
33
+
34
+ public function setToken($token)
35
+ {
36
+ $this->token = $token;
37
+ }
38
+
39
+ public function setAction($action)
40
+ {
41
+ $this->action = $action;
42
+ }
43
+
44
+ public function setType($type)
45
+ {
46
+ $this->type = $type;
47
+ }
48
+
49
+ public function setActionId($actionId)
50
+ {
51
+ $this->actionId = $actionId;
52
+ }
53
+
54
+ public function setActionStartTs($actionStartTs)
55
+ {
56
+ $this->actionStartTs = $actionStartTs;
57
+ }
58
+
59
+ public function setBackupFileName($name)
60
+ {
61
+ $this->backupFileName = $name;
62
+ }
63
+
64
+ public function setBackupFilePath($backupFilePath)
65
+ {
66
+ $this->backupFilePath = $backupFilePath;
67
+ }
68
+
69
+ public function setProgress($progress)
70
+ {
71
+ $this->progress = $progress;
72
+ }
73
+
74
+ public function setWarningsFound($warningsFound)
75
+ {
76
+ $this->warningsFound = $warningsFound;
77
+ }
78
+
79
+ public function setRestoreFiles($restoreFiles)
80
+ {
81
+ $this->restoreFiles = $restoreFiles;
82
+ }
83
+
84
+ public function setPendingStorageUploads($pendingStorageUploads)
85
+ {
86
+ $this->pendingStorageUploads = $pendingStorageUploads;
87
+ }
88
+
89
+ public function setRestoreMode($mode){
90
+ $this->restoreMode = $mode;
91
+ }
92
+
93
+ public function getRestoreMode(){
94
+ return $this->restoreMode;
95
+ }
96
+
97
+ public function getInprogress()
98
+ {
99
+ return $this->inprogress;
100
+ }
101
+
102
+ public function getToken()
103
+ {
104
+ return $this->token;
105
+ }
106
+
107
+ public function getAction()
108
+ {
109
+ return $this->action;
110
+ }
111
+
112
+ public function getType()
113
+ {
114
+ return $this->type;
115
+ }
116
+
117
+ public function getActionId()
118
+ {
119
+ return $this->actionId;
120
+ }
121
+
122
+ public function getActionStartTs()
123
+ {
124
+ return $this->actionStartTs;
125
+ }
126
+
127
+ public function getBackupFileName()
128
+ {
129
+ return $this->backupFileName;
130
+ }
131
+
132
+ public function getBackupFilePath()
133
+ {
134
+ return $this->backupFilePath;
135
+ }
136
+
137
+ public function getProgress()
138
+ {
139
+ return $this->progress;
140
+ }
141
+
142
+ public function getWarningsFound()
143
+ {
144
+ return $this->warningsFound;
145
+ }
146
+
147
+ public function getRestoreFiles()
148
+ {
149
+ return $this->restoreFiles;
150
+ }
151
+
152
+ public function getPendingStorageUploads()
153
+ {
154
+ return $this->pendingStorageUploads;
155
+ }
156
+
157
+ public function setOffset($offset)
158
+ {
159
+ $this->offset = $offset;
160
+ }
161
+
162
+ public function getOffset()
163
+ {
164
+ return $this->offset;
165
+ }
166
+
167
+ public function factory($stateJson)
168
+ {
169
+ $stateJson = json_decode($stateJson, true);
170
+
171
+ $type = $stateJson['type'];
172
+
173
+ if ($type == SG_STATE_TYPE_FILE) {
174
+ $sgState = new SGFileState();
175
+ }
176
+ else if ($type == SG_STATE_TYPE_UPLOAD) {
177
+ $sgState = new SGUploadState();
178
+ }
179
+ else if ($type == SG_STATE_TYPE_MIGRATE) {
180
+ $sgState = new SGMigrateState();
181
+ }
182
+ else {
183
+ $sgState = new SGDBState();
184
+ }
185
+
186
+ $sgState = $sgState->init($stateJson);
187
+ return $sgState;
188
+ }
189
+ }
com/lib/SGUploadHandler.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackupGuard\Upload;
4
+
5
+ class Handler
6
+ {
7
+ private $data = null;
8
+ private $fileName = "";
9
+ private $tmpFileName = "";
10
+
11
+ public function __construct($data)
12
+ {
13
+ $this->data = $data;
14
+ $this->import();
15
+ }
16
+
17
+ private function import()
18
+ {
19
+ $this->fileName = $this->data['files']['name'][0];
20
+ $this->tmpFileName = $this->data['files']['tmp_name'][0];
21
+
22
+ $dirPath = $this->getDestinationDirPath();
23
+ $file = $dirPath.$this->fileName;
24
+
25
+ $data = file_get_contents($this->tmpFileName);
26
+ file_put_contents($file, $data, FILE_APPEND);
27
+ }
28
+
29
+ private function getDestinationDirPath()
30
+ {
31
+ return SG_BACKUP_DIRECTORY;
32
+ }
33
+
34
+ private function getDestinationDirUrl()
35
+ {
36
+ return SG_BACKUP_DIRECTORY_URL;
37
+ }
38
+ }
com/lib/SGUploadState.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/SGState.php');
4
+
5
+ class SGUploadState extends SGState
6
+ {
7
+ private $activeDirectory = '';
8
+ private $currentUploadChunksCount = 0;
9
+ private $totalUploadChunksCount = 0;
10
+ private $uploadId = 0;
11
+ private $parts = array();
12
+ private $storageType = null;
13
+
14
+ function __construct()
15
+ {
16
+ $this->type = SG_STATE_TYPE_UPLOAD;
17
+ }
18
+
19
+ public function setActiveDirectory($activeDirectory)
20
+ {
21
+ $this->activeDirectory = $activeDirectory;
22
+ }
23
+
24
+ public function setCurrentUploadChunksCount($currentUploadChunksCount)
25
+ {
26
+ $this->currentUploadChunksCount = $currentUploadChunksCount;
27
+ }
28
+
29
+ public function setTotalUploadChunksCount($totalUploadChunksCount)
30
+ {
31
+ $this->totalUploadChunksCount = $totalUploadChunksCount;
32
+ }
33
+
34
+ public function setUploadId($uploadId)
35
+ {
36
+ $this->uploadId = $uploadId;
37
+ }
38
+
39
+ public function setParts($parts)
40
+ {
41
+ $this->parts = $parts;
42
+ }
43
+
44
+ public function setStorageType($storageType)
45
+ {
46
+ $this->storageType = $storageType;
47
+ }
48
+
49
+ public function getStorageType()
50
+ {
51
+ return $this->storageType;
52
+ }
53
+
54
+ public function getCurrentUploadChunksCount()
55
+ {
56
+ return $this->currentUploadChunksCount;
57
+ }
58
+
59
+ public function getTotalUploadChunksCount()
60
+ {
61
+ return $this->totalUploadChunksCount;
62
+ }
63
+
64
+ public function getUploadId()
65
+ {
66
+ return $this->uploadId;
67
+ }
68
+
69
+ public function getParts()
70
+ {
71
+ return $this->parts;
72
+ }
73
+
74
+ public function getActiveDirectory()
75
+ {
76
+ return $this->activeDirectory;
77
+ }
78
+
79
+ public function init($stateJson)
80
+ {
81
+ $this->type = $stateJson['type'];
82
+ $this->parts = $stateJson['parts'];
83
+ $this->offset = $stateJson['offset'];
84
+ $this->action = $stateJson['action'];
85
+ $this->uploadId = $stateJson['uploadId'];
86
+ $this->actionId = $stateJson['actionId'];
87
+ $this->progress = $stateJson['progress'];
88
+ $this->storageType = $stateJson['storageType'];
89
+ $this->actionStartTs = $stateJson['actionStartTs'];
90
+ $this->warningsFound = $stateJson['warningsFound'];
91
+ $this->backupFileName = $stateJson['backupFileName'];
92
+ $this->backupFilePath = $stateJson['backupFilePath'];
93
+ $this->activeDirectory = $stateJson['activeDirectory'];
94
+ $this->pendingStorageUploads = $stateJson['pendingStorageUploads'];
95
+ $this->totalUploadChunksCount = $stateJson['totalUploadChunksCount'];
96
+ $this->currentUploadChunksCount = $stateJson['currentUploadChunksCount'];
97
+
98
+ return $this;
99
+ }
100
+
101
+ public function save()
102
+ {
103
+ file_put_contents(SG_BACKUP_DIRECTORY.SG_STATE_FILE_NAME, json_encode(array(
104
+ 'type' => $this->type,
105
+ 'parts' => $this->parts,
106
+ 'token' => $this->token,
107
+ 'offset' => $this->offset,
108
+ 'action' => $this->action,
109
+ 'uploadId' => $this->uploadId,
110
+ 'actionId' => $this->actionId,
111
+ 'progress' => $this->progress,
112
+ 'inprogress' => $this->inprogress,
113
+ 'storageType' => $this->storageType,
114
+ 'actionStartTs' => $this->actionStartTs,
115
+ 'warningsFound' => $this->warningsFound,
116
+ 'backupFileName' => $this->backupFileName,
117
+ 'backupFilePath' => $this->backupFilePath,
118
+ 'activeDirectory' => $this->activeDirectory,
119
+ 'pendingStorageUploads' => $this->pendingStorageUploads,
120
+ 'totalUploadChunksCount' => $this->totalUploadChunksCount,
121
+ 'currentUploadChunksCount' => $this->currentUploadChunksCount
122
+ )));
123
+ }
124
+ }
index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
languages/backup-guard-pro-es_ES.mo ADDED
Binary file
languages/backup-guard-pro-es_ES.po ADDED
@@ -0,0 +1,1154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "POT-Creation-Date: 2019-02-14 19:02+0400\n"
5
+ "PO-Revision-Date: 2019-02-14 19:37+0400\n"
6
+ "Last-Translator: \n"
7
+ "Language-Team: \n"
8
+ "Language: es\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 1.8.11\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
15
+ "X-Poedit-KeywordsList: _backupGuardT\n"
16
+ "X-Poedit-SearchPath-0: backup-guard-pro.php\n"
17
+ "X-Poedit-SearchPath-1: BackupGuard.php\n"
18
+ "X-Poedit-SearchPath-2: index.php\n"
19
+ "X-Poedit-SearchPath-3: com\n"
20
+ "X-Poedit-SearchPath-4: public/ajax\n"
21
+ "X-Poedit-SearchPath-5: public/backups.php\n"
22
+ "X-Poedit-SearchPath-6: public/boot.php\n"
23
+ "X-Poedit-SearchPath-7: public/cloud.php\n"
24
+ "X-Poedit-SearchPath-8: public/config\n"
25
+ "X-Poedit-SearchPath-9: public/cron\n"
26
+ "X-Poedit-SearchPath-10: public/dashboardWidget.php\n"
27
+ "X-Poedit-SearchPath-11: public/include\n"
28
+ "X-Poedit-SearchPath-12: public/link_license.php\n"
29
+ "X-Poedit-SearchPath-13: public/login.php\n"
30
+ "X-Poedit-SearchPath-14: public/proFeatures.php\n"
31
+ "X-Poedit-SearchPath-15: public/restore_wordpress.php\n"
32
+ "X-Poedit-SearchPath-16: public/schedule-free.php\n"
33
+ "X-Poedit-SearchPath-17: public/schedule-single.php\n"
34
+ "X-Poedit-SearchPath-18: public/schedule.php\n"
35
+ "X-Poedit-SearchPath-19: public/security.php\n"
36
+ "X-Poedit-SearchPath-20: public/services.php\n"
37
+ "X-Poedit-SearchPath-21: public/settings.php\n"
38
+ "X-Poedit-SearchPath-22: public/support.php\n"
39
+ "X-Poedit-SearchPath-23: public/templates\n"
40
+
41
+ #: BackupGuard.php:96 public/backups.php:81 public/include/sidebar.php:36
42
+ msgid "Backups"
43
+ msgstr "Respaldos"
44
+
45
+ #: BackupGuard.php:97 public/include/sidebar.php:41
46
+ msgid "Cloud"
47
+ msgstr "Nube"
48
+
49
+ #: BackupGuard.php:98 public/include/sidebar.php:47
50
+ msgid "Schedule"
51
+ msgstr "Programar"
52
+
53
+ #: BackupGuard.php:100 public/cloud.php:85 public/cloud.php:103
54
+ #: public/include/sidebar.php:53
55
+ msgid "Settings"
56
+ msgstr "Ajustes"
57
+
58
+ #: BackupGuard.php:101 public/include/sidebar.php:58
59
+ msgid "Services"
60
+ msgstr "Servicios"
61
+
62
+ #: BackupGuard.php:102 public/include/sidebar.php:63
63
+ msgid "Support"
64
+ msgstr "Soporte"
65
+
66
+ #: BackupGuard.php:106 public/include/sidebar.php:69
67
+ msgid "Why upgrade?"
68
+ msgstr "¿Por qué actualizar?"
69
+
70
+ #: BackupGuard.php:163
71
+ msgid "Are you sure you want to cancel import?"
72
+ msgstr "¿Está seguro de que quiere cancelar la importación?"
73
+
74
+ #: BackupGuard.php:164 BackupGuard.php:214
75
+ msgid "Please choose at least one option."
76
+ msgstr "Por favor, elija al menos una opción."
77
+
78
+ #: BackupGuard.php:165 BackupGuard.php:215
79
+ msgid "Please choose at least one directory."
80
+ msgstr "Por favor, elija al menos un directorio."
81
+
82
+ #: BackupGuard.php:166 BackupGuard.php:216
83
+ msgid "Please choose at least one cloud."
84
+ msgstr "Por favor, elija al menos una nube."
85
+
86
+ #: BackupGuard.php:167
87
+ msgid "Backing Up..."
88
+ msgstr "Respaldando..."
89
+
90
+ #: BackupGuard.php:168
91
+ msgid "Something went wrong. Please try again."
92
+ msgstr "Algo ha ido mal. Favor de intentar de nuevo."
93
+
94
+ #: BackupGuard.php:169 public/backups.php:107
95
+ msgid "No backups found."
96
+ msgstr "No se encontraron respaldos."
97
+
98
+ #: BackupGuard.php:170
99
+ msgid "Please select one off the options."
100
+ msgstr "Por favor seleccione una de las opciones."
101
+
102
+ #: BackupGuard.php:171
103
+ msgid "Please choose one of the files."
104
+ msgstr "Por favor, elija uno de los archivos."
105
+
106
+ #: BackupGuard.php:172 public/ajax/modalImport.php:97 public/backups.php:90
107
+ msgid "Import"
108
+ msgstr "Importar"
109
+
110
+ #: BackupGuard.php:173
111
+ msgid "Importing please wait..."
112
+ msgstr "Importando, por favor espere ..."
113
+
114
+ #: BackupGuard.php:174
115
+ msgid "File upload failed."
116
+ msgstr "La subida del archivo falló."
117
+
118
+ #: BackupGuard.php:191
119
+ msgid "Please select a file."
120
+ msgstr "Por favor seleccione un archivo."
121
+
122
+ #: BackupGuard.php:192
123
+ msgid "File is too large."
124
+ msgstr "El archivo es demasiado grande."
125
+
126
+ #: BackupGuard.php:193
127
+ msgid "Connecting..."
128
+ msgstr "Conectando…"
129
+
130
+ #: BackupGuard.php:194 public/ajax/saveCloudFolder.php:15
131
+ msgid "Destination folder is required."
132
+ msgstr "La carpeta de destino es obligatoria."
133
+
134
+ #: BackupGuard.php:195 BackupGuard.php:239
135
+ msgid "Successfully saved."
136
+ msgstr "Guardado con éxito."
137
+
138
+ #: BackupGuard.php:212
139
+ msgid "Unable to delete schedule"
140
+ msgstr "No se puede eliminar la tarea programada"
141
+
142
+ #: BackupGuard.php:213 public/ajax/modalManualRestore.php:61
143
+ msgid "Are you sure?"
144
+ msgstr "¿Está seguro?"
145
+
146
+ #: BackupGuard.php:217 BackupGuard.php:240
147
+ msgid "Saving..."
148
+ msgstr "Guardando..."
149
+
150
+ #: BackupGuard.php:218
151
+ msgid "You have successfully activated schedule."
152
+ msgstr "Tarea programada con éxito."
153
+
154
+ #: BackupGuard.php:219 BackupGuard.php:243
155
+ #: public/ajax/modalAmazonSettings.php:49
156
+ #: public/ajax/modalCreateSchedule.php:224 public/ajax/modalFtpSettings.php:90
157
+ #: public/cloud.php:33 public/schedule-free.php:171
158
+ #: public/schedule-single.php:236 public/settings.php:205
159
+ msgid "Save"
160
+ msgstr "Guardar"
161
+
162
+ #: BackupGuard.php:236
163
+ msgid "Please enter valid email."
164
+ msgstr "Por favor introduzca un correo electrónico válido."
165
+
166
+ #: BackupGuard.php:237
167
+ msgid "Please enter valid file name."
168
+ msgstr "Por favor, introduzca un nombre de archivo válido."
169
+
170
+ #: BackupGuard.php:238
171
+ msgid "Please enter a valid retention number."
172
+ msgstr "Por favor, introduzca un número de retención válido."
173
+
174
+ #: BackupGuard.php:241
175
+ msgid "Are you sure you want to keep the latest"
176
+ msgstr "¿Estás seguro de que quieres mantener los últimos"
177
+
178
+ #: BackupGuard.php:242
179
+ msgid "backups? All older backups will be deleted."
180
+ msgstr "respaldos? Todas los respaldos antiguos serán eliminados."
181
+
182
+ #: BackupGuard.php:262
183
+ msgid "Please choose a license first"
184
+ msgstr "Por favor, elija una licencia primero"
185
+
186
+ #: BackupGuard.php:263
187
+ msgid "There are no available licenses for using the selected product"
188
+ msgstr "No hay licencias disponibles para usar el producto seleccionado."
189
+
190
+ #: BackupGuard.php:309
191
+ msgid "Are you sure you want to cancel?"
192
+ msgstr "¿Estas seguro que quieres cancelar?"
193
+
194
+ #: com/core/database/SGDB.php:725 com/core/database/SGDB.php:731
195
+ msgid "Unable to retrieve the error message from MySQL"
196
+ msgstr "No se puede recuperar el mensaje de error de MySQL"
197
+
198
+ #: com/core/functions.gold.php:28 com/core/functions.platinum.php:18
199
+ #: com/core/functions.platinum.php:33
200
+ msgid "Region *"
201
+ msgstr "Región *"
202
+
203
+ #: com/core/functions.php:483
204
+ msgid ""
205
+ "Symlink / shortcut creation failed! Seems your server configurations don't "
206
+ "allow symlink creation, so we're unable to provide you the direct download "
207
+ "url. You can download your backup using any FTP client. All backups and "
208
+ "related stuff we locate '/wp-content/uploads/backup-guard' directory. If you "
209
+ "need this functionality, you should check out your server configurations and "
210
+ "make sure you don't have any limitation related to symlink creation."
211
+ msgstr ""
212
+
213
+ #: com/core/functions.php:579 public/schedule-free.php:81
214
+ #: public/schedule-single.php:146
215
+ msgid "Backup database"
216
+ msgstr ""
217
+
218
+ #: com/core/functions.php:583
219
+ msgid "Backup all tables found in the database"
220
+ msgstr ""
221
+
222
+ #: com/core/functions.php:585 com/core/functions.php:658
223
+ msgid "Full"
224
+ msgstr ""
225
+
226
+ #: com/core/functions.php:587
227
+ msgid ""
228
+ "Backup tables related to the current WordPress installation. Only tables with"
229
+ msgstr ""
230
+
231
+ #: com/core/functions.php:587
232
+ msgid "will be backed up"
233
+ msgstr ""
234
+
235
+ #: com/core/functions.php:589
236
+ msgid "Only WordPress"
237
+ msgstr ""
238
+
239
+ #: com/core/functions.php:591
240
+ msgid "Select tables you want to include in your backup"
241
+ msgstr ""
242
+
243
+ #: com/core/functions.php:593 com/core/functions.php:663
244
+ #: com/core/functions.platinum.php:11
245
+ msgid "Custom"
246
+ msgstr "Personalizado"
247
+
248
+ #: com/core/functions.php:603
249
+ msgid "(excluded from settings)"
250
+ msgstr ""
251
+
252
+ #: com/core/functions.platinum.php:6
253
+ msgid "Server *"
254
+ msgstr "Servidor *"
255
+
256
+ #: com/core/functions.platinum.php:48
257
+ msgid "URL *"
258
+ msgstr "URL *"
259
+
260
+ #: com/core/functions.silver.php:107
261
+ msgid "Wait... Don't forget to create a backup before updating!"
262
+ msgstr ""
263
+
264
+ #: com/core/functions.silver.php:108
265
+ msgid "You have pending updates which should be installed on your WordPress."
266
+ msgstr ""
267
+
268
+ #: com/core/functions.silver.php:108
269
+ msgid ""
270
+ "strongly recommends to create a backup before installing any update package. "
271
+ "So, you'll be safe in case something goes wrong!"
272
+ msgstr ""
273
+
274
+ #: com/core/functions.silver.php:115
275
+ msgid ""
276
+ "If you close this notification you won't receive any alerts from BackupGuard "
277
+ "before installing updates."
278
+ msgstr ""
279
+
280
+ #: com/core/functions.silver.php:115
281
+ msgid "Are you sure you want to disable such notifications?"
282
+ msgstr ""
283
+
284
+ #: com/core/functions.silver.php:130 com/core/functions.silver.php:163
285
+ msgid ""
286
+ "Wait... You see this alert because you've enabled 'alert to create a backup "
287
+ "before updates' option in BackupGuard settings."
288
+ msgstr ""
289
+
290
+ #: com/core/functions.silver.php:130 com/core/functions.silver.php:163
291
+ msgid "Are you sure you want to continue updating?"
292
+ msgstr ""
293
+
294
+ #: public/ajax/cloudAmazon.php:23
295
+ msgid "Bucket field is required."
296
+ msgstr "Bucket field is required."
297
+
298
+ #: public/ajax/cloudAmazon.php:26
299
+ msgid "Access key field is required."
300
+ msgstr "El campo de Clave de acceso es obligatorio."
301
+
302
+ #: public/ajax/cloudAmazon.php:29
303
+ msgid "Secret access key field is required."
304
+ msgstr "El campo de Clave de acceso secreto es obligatorio."
305
+
306
+ #: public/ajax/cloudAmazon.php:39
307
+ msgid "Bucket region field is required."
308
+ msgstr "El campo de Región de bucket es obligatorio."
309
+
310
+ #: public/ajax/cloudAmazon.php:60
311
+ msgid "Could not connect to server. Please check given ditails"
312
+ msgstr "No se pudo conectar al servidor. Favor de checar los datos."
313
+
314
+ #: public/ajax/cloudFtp.php:28
315
+ msgid "Connection method field is required."
316
+ msgstr "El campo de Método de conexión es obligatorio."
317
+
318
+ #: public/ajax/cloudFtp.php:31
319
+ msgid "Host field is required."
320
+ msgstr "El campo de Host es obligatorio."
321
+
322
+ #: public/ajax/cloudFtp.php:34
323
+ msgid "Port field is required."
324
+ msgstr "El campo de Puerto es obligatorio."
325
+
326
+ #: public/ajax/cloudFtp.php:37
327
+ msgid "User field is required."
328
+ msgstr "El campo de Usuario es obligatorio."
329
+
330
+ #: public/ajax/cloudFtp.php:40
331
+ msgid "Root directory field is required."
332
+ msgstr "El campo de Directorio raíz es obligatorio."
333
+
334
+ #: public/ajax/cloudFtp.php:43
335
+ msgid "Private key field is required."
336
+ msgstr "El campo de Llave privada es obligatoria."
337
+
338
+ #: public/ajax/cloudFtp.php:46
339
+ msgid "Password field is required."
340
+ msgstr "El campo de Contraseña es obligatoria."
341
+
342
+ #: public/ajax/downloadFromCloud.php:7
343
+ msgid "Something went wrong. Please try again later."
344
+ msgstr "Algo ha ido mal. Favor de intentar de nuevo."
345
+
346
+ #: public/ajax/isFeatureAvailable.php:6
347
+ msgid "This feature is not available in your package."
348
+ msgstr "Esta característica no esta disponible en su paquete."
349
+
350
+ #: public/ajax/manualBackup.php:15
351
+ msgid "There is an active backup running. Please try later"
352
+ msgstr "Hay un respaldo en ejecución. Por favor intente mas tarde."
353
+
354
+ #: public/ajax/modalAmazonSettings.php:25
355
+ msgid "Bucket *"
356
+ msgstr "Bucket *"
357
+
358
+ #: public/ajax/modalAmazonSettings.php:32
359
+ msgid "Access Key *"
360
+ msgstr "Clave de Acceso *"
361
+
362
+ #: public/ajax/modalAmazonSettings.php:39
363
+ msgid "Secret Access Key *"
364
+ msgstr "Clave de Acceso Secreto *"
365
+
366
+ #: public/ajax/modalAmazonSettings.php:48 public/ajax/modalFtpSettings.php:89
367
+ #: public/ajax/modalImport.php:95
368
+ msgid "Close"
369
+ msgstr "Cerrar"
370
+
371
+ #: public/ajax/modalCreateSchedule.php:73 public/schedule-free.php:30
372
+ #: public/schedule-single.php:70
373
+ msgid "Schedule settings"
374
+ msgstr "Configuarción de horarios"
375
+
376
+ #: public/ajax/modalCreateSchedule.php:81 public/schedule-free.php:50
377
+ #: public/schedule-single.php:90
378
+ msgid "Schedule label"
379
+ msgstr "Etiqueta de programa"
380
+
381
+ #: public/ajax/modalCreateSchedule.php:88 public/schedule-free.php:57
382
+ #: public/schedule-single.php:97
383
+ msgid "Perform backup every"
384
+ msgstr "Realizar respaldo cada"
385
+
386
+ #: public/ajax/modalCreateSchedule.php:95 public/schedule-single.php:104
387
+ msgid "Day of month"
388
+ msgstr "Dia del mes"
389
+
390
+ #: public/ajax/modalCreateSchedule.php:106 public/schedule-single.php:115
391
+ msgid "Day of week"
392
+ msgstr "Día de la semana"
393
+
394
+ #: public/ajax/modalCreateSchedule.php:113 public/schedule-single.php:122
395
+ msgid "At (UTC+0)"
396
+ msgstr "A las (UTC+0)"
397
+
398
+ #: public/ajax/modalCreateSchedule.php:121 public/schedule.php:22
399
+ msgid "Backup options"
400
+ msgstr "Opciones de respaldo"
401
+
402
+ #: public/ajax/modalCreateSchedule.php:125 public/ajax/modalManualBackup.php:30
403
+ #: public/schedule-free.php:68 public/schedule-single.php:133
404
+ msgid "Full backup"
405
+ msgstr "Respaldo completo"
406
+
407
+ #: public/ajax/modalCreateSchedule.php:131 public/ajax/modalManualBackup.php:36
408
+ #: public/schedule-free.php:74 public/schedule-single.php:139
409
+ msgid "Custom backup"
410
+ msgstr "Respaldo personalizado"
411
+
412
+ #: public/ajax/modalCreateSchedule.php:140 public/ajax/modalManualBackup.php:44
413
+ #: public/schedule-free.php:87 public/schedule-single.php:152
414
+ msgid "Backup files"
415
+ msgstr "Respaldar archivos"
416
+
417
+ #: public/ajax/modalCreateSchedule.php:161 public/ajax/modalManualBackup.php:65
418
+ #: public/schedule-free.php:108 public/schedule-single.php:173
419
+ msgid "Upload to cloud"
420
+ msgstr "Subir a la nube"
421
+
422
+ #: public/ajax/modalCreateSchedule.php:167 public/ajax/modalManualBackup.php:71
423
+ #: public/schedule-free.php:114 public/schedule-single.php:179
424
+ msgid "FTP is not active."
425
+ msgstr "FTP no está activo."
426
+
427
+ #: public/ajax/modalCreateSchedule.php:175 public/ajax/modalManualBackup.php:79
428
+ #: public/schedule-free.php:122 public/schedule-single.php:187
429
+ msgid "Dropbox is not active."
430
+ msgstr "Dropbox no está activo."
431
+
432
+ #: public/ajax/modalCreateSchedule.php:183 public/schedule-single.php:195
433
+ msgid "Google Drive is not active."
434
+ msgstr "Google Drive no está activo."
435
+
436
+ #: public/ajax/modalCreateSchedule.php:191
437
+ msgid "S3 Drive is not active."
438
+ msgstr "S3 no está activo."
439
+
440
+ #: public/ajax/modalCreateSchedule.php:199
441
+ #: public/ajax/modalManualBackup.php:106 public/schedule-free.php:146
442
+ #: public/schedule-single.php:211
443
+ msgid "One Drive is not active."
444
+ msgstr "One Drive no está activo."
445
+
446
+ #: public/ajax/modalCreateSchedule.php:214
447
+ #: public/ajax/modalManualBackup.php:121 public/schedule-free.php:161
448
+ #: public/schedule-single.php:226
449
+ msgid "Background mode"
450
+ msgstr "Modo de fondo"
451
+
452
+ #: public/ajax/modalFtpSettings.php:14
453
+ msgid "FTP settings"
454
+ msgstr "Configuración de FTP"
455
+
456
+ #: public/ajax/modalFtpSettings.php:20
457
+ msgid "Type *"
458
+ msgstr "Tipo *"
459
+
460
+ #: public/ajax/modalFtpSettings.php:28
461
+ msgid "Host *"
462
+ msgstr "Host *"
463
+
464
+ #: public/ajax/modalFtpSettings.php:35
465
+ msgid "User *"
466
+ msgstr "Usuario *"
467
+
468
+ #: public/ajax/modalFtpSettings.php:43
469
+ msgid "Key authentication"
470
+ msgstr "Autenticación de clave"
471
+
472
+ #: public/ajax/modalFtpSettings.php:50
473
+ msgid "Private key *"
474
+ msgstr "Llave privada *"
475
+
476
+ #: public/ajax/modalFtpSettings.php:55 public/ajax/modalImport.php:66
477
+ msgid "Browse"
478
+ msgstr "Explorar"
479
+
480
+ #: public/ajax/modalFtpSettings.php:66
481
+ msgid "Password *"
482
+ msgstr "Contraseña *"
483
+
484
+ #: public/ajax/modalFtpSettings.php:73
485
+ msgid "Port *"
486
+ msgstr "Puerto *"
487
+
488
+ #: public/ajax/modalFtpSettings.php:80
489
+ msgid "Root directory *"
490
+ msgstr "Directorio raíz *"
491
+
492
+ #: public/ajax/modalImport.php:15
493
+ msgid "Import from"
494
+ msgstr "Importar de"
495
+
496
+ #: public/ajax/modalImport.php:25
497
+ msgid "Local PC"
498
+ msgstr "PC local"
499
+
500
+ #: public/ajax/modalImport.php:61
501
+ msgid "SGBP file"
502
+ msgstr "Archivo SGBP"
503
+
504
+ #: public/ajax/modalImport.php:81 public/backups.php:97
505
+ msgid "Filename"
506
+ msgstr "Nombre del archivo"
507
+
508
+ #: public/ajax/modalImport.php:82 public/backups.php:98
509
+ msgid "Size"
510
+ msgstr "Tamaño"
511
+
512
+ #: public/ajax/modalImport.php:83 public/backups.php:99
513
+ msgid "Date"
514
+ msgstr "Fecha"
515
+
516
+ #: public/ajax/modalImport.php:94
517
+ msgid "Back"
518
+ msgstr "Atrás"
519
+
520
+ #: public/ajax/modalImport.php:96
521
+ msgid "Next"
522
+ msgstr "Siguiente"
523
+
524
+ #: public/ajax/modalManualBackup.php:19
525
+ msgid "Prepare migration package"
526
+ msgstr "Preparar paquete de migración"
527
+
528
+ #: public/ajax/modalManualBackup.php:19
529
+ msgid "Manual Backup"
530
+ msgstr "Respaldo manual"
531
+
532
+ #: public/ajax/modalManualBackup.php:88 public/schedule-free.php:130
533
+ msgid "Google Drive is not active."
534
+ msgstr "Google Drive no está activo."
535
+
536
+ #: public/ajax/modalManualBackup.php:97
537
+ msgid "S3 is not active."
538
+ msgstr "S3 no está activo."
539
+
540
+ #: public/ajax/modalManualBackup.php:131 public/backups.php:83
541
+ #: public/backups.php:154
542
+ msgid "Backup"
543
+ msgstr "Respaldo"
544
+
545
+ #: public/ajax/modalManualRestore.php:15
546
+ msgid "Manual Restore"
547
+ msgstr "Restauración manual"
548
+
549
+ #: public/ajax/modalManualRestore.php:25
550
+ msgid "Full restore"
551
+ msgstr "Restauración completa"
552
+
553
+ #: public/ajax/modalManualRestore.php:31
554
+ msgid "Restore files"
555
+ msgstr "Restaurar archivos"
556
+
557
+ #: public/ajax/modalManualRestore.php:40
558
+ msgid "Restore DB"
559
+ msgstr "Restaurar base de datos"
560
+
561
+ #: public/ajax/modalManualRestore.php:49 public/ajax/modalManualRestore.php:65
562
+ #: public/backups.php:175
563
+ msgid "Restore"
564
+ msgstr "Restaurar"
565
+
566
+ #: public/ajax/modalPrivacy.php:8 public/backups.php:70
567
+ #: public/include/footer.php:6
568
+ msgid "Privacy Policy"
569
+ msgstr "Política de privacidad"
570
+
571
+ #: public/ajax/modalPrivacy.php:13
572
+ msgid ""
573
+ "Your privacy is very important to us. Accordingly, we have developed this "
574
+ "Policy in order for you to understand how we collect, use, communicate and "
575
+ "disclose and make use of personal information. The following outlines our "
576
+ "privacy policy."
577
+ msgstr ""
578
+
579
+ #: public/ajax/modalPrivacy.php:15
580
+ msgid ""
581
+ "Before or at the time of collecting personal information, we will identify "
582
+ "the purposes for which information is being collected."
583
+ msgstr ""
584
+
585
+ #: public/ajax/modalPrivacy.php:16
586
+ msgid ""
587
+ "We will collect and use of personal information solely with the objective of "
588
+ "fulfilling those purposes specified by us and for other compatible purposes, "
589
+ "unless we obtain the consent of the individual concerned or as required by "
590
+ "law."
591
+ msgstr ""
592
+
593
+ #: public/ajax/modalPrivacy.php:17
594
+ msgid ""
595
+ "We will only retain personal information as long as necessary for the "
596
+ "fulfillment of those purposes."
597
+ msgstr ""
598
+
599
+ #: public/ajax/modalPrivacy.php:18
600
+ msgid ""
601
+ "We will collect personal information by lawful and fair means and, where "
602
+ "appropriate, with the knowledge or consent of the individual concerned."
603
+ msgstr ""
604
+
605
+ #: public/ajax/modalPrivacy.php:19
606
+ msgid ""
607
+ "Personal data should be relevant to the purposes for which it is to be used, "
608
+ "and, to the extent necessary for those purposes, should be accurate, "
609
+ "complete, and up-to-date."
610
+ msgstr ""
611
+
612
+ #: public/ajax/modalPrivacy.php:20
613
+ msgid ""
614
+ "We will protect personal information by reasonable security safeguards "
615
+ "against loss or theft, as well as unauthorized access, disclosure, copying, "
616
+ "use or modification."
617
+ msgstr ""
618
+
619
+ #: public/ajax/modalPrivacy.php:21
620
+ msgid ""
621
+ "We will make readily available to customers information about our policies "
622
+ "and practices relating to the management of personal information."
623
+ msgstr ""
624
+
625
+ #: public/ajax/modalPrivacy.php:23
626
+ msgid ""
627
+ "We are committed to conducting our business in accordance with these "
628
+ "principles in order to ensure that the confidentiality of personal "
629
+ "information is protected and maintained."
630
+ msgstr ""
631
+
632
+ #: public/ajax/modalPrivacy.php:29 public/ajax/modalTerms.php:28
633
+ msgid "Ok"
634
+ msgstr "Aceptar"
635
+
636
+ #: public/ajax/modalReview.php:8
637
+ msgid "Leave a Review"
638
+ msgstr "Dejar una valoración"
639
+
640
+ #: public/ajax/modalReview.php:13
641
+ msgid ""
642
+ "If you have some time and appreciated our product, please leave us a review "
643
+ "by clicking on the \"Leave a review\" button below."
644
+ msgstr ""
645
+ "Si tiene tiempo y aprecia nuestro producto, déjenos una valoración haciendo "
646
+ "clic en el botón \\\"Dejar una valoración\\\" a continuación."
647
+
648
+ #: public/ajax/modalReview.php:26
649
+ msgid "Don't ask again"
650
+ msgstr "No preguntar de nuevo"
651
+
652
+ #: public/ajax/modalReview.php:27
653
+ msgid "Ask me later"
654
+ msgstr "Preguntar luego"
655
+
656
+ #: public/ajax/modalReview.php:28
657
+ msgid "Leave a review"
658
+ msgstr "Dejar una valoración"
659
+
660
+ #: public/ajax/modalTerms.php:8 public/include/footer.php:6
661
+ msgid "Terms & Conditions"
662
+ msgstr "Términos y condiciones"
663
+
664
+ #: public/ajax/modalTerms.php:13
665
+ msgid "Terms"
666
+ msgstr "Términos"
667
+
668
+ #: public/ajax/modalTerms.php:14
669
+ msgid ""
670
+ "By using this software, you are agreeing to be bound by these software Terms "
671
+ "and Conditions of Use, all applicable laws and regulations, and agree that "
672
+ "you are responsible for compliance with any applicable local laws. If you do "
673
+ "not agree with any of these terms, you are prohibited from using this "
674
+ "software. The materials contained in this software are protected by "
675
+ "applicable copyright and trade mark law."
676
+ msgstr ""
677
+
678
+ #: public/ajax/modalTerms.php:15
679
+ msgid "Disclaimer"
680
+ msgstr ""
681
+
682
+ #: public/ajax/modalTerms.php:16
683
+ msgid "The materials on BackupGuard's are provided"
684
+ msgstr ""
685
+
686
+ #: public/ajax/modalTerms.php:16
687
+ msgid "as is"
688
+ msgstr ""
689
+
690
+ #: public/ajax/modalTerms.php:16
691
+ msgid ""
692
+ "BackupGuard makes no warranties, expressed or implied, and hereby disclaims "
693
+ "and negates all other warranties, including without limitation, implied "
694
+ "warranties or conditions of merchantability, fitness for a particular "
695
+ "purpose, or non-infringement of intellectual property or other violation of "
696
+ "rights. Further, BackupGuard does not warrant or make any representations "
697
+ "concerning the accuracy, likely results, or reliability of the use of the "
698
+ "materials on its Software."
699
+ msgstr ""
700
+
701
+ #: public/ajax/modalTerms.php:17
702
+ msgid "Limitations"
703
+ msgstr ""
704
+
705
+ #: public/ajax/modalTerms.php:18
706
+ msgid ""
707
+ "In no event shall BackupGuard or its suppliers be liable for any damages "
708
+ "(including, without limitation, damages for loss of data or profit, or due "
709
+ "to business interruption,) arising out of the use or inability to use the "
710
+ "materials on BackupGuard's software, even if BackupGuard or a BackupGuard "
711
+ "authorized representative has been notified orally or in writing of the "
712
+ "possibility of such damage. Because some jurisdictions do not allow "
713
+ "limitations on implied warranties, or limitations of liability for "
714
+ "consequential or incidental damages, these limitations may not apply to you."
715
+ msgstr ""
716
+
717
+ #: public/ajax/modalTerms.php:19
718
+ msgid "Revisions and Errata"
719
+ msgstr ""
720
+
721
+ #: public/ajax/modalTerms.php:20
722
+ msgid ""
723
+ "The materials appearing on BackupGuard's software could include technical, "
724
+ "typographical, or photographic errors. BackupGuard does not warrant that any "
725
+ "of the materials on its software are accurate, complete, or current. "
726
+ "BackupGuard may make changes to the materials contained on its software at "
727
+ "any time without notice. BackupGuard does not, however, make any commitment "
728
+ "to update the materials."
729
+ msgstr ""
730
+
731
+ #: public/ajax/modalTerms.php:21
732
+ msgid "Terms of Use Modifications"
733
+ msgstr ""
734
+
735
+ #: public/ajax/modalTerms.php:22
736
+ msgid ""
737
+ "BackupGuard may revise these terms of use for its software at any time "
738
+ "without notice. By using this software you are agreeing to be bound by the "
739
+ "then current version of these Terms and Conditions of Use."
740
+ msgstr ""
741
+
742
+ #: public/ajax/schedule.php:24
743
+ msgid "Cron is not available on your hosting."
744
+ msgstr "Cron no está disponible en tu hosting."
745
+
746
+ #: public/ajax/schedule.php:44 public/ajax/schedule.php:52
747
+ msgid "Label field is required."
748
+ msgstr "El campo de la etiqueta es obligatorio."
749
+
750
+ #: public/ajax/schedule.php:112
751
+ msgid "Invalid backup type"
752
+ msgstr "Tipo de respaldo no válido"
753
+
754
+ #: public/ajax/settings.php:30
755
+ msgid "Email is required."
756
+ msgstr "Correo electronico es requerido."
757
+
758
+ #: public/ajax/settings.php:36
759
+ msgid "Invalid email address."
760
+ msgstr "Correo electrónico no válido."
761
+
762
+ #: public/backups.php:23
763
+ msgid "Let us be more helpful!"
764
+ msgstr "¡Permítanos ser más útiles!"
765
+
766
+ #: public/backups.php:25
767
+ msgid "Tell us about your primary needs and be aware of our news and updates."
768
+ msgstr ""
769
+ "Cuéntenos sobre sus necesidades principales y esté al tanto de nuestras "
770
+ "noticias y actualizaciones."
771
+
772
+ #: public/backups.php:31
773
+ msgid "Please Enter First Name."
774
+ msgstr "Por favor ingrese el nombre."
775
+
776
+ #: public/backups.php:35
777
+ msgid "Please Enter Last Name."
778
+ msgstr "Por favor ingrese el apellido."
779
+
780
+ #: public/backups.php:41
781
+ msgid "Please Enter Valid Email Address."
782
+ msgstr "Por favor ingrese una dirección de correo electrónico válida."
783
+
784
+ #: public/backups.php:47
785
+ msgid "Please Select Your Priority"
786
+ msgstr "Por favor seleccione su prioridad"
787
+
788
+ #: public/backups.php:48
789
+ msgid "Local Backup"
790
+ msgstr "Respaldo local"
791
+
792
+ #: public/backups.php:49
793
+ msgid "Cloud Backup"
794
+ msgstr "Respaldo en la nube"
795
+
796
+ #: public/backups.php:50
797
+ msgid "Scheduling"
798
+ msgstr "Respaldos programados"
799
+
800
+ #: public/backups.php:51
801
+ msgid "Migration"
802
+ msgstr "Migración"
803
+
804
+ #: public/backups.php:52
805
+ msgid "Other"
806
+ msgstr "Otro"
807
+
808
+ #: public/backups.php:54
809
+ msgid "Please Select Your Priority."
810
+ msgstr "Por favor, seleccione su prioridad."
811
+
812
+ #: public/backups.php:59
813
+ msgid "Please select your priority."
814
+ msgstr "Por favor, seleccione su prioridad."
815
+
816
+ #: public/backups.php:60
817
+ msgid "Please Enter Your Priority."
818
+ msgstr "Por favor ingrese su prioridad."
819
+
820
+ #: public/backups.php:64
821
+ msgid "Subscribe"
822
+ msgstr "Suscribirse"
823
+
824
+ #: public/backups.php:69
825
+ msgid "Terms of Service"
826
+ msgstr "Términos de servicio"
827
+
828
+ #: public/backups.php:87
829
+ msgid "Migrate"
830
+ msgstr "Migrar"
831
+
832
+ #: public/backups.php:100 public/schedule.php:24
833
+ msgid "Status"
834
+ msgstr "Estado"
835
+
836
+ #: public/backups.php:101 public/schedule.php:25
837
+ msgid "Actions"
838
+ msgstr "Acciones"
839
+
840
+ #: public/backups.php:129
841
+ msgid "Warnings found during backup"
842
+ msgstr "Advertencias encontradas durante el respaldo"
843
+
844
+ #: public/backups.php:129
845
+ msgid "Warnings found during restore"
846
+ msgstr "Advertencias encontradas durante la restauración"
847
+
848
+ #: public/backups.php:129
849
+ msgid "Warnings found during upload"
850
+ msgstr "Advertencias encontradas durante la subida"
851
+
852
+ #: public/backups.php:131
853
+ msgid "Errors found during backup"
854
+ msgstr "Errores encontrados durante el respaldo"
855
+
856
+ #: public/backups.php:131
857
+ msgid "Errors found during restore"
858
+ msgstr "Errores encontrados durante la restauración"
859
+
860
+ #: public/backups.php:131
861
+ msgid "Errors found during upload"
862
+ msgstr "Errores encontrados durante la subida"
863
+
864
+ #: public/backups.php:141
865
+ msgid "Stop"
866
+ msgstr "Detener"
867
+
868
+ #: public/backups.php:144 public/backups.php:186 public/schedule.php:74
869
+ msgid "Delete"
870
+ msgstr "Eliminar"
871
+
872
+ #: public/backups.php:146
873
+ msgid "Download"
874
+ msgstr "Descargar"
875
+
876
+ #: public/backups.php:161
877
+ msgid "Backup log"
878
+ msgstr "Log de respaldo"
879
+
880
+ #: public/backups.php:168
881
+ msgid "Restore log"
882
+ msgstr "Log de restauración"
883
+
884
+ #: public/cloud.php:24
885
+ msgid "Cloud settings"
886
+ msgstr "Configuración de la nube"
887
+
888
+ #: public/cloud.php:28
889
+ msgid "Destination folder"
890
+ msgstr "Carpeta de destino"
891
+
892
+ #: public/cloud.php:50 public/cloud.php:67 public/cloud.php:84
893
+ #: public/cloud.php:102 public/cloud.php:120
894
+ msgid "ON"
895
+ msgstr "ON"
896
+
897
+ #: public/cloud.php:50 public/cloud.php:67 public/cloud.php:84
898
+ #: public/cloud.php:102 public/cloud.php:120
899
+ msgid "OFF"
900
+ msgstr "OFF"
901
+
902
+ #: public/include/footer.php:4
903
+ msgid "Powered by BackupGuard"
904
+ msgstr ""
905
+
906
+ #: public/include/footer.php:7
907
+ msgid "v.1.0.0"
908
+ msgstr ""
909
+
910
+ #: public/link_license.php:15
911
+ msgid "Invalid or unassigned license"
912
+ msgstr "Licencia inválida o no asignada"
913
+
914
+ #: public/link_license.php:19
915
+ msgid ""
916
+ "Your license could not be validated. Maybe you forgot to link a license to "
917
+ "this domain. If that is the case, please link one license below:"
918
+ msgstr ""
919
+ "Su licencia no pudo ser validada. Tal vez se le olvidó vincular una licencia "
920
+ "a este dominio. Si ese es el caso, por favor vincule una licencia a "
921
+ "continuación:"
922
+
923
+ #: public/link_license.php:23
924
+ msgid "Choose a license"
925
+ msgstr "Elige una licencia"
926
+
927
+ #: public/link_license.php:33
928
+ msgid "Link this domain now"
929
+ msgstr "Enlace este dominio ahora"
930
+
931
+ #: public/link_license.php:37
932
+ msgid ""
933
+ "Your license could not be validated. It seems that you have already assigned "
934
+ "all of your licenses."
935
+ msgstr ""
936
+ "Su licencia no pudo ser validada. Parece que ya ha asignado todas sus "
937
+ "licencias."
938
+
939
+ #: public/link_license.php:40
940
+ msgid ""
941
+ "Please login to your dashboard to manage your website urls and release a "
942
+ "license to be able to use it."
943
+ msgstr ""
944
+ "Inicie sesión en su panel de control para administrar las URL de su sitio "
945
+ "web y libere una licencia para poder usarla."
946
+
947
+ #: public/link_license.php:43
948
+ msgid "Login to dashboard"
949
+ msgstr "Iniciar sesión en el panel"
950
+
951
+ #: public/link_license.php:46
952
+ msgid "Click here to try again"
953
+ msgstr "Haga clic aquí para volver a intentarlo"
954
+
955
+ #: public/login.php:11
956
+ msgid "Login to your account"
957
+ msgstr "Ingrese a su cuenta"
958
+
959
+ #: public/login.php:12
960
+ msgid "Invalid login info. Please try again."
961
+ msgstr "Información de inicio de sesión no válida. Inténtalo de nuevo."
962
+
963
+ #: public/login.php:17
964
+ msgid "How do I get this?"
965
+ msgstr "¿Cómo consigo esto?"
966
+
967
+ #: public/login.php:19
968
+ msgid "The credentials were sent to your email."
969
+ msgstr "Las credenciales fueron enviadas a su correo electrónico."
970
+
971
+ #: public/login.php:20
972
+ msgid "In case if you didn't receive them, please contact us."
973
+ msgstr "En caso de no recibirlos, por favor contáctenos."
974
+
975
+ #: public/login.php:25
976
+ msgid "Login"
977
+ msgstr "Iniciar sesión"
978
+
979
+ #: public/schedule-free.php:34 public/schedule-single.php:74
980
+ msgid "*Multiple schedule profiles are available only in"
981
+ msgstr ""
982
+ "*Los perfiles de horarios múltiples están disponibles solo en la versión"
983
+
984
+ #: public/schedule-free.php:34 public/schedule-single.php:74
985
+ msgid "Platinum"
986
+ msgstr "Platinum"
987
+
988
+ #: public/schedule-free.php:34 public/schedule-single.php:74
989
+ msgid "version."
990
+ msgstr "."
991
+
992
+ #: public/schedule-free.php:40 public/schedule-single.php:80
993
+ msgid "Scheduled backup"
994
+ msgstr "Respaldo programado"
995
+
996
+ #: public/schedule-free.php:138 public/schedule-single.php:203
997
+ msgid "Amazon S3 Drive is not active."
998
+ msgstr "Amazon S3 no está activo."
999
+
1000
+ #: public/schedule.php:13
1001
+ msgid "Schedules"
1002
+ msgstr "Horarios"
1003
+
1004
+ #: public/schedule.php:14
1005
+ msgid "Create schedule"
1006
+ msgstr "Programar"
1007
+
1008
+ #: public/schedule.php:19
1009
+ msgid "Label"
1010
+ msgstr "Etiqueta"
1011
+
1012
+ #: public/schedule.php:20
1013
+ msgid "Recurrence"
1014
+ msgstr "Recurrencia"
1015
+
1016
+ #: public/schedule.php:21
1017
+ msgid "Execution date"
1018
+ msgstr "Fecha de ejecución"
1019
+
1020
+ #: public/schedule.php:23
1021
+ msgid "Upload to"
1022
+ msgstr "Subir a"
1023
+
1024
+ #: public/schedule.php:31
1025
+ msgid "No schedules found."
1026
+ msgstr "No se han encontrado horarios."
1027
+
1028
+ #: public/schedule.php:71
1029
+ msgid "Pending"
1030
+ msgstr "Pendiente"
1031
+
1032
+ #: public/schedule.php:71
1033
+ msgid "Inactive"
1034
+ msgstr "Inactivo"
1035
+
1036
+ #: public/schedule.php:73
1037
+ msgid "Edit"
1038
+ msgstr "Editar"
1039
+
1040
+ #: public/services.php:8
1041
+ msgid "Special services"
1042
+ msgstr ""
1043
+
1044
+ #: public/services.php:13
1045
+ msgid "WordPress website migration"
1046
+ msgstr ""
1047
+
1048
+ #: public/services.php:22
1049
+ msgid "Order now"
1050
+ msgstr ""
1051
+
1052
+ #: public/services.php:28
1053
+ msgid ""
1054
+ "Our professionals will migrate all of your files and database and ensure "
1055
+ "everything is working properly on your new server. With our migration "
1056
+ "service, you can expect:"
1057
+ msgstr ""
1058
+
1059
+ #: public/services.php:32
1060
+ msgid "Migration of your files"
1061
+ msgstr ""
1062
+
1063
+ #: public/services.php:36
1064
+ msgid "Migration of your database"
1065
+ msgstr ""
1066
+
1067
+ #: public/services.php:40
1068
+ msgid "Refactoring of all urls"
1069
+ msgstr ""
1070
+
1071
+ #: public/services.php:44
1072
+ msgid "Refactoring of all file names and image paths"
1073
+ msgstr ""
1074
+
1075
+ #: public/services.php:48
1076
+ msgid "Serialized data refactoring"
1077
+ msgstr ""
1078
+
1079
+ #: public/settings.php:34
1080
+ msgid "General settings"
1081
+ msgstr "Configuración general"
1082
+
1083
+ #: public/settings.php:38
1084
+ msgid "Email notifications"
1085
+ msgstr "Notificaciónes de correo electrónico"
1086
+
1087
+ #: public/settings.php:51
1088
+ msgid "Enter email"
1089
+ msgstr "Ingrese correo electrónico"
1090
+
1091
+ #: public/settings.php:53
1092
+ msgid "You can enter multiple emails, just separate them with comma"
1093
+ msgstr ""
1094
+ "Puede ingresar múltiples correos electrónicos, solo sepárelos con una coma"
1095
+
1096
+ #: public/settings.php:60
1097
+ msgid "Reloads enabled"
1098
+ msgstr "Recargas habilitadas"
1099
+
1100
+ #: public/settings.php:71
1101
+ msgid "Delete local backup after upload"
1102
+ msgstr "Eliminar respaldo local después de subir"
1103
+
1104
+ #: public/settings.php:83
1105
+ msgid "Alert before update"
1106
+ msgstr "Alertar antes de actualizar"
1107
+
1108
+ #: public/settings.php:95
1109
+ msgid "Backup deletion will also delete from cloud"
1110
+ msgstr "La eliminación del respaldo también lo eliminará de la nube"
1111
+
1112
+ #: public/settings.php:106
1113
+ msgid "Show statistics"
1114
+ msgstr "Mostrar estadísticas"
1115
+
1116
+ #: public/settings.php:117
1117
+ msgid "FTP passive mode"
1118
+ msgstr "Modo pasivo FTP"
1119
+
1120
+ #: public/settings.php:129
1121
+ msgid "Disable ads"
1122
+ msgstr "Desactivar los anuncios"
1123
+
1124
+ #: public/settings.php:140
1125
+ msgid "Exclude paths (separated by commas)"
1126
+ msgstr "Excluir directorios (separados por comas)"
1127
+
1128
+ #: public/settings.php:147
1129
+ msgid "Tables to exclude (separated by commas)"
1130
+ msgstr "Excluir tablas (separadas por comas)"
1131
+
1132
+ #: public/settings.php:155
1133
+ msgid "Backup retention"
1134
+ msgstr "Retención de respaldos"
1135
+
1136
+ #: public/settings.php:163
1137
+ msgid "Number of rows to backup at once"
1138
+ msgstr "Número de lineas para respaldar a la vez"
1139
+
1140
+ #: public/settings.php:170
1141
+ msgid "Reload method"
1142
+ msgstr "Método de recarga"
1143
+
1144
+ #: public/settings.php:182
1145
+ msgid "Backup file name"
1146
+ msgstr "Nombre del archivo de respaldo"
1147
+
1148
+ #: public/settings.php:191
1149
+ msgid "AJAX request frequency"
1150
+ msgstr "Frecuencia de solicitudes AJAX"
1151
+
1152
+ #: public/settings.php:197
1153
+ msgid "Backup destination path"
1154
+ msgstr "Ruta de destino de respaldo"
public/ajax/awake.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/../boot.php');
4
+ require_once(SG_LIB_PATH.'SGReloader.php');
5
+
6
+ @session_write_close();
7
+
8
+ SGReloader::awake($method);
9
+ exit();
public/ajax/cancelBackup.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+
5
+ if(backupGuardIsAjax() && isset($_POST['actionId']))
6
+ {
7
+ $actionId = (int)$_POST['actionId'];
8
+ SGBackup::cancelAction($actionId);
9
+ die('{"success":1}');
10
+ }
public/ajax/cancelDownload.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+ if(backupGuardIsAjax() && isset($_POST['name']))
3
+ {
4
+ @unlink(SG_BACKUP_DIRECTORY.$_POST['name']);
5
+ die('{"success":1}');
6
+ }
public/ajax/checkBackupCreation.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+ if(backupGuardIsAjax())
5
+ {
6
+ while (true)
7
+ {
8
+ $created = SGConfig::get('SG_RUNNING_ACTION', true);
9
+
10
+ if ($created)
11
+ {
12
+ die('1');
13
+ }
14
+ }
15
+
16
+ die('2');
17
+ }
public/ajax/checkPHPVersionCompatibility.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/../boot.php');
4
+ require_once(SG_LIB_PATH.'SGArchive.php');
5
+
6
+ if(backupGuardIsAjax() && count($_POST)) {
7
+ try {
8
+ $name = $_POST['bname'];
9
+ $path = SG_BACKUP_DIRECTORY.$name.'/'.$name.'.sgbp';
10
+
11
+ $sgArchive = new SGArchive($path, 'r');
12
+ $headers = $sgArchive->getArchiveHeaders();
13
+
14
+ if (isset($headers['phpVersion'])) {
15
+ $oldPHPVersion = $headers['phpVersion'];
16
+ $currentVersion = phpversion();
17
+
18
+ // Drop the last digits of version (e.g. 5.3.3 will be 5) by explicit casting from string to int. This will check the migrations like php 5.x.x -> 7.x.x
19
+ if ((int)$oldPHPVersion != (int)$currentVersion) {
20
+ die(json_encode(array(
21
+ 'warning' => 'Warning: The backup has been captured for php '.$oldPHPVersion.' whereas your server is running php '.$currentVersion.'. If you’re sure the website is compatible with php '.$currentVersion.', please confirm to start the restoration.'
22
+ )));
23
+ }
24
+ }
25
+
26
+ die(json_encode(array()));
27
+ }
28
+ catch(Exception $e) {
29
+ die(json_encode(array(
30
+ 'error' => $e->getMessage()
31
+ )));
32
+ }
33
+ }
public/ajax/checkRestoreCreation.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/../boot.php');
4
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
5
+
6
+ if (backupGuardIsAjax()) {
7
+ $timeout = 10; //in sec
8
+ while ($timeout != 0) {
9
+ sleep(1);
10
+ $timeout--;
11
+ $created = SGConfig::get('SG_RUNNING_ACTION', true);
12
+
13
+ if ($created) {
14
+ $runningActions = SGBackup::getRunningActions();
15
+ if ($runningActions) {
16
+ $actionId = $runningActions[0]['id'];
17
+ die(json_encode(array(
18
+ 'status' => 0,
19
+ 'external_enabled' => SGExternalRestore::isEnabled()?1:0,
20
+ 'external_url' => SGExternalRestore::getInstance()->getDestinationFileUrl()
21
+ )));
22
+ }
23
+ }
24
+ }
25
+
26
+ die('{"status":1}');
27
+ }
public/ajax/cloudDropbox.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_STORAGE_PATH.'SGDropboxStorage.php');
4
+
5
+ if(backupGuardIsAjax()) {
6
+ SGConfig::set('SG_DROPBOX_ACCESS_TOKEN','');
7
+ SGConfig::set('SG_DROPBOX_CONNECTION_STRING','');
8
+
9
+ if(isset($_POST['cancel'])) {
10
+ die('{"success":1}');
11
+ }
12
+ }
13
+
14
+ $dp = new SGDropboxStorage();
15
+ try {
16
+ $dp->connect();
17
+ }
18
+ catch(Exception $e) {
19
+ header("Location: ".SG_PUBLIC_CLOUD_URL);
20
+ }
21
+
22
+ if($dp->isConnected()) {
23
+ header("Location: ".SG_PUBLIC_CLOUD_URL);
24
+ exit();
25
+ }
public/ajax/curlChecker.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ if(backupGuardIsAjax())
4
+ {
5
+ try
6
+ {
7
+ SGBoot::checkRequirement('curl');
8
+ die('{"success":1}');
9
+ }
10
+ catch(SGException $exception)
11
+ {
12
+ die('{"error":"'.$exception->getMessage().'"}');
13
+ }
14
+ }
public/ajax/deleteBackup.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+ if(isset($_POST['backupName']))
5
+ {
6
+ $backupName = backupGuardSanitizeTextField($_POST['backupName']);
7
+ for ($i=0; $i < count($backupName) ; $i++) {
8
+ SGBackup::deleteBackup($backupName[$i]);
9
+ }
10
+ }
11
+ die('{"success":1}');
public/ajax/dismissDiscountNotice.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/../boot.php');
4
+
5
+ SGConfig::set('SG_HIDE_DISCOUNT_NOTICE', 1);
public/ajax/downloadBackup.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+ if(count($_GET))
5
+ {
6
+ $response = array();
7
+ $downloadType = (int)$_GET['downloadType'];
8
+ if($downloadType == SG_BACKUP_DOWNLOAD_TYPE_BACKUP_LOG ||
9
+ $downloadType == SG_BACKUP_DOWNLOAD_TYPE_RESTORE_LOG ||
10
+ $downloadType == SG_BACKUP_DOWNLOAD_TYPE_SGBP)
11
+ {
12
+ $backupName = $_GET['backupName'];
13
+ try
14
+ {
15
+ SGBackup::download($backupName, $downloadType);
16
+ }
17
+ catch (SGException $exception)
18
+ {
19
+ die($exception->getMessage());
20
+ }
21
+ }
22
+ }
public/ajax/getAction.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+
5
+ if(backupGuardIsAjax() && count($_POST))
6
+ {
7
+ @session_write_close();
8
+
9
+ $actionId = (int)$_POST['actionId'];
10
+ $currentAction = SGBackup::getAction($actionId);
11
+
12
+ if($currentAction)
13
+ {
14
+ if($currentAction['status'] == SG_ACTION_STATUS_IN_PROGRESS_FILES || $currentAction['status'] == SG_ACTION_STATUS_IN_PROGRESS_DB)
15
+ {
16
+ if (!SGPing::ping()) {
17
+ $backup = new SGBackup;
18
+ $backup->handleExecutionTimeout($actionId);
19
+ $currentAction = SGBackup::getAction($actionId);
20
+ }
21
+ die(json_encode($currentAction));
22
+ }
23
+ die('0');
24
+ }
25
+ die('0');
26
+ }
public/ajax/getBackupContent.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ header('Content-Type: application/json');
3
+ require_once(dirname(__FILE__).'/../boot.php');
4
+ require_once(SG_LIB_PATH.'SGArchive.php');
5
+ require_once(SG_BACKUP_PATH.'SGBackupFiles.php');
6
+ $backupName = $_GET['backupName'];
7
+ $path = isset($_GET["path"])? $_GET["path"] : "wp-content/";
8
+ $parent = $path;
9
+ $data = array();
10
+
11
+ $disabled = !SGBoot::isFeatureAvailable('SLECTIVE_RESTORE');
12
+
13
+ if ($path == "#") {
14
+
15
+ $parentNode = array();
16
+ $parentNode["id"] = "/";
17
+ $parentNode["parent"] = "#";
18
+ $parentNode["text"] = "/";
19
+ $parentNode["type"] = "none";
20
+ $parentNode["children"] = true;
21
+ $parentNode["state"] = array ("selected"=>true);
22
+ array_push($data,$parentNode);
23
+
24
+ }
25
+ else {
26
+ if ($path == "/") {
27
+ $path = "";
28
+ }
29
+ else {
30
+ $path .= '/';
31
+ }
32
+
33
+ $backupPath = SG_BACKUP_DIRECTORY.$backupName;
34
+ $backupPath= $backupPath.'/'.$backupName.'.sgbp';
35
+ $backupFiles = new SGBackupFiles();
36
+ $archive = new SGArchive($backupPath,'r');
37
+ $archive->setDelegate($backupFiles);
38
+ $headers = $archive->getArchiveHeaders();
39
+ $filesList = $archive->getFilesList();
40
+ $tree = $archive->getTreefromList($filesList, $path);
41
+
42
+
43
+ foreach ($tree as $node) {
44
+ $el = array();
45
+ $el["id"] = $path.$node->name;
46
+ $el["parent"] = $parent;
47
+ $el["text"] = $node->name;
48
+ $el["type"] = $node->type;
49
+ if ($node->type == "folder") {
50
+ $el["children"] = true;
51
+ }
52
+ array_push($data, $el);
53
+ }
54
+ }
55
+
56
+ echo json_encode($data);
public/ajax/getRunningActions.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+ if(backupGuardIsAjax()) {
5
+ $runningAction = backupGuardGetRunningActions();
6
+ if($runningAction) {
7
+ die(json_encode($runningAction));
8
+ }
9
+ die('0');
10
+ }
public/ajax/hideNotice.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+
4
+ if(backupGuardIsAjax() && count($_POST)) {
5
+ if ($_POST['notice'] == SG_NOTICE_EXECUTION_TIMEOUT) {
6
+ SGConfig::set('SG_EXCEPTION_TIMEOUT_ERROR', '0');
7
+ }
8
+
9
+ if ($_POST['notice'] == SG_NOTICE_MIGRATION_ERROR) {
10
+ SGConfig::set('SG_BACKUP_SHOW_MIGRATION_ERROR', '0');
11
+ }
12
+
13
+ if ($_POST['notice'] == SG_NOTICE_NOT_WRITABLE_ERROR) {
14
+ SGConfig::set('SG_BACKUP_SHOW_NOT_WRITABLE_ERROR', '0');
15
+ }
16
+ }
public/ajax/importBackup.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+ require_once(SG_LIB_PATH.'SGUploadHandler.php');
5
+
6
+ $error = array();
7
+ $success = array('success'=>1);
8
+
9
+ try {
10
+ $sgUploadHandler = new BackupGuard\Upload\Handler($_FILES);
11
+ }
12
+ catch (SGException $exception) {
13
+ array_push($error, $exception->getMessage());
14
+ die(json_encode($error));
15
+ }
16
+
17
+ die();
public/ajax/isFeatureAvailable.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+
4
+ $sgFeature = $_POST['sgFeature'];
5
+ if (!SGBoot::isFeatureAvailable($sgFeature)) {
6
+ die('{"error":'._backupGuardT("This feature is not available in your package.", true).'"}');
7
+ }
8
+
9
+ die('{"success":1}');
public/ajax/manualBackup.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__) . '/../boot.php');
4
+ require_once(SG_BACKUP_PATH . 'SGBackup.php');
5
+
6
+ try {
7
+ $state = false;
8
+ $success = array('success' => 1);
9
+
10
+ if (backupGuardIsAjax() && count($_POST)) {
11
+
12
+ $allActions = SGBackup::getRunningActions();
13
+ if (count($allActions)) { // abort any other backup if there is an active action
14
+ die(json_encode(array(
15
+ "error" => _backupGuardT("There is an active backup running. Please try later", true)
16
+ )));
17
+ }
18
+
19
+ $options = $_POST;
20
+ $error = array();
21
+ SGConfig::set("SG_BACKUP_TYPE", (int)$options['backup-type']);
22
+
23
+ $options = backupGuardGetBackupOptions($options);
24
+
25
+ $sgBackup = new SGBackup();
26
+ $sgBackup->backup($options, $state);
27
+
28
+ die(json_encode($success));
29
+ }
30
+
31
+ die(json_encode(array(
32
+ "error" => "Direct call"
33
+ )));
34
+ }
35
+ catch (SGException $exception) {
36
+ array_push($error, $exception->getMessage());
37
+ die(json_encode($error));
38
+ }
public/ajax/modalImport.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ $backupDirectory = SGConfig::get('SG_BACKUP_DIRECTORY');
4
+ $maxUploadSize = ini_get('upload_max_filesize');
5
+ $dropbox = SGConfig::get('SG_DROPBOX_ACCESS_TOKEN');
6
+ $gdrive = SGConfig::get('SG_GOOGLE_DRIVE_REFRESH_TOKEN');
7
+ $ftp = SGConfig::get('SG_STORAGE_FTP_CONNECTED');
8
+ $amazon = SGConfig::get('SG_AMAZON_KEY');
9
+ $oneDrive = SGConfig::get('SG_ONE_DRIVE_REFRESH_TOKEN');
10
+ ?>
11
+ <div class="modal-dialog">
12
+ <div class="modal-content">
13
+ <div class="modal-header">
14
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
15
+ <h4 class="modal-title"><?php _backupGuardT('Import from')?></h4>
16
+ </div>
17
+ <div class="modal-body sg-modal-body" id="sg-modal-inport-from">
18
+ <div class="col-md-12" id="modal-import-1">
19
+ <div class="form-group">
20
+ <table class="table table-striped paginated sg-backup-table">
21
+ <tbody>
22
+ <tr>
23
+ <td class="file-select-radio"><input name="storage-radio" type="radio" value="local-pc"></td>
24
+ <td></td>
25
+ <td><?php _backupGuardT('Local PC')?></td>
26
+ </tr>
27
+ <?php if (SGBoot::isFeatureAvailable('DOWNLOAD_FROM_CLOUD')): ?>
28
+ <tr>
29
+ <td class="file-select-radio"><input name="storage-radio" type="radio" value="<?php echo SG_STORAGE_FTP?>" <?php echo empty($ftp)?'disabled="disabled"':''?>></td>
30
+ <td><span class="btn-xs sg-status-icon sg-status-31 active">&nbsp;</span></td>
31
+ <td><?php echo 'FTP' ?></td>
32
+ </tr>
33
+
34
+ <tr>
35
+ <td class="file-select-radio"><input name="storage-radio" type="radio" value="<?php echo SG_STORAGE_DROPBOX?>" <?php echo empty($dropbox)?'disabled="disabled"':''?>></td>
36
+ <td><span class="btn-xs sg-status-icon sg-status-32 active">&nbsp;</span></td>
37
+ <td><?php echo 'Dropbox' ?></td>
38
+ </tr>
39
+ <tr>
40
+ <td class="file-select-radio"><input name="storage-radio" type="radio" value="<?php echo SG_STORAGE_GOOGLE_DRIVE?>" <?php echo empty($gdrive)?'disabled="disabled"':''?>></td>
41
+ <td><span class="btn-xs sg-status-icon sg-status-33 active">&nbsp;</span></td>
42
+ <td><?php echo 'Google Drive' ?></td>
43
+ </tr>
44
+ <tr>
45
+ <td class="file-select-radio"><input name="storage-radio" type="radio" value="<?php echo SG_STORAGE_AMAZON?>" <?php echo empty($amazon)?'disabled="disabled"':''?>></td>
46
+ <td><span class="btn-xs sg-status-icon sg-status-34 active">&nbsp;</span></td>
47
+ <td><?php echo (backupGuardIsAccountGold()? 'Amazon ':'').'S3' ?></td>
48
+ </tr>
49
+ <tr>
50
+ <td class="file-select-radio"><input name="storage-radio" type="radio" value="<?php echo SG_STORAGE_ONE_DRIVE?>" <?php echo empty($oneDrive)?'disabled="disabled"':''?>></td>
51
+ <td><span class="btn-xs sg-status-icon sg-status-35 active">&nbsp;</span></td>
52
+ <td><?php echo 'One Drive' ?></td>
53
+ </tr>
54
+ <?php endif; ?>
55
+ </tbody>
56
+ </table>
57
+ </div>
58
+ </div>
59
+ <div class="col-md-12" id="modal-import-2">
60
+ <div class="form-group">
61
+ <label class="col-md-2 control-label sg-upload-label" for="textinput"><?php _backupGuardT('SGBP file')?></label>
62
+ <div class="col-md-10">
63
+ <div class="input-group">
64
+ <span class="input-group-btn">
65
+ <span class="btn btn-primary btn-file">
66
+ <?php _backupGuardT('Browse')?>&hellip; <input class="sg-backup-upload-input" type="file" name="files[]" data-url="<?php echo admin_url('admin-ajax.php')."?action=backup_guard_importBackup" ?>" data-max-file-size="<?php echo backupGuardConvertToBytes($maxUploadSize.'B'); ?>">
67
+ </span>
68
+ </span>
69
+ <input type="text" id="sg-import-file-name" class="form-control" readonly>
70
+ </div>
71
+ <br/>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ <?php if (SGBoot::isFeatureAvailable('DOWNLOAD_FROM_CLOUD')): ?>
76
+ <div class="col-md-12" id="modal-import-3">
77
+ <table class="table table-striped paginated sg-backup-table" id="sg-archive-list-table">
78
+ <thead>
79
+ <tr>
80
+ <th></th>
81
+ <th><?php _backupGuardT('Filename')?></th>
82
+ <th><?php _backupGuardT('Size')?></th>
83
+ <th><?php _backupGuardT('Date')?></th>
84
+ </tr>
85
+ </thead>
86
+ <tbody>
87
+ </tbody>
88
+ </table>
89
+ </div>
90
+ <?php endif; ?>
91
+ <div class="clearfix"></div>
92
+ </div>
93
+ <div class="modal-footer">
94
+ <button type="button" class="pull-left btn btn-default" id="switch-modal-import-pages-back" onclick="sgBackup.previousPage()"><?php _backupGuardT('Back')?></button>
95
+ <button type="button" class="btn btn-default" id="sg-close-modal-import" data-dismiss="modal"><?php _backupGuardT("Close")?></button>
96
+ <button type="button" class="btn btn-primary" id="switch-modal-import-pages-next" data-remote="importBackup" onclick="sgBackup.nextPage()"><?php _backupGuardT('Next')?></button>
97
+ <button type="button" data-remote="importBackup" id="uploadSgbpFile" class="btn btn-primary"><?php _backupGuardT('Import')?></button>
98
+ </div>
99
+ </div>
100
+ </div>
public/ajax/modalManualBackup.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+
4
+ $directories = SG_BACKUP_FILE_PATHS;
5
+ $directories = explode(',', $directories);
6
+ $dropbox = SGConfig::get('SG_DROPBOX_ACCESS_TOKEN');
7
+ $gdrive = SGConfig::get('SG_GOOGLE_DRIVE_REFRESH_TOKEN');
8
+ $ftp = SGConfig::get('SG_STORAGE_FTP_CONNECTED');
9
+ $amazon = SGConfig::get('SG_AMAZON_KEY');
10
+ $oneDrive = SGConfig::get('SG_ONE_DRIVE_REFRESH_TOKEN');
11
+
12
+ $backupType = (int)@$_GET['backupType'];
13
+ ?>
14
+ <div class="modal-dialog">
15
+ <div class="modal-content">
16
+ <div class="modal-header">
17
+ <div id="sg-modal-manual-backup-header">
18
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
19
+ <h4 class="modal-title"><?php ($backupType == SG_BACKUP_METHOD_MIGRATE)?_backupGuardT("Prepare migration package"):_backupGuardT("Manual Backup") ?></h4>
20
+ </div>
21
+ </div>
22
+ <form class="form-horizontal" method="post" id="manualBackup">
23
+ <div class="modal-body sg-modal-body">
24
+ <!-- Multiple Radios -->
25
+ <div class="form-group">
26
+ <div class="col-md-12">
27
+ <input type="text" name="sg-custom-backup-name" id="sg-custom-backup-name" placeholder="Custom backup name (optional)">
28
+ </div>
29
+ <div class="col-md-12">
30
+ <div class="radio">
31
+ <label for="fullbackup-radio">
32
+ <input type="radio" name="backupType" id="fullbackup-radio" value="1" checked="checked">
33
+ <?php _backupGuardT('Full backup'); ?>
34
+ </label>
35
+ </div>
36
+ <div class="radio">
37
+ <label for="custombackup-radio">
38
+ <input type="radio" name="backupType" id="custombackup-radio" value="2">
39
+ <?php _backupGuardT('Custom backup'); ?>
40
+ </label>
41
+ </div>
42
+ <div class="col-md-12 sg-custom-backup">
43
+ <?php backupGuardGetBackupTablesHTML(); ?>
44
+ <div class="checkbox sg-no-padding-top">
45
+ <label for="custombackupfiles-chbx">
46
+ <input type="checkbox" class="sg-custom-option" name="backupFiles" id="custombackupfiles-chbx">
47
+ <?php _backupGuardT('Backup files'); ?>
48
+ </label>
49
+ <!--Files-->
50
+ <div class="col-md-12 sg-checkbox sg-custom-backup-files">
51
+ <?php foreach ($directories as $directory): ?>
52
+ <div class="checkbox">
53
+ <label for="<?php echo 'sg'.$directory?>">
54
+ <input type="checkbox" name="directory[]" id="<?php echo 'sg'.$directory;?>" value="<?php echo $directory;?>">
55
+ <?php echo basename($directory);?>
56
+ </label>
57
+ </div>
58
+ <?php endforeach;?>
59
+ </div>
60
+ </div>
61
+ </div>
62
+ <div class="clearfix"></div>
63
+ <?php if(SGBoot::isFeatureAvailable('STORAGE')): ?>
64
+ <!--Cloud-->
65
+ <div class="checkbox sg-no-padding-top">
66
+ <label for="custombackupcloud-chbx">
67
+ <input type="checkbox" name="backupCloud" id="custombackupcloud-chbx">
68
+ <?php _backupGuardT('Upload to cloud'); ?>
69
+ </label>
70
+ <!--Storages-->
71
+ <div class="col-md-12 sg-checkbox sg-custom-backup-cloud">
72
+ <?php if(SGBoot::isFeatureAvailable('FTP')): ?>
73
+ <div class="checkbox">
74
+ <label for="cloud-ftp" <?php echo empty($ftp)?'data-toggle="tooltip" data-placement="right" title="'._backupGuardT('FTP is not active.',true).'"':''?>>
75
+ <input type="checkbox" name="backupStorages[]" id="cloud-ftp" value="<?php echo SG_STORAGE_FTP ?>" <?php echo empty($ftp)?'disabled="disabled"':''?>>
76
+ <?php echo 'FTP' ?>
77
+ </label>
78
+ </div>
79
+ <?php endif; ?>
80
+ <?php if(SGBoot::isFeatureAvailable('DROPBOX')): ?>
81
+ <div class="checkbox">
82
+ <label for="cloud-dropbox" <?php echo empty($dropbox)?'data-toggle="tooltip" data-placement="right" title="'._backupGuardT('Dropbox is not active.',true).'"':''?>>
83
+ <input type="checkbox" name="backupStorages[]" id="cloud-dropbox" value="<?php echo SG_STORAGE_DROPBOX ?>"
84
+ <?php echo empty($dropbox)?'disabled="disabled"':''?>>
85
+ <?php echo 'Dropbox' ?>
86
+ </label>
87
+ </div>
88
+ <?php endif; ?>
89
+ <?php if(SGBoot::isFeatureAvailable('GOOGLE_DRIVE')): ?>
90
+ <div class="checkbox">
91
+ <label for="cloud-gdrive" <?php echo empty($gdrive)?'data-toggle="tooltip" data-placement="right" title="'._backupGuardT('Google Drive is not active.',true).'"':''?>>
92
+ <input type="checkbox" name="backupStorages[]" id="cloud-gdrive" value="<?php echo SG_STORAGE_GOOGLE_DRIVE?>"
93
+ <?php echo empty($gdrive)?'disabled="disabled"':''?>>
94
+ <?php echo 'Google Drive' ?>
95
+ </label>
96
+ </div>
97
+ <?php endif; ?>
98
+ <?php if(SGBoot::isFeatureAvailable('AMAZON')): ?>
99
+ <div class="checkbox">
100
+ <label for="cloud-amazon" <?php echo empty($amazon)?'data-toggle="tooltip" data-placement="right" title="'._backupGuardT((backupGuardIsAccountGold()? 'Amazon ':'').'S3 is not active.',true).'"':''?>>
101
+ <input type="checkbox" name="backupStorages[]" id="cloud-amazon" value="<?php echo SG_STORAGE_AMAZON?>"
102
+ <?php echo empty($amazon)?'disabled="disabled"':''?>>
103
+ <?php echo (backupGuardIsAccountGold()? 'Amazon ':'').'S3' ?>
104
+ </label>
105
+ </div>
106
+ <?php endif; ?>
107
+ <?php if(SGBoot::isFeatureAvailable('ONE_DRIVE')): ?>
108
+ <div class="checkbox">
109
+ <label for="cloud-one-drive" <?php echo empty($oneDrive)?'data-toggle="tooltip" data-placement="right" title="'._backupGuardT('One Drive is not active.', true).'"':''?>>
110
+ <input type="checkbox" name="backupStorages[]" id="cloud-one-drive" value="<?php echo SG_STORAGE_ONE_DRIVE?>" <?php echo empty($oneDrive)?'disabled="disabled"':''?>>
111
+ <?php echo 'One Drive' ?>
112
+ </label>
113
+ </div>
114
+ <?php endif;?>
115
+ </div>
116
+ <div class="clearfix"></div>
117
+ </div>
118
+ <?php endif; ?>
119
+ <!-- Background mode -->
120
+ <?php if(SGBoot::isFeatureAvailable('BACKGROUND_MODE')): ?>
121
+ <div class="checkbox">
122
+ <label for="background-chbx">
123
+ <input type="checkbox" name="backgroundMode" id="background-chbx">
124
+ <?php _backupGuardT('Background mode'); ?>
125
+ </label>
126
+ </div>
127
+ <?php endif; ?>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ <div class="modal-footer">
132
+ <input type="text" name="backup-type" value="<?php echo $backupType?>" hidden>
133
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
134
+ <button type="button" onclick="sgBackup.manualBackup()" class="btn btn-primary"><?php _backupGuardT('Backup')?></button>
135
+ </div>
136
+ </form>
137
+ </div>
138
+ </div>
public/ajax/modalManualRestore.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_LIB_PATH.'SGArchive.php');
4
+ $backupName = $_GET['param'];
5
+ $backupPath = SG_BACKUP_DIRECTORY.$backupName;
6
+ $backupPath= $backupPath.'/'.$backupName.'.sgbp';
7
+ $archive = new SGArchive($backupPath,'r');
8
+ $headers = $archive->getArchiveHeaders();
9
+ if($headers["selectivRestoreable"]){
10
+ ?>
11
+ <div class="modal-dialog">
12
+ <div class="modal-content">
13
+ <div class="modal-header">
14
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
15
+ <h4 class="modal-title"><?php _backupGuardT("Manual Restore") ?></h4>
16
+ </div>
17
+ <form class="form-horizontal" method="post" id="manualBackup">
18
+ <div class="modal-body sg-modal-body">
19
+ <!-- Multiple Radios -->
20
+ <div class="form-group">
21
+ <div class="col-md-12">
22
+ <div class="radio">
23
+ <label for="fullrestore-radio">
24
+ <input type="radio" name="restoreType" id="fullrestore-radio" value="<?php echo SG_RESTORE_MODE_FULL ?>" checked="checked">
25
+ <?php _backupGuardT('Full restore'); ?>
26
+ </label>
27
+ </div>
28
+ <div class="radio">
29
+ <label for="filerestore-radio">
30
+ <input type="radio" name="restoreType" id="filerestore-radio" value="<?php echo SG_RESTORE_MODE_FILES ?>">
31
+ <?php _backupGuardT('Restore files'); ?>
32
+ </label>
33
+ </div>
34
+ <?php if (SGBoot::isFeatureAvailable('SLECTIVE_RESTORE')): ?>
35
+ <?php backupGuardGetFileSelectiveRestore(); ?>
36
+ <?php endif; ?>
37
+ <div class="radio">
38
+ <label for="dbrestore-radio">
39
+ <input type="radio" name="restoreType" id="dbrestore-radio" value="<?php echo SG_RESTORE_MODE_DB ?>">
40
+ <?php _backupGuardT('Restore DB'); ?>
41
+ </label>
42
+ </div>
43
+
44
+ </div>
45
+ </div>
46
+ </div>
47
+ <div class="modal-footer">
48
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
49
+ <button type="button" onclick="sgBackup.startRestore('<?php echo $backupName ?>')" class="btn btn-primary"><?php _backupGuardT('Restore')?></button>
50
+ </div>
51
+ </form>
52
+ </div>
53
+ </div>
54
+ <?php
55
+ }else{
56
+ ?>
57
+ <div class="modal-dialog">
58
+ <div class="modal-content">
59
+ <div class="modal-header">
60
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
61
+ <h4 class="modal-title"><?php _backupGuardT("Are you sure?") ?></h4>
62
+ </div>
63
+ <div class="modal-footer">
64
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
65
+ <button type="button" onclick="sgBackup.startRestore('<?php echo $backupName ?>')" class="btn btn-primary"><?php _backupGuardT('Restore')?></button>
66
+ </div>
67
+ </div>
68
+ </div>
69
+ <?php
70
+ }
71
+
72
+
public/ajax/modalPrivacy.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ ?>
4
+ <div class="modal-dialog">
5
+ <div class="modal-content">
6
+ <div class="modal-header">
7
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
8
+ <h4 class="modal-title"><?php _backupGuardT('Privacy Policy')?></h4>
9
+ </div>
10
+ <div class="modal-body sg-modal-body">
11
+ <div class="col-md-12">
12
+ <div class="form-group sg-justify">
13
+ <p><?php _backupGuardT('Your privacy is very important to us. Accordingly, we have developed this Policy in order for you to understand how we collect, use, communicate and disclose and make use of personal information. The following outlines our privacy policy.')?></p>
14
+ <ul style="list-style-type: disc;">
15
+ <li><?php _backupGuardT('Before or at the time of collecting personal information, we will identify the purposes for which information is being collected.')?></li>
16
+ <li><?php _backupGuardT('We will collect and use of personal information solely with the objective of fulfilling those purposes specified by us and for other compatible purposes, unless we obtain the consent of the individual concerned or as required by law.')?></li>
17
+ <li><?php _backupGuardT('We will only retain personal information as long as necessary for the fulfillment of those purposes.')?></li>
18
+ <li><?php _backupGuardT('We will collect personal information by lawful and fair means and, where appropriate, with the knowledge or consent of the individual concerned.')?></li>
19
+ <li><?php _backupGuardT('Personal data should be relevant to the purposes for which it is to be used, and, to the extent necessary for those purposes, should be accurate, complete, and up-to-date.')?></li>
20
+ <li><?php _backupGuardT('We will protect personal information by reasonable security safeguards against loss or theft, as well as unauthorized access, disclosure, copying, use or modification.')?></li>
21
+ <li><?php _backupGuardT('We will make readily available to customers information about our policies and practices relating to the management of personal information.')?></li>
22
+ </ul>
23
+ <p><?php _backupGuardT('We are committed to conducting our business in accordance with these principles in order to ensure that the confidentiality of personal information is protected and maintained.')?></p>
24
+ </div>
25
+ </div>
26
+ <div class="clearfix"></div>
27
+ </div>
28
+ <div class="modal-footer">
29
+ <button type="button" data-dismiss="modal" class="btn btn-primary"><?php _backupGuardT('Ok')?></button>
30
+ </div>
31
+ </div>
32
+ </div>
public/ajax/modalReview.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ ?>
4
+ <div class="modal-dialog">
5
+ <div class="modal-content">
6
+ <div class="modal-header">
7
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
8
+ <h4 class="modal-title"><?php _backupGuardT('Leave a Review')?></h4>
9
+ </div>
10
+ <div class="modal-body sg-modal-body">
11
+ <div class="col-md-12">
12
+ <div class="sg-justify">
13
+ <p><?php _backupGuardT('If you have some time and appreciated our product, please leave us a review by clicking on the "Leave a review" button below.')?></p>
14
+ <p class="text-center sg-no-margin-bottom">
15
+ <i class="glyphicon glyphicon-star sg-star"></i>
16
+ <i class="glyphicon glyphicon-star sg-star"></i>
17
+ <i class="glyphicon glyphicon-star sg-star"></i>
18
+ <i class="glyphicon glyphicon-star sg-star"></i>
19
+ <i class="glyphicon glyphicon-star sg-star"></i>
20
+ </p>
21
+ </div>
22
+ </div>
23
+ <div class="clearfix"></div>
24
+ </div>
25
+ <div class="modal-footer">
26
+ <button type="button" data-dismiss="modal" id="sgDontAskAgain" class="btn sg-btn-grey"><?php _backupGuardT('Don\'t ask again')?></button>
27
+ <button type="button" data-dismiss="modal" id="sgAskLater" class="btn sg-btn-grey"><?php _backupGuardT('Ask me later')?></button>
28
+ <button type="button" data-dismiss="modal" id="sgLeaveReview" class="btn btn-success" data-review-url="<?php echo SG_BACKUP_GUARD_REVIEW_URL; ?>"><?php _backupGuardT('Leave a review')?></button>
29
+ </div>
30
+ </div>
31
+ </div>
public/ajax/modalTerms.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ ?>
4
+ <div class="modal-dialog">
5
+ <div class="modal-content">
6
+ <div class="modal-header">
7
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
8
+ <h4 class="modal-title"><?php _backupGuardT('Terms & Conditions')?></h4>
9
+ </div>
10
+ <div class="modal-body sg-modal-body">
11
+ <div class="col-md-12">
12
+ <div class="form-group sg-justify">
13
+ <p>1. <?php _backupGuardT('Terms')?></p>
14
+ <p><?php _backupGuardT('By using this software, you are agreeing to be bound by these software Terms and Conditions of Use, all applicable laws and regulations, and agree that you are responsible for compliance with any applicable local laws. If you do not agree with any of these terms, you are prohibited from using this software. The materials contained in this software are protected by applicable copyright and trade mark law.')?></p><br/>
15
+ <p>2. <?php _backupGuardT('Disclaimer')?></p>
16
+ <p><?php _backupGuardT("The materials on BackupGuard's are provided")?> &quot;<?php _backupGuardT('as is')?>&quot;. <?php _backupGuardT('BackupGuard makes no warranties, expressed or implied, and hereby disclaims and negates all other warranties, including without limitation, implied warranties or conditions of merchantability, fitness for a particular purpose, or non-infringement of intellectual property or other violation of rights. Further, BackupGuard does not warrant or make any representations concerning the accuracy, likely results, or reliability of the use of the materials on its Software.')?></p><br/>
17
+ <p>3. <?php _backupGuardT('Limitations')?></p>
18
+ <p><?php _backupGuardT("In no event shall BackupGuard or its suppliers be liable for any damages (including, without limitation, damages for loss of data or profit, or due to business interruption,) arising out of the use or inability to use the materials on BackupGuard's software, even if BackupGuard or a BackupGuard authorized representative has been notified orally or in writing of the possibility of such damage. Because some jurisdictions do not allow limitations on implied warranties, or limitations of liability for consequential or incidental damages, these limitations may not apply to you.")?></p><br/>
19
+ <p>4. <?php _backupGuardT('Revisions and Errata')?></p>
20
+ <p><?php _backupGuardT("The materials appearing on BackupGuard's software could include technical, typographical, or photographic errors. BackupGuard does not warrant that any of the materials on its software are accurate, complete, or current. BackupGuard may make changes to the materials contained on its software at any time without notice. BackupGuard does not, however, make any commitment to update the materials.")?></p><br/>
21
+ <p>5. <?php _backupGuardT('Terms of Use Modifications')?></p>
22
+ <p><?php _backupGuardT('BackupGuard may revise these terms of use for its software at any time without notice. By using this software you are agreeing to be bound by the then current version of these Terms and Conditions of Use.')?></p>
23
+ </div>
24
+ </div>
25
+ <div class="clearfix"></div>
26
+ </div>
27
+ <div class="modal-footer">
28
+ <button type="button" data-dismiss="modal" class="btn btn-primary"><?php _backupGuardT('Ok')?></button>
29
+ </div>
30
+ </div>
31
+ </div>
public/ajax/resetStatus.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+
5
+ if(backupGuardIsAjax() && count($_POST)) {
6
+ $error = array();
7
+ try {
8
+
9
+ if (isset($_POST['backupName']) && $_POST['backupName']) {
10
+ if (file_exists(SG_BACKUP_DIRECTORY.$_POST['backupName'])) {
11
+ throw new SGExceptionForbidden($_POST['backupName']." backup already exists");
12
+ }
13
+ }
14
+
15
+ @unlink(SG_BACKUP_DIRECTORY.'sg_backup.state');
16
+ SGConfig::set('SG_RUNNING_ACTION', 0, true);
17
+ $key = md5(microtime(true));
18
+ SGConfig::set('SG_BACKUP_CURRENT_KEY', $key, true);
19
+ die('{"success":1}');
20
+ }
21
+ catch(SGException $exception) {
22
+ array_push($error, $exception->getMessage());
23
+ die(json_encode($error));
24
+ }
25
+ }
public/ajax/restore.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+ if(backupGuardIsAjax() && count($_POST)) {
5
+ $error = array();
6
+ try {
7
+ //Getting Backup Name
8
+ $backupName = $_POST['bname'];
9
+ $restoreMode = isset($_POST['type'])? $_POST['type'] : SG_RESTORE_MODE_FULL; //if type is not set that means it is an old backup and no selective restore is available. only full
10
+
11
+ if (!SGBoot::isFeatureAvailable('SLECTIVE_RESTORE')) {
12
+ $restoreMode = SG_RESTORE_MODE_FULL;
13
+ }
14
+
15
+ $restoreFiles = isset($_POST['paths']) ? $_POST['paths'] : array();
16
+ $backup = new SGBackup();
17
+ $backup->restore($backupName, $restoreMode, $restoreFiles);
18
+ }
19
+ catch(SGException $exception) {
20
+ array_push($error, $exception->getMessage());
21
+ die(json_encode($error));
22
+ }
23
+ }
public/ajax/schedule.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackupSchedule.php');
4
+
5
+ $error = array();
6
+ $success = array('success'=>1);
7
+
8
+ if(backupGuardIsAjax() && count($_POST)) {
9
+ $_POST = backupGuardRemoveSlashes($_POST);
10
+
11
+ if (isset($_POST['remove'])) {
12
+ if(isset($_POST['id'])) {
13
+ SGBackupSchedule::remove((int)$_POST['id']);
14
+ }
15
+ else {
16
+ SGBackupSchedule::remove();
17
+ }
18
+
19
+ die(json_encode($success));
20
+ }
21
+
22
+ //Check if cron available
23
+ if(!SGSchedule::isCronAvailable()) {
24
+ array_push($error, _backupGuardT('Cron is not available on your hosting.',true));
25
+ die(json_encode($error));
26
+ }
27
+
28
+ $options = $_POST;
29
+ $cronOptions = array(
30
+ 'SG_BACKUP_IN_BACKGROUND_MODE' => 0,
31
+ 'SG_BACKUP_UPLOAD_TO_STORAGES' => '',
32
+ 'SG_ACTION_BACKUP_DATABASE_AVAILABLE' => 0,
33
+ 'SG_ACTION_BACKUP_FILES_AVAILABLE' => '',
34
+ 'SG_BACKUP_FILE_PATHS_EXCLUDE' => '',
35
+ 'SG_BACKUP_FILE_PATHS' => '',
36
+ );
37
+
38
+ $cronLabel = '';
39
+ //Check if schedule name is not empaty
40
+ if (isset($options['sg-schedule-label'])) {
41
+ $label = trim($options['sg-schedule-label']);
42
+ $label = backupGuardSanitizeTextField($label);
43
+ if (empty($label)) {
44
+ array_push($error, _backupGuardT('Label field is required.',true));
45
+ die(json_encode($error));
46
+ }
47
+ else {
48
+ $cronLabel = $label;
49
+ }
50
+ }
51
+ else {
52
+ array_push($error, _backupGuardT('Label field is required.',true));
53
+ die(json_encode($error));
54
+ }
55
+
56
+ //If background mode
57
+ $isBackgroundMode = isset($options['backgroundMode'])?1:0;
58
+ $cronOptions['SG_BACKUP_IN_BACKGROUND_MODE'] = $isBackgroundMode;
59
+
60
+ //If cloud backup
61
+ if(isset($options['backupCloud']) && count($options['backupStorages'])) {
62
+ $clouds = backupGuardSanitizeTextField($options['backupStorages']);
63
+ $cronOptions['SG_BACKUP_UPLOAD_TO_STORAGES'] = implode(',', $clouds);
64
+ }
65
+
66
+ $cronOptions['SG_BACKUP_TYPE'] = $options['backupType'];
67
+
68
+ if ($options['backupType'] == SG_BACKUP_TYPE_FULL) {
69
+ $cronOptions['SG_BACKUP_FILE_PATHS_EXCLUDE'] = SG_BACKUP_FILE_PATHS_EXCLUDE;
70
+ $cronOptions['SG_BACKUP_FILE_PATHS'] = 'wp-content';
71
+ $cronOptions['SG_ACTION_BACKUP_DATABASE_AVAILABLE'] = 1;
72
+ $cronOptions['SG_ACTION_BACKUP_FILES_AVAILABLE'] = 1;
73
+ }
74
+ else if ($options['backupType'] == SG_BACKUP_TYPE_CUSTOM) {
75
+ //If database backup
76
+ $isDatabaseBackup = isset($options['backupDatabase'])?1:0;
77
+ $cronOptions['SG_ACTION_BACKUP_DATABASE_AVAILABLE'] = $isDatabaseBackup;
78
+
79
+ //If db backup
80
+ if($options['backupDBType']){
81
+ $tablesToBackup = implode(',', $options['table']);
82
+ $backupOptions['SG_BACKUP_TABLES_TO_BACKUP'] = $tablesToBackup;
83
+ }
84
+ //If files backup
85
+ if(isset($options['backupFiles']) && count($options['directory'])) {
86
+ $backupFiles = explode(',', SG_BACKUP_FILE_PATHS);
87
+ $options['directory'] = backupGuardSanitizeTextField($options['directory']);
88
+ $filesToExclude = @array_diff($backupFiles, $options['directory']);
89
+
90
+ if (in_array('wp-content', $options['directory'])) {
91
+ $options['directory'] = array('wp-content');
92
+ }
93
+ else {
94
+ $filesToExclude = array_diff($filesToExclude, array('wp-content'));
95
+ }
96
+
97
+ $filesToExclude = implode(',', $filesToExclude);
98
+ if (strlen($filesToExclude)) {
99
+ $filesToExclude = ','.$filesToExclude;
100
+ }
101
+
102
+ $cronOptions['SG_BACKUP_FILE_PATHS_EXCLUDE'] = SG_BACKUP_FILE_PATHS_EXCLUDE.$filesToExclude;
103
+ $cronOptions['SG_ACTION_BACKUP_FILES_AVAILABLE'] = 1;
104
+ $cronOptions['SG_BACKUP_FILE_PATHS'] = implode(',', $options['directory']);
105
+ }
106
+ else {
107
+ $cronOptions['SG_ACTION_BACKUP_FILES_AVAILABLE'] = 0;
108
+ $cronOptions['SG_BACKUP_FILE_PATHS'] = 0;
109
+ }
110
+ }
111
+ else {
112
+ array_push($error, _backupGuardT('Invalid backup type', true));
113
+ die(json_encode($error));
114
+ }
115
+
116
+ $scheduleIntervalDay = '';
117
+ if ($options['scheduleInterval'] == BG_SCHEDULE_INTERVAL_WEEKLY && isset($options['sg-schedule-day-of-week'])) {
118
+ $scheduleIntervalDay = (int)$options['sg-schedule-day-of-week'];
119
+ }
120
+ else if($options['scheduleInterval'] == BG_SCHEDULE_INTERVAL_MONTHLY && isset($options['sg-schedule-day-of-month'])) {
121
+ $scheduleIntervalDay = (int)$options['sg-schedule-day-of-month'];
122
+ }
123
+
124
+ try {
125
+ $cronTab = array(
126
+ 'dayOfInterval' => $scheduleIntervalDay,
127
+ 'intervalHour' => $options['scheduleHour'],
128
+ 'interval' => $options['scheduleInterval']
129
+ );
130
+
131
+ if (isset($options['sg-schedule-id'])) {
132
+ SGBackupSchedule::remove($options['sg-schedule-id']);
133
+ }
134
+
135
+ SGBackupSchedule::create($cronTab, $cronOptions, $cronLabel);
136
+
137
+ die(json_encode($success));
138
+ }
139
+ catch(SGException $exception) {
140
+ array_push($error, $exception->getMessage());
141
+ die(json_encode($error));
142
+ }
143
+ }
public/ajax/setReviewPopupState.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ if(backupGuardIsAjax() && count($_POST))
4
+ {
5
+ $state = (int)$_POST['reviewState'];
6
+ SGConfig::set('SG_REVIEW_POPUP_STATE', $state);
7
+ die('0');
8
+ }
public/ajax/setUserInfoVerificationPopupState.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/../boot.php');
4
+ require_once(SG_LIB_PATH.'BackupGuard/Client.php');
5
+
6
+ if(backupGuardIsAjax() && count($_POST)) {
7
+
8
+ $url = 'none';
9
+ $firstName = 'none';
10
+ $lastName = 'none';
11
+ $email = 'none';
12
+ $priority = 'none';
13
+
14
+ $client = new BackupGuard\Client();
15
+ $id = $client->storeSubscriberInfo($url, $firstName, $lastName, $email, $priority);
16
+
17
+ SGConfig::set('SG_HIDE_VERIFICATION_POPUP_STATE', 1);
18
+ die('0');
19
+ }
public/ajax/settings.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ $error = array();
4
+ $success = array('success'=>1);
5
+
6
+ if (backupGuardIsAjax() && isset($_POST['cancel'])) {
7
+ SGConfig::set('SG_NOTIFICATIONS_ENABLED', '0');
8
+ SGConfig::set('SG_NOTIFICATIONS_EMAIL_ADDRESS', '');
9
+
10
+ die(json_encode($success));
11
+ }
12
+
13
+ if (backupGuardIsAjax() && count($_POST)) {
14
+ $_POST = backupGuardRemoveSlashes($_POST);
15
+ $_POST = backupGuardSanitizeTextField($_POST);
16
+
17
+ $amountOfBackupsToKeep = (int)@$_POST['amount-of-backups-to-keep'];
18
+ if ($amountOfBackupsToKeep <= 0) {
19
+ $amountOfBackupsToKeep = SG_NUMBER_OF_BACKUPS_TO_KEEP;
20
+ }
21
+ SGConfig::set('SG_AMOUNT_OF_BACKUPS_TO_KEEP', $amountOfBackupsToKeep);
22
+
23
+ SGConfig::set('SG_NOTIFICATIONS_ENABLED', '0');
24
+ $emails = '';
25
+ if (isset($_POST['sgIsEmailNotification'])) {
26
+ $emails = @$_POST['sgUserEmail'];
27
+ $emailsArray = explode(',', $emails);
28
+
29
+ if (empty($emails)) {
30
+ array_push($error, _backupGuardT('Email is required.', true));
31
+ }
32
+
33
+ foreach ($emailsArray as $email) {
34
+ $email = trim($email);
35
+ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
36
+ array_push($error, _backupGuardT('Invalid email address.', true));
37
+ }
38
+ }
39
+
40
+ SGConfig::set('SG_NOTIFICATIONS_ENABLED', '1');
41
+ }
42
+ $ajaxInterval = (int)$_POST['ajaxInterval'];
43
+
44
+ if (count($error)) {
45
+ die(json_decode($error));
46
+ }
47
+
48
+ if (isset($_POST['sg-hide-ads'])) {
49
+ SGConfig::set('SG_DISABLE_ADS', '1');
50
+ }
51
+ else {
52
+ SGConfig::set('SG_DISABLE_ADS', '0');
53
+ }
54
+
55
+ if (isset($_POST['sg-background-reload-method'])) {
56
+ SGConfig::set('SG_BACKGROUND_RELOAD_METHOD', (int)$_POST['sg-background-reload-method']);
57
+ }
58
+ else {
59
+ SGConfig::set('SG_BACKGROUND_RELOAD_METHOD', SG_RELOAD_METHOD_CURL);
60
+ }
61
+
62
+ if (isset($_POST['delete-backup-after-upload'])) {
63
+ SGConfig::set('SG_DELETE_BACKUP_AFTER_UPLOAD', '1');
64
+ }
65
+ else {
66
+ SGConfig::set('SG_DELETE_BACKUP_AFTER_UPLOAD', '0');
67
+ }
68
+
69
+ if (isset($_POST['delete-backup-from-cloud'])) {
70
+ SGConfig::set('SG_DELETE_BACKUP_FROM_CLOUD', '1');
71
+ }
72
+ else {
73
+ SGConfig::set('SG_DELETE_BACKUP_FROM_CLOUD', '0');
74
+ }
75
+
76
+ if (isset($_POST['alert-before-update'])) {
77
+ SGConfig::set('SG_ALERT_BEFORE_UPDATE', '1');
78
+ }
79
+ else {
80
+ SGConfig::set('SG_ALERT_BEFORE_UPDATE', '0');
81
+ }
82
+
83
+ if (isset($_POST['show-statistics-widget'])) {
84
+ SGConfig::set('SG_SHOW_STATISTICS_WIDGET', '1');
85
+
86
+ }
87
+ else {
88
+ SGConfig::set('SG_SHOW_STATISTICS_WIDGET', '0');
89
+ }
90
+
91
+ if (isset($_POST['ftp-passive-mode'])) {
92
+ SGConfig::set('SG_FTP_PASSIVE_MODE', '1');
93
+ }
94
+ else {
95
+ SGConfig::set('SG_FTP_PASSIVE_MODE', '0');
96
+ }
97
+
98
+ if (isset($_POST['sg-number-of-rows-to-backup'])) {
99
+ SGConfig::set('SG_BACKUP_DATABASE_INSERT_LIMIT', (int)$_POST['sg-number-of-rows-to-backup']);
100
+ }
101
+ else {
102
+ SGConfig::set('SG_BACKUP_DATABASE_INSERT_LIMIT', SG_BACKUP_DATABASE_INSERT_LIMIT);
103
+ }
104
+
105
+ $backupFileName = 'sg_backup_';
106
+ if (isset($_POST['backup-file-name'])) {
107
+ $backupFileName = $_POST['backup-file-name'];
108
+ }
109
+
110
+ $isReloadingsEnabled = 0;
111
+ if (isset($_POST['backup-with-reloadings'])) {
112
+ $isReloadingsEnabled = 1;
113
+ }
114
+
115
+ if (isset($_POST['sg-paths-to-exclude'])) {
116
+ SGConfig::set('SG_PATHS_TO_EXCLUDE', $_POST['sg-paths-to-exclude']);
117
+ }
118
+ else {
119
+ SGConfig::set('SG_PATHS_TO_EXCLUDE', '');
120
+ }
121
+
122
+ if (isset($_POST['sg-tables-to-exclude'])) {
123
+ SGConfig::set('SG_TABLES_TO_EXCLUDE', $_POST['sg-tables-to-exclude']);
124
+ }
125
+ else {
126
+ SGConfig::set('SG_TABLES_TO_EXCLUDE', '');
127
+ }
128
+
129
+ SGConfig::set('SG_BACKUP_WITH_RELOADINGS', $isReloadingsEnabled);
130
+ SGConfig::set('SG_BACKUP_FILE_NAME_PREFIX', $backupFileName);
131
+ SGConfig::set('SG_AJAX_REQUEST_FREQUENCY', $ajaxInterval);
132
+ SGConfig::set('SG_NOTIFICATIONS_EMAIL_ADDRESS', $emails);
133
+ die(json_encode($success));
134
+ }
135
+
136
+ if (backupGuardIsAjax() && $_SERVER['REQUEST_METHOD'] === 'GET') {
137
+ if ($_GET["type"] == "updateSetting") {
138
+ //disable alert-before-update from updates page
139
+ if (isset($_GET["alert-before-update"])) {
140
+ SGConfig::set('SG_ALERT_BEFORE_UPDATE', $_GET["alert-before-update"]);
141
+ }
142
+ }
143
+ }
public/ajax/storeSubscriberInfo.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/../boot.php');
4
+ require_once(SG_LIB_PATH.'BackupGuard/Client.php');
5
+
6
+ if(backupGuardIsAjax() && count($_POST)) {
7
+ $_POST = backupGuardRemoveSlashes($_POST);
8
+ $_POST = backupGuardSanitizeTextField($_POST);
9
+
10
+ $error = '';
11
+ $firstName = $_POST['fname'];
12
+ $lastName = $_POST['lname'];
13
+ $email = $_POST['email'];
14
+ $priority = $_POST['priority'];
15
+ $url = site_url();
16
+
17
+ $client = new BackupGuard\Client();
18
+ $id = $client->storeSubscriberInfo($url, $firstName, $lastName, $email, $priority);
19
+
20
+ if ($id) {
21
+ SGConfig::set('SG_HIDE_VERIFICATION_POPUP_STATE', 1);
22
+ die('0');
23
+ }
24
+
25
+ die('"'.$error.'"');
26
+ }
public/ajax/storeSurveyResult.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/../boot.php');
4
+ require_once(SG_LIB_PATH.'BackupGuard/Client.php');
5
+
6
+ if(backupGuardIsAjax() && count($_POST)) {
7
+ $_POST = backupGuardRemoveSlashes($_POST);
8
+ $_POST = backupGuardSanitizeTextField($_POST);
9
+
10
+ $error = '';
11
+
12
+ if (isset($_POST['skip'])) {
13
+ $firstname = 'skip';
14
+ $lastname = 'skip';
15
+ $email = 'skip';
16
+ $response = 'skip';
17
+ $url = site_url();
18
+ }
19
+ else {
20
+ $firstname = $_POST['firstname'];
21
+ $lastname = $_POST['lastname'];
22
+ $email = $_POST['email'];
23
+ $response = $_POST['response'];
24
+ $url = site_url();
25
+ }
26
+
27
+ $client = new BackupGuard\Client();
28
+ $id = $client->storeSurveyResult($url, $firstname, $lastname, $email, $response);
29
+
30
+ if ($id) {
31
+ die('{"success":"success"}');
32
+ }
33
+
34
+ die('"'.$error.'"');
35
+ }
public/backups.php ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+ require_once(SG_PUBLIC_INCLUDE_PATH.'header.php');
5
+ require_once(SG_PUBLIC_INCLUDE_PATH.'sidebar.php');
6
+ $backups = SGBackup::getAllBackups();
7
+ $pluginCapabilities = backupGuardGetCapabilities();
8
+ $downloadUrl = admin_url('admin-post.php?action=backup_guard_downloadBackup&');
9
+ ?>
10
+ <?php if(SGConfig::get('SG_REVIEW_POPUP_STATE') == SG_SHOW_REVIEW_POPUP): ?>
11
+ <!-- Review Box -->
12
+ <a href="javascript:void(0)" id="sg-review" class="hidden" data-toggle="modal" data-modal-name="manual-review" data-remote="modalReview"></a>
13
+ <script type="text/javascript">sgShowReview = 1;</script>
14
+ <?php endif; ?>
15
+ <?php if(!SGConfig::get('SG_HIDE_VERIFICATION_POPUP_STATE') && ($pluginCapabilities == BACKUP_GUARD_CAPABILITIES_FREE)): ?>
16
+ <div id="bg-verify-user-info-container" class="bg-verify-user-info-container">
17
+ <div class="bg-verify-user-info-overlay"></div>
18
+ <div class="bg-verify-user-info-popup-tbl">
19
+ <div class="bg-verify-user-info-popup-cel">
20
+ <div class="bg-verify-user-info-popup-content">
21
+ <a href="javascript:void(0)" class="bg-verify-user-info-cancel"><img src="<?php echo SG_IMAGE_URL.'close.png' ?>" class="wp_fm_loader" /></a>
22
+ <div class="bg-verify-user-info-popup-inner-content">
23
+ <h3><?php _backupGuardT('Let us be more helpful!'); ?></h3>
24
+ <p class="bg-verify-user-info-desc">
25
+ <?php _backupGuardT('Tell us about your primary needs and be aware of our news and updates.'); ?>
26
+ </p>
27
+ <form>
28
+ <div class="bg-verify-user-info-form-group">
29
+ <div class="bg-verify-user-info-form-twocol">
30
+ <input name="bg-verify-user-info-name" id="bg-verify-user-info-name" class="regular-text" type="text" value="" placeholder="First Name" />
31
+ <span id="bg-verify-user-info-name-error" class="bg-verify-user-info-error-message"><?php _backupGuardT('Please Enter First Name.'); ?></span>
32
+ </div>
33
+ <div class="bg-verify-user-info-form-twocol">
34
+ <input name="bg-verify-user-info-last-name" id="bg-verify-user-info-last-name" class="regular-text" type="text" value="" placeholder="Last Name" />
35
+ <span id="bg-verify-user-info-last-name-error" class="bg-verify-user-info-error-message"><?php _backupGuardT('Please Enter Last Name.'); ?></span>
36
+ </div>
37
+ </div>
38
+ <div class="bg-verify-user-info-form-group">
39
+ <div class="bg-verify-user-info-form-onecol">
40
+ <input name="bg-verify-user-info-email" id="bg-verify-user-info-email" class="regular-text" type="text" value="" placeholder="Email Address" />
41
+ <span id="bg-verify-user-info-email-error" class="bg-verify-user-info-error-message"><?php _backupGuardT('Please Enter Valid Email Address.'); ?></span>
42
+ </div>
43
+ </div>
44
+ <div class="bg-verify-user-info-form-group">
45
+ <div class="bg-verify-user-info-form-onecol">
46
+ <select name="bg-verify-user-prioraty" id="bg-verify-user-prioraty">
47
+ <option value=""><?php _backupGuardT('Please Select Your Priority') ?></option>
48
+ <option value="local backup"><?php _backupGuardT('Local Backup') ?></option>
49
+ <option value="cloud backup"><?php _backupGuardT('Cloud Backup') ?></option>
50
+ <option value="scheduling"><?php _backupGuardT('Scheduling') ?></option>
51
+ <option value="migration"><?php _backupGuardT('Migration') ?></option>
52
+ <option value="other"><?php _backupGuardT('Other') ?></option>
53
+ </select>
54
+ <span id="bg-verify-user-info-priority-error" class="bg-verify-user-info-error-message"><?php _backupGuardT('Please Select Your Priority.'); ?></span>
55
+ </div>
56
+ </div>
57
+ <div class="bg-verify-user-info-form-group">
58
+ <div class="bg-verify-user-info-form-onecol">
59
+ <input name="bg-verify-user-priorati-custom" id="bg-verify-user-priorati-custom" class="regular-text" type="text" placeholder="<?php _backupGuardT('Please select your priority.') ?>" hidden>
60
+ <span id="bg-verify-user-info-priority-custom-error" class="bg-verify-user-info-error-message"><?php _backupGuardT('Please Enter Your Priority.'); ?></span>
61
+ </div>
62
+ </div>
63
+ <div class="bg-verify-user-info-control-buttons-container">
64
+ <button class="bg-verify-user-info-verify-email button button-primary"><?php _backupGuardT("Subscribe") ?></button>
65
+ </div>
66
+ </form>
67
+ </div>
68
+ <div class="bg-privacy-links-container">
69
+ <a href="<?php echo BACKUP_GUARD_TERMS_OF_SERVICE_URL ?>" target="_blank"><?php _backupGuardT('Terms of Service'); ?></a>
70
+ <a href="<?php echo BACKUP_GUARD_PRIVACY_POLICY_URL ?>" target="_blank"><?php _backupGuardT('Privacy Policy'); ?></a>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </div>
76
+
77
+ <?php endif; ?>
78
+ <div id="sg-content-wrapper">
79
+ <div class="container-fluid">
80
+ <fieldset>
81
+ <legend><?php _backupGuardT('Backups')?><?php echo backupGuardLoggedMessage(); ?></legend>
82
+
83
+ <a href="javascript:void(0)" id="sg-manual-backup" class="pull-left btn btn-success" data-toggle="modal" data-modal-name="manual-backup" data-remote="modalManualBackup" sg-data-backup-type="<?php echo SG_BACKUP_METHOD_STANDARD ?>"><i class="glyphicon glyphicon-play"></i> <?php _backupGuardT('Backup')?></a>
84
+
85
+ <a href="javascript:void(0)" id="sg-backup-with-migration" class="pull-left btn btn-primary" data-toggle="modal" data-modal-name="manual-backup" data-remote="modalManualBackup" sg-data-backup-type="<?php echo SG_BACKUP_METHOD_MIGRATE ?>"<?php echo SGBoot::isFeatureAvailable('BACKUP_WITH_MIGRATION')?'':'disabled' ?>>
86
+ <i class="glyphicon glyphicon-duplicate"></i>
87
+ <?php _backupGuardT('Migrate')?>
88
+ </a>
89
+
90
+ <a href="javascript:void(0)" id="sg-import" class="pull-right btn btn-primary" data-toggle="modal" data-modal-name="import" data-remote="modalImport"><i class="glyphicon glyphicon-open"></i> <?php _backupGuardT('Import')?></a>
91
+
92
+ <div class="clearfix"></div><br/>
93
+ <table class="table table-striped paginated sg-backup-table">
94
+ <thead>
95
+ <tr>
96
+ <th><input type="checkbox" id="sg-checkbox-select-all" autocomplete="off"></th>
97
+ <th><?php _backupGuardT('Filename')?></th>
98
+ <th><?php _backupGuardT('Size')?></th>
99
+ <th><?php _backupGuardT('Date')?></th>
100
+ <th><?php _backupGuardT('Status')?></th>
101
+ <th><?php _backupGuardT('Actions')?></th>
102
+ </tr>
103
+ </thead>
104
+ <tbody>
105
+ <?php if(empty($backups)):?>
106
+ <tr>
107
+ <td colspan="6"><?php _backupGuardT('No backups found.')?></td>
108
+ </tr>
109
+ <?php endif;?>
110
+ <?php foreach($backups as $backup): ?>
111
+ <tr>
112
+ <td> <input type="checkbox" autocomplete="off" value="<?php echo $backup['name']?>" <?php echo $backup['active']?'disabled':''?>> </td>
113
+ <td><?php echo $backup['name'] ?></td>
114
+ <td><?php echo !$backup['active']?$backup['size']:'' ?></td>
115
+ <td><?php echo backupGuardConvertDateTimezone($backup['date']) ?></td>
116
+ <td id="sg-status-tabe-data-<?php echo $backup['id']?>" <?php echo $backup['active']?'data-toggle="tooltip" data-placement="top" data-original-title="" data-container="#sg-wrapper"':''?>>
117
+ <?php if($backup['active']):
118
+ $filteredStatuses = backupGuardFilterStatusesByActionType($backup, $backup['options']);
119
+ ?>
120
+ <input type="hidden" class="sg-active-action-id" value="<?php echo $backup['id'];?>"/>
121
+ <?php foreach ($filteredStatuses as $statusCode): ?>
122
+ <span class="btn-xs sg-status-icon sg-status-<?php echo $statusCode; ?>">&nbsp;</span>
123
+ <?php endforeach; ?>
124
+ <div class="sg-progress progress">
125
+ <div class="progress-bar progress-bar-danger"></div>
126
+ </div>
127
+ <?php else: ?>
128
+ <?php if ($backup['status'] == SG_ACTION_STATUS_FINISHED_WARNINGS): ?>
129
+ <span class="glyphicon glyphicon-warning-sign btn-xs text-warning" data-toggle="tooltip" data-placement="top" data-original-title="<?php if($backup['type']==SG_ACTION_TYPE_BACKUP): echo _backupGuardT('Warnings found during backup',true); elseif($backup['type']==SG_ACTION_TYPE_RESTORE): echo _backupGuardT('Warnings found during restore',true); else: echo _backupGuardT('Warnings found during upload',true); endif; ?>" data-container="#sg-wrapper"></span>
130
+ <?php elseif ($backup['status'] == SG_ACTION_STATUS_ERROR): ?>
131
+ <span class="glyphicon glyphicon-warning-sign btn-xs text-danger" data-toggle="tooltip" data-placement="top" data-original-title="<?php if($backup['type']==SG_ACTION_TYPE_BACKUP): echo _backupGuardT('Errors found during backup',true); elseif($backup['type']==SG_ACTION_TYPE_RESTORE): echo _backupGuardT('Errors found during restore',true); else: echo _backupGuardT('Errors found during upload',true);
132
+ endif; ?>" data-container="#sg-wrapper"></span>
133
+ <?php else: ?>
134
+ <span class="glyphicon glyphicon-ok btn-xs text-success"></span>
135
+ <?php endif;?>
136
+ <?php endif; ?>
137
+ </td>
138
+ <td>
139
+ <?php if($backup['active']): ?>
140
+ <?php if($backup['type'] != SG_ACTION_TYPE_RESTORE): ?>
141
+ <a class="btn btn-danger btn-xs sg-cancel-backup" sg-data-backup-id="<?php echo $backup['id']?>" href="javascript:void(0)" title="<?php _backupGuardT('Stop')?>">&nbsp;<i class="glyphicon glyphicon-stop" aria-hidden="true"></i>&nbsp;</a>
142
+ <?php endif; ?>
143
+ <?php else: ?>
144
+ <a href="javascript:void(0)" data-sgbackup-name="<?php echo $backup['name'];?>" data-remote="deleteBackup" class="btn btn-danger btn-xs sg-remove-backup" title="<?php _backupGuardT('Delete')?>">&nbsp;<i class="glyphicon glyphicon-remove" aria-hidden="true"></i>&nbsp;</a>
145
+ <div class="btn-group">
146
+ <a href="javascript:void(0)" class="btn btn-primary dropdown-toggle btn-xs" data-toggle="dropdown" aria-expanded="false" title="<?php _backupGuardT('Download')?>">
147
+ &nbsp;<i class="glyphicon glyphicon-download-alt" aria-hidden="true"></i>&nbsp;
148
+ <span class="caret"></span>
149
+ </a>
150
+ <ul class="dropdown-menu">
151
+ <?php if($backup['files']):?>
152
+ <li>
153
+ <a href="<?php echo $downloadUrl.'backupName='.@$backup['name'].'&downloadType='.SG_BACKUP_DOWNLOAD_TYPE_SGBP ?>">
154
+ <i class="glyphicon glyphicon-hdd" aria-hidden="true"></i> <?php _backupGuardT('Backup')?>
155
+ </a>
156
+ </li>
157
+ <?php endif;?>
158
+ <?php if($backup['backup_log']):?>
159
+ <li>
160
+ <a href="<?php echo $downloadUrl.'backupName='.@$backup['name'].'&downloadType='.SG_BACKUP_DOWNLOAD_TYPE_BACKUP_LOG ?>">
161
+ <i class="glyphicon glyphicon-list-alt" aria-hidden="true"></i> <?php _backupGuardT('Backup log')?>
162
+ </a>
163
+ </li>
164
+ <?php endif;?>
165
+ <?php if($backup['restore_log']):?>
166
+ <li>
167
+ <a href="<?php echo $downloadUrl.'backupName='.@$backup['name'].'&downloadType='.SG_BACKUP_DOWNLOAD_TYPE_RESTORE_LOG ?>">
168
+ <i class="glyphicon glyphicon-th-list" aria-hidden="true"></i> <?php _backupGuardT('Restore log')?>
169
+ </a>
170
+ </li>
171
+ <?php endif;?>
172
+ </ul>
173
+ </div>
174
+ <?php if(file_exists(SG_BACKUP_DIRECTORY.$backup['name'].'/'.$backup['name'].'.sgbp')):?>
175
+ <a href="javascript:void(0)" title="<?php _backupGuardT('Restore')?>" class="btn btn-success btn-xs sg-restore-button" data-toggle="modal" data-modal-name="manual-restore" data-remote="modalManualRestore" data-sgbp-params="<?php echo $backup['name']?>">
176
+ &nbsp;<i class="glyphicon glyphicon-repeat" aria-hidden="true"></i>&nbsp;
177
+ </a>
178
+ <?php endif;?>
179
+ <?php endif; ?>
180
+ </td>
181
+ </tr>
182
+ <?php endforeach; ?>
183
+ </tbody>
184
+ </table>
185
+
186
+ <button id="sg-delete-multi-backups" class="pull-left btn btn-danger"><?php _backupGuardT('Delete')?></button>
187
+
188
+ <div class="text-right">
189
+ <ul class="pagination"></ul>
190
+ </div>
191
+ </fieldset>
192
+ </div>
193
+ <?php
194
+ require_once(SG_PUBLIC_INCLUDE_PATH.'/footer.php');
195
+ ?>
196
+ </div>
197
+ <div class="clearfix"></div>
public/boot.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . '/../com/boot.php');
3
+ require_once(dirname(__FILE__) . '/config/config.wordpress.php');
4
+ require_once(SG_PUBLIC_INCLUDE_PATH.'functions.php');
public/cloud.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/boot.php');
3
+ require_once(SG_PUBLIC_INCLUDE_PATH.'/header.php');
4
+ $dropbox = SGConfig::get('SG_DROPBOX_ACCESS_TOKEN');
5
+ $gdrive = SGConfig::get('SG_GOOGLE_DRIVE_REFRESH_TOKEN');
6
+ $ftp = SGConfig::get('SG_STORAGE_FTP_CONNECTED');
7
+ $amazon = SGConfig::get('SG_STORAGE_AMAZON_CONNECTED');
8
+ $oneDrive = SGConfig::get('SG_ONE_DRIVE_REFRESH_TOKEN');
9
+
10
+ $ftpUsername = SGConfig::get('SG_FTP_CONNECTION_STRING');
11
+ $gdriveUsername = SGConfig::get('SG_GOOGLE_DRIVE_CONNECTION_STRING');
12
+ $dropboxUsername = SGConfig::get('SG_DROPBOX_CONNECTION_STRING');
13
+ $amazonInfo = SGConfig::get('SG_AMAZON_BUCKET');
14
+
15
+ $oneDriveInfo = SGConfig::get('SG_ONE_DRIVE_CONNECTION_STRING');
16
+ ?>
17
+ <?php require_once(SG_PUBLIC_INCLUDE_PATH.'sidebar.php'); ?>
18
+ <div id="sg-content-wrapper">
19
+ <div class="container-fluid">
20
+ <div class="row sg-cloud-container">
21
+ <div class="col-md-12">
22
+ <form class="form-horizontal">
23
+ <fieldset>
24
+ <legend><?php _backupGuardT('Cloud settings')?><?php echo backupGuardLoggedMessage(); ?></legend>
25
+ <?php if (SGBoot::isFeatureAvailable('SUBDIRECTORIES')): ?>
26
+ <div class="form-group form-inline">
27
+ <label class="col-md-5 sg-control-label">
28
+ <?php _backupGuardT('Destination folder')?>
29
+ </label>
30
+
31
+ <div class="col-md-7 pull-right text-right">
32
+ <input id="cloudFolder" name="cloudFolder" type="text" class="form-control input-md" value="<?php echo esc_html(SGConfig::get('SG_STORAGE_BACKUPS_FOLDER_NAME'))?>">
33
+ <button type="button" id="sg-save-cloud-folder" class="btn btn-success pull-right"><?php _backupGuardT('Save');?></button>
34
+ </div>
35
+ </div>
36
+ <hr/>
37
+ <?php endif; ?>
38
+ <!-- Dropbox -->
39
+ <?php if (SGBoot::isFeatureAvailable('DROPBOX')): ?>
40
+ <div class="form-group">
41
+ <label class="col-md-8 sg-control-label">
42
+ <?php echo 'Dropbox' ?>
43
+ <?php if(!empty($dropboxUsername)): ?>
44
+ <br/>
45
+ <span class="text-muted sg-dropbox-user sg-helper-block"><?php echo $dropboxUsername;?></span>
46
+ <?php endif;?>
47
+ </label>
48
+ <div class="col-md-3 pull-right text-right">
49
+ <label class="sg-switch-container">
50
+ <input data-on-text="<?php _backupGuardT('ON')?>" data-off-text="<?php _backupGuardT('OFF')?>" data-storage="DROPBOX" data-remote="cloudDropbox" type="checkbox" class="sg-switch" <?php echo !empty($dropbox)?'checked="checked"':''?>>
51
+ </label>
52
+ </div>
53
+ </div>
54
+ <?php endif; ?>
55
+ <!-- Google Drive -->
56
+ <?php if (SGBoot::isFeatureAvailable('GOOGLE_DRIVE')): ?>
57
+ <div class="form-group">
58
+ <label class="col-md-8 sg-control-label">
59
+ <?php echo 'Google Drive' ?>
60
+ <?php if(!empty($gdriveUsername)): ?>
61
+ <br/>
62
+ <span class="text-muted sg-gdrive-user sg-helper-block"><?php echo $gdriveUsername;?></span>
63
+ <?php endif;?>
64
+ </label>
65
+ <div class="col-md-3 pull-right text-right">
66
+ <label class="sg-switch-container">
67
+ <input data-on-text="<?php _backupGuardT('ON')?>" data-off-text="<?php _backupGuardT('OFF')?>" data-storage="GOOGLE_DRIVE" data-remote="cloudGdrive" type="checkbox" class="sg-switch" <?php echo !empty($gdrive)?'checked="checked"':''?>>
68
+ </label>
69
+ </div>
70
+ </div>
71
+ <?php endif; ?>
72
+ <!-- FTP -->
73
+ <?php if (SGBoot::isFeatureAvailable('FTP')): ?>
74
+ <div class="form-group">
75
+ <label class="col-md-8 sg-control-label sg-user-info">
76
+ <?php echo 'FTP / SFTP' ?>
77
+ <?php if(!empty($ftpUsername)): ?>
78
+ <br/>
79
+ <span class="text-muted sg-ftp-user sg-helper-block"><?php echo $ftpUsername;?></span>
80
+ <?php endif;?>
81
+ </label>
82
+ <div class="col-md-3 pull-right text-right">
83
+ <label class="sg-switch-container">
84
+ <input type="checkbox" data-on-text="<?php _backupGuardT('ON')?>" data-off-text="<?php _backupGuardT('OFF')?>" data-storage="FTP" data-remote="cloudFtp" class="sg-switch" <?php echo !empty($ftp)?'checked="checked"':''?>>
85
+ <a id="ftp-settings" href="javascript:void(0)" class="hide" data-toggle="modal" data-modal-name="ftp-settings" data-remote="modalFtpSettings"><?php echo 'FTP '._backupGuardT('Settings', true) ?></a>
86
+ </label>
87
+ </div>
88
+ </div>
89
+ <?php endif; ?>
90
+ <!-- Amazon S3 -->
91
+ <?php if (SGBoot::isFeatureAvailable('AMAZON')): ?>
92
+ <div class="form-group">
93
+ <label class="col-md-8 sg-control-label">
94
+ <?php echo (backupGuardIsAccountGold()? 'Amazon ':'').'S3'?>
95
+ <?php if (!empty($amazonInfo)):?>
96
+ <br/>
97
+ <span class="text-muted sg-amazonr-user sg-helper-block"><?php echo $amazonInfo;?></span>
98
+ <?php endif;?>
99
+ </label>
100
+ <div class="col-md-3 pull-right text-right">
101
+ <label class="sg-switch-container">
102
+ <input type="checkbox" data-on-text="<?php _backupGuardT('ON')?>" data-off-text="<?php _backupGuardT('OFF')?>" data-storage="AMAZON" data-remote="cloudAmazon" class="sg-switch" <?php echo !empty($amazon)?'checked="checked"':''?>>
103
+ <a id="amazon-settings" href="javascript:void(0)" class="hide" data-toggle="modal" data-modal-name="amazon-settings" data-remote="modalAmazonSettings"><?php echo 'Amazon'._backupGuardT('Settings', true)?></a>
104
+ </label>
105
+ </div>
106
+ </div>
107
+ <?php endif; ?>
108
+ <!-- One Drive -->
109
+ <?php if (SGBoot::isFeatureAvailable('ONE_DRIVE')): ?>
110
+ <div class="form-group">
111
+ <label class="col-md-8 sg-control-label">
112
+ <?php echo 'One Drive' ?>
113
+ <?php if(!empty($oneDriveInfo)): ?>
114
+ <br/>
115
+ <span class="text-muted sg-gdrive-user sg-helper-block"><?php echo $oneDriveInfo;?></span>
116
+ <?php endif;?>
117
+ </label>
118
+ <div class="col-md-3 pull-right text-right">
119
+ <label class="sg-switch-container">
120
+ <input data-on-text="<?php _backupGuardT('ON')?>" data-off-text="<?php _backupGuardT('OFF')?>" data-storage="ONE_DRIVE" data-remote="cloudOneDrive" type="checkbox" class="sg-switch" <?php echo !empty($oneDrive)?'checked="checked"':''?>>
121
+ </label>
122
+ </div>
123
+ </div>
124
+ <?php endif; ?>
125
+ </fieldset>
126
+ </form>
127
+ </div>
128
+ </div>
129
+ </div>
130
+ <?php require_once(SG_PUBLIC_INCLUDE_PATH.'/footer.php'); ?>
131
+ </div>
public/config/config.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ //Paths
4
+ define('SG_PUBLIC_PATH', realpath(dirname(__FILE__).'/../').'/');
5
+ define('SG_PUBLIC_CONFIG_PATH', SG_PUBLIC_PATH.'config/');
6
+ define('SG_PUBLIC_INCLUDE_PATH', SG_PUBLIC_PATH.'include/');
7
+ define('SG_PUBLIC_MODALS_PATH', SG_PUBLIC_PATH.'include/modals/');
8
+ define('SG_PUBLIC_AJAX_PATH', SG_PUBLIC_PATH.'ajax/');
9
+
10
+ define('SG_EXTENSIONS_FOLDER_PATH', dirname(SG_PUBLIC_PATH)."/extensions/");
11
+
12
+ //Defines
13
+ define('SG_BACKUP_TYPE_FULL', 1);
14
+ define('SG_BACKUP_TYPE_CUSTOM', 2);
15
+ define('SG_BACKUP_MAX_FILE_UPLOAD_SIZE', 100); // in megabytes
16
+
17
+ @ini_set('upload_max_filesize',SG_BACKUP_MAX_FILE_UPLOAD_SIZE.'M');
18
+ @ini_set('post_max_size',SG_BACKUP_MAX_FILE_UPLOAD_SIZE.'M');
19
+
20
+ //Review popup states
21
+ define('SG_SHOW_REVIEW_POPUP', 1);
22
+ define('SG_NEVER_SHOW_REVIEW_POPUP', 2);
23
+
24
+ //Ajax frequency
25
+ define('SG_AJAX_DEFAULT_REQUEST_FREQUENCY', '2000'); //in miliseconds
public/config/config.wordpress.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/config.php');
3
+
4
+ //Plugin's directory name
5
+ define('SG_PLUGIN_NAME', basename(dirname(SG_PUBLIC_PATH)));
6
+
7
+ //Urls
8
+ define('SG_PUBLIC_URL', plugins_url().'/'.SG_PLUGIN_NAME.'/public/');
9
+ define('SG_PUBLIC_AJAX_URL', SG_PUBLIC_URL.'ajax/');
10
+ define('SG_PUBLIC_BACKUPS_URL', network_admin_url('admin.php?page=backup_guard_backups'));
11
+ define('SG_PUBLIC_CLOUD_URL', network_admin_url('admin.php?page=backup_guard_cloud'));
12
+ define('SG_BACKUP_GUARD_REVIEW_URL', 'https://wordpress.org/support/view/plugin-reviews/backup?filter=5');
13
+ define('SG_IMAGE_URL', SG_PUBLIC_URL.'img/');
14
+
15
+ //BackupGuard Site URL
16
+ define('SG_BACKUP_SITE_URL', 'https://backup-guard.com/products/backup-wordpress');
17
+
18
+ define('SG_BACKUP_UPGRADE_URL', 'https://backup-guard.com/products/backup-wordpress/0');
19
+
20
+ define('SG_BACKUP_SITE_PRICING_URL', 'https://backup-guard.com/products/backup-wordpress#pricing');
21
+
22
+ define('SG_BACKUP_ADMIN_LOGIN_URL', 'https://backup-guard.com/admin');
public/cron/sg_backup.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackup.php');
4
+
5
+ if ($id) {
6
+ $allActions = SGBackup::getRunningActions();
7
+ if (count($allActions)) { // abort any other backup if there is an active action
8
+ die();
9
+ }
10
+
11
+ $b = new SGBackup();
12
+ $options = $b->getScheduleParamsById($id);
13
+
14
+ if ($options) {
15
+ $b->backup(json_decode($options['backup_options'], true));
16
+ }
17
+ }
public/cron/sg_storage_upload.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/../boot.php');
3
+ require_once(SG_BACKUP_PATH.'SGBackupStorage.php');
4
+
5
+ SGBackupStorage::getInstance()->startNextUploadInQueue();
public/css/bgstyle.less.css ADDED
@@ -0,0 +1,7893 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #sg-custom-backup-name {
2
+ width: 100%;
3
+ }
4
+
5
+ .backup-guard-label-success {
6
+ color: green;
7
+ }
8
+
9
+ .backup-guard-label-warning {
10
+ color: red;
11
+ }
12
+
13
+ .sg-feature-alert-text {
14
+ color: gray;
15
+ font-size: 13px;
16
+ font-style: italic;
17
+ text-align: center;
18
+ }
19
+
20
+ #sg-product-name-div {
21
+ position: absolute;
22
+ font-size: 10px;
23
+ color: orange;
24
+ bottom: 15px;
25
+ text-align: center;
26
+ width: 100%;
27
+ margin-left: -20px;
28
+ }
29
+
30
+ .sg-badge-warning {
31
+ background-color: #ff7518 !important;
32
+ border-color: #ff4309 !important;
33
+ border-radius: 2px !important;
34
+ color: #ffffff !important;
35
+ }
36
+
37
+ .sg-margin-left-20 {
38
+ margin-left: 20px;
39
+ }
40
+
41
+ .sg-service-container {
42
+ width: 100%;
43
+ margin: 0;
44
+ }
45
+
46
+ .sg-service-container h3 {
47
+ margin-top: 0px !important;
48
+ }
49
+
50
+ .sg-service-container .plugin-card-top {
51
+ margin-bottom: 20px;
52
+ }
53
+
54
+ #sg-migration-service-price {
55
+ font-size: 22px;
56
+ text-align: center;
57
+ }
58
+
59
+ #sg-banner {
60
+ margin-top: 10px;
61
+ width: calc(100% - 20px) !important;
62
+ height: 185px;
63
+ background-color: #333;
64
+ color: #FFFFFF;
65
+ font-size: 12px;
66
+ min-width: 650px;
67
+ }
68
+
69
+ #sg-left-column {
70
+ width: 18%;
71
+ float: left;
72
+ display: inline-block;
73
+ }
74
+
75
+ #sg-left-column ul {
76
+ display: inline-block;
77
+ }
78
+
79
+ #sg-center-column {
80
+ width: 60%;
81
+ padding-top: 17px;
82
+ text-align: center;
83
+ display: inline-block;
84
+ }
85
+
86
+ #sg-right-column {
87
+ width: 22%;
88
+ float: right;
89
+ display: inline-block;
90
+ }
91
+
92
+ .sg-banner-social-button {
93
+ display: inline-block;
94
+ width: 32px;
95
+ height: 32px;
96
+ border: none;
97
+ border-radius: 50%;
98
+ cursor: pointer;
99
+ margin-right: 3px;
100
+ }
101
+
102
+ #sg-banner p {
103
+ width: 100%;
104
+ text-align: center;
105
+ font-size: 13px !important;
106
+ }
107
+
108
+ #sg-banner a {
109
+ vertical-align: middle;
110
+ text-decoration: none;
111
+ color: #FFFFFF;
112
+ cursor: pointer;
113
+ }
114
+
115
+ #sg-banner ul {
116
+ list-style-type: none;
117
+ }
118
+
119
+ #sg-banner li {
120
+ vertical-align: middle;
121
+ margin-bottom: 5px;
122
+ height: 32px;
123
+ }
124
+
125
+ #sg-right-column ul {
126
+ float: right;
127
+ padding-right: 16px;
128
+ padding-top: 10px;
129
+ }
130
+
131
+ #sg-right-column li {
132
+ vertical-align: middle;
133
+ }
134
+
135
+ #sg-left-column li {
136
+ padding-left: 20px;
137
+ }
138
+
139
+ #sg-left-column ul {
140
+ padding-top: 10px;
141
+ }
142
+
143
+ .sg-img-class {
144
+ margin-right: 10px;
145
+ vertical-align: middle;
146
+ }
147
+
148
+ #sg-logo {
149
+ display: inline-block;
150
+ width: 140px;
151
+ height: 30px;
152
+ background-size: 140px 30px;
153
+ background-repeat: no-repeat;
154
+ background-image: url("../img/logo-horizontal.png");
155
+ }
156
+
157
+ #sg-facebook {
158
+ background: url('../img/fb.png') no-repeat;
159
+ }
160
+
161
+ #sg-facebook:hover {
162
+ background-color: #3C5A96;
163
+ }
164
+
165
+ #sg-twitter {
166
+ background: url("../img/TW.png") no-repeat;
167
+ }
168
+
169
+ #sg-twitter:hover {
170
+ background-color: #2AA3EF;
171
+ }
172
+
173
+ #sg-google-plus {
174
+ background: url("../img/G+.png") no-repeat;
175
+ }
176
+
177
+ #sg-google-plus:hover {
178
+ background-color: #D9453D;
179
+ }
180
+
181
+ #sg-youtube {
182
+ background: url("../img/youtube.png") no-repeat;
183
+ }
184
+
185
+ #sg-youtube:hover {
186
+ background-color: #E32424;
187
+ }
188
+
189
+ .sg-star-class {
190
+ cursor:pointer;
191
+ margin-right: 3px;
192
+ }
193
+
194
+ #rateYo {
195
+ display: inline-block;
196
+ }
197
+
198
+ #sg-buy-now {
199
+ background-color: #951b17;
200
+ border: none;
201
+ color: #fff;
202
+ font-size: 18px;
203
+ vertical-align: middle;
204
+ cursor: pointer;
205
+ display: inline-block;
206
+ padding: 6px 15px;
207
+ }
208
+
209
+ #sg-buy-now:hover {
210
+ background-color: #2f8912;
211
+ }
212
+
213
+ #sg-buy-now-text {
214
+ vertical-align: middle;
215
+ }
216
+
217
+ #sg-banner-clarification {
218
+ font-size: 10px;
219
+ }
220
+
221
+ #sg-rate-us {
222
+ height: 32px;
223
+ position: relative;
224
+ }
225
+
226
+ #sg-banner-test {
227
+ position: absolute;
228
+ top:50%;
229
+ width: 100%;
230
+ margin-top: -15px;
231
+ }
232
+
233
+ .sg-banner-rate-us-in {
234
+ display: inline-block;
235
+ height: 30px;
236
+ }
237
+
238
+ /* Bounce In */
239
+ .hvr-bounce-in {
240
+ /*display: inline-block;*/
241
+ vertical-align: middle;
242
+ -webkit-transition-duration: 0.04s;
243
+ transition-duration: 0.04s;
244
+ cursor: pointer;
245
+ }
246
+ .hvr-bounce-in:hover, .hvr-bounce-in:focus, .hvr-bounce-in:active {
247
+ -ms-transform: translate(4px, 0);
248
+ -webkit-transform: translate(4px, 0);
249
+ transform: translate(4px, 0);
250
+ }
251
+
252
+ @media (max-width: 835px) {
253
+ #sg-banner {
254
+ font-size: 8px;
255
+ }
256
+
257
+ #sg-banner p {
258
+ font-size: 8px !important;
259
+ }
260
+
261
+ #sg-center-column {
262
+ width: 50%;
263
+ }
264
+
265
+ #sg-left-column {
266
+ width: 23%;
267
+ }
268
+
269
+ #sg-right-column {
270
+ width: 27%;
271
+ }
272
+ }
273
+
274
+ /**************************************/
275
+
276
+ #sg-backup-with-migration {
277
+ margin-left: 12px;
278
+ }
279
+
280
+ #modal-import-1,
281
+ #sg-modal-inport-from,
282
+ #modal-import-3 {
283
+ padding: 0;
284
+ }
285
+
286
+ #sg-checkbox-select-all {
287
+ margin-top: 0;
288
+ }
289
+
290
+ .sg-wrap-container {
291
+ height: 650px;
292
+ width: 100%;
293
+ }
294
+
295
+ #sg-backup-guard-iframe {
296
+ width: 100%;
297
+ height: 100%;
298
+ }
299
+
300
+ #modal-import-2 {
301
+ margin-top: 15px;
302
+ }
303
+
304
+ #modal-import-1 .form-group{
305
+ margin-bottom: 0;
306
+ }
307
+
308
+ #modal-import-1 .table{
309
+ margin-bottom: 0;
310
+ }
311
+
312
+ #modal-import-3 .form-group{
313
+ margin-bottom: 0;
314
+ }
315
+
316
+ #modal-import-3 .table{
317
+ margin-bottom: 0;
318
+ }
319
+
320
+ .file-select-radio {
321
+ padding-left: 15px !important;
322
+ }
323
+
324
+ .sg-wrapper-less {
325
+ /* vietnamese */
326
+ /* latin-ext */
327
+ /* latin */
328
+ /* vietnamese */
329
+ /* latin-ext */
330
+ /* latin */
331
+ /* vietnamese */
332
+ /* latin-ext */
333
+ /* latin */
334
+ /*!
335
+ * bootswatch v3.3.4+1
336
+ * Homepage: http://bootswatch.com
337
+ * Copyright 2012-2015 Thomas Park
338
+ * Licensed under MIT
339
+ * Based on Bootstrap
340
+ */
341
+ /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
342
+ /*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
343
+ /* Sidebar Styles */
344
+ /*Files*/
345
+ /*ftp*/
346
+ /*dropbox*/
347
+ /*gdrive*/
348
+ /*rdb*/
349
+ /*rfiles*/
350
+ }
351
+ @font-face {
352
+ font-family: 'Source Sans Pro';
353
+ font-style: normal;
354
+ font-weight: 300;
355
+ src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/toadOcfmlt9b38dHJxOBGCD5K6T8I4oZ1X3Xvlj_UeP3rGVtsTkPsbDajuO5ueQw.woff2') format('woff2');
356
+ unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
357
+ }
358
+ @font-face {
359
+ font-family: 'Source Sans Pro';
360
+ font-style: normal;
361
+ font-weight: 300;
362
+ src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/toadOcfmlt9b38dHJxOBGDOFnJNygIkrHciC8BWzbCz3rGVtsTkPsbDajuO5ueQw.woff2') format('woff2');
363
+ unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
364
+ }
365
+ @font-face {
366
+ font-family: 'Source Sans Pro';
367
+ font-style: normal;
368
+ font-weight: 300;
369
+ src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/toadOcfmlt9b38dHJxOBGCP2LEk6lMzYsRqr3dHFImA.woff2') format('woff2');
370
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
371
+ }
372
+ @font-face {
373
+ font-family: 'Source Sans Pro';
374
+ font-style: normal;
375
+ font-weight: 400;
376
+ src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url('../fonts/ODelI1aHBYDBqgeIAH2zlCxe5Tewm2_XWfbGchcXw4g.woff2') format('woff2');
377
+ unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
378
+ }
379
+ @font-face {
380
+ font-family: 'Source Sans Pro';
381
+ font-style: normal;
382
+ font-weight: 400;
383
+ src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url('../fonts/ODelI1aHBYDBqgeIAH2zlIa1YDtoarzwSXxTHggEXMw.woff2') format('woff2');
384
+ unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
385
+ }
386
+ @font-face {
387
+ font-family: 'Source Sans Pro';
388
+ font-style: normal;
389
+ font-weight: 400;
390
+ src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url('../fonts/ODelI1aHBYDBqgeIAH2zlJbPFduIYtoLzwST68uhz_Y.woff2') format('woff2');
391
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
392
+ }
393
+ @font-face {
394
+ font-family: 'Source Sans Pro';
395
+ font-style: normal;
396
+ font-weight: 700;
397
+ src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/toadOcfmlt9b38dHJxOBGMms7UHsIbjUxEJqIwog-i_3rGVtsTkPsbDajuO5ueQw.woff2') format('woff2');
398
+ unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
399
+ }
400
+ @font-face {
401
+ font-family: 'Source Sans Pro';
402
+ font-style: normal;
403
+ font-weight: 700;
404
+ src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/toadOcfmlt9b38dHJxOBGO4s1Ux4PuImWPk5fSr6HPL3rGVtsTkPsbDajuO5ueQw.woff2') format('woff2');
405
+ unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
406
+ }
407
+ @font-face {
408
+ font-family: 'Source Sans Pro';
409
+ font-style: normal;
410
+ font-weight: 700;
411
+ src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/toadOcfmlt9b38dHJxOBGJkF8H8ye47wsfpWywda8og.woff2') format('woff2');
412
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
413
+ }
414
+ .sg-wrapper-less html {
415
+ font-family: sans-serif;
416
+ -ms-text-size-adjust: 100%;
417
+ -webkit-text-size-adjust: 100%;
418
+ }
419
+ .sg-wrapper-less body {
420
+ margin: 0;
421
+ }
422
+ .sg-wrapper-less article,
423
+ .sg-wrapper-less aside,
424
+ .sg-wrapper-less details,
425
+ .sg-wrapper-less figcaption,
426
+ .sg-wrapper-less figure,
427
+ .sg-wrapper-less footer,
428
+ .sg-wrapper-less header,
429
+ .sg-wrapper-less hgroup,
430
+ .sg-wrapper-less main,
431
+ .sg-wrapper-less menu,
432
+ .sg-wrapper-less nav,
433
+ .sg-wrapper-less section,
434
+ .sg-wrapper-less summary {
435
+ display: block;
436
+ }
437
+ .sg-wrapper-less audio,
438
+ .sg-wrapper-less canvas,
439
+ .sg-wrapper-less progress,
440
+ .sg-wrapper-less video {
441
+ display: inline-block;
442
+ vertical-align: baseline;
443
+ }
444
+ .sg-wrapper-less audio:not([controls]) {
445
+ display: none;
446
+ height: 0;
447
+ }
448
+ .sg-wrapper-less [hidden],
449
+ .sg-wrapper-less template {
450
+ display: none;
451
+ }
452
+ .sg-wrapper-less a {
453
+ background-color: transparent;
454
+ }
455
+ .sg-wrapper-less a:active,
456
+ .sg-wrapper-less a:hover {
457
+ outline: 0;
458
+ }
459
+ .sg-wrapper-less abbr[title] {
460
+ border-bottom: 1px dotted;
461
+ }
462
+ .sg-wrapper-less b,
463
+ .sg-wrapper-less strong {
464
+ font-weight: bold;
465
+ }
466
+ .sg-wrapper-less dfn {
467
+ font-style: italic;
468
+ }
469
+ .sg-wrapper-less h1 {
470
+ font-size: 2em;
471
+ margin: 0.67em 0;
472
+ }
473
+ .sg-wrapper-less mark {
474
+ background: #ff0;
475
+ color: #000;
476
+ }
477
+ .sg-wrapper-less small {
478
+ font-size: 80%;
479
+ }
480
+ .sg-wrapper-less sub,
481
+ .sg-wrapper-less sup {
482
+ font-size: 75%;
483
+ line-height: 0;
484
+ position: relative;
485
+ vertical-align: baseline;
486
+ }
487
+ .sg-wrapper-less sup {
488
+ top: -0.5em;
489
+ }
490
+ .sg-wrapper-less sub {
491
+ bottom: -0.25em;
492
+ }
493
+ .sg-wrapper-less img {
494
+ border: 0;
495
+ }
496
+ .sg-wrapper-less svg:not(:root) {
497
+ overflow: hidden;
498
+ }
499
+ .sg-wrapper-less figure {
500
+ margin: 1em 40px;
501
+ }
502
+ .sg-wrapper-less hr {
503
+ -moz-box-sizing: content-box;
504
+ -webkit-box-sizing: content-box;
505
+ box-sizing: content-box;
506
+ height: 0;
507
+ }
508
+ .sg-wrapper-less pre {
509
+ overflow: auto;
510
+ }
511
+ .sg-wrapper-less code,
512
+ .sg-wrapper-less kbd,
513
+ .sg-wrapper-less pre,
514
+ .sg-wrapper-less samp {
515
+ font-family: monospace, monospace;
516
+ font-size: 1em;
517
+ }
518
+ .sg-wrapper-less button,
519
+ .sg-wrapper-less input,
520
+ .sg-wrapper-less optgroup,
521
+ .sg-wrapper-less select,
522
+ .sg-wrapper-less textarea {
523
+ color: inherit;
524
+ font: inherit;
525
+ margin: 0;
526
+ }
527
+ .sg-wrapper-less button {
528
+ overflow: visible;
529
+ }
530
+ .sg-wrapper-less button,
531
+ .sg-wrapper-less select {
532
+ text-transform: none;
533
+ }
534
+ .sg-wrapper-less button,
535
+ .sg-wrapper-less html input[type="button"],
536
+ .sg-wrapper-less input[type="reset"],
537
+ .sg-wrapper-less input[type="submit"] {
538
+ -webkit-appearance: button;
539
+ cursor: pointer;
540
+ }
541
+ .sg-wrapper-less button[disabled],
542
+ .sg-wrapper-less html input[disabled] {
543
+ cursor: default;
544
+ }
545
+ .sg-wrapper-less button::-moz-focus-inner,
546
+ .sg-wrapper-less input::-moz-focus-inner {
547
+ border: 0;
548
+ padding: 0;
549
+ }
550
+ .sg-wrapper-less input {
551
+ line-height: normal;
552
+ }
553
+ .sg-wrapper-less input[type="checkbox"],
554
+ .sg-wrapper-less input[type="radio"] {
555
+ -webkit-box-sizing: border-box;
556
+ -moz-box-sizing: border-box;
557
+ box-sizing: border-box;
558
+ padding: 0;
559
+ }
560
+ .sg-wrapper-less input[type="number"]::-webkit-inner-spin-button,
561
+ .sg-wrapper-less input[type="number"]::-webkit-outer-spin-button {
562
+ height: auto;
563
+ }
564
+ .sg-wrapper-less input[type="search"] {
565
+ -webkit-appearance: textfield;
566
+ -moz-box-sizing: content-box;
567
+ -webkit-box-sizing: content-box;
568
+ box-sizing: content-box;
569
+ }
570
+ .sg-wrapper-less input[type="search"]::-webkit-search-cancel-button,
571
+ .sg-wrapper-less input[type="search"]::-webkit-search-decoration {
572
+ -webkit-appearance: none;
573
+ }
574
+ .sg-wrapper-less fieldset {
575
+ border: 1px solid #c0c0c0;
576
+ margin: 0 2px;
577
+ padding: 0.35em 0.625em 0.75em;
578
+ }
579
+ .sg-wrapper-less legend {
580
+ border: 0;
581
+ padding: 0;
582
+ }
583
+ .sg-wrapper-less textarea {
584
+ overflow: auto;
585
+ }
586
+ .sg-wrapper-less optgroup {
587
+ font-weight: bold;
588
+ }
589
+ .sg-wrapper-less table {
590
+ border-collapse: collapse;
591
+ border-spacing: 0;
592
+ }
593
+ .sg-wrapper-less td,
594
+ .sg-wrapper-less th {
595
+ padding: 0;
596
+ }
597
+ @media print {
598
+ .sg-wrapper-less *,
599
+ .sg-wrapper-less *:before,
600
+ .sg-wrapper-less *:after {
601
+ background: transparent !important;
602
+ color: #000 !important;
603
+ -webkit-box-shadow: none !important;
604
+ box-shadow: none !important;
605
+ text-shadow: none !important;
606
+ }
607
+ .sg-wrapper-less a,
608
+ .sg-wrapper-less a:visited {
609
+ text-decoration: underline;
610
+ }
611
+ .sg-wrapper-less a[href]:after {
612
+ content: " (" attr(href) ")";
613
+ }
614
+ .sg-wrapper-less abbr[title]:after {
615
+ content: " (" attr(title) ")";
616
+ }
617
+ .sg-wrapper-less a[href^="#"]:after,
618
+ .sg-wrapper-less a[href^="javascript:"]:after {
619
+ content: "";
620
+ }
621
+ .sg-wrapper-less pre,
622
+ .sg-wrapper-less blockquote {
623
+ border: 1px solid #999;
624
+ page-break-inside: avoid;
625
+ }
626
+ .sg-wrapper-less thead {
627
+ display: table-header-group;
628
+ }
629
+ .sg-wrapper-less tr,
630
+ .sg-wrapper-less img {
631
+ page-break-inside: avoid;
632
+ }
633
+ .sg-wrapper-less img {
634
+ max-width: 100% !important;
635
+ }
636
+ .sg-wrapper-less p,
637
+ .sg-wrapper-less h2,
638
+ .sg-wrapper-less h3 {
639
+ orphans: 3;
640
+ widows: 3;
641
+ }
642
+ .sg-wrapper-less h2,
643
+ .sg-wrapper-less h3 {
644
+ page-break-after: avoid;
645
+ }
646
+ .sg-wrapper-less select {
647
+ background: #fff !important;
648
+ }
649
+ .sg-wrapper-less .navbar {
650
+ display: none;
651
+ }
652
+ .sg-wrapper-less .btn > .caret,
653
+ .sg-wrapper-less .dropup > .btn > .caret {
654
+ border-top-color: #000 !important;
655
+ }
656
+ .sg-wrapper-less .label {
657
+ border: 1px solid #000;
658
+ }
659
+ .sg-wrapper-less .table {
660
+ border-collapse: collapse !important;
661
+ }
662
+ .sg-wrapper-less .table td,
663
+ .sg-wrapper-less .table th {
664
+ background-color: #fff !important;
665
+ }
666
+ .sg-wrapper-less .table-bordered th,
667
+ .sg-wrapper-less .table-bordered td {
668
+ border: 1px solid #ddd !important;
669
+ }
670
+ }
671
+ @font-face {
672
+ font-family: 'Glyphicons Halflings';
673
+ src: url('../fonts/glyphicons-halflings-regular.eot');
674
+ src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
675
+ }
676
+ .sg-wrapper-less .glyphicon {
677
+ position: relative;
678
+ top: 1px;
679
+ display: inline-block;
680
+ font-family: 'Glyphicons Halflings';
681
+ font-style: normal;
682
+ font-weight: normal;
683
+ line-height: 1;
684
+ -webkit-font-smoothing: antialiased;
685
+ -moz-osx-font-smoothing: grayscale;
686
+ }
687
+ .sg-wrapper-less .glyphicon-asterisk:before {
688
+ content: "\2a";
689
+ }
690
+ .sg-wrapper-less .glyphicon-plus:before {
691
+ content: "\2b";
692
+ }
693
+ .sg-wrapper-less .glyphicon-euro:before,
694
+ .sg-wrapper-less .glyphicon-eur:before {
695
+ content: "\20ac";
696
+ }
697
+ .sg-wrapper-less .glyphicon-minus:before {
698
+ content: "\2212";
699
+ }
700
+ .sg-wrapper-less .glyphicon-cloud:before {
701
+ content: "\2601";
702
+ }
703
+ .sg-wrapper-less .glyphicon-envelope:before {
704
+ content: "\2709";
705
+ }
706
+ .sg-wrapper-less .glyphicon-pencil:before {
707
+ content: "\270f";
708
+ }
709
+ .sg-wrapper-less .glyphicon-glass:before {
710
+ content: "\e001";
711
+ }
712
+ .sg-wrapper-less .glyphicon-music:before {
713
+ content: "\e002";
714
+ }
715
+ .sg-wrapper-less .glyphicon-search:before {
716
+ content: "\e003";
717
+ }
718
+ .sg-wrapper-less .glyphicon-heart:before {
719
+ content: "\e005";
720
+ }
721
+ .sg-wrapper-less .glyphicon-star:before {
722
+ content: "\e006";
723
+ }
724
+ .sg-wrapper-less .glyphicon-star-empty:before {
725
+ content: "\e007";
726
+ }
727
+ .sg-wrapper-less .glyphicon-user:before {
728
+ content: "\e008";
729
+ }
730
+ .sg-wrapper-less .glyphicon-film:before {
731
+ content: "\e009";
732
+ }
733
+ .sg-wrapper-less .glyphicon-th-large:before {
734
+ content: "\e010";
735
+ }
736
+ .sg-wrapper-less .glyphicon-th:before {
737
+ content: "\e011";
738
+ }
739
+ .sg-wrapper-less .glyphicon-th-list:before {
740
+ content: "\e012";
741
+ }
742
+ .sg-wrapper-less .glyphicon-ok:before {
743
+ content: "\e013";
744
+ }
745
+ .sg-wrapper-less .glyphicon-remove:before {
746
+ content: "\e014";
747
+ }
748
+ .sg-wrapper-less .glyphicon-zoom-in:before {
749
+ content: "\e015";
750
+ }
751
+ .sg-wrapper-less .glyphicon-zoom-out:before {
752
+ content: "\e016";
753
+ }
754
+ .sg-wrapper-less .glyphicon-off:before {
755
+ content: "\e017";
756
+ }
757
+ .sg-wrapper-less .glyphicon-signal:before {
758
+ content: "\e018";
759
+ }
760
+ .sg-wrapper-less .glyphicon-cog:before {
761
+ content: "\e019";
762
+ }
763
+ .sg-wrapper-less .glyphicon-trash:before {
764
+ content: "\e020";
765
+ }
766
+ .sg-wrapper-less .glyphicon-home:before {
767
+ content: "\e021";
768
+ }
769
+ .sg-wrapper-less .glyphicon-file:before {
770
+ content: "\e022";
771
+ }
772
+ .sg-wrapper-less .glyphicon-time:before {
773
+ content: "\e023";
774
+ }
775
+ .sg-wrapper-less .glyphicon-road:before {
776
+ content: "\e024";
777
+ }
778
+ .sg-wrapper-less .glyphicon-download-alt:before {
779
+ content: "\e025";
780
+ }
781
+ .sg-wrapper-less .glyphicon-download:before {
782
+ content: "\e026";
783
+ }
784
+ .sg-wrapper-less .glyphicon-upload:before {
785
+ content: "\e027";
786
+ }
787
+ .sg-wrapper-less .glyphicon-inbox:before {
788
+ content: "\e028";
789
+ }
790
+ .sg-wrapper-less .glyphicon-play-circle:before {
791
+ content: "\e029";
792
+ }
793
+ .sg-wrapper-less .glyphicon-repeat:before {
794
+ content: "\e030";
795
+ }
796
+ .sg-wrapper-less .glyphicon-refresh:before {
797
+ content: "\e031";
798
+ }
799
+ .sg-wrapper-less .glyphicon-list-alt:before {
800
+ content: "\e032";
801
+ }
802
+ .sg-wrapper-less .glyphicon-lock:before {
803
+ content: "\e033";
804
+ }
805
+ .sg-wrapper-less .glyphicon-flag:before {
806
+ content: "\e034";
807
+ }
808
+ .sg-wrapper-less .glyphicon-headphones:before {
809
+ content: "\e035";
810
+ }
811
+ .sg-wrapper-less .glyphicon-volume-off:before {
812
+ content: "\e036";
813
+ }
814
+ .sg-wrapper-less .glyphicon-volume-down:before {
815
+ content: "\e037";
816
+ }
817
+ .sg-wrapper-less .glyphicon-volume-up:before {
818
+ content: "\e038";
819
+ }
820
+ .sg-wrapper-less .glyphicon-qrcode:before {
821
+ content: "\e039";
822
+ }
823
+ .sg-wrapper-less .glyphicon-barcode:before {
824
+ content: "\e040";
825
+ }
826
+ .sg-wrapper-less .glyphicon-tag:before {
827
+ content: "\e041";
828
+ }
829
+ .sg-wrapper-less .glyphicon-tags:before {
830
+ content: "\e042";
831
+ }
832
+ .sg-wrapper-less .glyphicon-book:before {
833
+ content: "\e043";
834
+ }
835
+ .sg-wrapper-less .glyphicon-bookmark:before {
836
+ content: "\e044";
837
+ }
838
+ .sg-wrapper-less .glyphicon-print:before {
839
+ content: "\e045";
840
+ }
841
+ .sg-wrapper-less .glyphicon-camera:before {
842
+ content: "\e046";
843
+ }
844
+ .sg-wrapper-less .glyphicon-font:before {
845
+ content: "\e047";
846
+ }
847
+ .sg-wrapper-less .glyphicon-bold:before {
848
+ content: "\e048";
849
+ }
850
+ .sg-wrapper-less .glyphicon-italic:before {
851
+ content: "\e049";
852
+ }
853
+ .sg-wrapper-less .glyphicon-text-height:before {
854
+ content: "\e050";
855
+ }
856
+ .sg-wrapper-less .glyphicon-text-width:before {
857
+ content: "\e051";
858
+ }
859
+ .sg-wrapper-less .glyphicon-align-left:before {
860
+ content: "\e052";
861
+ }
862
+ .sg-wrapper-less .glyphicon-align-center:before {
863
+ content: "\e053";
864
+ }
865
+ .sg-wrapper-less .glyphicon-align-right:before {
866
+ content: "\e054";
867
+ }
868
+ .sg-wrapper-less .glyphicon-align-justify:before {
869
+ content: "\e055";
870
+ }
871
+ .sg-wrapper-less .glyphicon-list:before {
872
+ content: "\e056";
873
+ }
874
+ .sg-wrapper-less .glyphicon-indent-left:before {
875
+ content: "\e057";
876
+ }
877
+ .sg-wrapper-less .glyphicon-indent-right:before {
878
+ content: "\e058";
879
+ }
880
+ .sg-wrapper-less .glyphicon-facetime-video:before {
881
+ content: "\e059";
882
+ }
883
+ .sg-wrapper-less .glyphicon-picture:before {
884
+ content: "\e060";
885
+ }
886
+ .sg-wrapper-less .glyphicon-map-marker:before {
887
+ content: "\e062";
888
+ }
889
+ .sg-wrapper-less .glyphicon-adjust:before {
890
+ content: "\e063";
891
+ }
892
+ .sg-wrapper-less .glyphicon-tint:before {
893
+ content: "\e064";
894
+ }
895
+ .sg-wrapper-less .glyphicon-edit:before {
896
+ content: "\e065";
897
+ }
898
+ .sg-wrapper-less .glyphicon-share:before {
899
+ content: "\e066";
900
+ }
901
+ .sg-wrapper-less .glyphicon-check:before {
902
+ content: "\e067";
903
+ }
904
+ .sg-wrapper-less .glyphicon-move:before {
905
+ content: "\e068";
906
+ }
907
+ .sg-wrapper-less .glyphicon-step-backward:before {
908
+ content: "\e069";
909
+ }
910
+ .sg-wrapper-less .glyphicon-fast-backward:before {
911
+ content: "\e070";
912
+ }
913
+ .sg-wrapper-less .glyphicon-backward:before {
914
+ content: "\e071";
915
+ }
916
+ .sg-wrapper-less .glyphicon-play:before {
917
+ content: "\e072";
918
+ }
919
+ .sg-wrapper-less .glyphicon-pause:before {
920
+ content: "\e073";
921
+ }
922
+ .sg-wrapper-less .glyphicon-stop:before {
923
+ content: "\e074";
924
+ }
925
+ .sg-wrapper-less .glyphicon-forward:before {
926
+ content: "\e075";
927
+ }
928
+ .sg-wrapper-less .glyphicon-fast-forward:before {
929
+ content: "\e076";
930
+ }
931
+ .sg-wrapper-less .glyphicon-step-forward:before {
932
+ content: "\e077";
933
+ }
934
+ .sg-wrapper-less .glyphicon-eject:before {
935
+ content: "\e078";
936
+ }
937
+ .sg-wrapper-less .glyphicon-chevron-left:before {
938
+ content: "\e079";
939
+ }
940
+ .sg-wrapper-less .glyphicon-chevron-right:before {
941
+ content: "\e080";
942
+ }
943
+ .sg-wrapper-less .glyphicon-plus-sign:before {
944
+ content: "\e081";
945
+ }
946
+ .sg-wrapper-less .glyphicon-minus-sign:before {
947
+ content: "\e082";
948
+ }
949
+ .sg-wrapper-less .glyphicon-remove-sign:before {
950
+ content: "\e083";
951
+ }
952
+ .sg-wrapper-less .glyphicon-ok-sign:before {
953
+ content: "\e084";
954
+ }
955
+ .sg-wrapper-less .glyphicon-question-sign:before {
956
+ content: "\e085";
957
+ }
958
+ .sg-wrapper-less .glyphicon-info-sign:before {
959
+ content: "\e086";
960
+ }
961
+ .sg-wrapper-less .glyphicon-screenshot:before {
962
+ content: "\e087";
963
+ }
964
+ .sg-wrapper-less .glyphicon-remove-circle:before {
965
+ content: "\e088";
966
+ }
967
+ .sg-wrapper-less .glyphicon-ok-circle:before {
968
+ content: "\e089";
969
+ }
970
+ .sg-wrapper-less .glyphicon-ban-circle:before {
971
+ content: "\e090";
972
+ }
973
+ .sg-wrapper-less .glyphicon-arrow-left:before {
974
+ content: "\e091";
975
+ }
976
+ .sg-wrapper-less .glyphicon-arrow-right:before {
977
+ content: "\e092";
978
+ }
979
+ .sg-wrapper-less .glyphicon-arrow-up:before {
980
+ content: "\e093";
981
+ }
982
+ .sg-wrapper-less .glyphicon-arrow-down:before {
983
+ content: "\e094";
984
+ }
985
+ .sg-wrapper-less .glyphicon-share-alt:before {
986
+ content: "\e095";
987
+ }
988
+ .sg-wrapper-less .glyphicon-resize-full:before {
989
+ content: "\e096";
990
+ }
991
+ .sg-wrapper-less .glyphicon-resize-small:before {
992
+ content: "\e097";
993
+ }
994
+ .sg-wrapper-less .glyphicon-exclamation-sign:before {
995
+ content: "\e101";
996
+ }
997
+ .sg-wrapper-less .glyphicon-gift:before {
998
+ content: "\e102";
999
+ }
1000
+ .sg-wrapper-less .glyphicon-leaf:before {
1001
+ content: "\e103";
1002
+ }
1003
+ .sg-wrapper-less .glyphicon-fire:before {
1004
+ content: "\e104";
1005
+ }
1006
+ .sg-wrapper-less .glyphicon-eye-open:before {
1007
+ content: "\e105";
1008
+ }
1009
+ .sg-wrapper-less .glyphicon-eye-close:before {
1010
+ content: "\e106";
1011
+ }
1012
+ .sg-wrapper-less .glyphicon-warning-sign:before {
1013
+ content: "\e107";
1014
+ }
1015
+ .sg-wrapper-less .glyphicon-plane:before {
1016
+ content: "\e108";
1017
+ }
1018
+ .sg-wrapper-less .glyphicon-calendar:before {
1019
+ content: "\e109";
1020
+ }
1021
+ .sg-wrapper-less .glyphicon-random:before {
1022
+ content: "\e110";
1023
+ }
1024
+ .sg-wrapper-less .glyphicon-comment:before {
1025
+ content: "\e111";
1026
+ }
1027
+ .sg-wrapper-less .glyphicon-magnet:before {
1028
+ content: "\e112";
1029
+ }
1030
+ .sg-wrapper-less .glyphicon-chevron-up:before {
1031
+ content: "\e113";
1032
+ }
1033
+ .sg-wrapper-less .glyphicon-chevron-down:before {
1034
+ content: "\e114";
1035
+ }
1036
+ .sg-wrapper-less .glyphicon-retweet:before {
1037
+ content: "\e115";
1038
+ }
1039
+ .sg-wrapper-less .glyphicon-shopping-cart:before {
1040
+ content: "\e116";
1041
+ }
1042
+ .sg-wrapper-less .glyphicon-folder-close:before {
1043
+ content: "\e117";
1044
+ }
1045
+ .sg-wrapper-less .glyphicon-folder-open:before {
1046
+ content: "\e118";
1047
+ }
1048
+ .sg-wrapper-less .glyphicon-resize-vertical:before {
1049
+ content: "\e119";
1050
+ }
1051
+ .sg-wrapper-less .glyphicon-resize-horizontal:before {
1052
+ content: "\e120";
1053
+ }
1054
+ .sg-wrapper-less .glyphicon-hdd:before {
1055
+ content: "\e121";
1056
+ }
1057
+ .sg-wrapper-less .glyphicon-bullhorn:before {
1058
+ content: "\e122";
1059
+ }
1060
+ .sg-wrapper-less .glyphicon-bell:before {
1061
+ content: "\e123";
1062
+ }
1063
+ .sg-wrapper-less .glyphicon-certificate:before {
1064
+ content: "\e124";
1065
+ }
1066
+ .sg-wrapper-less .glyphicon-thumbs-up:before {
1067
+ content: "\e125";
1068
+ }
1069
+ .sg-wrapper-less .glyphicon-thumbs-down:before {
1070
+ content: "\e126";
1071
+ }
1072
+ .sg-wrapper-less .glyphicon-hand-right:before {
1073
+ content: "\e127";
1074
+ }
1075
+ .sg-wrapper-less .glyphicon-hand-left:before {
1076
+ content: "\e128";
1077
+ }
1078
+ .sg-wrapper-less .glyphicon-hand-up:before {
1079
+ content: "\e129";
1080
+ }
1081
+ .sg-wrapper-less .glyphicon-hand-down:before {
1082
+ content: "\e130";
1083
+ }
1084
+ .sg-wrapper-less .glyphicon-circle-arrow-right:before {
1085
+ content: "\e131";
1086
+ }
1087
+ .sg-wrapper-less .glyphicon-circle-arrow-left:before {
1088
+ content: "\e132";
1089
+ }
1090
+ .sg-wrapper-less .glyphicon-circle-arrow-up:before {
1091
+ content: "\e133";
1092
+ }
1093
+ .sg-wrapper-less .glyphicon-circle-arrow-down:before {
1094
+ content: "\e134";
1095
+ }
1096
+ .sg-wrapper-less .glyphicon-globe:before {
1097
+ content: "\e135";
1098
+ }
1099
+ .sg-wrapper-less .glyphicon-wrench:before {
1100
+ content: "\e136";
1101
+ }
1102
+ .sg-wrapper-less .glyphicon-tasks:before {
1103
+ content: "\e137";
1104
+ }
1105
+ .sg-wrapper-less .glyphicon-filter:before {
1106
+ content: "\e138";
1107
+ }
1108
+ .sg-wrapper-less .glyphicon-briefcase:before {
1109
+ content: "\e139";
1110
+ }
1111
+ .sg-wrapper-less .glyphicon-fullscreen:before {
1112
+ content: "\e140";
1113
+ }
1114
+ .sg-wrapper-less .glyphicon-dashboard:before {
1115
+ content: "\e141";
1116
+ }
1117
+ .sg-wrapper-less .glyphicon-paperclip:before {
1118
+ content: "\e142";
1119
+ }
1120
+ .sg-wrapper-less .glyphicon-heart-empty:before {
1121
+ content: "\e143";
1122
+ }
1123
+ .sg-wrapper-less .glyphicon-link:before {
1124
+ content: "\e144";
1125
+ }
1126
+ .sg-wrapper-less .glyphicon-phone:before {
1127
+ content: "\e145";
1128
+ }
1129
+ .sg-wrapper-less .glyphicon-pushpin:before {
1130
+ content: "\e146";
1131
+ }
1132
+ .sg-wrapper-less .glyphicon-usd:before {
1133
+ content: "\e148";
1134
+ }
1135
+ .sg-wrapper-less .glyphicon-gbp:before {
1136
+ content: "\e149";
1137
+ }
1138
+ .sg-wrapper-less .glyphicon-sort:before {
1139
+ content: "\e150";
1140
+ }
1141
+ .sg-wrapper-less .glyphicon-sort-by-alphabet:before {
1142
+ content: "\e151";
1143
+ }
1144
+ .sg-wrapper-less .glyphicon-sort-by-alphabet-alt:before {
1145
+ content: "\e152";
1146
+ }
1147
+ .sg-wrapper-less .glyphicon-sort-by-order:before {
1148
+ content: "\e153";
1149
+ }
1150
+ .sg-wrapper-less .glyphicon-sort-by-order-alt:before {
1151
+ content: "\e154";
1152
+ }
1153
+ .sg-wrapper-less .glyphicon-sort-by-attributes:before {
1154
+ content: "\e155";
1155
+ }
1156
+ .sg-wrapper-less .glyphicon-sort-by-attributes-alt:before {
1157
+ content: "\e156";
1158
+ }
1159
+ .sg-wrapper-less .glyphicon-unchecked:before {
1160
+ content: "\e157";
1161
+ }
1162
+ .sg-wrapper-less .glyphicon-expand:before {
1163
+ content: "\e158";
1164
+ }
1165
+ .sg-wrapper-less .glyphicon-collapse-down:before {
1166
+ content: "\e159";
1167
+ }
1168
+ .sg-wrapper-less .glyphicon-collapse-up:before {
1169
+ content: "\e160";
1170
+ }
1171
+ .sg-wrapper-less .glyphicon-log-in:before {
1172
+ content: "\e161";
1173
+ }
1174
+ .sg-wrapper-less .glyphicon-flash:before {
1175
+ content: "\e162";
1176
+ }
1177
+ .sg-wrapper-less .glyphicon-log-out:before {
1178
+ content: "\e163";
1179
+ }
1180
+ .sg-wrapper-less .glyphicon-new-window:before {
1181
+ content: "\e164";
1182
+ }
1183
+ .sg-wrapper-less .glyphicon-record:before {
1184
+ content: "\e165";
1185
+ }
1186
+ .sg-wrapper-less .glyphicon-save:before {
1187
+ content: "\e166";
1188
+ }
1189
+ .sg-wrapper-less .glyphicon-open:before {
1190
+ content: "\e167";
1191
+ }
1192
+ .sg-wrapper-less .glyphicon-saved:before {
1193
+ content: "\e168";
1194
+ }
1195
+ .sg-wrapper-less .glyphicon-import:before {
1196
+ content: "\e169";
1197
+ }
1198
+ .sg-wrapper-less .glyphicon-export:before {
1199
+ content: "\e170";
1200
+ }
1201
+ .sg-wrapper-less .glyphicon-send:before {
1202
+ content: "\e171";
1203
+ }
1204
+ .sg-wrapper-less .glyphicon-floppy-disk:before {
1205
+ content: "\e172";
1206
+ }
1207
+ .sg-wrapper-less .glyphicon-floppy-saved:before {
1208
+ content: "\e173";
1209
+ }
1210
+ .sg-wrapper-less .glyphicon-floppy-remove:before {
1211
+ content: "\e174";
1212
+ }
1213
+ .sg-wrapper-less .glyphicon-floppy-save:before {
1214
+ content: "\e175";
1215
+ }
1216
+ .sg-wrapper-less .glyphicon-floppy-open:before {
1217
+ content: "\e176";
1218
+ }
1219
+ .sg-wrapper-less .glyphicon-credit-card:before {
1220
+ content: "\e177";
1221
+ }
1222
+ .sg-wrapper-less .glyphicon-transfer:before {
1223
+ content: "\e178";
1224
+ }
1225
+ .sg-wrapper-less .glyphicon-cutlery:before {
1226
+ content: "\e179";
1227
+ }
1228
+ .sg-wrapper-less .glyphicon-header:before {
1229
+ content: "\e180";
1230
+ }
1231
+ .sg-wrapper-less .glyphicon-compressed:before {
1232
+ content: "\e181";
1233
+ }
1234
+ .sg-wrapper-less .glyphicon-earphone:before {
1235
+ content: "\e182";
1236
+ }
1237
+ .sg-wrapper-less .glyphicon-phone-alt:before {
1238
+ content: "\e183";
1239
+ }
1240
+ .sg-wrapper-less .glyphicon-tower:before {
1241
+ content: "\e184";
1242
+ }
1243
+ .sg-wrapper-less .glyphicon-stats:before {
1244
+ content: "\e185";
1245
+ }
1246
+ .sg-wrapper-less .glyphicon-sd-video:before {
1247
+ content: "\e186";
1248
+ }
1249
+ .sg-wrapper-less .glyphicon-hd-video:before {
1250
+ content: "\e187";
1251
+ }
1252
+ .sg-wrapper-less .glyphicon-subtitles:before {
1253
+ content: "\e188";
1254
+ }
1255
+ .sg-wrapper-less .glyphicon-sound-stereo:before {
1256
+ content: "\e189";
1257
+ }
1258
+ .sg-wrapper-less .glyphicon-sound-dolby:before {
1259
+ content: "\e190";
1260
+ }
1261
+ .sg-wrapper-less .glyphicon-sound-5-1:before {
1262
+ content: "\e191";
1263
+ }
1264
+ .sg-wrapper-less .glyphicon-sound-6-1:before {
1265
+ content: "\e192";
1266
+ }
1267
+ .sg-wrapper-less .glyphicon-sound-7-1:before {
1268
+ content: "\e193";
1269
+ }
1270
+ .sg-wrapper-less .glyphicon-copyright-mark:before {
1271
+ content: "\e194";
1272
+ }
1273
+ .sg-wrapper-less .glyphicon-registration-mark:before {
1274
+ content: "\e195";
1275
+ }
1276
+ .sg-wrapper-less .glyphicon-cloud-download:before {
1277
+ content: "\e197";
1278
+ }
1279
+ .sg-wrapper-less .glyphicon-cloud-upload:before {
1280
+ content: "\e198";
1281
+ }
1282
+ .sg-wrapper-less .glyphicon-tree-conifer:before {
1283
+ content: "\e199";
1284
+ }
1285
+ .sg-wrapper-less .glyphicon-tree-deciduous:before {
1286
+ content: "\e200";
1287
+ }
1288
+ .sg-wrapper-less .glyphicon-cd:before {
1289
+ content: "\e201";
1290
+ }
1291
+ .sg-wrapper-less .glyphicon-save-file:before {
1292
+ content: "\e202";
1293
+ }
1294
+ .sg-wrapper-less .glyphicon-open-file:before {
1295
+ content: "\e203";
1296
+ }
1297
+ .sg-wrapper-less .glyphicon-level-up:before {
1298
+ content: "\e204";
1299
+ }
1300
+ .sg-wrapper-less .glyphicon-copy:before {
1301
+ content: "\e205";
1302
+ }
1303
+ .sg-wrapper-less .glyphicon-paste:before {
1304
+ content: "\e206";
1305
+ }
1306
+ .sg-wrapper-less .glyphicon-alert:before {
1307
+ content: "\e209";
1308
+ }
1309
+ .sg-wrapper-less .glyphicon-equalizer:before {
1310
+ content: "\e210";
1311
+ }
1312
+ .sg-wrapper-less .glyphicon-king:before {
1313
+ content: "\e211";
1314
+ }
1315
+ .sg-wrapper-less .glyphicon-queen:before {
1316
+ content: "\e212";
1317
+ }
1318
+ .sg-wrapper-less .glyphicon-pawn:before {
1319
+ content: "\e213";
1320
+ }
1321
+ .sg-wrapper-less .glyphicon-bishop:before {
1322
+ content: "\e214";
1323
+ }
1324
+ .sg-wrapper-less .glyphicon-knight:before {
1325
+ content: "\e215";
1326
+ }
1327
+ .sg-wrapper-less .glyphicon-baby-formula:before {
1328
+ content: "\e216";
1329
+ }
1330
+ .sg-wrapper-less .glyphicon-tent:before {
1331
+ content: "\26fa";
1332
+ }
1333
+ .sg-wrapper-less .glyphicon-blackboard:before {
1334
+ content: "\e218";
1335
+ }
1336
+ .sg-wrapper-less .glyphicon-bed:before {
1337
+ content: "\e219";
1338
+ }
1339
+ .sg-wrapper-less .glyphicon-apple:before {
1340
+ content: "\f8ff";
1341
+ }
1342
+ .sg-wrapper-less .glyphicon-erase:before {
1343
+ content: "\e221";
1344
+ }
1345
+ .sg-wrapper-less .glyphicon-hourglass:before {
1346
+ content: "\231b";
1347
+ }
1348
+ .sg-wrapper-less .glyphicon-lamp:before {
1349
+ content: "\e223";
1350
+ }
1351
+ .sg-wrapper-less .glyphicon-duplicate:before {
1352
+ content: "\e224";
1353
+ }
1354
+ .sg-wrapper-less .glyphicon-piggy-bank:before {
1355
+ content: "\e225";
1356
+ }
1357
+ .sg-wrapper-less .glyphicon-scissors:before {
1358
+ content: "\e226";
1359
+ }
1360
+ .sg-wrapper-less .glyphicon-bitcoin:before {
1361
+ content: "\e227";
1362
+ }
1363
+ .sg-wrapper-less .glyphicon-btc:before {
1364
+ content: "\e227";
1365
+ }
1366
+ .sg-wrapper-less .glyphicon-xbt:before {
1367
+ content: "\e227";
1368
+ }
1369
+ .sg-wrapper-less .glyphicon-yen:before {
1370
+ content: "\00a5";
1371
+ }
1372
+ .sg-wrapper-less .glyphicon-jpy:before {
1373
+ content: "\00a5";
1374
+ }
1375
+ .sg-wrapper-less .glyphicon-ruble:before {
1376
+ content: "\20bd";
1377
+ }
1378
+ .sg-wrapper-less .glyphicon-rub:before {
1379
+ content: "\20bd";
1380
+ }
1381
+ .sg-wrapper-less .glyphicon-scale:before {
1382
+ content: "\e230";
1383
+ }
1384
+ .sg-wrapper-less .glyphicon-ice-lolly:before {
1385
+ content: "\e231";
1386
+ }
1387
+ .sg-wrapper-less .glyphicon-ice-lolly-tasted:before {
1388
+ content: "\e232";
1389
+ }
1390
+ .sg-wrapper-less .glyphicon-education:before {
1391
+ content: "\e233";
1392
+ }
1393
+ .sg-wrapper-less .glyphicon-option-horizontal:before {
1394
+ content: "\e234";
1395
+ }
1396
+ .sg-wrapper-less .glyphicon-option-vertical:before {
1397
+ content: "\e235";
1398
+ }
1399
+ .sg-wrapper-less .glyphicon-menu-hamburger:before {
1400
+ content: "\e236";
1401
+ }
1402
+ .sg-wrapper-less .glyphicon-modal-window:before {
1403
+ content: "\e237";
1404
+ }
1405
+ .sg-wrapper-less .glyphicon-oil:before {
1406
+ content: "\e238";
1407
+ }
1408
+ .sg-wrapper-less .glyphicon-grain:before {
1409
+ content: "\e239";
1410
+ }
1411
+ .sg-wrapper-less .glyphicon-sunglasses:before {
1412
+ content: "\e240";
1413
+ }
1414
+ .sg-wrapper-less .glyphicon-text-size:before {
1415
+ content: "\e241";
1416
+ }
1417
+ .sg-wrapper-less .glyphicon-text-color:before {
1418
+ content: "\e242";
1419
+ }
1420
+ .sg-wrapper-less .glyphicon-text-background:before {
1421
+ content: "\e243";
1422
+ }
1423
+ .sg-wrapper-less .glyphicon-object-align-top:before {
1424
+ content: "\e244";
1425
+ }
1426
+ .sg-wrapper-less .glyphicon-object-align-bottom:before {
1427
+ content: "\e245";
1428
+ }
1429
+ .sg-wrapper-less .glyphicon-object-align-horizontal:before {
1430
+ content: "\e246";
1431
+ }
1432
+ .sg-wrapper-less .glyphicon-object-align-left:before {
1433
+ content: "\e247";
1434
+ }
1435
+ .sg-wrapper-less .glyphicon-object-align-vertical:before {
1436
+ content: "\e248";
1437
+ }
1438
+ .sg-wrapper-less .glyphicon-object-align-right:before {
1439
+ content: "\e249";
1440
+ }
1441
+ .sg-wrapper-less .glyphicon-triangle-right:before {
1442
+ content: "\e250";
1443
+ }
1444
+ .sg-wrapper-less .glyphicon-triangle-left:before {
1445
+ content: "\e251";
1446
+ }
1447
+ .sg-wrapper-less .glyphicon-triangle-bottom:before {
1448
+ content: "\e252";
1449
+ }
1450
+ .sg-wrapper-less .glyphicon-triangle-top:before {
1451
+ content: "\e253";
1452
+ }
1453
+ .sg-wrapper-less .glyphicon-console:before {
1454
+ content: "\e254";
1455
+ }
1456
+ .sg-wrapper-less .glyphicon-superscript:before {
1457
+ content: "\e255";
1458
+ }
1459
+ .sg-wrapper-less .glyphicon-subscript:before {
1460
+ content: "\e256";
1461
+ }
1462
+ .sg-wrapper-less .glyphicon-menu-left:before {
1463
+ content: "\e257";
1464
+ }
1465
+ .sg-wrapper-less .glyphicon-menu-right:before {
1466
+ content: "\e258";
1467
+ }
1468
+ .sg-wrapper-less .glyphicon-menu-down:before {
1469
+ content: "\e259";
1470
+ }
1471
+ .sg-wrapper-less .glyphicon-menu-up:before {
1472
+ content: "\e260";
1473
+ }
1474
+ .sg-wrapper-less * {
1475
+ -webkit-box-sizing: border-box;
1476
+ -moz-box-sizing: border-box;
1477
+ box-sizing: border-box;
1478
+ }
1479
+ .sg-wrapper-less *:before,
1480
+ .sg-wrapper-less *:after {
1481
+ -webkit-box-sizing: border-box;
1482
+ -moz-box-sizing: border-box;
1483
+ box-sizing: border-box;
1484
+ }
1485
+ .sg-wrapper-less html {
1486
+ font-size: 10px;
1487
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
1488
+ }
1489
+ .sg-wrapper-less #sg-wrapper {
1490
+ font-family: "Source Sans Pro", Calibri, Candara, Arial, sans-serif;
1491
+ font-size: 15px;
1492
+ line-height: 1.42857143;
1493
+ color: #333333;
1494
+ background-color: #ffffff;
1495
+ }
1496
+ .sg-wrapper-less input,
1497
+ .sg-wrapper-less button,
1498
+ .sg-wrapper-less select,
1499
+ .sg-wrapper-less textarea {
1500
+ font-family: inherit;
1501
+ font-size: inherit;
1502
+ line-height: inherit;
1503
+ }
1504
+ .sg-wrapper-less a {
1505
+ color: #2780e3;
1506
+ text-decoration: none;
1507
+ }
1508
+ .sg-wrapper-less a:hover,
1509
+ .sg-wrapper-less a:focus {
1510
+ color: #165ba8;
1511
+ text-decoration: underline;
1512
+ }
1513
+ .sg-wrapper-less a:focus {
1514
+ outline: thin dotted;
1515
+ outline: 5px auto -webkit-focus-ring-color;
1516
+ outline-offset: -2px;
1517
+ }
1518
+ .sg-wrapper-less figure {
1519
+ margin: 0;
1520
+ }
1521
+ .sg-wrapper-less img {
1522
+ vertical-align: middle;
1523
+ }
1524
+ .sg-wrapper-less .img-responsive,
1525
+ .sg-wrapper-less .thumbnail > img,
1526
+ .sg-wrapper-less .thumbnail a > img,
1527
+ .sg-wrapper-less .carousel-inner > .item > img,
1528
+ .sg-wrapper-less .carousel-inner > .item > a > img {
1529
+ display: block;
1530
+ max-width: 100%;
1531
+ height: auto;
1532
+ }
1533
+ .sg-wrapper-less .img-rounded {
1534
+ border-radius: 0;
1535
+ }
1536
+ .sg-wrapper-less .img-thumbnail {
1537
+ padding: 4px;
1538
+ line-height: 1.42857143;
1539
+ background-color: #ffffff;
1540
+ border: 1px solid #dddddd;
1541
+ border-radius: 0;
1542
+ -webkit-transition: all 0.2s ease-in-out;
1543
+ -o-transition: all 0.2s ease-in-out;
1544
+ transition: all 0.2s ease-in-out;
1545
+ display: inline-block;
1546
+ max-width: 100%;
1547
+ height: auto;
1548
+ }
1549
+ .sg-wrapper-less .img-circle {
1550
+ border-radius: 50%;
1551
+ }
1552
+ .sg-wrapper-less hr {
1553
+ margin-top: 21px;
1554
+ margin-bottom: 21px;
1555
+ border: 0;
1556
+ border-top: 1px solid #e6e6e6;
1557
+ }
1558
+ .sg-wrapper-less .sr-only {
1559
+ position: absolute;
1560
+ width: 1px;
1561
+ height: 1px;
1562
+ margin: -1px;
1563
+ padding: 0;
1564
+ overflow: hidden;
1565
+ clip: rect(0, 0, 0, 0);
1566
+ border: 0;
1567
+ }
1568
+ .sg-wrapper-less .sr-only-focusable:active,
1569
+ .sg-wrapper-less .sr-only-focusable:focus {
1570
+ position: static;
1571
+ width: auto;
1572
+ height: auto;
1573
+ margin: 0;
1574
+ overflow: visible;
1575
+ clip: auto;
1576
+ }
1577
+ .sg-wrapper-less [role="button"] {
1578
+ cursor: pointer;
1579
+ }
1580
+ .sg-wrapper-less h1,
1581
+ .sg-wrapper-less h2,
1582
+ .sg-wrapper-less h3,
1583
+ .sg-wrapper-less h4,
1584
+ .sg-wrapper-less h5,
1585
+ .sg-wrapper-less h6,
1586
+ .sg-wrapper-less .h1,
1587
+ .sg-wrapper-less .h2,
1588
+ .sg-wrapper-less .h3,
1589
+ .sg-wrapper-less .h4,
1590
+ .sg-wrapper-less .h5,
1591
+ .sg-wrapper-less .h6 {
1592
+ font-family: "Source Sans Pro", Calibri, Candara, Arial, sans-serif;
1593
+ font-weight: 300;
1594
+ line-height: 1.1;
1595
+ color: inherit;
1596
+ }
1597
+ .sg-wrapper-less h1 small,
1598
+ .sg-wrapper-less h2 small,
1599
+ .sg-wrapper-less h3 small,
1600
+ .sg-wrapper-less h4 small,
1601
+ .sg-wrapper-less h5 small,
1602
+ .sg-wrapper-less h6 small,
1603
+ .sg-wrapper-less .h1 small,
1604
+ .sg-wrapper-less .h2 small,
1605
+ .sg-wrapper-less .h3 small,
1606
+ .sg-wrapper-less .h4 small,
1607
+ .sg-wrapper-less .h5 small,
1608
+ .sg-wrapper-less .h6 small,
1609
+ .sg-wrapper-less h1 .small,
1610
+ .sg-wrapper-less h2 .small,
1611
+ .sg-wrapper-less h3 .small,
1612
+ .sg-wrapper-less h4 .small,
1613
+ .sg-wrapper-less h5 .small,
1614
+ .sg-wrapper-less h6 .small,
1615
+ .sg-wrapper-less .h1 .small,
1616
+ .sg-wrapper-less .h2 .small,
1617
+ .sg-wrapper-less .h3 .small,
1618
+ .sg-wrapper-less .h4 .small,
1619
+ .sg-wrapper-less .h5 .small,
1620
+ .sg-wrapper-less .h6 .small {
1621
+ font-weight: normal;
1622
+ line-height: 1;
1623
+ color: #999999;
1624
+ }
1625
+ .sg-wrapper-less h1,
1626
+ .sg-wrapper-less .h1,
1627
+ .sg-wrapper-less h2,
1628
+ .sg-wrapper-less .h2,
1629
+ .sg-wrapper-less h3,
1630
+ .sg-wrapper-less .h3 {
1631
+ margin-top: 21px;
1632
+ margin-bottom: 10.5px;
1633
+ }
1634
+ .sg-wrapper-less h1 small,
1635
+ .sg-wrapper-less .h1 small,
1636
+ .sg-wrapper-less h2 small,
1637
+ .sg-wrapper-less .h2 small,
1638
+ .sg-wrapper-less h3 small,
1639
+ .sg-wrapper-less .h3 small,
1640
+ .sg-wrapper-less h1 .small,
1641
+ .sg-wrapper-less .h1 .small,
1642
+ .sg-wrapper-less h2 .small,
1643
+ .sg-wrapper-less .h2 .small,
1644
+ .sg-wrapper-less h3 .small,
1645
+ .sg-wrapper-less .h3 .small {
1646
+ font-size: 65%;
1647
+ }
1648
+ .sg-wrapper-less h4,
1649
+ .sg-wrapper-less .h4,
1650
+ .sg-wrapper-less h5,
1651
+ .sg-wrapper-less .h5,
1652
+ .sg-wrapper-less h6,
1653
+ .sg-wrapper-less .h6 {
1654
+ margin-top: 10.5px;
1655
+ margin-bottom: 10.5px;
1656
+ }
1657
+ .sg-wrapper-less h4 small,
1658
+ .sg-wrapper-less .h4 small,
1659
+ .sg-wrapper-less h5 small,
1660
+ .sg-wrapper-less .h5 small,
1661
+ .sg-wrapper-less h6 small,
1662
+ .sg-wrapper-less .h6 small,
1663
+ .sg-wrapper-less h4 .small,
1664
+ .sg-wrapper-less .h4 .small,
1665
+ .sg-wrapper-less h5 .small,
1666
+ .sg-wrapper-less .h5 .small,
1667
+ .sg-wrapper-less h6 .small,
1668
+ .sg-wrapper-less .h6 .small {
1669
+ font-size: 75%;
1670
+ }
1671
+ .sg-wrapper-less h1,
1672
+ .sg-wrapper-less .h1 {
1673
+ font-size: 39px;
1674
+ }
1675
+ .sg-wrapper-less h2,
1676
+ .sg-wrapper-less .h2 {
1677
+ font-size: 32px;
1678
+ }
1679
+ .sg-wrapper-less h3,
1680
+ .sg-wrapper-less .h3 {
1681
+ font-size: 26px;
1682
+ }
1683
+ .sg-wrapper-less h4,
1684
+ .sg-wrapper-less .h4 {
1685
+ font-size: 19px;
1686
+ }
1687
+ .sg-wrapper-less h5,
1688
+ .sg-wrapper-less .h5 {
1689
+ font-size: 15px;
1690
+ }
1691
+ .sg-wrapper-less h6,
1692
+ .sg-wrapper-less .h6 {
1693
+ font-size: 13px;
1694
+ }
1695
+ .sg-wrapper-less p {
1696
+ margin: 0 0 9.5px;
1697
+ }
1698
+ .sg-wrapper-less .lead {
1699
+ margin-bottom: 21px;
1700
+ font-size: 17px;
1701
+ font-weight: 300;
1702
+ line-height: 1.4;
1703
+ }
1704
+ @media (min-width: 768px) {
1705
+ .sg-wrapper-less .lead {
1706
+ font-size: 22.5px;
1707
+ }
1708
+ }
1709
+ .sg-wrapper-less small,
1710
+ .sg-wrapper-less .small {
1711
+ font-size: 86%;
1712
+ }
1713
+ .sg-wrapper-less mark,
1714
+ .sg-wrapper-less .mark {
1715
+ background-color: #ff7518;
1716
+ padding: .2em;
1717
+ }
1718
+ .sg-wrapper-less .text-left {
1719
+ text-align: left;
1720
+ }
1721
+ .sg-wrapper-less .text-right {
1722
+ text-align: right;
1723
+ }
1724
+ .sg-wrapper-less .text-center {
1725
+ text-align: center;
1726
+ }
1727
+ .sg-wrapper-less .text-justify {
1728
+ text-align: justify;
1729
+ }
1730
+ .sg-wrapper-less .text-nowrap {
1731
+ white-space: nowrap;
1732
+ }
1733
+ .sg-wrapper-less .text-lowercase {
1734
+ text-transform: lowercase;
1735
+ }
1736
+ .sg-wrapper-less .text-uppercase {
1737
+ text-transform: uppercase;
1738
+ }
1739
+ .sg-wrapper-less .text-capitalize {
1740
+ text-transform: capitalize;
1741
+ }
1742
+ .sg-wrapper-less .text-muted {
1743
+ color: #999999;
1744
+ }
1745
+ .sg-wrapper-less .text-primary {
1746
+ color: #2780e3;
1747
+ }
1748
+ .sg-wrapper-less a.text-primary:hover {
1749
+ color: #1967be;
1750
+ }
1751
+ .sg-wrapper-less .text-success {
1752
+ color: #ffffff;
1753
+ }
1754
+ .sg-wrapper-less a.text-success:hover {
1755
+ color: #e6e6e6;
1756
+ }
1757
+ .sg-wrapper-less .text-info {
1758
+ color: #ffffff;
1759
+ }
1760
+ .sg-wrapper-less a.text-info:hover {
1761
+ color: #e6e6e6;
1762
+ }
1763
+ .sg-wrapper-less .text-warning {
1764
+ color: #ffffff;
1765
+ }
1766
+ .sg-wrapper-less a.text-warning:hover {
1767
+ color: #e6e6e6;
1768
+ }
1769
+ .sg-wrapper-less .text-danger {
1770
+ color: #ffffff;
1771
+ }
1772
+ .sg-wrapper-less a.text-danger:hover {
1773
+ color: #e6e6e6;
1774
+ }
1775
+ .sg-wrapper-less .bg-primary {
1776
+ color: #fff;
1777
+ background-color: #2780e3;
1778
+ }
1779
+ .sg-wrapper-less a.bg-primary:hover {
1780
+ background-color: #1967be;
1781
+ }
1782
+ .sg-wrapper-less .bg-success {
1783
+ background-color: #3fb618;
1784
+ }
1785
+ .sg-wrapper-less a.bg-success:hover {
1786
+ background-color: #2f8912;
1787
+ }
1788
+ .sg-wrapper-less .bg-info {
1789
+ background-color: #9954bb;
1790
+ }
1791
+ .sg-wrapper-less a.bg-info:hover {
1792
+ background-color: #7e3f9d;
1793
+ }
1794
+ .sg-wrapper-less .bg-warning {
1795
+ background-color: #ff7518;
1796
+ }
1797
+ .sg-wrapper-less a.bg-warning:hover {
1798
+ background-color: #e45c00;
1799
+ }
1800
+ .sg-wrapper-less .bg-danger {
1801
+ background-color: #ff0039;
1802
+ }
1803
+ .sg-wrapper-less a.bg-danger:hover {
1804
+ background-color: #cc002e;
1805
+ }
1806
+ .sg-wrapper-less .page-header {
1807
+ padding-bottom: 9.5px;
1808
+ margin: 42px 0 21px;
1809
+ border-bottom: 1px solid #e6e6e6;
1810
+ }
1811
+ .sg-wrapper-less ul,
1812
+ .sg-wrapper-less ol {
1813
+ margin-top: 0;
1814
+ margin-bottom: 10.5px;
1815
+ }
1816
+ .sg-wrapper-less ul ul,
1817
+ .sg-wrapper-less ol ul,
1818
+ .sg-wrapper-less ul ol,
1819
+ .sg-wrapper-less ol ol {
1820
+ margin-bottom: 0;
1821
+ }
1822
+ .sg-wrapper-less .list-unstyled {
1823
+ padding-left: 0;
1824
+ list-style: none;
1825
+ }
1826
+ .sg-wrapper-less .list-inline {
1827
+ padding-left: 0;
1828
+ list-style: none;
1829
+ margin-left: -5px;
1830
+ }
1831
+ .sg-wrapper-less .list-inline > li {
1832
+ display: inline-block;
1833
+ padding-left: 5px;
1834
+ padding-right: 5px;
1835
+ }
1836
+ .sg-wrapper-less dl {
1837
+ margin-top: 0;
1838
+ margin-bottom: 21px;
1839
+ }
1840
+ .sg-wrapper-less dt,
1841
+ .sg-wrapper-less dd {
1842
+ line-height: 1.42857143;
1843
+ }
1844
+ .sg-wrapper-less dt {
1845
+ font-weight: bold;
1846
+ }
1847
+ .sg-wrapper-less dd {
1848
+ margin-left: 0;
1849
+ }
1850
+ @media (min-width: 768px) {
1851
+ .sg-wrapper-less .dl-horizontal dt {
1852
+ float: left;
1853
+ width: 160px;
1854
+ clear: left;
1855
+ text-align: right;
1856
+ overflow: hidden;
1857
+ text-overflow: ellipsis;
1858
+ white-space: nowrap;
1859
+ }
1860
+ .sg-wrapper-less .dl-horizontal dd {
1861
+ margin-left: 180px;
1862
+ }
1863
+ }
1864
+ .sg-wrapper-less abbr[title],
1865
+ .sg-wrapper-less abbr[data-original-title] {
1866
+ cursor: help;
1867
+ border-bottom: 1px dotted #999999;
1868
+ }
1869
+ .sg-wrapper-less .initialism {
1870
+ font-size: 90%;
1871
+ text-transform: uppercase;
1872
+ }
1873
+ .sg-wrapper-less blockquote {
1874
+ padding: 10.5px 21px;
1875
+ margin: 0 0 21px;
1876
+ font-size: 18.75px;
1877
+ border-left: 5px solid #e6e6e6;
1878
+ }
1879
+ .sg-wrapper-less blockquote p:last-child,
1880
+ .sg-wrapper-less blockquote ul:last-child,
1881
+ .sg-wrapper-less blockquote ol:last-child {
1882
+ margin-bottom: 0;
1883
+ }
1884
+ .sg-wrapper-less blockquote footer,
1885
+ .sg-wrapper-less blockquote small,
1886
+ .sg-wrapper-less blockquote .small {
1887
+ display: block;
1888
+ font-size: 80%;
1889
+ line-height: 1.42857143;
1890
+ color: #999999;
1891
+ }
1892
+ .sg-wrapper-less blockquote footer:before,
1893
+ .sg-wrapper-less blockquote small:before,
1894
+ .sg-wrapper-less blockquote .small:before {
1895
+ content: '\2014 \00A0';
1896
+ }
1897
+ .sg-wrapper-less .blockquote-reverse,
1898
+ .sg-wrapper-less blockquote.pull-right {
1899
+ padding-right: 15px;
1900
+ padding-left: 0;
1901
+ border-right: 5px solid #e6e6e6;
1902
+ border-left: 0;
1903
+ text-align: right;
1904
+ }
1905
+ .sg-wrapper-less .blockquote-reverse footer:before,
1906
+ .sg-wrapper-less blockquote.pull-right footer:before,
1907
+ .sg-wrapper-less .blockquote-reverse small:before,
1908
+ .sg-wrapper-less blockquote.pull-right small:before,
1909
+ .sg-wrapper-less .blockquote-reverse .small:before,
1910
+ .sg-wrapper-less blockquote.pull-right .small:before {
1911
+ content: '';
1912
+ }
1913
+ .sg-wrapper-less .blockquote-reverse footer:after,
1914
+ .sg-wrapper-less blockquote.pull-right footer:after,
1915
+ .sg-wrapper-less .blockquote-reverse small:after,
1916
+ .sg-wrapper-less blockquote.pull-right small:after,
1917
+ .sg-wrapper-less .blockquote-reverse .small:after,
1918
+ .sg-wrapper-less blockquote.pull-right .small:after {
1919
+ content: '\00A0 \2014';
1920
+ }
1921
+ .sg-wrapper-less address {
1922
+ margin-bottom: 21px;
1923
+ font-style: normal;
1924
+ line-height: 1.42857143;
1925
+ }
1926
+ .sg-wrapper-less code,
1927
+ .sg-wrapper-less kbd,
1928
+ .sg-wrapper-less pre,
1929
+ .sg-wrapper-less samp {
1930
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
1931
+ }
1932
+ .sg-wrapper-less code {
1933
+ padding: 2px 4px;
1934
+ font-size: 90%;
1935
+ color: #c7254e;
1936
+ background-color: #f9f2f4;
1937
+ border-radius: 0;
1938
+ }
1939
+ .sg-wrapper-less kbd {
1940
+ padding: 2px 4px;
1941
+ font-size: 90%;
1942
+ color: #ffffff;
1943
+ background-color: #333333;
1944
+ border-radius: 0;
1945
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
1946
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
1947
+ }
1948
+ .sg-wrapper-less kbd kbd {
1949
+ padding: 0;
1950
+ font-size: 100%;
1951
+ font-weight: bold;
1952
+ -webkit-box-shadow: none;
1953
+ box-shadow: none;
1954
+ }
1955
+ .sg-wrapper-less pre {
1956
+ display: block;
1957
+ padding: 10px;
1958
+ margin: 0 0 10.5px;
1959
+ font-size: 14px;
1960
+ line-height: 1.42857143;
1961
+ word-break: break-all;
1962
+ word-wrap: break-word;
1963
+ color: #333333;
1964
+ background-color: #f5f5f5;
1965
+ border: 1px solid #cccccc;
1966
+ border-radius: 0;
1967
+ }
1968
+ .sg-wrapper-less pre code {
1969
+ padding: 0;
1970
+ font-size: inherit;
1971
+ color: inherit;
1972
+ white-space: pre-wrap;
1973
+ background-color: transparent;
1974
+ border-radius: 0;
1975
+ }
1976
+ .sg-wrapper-less .pre-scrollable {
1977
+ max-height: 340px;
1978
+ overflow-y: scroll;
1979
+ }
1980
+ .sg-wrapper-less .container {
1981
+ margin-right: auto;
1982
+ margin-left: auto;
1983
+ padding-left: 15px;
1984
+ padding-right: 15px;
1985
+ }
1986
+ @media (min-width: 768px) {
1987
+ .sg-wrapper-less .container {
1988
+ width: 750px;
1989
+ }
1990
+ }
1991
+ @media (min-width: 992px) {
1992
+ .sg-wrapper-less .container {
1993
+ width: 970px;
1994
+ }
1995
+ }
1996
+ @media (min-width: 1200px) {
1997
+ .sg-wrapper-less .container {
1998
+ width: 1170px;
1999
+ }
2000
+ }
2001
+ .sg-wrapper-less .container-fluid {
2002
+ margin-right: auto;
2003
+ margin-left: auto;
2004
+ padding-left: 15px;
2005
+ padding-right: 15px;
2006
+ }
2007
+ .sg-wrapper-less .row {
2008
+ margin-left: -15px;
2009
+ margin-right: -15px;
2010
+ }
2011
+ .sg-wrapper-less .col-xs-1,
2012
+ .sg-wrapper-less .col-sm-1,
2013
+ .sg-wrapper-less .col-md-1,
2014
+ .sg-wrapper-less .col-lg-1,
2015
+ .sg-wrapper-less .col-xs-2,
2016
+ .sg-wrapper-less .col-sm-2,
2017
+ .sg-wrapper-less .col-md-2,
2018
+ .sg-wrapper-less .col-lg-2,
2019
+ .sg-wrapper-less .col-xs-3,
2020
+ .sg-wrapper-less .col-sm-3,
2021
+ .sg-wrapper-less .col-md-3,
2022
+ .sg-wrapper-less .col-lg-3,
2023
+ .sg-wrapper-less .col-xs-4,
2024
+ .sg-wrapper-less .col-sm-4,
2025
+ .sg-wrapper-less .col-md-4,
2026
+ .sg-wrapper-less .col-lg-4,
2027
+ .sg-wrapper-less .col-xs-5,
2028
+ .sg-wrapper-less .col-sm-5,
2029
+ .sg-wrapper-less .col-md-5,
2030
+ .sg-wrapper-less .col-lg-5,
2031
+ .sg-wrapper-less .col-xs-6,
2032
+ .sg-wrapper-less .col-sm-6,
2033
+ .sg-wrapper-less .col-md-6,
2034
+ .sg-wrapper-less .col-lg-6,
2035
+ .sg-wrapper-less .col-xs-7,
2036
+ .sg-wrapper-less .col-sm-7,
2037
+ .sg-wrapper-less .col-md-7,
2038
+ .sg-wrapper-less .col-lg-7,
2039
+ .sg-wrapper-less .col-xs-8,
2040
+ .sg-wrapper-less .col-sm-8,
2041
+ .sg-wrapper-less .col-md-8,
2042
+ .sg-wrapper-less .col-lg-8,
2043
+ .sg-wrapper-less .col-xs-9,
2044
+ .sg-wrapper-less .col-sm-9,
2045
+ .sg-wrapper-less .col-md-9,
2046
+ .sg-wrapper-less .col-lg-9,
2047
+ .sg-wrapper-less .col-xs-10,
2048
+ .sg-wrapper-less .col-sm-10,
2049
+ .sg-wrapper-less .col-md-10,
2050
+ .sg-wrapper-less .col-lg-10,
2051
+ .sg-wrapper-less .col-xs-11,
2052
+ .sg-wrapper-less .col-sm-11,
2053
+ .sg-wrapper-less .col-md-11,
2054
+ .sg-wrapper-less .col-lg-11,
2055
+ .sg-wrapper-less .col-xs-12,
2056
+ .sg-wrapper-less .col-sm-12,
2057
+ .sg-wrapper-less .col-md-12,
2058
+ .sg-wrapper-less .col-lg-12 {
2059
+ position: relative;
2060
+ min-height: 1px;
2061
+ padding-left: 15px;
2062
+ padding-right: 15px;
2063
+ }
2064
+ .sg-wrapper-less .col-xs-1,
2065
+ .sg-wrapper-less .col-xs-2,
2066
+ .sg-wrapper-less .col-xs-3,
2067
+ .sg-wrapper-less .col-xs-4,
2068
+ .sg-wrapper-less .col-xs-5,
2069
+ .sg-wrapper-less .col-xs-6,
2070
+ .sg-wrapper-less .col-xs-7,
2071
+ .sg-wrapper-less .col-xs-8,
2072
+ .sg-wrapper-less .col-xs-9,
2073
+ .sg-wrapper-less .col-xs-10,
2074
+ .sg-wrapper-less .col-xs-11,
2075
+ .sg-wrapper-less .col-xs-12 {
2076
+ float: left;
2077
+ }
2078
+ .sg-wrapper-less .col-xs-12 {
2079
+ width: 100%;
2080
+ }
2081
+ .sg-wrapper-less .col-xs-11 {
2082
+ width: 91.66666667%;
2083
+ }
2084
+ .sg-wrapper-less .col-xs-10 {
2085
+ width: 83.33333333%;
2086
+ }
2087
+ .sg-wrapper-less .col-xs-9 {
2088
+ width: 75%;
2089
+ }
2090
+ .sg-wrapper-less .col-xs-8 {
2091
+ width: 66.66666667%;
2092
+ }
2093
+ .sg-wrapper-less .col-xs-7 {
2094
+ width: 58.33333333%;
2095
+ }
2096
+ .sg-wrapper-less .col-xs-6 {
2097
+ width: 50%;
2098
+ }
2099
+ .sg-wrapper-less .col-xs-5 {
2100
+ width: 41.66666667%;
2101
+ }
2102
+ .sg-wrapper-less .col-xs-4 {
2103
+ width: 33.33333333%;
2104
+ }
2105
+ .sg-wrapper-less .col-xs-3 {
2106
+ width: 25%;
2107
+ }
2108
+ .sg-wrapper-less .col-xs-2 {
2109
+ width: 16.66666667%;
2110
+ }
2111
+ .sg-wrapper-less .col-xs-1 {
2112
+ width: 8.33333333%;
2113
+ }
2114
+ .sg-wrapper-less .col-xs-pull-12 {
2115
+ right: 100%;
2116
+ }
2117
+ .sg-wrapper-less .col-xs-pull-11 {
2118
+ right: 91.66666667%;
2119
+ }
2120
+ .sg-wrapper-less .col-xs-pull-10 {
2121
+ right: 83.33333333%;
2122
+ }
2123
+ .sg-wrapper-less .col-xs-pull-9 {
2124
+ right: 75%;
2125
+ }
2126
+ .sg-wrapper-less .col-xs-pull-8 {
2127
+ right: 66.66666667%;
2128
+ }
2129
+ .sg-wrapper-less .col-xs-pull-7 {
2130
+ right: 58.33333333%;
2131
+ }
2132
+ .sg-wrapper-less .col-xs-pull-6 {
2133
+ right: 50%;
2134
+ }
2135
+ .sg-wrapper-less .col-xs-pull-5 {
2136
+ right: 41.66666667%;
2137
+ }
2138
+ .sg-wrapper-less .col-xs-pull-4 {
2139
+ right: 33.33333333%;
2140
+ }
2141
+ .sg-wrapper-less .col-xs-pull-3 {
2142
+ right: 25%;
2143
+ }
2144
+ .sg-wrapper-less .col-xs-pull-2 {
2145
+ right: 16.66666667%;
2146
+ }
2147
+ .sg-wrapper-less .col-xs-pull-1 {
2148
+ right: 8.33333333%;
2149
+ }
2150
+ .sg-wrapper-less .col-xs-pull-0 {
2151
+ right: auto;
2152
+ }
2153
+ .sg-wrapper-less .col-xs-push-12 {
2154
+ left: 100%;
2155
+ }
2156
+ .sg-wrapper-less .col-xs-push-11 {
2157
+ left: 91.66666667%;
2158
+ }
2159
+ .sg-wrapper-less .col-xs-push-10 {
2160
+ left: 83.33333333%;
2161
+ }
2162
+ .sg-wrapper-less .col-xs-push-9 {
2163
+ left: 75%;
2164
+ }
2165
+ .sg-wrapper-less .col-xs-push-8 {
2166
+ left: 66.66666667%;
2167
+ }
2168
+ .sg-wrapper-less .col-xs-push-7 {
2169
+ left: 58.33333333%;
2170
+ }
2171
+ .sg-wrapper-less .col-xs-push-6 {
2172
+ left: 50%;
2173
+ }
2174
+ .sg-wrapper-less .col-xs-push-5 {
2175
+ left: 41.66666667%;
2176
+ }
2177
+ .sg-wrapper-less .col-xs-push-4 {
2178
+ left: 33.33333333%;
2179
+ }
2180
+ .sg-wrapper-less .col-xs-push-3 {
2181
+ left: 25%;
2182
+ }
2183
+ .sg-wrapper-less .col-xs-push-2 {
2184
+ left: 16.66666667%;
2185
+ }
2186
+ .sg-wrapper-less .col-xs-push-1 {
2187
+ left: 8.33333333%;
2188
+ }
2189
+ .sg-wrapper-less .col-xs-push-0 {
2190
+ left: auto;
2191
+ }
2192
+ .sg-wrapper-less .col-xs-offset-12 {
2193
+ margin-left: 100%;
2194
+ }
2195
+ .sg-wrapper-less .col-xs-offset-11 {
2196
+ margin-left: 91.66666667%;
2197
+ }
2198
+ .sg-wrapper-less .col-xs-offset-10 {
2199
+ margin-left: 83.33333333%;
2200
+ }
2201
+ .sg-wrapper-less .col-xs-offset-9 {
2202
+ margin-left: 75%;
2203
+ }
2204
+ .sg-wrapper-less .col-xs-offset-8 {
2205
+ margin-left: 66.66666667%;
2206
+ }
2207
+ .sg-wrapper-less .col-xs-offset-7 {
2208
+ margin-left: 58.33333333%;
2209
+ }
2210
+ .sg-wrapper-less .col-xs-offset-6 {
2211
+ margin-left: 50%;
2212
+ }
2213
+ .sg-wrapper-less .col-xs-offset-5 {
2214
+ margin-left: 41.66666667%;
2215
+ }
2216
+ .sg-wrapper-less .col-xs-offset-4 {
2217
+ margin-left: 33.33333333%;
2218
+ }
2219
+ .sg-wrapper-less .col-xs-offset-3 {
2220
+ margin-left: 25%;
2221
+ }
2222
+ .sg-wrapper-less .col-xs-offset-2 {
2223
+ margin-left: 16.66666667%;
2224
+ }
2225
+ .sg-wrapper-less .col-xs-offset-1 {
2226
+ margin-left: 8.33333333%;
2227
+ }
2228
+ .sg-wrapper-less .col-xs-offset-0 {
2229
+ margin-left: 0%;
2230
+ }
2231
+ @media (min-width: 768px) {
2232
+ .sg-wrapper-less .col-sm-1,
2233
+ .sg-wrapper-less .col-sm-2,
2234
+ .sg-wrapper-less .col-sm-3,
2235
+ .sg-wrapper-less .col-sm-4,
2236
+ .sg-wrapper-less .col-sm-5,
2237
+ .sg-wrapper-less .col-sm-6,
2238
+ .sg-wrapper-less .col-sm-7,
2239
+ .sg-wrapper-less .col-sm-8,
2240
+ .sg-wrapper-less .col-sm-9,
2241
+ .sg-wrapper-less .col-sm-10,
2242
+ .sg-wrapper-less .col-sm-11,
2243
+ .sg-wrapper-less .col-sm-12 {
2244
+ float: left;
2245
+ }
2246
+ .sg-wrapper-less .col-sm-12 {
2247
+ width: 100%;
2248
+ }
2249
+ .sg-wrapper-less .col-sm-11 {
2250
+ width: 91.66666667%;
2251
+ }
2252
+ .sg-wrapper-less .col-sm-10 {
2253
+ width: 83.33333333%;
2254
+ }
2255
+ .sg-wrapper-less .col-sm-9 {
2256
+ width: 75%;
2257
+ }
2258
+ .sg-wrapper-less .col-sm-8 {
2259
+ width: 66.66666667%;
2260
+ }
2261
+ .sg-wrapper-less .col-sm-7 {
2262
+ width: 58.33333333%;
2263
+ }
2264
+ .sg-wrapper-less .col-sm-6 {
2265
+ width: 50%;
2266
+ }
2267
+ .sg-wrapper-less .col-sm-5 {
2268
+ width: 41.66666667%;
2269
+ }
2270
+ .sg-wrapper-less .col-sm-4 {
2271
+ width: 33.33333333%;
2272
+ }
2273
+ .sg-wrapper-less .col-sm-3 {
2274
+ width: 25%;
2275
+ }
2276
+ .sg-wrapper-less .col-sm-2 {
2277
+ width: 16.66666667%;
2278
+ }
2279
+ .sg-wrapper-less .col-sm-1 {
2280
+ width: 8.33333333%;
2281
+ }
2282
+ .sg-wrapper-less .col-sm-pull-12 {
2283
+ right: 100%;
2284
+ }
2285
+ .sg-wrapper-less .col-sm-pull-11 {
2286
+ right: 91.66666667%;
2287
+ }
2288
+ .sg-wrapper-less .col-sm-pull-10 {
2289
+ right: 83.33333333%;
2290
+ }
2291
+ .sg-wrapper-less .col-sm-pull-9 {
2292
+ right: 75%;
2293
+ }
2294
+ .sg-wrapper-less .col-sm-pull-8 {
2295
+ right: 66.66666667%;
2296
+ }
2297
+ .sg-wrapper-less .col-sm-pull-7 {
2298
+ right: 58.33333333%;
2299
+ }
2300
+ .sg-wrapper-less .col-sm-pull-6 {
2301
+ right: 50%;
2302
+ }
2303
+ .sg-wrapper-less .col-sm-pull-5 {
2304
+ right: 41.66666667%;
2305
+ }
2306
+ .sg-wrapper-less .col-sm-pull-4 {
2307
+ right: 33.33333333%;
2308
+ }
2309
+ .sg-wrapper-less .col-sm-pull-3 {
2310
+ right: 25%;
2311
+ }
2312
+ .sg-wrapper-less .col-sm-pull-2 {
2313
+ right: 16.66666667%;
2314
+ }
2315
+ .sg-wrapper-less .col-sm-pull-1 {
2316
+ right: 8.33333333%;
2317
+ }
2318
+ .sg-wrapper-less .col-sm-pull-0 {
2319
+ right: auto;
2320
+ }
2321
+ .sg-wrapper-less .col-sm-push-12 {
2322
+ left: 100%;
2323
+ }
2324
+ .sg-wrapper-less .col-sm-push-11 {
2325
+ left: 91.66666667%;
2326
+ }
2327
+ .sg-wrapper-less .col-sm-push-10 {
2328
+ left: 83.33333333%;
2329
+ }
2330
+ .sg-wrapper-less .col-sm-push-9 {
2331
+ left: 75%;
2332
+ }
2333
+ .sg-wrapper-less .col-sm-push-8 {
2334
+ left: 66.66666667%;
2335
+ }
2336
+ .sg-wrapper-less .col-sm-push-7 {
2337
+ left: 58.33333333%;
2338
+ }
2339
+ .sg-wrapper-less .col-sm-push-6 {
2340
+ left: 50%;
2341
+ }
2342
+ .sg-wrapper-less .col-sm-push-5 {
2343
+ left: 41.66666667%;
2344
+ }
2345
+ .sg-wrapper-less .col-sm-push-4 {
2346
+ left: 33.33333333%;
2347
+ }
2348
+ .sg-wrapper-less .col-sm-push-3 {
2349
+ left: 25%;
2350
+ }
2351
+ .sg-wrapper-less .col-sm-push-2 {
2352
+ left: 16.66666667%;
2353
+ }
2354
+ .sg-wrapper-less .col-sm-push-1 {
2355
+ left: 8.33333333%;
2356
+ }
2357
+ .sg-wrapper-less .col-sm-push-0 {
2358
+ left: auto;
2359
+ }
2360
+ .sg-wrapper-less .col-sm-offset-12 {
2361
+ margin-left: 100%;
2362
+ }
2363
+ .sg-wrapper-less .col-sm-offset-11 {
2364
+ margin-left: 91.66666667%;
2365
+ }
2366
+ .sg-wrapper-less .col-sm-offset-10 {
2367
+ margin-left: 83.33333333%;
2368
+ }
2369
+ .sg-wrapper-less .col-sm-offset-9 {
2370
+ margin-left: 75%;
2371
+ }
2372
+ .sg-wrapper-less .col-sm-offset-8 {
2373
+ margin-left: 66.66666667%;
2374
+ }
2375
+ .sg-wrapper-less .col-sm-offset-7 {
2376
+ margin-left: 58.33333333%;
2377
+ }
2378
+ .sg-wrapper-less .col-sm-offset-6 {
2379
+ margin-left: 50%;
2380
+ }
2381
+ .sg-wrapper-less .col-sm-offset-5 {
2382
+ margin-left: 41.66666667%;
2383
+ }
2384
+ .sg-wrapper-less .col-sm-offset-4 {
2385
+ margin-left: 33.33333333%;
2386
+ }
2387
+ .sg-wrapper-less .col-sm-offset-3 {
2388
+ margin-left: 25%;
2389
+ }
2390
+ .sg-wrapper-less .col-sm-offset-2 {
2391
+ margin-left: 16.66666667%;
2392
+ }
2393
+ .sg-wrapper-less .col-sm-offset-1 {
2394
+ margin-left: 8.33333333%;
2395
+ }
2396
+ .sg-wrapper-less .col-sm-offset-0 {
2397
+ margin-left: 0%;
2398
+ }
2399
+ }
2400
+ @media (min-width: 992px) {
2401
+ .sg-wrapper-less .col-md-1,
2402
+ .sg-wrapper-less .col-md-2,
2403
+ .sg-wrapper-less .col-md-3,
2404
+ .sg-wrapper-less .col-md-4,
2405
+ .sg-wrapper-less .col-md-5,
2406
+ .sg-wrapper-less .col-md-6,
2407
+ .sg-wrapper-less .col-md-7,
2408
+ .sg-wrapper-less .col-md-8,
2409
+ .sg-wrapper-less .col-md-9,
2410
+ .sg-wrapper-less .col-md-10,
2411
+ .sg-wrapper-less .col-md-11,
2412
+ .sg-wrapper-less .col-md-12 {
2413
+ float: left;
2414
+ }
2415
+ .sg-wrapper-less .col-md-12 {
2416
+ width: 100%;
2417
+ }
2418
+ .sg-wrapper-less .col-md-11 {
2419
+ width: 91.66666667%;
2420
+ }
2421
+ .sg-wrapper-less .col-md-10 {
2422
+ width: 83.33333333%;
2423
+ }
2424
+ .sg-wrapper-less .col-md-9 {
2425
+ width: 75%;
2426
+ }
2427
+ .sg-wrapper-less .col-md-8 {
2428
+ width: 66.66666667%;
2429
+ }
2430
+ .sg-wrapper-less .col-md-7 {
2431
+ width: 58.33333333%;
2432
+ }
2433
+ .sg-wrapper-less .col-md-6 {
2434
+ width: 50%;
2435
+ }
2436
+ .sg-wrapper-less .col-md-5 {
2437
+ width: 41.66666667%;
2438
+ }
2439
+ .sg-wrapper-less .col-md-4 {
2440
+ width: 33.33333333%;
2441
+ }
2442
+ .sg-wrapper-less .col-md-3 {
2443
+ width: 25%;
2444
+ }
2445
+ .sg-wrapper-less .col-md-2 {
2446
+ width: 16.66666667%;
2447
+ }
2448
+ .sg-wrapper-less .col-md-1 {
2449
+ width: 8.33333333%;
2450
+ }
2451
+ .sg-wrapper-less .col-md-pull-12 {
2452
+ right: 100%;
2453
+ }
2454
+ .sg-wrapper-less .col-md-pull-11 {
2455
+ right: 91.66666667%;
2456
+ }
2457
+ .sg-wrapper-less .col-md-pull-10 {
2458
+ right: 83.33333333%;
2459
+ }
2460
+ .sg-wrapper-less .col-md-pull-9 {
2461
+ right: 75%;
2462
+ }
2463
+ .sg-wrapper-less .col-md-pull-8 {
2464
+ right: 66.66666667%;
2465
+ }
2466
+ .sg-wrapper-less .col-md-pull-7 {
2467
+ right: 58.33333333%;
2468
+ }
2469
+ .sg-wrapper-less .col-md-pull-6 {
2470
+ right: 50%;
2471
+ }
2472
+ .sg-wrapper-less .col-md-pull-5 {
2473
+ right: 41.66666667%;
2474
+ }
2475
+ .sg-wrapper-less .col-md-pull-4 {
2476
+ right: 33.33333333%;
2477
+ }
2478
+ .sg-wrapper-less .col-md-pull-3 {
2479
+ right: 25%;
2480
+ }
2481
+ .sg-wrapper-less .col-md-pull-2 {
2482
+ right: 16.66666667%;
2483
+ }
2484
+ .sg-wrapper-less .col-md-pull-1 {
2485
+ right: 8.33333333%;
2486
+ }
2487
+ .sg-wrapper-less .col-md-pull-0 {
2488
+ right: auto;
2489
+ }
2490
+ .sg-wrapper-less .col-md-push-12 {
2491
+ left: 100%;
2492
+ }
2493
+ .sg-wrapper-less .col-md-push-11 {
2494
+ left: 91.66666667%;
2495
+ }
2496
+ .sg-wrapper-less .col-md-push-10 {
2497
+ left: 83.33333333%;
2498
+ }
2499
+ .sg-wrapper-less .col-md-push-9 {
2500
+ left: 75%;
2501
+ }
2502
+ .sg-wrapper-less .col-md-push-8 {
2503
+ left: 66.66666667%;
2504
+ }
2505
+ .sg-wrapper-less .col-md-push-7 {
2506
+ left: 58.33333333%;
2507
+ }
2508
+ .sg-wrapper-less .col-md-push-6 {
2509
+ left: 50%;
2510
+ }
2511
+ .sg-wrapper-less .col-md-push-5 {
2512
+ left: 41.66666667%;
2513
+ }
2514
+ .sg-wrapper-less .col-md-push-4 {
2515
+ left: 33.33333333%;
2516
+ }
2517
+ .sg-wrapper-less .col-md-push-3 {
2518
+ left: 25%;
2519
+ }
2520
+ .sg-wrapper-less .col-md-push-2 {
2521
+ left: 16.66666667%;
2522
+ }
2523
+ .sg-wrapper-less .col-md-push-1 {
2524
+ left: 8.33333333%;
2525
+ }
2526
+ .sg-wrapper-less .col-md-push-0 {
2527
+ left: auto;
2528
+ }
2529
+ .sg-wrapper-less .col-md-offset-12 {
2530
+ margin-left: 100%;
2531
+ }
2532
+ .sg-wrapper-less .col-md-offset-11 {
2533
+ margin-left: 91.66666667%;
2534
+ }
2535
+ .sg-wrapper-less .col-md-offset-10 {
2536
+ margin-left: 83.33333333%;
2537
+ }
2538
+ .sg-wrapper-less .col-md-offset-9 {
2539
+ margin-left: 75%;
2540
+ }
2541
+ .sg-wrapper-less .col-md-offset-8 {
2542
+ margin-left: 66.66666667%;
2543
+ }
2544
+ .sg-wrapper-less .col-md-offset-7 {
2545
+ margin-left: 58.33333333%;
2546
+ }
2547
+ .sg-wrapper-less .col-md-offset-6 {
2548
+ margin-left: 50%;
2549
+ }
2550
+ .sg-wrapper-less .col-md-offset-5 {
2551
+ margin-left: 41.66666667%;
2552
+ }
2553
+ .sg-wrapper-less .col-md-offset-4 {
2554
+ margin-left: 33.33333333%;
2555
+ }
2556
+ .sg-wrapper-less .col-md-offset-3 {
2557
+ margin-left: 25%;
2558
+ }
2559
+ .sg-wrapper-less .col-md-offset-2 {
2560
+ margin-left: 16.66666667%;
2561
+ }
2562
+ .sg-wrapper-less .col-md-offset-1 {
2563
+ margin-left: 8.33333333%;
2564
+ }
2565
+ .sg-wrapper-less .col-md-offset-0 {
2566
+ margin-left: 0%;
2567
+ }
2568
+ }
2569
+ @media (min-width: 1200px) {
2570
+ .sg-wrapper-less .col-lg-1,
2571
+ .sg-wrapper-less .col-lg-2,
2572
+ .sg-wrapper-less .col-lg-3,
2573
+ .sg-wrapper-less .col-lg-4,
2574
+ .sg-wrapper-less .col-lg-5,
2575
+ .sg-wrapper-less .col-lg-6,
2576
+ .sg-wrapper-less .col-lg-7,
2577
+ .sg-wrapper-less .col-lg-8,
2578
+ .sg-wrapper-less .col-lg-9,
2579
+ .sg-wrapper-less .col-lg-10,
2580
+ .sg-wrapper-less .col-lg-11,
2581
+ .sg-wrapper-less .col-lg-12 {
2582
+ float: left;
2583
+ }
2584
+ .sg-wrapper-less .col-lg-12 {
2585
+ width: 100%;
2586
+ }
2587
+ .sg-wrapper-less .col-lg-11 {
2588
+ width: 91.66666667%;
2589
+ }
2590
+ .sg-wrapper-less .col-lg-10 {
2591
+ width: 83.33333333%;
2592
+ }
2593
+ .sg-wrapper-less .col-lg-9 {
2594
+ width: 75%;
2595
+ }
2596
+ .sg-wrapper-less .col-lg-8 {
2597
+ width: 66.66666667%;
2598
+ }
2599
+ .sg-wrapper-less .col-lg-7 {
2600
+ width: 58.33333333%;
2601
+ }
2602
+ .sg-wrapper-less .col-lg-6 {
2603
+ width: 50%;
2604
+ }
2605
+ .sg-wrapper-less .col-lg-5 {
2606
+ width: 41.66666667%;
2607
+ }
2608
+ .sg-wrapper-less .col-lg-4 {
2609
+ width: 33.33333333%;
2610
+ }
2611
+ .sg-wrapper-less .col-lg-3 {
2612
+ width: 25%;
2613
+ }
2614
+ .sg-wrapper-less .col-lg-2 {
2615
+ width: 16.66666667%;
2616
+ }
2617
+ .sg-wrapper-less .col-lg-1 {
2618
+ width: 8.33333333%;
2619
+ }
2620
+ .sg-wrapper-less .col-lg-pull-12 {
2621
+ right: 100%;
2622
+ }
2623
+ .sg-wrapper-less .col-lg-pull-11 {
2624
+ right: 91.66666667%;
2625
+ }
2626
+ .sg-wrapper-less .col-lg-pull-10 {
2627
+ right: 83.33333333%;
2628
+ }
2629
+ .sg-wrapper-less .col-lg-pull-9 {
2630
+ right: 75%;
2631
+ }
2632
+ .sg-wrapper-less .col-lg-pull-8 {
2633
+ right: 66.66666667%;
2634
+ }
2635
+ .sg-wrapper-less .col-lg-pull-7 {
2636
+ right: 58.33333333%;
2637
+ }
2638
+ .sg-wrapper-less .col-lg-pull-6 {
2639
+ right: 50%;
2640
+ }
2641
+ .sg-wrapper-less .col-lg-pull-5 {
2642
+ right: 41.66666667%;
2643
+ }
2644
+ .sg-wrapper-less .col-lg-pull-4 {
2645
+ right: 33.33333333%;
2646
+ }
2647
+ .sg-wrapper-less .col-lg-pull-3 {
2648
+ right: 25%;
2649
+ }
2650
+ .sg-wrapper-less .col-lg-pull-2 {
2651
+ right: 16.66666667%;
2652
+ }
2653
+ .sg-wrapper-less .col-lg-pull-1 {
2654
+ right: 8.33333333%;
2655
+ }
2656
+ .sg-wrapper-less .col-lg-pull-0 {
2657
+ right: auto;
2658
+ }
2659
+ .sg-wrapper-less .col-lg-push-12 {
2660
+ left: 100%;
2661
+ }
2662
+ .sg-wrapper-less .col-lg-push-11 {
2663
+ left: 91.66666667%;
2664
+ }
2665
+ .sg-wrapper-less .col-lg-push-10 {
2666
+ left: 83.33333333%;
2667
+ }
2668
+ .sg-wrapper-less .col-lg-push-9 {
2669
+ left: 75%;
2670
+ }
2671
+ .sg-wrapper-less .col-lg-push-8 {
2672
+ left: 66.66666667%;
2673
+ }
2674
+ .sg-wrapper-less .col-lg-push-7 {
2675
+ left: 58.33333333%;
2676
+ }
2677
+ .sg-wrapper-less .col-lg-push-6 {
2678
+ left: 50%;
2679
+ }
2680
+ .sg-wrapper-less .col-lg-push-5 {
2681
+ left: 41.66666667%;
2682
+ }
2683
+ .sg-wrapper-less .col-lg-push-4 {
2684
+ left: 33.33333333%;
2685
+ }
2686
+ .sg-wrapper-less .col-lg-push-3 {
2687
+ left: 25%;
2688
+ }
2689
+ .sg-wrapper-less .col-lg-push-2 {
2690
+ left: 16.66666667%;
2691
+ }
2692
+ .sg-wrapper-less .col-lg-push-1 {
2693
+ left: 8.33333333%;
2694
+ }
2695
+ .sg-wrapper-less .col-lg-push-0 {
2696
+ left: auto;
2697
+ }
2698
+ .sg-wrapper-less .col-lg-offset-12 {
2699
+ margin-left: 100%;
2700
+ }
2701
+ .sg-wrapper-less .col-lg-offset-11 {
2702
+ margin-left: 91.66666667%;
2703
+ }
2704
+ .sg-wrapper-less .col-lg-offset-10 {
2705
+ margin-left: 83.33333333%;
2706
+ }
2707
+ .sg-wrapper-less .col-lg-offset-9 {
2708
+ margin-left: 75%;
2709
+ }
2710
+ .sg-wrapper-less .col-lg-offset-8 {
2711
+ margin-left: 66.66666667%;
2712
+ }
2713
+ .sg-wrapper-less .col-lg-offset-7 {
2714
+ margin-left: 58.33333333%;
2715
+ }
2716
+ .sg-wrapper-less .col-lg-offset-6 {
2717
+ margin-left: 50%;
2718
+ }
2719
+ .sg-wrapper-less .col-lg-offset-5 {
2720
+ margin-left: 41.66666667%;
2721
+ }
2722
+ .sg-wrapper-less .col-lg-offset-4 {
2723
+ margin-left: 33.33333333%;
2724
+ }
2725
+ .sg-wrapper-less .col-lg-offset-3 {
2726
+ margin-left: 25%;
2727
+ }
2728
+ .sg-wrapper-less .col-lg-offset-2 {
2729
+ margin-left: 16.66666667%;
2730
+ }
2731
+ .sg-wrapper-less .col-lg-offset-1 {
2732
+ margin-left: 8.33333333%;
2733
+ }
2734
+ .sg-wrapper-less .col-lg-offset-0 {
2735
+ margin-left: 0%;
2736
+ }
2737
+ }
2738
+ .sg-wrapper-less table {
2739
+ background-color: transparent;
2740
+ }
2741
+ .sg-wrapper-less caption {
2742
+ padding-top: 8px;
2743
+ padding-bottom: 8px;
2744
+ color: #999999;
2745
+ text-align: left;
2746
+ }
2747
+ .sg-wrapper-less th {
2748
+ text-align: left;
2749
+ }
2750
+ .sg-wrapper-less .table {
2751
+ width: 100%;
2752
+ max-width: 100%;
2753
+ margin-bottom: 21px;
2754
+ }
2755
+ .sg-wrapper-less .table > thead > tr > th,
2756
+ .sg-wrapper-less .table > tbody > tr > th,
2757
+ .sg-wrapper-less .table > tfoot > tr > th,
2758
+ .sg-wrapper-less .table > thead > tr > td,
2759
+ .sg-wrapper-less .table > tbody > tr > td,
2760
+ .sg-wrapper-less .table > tfoot > tr > td {
2761
+ padding: 8px;
2762
+ line-height: 1.42857143;
2763
+ vertical-align: top;
2764
+ border-top: 1px solid #dddddd;
2765
+ }
2766
+ .sg-wrapper-less .table > thead > tr > th {
2767
+ vertical-align: bottom;
2768
+ border-bottom: 2px solid #dddddd;
2769
+ }
2770
+ .sg-wrapper-less .table > caption + thead > tr:first-child > th,
2771
+ .sg-wrapper-less .table > colgroup + thead > tr:first-child > th,
2772
+ .sg-wrapper-less .table > thead:first-child > tr:first-child > th,
2773
+ .sg-wrapper-less .table > caption + thead > tr:first-child > td,
2774
+ .sg-wrapper-less .table > colgroup + thead > tr:first-child > td,
2775
+ .sg-wrapper-less .table > thead:first-child > tr:first-child > td {
2776
+ border-top: 0;
2777
+ }
2778
+ .sg-wrapper-less .table > tbody + tbody {
2779
+ border-top: 2px solid #dddddd;
2780
+ }
2781
+ .sg-wrapper-less .table .table {
2782
+ background-color: #ffffff;
2783
+ }
2784
+ .sg-wrapper-less .table-condensed > thead > tr > th,
2785
+ .sg-wrapper-less .table-condensed > tbody > tr > th,
2786
+ .sg-wrapper-less .table-condensed > tfoot > tr > th,
2787
+ .sg-wrapper-less .table-condensed > thead > tr > td,
2788
+ .sg-wrapper-less .table-condensed > tbody > tr > td,
2789
+ .sg-wrapper-less .table-condensed > tfoot > tr > td {
2790
+ padding: 5px;
2791
+ }
2792
+ .sg-wrapper-less .table-bordered {
2793
+ border: 1px solid #dddddd;
2794
+ }
2795
+ .sg-wrapper-less .table-bordered > thead > tr > th,
2796
+ .sg-wrapper-less .table-bordered > tbody > tr > th,
2797
+ .sg-wrapper-less .table-bordered > tfoot > tr > th,
2798
+ .sg-wrapper-less .table-bordered > thead > tr > td,
2799
+ .sg-wrapper-less .table-bordered > tbody > tr > td,
2800
+ .sg-wrapper-less .table-bordered > tfoot > tr > td {
2801
+ border: 1px solid #dddddd;
2802
+ }
2803
+ .sg-wrapper-less .table-bordered > thead > tr > th,
2804
+ .sg-wrapper-less .table-bordered > thead > tr > td {
2805
+ border-bottom-width: 2px;
2806
+ }
2807
+ .sg-wrapper-less .table-striped > tbody > tr:nth-of-type(odd) {
2808
+ background-color: #f9f9f9;
2809
+ }
2810
+ .sg-wrapper-less .table-hover > tbody > tr:hover {
2811
+ background-color: #f5f5f5;
2812
+ }
2813
+ .sg-wrapper-less table col[class*="col-"] {
2814
+ position: static;
2815
+ float: none;
2816
+ display: table-column;
2817
+ }
2818
+ .sg-wrapper-less table td[class*="col-"],
2819
+ .sg-wrapper-less table th[class*="col-"] {
2820
+ position: static;
2821
+ float: none;
2822
+ display: table-cell;
2823
+ }
2824
+ .sg-wrapper-less .table > thead > tr > td.active,
2825
+ .sg-wrapper-less .table > tbody > tr > td.active,
2826
+ .sg-wrapper-less .table > tfoot > tr > td.active,
2827
+ .sg-wrapper-less .table > thead > tr > th.active,
2828
+ .sg-wrapper-less .table > tbody > tr > th.active,
2829
+ .sg-wrapper-less .table > tfoot > tr > th.active,
2830
+ .sg-wrapper-less .table > thead > tr.active > td,
2831
+ .sg-wrapper-less .table > tbody > tr.active > td,
2832
+ .sg-wrapper-less .table > tfoot > tr.active > td,
2833
+ .sg-wrapper-less .table > thead > tr.active > th,
2834
+ .sg-wrapper-less .table > tbody > tr.active > th,
2835
+ .sg-wrapper-less .table > tfoot > tr.active > th {
2836
+ background-color: #f5f5f5;
2837
+ }
2838
+ .sg-wrapper-less .table-hover > tbody > tr > td.active:hover,
2839
+ .sg-wrapper-less .table-hover > tbody > tr > th.active:hover,
2840
+ .sg-wrapper-less .table-hover > tbody > tr.active:hover > td,
2841
+ .sg-wrapper-less .table-hover > tbody > tr:hover > .active,
2842
+ .sg-wrapper-less .table-hover > tbody > tr.active:hover > th {
2843
+ background-color: #e8e8e8;
2844
+ }
2845
+ .sg-wrapper-less .table > thead > tr > td.success,
2846
+ .sg-wrapper-less .table > tbody > tr > td.success,
2847
+ .sg-wrapper-less .table > tfoot > tr > td.success,
2848
+ .sg-wrapper-less .table > thead > tr > th.success,
2849
+ .sg-wrapper-less .table > tbody > tr > th.success,
2850
+ .sg-wrapper-less .table > tfoot > tr > th.success,
2851
+ .sg-wrapper-less .table > thead > tr.success > td,
2852
+ .sg-wrapper-less .table > tbody > tr.success > td,
2853
+ .sg-wrapper-less .table > tfoot > tr.success > td,
2854
+ .sg-wrapper-less .table > thead > tr.success > th,
2855
+ .sg-wrapper-less .table > tbody > tr.success > th,
2856
+ .sg-wrapper-less .table > tfoot > tr.success > th {
2857
+ background-color: #3fb618;
2858
+ }
2859
+ .sg-wrapper-less .table-hover > tbody > tr > td.success:hover,
2860
+ .sg-wrapper-less .table-hover > tbody > tr > th.success:hover,
2861
+ .sg-wrapper-less .table-hover > tbody > tr.success:hover > td,
2862
+ .sg-wrapper-less .table-hover > tbody > tr:hover > .success,
2863
+ .sg-wrapper-less .table-hover > tbody > tr.success:hover > th {
2864
+ background-color: #379f15;
2865
+ }
2866
+ .sg-wrapper-less .table > thead > tr > td.info,
2867
+ .sg-wrapper-less .table > tbody > tr > td.info,
2868
+ .sg-wrapper-less .table > tfoot > tr > td.info,
2869
+ .sg-wrapper-less .table > thead > tr > th.info,
2870
+ .sg-wrapper-less .table > tbody > tr > th.info,
2871
+ .sg-wrapper-less .table > tfoot > tr > th.info,
2872
+ .sg-wrapper-less .table > thead > tr.info > td,
2873
+ .sg-wrapper-less .table > tbody > tr.info > td,
2874
+ .sg-wrapper-less .table > tfoot > tr.info > td,
2875
+ .sg-wrapper-less .table > thead > tr.info > th,
2876
+ .sg-wrapper-less .table > tbody > tr.info > th,
2877
+ .sg-wrapper-less .table > tfoot > tr.info > th {
2878
+ background-color: #9954bb;
2879
+ }
2880
+ .sg-wrapper-less .table-hover > tbody > tr > td.info:hover,
2881
+ .sg-wrapper-less .table-hover > tbody > tr > th.info:hover,
2882
+ .sg-wrapper-less .table-hover > tbody > tr.info:hover > td,
2883
+ .sg-wrapper-less .table-hover > tbody > tr:hover > .info,
2884
+ .sg-wrapper-less .table-hover > tbody > tr.info:hover > th {
2885
+ background-color: #8d46b0;
2886
+ }
2887
+ .sg-wrapper-less .table > thead > tr > td.warning,
2888
+ .sg-wrapper-less .table > tbody > tr > td.warning,
2889
+ .sg-wrapper-less .table > tfoot > tr > td.warning,
2890
+ .sg-wrapper-less .table > thead > tr > th.warning,
2891
+ .sg-wrapper-less .table > tbody > tr > th.warning,
2892
+ .sg-wrapper-less .table > tfoot > tr > th.warning,
2893
+ .sg-wrapper-less .table > thead > tr.warning > td,
2894
+ .sg-wrapper-less .table > tbody > tr.warning > td,
2895
+ .sg-wrapper-less .table > tfoot > tr.warning > td,
2896
+ .sg-wrapper-less .table > thead > tr.warning > th,
2897
+ .sg-wrapper-less .table > tbody > tr.warning > th,
2898
+ .sg-wrapper-less .table > tfoot > tr.warning > th {
2899
+ background-color: #ff7518;
2900
+ }
2901
+ .sg-wrapper-less .table-hover > tbody > tr > td.warning:hover,
2902
+ .sg-wrapper-less .table-hover > tbody > tr > th.warning:hover,
2903
+ .sg-wrapper-less .table-hover > tbody > tr.warning:hover > td,
2904
+ .sg-wrapper-less .table-hover > tbody > tr:hover > .warning,
2905
+ .sg-wrapper-less .table-hover > tbody > tr.warning:hover > th {
2906
+ background-color: #fe6600;
2907
+ }
2908
+ .sg-wrapper-less .table > thead > tr > td.danger,
2909
+ .sg-wrapper-less .table > tbody > tr > td.danger,
2910
+ .sg-wrapper-less .table > tfoot > tr > td.danger,
2911
+ .sg-wrapper-less .table > thead > tr > th.danger,
2912
+ .sg-wrapper-less .table > tbody > tr > th.danger,
2913
+ .sg-wrapper-less .table > tfoot > tr > th.danger,
2914
+ .sg-wrapper-less .table > thead > tr.danger > td,
2915
+ .sg-wrapper-less .table > tbody > tr.danger > td,
2916
+ .sg-wrapper-less .table > tfoot > tr.danger > td,
2917
+ .sg-wrapper-less .table > thead > tr.danger > th,
2918
+ .sg-wrapper-less .table > tbody > tr.danger > th,
2919
+ .sg-wrapper-less .table > tfoot > tr.danger > th {
2920
+ background-color: #ff0039;
2921
+ }
2922
+ .sg-wrapper-less .table-hover > tbody > tr > td.danger:hover,
2923
+ .sg-wrapper-less .table-hover > tbody > tr > th.danger:hover,
2924
+ .sg-wrapper-less .table-hover > tbody > tr.danger:hover > td,
2925
+ .sg-wrapper-less .table-hover > tbody > tr:hover > .danger,
2926
+ .sg-wrapper-less .table-hover > tbody > tr.danger:hover > th {
2927
+ background-color: #e60033;
2928
+ }
2929
+ .sg-wrapper-less .table-responsive {
2930
+ overflow-x: auto;
2931
+ min-height: 0.01%;
2932
+ }
2933
+ @media screen and (max-width: 767px) {
2934
+ .sg-wrapper-less .table-responsive {
2935
+ width: 100%;
2936
+ margin-bottom: 15.75px;
2937
+ overflow-y: hidden;
2938
+ -ms-overflow-style: -ms-autohiding-scrollbar;
2939
+ border: 1px solid #dddddd;
2940
+ }
2941
+ .sg-wrapper-less .table-responsive > .table {
2942
+ margin-bottom: 0;
2943
+ }
2944
+ .sg-wrapper-less .table-responsive > .table > thead > tr > th,
2945
+ .sg-wrapper-less .table-responsive > .table > tbody > tr > th,
2946
+ .sg-wrapper-less .table-responsive > .table > tfoot > tr > th,
2947
+ .sg-wrapper-less .table-responsive > .table > thead > tr > td,
2948
+ .sg-wrapper-less .table-responsive > .table > tbody > tr > td,
2949
+ .sg-wrapper-less .table-responsive > .table > tfoot > tr > td {
2950
+ white-space: nowrap;
2951
+ }
2952
+ .sg-wrapper-less .table-responsive > .table-bordered {
2953
+ border: 0;
2954
+ }
2955
+ .sg-wrapper-less .table-responsive > .table-bordered > thead > tr > th:first-child,
2956
+ .sg-wrapper-less .table-responsive > .table-bordered > tbody > tr > th:first-child,
2957
+ .sg-wrapper-less .table-responsive > .table-bordered > tfoot > tr > th:first-child,
2958
+ .sg-wrapper-less .table-responsive > .table-bordered > thead > tr > td:first-child,
2959
+ .sg-wrapper-less .table-responsive > .table-bordered > tbody > tr > td:first-child,
2960
+ .sg-wrapper-less .table-responsive > .table-bordered > tfoot > tr > td:first-child {
2961
+ border-left: 0;
2962
+ }
2963
+ .sg-wrapper-less .table-responsive > .table-bordered > thead > tr > th:last-child,
2964
+ .sg-wrapper-less .table-responsive > .table-bordered > tbody > tr > th:last-child,
2965
+ .sg-wrapper-less .table-responsive > .table-bordered > tfoot > tr > th:last-child,
2966
+ .sg-wrapper-less .table-responsive > .table-bordered > thead > tr > td:last-child,
2967
+ .sg-wrapper-less .table-responsive > .table-bordered > tbody > tr > td:last-child,
2968
+ .sg-wrapper-less .table-responsive > .table-bordered > tfoot > tr > td:last-child {
2969
+ border-right: 0;
2970
+ }
2971
+ .sg-wrapper-less .table-responsive > .table-bordered > tbody > tr:last-child > th,
2972
+ .sg-wrapper-less .table-responsive > .table-bordered > tfoot > tr:last-child > th,
2973
+ .sg-wrapper-less .table-responsive > .table-bordered > tbody > tr:last-child > td,
2974
+ .sg-wrapper-less .table-responsive > .table-bordered > tfoot > tr:last-child > td {
2975
+ border-bottom: 0;
2976
+ }
2977
+ }
2978
+ .sg-wrapper-less fieldset {
2979
+ padding: 0;
2980
+ margin: 0;
2981
+ border: 0;
2982
+ min-width: 0;
2983
+ }
2984
+ .sg-wrapper-less legend {
2985
+ display: block;
2986
+ width: 100%;
2987
+ padding: 0;
2988
+ margin-bottom: 21px;
2989
+ font-size: 22.5px;
2990
+ line-height: inherit;
2991
+ color: #333333;
2992
+ border: 0;
2993
+ border-bottom: 1px solid #e5e5e5;
2994
+ }
2995
+ .sg-wrapper-less label {
2996
+ display: inline-block;
2997
+ max-width: 100%;
2998
+ margin-bottom: 5px;
2999
+ font-weight: bold;
3000
+ }
3001
+ .sg-wrapper-less input[type="search"] {
3002
+ -webkit-box-sizing: border-box;
3003
+ -moz-box-sizing: border-box;
3004
+ box-sizing: border-box;
3005
+ }
3006
+ .sg-wrapper-less input[type="radio"],
3007
+ .sg-wrapper-less input[type="checkbox"] {
3008
+ margin: 4px 0 0;
3009
+ margin-top: 1px \9;
3010
+ line-height: normal;
3011
+ }
3012
+ .sg-wrapper-less input[type="file"] {
3013
+ display: block;
3014
+ }
3015
+ .sg-wrapper-less input[type="range"] {
3016
+ display: block;
3017
+ width: 100%;
3018
+ }
3019
+ .sg-wrapper-less select[multiple],
3020
+ .sg-wrapper-less select[size] {
3021
+ height: auto;
3022
+ }
3023
+ .sg-wrapper-less input[type="file"]:focus,
3024
+ .sg-wrapper-less input[type="radio"]:focus,
3025
+ .sg-wrapper-less input[type="checkbox"]:focus {
3026
+ outline: thin dotted;
3027
+ outline: 5px auto -webkit-focus-ring-color;
3028
+ outline-offset: -2px;
3029
+ }
3030
+ .sg-wrapper-less output {
3031
+ display: block;
3032
+ padding-top: 11px;
3033
+ font-size: 15px;
3034
+ line-height: 1.42857143;
3035
+ color: #333333;
3036
+ }
3037
+ .sg-wrapper-less .form-control {
3038
+ display: block;
3039
+ width: 100%;
3040
+ height: 43px;
3041
+ padding: 10px 18px;
3042
+ font-size: 15px;
3043
+ line-height: 1.42857143;
3044
+ color: #333333;
3045
+ background-color: #ffffff;
3046
+ background-image: none;
3047
+ border: 1px solid #cccccc;
3048
+ border-radius: 0;
3049
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
3050
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
3051
+ -webkit-transition: border-color ease-in-out 0.15s, -webkit-box-shadow ease-in-out 0.15s;
3052
+ -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
3053
+ transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
3054
+ }
3055
+ .sg-wrapper-less .form-control:focus {
3056
+ border-color: #66afe9;
3057
+ outline: 0;
3058
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
3059
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
3060
+ }
3061
+ .sg-wrapper-less .form-control::-moz-placeholder {
3062
+ color: #999999;
3063
+ opacity: 1;
3064
+ }
3065
+ .sg-wrapper-less .form-control:-ms-input-placeholder {
3066
+ color: #999999;
3067
+ }
3068
+ .sg-wrapper-less .form-control::-webkit-input-placeholder {
3069
+ color: #999999;
3070
+ }
3071
+ .sg-wrapper-less .form-control[disabled],
3072
+ .sg-wrapper-less .form-control[readonly],
3073
+ .sg-wrapper-less fieldset[disabled] .form-control {
3074
+ background-color: #e6e6e6;
3075
+ opacity: 1;
3076
+ }
3077
+ .sg-wrapper-less .form-control[disabled],
3078
+ .sg-wrapper-less fieldset[disabled] .form-control {
3079
+ cursor: not-allowed;
3080
+ }
3081
+ .sg-wrapper-less textarea.form-control {
3082
+ height: auto;
3083
+ }
3084
+ .sg-wrapper-less input[type="search"] {
3085
+ -webkit-appearance: none;
3086
+ }
3087
+ @media screen and (-webkit-min-device-pixel-ratio: 0) {
3088
+ .sg-wrapper-less input[type="date"],
3089
+ .sg-wrapper-less input[type="time"],
3090
+ .sg-wrapper-less input[type="datetime-local"],
3091
+ .sg-wrapper-less input[type="month"] {
3092
+ line-height: 43px;
3093
+ }
3094
+ .sg-wrapper-less input[type="date"].input-sm,
3095
+ .sg-wrapper-less input[type="time"].input-sm,
3096
+ .sg-wrapper-less input[type="datetime-local"].input-sm,
3097
+ .sg-wrapper-less input[type="month"].input-sm,
3098
+ .sg-wrapper-less .input-group-sm input[type="date"],
3099
+ .sg-wrapper-less .input-group-sm input[type="time"],
3100
+ .sg-wrapper-less .input-group-sm input[type="datetime-local"],
3101
+ .sg-wrapper-less .input-group-sm input[type="month"] {
3102
+ line-height: 31px;
3103
+ }
3104
+ .sg-wrapper-less input[type="date"].input-lg,
3105
+ .sg-wrapper-less input[type="time"].input-lg,
3106
+ .sg-wrapper-less input[type="datetime-local"].input-lg,
3107
+ .sg-wrapper-less input[type="month"].input-lg,
3108
+ .sg-wrapper-less .input-group-lg input[type="date"],
3109
+ .sg-wrapper-less .input-group-lg input[type="time"],
3110
+ .sg-wrapper-less .input-group-lg input[type="datetime-local"],
3111
+ .sg-wrapper-less .input-group-lg input[type="month"] {
3112
+ line-height: 64px;
3113
+ }
3114
+ }
3115
+ .sg-wrapper-less .form-group {
3116
+ margin-bottom: 15px;
3117
+ }
3118
+ .sg-wrapper-less .radio,
3119
+ .sg-wrapper-less .checkbox {
3120
+ display: block;
3121
+ margin-top: 10px;
3122
+ margin-bottom: 10px;
3123
+ }
3124
+ .sg-wrapper-less .radio label,
3125
+ .sg-wrapper-less .checkbox label {
3126
+ min-height: 21px;
3127
+ padding-left: 20px;
3128
+ margin-bottom: 0;
3129
+ font-weight: normal;
3130
+ cursor: pointer;
3131
+ }
3132
+ .sg-wrapper-less .radio input[type="radio"],
3133
+ .sg-wrapper-less .radio-inline input[type="radio"],
3134
+ .sg-wrapper-less .checkbox input[type="checkbox"],
3135
+ .sg-wrapper-less .checkbox-inline input[type="checkbox"] {
3136
+ position: absolute;
3137
+ margin-left: -20px;
3138
+ margin-top: 4px \9;
3139
+ }
3140
+ .sg-wrapper-less .radio + .radio,
3141
+ .sg-wrapper-less .checkbox + .checkbox {
3142
+ margin-top: -5px;
3143
+ }
3144
+ .sg-wrapper-less .radio-inline,
3145
+ .sg-wrapper-less .checkbox-inline {
3146
+ position: relative;
3147
+ display: inline-block;
3148
+ padding-left: 20px;
3149
+ margin-bottom: 0;
3150
+ vertical-align: middle;
3151
+ font-weight: normal;
3152
+ cursor: pointer;
3153
+ }
3154
+ .sg-wrapper-less .radio-inline + .radio-inline,
3155
+ .sg-wrapper-less .checkbox-inline + .checkbox-inline {
3156
+ margin-top: 0;
3157
+ margin-left: 10px;
3158
+ }
3159
+ .sg-wrapper-less input[type="radio"][disabled],
3160
+ .sg-wrapper-less input[type="checkbox"][disabled],
3161
+ .sg-wrapper-less input[type="radio"].disabled,
3162
+ .sg-wrapper-less input[type="checkbox"].disabled,
3163
+ .sg-wrapper-less fieldset[disabled] input[type="radio"],
3164
+ .sg-wrapper-less fieldset[disabled] input[type="checkbox"] {
3165
+ cursor: not-allowed;
3166
+ }
3167
+ .sg-wrapper-less .radio-inline.disabled,
3168
+ .sg-wrapper-less .checkbox-inline.disabled,
3169
+ .sg-wrapper-less fieldset[disabled] .radio-inline,
3170
+ .sg-wrapper-less fieldset[disabled] .checkbox-inline {
3171
+ cursor: not-allowed;
3172
+ }
3173
+ .sg-wrapper-less .radio.disabled label,
3174
+ .sg-wrapper-less .checkbox.disabled label,
3175
+ .sg-wrapper-less fieldset[disabled] .radio label,
3176
+ .sg-wrapper-less fieldset[disabled] .checkbox label {
3177
+ cursor: not-allowed;
3178
+ }
3179
+ .sg-wrapper-less .form-control-static {
3180
+ padding-top: 11px;
3181
+ padding-bottom: 11px;
3182
+ margin-bottom: 0;
3183
+ min-height: 36px;
3184
+ }
3185
+ .sg-wrapper-less .form-control-static.input-lg,
3186
+ .sg-wrapper-less .form-control-static.input-sm {
3187
+ padding-left: 0;
3188
+ padding-right: 0;
3189
+ }
3190
+ .sg-wrapper-less .input-sm {
3191
+ height: 31px;
3192
+ padding: 5px 10px;
3193
+ font-size: 13px;
3194
+ line-height: 1.5;
3195
+ border-radius: 0;
3196
+ }
3197
+ .sg-wrapper-less select.input-sm {
3198
+ height: 31px;
3199
+ line-height: 31px;
3200
+ }
3201
+ .sg-wrapper-less textarea.input-sm,
3202
+ .sg-wrapper-less select[multiple].input-sm {
3203
+ height: auto;
3204
+ }
3205
+ .sg-wrapper-less .form-group-sm .form-control {
3206
+ height: 31px;
3207
+ padding: 5px 10px;
3208
+ font-size: 13px;
3209
+ line-height: 1.5;
3210
+ border-radius: 0;
3211
+ }
3212
+ .sg-wrapper-less select.form-group-sm .form-control {
3213
+ height: 31px;
3214
+ line-height: 31px;
3215
+ }
3216
+ .sg-wrapper-less textarea.form-group-sm .form-control,
3217
+ .sg-wrapper-less select[multiple].form-group-sm .form-control {
3218
+ height: auto;
3219
+ }
3220
+ .sg-wrapper-less .form-group-sm .form-control-static {
3221
+ height: 31px;
3222
+ padding: 5px 10px;
3223
+ font-size: 13px;
3224
+ line-height: 1.5;
3225
+ min-height: 34px;
3226
+ }
3227
+ .sg-wrapper-less .input-lg {
3228
+ height: 64px;
3229
+ padding: 18px 30px;
3230
+ font-size: 19px;
3231
+ line-height: 1.3333333;
3232
+ border-radius: 0;
3233
+ }
3234
+ .sg-wrapper-less select.input-lg {
3235
+ height: 64px;
3236
+ line-height: 64px;
3237
+ }
3238
+ .sg-wrapper-less textarea.input-lg,
3239
+ .sg-wrapper-less select[multiple].input-lg {
3240
+ height: auto;
3241
+ }
3242
+ .sg-wrapper-less .form-group-lg .form-control {
3243
+ height: 64px;
3244
+ padding: 18px 30px;
3245
+ font-size: 19px;
3246
+ line-height: 1.3333333;
3247
+ border-radius: 0;
3248
+ }
3249
+ .sg-wrapper-less select.form-group-lg .form-control {
3250
+ height: 64px;
3251
+ line-height: 64px;
3252
+ }
3253
+ .sg-wrapper-less textarea.form-group-lg .form-control,
3254
+ .sg-wrapper-less select[multiple].form-group-lg .form-control {
3255
+ height: auto;
3256
+ }
3257
+ .sg-wrapper-less .form-group-lg .form-control-static {
3258
+ height: 64px;
3259
+ padding: 18px 30px;
3260
+ font-size: 19px;
3261
+ line-height: 1.3333333;
3262
+ min-height: 40px;
3263
+ }
3264
+ .sg-wrapper-less .has-feedback {
3265
+ position: relative;
3266
+ }
3267
+ .sg-wrapper-less .has-feedback .form-control {
3268
+ padding-right: 53.75px;
3269
+ }
3270
+ .sg-wrapper-less .form-control-feedback {
3271
+ position: absolute;
3272
+ top: 0;
3273
+ right: 0;
3274
+ z-index: 2;
3275
+ display: block;
3276
+ width: 43px;
3277
+ height: 43px;
3278
+ line-height: 43px;
3279
+ text-align: center;
3280
+ pointer-events: none;
3281
+ }
3282
+ .sg-wrapper-less .input-lg + .form-control-feedback {
3283
+ width: 64px;
3284
+ height: 64px;
3285
+ line-height: 64px;
3286
+ }
3287
+ .sg-wrapper-less .input-sm + .form-control-feedback {
3288
+ width: 31px;
3289
+ height: 31px;
3290
+ line-height: 31px;
3291
+ }
3292
+ .sg-wrapper-less .has-success .help-block,
3293
+ .sg-wrapper-less .has-success .control-label,
3294
+ .sg-wrapper-less .has-success .radio,
3295
+ .sg-wrapper-less .has-success .checkbox,
3296
+ .sg-wrapper-less .has-success .radio-inline,
3297
+ .sg-wrapper-less .has-success .checkbox-inline,
3298
+ .sg-wrapper-less .has-success.radio label,
3299
+ .sg-wrapper-less .has-success.checkbox label,
3300
+ .sg-wrapper-less .has-success.radio-inline label,
3301
+ .sg-wrapper-less .has-success.checkbox-inline label {
3302
+ color: #ffffff;
3303
+ }
3304
+ .sg-wrapper-less .has-success .form-control {
3305
+ border-color: #ffffff;
3306
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
3307
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
3308
+ }
3309
+ .sg-wrapper-less .has-success .form-control:focus {
3310
+ border-color: #e6e6e6;
3311
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;
3312
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;
3313
+ }
3314
+ .sg-wrapper-less .has-success .input-group-addon {
3315
+ color: #ffffff;
3316
+ border-color: #ffffff;
3317
+ background-color: #3fb618;
3318
+ }
3319
+ .sg-wrapper-less .has-success .form-control-feedback {
3320
+ color: #ffffff;
3321
+ }
3322
+ .sg-wrapper-less .has-warning .help-block,
3323
+ .sg-wrapper-less .has-warning .control-label,
3324
+ .sg-wrapper-less .has-warning .radio,
3325
+ .sg-wrapper-less .has-warning .checkbox,
3326
+ .sg-wrapper-less .has-warning .radio-inline,
3327
+ .sg-wrapper-less .has-warning .checkbox-inline,
3328
+ .sg-wrapper-less .has-warning.radio label,
3329
+ .sg-wrapper-less .has-warning.checkbox label,
3330
+ .sg-wrapper-less .has-warning.radio-inline label,
3331
+ .sg-wrapper-less .has-warning.checkbox-inline label {
3332
+ color: #ffffff;
3333
+ }
3334
+ .sg-wrapper-less .has-warning .form-control {
3335
+ border-color: #ffffff;
3336
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
3337
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
3338
+ }
3339
+ .sg-wrapper-less .has-warning .form-control:focus {
3340
+ border-color: #e6e6e6;
3341
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;
3342
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;
3343
+ }
3344
+ .sg-wrapper-less .has-warning .input-group-addon {
3345
+ color: #ffffff;
3346
+ border-color: #ffffff;
3347
+ background-color: #ff7518;
3348
+ }
3349
+ .sg-wrapper-less .has-warning .form-control-feedback {
3350
+ color: #ffffff;
3351
+ }
3352
+ .sg-wrapper-less .has-error .help-block,
3353
+ .sg-wrapper-less .has-error .control-label,
3354
+ .sg-wrapper-less .has-error .radio,
3355
+ .sg-wrapper-less .has-error .checkbox,
3356
+ .sg-wrapper-less .has-error .radio-inline,
3357
+ .sg-wrapper-less .has-error .checkbox-inline,
3358
+ .sg-wrapper-less .has-error.radio label,
3359
+ .sg-wrapper-less .has-error.checkbox label,
3360
+ .sg-wrapper-less .has-error.radio-inline label,
3361
+ .sg-wrapper-less .has-error.checkbox-inline label {
3362
+ color: #ffffff;
3363
+ }
3364
+ .sg-wrapper-less .has-error .form-control {
3365
+ border-color: #ffffff;
3366
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
3367
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
3368
+ }
3369
+ .sg-wrapper-less .has-error .form-control:focus {
3370
+ border-color: #e6e6e6;
3371
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;
3372
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;
3373
+ }
3374
+ .sg-wrapper-less .has-error .input-group-addon {
3375
+ color: #ffffff;
3376
+ border-color: #ffffff;
3377
+ background-color: #ff0039;
3378
+ }
3379
+ .sg-wrapper-less .has-error .form-control-feedback {
3380
+ color: #ffffff;
3381
+ }
3382
+ .sg-wrapper-less .has-feedback label ~ .form-control-feedback {
3383
+ top: 26px;
3384
+ }
3385
+ .sg-wrapper-less .has-feedback label.sr-only ~ .form-control-feedback {
3386
+ top: 0;
3387
+ }
3388
+ .sg-wrapper-less .help-block {
3389
+ display: block;
3390
+ margin-top: 5px;
3391
+ margin-bottom: 10px;
3392
+ color: #737373;
3393
+ }
3394
+ @media (min-width: 768px) {
3395
+ .sg-wrapper-less .form-inline .form-group {
3396
+ display: inline-block;
3397
+ margin-bottom: 0;
3398
+ vertical-align: middle;
3399
+ }
3400
+ .sg-wrapper-less .form-inline .form-control {
3401
+ display: inline-block;
3402
+ width: auto;
3403
+ vertical-align: middle;
3404
+ }
3405
+ .sg-wrapper-less .form-inline .form-control-static {
3406
+ display: inline-block;
3407
+ }
3408
+ .sg-wrapper-less .form-inline .input-group {
3409
+ display: inline-table;
3410
+ vertical-align: middle;
3411
+ }
3412
+ .sg-wrapper-less .form-inline .input-group .input-group-addon,
3413
+ .sg-wrapper-less .form-inline .input-group .input-group-btn,
3414
+ .sg-wrapper-less .form-inline .input-group .form-control {
3415
+ width: auto;
3416
+ }
3417
+ .sg-wrapper-less .form-inline .input-group > .form-control {
3418
+ width: 100%;
3419
+ }
3420
+ .sg-wrapper-less .form-inline .control-label {
3421
+ margin-bottom: 0;
3422
+ vertical-align: middle;
3423
+ }
3424
+ .sg-wrapper-less .form-inline .radio,
3425
+ .sg-wrapper-less .form-inline .checkbox {
3426
+ display: inline-block;
3427
+ margin-top: 0;
3428
+ margin-bottom: 0;
3429
+ vertical-align: middle;
3430
+ }
3431
+ .sg-wrapper-less .form-inline .radio label,
3432
+ .sg-wrapper-less .form-inline .checkbox label {
3433
+ padding-left: 0;
3434
+ }
3435
+ .sg-wrapper-less .form-inline .radio input[type="radio"],
3436
+ .sg-wrapper-less .form-inline .checkbox input[type="checkbox"] {
3437
+ position: relative;
3438
+ margin-left: 0;
3439
+ }
3440
+ .sg-wrapper-less .form-inline .has-feedback .form-control-feedback {
3441
+ top: 0;
3442
+ }
3443
+ }
3444
+ .sg-wrapper-less .form-horizontal .radio,
3445
+ .sg-wrapper-less .form-horizontal .checkbox,
3446
+ .sg-wrapper-less .form-horizontal .radio-inline,
3447
+ .sg-wrapper-less .form-horizontal .checkbox-inline {
3448
+ margin-top: 0;
3449
+ margin-bottom: 0;
3450
+ padding-top: 11px;
3451
+ }
3452
+ .sg-wrapper-less .form-horizontal .radio,
3453
+ .sg-wrapper-less .form-horizontal .checkbox {
3454
+ min-height: 32px;
3455
+ }
3456
+ .sg-wrapper-less .form-horizontal .form-group {
3457
+ margin-left: -15px;
3458
+ margin-right: -15px;
3459
+ }
3460
+ @media (min-width: 768px) {
3461
+ .sg-wrapper-less .form-horizontal .control-label {
3462
+ text-align: right;
3463
+ margin-bottom: 0;
3464
+ padding-top: 11px;
3465
+ }
3466
+ }
3467
+ .sg-wrapper-less .form-horizontal .has-feedback .form-control-feedback {
3468
+ right: 15px;
3469
+ }
3470
+ @media (min-width: 768px) {
3471
+ .sg-wrapper-less .form-horizontal .form-group-lg .control-label {
3472
+ padding-top: 24.9999994px;
3473
+ }
3474
+ }
3475
+ @media (min-width: 768px) {
3476
+ .sg-wrapper-less .form-horizontal .form-group-sm .control-label {
3477
+ padding-top: 6px;
3478
+ }
3479
+ }
3480
+ .sg-wrapper-less .btn {
3481
+ display: inline-block;
3482
+ margin-bottom: 0;
3483
+ font-weight: normal;
3484
+ text-align: center;
3485
+ vertical-align: middle;
3486
+ -ms-touch-action: manipulation;
3487
+ touch-action: manipulation;
3488
+ cursor: pointer;
3489
+ background-image: none;
3490
+ border: 1px solid transparent;
3491
+ white-space: nowrap;
3492
+ padding: 10px 18px;
3493
+ font-size: 15px;
3494
+ line-height: 1.42857143;
3495
+ border-radius: 0;
3496
+ -webkit-user-select: none;
3497
+ -moz-user-select: none;
3498
+ -ms-user-select: none;
3499
+ user-select: none;
3500
+ }
3501
+ .sg-wrapper-less .btn:focus,
3502
+ .sg-wrapper-less .btn:active:focus,
3503
+ .sg-wrapper-less .btn.active:focus,
3504
+ .sg-wrapper-less .btn.focus,
3505
+ .sg-wrapper-less .btn:active.focus,
3506
+ .sg-wrapper-less .btn.active.focus {
3507
+ outline: thin dotted;
3508
+ outline: 5px auto -webkit-focus-ring-color;
3509
+ outline-offset: -2px;
3510
+ }
3511
+ .sg-wrapper-less .btn:hover,
3512
+ .sg-wrapper-less .btn:focus,
3513
+ .sg-wrapper-less .btn.focus {
3514
+ color: #ffffff;
3515
+ text-decoration: none;
3516
+ }
3517
+ .sg-wrapper-less .btn:active,
3518
+ .sg-wrapper-less .btn.active {
3519
+ outline: 0;
3520
+ background-image: none;
3521
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
3522
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
3523
+ }
3524
+ .sg-wrapper-less .btn.disabled,
3525
+ .sg-wrapper-less .btn[disabled],
3526
+ .sg-wrapper-less fieldset[disabled] .btn {
3527
+ cursor: not-allowed;
3528
+ pointer-events: none;
3529
+ opacity: 0.65;
3530
+ filter: alpha(opacity=65);
3531
+ -webkit-box-shadow: none;
3532
+ box-shadow: none;
3533
+ }
3534
+ .sg-wrapper-less .btn-default {
3535
+ color: #ffffff;
3536
+ background-color: #222222;
3537
+ border-color: #222222;
3538
+ }
3539
+ .sg-wrapper-less .btn-default:hover,
3540
+ .sg-wrapper-less .btn-default:focus,
3541
+ .sg-wrapper-less .btn-default.focus,
3542
+ .sg-wrapper-less .btn-default:active,
3543
+ .sg-wrapper-less .btn-default.active,
3544
+ .sg-wrapper-less .open > .dropdown-toggle.btn-default {
3545
+ color: #ffffff;
3546
+ background-color: #090909;
3547
+ border-color: #040404;
3548
+ }
3549
+ .sg-wrapper-less .btn-default:active,
3550
+ .sg-wrapper-less .btn-default.active,
3551
+ .sg-wrapper-less .open > .dropdown-toggle.btn-default {
3552
+ background-image: none;
3553
+ }
3554
+ .sg-wrapper-less .btn-default.disabled,
3555
+ .sg-wrapper-less .btn-default[disabled],
3556
+ .sg-wrapper-less fieldset[disabled] .btn-default,
3557
+ .sg-wrapper-less .btn-default.disabled:hover,
3558
+ .sg-wrapper-less .btn-default[disabled]:hover,
3559
+ .sg-wrapper-less fieldset[disabled] .btn-default:hover,
3560
+ .sg-wrapper-less .btn-default.disabled:focus,
3561
+ .sg-wrapper-less .btn-default[disabled]:focus,
3562
+ .sg-wrapper-less fieldset[disabled] .btn-default:focus,
3563
+ .sg-wrapper-less .btn-default.disabled.focus,
3564
+ .sg-wrapper-less .btn-default[disabled].focus,
3565
+ .sg-wrapper-less fieldset[disabled] .btn-default.focus,
3566
+ .sg-wrapper-less .btn-default.disabled:active,
3567
+ .sg-wrapper-less .btn-default[disabled]:active,
3568
+ .sg-wrapper-less fieldset[disabled] .btn-default:active,
3569
+ .sg-wrapper-less .btn-default.disabled.active,
3570
+ .sg-wrapper-less .btn-default[disabled].active,
3571
+ .sg-wrapper-less fieldset[disabled] .btn-default.active {
3572
+ background-color: #222222;
3573
+ border-color: #222222;
3574
+ }
3575
+ .sg-wrapper-less .btn-default .badge {
3576
+ color: #222222;
3577
+ background-color: #ffffff;
3578
+ }
3579
+ .sg-wrapper-less .btn-primary {
3580
+ color: #ffffff;
3581
+ background-color: #2780e3;
3582
+ border-color: #2780e3;
3583
+ }
3584
+ .sg-wrapper-less .btn-primary:hover,
3585
+ .sg-wrapper-less .btn-primary:focus,
3586
+ .sg-wrapper-less .btn-primary.focus,
3587
+ .sg-wrapper-less .btn-primary:active,
3588
+ .sg-wrapper-less .btn-primary.active,
3589
+ .sg-wrapper-less .open > .dropdown-toggle.btn-primary {
3590
+ color: #ffffff;
3591
+ background-color: #1967be;
3592
+ border-color: #1862b5;
3593
+ }
3594
+ .sg-wrapper-less .btn-primary:active,
3595
+ .sg-wrapper-less .btn-primary.active,
3596
+ .sg-wrapper-less .open > .dropdown-toggle.btn-primary {
3597
+ background-image: none;
3598
+ }
3599
+ .sg-wrapper-less .btn-primary.disabled,
3600
+ .sg-wrapper-less .btn-primary[disabled],
3601
+ .sg-wrapper-less fieldset[disabled] .btn-primary,
3602
+ .sg-wrapper-less .btn-primary.disabled:hover,
3603
+ .sg-wrapper-less .btn-primary[disabled]:hover,
3604
+ .sg-wrapper-less fieldset[disabled] .btn-primary:hover,
3605
+ .sg-wrapper-less .btn-primary.disabled:focus,
3606
+ .sg-wrapper-less .btn-primary[disabled]:focus,
3607
+ .sg-wrapper-less fieldset[disabled] .btn-primary:focus,
3608
+ .sg-wrapper-less .btn-primary.disabled.focus,
3609
+ .sg-wrapper-less .btn-primary[disabled].focus,
3610
+ .sg-wrapper-less fieldset[disabled] .btn-primary.focus,
3611
+ .sg-wrapper-less .btn-primary.disabled:active,
3612
+ .sg-wrapper-less .btn-primary[disabled]:active,
3613
+ .sg-wrapper-less fieldset[disabled] .btn-primary:active,
3614
+ .sg-wrapper-less .btn-primary.disabled.active,
3615
+ .sg-wrapper-less .btn-primary[disabled].active,
3616
+ .sg-wrapper-less fieldset[disabled] .btn-primary.active {
3617
+ background-color: #2780e3;
3618
+ border-color: #2780e3;
3619
+ }
3620
+ .sg-wrapper-less .btn-primary .badge {
3621
+ color: #2780e3;
3622
+ background-color: #ffffff;
3623
+ }
3624
+ .sg-wrapper-less .btn-success {
3625
+ color: #ffffff;
3626
+ background-color: #3fb618;
3627
+ border-color: #3fb618;
3628
+ }
3629
+ .sg-wrapper-less .btn-success:hover,
3630
+ .sg-wrapper-less .btn-success:focus,
3631
+ .sg-wrapper-less .btn-success.focus,
3632
+ .sg-wrapper-less .btn-success:active,
3633
+ .sg-wrapper-less .btn-success.active,
3634
+ .sg-wrapper-less .open > .dropdown-toggle.btn-success {
3635
+ color: #ffffff;
3636
+ background-color: #2f8912;
3637
+ border-color: #2c8011;
3638
+ }
3639
+ .sg-wrapper-less .btn-success:active,
3640
+ .sg-wrapper-less .btn-success.active,
3641
+ .sg-wrapper-less .open > .dropdown-toggle.btn-success {
3642
+ background-image: none;
3643
+ }
3644
+ .sg-wrapper-less .btn-success.disabled,
3645
+ .sg-wrapper-less .btn-success[disabled],
3646
+ .sg-wrapper-less fieldset[disabled] .btn-success,
3647
+ .sg-wrapper-less .btn-success.disabled:hover,
3648
+ .sg-wrapper-less .btn-success[disabled]:hover,
3649
+ .sg-wrapper-less fieldset[disabled] .btn-success:hover,
3650
+ .sg-wrapper-less .btn-success.disabled:focus,
3651
+ .sg-wrapper-less .btn-success[disabled]:focus,
3652
+ .sg-wrapper-less fieldset[disabled] .btn-success:focus,
3653
+ .sg-wrapper-less .btn-success.disabled.focus,
3654
+ .sg-wrapper-less .btn-success[disabled].focus,
3655
+ .sg-wrapper-less fieldset[disabled] .btn-success.focus,
3656
+ .sg-wrapper-less .btn-success.disabled:active,
3657
+ .sg-wrapper-less .btn-success[disabled]:active,
3658
+ .sg-wrapper-less fieldset[disabled] .btn-success:active,
3659
+ .sg-wrapper-less .btn-success.disabled.active,
3660
+ .sg-wrapper-less .btn-success[disabled].active,
3661
+ .sg-wrapper-less fieldset[disabled] .btn-success.active {
3662
+ background-color: #3fb618;
3663
+ border-color: #3fb618;
3664
+ }
3665
+ .sg-wrapper-less .btn-success .badge {
3666
+ color: #3fb618;
3667
+ background-color: #ffffff;
3668
+ }
3669
+ .sg-wrapper-less .btn-info {
3670
+ color: #ffffff;
3671
+ background-color: #9954bb;
3672
+ border-color: #9954bb;
3673
+ }
3674
+ .sg-wrapper-less .btn-info:hover,
3675
+ .sg-wrapper-less .btn-info:focus,
3676
+ .sg-wrapper-less .btn-info.focus,
3677
+ .sg-wrapper-less .btn-info:active,
3678
+ .sg-wrapper-less .btn-info.active,
3679
+ .sg-wrapper-less .open > .dropdown-toggle.btn-info {
3680
+ color: #ffffff;
3681
+ background-color: #7e3f9d;
3682
+ border-color: #783c96;
3683
+ }
3684
+ .sg-wrapper-less .btn-info:active,
3685
+ .sg-wrapper-less .btn-info.active,
3686
+ .sg-wrapper-less .open > .dropdown-toggle.btn-info {
3687
+ background-image: none;
3688
+ }
3689
+ .sg-wrapper-less .btn-info.disabled,
3690
+ .sg-wrapper-less .btn-info[disabled],
3691
+ .sg-wrapper-less fieldset[disabled] .btn-info,
3692
+ .sg-wrapper-less .btn-info.disabled:hover,
3693
+ .sg-wrapper-less .btn-info[disabled]:hover,
3694
+ .sg-wrapper-less fieldset[disabled] .btn-info:hover,
3695
+ .sg-wrapper-less .btn-info.disabled:focus,
3696
+ .sg-wrapper-less .btn-info[disabled]:focus,
3697
+ .sg-wrapper-less fieldset[disabled] .btn-info:focus,
3698
+ .sg-wrapper-less .btn-info.disabled.focus,
3699
+ .sg-wrapper-less .btn-info[disabled].focus,
3700
+ .sg-wrapper-less fieldset[disabled] .btn-info.focus,
3701
+ .sg-wrapper-less .btn-info.disabled:active,
3702
+ .sg-wrapper-less .btn-info[disabled]:active,
3703
+ .sg-wrapper-less fieldset[disabled] .btn-info:active,
3704
+ .sg-wrapper-less .btn-info.disabled.active,
3705
+ .sg-wrapper-less .btn-info[disabled].active,
3706
+ .sg-wrapper-less fieldset[disabled] .btn-info.active {
3707
+ background-color: #9954bb;
3708
+ border-color: #9954bb;
3709
+ }
3710
+ .sg-wrapper-less .btn-info .badge {
3711
+ color: #9954bb;
3712
+ background-color: #ffffff;
3713
+ }
3714
+ .sg-wrapper-less .btn-warning {
3715
+ color: #ffffff;
3716
+ background-color: #ff7518;
3717
+ border-color: #ff7518;
3718
+ }
3719
+ .sg-wrapper-less .btn-warning:hover,
3720
+ .sg-wrapper-less .btn-warning:focus,
3721
+ .sg-wrapper-less .btn-warning.focus,
3722
+ .sg-wrapper-less .btn-warning:active,
3723
+ .sg-wrapper-less .btn-warning.active,
3724
+ .sg-wrapper-less .open > .dropdown-toggle.btn-warning {
3725
+ color: #ffffff;
3726
+ background-color: #e45c00;
3727
+ border-color: #da5800;
3728
+ }
3729
+ .sg-wrapper-less .btn-warning:active,
3730
+ .sg-wrapper-less .btn-warning.active,
3731
+ .sg-wrapper-less .open > .dropdown-toggle.btn-warning {
3732
+ background-image: none;
3733
+ }
3734
+ .sg-wrapper-less .btn-warning.disabled,
3735
+ .sg-wrapper-less .btn-warning[disabled],
3736
+ .sg-wrapper-less fieldset[disabled] .btn-warning,
3737
+ .sg-wrapper-less .btn-warning.disabled:hover,
3738
+ .sg-wrapper-less .btn-warning[disabled]:hover,
3739
+ .sg-wrapper-less fieldset[disabled] .btn-warning:hover,
3740
+ .sg-wrapper-less .btn-warning.disabled:focus,
3741
+ .sg-wrapper-less .btn-warning[disabled]:focus,
3742
+ .sg-wrapper-less fieldset[disabled] .btn-warning:focus,
3743
+ .sg-wrapper-less .btn-warning.disabled.focus,
3744
+ .sg-wrapper-less .btn-warning[disabled].focus,
3745
+ .sg-wrapper-less fieldset[disabled] .btn-warning.focus,
3746
+ .sg-wrapper-less .btn-warning.disabled:active,
3747
+ .sg-wrapper-less .btn-warning[disabled]:active,
3748
+ .sg-wrapper-less fieldset[disabled] .btn-warning:active,
3749
+ .sg-wrapper-less .btn-warning.disabled.active,
3750
+ .sg-wrapper-less .btn-warning[disabled].active,
3751
+ .sg-wrapper-less fieldset[disabled] .btn-warning.active {
3752
+ background-color: #ff7518;
3753
+ border-color: #ff7518;
3754
+ }
3755
+ .sg-wrapper-less .btn-warning .badge {
3756
+ color: #ff7518;
3757
+ background-color: #ffffff;
3758
+ }
3759
+ .sg-wrapper-less .btn-danger {
3760
+ color: #ffffff;
3761
+ background-color: #ff0039;
3762
+ border-color: #ff0039;
3763
+ }
3764
+ .sg-wrapper-less .btn-danger:hover,
3765
+ .sg-wrapper-less .btn-danger:focus,
3766
+ .sg-wrapper-less .btn-danger.focus,
3767
+ .sg-wrapper-less .btn-danger:active,
3768
+ .sg-wrapper-less .btn-danger.active,
3769
+ .sg-wrapper-less .open > .dropdown-toggle.btn-danger {
3770
+ color: #ffffff;
3771
+ background-color: #cc002e;
3772
+ border-color: #c2002b;
3773
+ }
3774
+ .sg-wrapper-less .btn-danger:active,
3775
+ .sg-wrapper-less .btn-danger.active,
3776
+ .sg-wrapper-less .open > .dropdown-toggle.btn-danger {
3777
+ background-image: none;
3778
+ }
3779
+ .sg-wrapper-less .btn-danger.disabled,
3780
+ .sg-wrapper-less .btn-danger[disabled],
3781
+ .sg-wrapper-less fieldset[disabled] .btn-danger,
3782
+ .sg-wrapper-less .btn-danger.disabled:hover,
3783
+ .sg-wrapper-less .btn-danger[disabled]:hover,
3784
+ .sg-wrapper-less fieldset[disabled] .btn-danger:hover,
3785
+ .sg-wrapper-less .btn-danger.disabled:focus,
3786
+ .sg-wrapper-less .btn-danger[disabled]:focus,
3787
+ .sg-wrapper-less fieldset[disabled] .btn-danger:focus,
3788
+ .sg-wrapper-less .btn-danger.disabled.focus,
3789
+ .sg-wrapper-less .btn-danger[disabled].focus,
3790
+ .sg-wrapper-less fieldset[disabled] .btn-danger.focus,
3791
+ .sg-wrapper-less .btn-danger.disabled:active,
3792
+ .sg-wrapper-less .btn-danger[disabled]:active,
3793
+ .sg-wrapper-less fieldset[disabled] .btn-danger:active,
3794
+ .sg-wrapper-less .btn-danger.disabled.active,
3795
+ .sg-wrapper-less .btn-danger[disabled].active,
3796
+ .sg-wrapper-less fieldset[disabled] .btn-danger.active {
3797
+ background-color: #ff0039;
3798
+ border-color: #ff0039;
3799
+ }
3800
+ .sg-wrapper-less .btn-danger .badge {
3801
+ color: #ff0039;
3802
+ background-color: #ffffff;
3803
+ }
3804
+ .sg-wrapper-less .btn-link {
3805
+ color: #2780e3;
3806
+ font-weight: normal;
3807
+ border-radius: 0;
3808
+ }
3809
+ .sg-wrapper-less .btn-link,
3810
+ .sg-wrapper-less .btn-link:active,
3811
+ .sg-wrapper-less .btn-link.active,
3812
+ .sg-wrapper-less .btn-link[disabled],
3813
+ .sg-wrapper-less fieldset[disabled] .btn-link {
3814
+ background-color: transparent;
3815
+ -webkit-box-shadow: none;
3816
+ box-shadow: none;
3817
+ }
3818
+ .sg-wrapper-less .btn-link,
3819
+ .sg-wrapper-less .btn-link:hover,
3820
+ .sg-wrapper-less .btn-link:focus,
3821
+ .sg-wrapper-less .btn-link:active {
3822
+ border-color: transparent;
3823
+ }
3824
+ .sg-wrapper-less .btn-link:hover,
3825
+ .sg-wrapper-less .btn-link:focus {
3826
+ color: #165ba8;
3827
+ text-decoration: underline;
3828
+ background-color: transparent;
3829
+ }
3830
+ .sg-wrapper-less .btn-link[disabled]:hover,
3831
+ .sg-wrapper-less fieldset[disabled] .btn-link:hover,
3832
+ .sg-wrapper-less .btn-link[disabled]:focus,
3833
+ .sg-wrapper-less fieldset[disabled] .btn-link:focus {
3834
+ color: #999999;
3835
+ text-decoration: none;
3836
+ }
3837
+ .sg-wrapper-less .btn-lg,
3838
+ .sg-wrapper-less .btn-group-lg > .btn {
3839
+ padding: 18px 30px;
3840
+ font-size: 19px;
3841
+ line-height: 1.3333333;
3842
+ border-radius: 0;
3843
+ }
3844
+ .sg-wrapper-less .btn-sm,
3845
+ .sg-wrapper-less .btn-group-sm > .btn {
3846
+ padding: 5px 10px;
3847
+ font-size: 13px;
3848
+ line-height: 1.5;
3849
+ border-radius: 0;
3850
+ }
3851
+ .sg-wrapper-less .btn-xs,
3852
+ .sg-wrapper-less .btn-group-xs > .btn {
3853
+ padding: 1px 5px;
3854
+ font-size: 13px;
3855
+ line-height: 1.5;
3856
+ border-radius: 0;
3857
+ }
3858
+ .sg-wrapper-less .btn-block {
3859
+ display: block;
3860
+ width: 100%;
3861
+ }
3862
+ .sg-wrapper-less .btn-block + .btn-block {
3863
+ margin-top: 5px;
3864
+ }
3865
+ .sg-wrapper-less input[type="submit"].btn-block,
3866
+ .sg-wrapper-less input[type="reset"].btn-block,
3867
+ .sg-wrapper-less input[type="button"].btn-block {
3868
+ width: 100%;
3869
+ }
3870
+ .sg-wrapper-less .fade {
3871
+ opacity: 0;
3872
+ -webkit-transition: opacity 0.15s linear;
3873
+ -o-transition: opacity 0.15s linear;
3874
+ transition: opacity 0.15s linear;
3875
+ }
3876
+ .sg-wrapper-less .fade.in {
3877
+ opacity: 1;
3878
+ }
3879
+ .sg-wrapper-less .collapse {
3880
+ display: none;
3881
+ }
3882
+ .sg-wrapper-less .collapse.in {
3883
+ display: block;
3884
+ }
3885
+ .sg-wrapper-less tr.collapse.in {
3886
+ display: table-row;
3887
+ }
3888
+ .sg-wrapper-less tbody.collapse.in {
3889
+ display: table-row-group;
3890
+ }
3891
+ .sg-wrapper-less .collapsing {
3892
+ position: relative;
3893
+ height: 0;
3894
+ overflow: hidden;
3895
+ -webkit-transition-property: height, visibility;
3896
+ -o-transition-property: height, visibility;
3897
+ transition-property: height, visibility;
3898
+ -webkit-transition-duration: 0.35s;
3899
+ -o-transition-duration: 0.35s;
3900
+ transition-duration: 0.35s;
3901
+ -webkit-transition-timing-function: ease;
3902
+ -o-transition-timing-function: ease;
3903
+ transition-timing-function: ease;
3904
+ }
3905
+ .sg-wrapper-less .caret {
3906
+ display: inline-block;
3907
+ width: 0;
3908
+ height: 0;
3909
+ margin-left: 2px;
3910
+ vertical-align: middle;
3911
+ border-top: 4px dashed;
3912
+ border-right: 4px solid transparent;
3913
+ border-left: 4px solid transparent;
3914
+ }
3915
+ .sg-wrapper-less .dropup,
3916
+ .sg-wrapper-less .dropdown {
3917
+ position: relative;
3918
+ }
3919
+ .sg-wrapper-less .dropdown-toggle:focus {
3920
+ outline: 0;
3921
+ }
3922
+ .sg-wrapper-less .dropdown-menu {
3923
+ position: absolute;
3924
+ top: 100%;
3925
+ left: 0;
3926
+ z-index: 1000;
3927
+ display: none;
3928
+ float: left;
3929
+ min-width: 160px;
3930
+ padding: 5px 0;
3931
+ margin: 2px 0 0;
3932
+ list-style: none;
3933
+ font-size: 15px;
3934
+ text-align: left;
3935
+ background-color: #ffffff;
3936
+ border: 1px solid #cccccc;
3937
+ border: 1px solid rgba(0, 0, 0, 0.15);
3938
+ border-radius: 0;
3939
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
3940
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
3941
+ -webkit-background-clip: padding-box;
3942
+ background-clip: padding-box;
3943
+ }
3944
+ .sg-wrapper-less .dropdown-menu.pull-right {
3945
+ right: 0;
3946
+ left: auto;
3947
+ }
3948
+ .sg-wrapper-less .dropdown-menu .divider {
3949
+ height: 1px;
3950
+ margin: 9.5px 0;
3951
+ overflow: hidden;
3952
+ background-color: #e5e5e5;
3953
+ }
3954
+ .sg-wrapper-less .dropdown-menu > li > a {
3955
+ display: block;
3956
+ padding: 3px 20px;
3957
+ clear: both;
3958
+ font-weight: normal;
3959
+ line-height: 1.42857143;
3960
+ color: #333333;
3961
+ white-space: nowrap;
3962
+ }
3963
+ .sg-wrapper-less .dropdown-menu > li > a:hover,
3964
+ .sg-wrapper-less .dropdown-menu > li > a:focus {
3965
+ text-decoration: none;
3966
+ color: #ffffff;
3967
+ background-color: #2780e3;
3968
+ }
3969
+ .sg-wrapper-less .dropdown-menu > .active > a,
3970
+ .sg-wrapper-less .dropdown-menu > .active > a:hover,
3971
+ .sg-wrapper-less .dropdown-menu > .active > a:focus {
3972
+ color: #ffffff;
3973
+ text-decoration: none;
3974
+ outline: 0;
3975
+ background-color: #2780e3;
3976
+ }
3977
+ .sg-wrapper-less .dropdown-menu > .disabled > a,
3978
+ .sg-wrapper-less .dropdown-menu > .disabled > a:hover,
3979
+ .sg-wrapper-less .dropdown-menu > .disabled > a:focus {
3980
+ color: #999999;
3981
+ }
3982
+ .sg-wrapper-less .dropdown-menu > .disabled > a:hover,
3983
+ .sg-wrapper-less .dropdown-menu > .disabled > a:focus {
3984
+ text-decoration: none;
3985
+ background-color: transparent;
3986
+ background-image: none;
3987
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
3988
+ cursor: not-allowed;
3989
+ }
3990
+ .sg-wrapper-less .open > .dropdown-menu {
3991
+ display: block;
3992
+ }
3993
+ .sg-wrapper-less .open > a {
3994
+ outline: 0;
3995
+ }
3996
+ .sg-wrapper-less .dropdown-menu-right {
3997
+ left: auto;
3998
+ right: 0;
3999
+ }
4000
+ .sg-wrapper-less .dropdown-menu-left {
4001
+ left: 0;
4002
+ right: auto;
4003
+ }
4004
+ .sg-wrapper-less .dropdown-header {
4005
+ display: block;
4006
+ padding: 3px 20px;
4007
+ font-size: 13px;
4008
+ line-height: 1.42857143;
4009
+ color: #999999;
4010
+ white-space: nowrap;
4011
+ }
4012
+ .sg-wrapper-less .dropdown-backdrop {
4013
+ position: fixed;
4014
+ left: 0;
4015
+ right: 0;
4016
+ bottom: 0;
4017
+ top: 0;
4018
+ z-index: 990;
4019
+ }
4020
+ .sg-wrapper-less .pull-right > .dropdown-menu {
4021
+ right: 0;
4022
+ left: auto;
4023
+ }
4024
+ .sg-wrapper-less .dropup .caret,
4025
+ .sg-wrapper-less .navbar-fixed-bottom .dropdown .caret {
4026
+ border-top: 0;
4027
+ border-bottom: 4px solid;
4028
+ content: "";
4029
+ }
4030
+ .sg-wrapper-less .dropup .dropdown-menu,
4031
+ .sg-wrapper-less .navbar-fixed-bottom .dropdown .dropdown-menu {
4032
+ top: auto;
4033
+ bottom: 100%;
4034
+ margin-bottom: 2px;
4035
+ }
4036
+ @media (min-width: 768px) {
4037
+ .sg-wrapper-less .navbar-right .dropdown-menu {
4038
+ left: auto;
4039
+ right: 0;
4040
+ }
4041
+ .sg-wrapper-less .navbar-right .dropdown-menu-left {
4042
+ left: 0;
4043
+ right: auto;
4044
+ }
4045
+ }
4046
+ .sg-wrapper-less .btn-group,
4047
+ .sg-wrapper-less .btn-group-vertical {
4048
+ position: relative;
4049
+ display: inline-block;
4050
+ vertical-align: middle;
4051
+ }
4052
+ .sg-wrapper-less .btn-group > .btn,
4053
+ .sg-wrapper-less .btn-group-vertical > .btn {
4054
+ position: relative;
4055
+ float: left;
4056
+ }
4057
+ .sg-wrapper-less .btn-group > .btn:hover,
4058
+ .sg-wrapper-less .btn-group-vertical > .btn:hover,
4059
+ .sg-wrapper-less .btn-group > .btn:focus,
4060
+ .sg-wrapper-less .btn-group-vertical > .btn:focus,
4061
+ .sg-wrapper-less .btn-group > .btn:active,
4062
+ .sg-wrapper-less .btn-group-vertical > .btn:active,
4063
+ .sg-wrapper-less .btn-group > .btn.active,
4064
+ .sg-wrapper-less .btn-group-vertical > .btn.active {
4065
+ z-index: 2;
4066
+ }
4067
+ .sg-wrapper-less .btn-group .btn + .btn,
4068
+ .sg-wrapper-less .btn-group .btn + .btn-group,
4069
+ .sg-wrapper-less .btn-group .btn-group + .btn,
4070
+ .sg-wrapper-less .btn-group .btn-group + .btn-group {
4071
+ margin-left: -1px;
4072
+ }
4073
+ .sg-wrapper-less .btn-toolbar {
4074
+ margin-left: -5px;
4075
+ }
4076
+ .sg-wrapper-less .btn-toolbar .btn-group,
4077
+ .sg-wrapper-less .btn-toolbar .input-group {
4078
+ float: left;
4079
+ }
4080
+ .sg-wrapper-less .btn-toolbar > .btn,
4081
+ .sg-wrapper-less .btn-toolbar > .btn-group,
4082
+ .sg-wrapper-less .btn-toolbar > .input-group {
4083
+ margin-left: 5px;
4084
+ }
4085
+ .sg-wrapper-less .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
4086
+ border-radius: 0;
4087
+ }
4088
+ .sg-wrapper-less .btn-group > .btn:first-child {
4089
+ margin-left: 0;
4090
+ }
4091
+ .sg-wrapper-less .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
4092
+ border-bottom-right-radius: 0;
4093
+ border-top-right-radius: 0;
4094
+ }
4095
+ .sg-wrapper-less .btn-group > .btn:last-child:not(:first-child),
4096
+ .sg-wrapper-less .btn-group > .dropdown-toggle:not(:first-child) {
4097
+ border-bottom-left-radius: 0;
4098
+ border-top-left-radius: 0;
4099
+ }
4100
+ .sg-wrapper-less .btn-group > .btn-group {
4101
+ float: left;
4102
+ }
4103
+ .sg-wrapper-less .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
4104
+ border-radius: 0;
4105
+ }
4106
+ .sg-wrapper-less .btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
4107
+ .sg-wrapper-less .btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
4108
+ border-bottom-right-radius: 0;
4109
+ border-top-right-radius: 0;
4110
+ }
4111
+ .sg-wrapper-less .btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
4112
+ border-bottom-left-radius: 0;
4113
+ border-top-left-radius: 0;
4114
+ }
4115
+ .sg-wrapper-less .btn-group .dropdown-toggle:active,
4116
+ .sg-wrapper-less .btn-group.open .dropdown-toggle {
4117
+ outline: 0;
4118
+ }
4119
+ .sg-wrapper-less .btn-group > .btn + .dropdown-toggle {
4120
+ padding-left: 8px;
4121
+ padding-right: 8px;
4122
+ }
4123
+ .sg-wrapper-less .btn-group > .btn-lg + .dropdown-toggle {
4124
+ padding-left: 12px;
4125
+ padding-right: 12px;
4126
+ }
4127
+ .sg-wrapper-less .btn-group.open .dropdown-toggle {
4128
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
4129
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
4130
+ }
4131
+ .sg-wrapper-less .btn-group.open .dropdown-toggle.btn-link {
4132
+ -webkit-box-shadow: none;
4133
+ box-shadow: none;
4134
+ }
4135
+ .sg-wrapper-less .btn .caret {
4136
+ margin-left: 0;
4137
+ }
4138
+ .sg-wrapper-less .btn-lg .caret {
4139
+ border-width: 5px 5px 0;
4140
+ border-bottom-width: 0;
4141
+ }
4142
+ .sg-wrapper-less .dropup .btn-lg .caret {
4143
+ border-width: 0 5px 5px;
4144
+ }
4145
+ .sg-wrapper-less .btn-group-vertical > .btn,
4146
+ .sg-wrapper-less .btn-group-vertical > .btn-group,
4147
+ .sg-wrapper-less .btn-group-vertical > .btn-group > .btn {
4148
+ display: block;
4149
+ float: none;
4150
+ width: 100%;
4151
+ max-width: 100%;
4152
+ }
4153
+ .sg-wrapper-less .btn-group-vertical > .btn-group > .btn {
4154
+ float: none;
4155
+ }
4156
+ .sg-wrapper-less .btn-group-vertical > .btn + .btn,
4157
+ .sg-wrapper-less .btn-group-vertical > .btn + .btn-group,
4158
+ .sg-wrapper-less .btn-group-vertical > .btn-group + .btn,
4159
+ .sg-wrapper-less .btn-group-vertical > .btn-group + .btn-group {
4160
+ margin-top: -1px;
4161
+ margin-left: 0;
4162
+ }
4163
+ .sg-wrapper-less .btn-group-vertical > .btn:not(:first-child):not(:last-child) {
4164
+ border-radius: 0;
4165
+ }
4166
+ .sg-wrapper-less .btn-group-vertical > .btn:first-child:not(:last-child) {
4167
+ border-top-right-radius: 0;
4168
+ border-bottom-right-radius: 0;
4169
+ border-bottom-left-radius: 0;
4170
+ }
4171
+ .sg-wrapper-less .btn-group-vertical > .btn:last-child:not(:first-child) {
4172
+ border-bottom-left-radius: 0;
4173
+ border-top-right-radius: 0;
4174
+ border-top-left-radius: 0;
4175
+ }
4176
+ .sg-wrapper-less .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
4177
+ border-radius: 0;
4178
+ }
4179
+ .sg-wrapper-less .btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
4180
+ .sg-wrapper-less .btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
4181
+ border-bottom-right-radius: 0;
4182
+ border-bottom-left-radius: 0;
4183
+ }
4184
+ .sg-wrapper-less .btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
4185
+ border-top-right-radius: 0;
4186
+ border-top-left-radius: 0;
4187
+ }
4188
+ .sg-wrapper-less .btn-group-justified {
4189
+ display: table;
4190
+ width: 100%;
4191
+ table-layout: fixed;
4192
+ border-collapse: separate;
4193
+ }
4194
+ .sg-wrapper-less .btn-group-justified > .btn,
4195
+ .sg-wrapper-less .btn-group-justified > .btn-group {
4196
+ float: none;
4197
+ display: table-cell;
4198
+ width: 1%;
4199
+ }
4200
+ .sg-wrapper-less .btn-group-justified > .btn-group .btn {
4201
+ width: 100%;
4202
+ }
4203
+ .sg-wrapper-less .btn-group-justified > .btn-group .dropdown-menu {
4204
+ left: auto;
4205
+ }
4206
+ .sg-wrapper-less [data-toggle="buttons"] > .btn input[type="radio"],
4207
+ .sg-wrapper-less [data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
4208
+ .sg-wrapper-less [data-toggle="buttons"] > .btn input[type="checkbox"],
4209
+ .sg-wrapper-less [data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
4210
+ position: absolute;
4211
+ clip: rect(0, 0, 0, 0);
4212
+ pointer-events: none;
4213
+ }
4214
+ .sg-wrapper-less .input-group {
4215
+ position: relative;
4216
+ display: table;
4217
+ border-collapse: separate;
4218
+ }
4219
+ .sg-wrapper-less .input-group[class*="col-"] {
4220
+ float: none;
4221
+ padding-left: 0;
4222
+ padding-right: 0;
4223
+ }
4224
+ .sg-wrapper-less .input-group .form-control {
4225
+ position: relative;
4226
+ z-index: 2;
4227
+ float: left;
4228
+ width: 100%;
4229
+ margin-bottom: 0;
4230
+ }
4231
+ .sg-wrapper-less .input-group-lg > .form-control,
4232
+ .sg-wrapper-less .input-group-lg > .input-group-addon,
4233
+ .sg-wrapper-less .input-group-lg > .input-group-btn > .btn {
4234
+ height: 64px;
4235
+ padding: 18px 30px;
4236
+ font-size: 19px;
4237
+ line-height: 1.3333333;
4238
+ border-radius: 0;
4239
+ }
4240
+ .sg-wrapper-less select.input-group-lg > .form-control,
4241
+ .sg-wrapper-less select.input-group-lg > .input-group-addon,
4242
+ .sg-wrapper-less select.input-group-lg > .input-group-btn > .btn {
4243
+ height: 64px;
4244
+ line-height: 64px;
4245
+ }
4246
+ .sg-wrapper-less textarea.input-group-lg > .form-control,
4247
+ .sg-wrapper-less textarea.input-group-lg > .input-group-addon,
4248
+ .sg-wrapper-less textarea.input-group-lg > .input-group-btn > .btn,
4249
+ .sg-wrapper-less select[multiple].input-group-lg > .form-control,
4250
+ .sg-wrapper-less select[multiple].input-group-lg > .input-group-addon,
4251
+ .sg-wrapper-less select[multiple].input-group-lg > .input-group-btn > .btn {
4252
+ height: auto;
4253
+ }
4254
+ .sg-wrapper-less .input-group-sm > .form-control,
4255
+ .sg-wrapper-less .input-group-sm > .input-group-addon,
4256
+ .sg-wrapper-less .input-group-sm > .input-group-btn > .btn {
4257
+ height: 31px;
4258
+ padding: 5px 10px;
4259
+ font-size: 13px;
4260
+ line-height: 1.5;
4261
+ border-radius: 0;
4262
+ }
4263
+ .sg-wrapper-less select.input-group-sm > .form-control,
4264
+ .sg-wrapper-less select.input-group-sm > .input-group-addon,
4265
+ .sg-wrapper-less select.input-group-sm > .input-group-btn > .btn {
4266
+ height: 31px;
4267
+ line-height: 31px;
4268
+ }
4269
+ .sg-wrapper-less textarea.input-group-sm > .form-control,
4270
+ .sg-wrapper-less textarea.input-group-sm > .input-group-addon,
4271
+ .sg-wrapper-less textarea.input-group-sm > .input-group-btn > .btn,
4272
+ .sg-wrapper-less select[multiple].input-group-sm > .form-control,
4273
+ .sg-wrapper-less select[multiple].input-group-sm > .input-group-addon,
4274
+ .sg-wrapper-less select[multiple].input-group-sm > .input-group-btn > .btn {
4275
+ height: auto;
4276
+ }
4277
+ .sg-wrapper-less .input-group-addon,
4278
+ .sg-wrapper-less .input-group-btn,
4279
+ .sg-wrapper-less .input-group .form-control {
4280
+ display: table-cell;
4281
+ }
4282
+ .sg-wrapper-less .input-group-addon:not(:first-child):not(:last-child),
4283
+ .sg-wrapper-less .input-group-btn:not(:first-child):not(:last-child),
4284
+ .sg-wrapper-less .input-group .form-control:not(:first-child):not(:last-child) {
4285
+ border-radius: 0;
4286
+ }
4287
+ .sg-wrapper-less .input-group-addon,
4288
+ .sg-wrapper-less .input-group-btn {
4289
+ width: 1%;
4290
+ white-space: nowrap;
4291
+ vertical-align: middle;
4292
+ }
4293
+ .sg-wrapper-less .input-group-addon {
4294
+ padding: 10px 18px;
4295
+ font-size: 15px;
4296
+ font-weight: normal;
4297
+ line-height: 1;
4298
+ color: #333333;
4299
+ text-align: center;
4300
+ background-color: #e6e6e6;
4301
+ border: 1px solid #cccccc;
4302
+ border-radius: 0;
4303
+ }
4304
+ .sg-wrapper-less .input-group-addon.input-sm {
4305
+ padding: 5px 10px;
4306
+ font-size: 13px;
4307
+ border-radius: 0;
4308
+ }
4309
+ .sg-wrapper-less .input-group-addon.input-lg {
4310
+ padding: 18px 30px;
4311
+ font-size: 19px;
4312
+ border-radius: 0;
4313
+ }
4314
+ .sg-wrapper-less .input-group-addon input[type="radio"],
4315
+ .sg-wrapper-less .input-group-addon input[type="checkbox"] {
4316
+ margin-top: 0;
4317
+ }
4318
+ .sg-wrapper-less .input-group .form-control:first-child,
4319
+ .sg-wrapper-less .input-group-addon:first-child,
4320
+ .sg-wrapper-less .input-group-btn:first-child > .btn,
4321
+ .sg-wrapper-less .input-group-btn:first-child > .btn-group > .btn,
4322
+ .sg-wrapper-less .input-group-btn:first-child > .dropdown-toggle,
4323
+ .sg-wrapper-less .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
4324
+ .sg-wrapper-less .input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
4325
+ border-bottom-right-radius: 0;
4326
+ border-top-right-radius: 0;
4327
+ }
4328
+ .sg-wrapper-less .input-group-addon:first-child {
4329
+ border-right: 0;
4330
+ }
4331
+ .sg-wrapper-less .input-group .form-control:last-child,
4332
+ .sg-wrapper-less .input-group-addon:last-child,
4333
+ .sg-wrapper-less .input-group-btn:last-child > .btn,
4334
+ .sg-wrapper-less .input-group-btn:last-child > .btn-group > .btn,
4335
+ .sg-wrapper-less .input-group-btn:last-child > .dropdown-toggle,
4336
+ .sg-wrapper-less .input-group-btn:first-child > .btn:not(:first-child),
4337
+ .sg-wrapper-less .input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
4338
+ border-bottom-left-radius: 0;
4339
+ border-top-left-radius: 0;
4340
+ }
4341
+ .sg-wrapper-less .input-group-addon:last-child {
4342
+ border-left: 0;
4343
+ }
4344
+ .sg-wrapper-less .input-group-btn {
4345
+ position: relative;
4346
+ font-size: 0;
4347
+ white-space: nowrap;
4348
+ }
4349
+ .sg-wrapper-less .input-group-btn > .btn {
4350
+ position: relative;
4351
+ }
4352
+ .sg-wrapper-less .input-group-btn > .btn + .btn {
4353
+ margin-left: -1px;
4354
+ }
4355
+ .sg-wrapper-less .input-group-btn > .btn:hover,
4356
+ .sg-wrapper-less .input-group-btn > .btn:focus,
4357
+ .sg-wrapper-less .input-group-btn > .btn:active {
4358
+ z-index: 2;
4359
+ }
4360
+ .sg-wrapper-less .input-group-btn:first-child > .btn,
4361
+ .sg-wrapper-less .input-group-btn:first-child > .btn-group {
4362
+ margin-right: -1px;
4363
+ }
4364
+ .sg-wrapper-less .input-group-btn:last-child > .btn,
4365
+ .sg-wrapper-less .input-group-btn:last-child > .btn-group {
4366
+ margin-left: -1px;
4367
+ }
4368
+ .sg-wrapper-less .nav {
4369
+ margin-bottom: 0;
4370
+ padding-left: 0;
4371
+ list-style: none;
4372
+ }
4373
+ .sg-wrapper-less .nav > li {
4374
+ position: relative;
4375
+ display: block;
4376
+ }
4377
+ .sg-wrapper-less .nav > li > a {
4378
+ position: relative;
4379
+ display: block;
4380
+ padding: 10px 15px;
4381
+ }
4382
+ .sg-wrapper-less .nav > li > a:hover,
4383
+ .sg-wrapper-less .nav > li > a:focus {
4384
+ text-decoration: none;
4385
+ background-color: #e6e6e6;
4386
+ }
4387
+ .sg-wrapper-less .nav > li.disabled > a {
4388
+ color: #999999;
4389
+ }
4390
+ .sg-wrapper-less .nav > li.disabled > a:hover,
4391
+ .sg-wrapper-less .nav > li.disabled > a:focus {
4392
+ color: #999999;
4393
+ text-decoration: none;
4394
+ background-color: transparent;
4395
+ cursor: not-allowed;
4396
+ }
4397
+ .sg-wrapper-less .nav .open > a,
4398
+ .sg-wrapper-less .nav .open > a:hover,
4399
+ .sg-wrapper-less .nav .open > a:focus {
4400
+ background-color: #e6e6e6;
4401
+ border-color: #2780e3;
4402
+ }
4403
+ .sg-wrapper-less .nav .nav-divider {
4404
+ height: 1px;
4405
+ margin: 9.5px 0;
4406
+ overflow: hidden;
4407
+ background-color: #e5e5e5;
4408
+ }
4409
+ .sg-wrapper-less .nav > li > a > img {
4410
+ max-width: none;
4411
+ }
4412
+ .sg-wrapper-less .nav-tabs {
4413
+ border-bottom: 1px solid #dddddd;
4414
+ }
4415
+ .sg-wrapper-less .nav-tabs > li {
4416
+ float: left;
4417
+ margin-bottom: -1px;
4418
+ }
4419
+ .sg-wrapper-less .nav-tabs > li > a {
4420
+ margin-right: 2px;
4421
+ line-height: 1.42857143;
4422
+ border: 1px solid transparent;
4423
+ border-radius: 0 0 0 0;
4424
+ }
4425
+ .sg-wrapper-less .nav-tabs > li > a:hover {
4426
+ border-color: #e6e6e6 #e6e6e6 #dddddd;
4427
+ }
4428
+ .sg-wrapper-less .nav-tabs > li.active > a,
4429
+ .sg-wrapper-less .nav-tabs > li.active > a:hover,
4430
+ .sg-wrapper-less .nav-tabs > li.active > a:focus {
4431
+ color: #555555;
4432
+ background-color: #ffffff;
4433
+ border: 1px solid #dddddd;
4434
+ border-bottom-color: transparent;
4435
+ cursor: default;
4436
+ }
4437
+ .sg-wrapper-less .nav-tabs.nav-justified {
4438
+ width: 100%;
4439
+ border-bottom: 0;
4440
+ }
4441
+ .sg-wrapper-less .nav-tabs.nav-justified > li {
4442
+ float: none;
4443
+ }
4444
+ .sg-wrapper-less .nav-tabs.nav-justified > li > a {
4445
+ text-align: center;
4446
+ margin-bottom: 5px;
4447
+ }
4448
+ .sg-wrapper-less .nav-tabs.nav-justified > .dropdown .dropdown-menu {
4449
+ top: auto;
4450
+ left: auto;
4451
+ }
4452
+ @media (min-width: 768px) {
4453
+ .sg-wrapper-less .nav-tabs.nav-justified > li {
4454
+ display: table-cell;
4455
+ width: 1%;
4456
+ }
4457
+ .sg-wrapper-less .nav-tabs.nav-justified > li > a {
4458
+ margin-bottom: 0;
4459
+ }
4460
+ }
4461
+ .sg-wrapper-less .nav-tabs.nav-justified > li > a {
4462
+ margin-right: 0;
4463
+ border-radius: 0;
4464
+ }
4465
+ .sg-wrapper-less .nav-tabs.nav-justified > .active > a,
4466
+ .sg-wrapper-less .nav-tabs.nav-justified > .active > a:hover,
4467
+ .sg-wrapper-less .nav-tabs.nav-justified > .active > a:focus {
4468
+ border: 1px solid #dddddd;
4469
+ }
4470
+ @media (min-width: 768px) {
4471
+ .sg-wrapper-less .nav-tabs.nav-justified > li > a {
4472
+ border-bottom: 1px solid #dddddd;
4473
+ border-radius: 0 0 0 0;
4474
+ }
4475
+ .sg-wrapper-less .nav-tabs.nav-justified > .active > a,
4476
+ .sg-wrapper-less .nav-tabs.nav-justified > .active > a:hover,
4477
+ .sg-wrapper-less .nav-tabs.nav-justified > .active > a:focus {
4478
+ border-bottom-color: #ffffff;
4479
+ }
4480
+ }
4481
+ .sg-wrapper-less .nav-pills > li {
4482
+ float: left;
4483
+ }
4484
+ .sg-wrapper-less .nav-pills > li > a {
4485
+ border-radius: 0;
4486
+ }
4487
+ .sg-wrapper-less .nav-pills > li + li {
4488
+ margin-left: 2px;
4489
+ }
4490
+ .sg-wrapper-less .nav-pills > li.active > a,
4491
+ .sg-wrapper-less .nav-pills > li.active > a:hover,
4492
+ .sg-wrapper-less .nav-pills > li.active > a:focus {
4493
+ color: #ffffff;
4494
+ background-color: #2780e3;
4495
+ }
4496
+ .sg-wrapper-less .nav-stacked > li {
4497
+ float: none;
4498
+ }
4499
+ .sg-wrapper-less .nav-stacked > li + li {
4500
+ margin-top: 2px;
4501
+ margin-left: 0;
4502
+ }
4503
+ .sg-wrapper-less .nav-justified {
4504
+ width: 100%;
4505
+ }
4506
+ .sg-wrapper-less .nav-justified > li {
4507
+ float: none;
4508
+ }
4509
+ .sg-wrapper-less .nav-justified > li > a {
4510
+ text-align: center;
4511
+ margin-bottom: 5px;
4512
+ }
4513
+ .sg-wrapper-less .nav-justified > .dropdown .dropdown-menu {
4514
+ top: auto;
4515
+ left: auto;
4516
+ }
4517
+ @media (min-width: 768px) {
4518
+ .sg-wrapper-less .nav-justified > li {
4519
+ display: table-cell;
4520
+ width: 1%;
4521
+ }
4522
+ .sg-wrapper-less .nav-justified > li > a {
4523
+ margin-bottom: 0;
4524
+ }
4525
+ }
4526
+ .sg-wrapper-less .nav-tabs-justified {
4527
+ border-bottom: 0;
4528
+ }
4529
+ .sg-wrapper-less .nav-tabs-justified > li > a {
4530
+ margin-right: 0;
4531
+ border-radius: 0;
4532
+ }
4533
+ .sg-wrapper-less .nav-tabs-justified > .active > a,
4534
+ .sg-wrapper-less .nav-tabs-justified > .active > a:hover,
4535
+ .sg-wrapper-less .nav-tabs-justified > .active > a:focus {
4536
+ border: 1px solid #dddddd;
4537
+ }
4538
+ @media (min-width: 768px) {
4539
+ .sg-wrapper-less .nav-tabs-justified > li > a {
4540
+ border-bottom: 1px solid #dddddd;
4541
+ border-radius: 0 0 0 0;
4542
+ }
4543
+ .sg-wrapper-less .nav-tabs-justified > .active > a,
4544
+ .sg-wrapper-less .nav-tabs-justified > .active > a:hover,
4545
+ .sg-wrapper-less .nav-tabs-justified > .active > a:focus {
4546
+ border-bottom-color: #ffffff;
4547
+ }
4548
+ }
4549
+ .sg-wrapper-less .tab-content > .tab-pane {
4550
+ display: none;
4551
+ }
4552
+ .sg-wrapper-less .tab-content > .active {
4553
+ display: block;
4554
+ }
4555
+ .sg-wrapper-less .nav-tabs .dropdown-menu {
4556
+ margin-top: -1px;
4557
+ border-top-right-radius: 0;
4558
+ border-top-left-radius: 0;
4559
+ }
4560
+ .sg-wrapper-less .navbar {
4561
+ position: relative;
4562
+ min-height: 50px;
4563
+ margin-bottom: 21px;
4564
+ border: 1px solid transparent;
4565
+ }
4566
+ @media (min-width: 768px) {
4567
+ .sg-wrapper-less .navbar {
4568
+ border-radius: 0;
4569
+ }
4570
+ }
4571
+ @media (min-width: 768px) {
4572
+ .sg-wrapper-less .navbar-header {
4573
+ float: left;
4574
+ }
4575
+ }
4576
+ .sg-wrapper-less .navbar-collapse {
4577
+ overflow-x: visible;
4578
+ padding-right: 15px;
4579
+ padding-left: 15px;
4580
+ border-top: 1px solid transparent;
4581
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
4582
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
4583
+ -webkit-overflow-scrolling: touch;
4584
+ }
4585
+ .sg-wrapper-less .navbar-collapse.in {
4586
+ overflow-y: auto;
4587
+ }
4588
+ @media (min-width: 768px) {
4589
+ .sg-wrapper-less .navbar-collapse {
4590
+ width: auto;
4591
+ border-top: 0;
4592
+ -webkit-box-shadow: none;
4593
+ box-shadow: none;
4594
+ }
4595
+ .sg-wrapper-less .navbar-collapse.collapse {
4596
+ display: block !important;
4597
+ height: auto !important;
4598
+ padding-bottom: 0;
4599
+ overflow: visible !important;
4600
+ }
4601
+ .sg-wrapper-less .navbar-collapse.in {
4602
+ overflow-y: visible;
4603
+ }
4604
+ .sg-wrapper-less .navbar-fixed-top .navbar-collapse,
4605
+ .sg-wrapper-less .navbar-static-top .navbar-collapse,
4606
+ .sg-wrapper-less .navbar-fixed-bottom .navbar-collapse {
4607
+ padding-left: 0;
4608
+ padding-right: 0;
4609
+ }
4610
+ }
4611
+ .sg-wrapper-less .navbar-fixed-top .navbar-collapse,
4612
+ .sg-wrapper-less .navbar-fixed-bottom .navbar-collapse {
4613
+ max-height: 340px;
4614
+ }
4615
+ @media (max-device-width: 480px) and (orientation: landscape) {
4616
+ .sg-wrapper-less .navbar-fixed-top .navbar-collapse,
4617
+ .sg-wrapper-less .navbar-fixed-bottom .navbar-collapse {
4618
+ max-height: 200px;
4619
+ }
4620
+ }
4621
+ .sg-wrapper-less .container > .navbar-header,
4622
+ .sg-wrapper-less .container-fluid > .navbar-header,
4623
+ .sg-wrapper-less .container > .navbar-collapse,
4624
+ .sg-wrapper-less .container-fluid > .navbar-collapse {
4625
+ margin-right: -15px;
4626
+ margin-left: -15px;
4627
+ }
4628
+ @media (min-width: 768px) {
4629
+ .sg-wrapper-less .container > .navbar-header,
4630
+ .sg-wrapper-less .container-fluid > .navbar-header,
4631
+ .sg-wrapper-less .container > .navbar-collapse,
4632
+ .sg-wrapper-less .container-fluid > .navbar-collapse {
4633
+ margin-right: 0;
4634
+ margin-left: 0;
4635
+ }
4636
+ }
4637
+ .sg-wrapper-less .navbar-static-top {
4638
+ z-index: 1000;
4639
+ border-width: 0 0 1px;
4640
+ }
4641
+ @media (min-width: 768px) {
4642
+ .sg-wrapper-less .navbar-static-top {
4643
+ border-radius: 0;
4644
+ }
4645
+ }
4646
+ .sg-wrapper-less .navbar-fixed-top,
4647
+ .sg-wrapper-less .navbar-fixed-bottom {
4648
+ position: fixed;
4649
+ right: 0;
4650
+ left: 0;
4651
+ z-index: 1030;
4652
+ }
4653
+ @media (min-width: 768px) {
4654
+ .sg-wrapper-less .navbar-fixed-top,
4655
+ .sg-wrapper-less .navbar-fixed-bottom {
4656
+ border-radius: 0;
4657
+ }
4658
+ }
4659
+ .sg-wrapper-less .navbar-fixed-top {
4660
+ top: 0;
4661
+ border-width: 0 0 1px;
4662
+ }
4663
+ .sg-wrapper-less .navbar-fixed-bottom {
4664
+ bottom: 0;
4665
+ margin-bottom: 0;
4666
+ border-width: 1px 0 0;
4667
+ }
4668
+ .sg-wrapper-less .navbar-brand {
4669
+ float: left;
4670
+ padding: 14.5px 15px;
4671
+ font-size: 19px;
4672
+ line-height: 21px;
4673
+ height: 50px;
4674
+ }
4675
+ .sg-wrapper-less .navbar-brand:hover,
4676
+ .sg-wrapper-less .navbar-brand:focus {
4677
+ text-decoration: none;
4678
+ }
4679
+ .sg-wrapper-less .navbar-brand > img {
4680
+ display: block;
4681
+ }
4682
+ @media (min-width: 768px) {
4683
+ .sg-wrapper-less .navbar > .container .navbar-brand,
4684
+ .sg-wrapper-less .navbar > .container-fluid .navbar-brand {
4685
+ margin-left: -15px;
4686
+ }
4687
+ }
4688
+ .sg-wrapper-less .navbar-toggle {
4689
+ position: relative;
4690
+ float: right;
4691
+ margin-right: 15px;
4692
+ padding: 9px 10px;
4693
+ margin-top: 8px;
4694
+ margin-bottom: 8px;
4695
+ background-color: transparent;
4696
+ background-image: none;
4697
+ border: 1px solid transparent;
4698
+ border-radius: 0;
4699
+ }
4700
+ .sg-wrapper-less .navbar-toggle:focus {
4701
+ outline: 0;
4702
+ }
4703
+ .sg-wrapper-less .navbar-toggle .icon-bar {
4704
+ display: block;
4705
+ width: 22px;
4706
+ height: 2px;
4707
+ border-radius: 1px;
4708
+ }
4709
+ .sg-wrapper-less .navbar-toggle .icon-bar + .icon-bar {
4710
+ margin-top: 4px;
4711
+ }
4712
+ @media (min-width: 768px) {
4713
+ .sg-wrapper-less .navbar-toggle {
4714
+ display: none;
4715
+ }
4716
+ }
4717
+ .sg-wrapper-less .navbar-nav {
4718
+ margin: 7.25px -15px;
4719
+ }
4720
+ .sg-wrapper-less .navbar-nav > li > a {
4721
+ padding-top: 10px;
4722
+ padding-bottom: 10px;
4723
+ line-height: 21px;
4724
+ }
4725
+ @media (max-width: 767px) {
4726
+ .sg-wrapper-less .navbar-nav .open .dropdown-menu {
4727
+ position: static;
4728
+ float: none;
4729
+ width: auto;
4730
+ margin-top: 0;
4731
+ background-color: transparent;
4732
+ border: 0;
4733
+ -webkit-box-shadow: none;
4734
+ box-shadow: none;
4735
+ }
4736
+ .sg-wrapper-less .navbar-nav .open .dropdown-menu > li > a,
4737
+ .sg-wrapper-less .navbar-nav .open .dropdown-menu .dropdown-header {
4738
+ padding: 5px 15px 5px 25px;
4739
+ }
4740
+ .sg-wrapper-less .navbar-nav .open .dropdown-menu > li > a {
4741
+ line-height: 21px;
4742
+ }
4743
+ .sg-wrapper-less .navbar-nav .open .dropdown-menu > li > a:hover,
4744
+ .sg-wrapper-less .navbar-nav .open .dropdown-menu > li > a:focus {
4745
+ background-image: none;
4746
+ }
4747
+ }
4748
+ @media (min-width: 768px) {
4749
+ .sg-wrapper-less .navbar-nav {
4750
+ float: left;
4751
+ margin: 0;
4752
+ }
4753
+ .sg-wrapper-less .navbar-nav > li {
4754
+ float: left;
4755
+ }
4756
+ .sg-wrapper-less .navbar-nav > li > a {
4757
+ padding-top: 14.5px;
4758
+ padding-bottom: 14.5px;
4759
+ }
4760
+ }
4761
+ .sg-wrapper-less .navbar-form {
4762
+ margin-left: -15px;
4763
+ margin-right: -15px;
4764
+ padding: 10px 15px;
4765
+ border-top: 1px solid transparent;
4766
+ border-bottom: 1px solid transparent;
4767
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
4768
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
4769
+ margin-top: 3.5px;
4770
+ margin-bottom: 3.5px;
4771
+ }
4772
+ @media (min-width: 768px) {
4773
+ .sg-wrapper-less .navbar-form .form-group {
4774
+ display: inline-block;
4775
+ margin-bottom: 0;
4776
+ vertical-align: middle;
4777
+ }
4778
+ .sg-wrapper-less .navbar-form .form-control {
4779
+ display: inline-block;
4780
+ width: auto;
4781
+ vertical-align: middle;
4782
+ }
4783
+ .sg-wrapper-less .navbar-form .form-control-static {
4784
+ display: inline-block;
4785
+ }
4786
+ .sg-wrapper-less .navbar-form .input-group {
4787
+ display: inline-table;
4788
+ vertical-align: middle;
4789
+ }
4790
+ .sg-wrapper-less .navbar-form .input-group .input-group-addon,
4791
+ .sg-wrapper-less .navbar-form .input-group .input-group-btn,
4792
+ .sg-wrapper-less .navbar-form .input-group .form-control {
4793
+ width: auto;
4794
+ }
4795
+ .sg-wrapper-less .navbar-form .input-group > .form-control {
4796
+ width: 100%;
4797
+ }
4798
+ .sg-wrapper-less .navbar-form .control-label {
4799
+ margin-bottom: 0;
4800
+ vertical-align: middle;
4801
+ }
4802
+ .sg-wrapper-less .navbar-form .radio,
4803
+ .sg-wrapper-less .navbar-form .checkbox {
4804
+ display: inline-block;
4805
+ margin-top: 0;
4806
+ margin-bottom: 0;
4807
+ vertical-align: middle;
4808
+ }
4809
+ .sg-wrapper-less .navbar-form .radio label,
4810
+ .sg-wrapper-less .navbar-form .checkbox label {
4811
+ padding-left: 0;
4812
+ }
4813
+ .sg-wrapper-less .navbar-form .radio input[type="radio"],
4814
+ .sg-wrapper-less .navbar-form .checkbox input[type="checkbox"] {
4815
+ position: relative;
4816
+ margin-left: 0;
4817
+ }
4818
+ .sg-wrapper-less .navbar-form .has-feedback .form-control-feedback {
4819
+ top: 0;
4820
+ }
4821
+ }
4822
+ @media (max-width: 767px) {
4823
+ .sg-wrapper-less .navbar-form .form-group {
4824
+ margin-bottom: 5px;
4825
+ }
4826
+ .sg-wrapper-less .navbar-form .form-group:last-child {
4827
+ margin-bottom: 0;
4828
+ }
4829
+ }
4830
+ @media (min-width: 768px) {
4831
+ .sg-wrapper-less .navbar-form {
4832
+ width: auto;
4833
+ border: 0;
4834
+ margin-left: 0;
4835
+ margin-right: 0;
4836
+ padding-top: 0;
4837
+ padding-bottom: 0;
4838
+ -webkit-box-shadow: none;
4839
+ box-shadow: none;
4840
+ }
4841
+ }
4842
+ .sg-wrapper-less .navbar-nav > li > .dropdown-menu {
4843
+ margin-top: 0;
4844
+ border-top-right-radius: 0;
4845
+ border-top-left-radius: 0;
4846
+ }
4847
+ .sg-wrapper-less .navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
4848
+ margin-bottom: 0;
4849
+ border-top-right-radius: 0;
4850
+ border-top-left-radius: 0;
4851
+ border-bottom-right-radius: 0;
4852
+ border-bottom-left-radius: 0;
4853
+ }
4854
+ .sg-wrapper-less .navbar-btn {
4855
+ margin-top: 3.5px;
4856
+ margin-bottom: 3.5px;
4857
+ }
4858
+ .sg-wrapper-less .navbar-btn.btn-sm {
4859
+ margin-top: 9.5px;
4860
+ margin-bottom: 9.5px;
4861
+ }
4862
+ .sg-wrapper-less .navbar-btn.btn-xs {
4863
+ margin-top: 14px;
4864
+ margin-bottom: 14px;
4865
+ }
4866
+ .sg-wrapper-less .navbar-text {
4867
+ margin-top: 14.5px;
4868
+ margin-bottom: 14.5px;
4869
+ }
4870
+ @media (min-width: 768px) {
4871
+ .sg-wrapper-less .navbar-text {
4872
+ float: left;
4873
+ margin-left: 15px;
4874
+ margin-right: 15px;
4875
+ }
4876
+ }
4877
+ @media (min-width: 768px) {
4878
+ .sg-wrapper-less .navbar-left {
4879
+ float: left !important;
4880
+ }
4881
+ .sg-wrapper-less .navbar-right {
4882
+ float: right !important;
4883
+ margin-right: -15px;
4884
+ }
4885
+ .sg-wrapper-less .navbar-right ~ .navbar-right {
4886
+ margin-right: 0;
4887
+ }
4888
+ }
4889
+ .sg-wrapper-less .navbar-default {
4890
+ background-color: #222222;
4891
+ border-color: #121212;
4892
+ }
4893
+ .sg-wrapper-less .navbar-default .navbar-brand {
4894
+ color: #ffffff;
4895
+ }
4896
+ .sg-wrapper-less .navbar-default .navbar-brand:hover,
4897
+ .sg-wrapper-less .navbar-default .navbar-brand:focus {
4898
+ color: #ffffff;
4899
+ background-color: none;
4900
+ }
4901
+ .sg-wrapper-less .navbar-default .navbar-text {
4902
+ color: #ffffff;
4903
+ }
4904
+ .sg-wrapper-less .navbar-default .navbar-nav > li > a {
4905
+ color: #ffffff;
4906
+ }
4907
+ .sg-wrapper-less .navbar-default .navbar-nav > li > a:hover,
4908
+ .sg-wrapper-less .navbar-default .navbar-nav > li > a:focus {
4909
+ color: #ffffff;
4910
+ background-color: #090909;
4911
+ }
4912
+ .sg-wrapper-less .navbar-default .navbar-nav > .active > a,
4913
+ .sg-wrapper-less .navbar-default .navbar-nav > .active > a:hover,
4914
+ .sg-wrapper-less .navbar-default .navbar-nav > .active > a:focus {
4915
+ color: #ffffff;
4916
+ background-color: #090909;
4917
+ }
4918
+ .sg-wrapper-less .navbar-default .navbar-nav > .disabled > a,
4919
+ .sg-wrapper-less .navbar-default .navbar-nav > .disabled > a:hover,
4920
+ .sg-wrapper-less .navbar-default .navbar-nav > .disabled > a:focus {
4921
+ color: #cccccc;
4922
+ background-color: transparent;
4923
+ }
4924
+ .sg-wrapper-less .navbar-default .navbar-toggle {
4925
+ border-color: transparent;
4926
+ }
4927
+ .sg-wrapper-less .navbar-default .navbar-toggle:hover,
4928
+ .sg-wrapper-less .navbar-default .navbar-toggle:focus {
4929
+ background-color: #090909;
4930
+ }
4931
+ .sg-wrapper-less .navbar-default .navbar-toggle .icon-bar {
4932
+ background-color: #ffffff;
4933
+ }
4934
+ .sg-wrapper-less .navbar-default .navbar-collapse,
4935
+ .sg-wrapper-less .navbar-default .navbar-form {
4936
+ border-color: #121212;
4937
+ }
4938
+ .sg-wrapper-less .navbar-default .navbar-nav > .open > a,
4939
+ .sg-wrapper-less .navbar-default .navbar-nav > .open > a:hover,
4940
+ .sg-wrapper-less .navbar-default .navbar-nav > .open > a:focus {
4941
+ background-color: #090909;
4942
+ color: #ffffff;
4943
+ }
4944
+ @media (max-width: 767px) {
4945
+ .sg-wrapper-less .navbar-default .navbar-nav .open .dropdown-menu > li > a {
4946
+ color: #ffffff;
4947
+ }
4948
+ .sg-wrapper-less .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
4949
+ .sg-wrapper-less .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
4950
+ color: #ffffff;
4951
+ background-color: #090909;
4952
+ }
4953
+ .sg-wrapper-less .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
4954
+ .sg-wrapper-less .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
4955
+ .sg-wrapper-less .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
4956
+ color: #ffffff;
4957
+ background-color: #090909;
4958
+ }
4959
+ .sg-wrapper-less .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
4960
+ .sg-wrapper-less .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
4961
+ .sg-wrapper-less .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
4962
+ color: #cccccc;
4963
+ background-color: transparent;
4964
+ }
4965
+ }
4966
+ .sg-wrapper-less .navbar-default .navbar-link {
4967
+ color: #ffffff;
4968
+ }
4969
+ .sg-wrapper-less .navbar-default .navbar-link:hover {
4970
+ color: #ffffff;
4971
+ }
4972
+ .sg-wrapper-less .navbar-default .btn-link {
4973
+ color: #ffffff;
4974
+ }
4975
+ .sg-wrapper-less .navbar-default .btn-link:hover,
4976
+ .sg-wrapper-less .navbar-default .btn-link:focus {
4977
+ color: #ffffff;
4978
+ }
4979
+ .sg-wrapper-less .navbar-default .btn-link[disabled]:hover,
4980
+ .sg-wrapper-less fieldset[disabled] .navbar-default .btn-link:hover,
4981
+ .sg-wrapper-less .navbar-default .btn-link[disabled]:focus,
4982
+ .sg-wrapper-less fieldset[disabled] .navbar-default .btn-link:focus {
4983
+ color: #cccccc;
4984
+ }
4985
+ .sg-wrapper-less .navbar-inverse {
4986
+ background-color: #2780e3;
4987
+ border-color: #1967be;
4988
+ }
4989
+ .sg-wrapper-less .navbar-inverse .navbar-brand {
4990
+ color: #ffffff;
4991
+ }
4992
+ .sg-wrapper-less .navbar-inverse .navbar-brand:hover,
4993
+ .sg-wrapper-less .navbar-inverse .navbar-brand:focus {
4994
+ color: #ffffff;
4995
+ background-color: none;
4996
+ }
4997
+ .sg-wrapper-less .navbar-inverse .navbar-text {
4998
+ color: #ffffff;
4999
+ }
5000
+ .sg-wrapper-less .navbar-inverse .navbar-nav > li > a {
5001
+ color: #ffffff;
5002
+ }
5003
+ .sg-wrapper-less .navbar-inverse .navbar-nav > li > a:hover,
5004
+ .sg-wrapper-less .navbar-inverse .navbar-nav > li > a:focus {
5005
+ color: #ffffff;
5006
+ background-color: #1967be;
5007
+ }
5008
+ .sg-wrapper-less .navbar-inverse .navbar-nav > .active > a,
5009
+ .sg-wrapper-less .navbar-inverse .navbar-nav > .active > a:hover,
5010
+ .sg-wrapper-less .navbar-inverse .navbar-nav > .active > a:focus {
5011
+ color: #ffffff;
5012
+ background-color: #1967be;
5013
+ }
5014
+ .sg-wrapper-less .navbar-inverse .navbar-nav > .disabled > a,
5015
+ .sg-wrapper-less .navbar-inverse .navbar-nav > .disabled > a:hover,
5016
+ .sg-wrapper-less .navbar-inverse .navbar-nav > .disabled > a:focus {
5017
+ color: #ffffff;
5018
+ background-color: transparent;
5019
+ }
5020
+ .sg-wrapper-less .navbar-inverse .navbar-toggle {
5021
+ border-color: transparent;
5022
+ }
5023
+ .sg-wrapper-less .navbar-inverse .navbar-toggle:hover,
5024
+ .sg-wrapper-less .navbar-inverse .navbar-toggle:focus {
5025
+ background-color: #1967be;
5026
+ }
5027
+ .sg-wrapper-less .navbar-inverse .navbar-toggle .icon-bar {
5028
+ background-color: #ffffff;
5029
+ }
5030
+ .sg-wrapper-less .navbar-inverse .navbar-collapse,
5031
+ .sg-wrapper-less .navbar-inverse .navbar-form {
5032
+ border-color: #1a6ecc;
5033
+ }
5034
+ .sg-wrapper-less .navbar-inverse .navbar-nav > .open > a,
5035
+ .sg-wrapper-less .navbar-inverse .navbar-nav > .open > a:hover,
5036
+ .sg-wrapper-less .navbar-inverse .navbar-nav > .open > a:focus {
5037
+ background-color: #1967be;
5038
+ color: #ffffff;
5039
+ }
5040
+ @media (max-width: 767px) {
5041
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
5042
+ border-color: #1967be;
5043
+ }
5044
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
5045
+ background-color: #1967be;
5046
+ }
5047
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
5048
+ color: #ffffff;
5049
+ }
5050
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
5051
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
5052
+ color: #ffffff;
5053
+ background-color: #1967be;
5054
+ }
5055
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
5056
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
5057
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
5058
+ color: #ffffff;
5059
+ background-color: #1967be;
5060
+ }
5061
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
5062
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
5063
+ .sg-wrapper-less .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
5064
+ color: #ffffff;
5065
+ background-color: transparent;
5066
+ }
5067
+ }
5068
+ .sg-wrapper-less .navbar-inverse .navbar-link {
5069
+ color: #ffffff;
5070
+ }
5071
+ .sg-wrapper-less .navbar-inverse .navbar-link:hover {
5072
+ color: #ffffff;
5073
+ }
5074
+ .sg-wrapper-less .navbar-inverse .btn-link {
5075
+ color: #ffffff;
5076
+ }
5077
+ .sg-wrapper-less .navbar-inverse .btn-link:hover,
5078
+ .sg-wrapper-less .navbar-inverse .btn-link:focus {
5079
+ color: #ffffff;
5080
+ }
5081
+ .sg-wrapper-less .navbar-inverse .btn-link[disabled]:hover,
5082
+ .sg-wrapper-less fieldset[disabled] .navbar-inverse .btn-link:hover,
5083
+ .sg-wrapper-less .navbar-inverse .btn-link[disabled]:focus,
5084
+ .sg-wrapper-less fieldset[disabled] .navbar-inverse .btn-link:focus {
5085
+ color: #ffffff;
5086
+ }
5087
+ .sg-wrapper-less .breadcrumb {
5088
+ padding: 8px 15px;
5089
+ margin-bottom: 21px;
5090
+ list-style: none;
5091
+ background-color: #f5f5f5;
5092
+ border-radius: 0;
5093
+ }
5094
+ .sg-wrapper-less .breadcrumb > li {
5095
+ display: inline-block;
5096
+ }
5097
+ .sg-wrapper-less .breadcrumb > li + li:before {
5098
+ content: "/\00a0";
5099
+ padding: 0 5px;
5100
+ color: #cccccc;
5101
+ }
5102
+ .sg-wrapper-less .breadcrumb > .active {
5103
+ color: #999999;
5104
+ }
5105
+ .sg-wrapper-less .pagination {
5106
+ display: inline-block;
5107
+ padding-left: 0;
5108
+ margin: 21px 0;
5109
+ border-radius: 0;
5110
+ }
5111
+ .sg-wrapper-less .pagination > li {
5112
+ display: inline;
5113
+ }
5114
+ .sg-wrapper-less .pagination > li > a,
5115
+ .sg-wrapper-less .pagination > li > span {
5116
+ position: relative;
5117
+ float: left;
5118
+ padding: 10px 18px;
5119
+ line-height: 1.42857143;
5120
+ text-decoration: none;
5121
+ color: #2780e3;
5122
+ background-color: #ffffff;
5123
+ border: 1px solid #dddddd;
5124
+ margin-left: -1px;
5125
+ }
5126
+ .sg-wrapper-less .pagination > li:first-child > a,
5127
+ .sg-wrapper-less .pagination > li:first-child > span {
5128
+ margin-left: 0;
5129
+ border-bottom-left-radius: 0;
5130
+ border-top-left-radius: 0;
5131
+ }
5132
+ .sg-wrapper-less .pagination > li:last-child > a,
5133
+ .sg-wrapper-less .pagination > li:last-child > span {
5134
+ border-bottom-right-radius: 0;
5135
+ border-top-right-radius: 0;
5136
+ }
5137
+ .sg-wrapper-less .pagination > li > a:hover,
5138
+ .sg-wrapper-less .pagination > li > span:hover,
5139
+ .sg-wrapper-less .pagination > li > a:focus,
5140
+ .sg-wrapper-less .pagination > li > span:focus {
5141
+ color: #165ba8;
5142
+ background-color: #e6e6e6;
5143
+ border-color: #dddddd;
5144
+ }
5145
+ .sg-wrapper-less .pagination > .active > a,
5146
+ .sg-wrapper-less .pagination > .active > span,
5147
+ .sg-wrapper-less .pagination > .active > a:hover,
5148
+ .sg-wrapper-less .pagination > .active > span:hover,
5149
+ .sg-wrapper-less .pagination > .active > a:focus,
5150
+ .sg-wrapper-less .pagination > .active > span:focus {
5151
+ z-index: 2;
5152
+ color: #999999;
5153
+ background-color: #f5f5f5;
5154
+ border-color: #dddddd;
5155
+ cursor: default;
5156
+ }
5157
+ .sg-wrapper-less .pagination > .disabled > span,
5158
+ .sg-wrapper-less .pagination > .disabled > span:hover,
5159
+ .sg-wrapper-less .pagination > .disabled > span:focus,
5160
+ .sg-wrapper-less .pagination > .disabled > a,
5161
+ .sg-wrapper-less .pagination > .disabled > a:hover,
5162
+ .sg-wrapper-less .pagination > .disabled > a:focus {
5163
+ color: #999999;
5164
+ background-color: #ffffff;
5165
+ border-color: #dddddd;
5166
+ cursor: not-allowed;
5167
+ }
5168
+ .sg-wrapper-less .pagination-lg > li > a,
5169
+ .sg-wrapper-less .pagination-lg > li > span {
5170
+ padding: 18px 30px;
5171
+ font-size: 19px;
5172
+ }
5173
+ .sg-wrapper-less .pagination-lg > li:first-child > a,
5174
+ .sg-wrapper-less .pagination-lg > li:first-child > span {
5175
+ border-bottom-left-radius: 0;
5176
+ border-top-left-radius: 0;
5177
+ }
5178
+ .sg-wrapper-less .pagination-lg > li:last-child > a,
5179
+ .sg-wrapper-less .pagination-lg > li:last-child > span {
5180
+ border-bottom-right-radius: 0;
5181
+ border-top-right-radius: 0;
5182
+ }
5183
+ .sg-wrapper-less .pagination-sm > li > a,
5184
+ .sg-wrapper-less .pagination-sm > li > span {
5185
+ padding: 5px 10px;
5186
+ font-size: 13px;
5187
+ }
5188
+ .sg-wrapper-less .pagination-sm > li:first-child > a,
5189
+ .sg-wrapper-less .pagination-sm > li:first-child > span {
5190
+ border-bottom-left-radius: 0;
5191
+ border-top-left-radius: 0;
5192
+ }
5193
+ .sg-wrapper-less .pagination-sm > li:last-child > a,
5194
+ .sg-wrapper-less .pagination-sm > li:last-child > span {
5195
+ border-bottom-right-radius: 0;
5196
+ border-top-right-radius: 0;
5197
+ }
5198
+ .sg-wrapper-less .pager {
5199
+ padding-left: 0;
5200
+ margin: 21px 0;
5201
+ list-style: none;
5202
+ text-align: center;
5203
+ }
5204
+ .sg-wrapper-less .pager li {
5205
+ display: inline;
5206
+ }
5207
+ .sg-wrapper-less .pager li > a,
5208
+ .sg-wrapper-less .pager li > span {
5209
+ display: inline-block;
5210
+ padding: 5px 14px;
5211
+ background-color: #ffffff;
5212
+ border: 1px solid #dddddd;
5213
+ border-radius: 0;
5214
+ }
5215
+ .sg-wrapper-less .pager li > a:hover,
5216
+ .sg-wrapper-less .pager li > a:focus {
5217
+ text-decoration: none;
5218
+ background-color: #e6e6e6;
5219
+ }
5220
+ .sg-wrapper-less .pager .next > a,
5221
+ .sg-wrapper-less .pager .next > span {
5222
+ float: right;
5223
+ }
5224
+ .sg-wrapper-less .pager .previous > a,
5225
+ .sg-wrapper-less .pager .previous > span {
5226
+ float: left;
5227
+ }
5228
+ .sg-wrapper-less .pager .disabled > a,
5229
+ .sg-wrapper-less .pager .disabled > a:hover,
5230
+ .sg-wrapper-less .pager .disabled > a:focus,
5231
+ .sg-wrapper-less .pager .disabled > span {
5232
+ color: #999999;
5233
+ background-color: #ffffff;
5234
+ cursor: not-allowed;
5235
+ }
5236
+ .sg-wrapper-less .label {
5237
+ display: inline;
5238
+ padding: .2em .6em .3em;
5239
+ font-size: 75%;
5240
+ font-weight: bold;
5241
+ line-height: 1;
5242
+ color: #ffffff;
5243
+ text-align: center;
5244
+ white-space: nowrap;
5245
+ vertical-align: baseline;
5246
+ border-radius: .25em;
5247
+ }
5248
+ .sg-wrapper-less a.label:hover,
5249
+ .sg-wrapper-less a.label:focus {
5250
+ color: #ffffff;
5251
+ text-decoration: none;
5252
+ cursor: pointer;
5253
+ }
5254
+ .sg-wrapper-less .label:empty {
5255
+ display: none;
5256
+ }
5257
+ .sg-wrapper-less .btn .label {
5258
+ position: relative;
5259
+ top: -1px;
5260
+ }
5261
+ .sg-wrapper-less .label-default {
5262
+ background-color: #222222;
5263
+ }
5264
+ .sg-wrapper-less .label-default[href]:hover,
5265
+ .sg-wrapper-less .label-default[href]:focus {
5266
+ background-color: #090909;
5267
+ }
5268
+ .sg-wrapper-less .label-primary {
5269
+ background-color: #2780e3;
5270
+ }
5271
+ .sg-wrapper-less .label-primary[href]:hover,
5272
+ .sg-wrapper-less .label-primary[href]:focus {
5273
+ background-color: #1967be;
5274
+ }
5275
+ .sg-wrapper-less .label-success {
5276
+ background-color: #3fb618;
5277
+ }
5278
+ .sg-wrapper-less .label-success[href]:hover,
5279
+ .sg-wrapper-less .label-success[href]:focus {
5280
+ background-color: #2f8912;
5281
+ }
5282
+ .sg-wrapper-less .label-info {
5283
+ background-color: #9954bb;
5284
+ }
5285
+ .sg-wrapper-less .label-info[href]:hover,
5286
+ .sg-wrapper-less .label-info[href]:focus {
5287
+ background-color: #7e3f9d;
5288
+ }
5289
+ .sg-wrapper-less .label-warning {
5290
+ background-color: #ff7518;
5291
+ }
5292
+ .sg-wrapper-less .label-warning[href]:hover,
5293
+ .sg-wrapper-less .label-warning[href]:focus {
5294
+ background-color: #e45c00;
5295
+ }
5296
+ .sg-wrapper-less .label-danger {
5297
+ background-color: #ff0039;
5298
+ }
5299
+ .sg-wrapper-less .label-danger[href]:hover,
5300
+ .sg-wrapper-less .label-danger[href]:focus {
5301
+ background-color: #cc002e;
5302
+ }
5303
+ .sg-wrapper-less .badge {
5304
+ display: inline-block;
5305
+ min-width: 10px;
5306
+ padding: 3px 7px;
5307
+ font-size: 13px;
5308
+ font-weight: bold;
5309
+ color: #ffffff;
5310
+ line-height: 1;
5311
+ vertical-align: baseline;
5312
+ white-space: nowrap;
5313
+ text-align: center;
5314
+ background-color: #2780e3;
5315
+ border-radius: 10px;
5316
+ }
5317
+ .sg-wrapper-less .badge:empty {
5318
+ display: none;
5319
+ }
5320
+ .sg-wrapper-less .btn .badge {
5321
+ position: relative;
5322
+ top: -1px;
5323
+ }
5324
+ .sg-wrapper-less .btn-xs .badge,
5325
+ .sg-wrapper-less .btn-group-xs > .btn .badge {
5326
+ top: 0;
5327
+ padding: 1px 5px;
5328
+ }
5329
+ .sg-wrapper-less a.badge:hover,
5330
+ .sg-wrapper-less a.badge:focus {
5331
+ color: #ffffff;
5332
+ text-decoration: none;
5333
+ cursor: pointer;
5334
+ }
5335
+ .sg-wrapper-less .list-group-item.active > .badge,
5336
+ .sg-wrapper-less .nav-pills > .active > a > .badge {
5337
+ color: #2780e3;
5338
+ background-color: #ffffff;
5339
+ }
5340
+ .sg-wrapper-less .list-group-item > .badge {
5341
+ float: right;
5342
+ }
5343
+ .sg-wrapper-less .list-group-item > .badge + .badge {
5344
+ margin-right: 5px;
5345
+ }
5346
+ .sg-wrapper-less .nav-pills > li > a > .badge {
5347
+ margin-left: 3px;
5348
+ }
5349
+ .sg-wrapper-less .jumbotron {
5350
+ padding: 30px 15px;
5351
+ margin-bottom: 30px;
5352
+ color: inherit;
5353
+ background-color: #e6e6e6;
5354
+ }
5355
+ .sg-wrapper-less .jumbotron h1,
5356
+ .sg-wrapper-less .jumbotron .h1 {
5357
+ color: inherit;
5358
+ }
5359
+ .sg-wrapper-less .jumbotron p {
5360
+ margin-bottom: 15px;
5361
+ font-size: 23px;
5362
+ font-weight: 200;
5363
+ }
5364
+ .sg-wrapper-less .jumbotron > hr {
5365
+ border-top-color: #cccccc;
5366
+ }
5367
+ .sg-wrapper-less .container .jumbotron,
5368
+ .sg-wrapper-less .container-fluid .jumbotron {
5369
+ border-radius: 0;
5370
+ }
5371
+ .sg-wrapper-less .jumbotron .container {
5372
+ max-width: 100%;
5373
+ }
5374
+ @media screen and (min-width: 768px) {
5375
+ .sg-wrapper-less .jumbotron {
5376
+ padding: 48px 0;
5377
+ }
5378
+ .sg-wrapper-less .container .jumbotron,
5379
+ .sg-wrapper-less .container-fluid .jumbotron {
5380
+ padding-left: 60px;
5381
+ padding-right: 60px;
5382
+ }
5383
+ .sg-wrapper-less .jumbotron h1,
5384
+ .sg-wrapper-less .jumbotron .h1 {
5385
+ font-size: 67.5px;
5386
+ }
5387
+ }
5388
+ .sg-wrapper-less .thumbnail {
5389
+ display: block;
5390
+ padding: 4px;
5391
+ margin-bottom: 21px;
5392
+ line-height: 1.42857143;
5393
+ background-color: #ffffff;
5394
+ border: 1px solid #dddddd;
5395
+ border-radius: 0;
5396
+ -webkit-transition: border 0.2s ease-in-out;
5397
+ -o-transition: border 0.2s ease-in-out;
5398
+ transition: border 0.2s ease-in-out;
5399
+ }
5400
+ .sg-wrapper-less .thumbnail > img,
5401
+ .sg-wrapper-less .thumbnail a > img {
5402
+ margin-left: auto;
5403
+ margin-right: auto;
5404
+ }
5405
+ .sg-wrapper-less a.thumbnail:hover,
5406
+ .sg-wrapper-less a.thumbnail:focus,
5407
+ .sg-wrapper-less a.thumbnail.active {
5408
+ border-color: #2780e3;
5409
+ }
5410
+ .sg-wrapper-less .thumbnail .caption {
5411
+ padding: 9px;
5412
+ color: #333333;
5413
+ }
5414
+ .sg-wrapper-less .alert {
5415
+ padding: 15px;
5416
+ margin-bottom: 21px;
5417
+ border: 1px solid transparent;
5418
+ border-radius: 0;
5419
+ }
5420
+ .sg-wrapper-less .alert h4 {
5421
+ margin-top: 0;
5422
+ color: inherit;
5423
+ }
5424
+ .sg-wrapper-less .alert .alert-link {
5425
+ font-weight: bold;
5426
+ }
5427
+ .sg-wrapper-less .alert > p,
5428
+ .sg-wrapper-less .alert > ul {
5429
+ margin-bottom: 0;
5430
+ }
5431
+ .sg-wrapper-less .alert > p + p {
5432
+ margin-top: 5px;
5433
+ }
5434
+ .sg-wrapper-less .alert-dismissable,
5435
+ .sg-wrapper-less .alert-dismissible {
5436
+ padding-right: 35px;
5437
+ }
5438
+ .sg-wrapper-less .alert-dismissable .close,
5439
+ .sg-wrapper-less .alert-dismissible .close {
5440
+ position: relative;
5441
+ top: -2px;
5442
+ right: -21px;
5443
+ color: inherit;
5444
+ }
5445
+ .sg-wrapper-less .alert-success {
5446
+ background-color: #3fb618;
5447
+ border-color: #4e9f15;
5448
+ color: #ffffff;
5449
+ }
5450
+ .sg-wrapper-less .alert-success hr {
5451
+ border-top-color: #438912;
5452
+ }
5453
+ .sg-wrapper-less .alert-success .alert-link {
5454
+ color: #e6e6e6;
5455
+ }
5456
+ .sg-wrapper-less .alert-info {
5457
+ background-color: #9954bb;
5458
+ border-color: #7643a8;
5459
+ color: #ffffff;
5460
+ }
5461
+ .sg-wrapper-less .alert-info hr {
5462
+ border-top-color: #693c96;
5463
+ }
5464
+ .sg-wrapper-less .alert-info .alert-link {
5465
+ color: #e6e6e6;
5466
+ }
5467
+ .sg-wrapper-less .alert-warning {
5468
+ background-color: #ff7518;
5469
+ border-color: #ff4309;
5470
+ color: #ffffff;
5471
+ }
5472
+ .sg-wrapper-less .alert-warning hr {
5473
+ border-top-color: #ee3800;
5474
+ }
5475
+ .sg-wrapper-less .alert-warning .alert-link {
5476
+ color: #e6e6e6;
5477
+ }
5478
+ .sg-wrapper-less .alert-danger {
5479
+ background-color: #ff0039;
5480
+ border-color: #f0005e;
5481
+ color: #ffffff;
5482
+ }
5483
+ .sg-wrapper-less .alert-danger hr {
5484
+ border-top-color: #d60054;
5485
+ }
5486
+ .sg-wrapper-less .alert-danger .alert-link {
5487
+ color: #e6e6e6;
5488
+ }
5489
+ @-webkit-keyframes progress-bar-stripes {
5490
+ from {
5491
+ background-position: 40px 0;
5492
+ }
5493
+ to {
5494
+ background-position: 0 0;
5495
+ }
5496
+ }
5497
+ @-o-keyframes progress-bar-stripes {
5498
+ from {
5499
+ background-position: 40px 0;
5500
+ }
5501
+ to {
5502
+ background-position: 0 0;
5503
+ }
5504
+ }
5505
+ @keyframes progress-bar-stripes {
5506
+ from {
5507
+ background-position: 40px 0;
5508
+ }
5509
+ to {
5510
+ background-position: 0 0;
5511
+ }
5512
+ }
5513
+ .sg-wrapper-less .progress {
5514
+ overflow: hidden;
5515
+ height: 21px;
5516
+ margin-bottom: 21px;
5517
+ background-color: #cccccc;
5518
+ border-radius: 0;
5519
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
5520
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
5521
+ }
5522
+ .sg-wrapper-less .progress-bar {
5523
+ float: left;
5524
+ width: 0%;
5525
+ height: 100%;
5526
+ font-size: 13px;
5527
+ line-height: 21px;
5528
+ color: #ffffff;
5529
+ text-align: center;
5530
+ background-color: #2780e3;
5531
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
5532
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
5533
+ -webkit-transition: width 0.6s ease;
5534
+ -o-transition: width 0.6s ease;
5535
+ transition: width 0.6s ease;
5536
+ }
5537
+ .sg-wrapper-less .progress-striped .progress-bar,
5538
+ .sg-wrapper-less .progress-bar-striped {
5539
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5540
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5541
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5542
+ -webkit-background-size: 40px 40px;
5543
+ background-size: 40px 40px;
5544
+ }
5545
+ .sg-wrapper-less .progress.active .progress-bar,
5546
+ .sg-wrapper-less .progress-bar.active {
5547
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
5548
+ -o-animation: progress-bar-stripes 2s linear infinite;
5549
+ animation: progress-bar-stripes 2s linear infinite;
5550
+ }
5551
+ .sg-wrapper-less .progress-bar-success {
5552
+ background-color: #3fb618;
5553
+ }
5554
+ .sg-wrapper-less .progress-striped .progress-bar-success {
5555
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5556
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5557
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5558
+ }
5559
+ .sg-wrapper-less .progress-bar-info {
5560
+ background-color: #9954bb;
5561
+ }
5562
+ .sg-wrapper-less .progress-striped .progress-bar-info {
5563
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5564
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5565
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5566
+ }
5567
+ .sg-wrapper-less .progress-bar-warning {
5568
+ background-color: #ff7518;
5569
+ }
5570
+ .sg-wrapper-less .progress-striped .progress-bar-warning {
5571
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5572
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5573
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5574
+ }
5575
+ .sg-wrapper-less .progress-bar-danger {
5576
+ background-color: #ff0039;
5577
+ }
5578
+ .sg-wrapper-less .progress-striped .progress-bar-danger {
5579
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5580
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5581
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
5582
+ }
5583
+ .sg-wrapper-less .media {
5584
+ margin-top: 15px;
5585
+ }
5586
+ .sg-wrapper-less .media:first-child {
5587
+ margin-top: 0;
5588
+ }
5589
+ .sg-wrapper-less .media,
5590
+ .sg-wrapper-less .media-body {
5591
+ zoom: 1;
5592
+ overflow: hidden;
5593
+ }
5594
+ .sg-wrapper-less .media-body {
5595
+ width: 10000px;
5596
+ }
5597
+ .sg-wrapper-less .media-object {
5598
+ display: block;
5599
+ }
5600
+ .sg-wrapper-less .media-right,
5601
+ .sg-wrapper-less .media > .pull-right {
5602
+ padding-left: 10px;
5603
+ }
5604
+ .sg-wrapper-less .media-left,
5605
+ .sg-wrapper-less .media > .pull-left {
5606
+ padding-right: 10px;
5607
+ }
5608
+ .sg-wrapper-less .media-left,
5609
+ .sg-wrapper-less .media-right,
5610
+ .sg-wrapper-less .media-body {
5611
+ display: table-cell;
5612
+ vertical-align: top;
5613
+ }
5614
+ .sg-wrapper-less .media-middle {
5615
+ vertical-align: middle;
5616
+ }
5617
+ .sg-wrapper-less .media-bottom {
5618
+ vertical-align: bottom;
5619
+ }
5620
+ .sg-wrapper-less .media-heading {
5621
+ margin-top: 0;
5622
+ margin-bottom: 5px;
5623
+ }
5624
+ .sg-wrapper-less .media-list {
5625
+ padding-left: 0;
5626
+ list-style: none;
5627
+ }
5628
+ .sg-wrapper-less .list-group {
5629
+ margin-bottom: 20px;
5630
+ padding-left: 0;
5631
+ }
5632
+ .sg-wrapper-less .list-group-item {
5633
+ position: relative;
5634
+ display: block;
5635
+ padding: 10px 15px;
5636
+ margin-bottom: -1px;
5637
+ background-color: #ffffff;
5638
+ border: 1px solid #dddddd;
5639
+ }
5640
+ .sg-wrapper-less .list-group-item:first-child {
5641
+ border-top-right-radius: 0;
5642
+ border-top-left-radius: 0;
5643
+ }
5644
+ .sg-wrapper-less .list-group-item:last-child {
5645
+ margin-bottom: 0;
5646
+ border-bottom-right-radius: 0;
5647
+ border-bottom-left-radius: 0;
5648
+ }
5649
+ .sg-wrapper-less a.list-group-item {
5650
+ color: #555555;
5651
+ }
5652
+ .sg-wrapper-less a.list-group-item .list-group-item-heading {
5653
+ color: #333333;
5654
+ }
5655
+ .sg-wrapper-less a.list-group-item:hover,
5656
+ .sg-wrapper-less a.list-group-item:focus {
5657
+ text-decoration: none;
5658
+ color: #555555;
5659
+ background-color: #f5f5f5;
5660
+ }
5661
+ .sg-wrapper-less .list-group-item.disabled,
5662
+ .sg-wrapper-less .list-group-item.disabled:hover,
5663
+ .sg-wrapper-less .list-group-item.disabled:focus {
5664
+ background-color: #e6e6e6;
5665
+ color: #999999;
5666
+ cursor: not-allowed;
5667
+ }
5668
+ .sg-wrapper-less .list-group-item.disabled .list-group-item-heading,
5669
+ .sg-wrapper-less .list-group-item.disabled:hover .list-group-item-heading,
5670
+ .sg-wrapper-less .list-group-item.disabled:focus .list-group-item-heading {
5671
+ color: inherit;
5672
+ }
5673
+ .sg-wrapper-less .list-group-item.disabled .list-group-item-text,
5674
+ .sg-wrapper-less .list-group-item.disabled:hover .list-group-item-text,
5675
+ .sg-wrapper-less .list-group-item.disabled:focus .list-group-item-text {
5676
+ color: #999999;
5677
+ }
5678
+ .sg-wrapper-less .list-group-item.active,
5679
+ .sg-wrapper-less .list-group-item.active:hover,
5680
+ .sg-wrapper-less .list-group-item.active:focus {
5681
+ z-index: 2;
5682
+ color: #ffffff;
5683
+ background-color: #2780e3;
5684
+ border-color: #dddddd;
5685
+ }
5686
+ .sg-wrapper-less .list-group-item.active .list-group-item-heading,
5687
+ .sg-wrapper-less .list-group-item.active:hover .list-group-item-heading,
5688
+ .sg-wrapper-less .list-group-item.active:focus .list-group-item-heading,
5689
+ .sg-wrapper-less .list-group-item.active .list-group-item-heading > small,
5690
+ .sg-wrapper-less .list-group-item.active:hover .list-group-item-heading > small,
5691
+ .sg-wrapper-less .list-group-item.active:focus .list-group-item-heading > small,
5692
+ .sg-wrapper-less .list-group-item.active .list-group-item-heading > .small,
5693
+ .sg-wrapper-less .list-group-item.active:hover .list-group-item-heading > .small,
5694
+ .sg-wrapper-less .list-group-item.active:focus .list-group-item-heading > .small {
5695
+ color: inherit;
5696
+ }
5697
+ .sg-wrapper-less .list-group-item.active .list-group-item-text,
5698
+ .sg-wrapper-less .list-group-item.active:hover .list-group-item-text,
5699
+ .sg-wrapper-less .list-group-item.active:focus .list-group-item-text {
5700
+ color: #dceafa;
5701
+ }
5702
+ .sg-wrapper-less .list-group-item-success {
5703
+ color: #ffffff;
5704
+ background-color: #3fb618;
5705
+ }
5706
+ .sg-wrapper-less a.list-group-item-success {
5707
+ color: #ffffff;
5708
+ }
5709
+ .sg-wrapper-less a.list-group-item-success .list-group-item-heading {
5710
+ color: inherit;
5711
+ }
5712
+ .sg-wrapper-less a.list-group-item-success:hover,
5713
+ .sg-wrapper-less a.list-group-item-success:focus {
5714
+ color: #ffffff;
5715
+ background-color: #379f15;
5716
+ }
5717
+ .sg-wrapper-less a.list-group-item-success.active,
5718
+ .sg-wrapper-less a.list-group-item-success.active:hover,
5719
+ .sg-wrapper-less a.list-group-item-success.active:focus {
5720
+ color: #fff;
5721
+ background-color: #ffffff;
5722
+ border-color: #ffffff;
5723
+ }
5724
+ .sg-wrapper-less .list-group-item-info {
5725
+ color: #ffffff;
5726
+ background-color: #9954bb;
5727
+ }
5728
+ .sg-wrapper-less a.list-group-item-info {
5729
+ color: #ffffff;
5730
+ }
5731
+ .sg-wrapper-less a.list-group-item-info .list-group-item-heading {
5732
+ color: inherit;
5733
+ }
5734
+ .sg-wrapper-less a.list-group-item-info:hover,
5735
+ .sg-wrapper-less a.list-group-item-info:focus {
5736
+ color: #ffffff;
5737
+ background-color: #8d46b0;
5738
+ }
5739
+ .sg-wrapper-less a.list-group-item-info.active,
5740
+ .sg-wrapper-less a.list-group-item-info.active:hover,
5741
+ .sg-wrapper-less a.list-group-item-info.active:focus {
5742
+ color: #fff;
5743
+ background-color: #ffffff;
5744
+ border-color: #ffffff;
5745
+ }
5746
+ .sg-wrapper-less .list-group-item-warning {
5747
+ color: #ffffff;
5748
+ background-color: #ff7518;
5749
+ }
5750
+ .sg-wrapper-less a.list-group-item-warning {
5751
+ color: #ffffff;
5752
+ }
5753
+ .sg-wrapper-less a.list-group-item-warning .list-group-item-heading {
5754
+ color: inherit;
5755
+ }
5756
+ .sg-wrapper-less a.list-group-item-warning:hover,
5757
+ .sg-wrapper-less a.list-group-item-warning:focus {
5758
+ color: #ffffff;
5759
+ background-color: #fe6600;
5760
+ }
5761
+ .sg-wrapper-less a.list-group-item-warning.active,
5762
+ .sg-wrapper-less a.list-group-item-warning.active:hover,
5763
+ .sg-wrapper-less a.list-group-item-warning.active:focus {
5764
+ color: #fff;
5765
+ background-color: #ffffff;
5766
+ border-color: #ffffff;
5767
+ }
5768
+ .sg-wrapper-less .list-group-item-danger {
5769
+ color: #ffffff;
5770
+ background-color: #ff0039;
5771
+ }
5772
+ .sg-wrapper-less a.list-group-item-danger {
5773
+ color: #ffffff;
5774
+ }
5775
+ .sg-wrapper-less a.list-group-item-danger .list-group-item-heading {
5776
+ color: inherit;
5777
+ }
5778
+ .sg-wrapper-less a.list-group-item-danger:hover,
5779
+ .sg-wrapper-less a.list-group-item-danger:focus {
5780
+ color: #ffffff;
5781
+ background-color: #e60033;
5782
+ }
5783
+ .sg-wrapper-less a.list-group-item-danger.active,
5784
+ .sg-wrapper-less a.list-group-item-danger.active:hover,
5785
+ .sg-wrapper-less a.list-group-item-danger.active:focus {
5786
+ color: #fff;
5787
+ background-color: #ffffff;
5788
+ border-color: #ffffff;
5789
+ }
5790
+ .sg-wrapper-less .list-group-item-heading {
5791
+ margin-top: 0;
5792
+ margin-bottom: 5px;
5793
+ }
5794
+ .sg-wrapper-less .list-group-item-text {
5795
+ margin-bottom: 0;
5796
+ line-height: 1.3;
5797
+ }
5798
+ .sg-wrapper-less .panel {
5799
+ margin-bottom: 21px;
5800
+ background-color: #ffffff;
5801
+ border: 1px solid transparent;
5802
+ border-radius: 0;
5803
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
5804
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
5805
+ }
5806
+ .sg-wrapper-less .panel-body {
5807
+ padding: 15px;
5808
+ }
5809
+ .sg-wrapper-less .panel-heading {
5810
+ padding: 10px 15px;
5811
+ border-bottom: 1px solid transparent;
5812
+ border-top-right-radius: -1;
5813
+ border-top-left-radius: -1;
5814
+ }
5815
+ .sg-wrapper-less .panel-heading > .dropdown .dropdown-toggle {
5816
+ color: inherit;
5817
+ }
5818
+ .sg-wrapper-less .panel-title {
5819
+ margin-top: 0;
5820
+ margin-bottom: 0;
5821
+ font-size: 17px;
5822
+ color: inherit;
5823
+ }
5824
+ .sg-wrapper-less .panel-title > a,
5825
+ .sg-wrapper-less .panel-title > small,
5826
+ .sg-wrapper-less .panel-title > .small,
5827
+ .sg-wrapper-less .panel-title > small > a,
5828
+ .sg-wrapper-less .panel-title > .small > a {
5829
+ color: inherit;
5830
+ }
5831
+ .sg-wrapper-less .panel-footer {
5832
+ padding: 10px 15px;
5833
+ background-color: #f5f5f5;
5834
+ border-top: 1px solid #dddddd;
5835
+ border-bottom-right-radius: -1;
5836
+ border-bottom-left-radius: -1;
5837
+ }
5838
+ .sg-wrapper-less .panel > .list-group,
5839
+ .sg-wrapper-less .panel > .panel-collapse > .list-group {
5840
+ margin-bottom: 0;
5841
+ }
5842
+ .sg-wrapper-less .panel > .list-group .list-group-item,
5843
+ .sg-wrapper-less .panel > .panel-collapse > .list-group .list-group-item {
5844
+ border-width: 1px 0;
5845
+ border-radius: 0;
5846
+ }
5847
+ .sg-wrapper-less .panel > .list-group:first-child .list-group-item:first-child,
5848
+ .sg-wrapper-less .panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
5849
+ border-top: 0;
5850
+ border-top-right-radius: -1;
5851
+ border-top-left-radius: -1;
5852
+ }
5853
+ .sg-wrapper-less .panel > .list-group:last-child .list-group-item:last-child,
5854
+ .sg-wrapper-less .panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
5855
+ border-bottom: 0;
5856
+ border-bottom-right-radius: -1;
5857
+ border-bottom-left-radius: -1;
5858
+ }
5859
+ .sg-wrapper-less .panel-heading + .list-group .list-group-item:first-child {
5860
+ border-top-width: 0;
5861
+ }
5862
+ .sg-wrapper-less .list-group + .panel-footer {
5863
+ border-top-width: 0;
5864
+ }
5865
+ .sg-wrapper-less .panel > .table,
5866
+ .sg-wrapper-less .panel > .table-responsive > .table,
5867
+ .sg-wrapper-less .panel > .panel-collapse > .table {
5868
+ margin-bottom: 0;
5869
+ }
5870
+ .sg-wrapper-less .panel > .table caption,
5871
+ .sg-wrapper-less .panel > .table-responsive > .table caption,
5872
+ .sg-wrapper-less .panel > .panel-collapse > .table caption {
5873
+ padding-left: 15px;
5874
+ padding-right: 15px;
5875
+ }
5876
+ .sg-wrapper-less .panel > .table:first-child,
5877
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child {
5878
+ border-top-right-radius: -1;
5879
+ border-top-left-radius: -1;
5880
+ }
5881
+ .sg-wrapper-less .panel > .table:first-child > thead:first-child > tr:first-child,
5882
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
5883
+ .sg-wrapper-less .panel > .table:first-child > tbody:first-child > tr:first-child,
5884
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
5885
+ border-top-left-radius: -1;
5886
+ border-top-right-radius: -1;
5887
+ }
5888
+ .sg-wrapper-less .panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
5889
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
5890
+ .sg-wrapper-less .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
5891
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
5892
+ .sg-wrapper-less .panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
5893
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
5894
+ .sg-wrapper-less .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
5895
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
5896
+ border-top-left-radius: -1;
5897
+ }
5898
+ .sg-wrapper-less .panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
5899
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
5900
+ .sg-wrapper-less .panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
5901
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
5902
+ .sg-wrapper-less .panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
5903
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
5904
+ .sg-wrapper-less .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
5905
+ .sg-wrapper-less .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
5906
+ border-top-right-radius: -1;
5907
+ }
5908
+ .sg-wrapper-less .panel > .table:last-child,
5909
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child {
5910
+ border-bottom-right-radius: -1;
5911
+ border-bottom-left-radius: -1;
5912
+ }
5913
+ .sg-wrapper-less .panel > .table:last-child > tbody:last-child > tr:last-child,
5914
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
5915
+ .sg-wrapper-less .panel > .table:last-child > tfoot:last-child > tr:last-child,
5916
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
5917
+ border-bottom-left-radius: -1;
5918
+ border-bottom-right-radius: -1;
5919
+ }
5920
+ .sg-wrapper-less .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
5921
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
5922
+ .sg-wrapper-less .panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
5923
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
5924
+ .sg-wrapper-less .panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
5925
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
5926
+ .sg-wrapper-less .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
5927
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
5928
+ border-bottom-left-radius: -1;
5929
+ }
5930
+ .sg-wrapper-less .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
5931
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
5932
+ .sg-wrapper-less .panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
5933
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
5934
+ .sg-wrapper-less .panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
5935
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
5936
+ .sg-wrapper-less .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
5937
+ .sg-wrapper-less .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
5938
+ border-bottom-right-radius: -1;
5939
+ }
5940
+ .sg-wrapper-less .panel > .panel-body + .table,
5941
+ .sg-wrapper-less .panel > .panel-body + .table-responsive,
5942
+ .sg-wrapper-less .panel > .table + .panel-body,
5943
+ .sg-wrapper-less .panel > .table-responsive + .panel-body {
5944
+ border-top: 1px solid #dddddd;
5945
+ }
5946
+ .sg-wrapper-less .panel > .table > tbody:first-child > tr:first-child th,
5947
+ .sg-wrapper-less .panel > .table > tbody:first-child > tr:first-child td {
5948
+ border-top: 0;
5949
+ }
5950
+ .sg-wrapper-less .panel > .table-bordered,
5951
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered {
5952
+ border: 0;
5953
+ }
5954
+ .sg-wrapper-less .panel > .table-bordered > thead > tr > th:first-child,
5955
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
5956
+ .sg-wrapper-less .panel > .table-bordered > tbody > tr > th:first-child,
5957
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
5958
+ .sg-wrapper-less .panel > .table-bordered > tfoot > tr > th:first-child,
5959
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
5960
+ .sg-wrapper-less .panel > .table-bordered > thead > tr > td:first-child,
5961
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
5962
+ .sg-wrapper-less .panel > .table-bordered > tbody > tr > td:first-child,
5963
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
5964
+ .sg-wrapper-less .panel > .table-bordered > tfoot > tr > td:first-child,
5965
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
5966
+ border-left: 0;
5967
+ }
5968
+ .sg-wrapper-less .panel > .table-bordered > thead > tr > th:last-child,
5969
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
5970
+ .sg-wrapper-less .panel > .table-bordered > tbody > tr > th:last-child,
5971
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
5972
+ .sg-wrapper-less .panel > .table-bordered > tfoot > tr > th:last-child,
5973
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
5974
+ .sg-wrapper-less .panel > .table-bordered > thead > tr > td:last-child,
5975
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
5976
+ .sg-wrapper-less .panel > .table-bordered > tbody > tr > td:last-child,
5977
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
5978
+ .sg-wrapper-less .panel > .table-bordered > tfoot > tr > td:last-child,
5979
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
5980
+ border-right: 0;
5981
+ }
5982
+ .sg-wrapper-less .panel > .table-bordered > thead > tr:first-child > td,
5983
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
5984
+ .sg-wrapper-less .panel > .table-bordered > tbody > tr:first-child > td,
5985
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
5986
+ .sg-wrapper-less .panel > .table-bordered > thead > tr:first-child > th,
5987
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
5988
+ .sg-wrapper-less .panel > .table-bordered > tbody > tr:first-child > th,
5989
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
5990
+ border-bottom: 0;
5991
+ }
5992
+ .sg-wrapper-less .panel > .table-bordered > tbody > tr:last-child > td,
5993
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
5994
+ .sg-wrapper-less .panel > .table-bordered > tfoot > tr:last-child > td,
5995
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
5996
+ .sg-wrapper-less .panel > .table-bordered > tbody > tr:last-child > th,
5997
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
5998
+ .sg-wrapper-less .panel > .table-bordered > tfoot > tr:last-child > th,
5999
+ .sg-wrapper-less .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
6000
+ border-bottom: 0;
6001
+ }
6002
+ .sg-wrapper-less .panel > .table-responsive {
6003
+ border: 0;
6004
+ margin-bottom: 0;
6005
+ }
6006
+ .sg-wrapper-less .panel-group {
6007
+ margin-bottom: 21px;
6008
+ }
6009
+ .sg-wrapper-less .panel-group .panel {
6010
+ margin-bottom: 0;
6011
+ border-radius: 0;
6012
+ }
6013
+ .sg-wrapper-less .panel-group .panel + .panel {
6014
+ margin-top: 5px;
6015
+ }
6016
+ .sg-wrapper-less .panel-group .panel-heading {
6017
+ border-bottom: 0;
6018
+ }
6019
+ .sg-wrapper-less .panel-group .panel-heading + .panel-collapse > .panel-body,
6020
+ .sg-wrapper-less .panel-group .panel-heading + .panel-collapse > .list-group {
6021
+ border-top: 1px solid #dddddd;
6022
+ }
6023
+ .sg-wrapper-less .panel-group .panel-footer {
6024
+ border-top: 0;
6025
+ }
6026
+ .sg-wrapper-less .panel-group .panel-footer + .panel-collapse .panel-body {
6027
+ border-bottom: 1px solid #dddddd;
6028
+ }
6029
+ .sg-wrapper-less .panel-default {
6030
+ border-color: #dddddd;
6031
+ }
6032
+ .sg-wrapper-less .panel-default > .panel-heading {
6033
+ color: #333333;
6034
+ background-color: #f5f5f5;
6035
+ border-color: #dddddd;
6036
+ }
6037
+ .sg-wrapper-less .panel-default > .panel-heading + .panel-collapse > .panel-body {
6038
+ border-top-color: #dddddd;
6039
+ }
6040
+ .sg-wrapper-less .panel-default > .panel-heading .badge {
6041
+ color: #f5f5f5;
6042
+ background-color: #333333;
6043
+ }
6044
+ .sg-wrapper-less .panel-default > .panel-footer + .panel-collapse > .panel-body {
6045
+ border-bottom-color: #dddddd;
6046
+ }
6047
+ .sg-wrapper-less .panel-primary {
6048
+ border-color: #2780e3;
6049
+ }
6050
+ .sg-wrapper-less .panel-primary > .panel-heading {
6051
+ color: #ffffff;
6052
+ background-color: #2780e3;
6053
+ border-color: #2780e3;
6054
+ }
6055
+ .sg-wrapper-less .panel-primary > .panel-heading + .panel-collapse > .panel-body {
6056
+ border-top-color: #2780e3;
6057
+ }
6058
+ .sg-wrapper-less .panel-primary > .panel-heading .badge {
6059
+ color: #2780e3;
6060
+ background-color: #ffffff;
6061
+ }
6062
+ .sg-wrapper-less .panel-primary > .panel-footer + .panel-collapse > .panel-body {
6063
+ border-bottom-color: #2780e3;
6064
+ }
6065
+ .sg-wrapper-less .panel-success {
6066
+ border-color: #4e9f15;
6067
+ }
6068
+ .sg-wrapper-less .panel-success > .panel-heading {
6069
+ color: #ffffff;
6070
+ background-color: #3fb618;
6071
+ border-color: #4e9f15;
6072
+ }
6073
+ .sg-wrapper-less .panel-success > .panel-heading + .panel-collapse > .panel-body {
6074
+ border-top-color: #4e9f15;
6075
+ }
6076
+ .sg-wrapper-less .panel-success > .panel-heading .badge {
6077
+ color: #3fb618;
6078
+ background-color: #ffffff;
6079
+ }
6080
+ .sg-wrapper-less .panel-success > .panel-footer + .panel-collapse > .panel-body {
6081
+ border-bottom-color: #4e9f15;
6082
+ }
6083
+ .sg-wrapper-less .panel-info {
6084
+ border-color: #7643a8;
6085
+ }
6086
+ .sg-wrapper-less .panel-info > .panel-heading {
6087
+ color: #ffffff;
6088
+ background-color: #9954bb;
6089
+ border-color: #7643a8;
6090
+ }
6091
+ .sg-wrapper-less .panel-info > .panel-heading + .panel-collapse > .panel-body {
6092
+ border-top-color: #7643a8;
6093
+ }
6094
+ .sg-wrapper-less .panel-info > .panel-heading .badge {
6095
+ color: #9954bb;
6096
+ background-color: #ffffff;
6097
+ }
6098
+ .sg-wrapper-less .panel-info > .panel-footer + .panel-collapse > .panel-body {
6099
+ border-bottom-color: #7643a8;
6100
+ }
6101
+ .sg-wrapper-less .panel-warning {
6102
+ border-color: #ff4309;
6103
+ }
6104
+ .sg-wrapper-less .panel-warning > .panel-heading {
6105
+ color: #ffffff;
6106
+ background-color: #ff7518;
6107
+ border-color: #ff4309;
6108
+ }
6109
+ .sg-wrapper-less .panel-warning > .panel-heading + .panel-collapse > .panel-body {
6110
+ border-top-color: #ff4309;
6111
+ }
6112
+ .sg-wrapper-less .panel-warning > .panel-heading .badge {
6113
+ color: #ff7518;
6114
+ background-color: #ffffff;
6115
+ }
6116
+ .sg-wrapper-less .panel-warning > .panel-footer + .panel-collapse > .panel-body {
6117
+ border-bottom-color: #ff4309;
6118
+ }
6119
+ .sg-wrapper-less .panel-danger {
6120
+ border-color: #f0005e;
6121
+ }
6122
+ .sg-wrapper-less .panel-danger > .panel-heading {
6123
+ color: #ffffff;
6124
+ background-color: #ff0039;
6125
+ border-color: #f0005e;
6126
+ }
6127
+ .sg-wrapper-less .panel-danger > .panel-heading + .panel-collapse > .panel-body {
6128
+ border-top-color: #f0005e;
6129
+ }
6130
+ .sg-wrapper-less .panel-danger > .panel-heading .badge {
6131
+ color: #ff0039;
6132
+ background-color: #ffffff;
6133
+ }
6134
+ .sg-wrapper-less .panel-danger > .panel-footer + .panel-collapse > .panel-body {
6135
+ border-bottom-color: #f0005e;
6136
+ }
6137
+ .sg-wrapper-less .embed-responsive {
6138
+ position: relative;
6139
+ display: block;
6140
+ height: 0;
6141
+ padding: 0;
6142
+ overflow: hidden;
6143
+ }
6144
+ .sg-wrapper-less .embed-responsive .embed-responsive-item,
6145
+ .sg-wrapper-less .embed-responsive iframe,
6146
+ .sg-wrapper-less .embed-responsive embed,
6147
+ .sg-wrapper-less .embed-responsive object,
6148
+ .sg-wrapper-less .embed-responsive video {
6149
+ position: absolute;
6150
+ top: 0;
6151
+ left: 0;
6152
+ bottom: 0;
6153
+ height: 100%;
6154
+ width: 100%;
6155
+ border: 0;
6156
+ }
6157
+ .sg-wrapper-less .embed-responsive-16by9 {
6158
+ padding-bottom: 56.25%;
6159
+ }
6160
+ .sg-wrapper-less .embed-responsive-4by3 {
6161
+ padding-bottom: 75%;
6162
+ }
6163
+ .sg-wrapper-less .well {
6164
+ min-height: 20px;
6165
+ padding: 19px;
6166
+ margin-bottom: 20px;
6167
+ background-color: #f5f5f5;
6168
+ border: 1px solid #e3e3e3;
6169
+ border-radius: 0;
6170
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
6171
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
6172
+ }
6173
+ .sg-wrapper-less .well blockquote {
6174
+ border-color: #ddd;
6175
+ border-color: rgba(0, 0, 0, 0.15);
6176
+ }
6177
+ .sg-wrapper-less .well-lg {
6178
+ padding: 24px;
6179
+ border-radius: 0;
6180
+ }
6181
+ .sg-wrapper-less .well-sm {
6182
+ padding: 9px;
6183
+ border-radius: 0;
6184
+ }
6185
+ .sg-wrapper-less .close {
6186
+ float: right;
6187
+ font-size: 22.5px;
6188
+ font-weight: bold;
6189
+ line-height: 1;
6190
+ color: #ffffff;
6191
+ text-shadow: 0 1px 0 #ffffff;
6192
+ opacity: 0.2;
6193
+ filter: alpha(opacity=20);
6194
+ }
6195
+ .sg-wrapper-less .close:hover,
6196
+ .sg-wrapper-less .close:focus {
6197
+ color: #ffffff;
6198
+ text-decoration: none;
6199
+ cursor: pointer;
6200
+ opacity: 0.5;
6201
+ filter: alpha(opacity=50);
6202
+ }
6203
+ .sg-wrapper-less button.close {
6204
+ padding: 0;
6205
+ cursor: pointer;
6206
+ background: transparent;
6207
+ border: 0;
6208
+ -webkit-appearance: none;
6209
+ }
6210
+ .sg-wrapper-less .modal-open {
6211
+ overflow: hidden;
6212
+ }
6213
+ .sg-wrapper-less .modal {
6214
+ display: none;
6215
+ overflow: hidden;
6216
+ position: fixed;
6217
+ top: 0;
6218
+ right: 0;
6219
+ bottom: 0;
6220
+ left: 0;
6221
+ z-index: 1050;
6222
+ -webkit-overflow-scrolling: touch;
6223
+ outline: 0;
6224
+ }
6225
+ .sg-wrapper-less .modal.fade .modal-dialog {
6226
+ -webkit-transform: translate(0, -25%);
6227
+ -ms-transform: translate(0, -25%);
6228
+ -o-transform: translate(0, -25%);
6229
+ transform: translate(0, -25%);
6230
+ -webkit-transition: -webkit-transform 0.3s ease-out;
6231
+ -o-transition: -o-transform 0.3s ease-out;
6232
+ transition: transform 0.3s ease-out;
6233
+ }
6234
+ .sg-wrapper-less .modal.in .modal-dialog {
6235
+ -webkit-transform: translate(0, 0);
6236
+ -ms-transform: translate(0, 0);
6237
+ -o-transform: translate(0, 0);
6238
+ transform: translate(0, 0);
6239
+ }
6240
+ .sg-wrapper-less .modal-open .modal {
6241
+ overflow-x: hidden;
6242
+ overflow-y: auto;
6243
+ }
6244
+ .sg-wrapper-less .modal-dialog {
6245
+ position: relative;
6246
+ width: auto;
6247
+ margin: 10px;
6248
+ }
6249
+ .sg-wrapper-less .modal-content {
6250
+ position: relative;
6251
+ background-color: #ffffff;
6252
+ border: 1px solid #999999;
6253
+ border: 1px solid transparent;
6254
+ border-radius: 0;
6255
+ -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
6256
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
6257
+ -webkit-background-clip: padding-box;
6258
+ background-clip: padding-box;
6259
+ outline: 0;
6260
+ }
6261
+ .sg-wrapper-less .modal-backdrop {
6262
+ position: fixed;
6263
+ top: 0;
6264
+ right: 0;
6265
+ bottom: 0;
6266
+ left: 0;
6267
+ z-index: 1040;
6268
+ background-color: #000000;
6269
+ }
6270
+ .sg-wrapper-less .modal-backdrop.fade {
6271
+ opacity: 0;
6272
+ filter: alpha(opacity=0);
6273
+ }
6274
+ .sg-wrapper-less .modal-backdrop.in {
6275
+ opacity: 0.5;
6276
+ filter: alpha(opacity=50);
6277
+ }
6278
+ .sg-wrapper-less .modal-header {
6279
+ padding: 20px;
6280
+ border-bottom: 1px solid #e5e5e5;
6281
+ min-height: 16.42857143px;
6282
+ }
6283
+ .sg-wrapper-less .modal-header .close {
6284
+ margin-top: -2px;
6285
+ }
6286
+ .sg-wrapper-less .modal-title {
6287
+ margin: 0;
6288
+ line-height: 1.42857143;
6289
+ }
6290
+ .sg-wrapper-less .modal-body {
6291
+ position: relative;
6292
+ padding: 20px;
6293
+ }
6294
+ .sg-wrapper-less .modal-footer {
6295
+ padding: 20px;
6296
+ text-align: right;
6297
+ border-top: 1px solid #e5e5e5;
6298
+ }
6299
+ .sg-wrapper-less .modal-footer .btn + .btn {
6300
+ margin-left: 5px;
6301
+ margin-bottom: 0;
6302
+ }
6303
+ .sg-wrapper-less .modal-footer .btn-group .btn + .btn {
6304
+ margin-left: -1px;
6305
+ }
6306
+ .sg-wrapper-less .modal-footer .btn-block + .btn-block {
6307
+ margin-left: 0;
6308
+ }
6309
+ .sg-wrapper-less .modal-scrollbar-measure {
6310
+ position: absolute;
6311
+ top: -9999px;
6312
+ width: 50px;
6313
+ height: 50px;
6314
+ overflow: scroll;
6315
+ }
6316
+ @media (min-width: 768px) {
6317
+ .sg-wrapper-less .modal-dialog {
6318
+ width: 600px;
6319
+ margin: 30px auto;
6320
+ }
6321
+ .sg-wrapper-less .modal-content {
6322
+ -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
6323
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
6324
+ }
6325
+ .sg-wrapper-less .modal-sm {
6326
+ width: 300px;
6327
+ }
6328
+ }
6329
+ @media (min-width: 992px) {
6330
+ .sg-wrapper-less .modal-lg {
6331
+ width: 900px;
6332
+ }
6333
+ }
6334
+ .sg-wrapper-less .tooltip {
6335
+ position: absolute;
6336
+ z-index: 1070;
6337
+ display: block;
6338
+ font-family: "Source Sans Pro", Calibri, Candara, Arial, sans-serif;
6339
+ font-size: 13px;
6340
+ font-weight: normal;
6341
+ line-height: 1.4;
6342
+ opacity: 0;
6343
+ filter: alpha(opacity=0);
6344
+ }
6345
+ .sg-wrapper-less .tooltip.in {
6346
+ opacity: 0.9;
6347
+ filter: alpha(opacity=90);
6348
+ }
6349
+ .sg-wrapper-less .tooltip.top {
6350
+ margin-top: -3px;
6351
+ padding: 5px 0;
6352
+ }
6353
+ .sg-wrapper-less .tooltip.right {
6354
+ margin-left: 3px;
6355
+ padding: 0 5px;
6356
+ }
6357
+ .sg-wrapper-less .tooltip.bottom {
6358
+ margin-top: 3px;
6359
+ padding: 5px 0;
6360
+ }
6361
+ .sg-wrapper-less .tooltip.left {
6362
+ margin-left: -3px;
6363
+ padding: 0 5px;
6364
+ }
6365
+ .sg-wrapper-less .tooltip-inner {
6366
+ max-width: 200px;
6367
+ padding: 3px 8px;
6368
+ color: #ffffff;
6369
+ text-align: center;
6370
+ text-decoration: none;
6371
+ background-color: #000000;
6372
+ border-radius: 0;
6373
+ }
6374
+ .sg-wrapper-less .tooltip-arrow {
6375
+ position: absolute;
6376
+ width: 0;
6377
+ height: 0;
6378
+ border-color: transparent;
6379
+ border-style: solid;
6380
+ }
6381
+ .sg-wrapper-less .tooltip.top .tooltip-arrow {
6382
+ bottom: 0;
6383
+ left: 50%;
6384
+ margin-left: -5px;
6385
+ border-width: 5px 5px 0;
6386
+ border-top-color: #000000;
6387
+ }
6388
+ .sg-wrapper-less .tooltip.top-left .tooltip-arrow {
6389
+ bottom: 0;
6390
+ right: 5px;
6391
+ margin-bottom: -5px;
6392
+ border-width: 5px 5px 0;
6393
+ border-top-color: #000000;
6394
+ }
6395
+ .sg-wrapper-less .tooltip.top-right .tooltip-arrow {
6396
+ bottom: 0;
6397
+ left: 5px;
6398
+ margin-bottom: -5px;
6399
+ border-width: 5px 5px 0;
6400
+ border-top-color: #000000;
6401
+ }
6402
+ .sg-wrapper-less .tooltip.right .tooltip-arrow {
6403
+ top: 50%;
6404
+ left: 0;
6405
+ margin-top: -5px;
6406
+ border-width: 5px 5px 5px 0;
6407
+ border-right-color: #000000;
6408
+ }
6409
+ .sg-wrapper-less .tooltip.left .tooltip-arrow {
6410
+ top: 50%;
6411
+ right: 0;
6412
+ margin-top: -5px;
6413
+ border-width: 5px 0 5px 5px;
6414
+ border-left-color: #000000;
6415
+ }
6416
+ .sg-wrapper-less .tooltip.bottom .tooltip-arrow {
6417
+ top: 0;
6418
+ left: 50%;
6419
+ margin-left: -5px;
6420
+ border-width: 0 5px 5px;
6421
+ border-bottom-color: #000000;
6422
+ }
6423
+ .sg-wrapper-less .tooltip.bottom-left .tooltip-arrow {
6424
+ top: 0;
6425
+ right: 5px;
6426
+ margin-top: -5px;
6427
+ border-width: 0 5px 5px;
6428
+ border-bottom-color: #000000;
6429
+ }
6430
+ .sg-wrapper-less .tooltip.bottom-right .tooltip-arrow {
6431
+ top: 0;
6432
+ left: 5px;
6433
+ margin-top: -5px;
6434
+ border-width: 0 5px 5px;
6435
+ border-bottom-color: #000000;
6436
+ }
6437
+ .sg-wrapper-less .popover {
6438
+ position: absolute;
6439
+ top: 0;
6440
+ left: 0;
6441
+ z-index: 1060;
6442
+ display: none;
6443
+ max-width: 276px;
6444
+ padding: 1px;
6445
+ font-family: "Source Sans Pro", Calibri, Candara, Arial, sans-serif;
6446
+ font-size: 15px;
6447
+ font-weight: normal;
6448
+ line-height: 1.42857143;
6449
+ text-align: left;
6450
+ background-color: #ffffff;
6451
+ -webkit-background-clip: padding-box;
6452
+ background-clip: padding-box;
6453
+ border: 1px solid #cccccc;
6454
+ border: 1px solid rgba(0, 0, 0, 0.2);
6455
+ border-radius: 0;
6456
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
6457
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
6458
+ white-space: normal;
6459
+ }
6460
+ .sg-wrapper-less .popover.top {
6461
+ margin-top: -10px;
6462
+ }
6463
+ .sg-wrapper-less .popover.right {
6464
+ margin-left: 10px;
6465
+ }
6466
+ .sg-wrapper-less .popover.bottom {
6467
+ margin-top: 10px;
6468
+ }
6469
+ .sg-wrapper-less .popover.left {
6470
+ margin-left: -10px;
6471
+ }
6472
+ .sg-wrapper-less .popover-title {
6473
+ margin: 0;
6474
+ padding: 8px 14px;
6475
+ font-size: 15px;
6476
+ background-color: #f7f7f7;
6477
+ border-bottom: 1px solid #ebebeb;
6478
+ border-radius: -1 -1 0 0;
6479
+ }
6480
+ .sg-wrapper-less .popover-content {
6481
+ padding: 9px 14px;
6482
+ }
6483
+ .sg-wrapper-less .popover > .arrow,
6484
+ .sg-wrapper-less .popover > .arrow:after {
6485
+ position: absolute;
6486
+ display: block;
6487
+ width: 0;
6488
+ height: 0;
6489
+ border-color: transparent;
6490
+ border-style: solid;
6491
+ }
6492
+ .sg-wrapper-less .popover > .arrow {
6493
+ border-width: 11px;
6494
+ }
6495
+ .sg-wrapper-less .popover > .arrow:after {
6496
+ border-width: 10px;
6497
+ content: "";
6498
+ }
6499
+ .sg-wrapper-less .popover.top > .arrow {
6500
+ left: 50%;
6501
+ margin-left: -11px;
6502
+ border-bottom-width: 0;
6503
+ border-top-color: #999999;
6504
+ border-top-color: rgba(0, 0, 0, 0.25);
6505
+ bottom: -11px;
6506
+ }
6507
+ .sg-wrapper-less .popover.top > .arrow:after {
6508
+ content: " ";
6509
+ bottom: 1px;
6510
+ margin-left: -10px;
6511
+ border-bottom-width: 0;
6512
+ border-top-color: #ffffff;
6513
+ }
6514
+ .sg-wrapper-less .popover.right > .arrow {
6515
+ top: 50%;
6516
+ left: -11px;
6517
+ margin-top: -11px;
6518
+ border-left-width: 0;
6519
+ border-right-color: #999999;
6520
+ border-right-color: rgba(0, 0, 0, 0.25);
6521
+ }
6522
+ .sg-wrapper-less .popover.right > .arrow:after {
6523
+ content: " ";
6524
+ left: 1px;
6525
+ bottom: -10px;
6526
+ border-left-width: 0;
6527
+ border-right-color: #ffffff;
6528
+ }
6529
+ .sg-wrapper-less .popover.bottom > .arrow {
6530
+ left: 50%;
6531
+ margin-left: -11px;
6532
+ border-top-width: 0;
6533
+ border-bottom-color: #999999;
6534
+ border-bottom-color: rgba(0, 0, 0, 0.25);
6535
+ top: -11px;
6536
+ }
6537
+ .sg-wrapper-less .popover.bottom > .arrow:after {
6538
+ content: " ";
6539
+ top: 1px;
6540
+ margin-left: -10px;
6541
+ border-top-width: 0;
6542
+ border-bottom-color: #ffffff;
6543
+ }
6544
+ .sg-wrapper-less .popover.left > .arrow {
6545
+ top: 50%;
6546
+ right: -11px;
6547
+ margin-top: -11px;
6548
+ border-right-width: 0;
6549
+ border-left-color: #999999;
6550
+ border-left-color: rgba(0, 0, 0, 0.25);
6551
+ }
6552
+ .sg-wrapper-less .popover.left > .arrow:after {
6553
+ content: " ";
6554
+ right: 1px;
6555
+ border-right-width: 0;
6556
+ border-left-color: #ffffff;
6557
+ bottom: -10px;
6558
+ }
6559
+ .sg-wrapper-less .carousel {
6560
+ position: relative;
6561
+ }
6562
+ .sg-wrapper-less .carousel-inner {
6563
+ position: relative;
6564
+ overflow: hidden;
6565
+ width: 100%;
6566
+ }
6567
+ .sg-wrapper-less .carousel-inner > .item {
6568
+ display: none;
6569
+ position: relative;
6570
+ -webkit-transition: 0.6s ease-in-out left;
6571
+ -o-transition: 0.6s ease-in-out left;
6572
+ transition: 0.6s ease-in-out left;
6573
+ }
6574
+ .sg-wrapper-less .carousel-inner > .item > img,
6575
+ .sg-wrapper-less .carousel-inner > .item > a > img {
6576
+ line-height: 1;
6577
+ }
6578
+ @media all and (transform-3d), (-webkit-transform-3d) {
6579
+ .sg-wrapper-less .carousel-inner > .item {
6580
+ -webkit-transition: -webkit-transform 0.6s ease-in-out;
6581
+ -o-transition: -o-transform 0.6s ease-in-out;
6582
+ transition: transform 0.6s ease-in-out;
6583
+ -webkit-backface-visibility: hidden;
6584
+ backface-visibility: hidden;
6585
+ -webkit-perspective: 1000;
6586
+ perspective: 1000;
6587
+ }
6588
+ .sg-wrapper-less .carousel-inner > .item.next,
6589
+ .sg-wrapper-less .carousel-inner > .item.active.right {
6590
+ -webkit-transform: translate3d(100%, 0, 0);
6591
+ transform: translate3d(100%, 0, 0);
6592
+ left: 0;
6593
+ }
6594
+ .sg-wrapper-less .carousel-inner > .item.prev,
6595
+ .sg-wrapper-less .carousel-inner > .item.active.left {
6596
+ -webkit-transform: translate3d(-100%, 0, 0);
6597
+ transform: translate3d(-100%, 0, 0);
6598
+ left: 0;
6599
+ }
6600
+ .sg-wrapper-less .carousel-inner > .item.next.left,
6601
+ .sg-wrapper-less .carousel-inner > .item.prev.right,
6602
+ .sg-wrapper-less .carousel-inner > .item.active {
6603
+ -webkit-transform: translate3d(0, 0, 0);
6604
+ transform: translate3d(0, 0, 0);
6605
+ left: 0;
6606
+ }
6607
+ }
6608
+ .sg-wrapper-less .carousel-inner > .active,
6609
+ .sg-wrapper-less .carousel-inner > .next,
6610
+ .sg-wrapper-less .carousel-inner > .prev {
6611
+ display: block;
6612
+ }
6613
+ .sg-wrapper-less .carousel-inner > .active {
6614
+ left: 0;
6615
+ }
6616
+ .sg-wrapper-less .carousel-inner > .next,
6617
+ .sg-wrapper-less .carousel-inner > .prev {
6618
+ position: absolute;
6619
+ top: 0;
6620
+ width: 100%;
6621
+ }
6622
+ .sg-wrapper-less .carousel-inner > .next {
6623
+ left: 100%;
6624
+ }
6625
+ .sg-wrapper-less .carousel-inner > .prev {
6626
+ left: -100%;
6627
+ }
6628
+ .sg-wrapper-less .carousel-inner > .next.left,
6629
+ .sg-wrapper-less .carousel-inner > .prev.right {
6630
+ left: 0;
6631
+ }
6632
+ .sg-wrapper-less .carousel-inner > .active.left {
6633
+ left: -100%;
6634
+ }
6635
+ .sg-wrapper-less .carousel-inner > .active.right {
6636
+ left: 100%;
6637
+ }
6638
+ .sg-wrapper-less .carousel-control {
6639
+ position: absolute;
6640
+ top: 0;
6641
+ left: 0;
6642
+ bottom: 0;
6643
+ width: 15%;
6644
+ opacity: 0.5;
6645
+ filter: alpha(opacity=50);
6646
+ font-size: 20px;
6647
+ color: #ffffff;
6648
+ text-align: center;
6649
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
6650
+ }
6651
+ .sg-wrapper-less .carousel-control.left {
6652
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
6653
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
6654
+ background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001)));
6655
+ background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
6656
+ background-repeat: repeat-x;
6657
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
6658
+ }
6659
+ .sg-wrapper-less .carousel-control.right {
6660
+ left: auto;
6661
+ right: 0;
6662
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
6663
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
6664
+ background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5)));
6665
+ background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
6666
+ background-repeat: repeat-x;
6667
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
6668
+ }
6669
+ .sg-wrapper-less .carousel-control:hover,
6670
+ .sg-wrapper-less .carousel-control:focus {
6671
+ outline: 0;
6672
+ color: #ffffff;
6673
+ text-decoration: none;
6674
+ opacity: 0.9;
6675
+ filter: alpha(opacity=90);
6676
+ }
6677
+ .sg-wrapper-less .carousel-control .icon-prev,
6678
+ .sg-wrapper-less .carousel-control .icon-next,
6679
+ .sg-wrapper-less .carousel-control .glyphicon-chevron-left,
6680
+ .sg-wrapper-less .carousel-control .glyphicon-chevron-right {
6681
+ position: absolute;
6682
+ top: 50%;
6683
+ z-index: 5;
6684
+ display: inline-block;
6685
+ }
6686
+ .sg-wrapper-less .carousel-control .icon-prev,
6687
+ .sg-wrapper-less .carousel-control .glyphicon-chevron-left {
6688
+ left: 50%;
6689
+ margin-left: -10px;
6690
+ }
6691
+ .sg-wrapper-less .carousel-control .icon-next,
6692
+ .sg-wrapper-less .carousel-control .glyphicon-chevron-right {
6693
+ right: 50%;
6694
+ margin-right: -10px;
6695
+ }
6696
+ .sg-wrapper-less .carousel-control .icon-prev,
6697
+ .sg-wrapper-less .carousel-control .icon-next {
6698
+ width: 20px;
6699
+ height: 20px;
6700
+ margin-top: -10px;
6701
+ line-height: 1;
6702
+ font-family: serif;
6703
+ }
6704
+ .sg-wrapper-less .carousel-control .icon-prev:before {
6705
+ content: '\2039';
6706
+ }
6707
+ .sg-wrapper-less .carousel-control .icon-next:before {
6708
+ content: '\203a';
6709
+ }
6710
+ .sg-wrapper-less .carousel-indicators {
6711
+ position: absolute;
6712
+ bottom: 10px;
6713
+ left: 50%;
6714
+ z-index: 15;
6715
+ width: 60%;
6716
+ margin-left: -30%;
6717
+ padding-left: 0;
6718
+ list-style: none;
6719
+ text-align: center;
6720
+ }
6721
+ .sg-wrapper-less .carousel-indicators li {
6722
+ display: inline-block;
6723
+ width: 10px;
6724
+ height: 10px;
6725
+ margin: 1px;
6726
+ text-indent: -999px;
6727
+ border: 1px solid #ffffff;
6728
+ border-radius: 10px;
6729
+ cursor: pointer;
6730
+ background-color: #000 \9;
6731
+ background-color: rgba(0, 0, 0, 0);
6732
+ }
6733
+ .sg-wrapper-less .carousel-indicators .active {
6734
+ margin: 0;
6735
+ width: 12px;
6736
+ height: 12px;
6737
+ background-color: #ffffff;
6738
+ }
6739
+ .sg-wrapper-less .carousel-caption {
6740
+ position: absolute;
6741
+ left: 15%;
6742
+ right: 15%;
6743
+ bottom: 20px;
6744
+ z-index: 10;
6745
+ padding-top: 20px;
6746
+ padding-bottom: 20px;
6747
+ color: #ffffff;
6748
+ text-align: center;
6749
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
6750
+ }
6751
+ .sg-wrapper-less .carousel-caption .btn {
6752
+ text-shadow: none;
6753
+ }
6754
+ @media screen and (min-width: 768px) {
6755
+ .sg-wrapper-less .carousel-control .glyphicon-chevron-left,
6756
+ .sg-wrapper-less .carousel-control .glyphicon-chevron-right,
6757
+ .sg-wrapper-less .carousel-control .icon-prev,
6758
+ .sg-wrapper-less .carousel-control .icon-next {
6759
+ width: 30px;
6760
+ height: 30px;
6761
+ margin-top: -15px;
6762
+ font-size: 30px;
6763
+ }
6764
+ .sg-wrapper-less .carousel-control .glyphicon-chevron-left,
6765
+ .sg-wrapper-less .carousel-control .icon-prev {
6766
+ margin-left: -15px;
6767
+ }
6768
+ .sg-wrapper-less .carousel-control .glyphicon-chevron-right,
6769
+ .sg-wrapper-less .carousel-control .icon-next {
6770
+ margin-right: -15px;
6771
+ }
6772
+ .sg-wrapper-less .carousel-caption {
6773
+ left: 20%;
6774
+ right: 20%;
6775
+ padding-bottom: 30px;
6776
+ }
6777
+ .sg-wrapper-less .carousel-indicators {
6778
+ bottom: 20px;
6779
+ }
6780
+ }
6781
+ .sg-wrapper-less .clearfix:before,
6782
+ .sg-wrapper-less .clearfix:after,
6783
+ .sg-wrapper-less .dl-horizontal dd:before,
6784
+ .sg-wrapper-less .dl-horizontal dd:after,
6785
+ .sg-wrapper-less .container:before,
6786
+ .sg-wrapper-less .container:after,
6787
+ .sg-wrapper-less .container-fluid:before,
6788
+ .sg-wrapper-less .container-fluid:after,
6789
+ .sg-wrapper-less .row:before,
6790
+ .sg-wrapper-less .row:after,
6791
+ .sg-wrapper-less .form-horizontal .form-group:before,
6792
+ .sg-wrapper-less .form-horizontal .form-group:after,
6793
+ .sg-wrapper-less .btn-toolbar:before,
6794
+ .sg-wrapper-less .btn-toolbar:after,
6795
+ .sg-wrapper-less .btn-group-vertical > .btn-group:before,
6796
+ .sg-wrapper-less .btn-group-vertical > .btn-group:after,
6797
+ .sg-wrapper-less .nav:before,
6798
+ .sg-wrapper-less .nav:after,
6799
+ .sg-wrapper-less .navbar:before,
6800
+ .sg-wrapper-less .navbar:after,
6801
+ .sg-wrapper-less .navbar-header:before,
6802
+ .sg-wrapper-less .navbar-header:after,
6803
+ .sg-wrapper-less .navbar-collapse:before,
6804
+ .sg-wrapper-less .navbar-collapse:after,
6805
+ .sg-wrapper-less .pager:before,
6806
+ .sg-wrapper-less .pager:after,
6807
+ .sg-wrapper-less .panel-body:before,
6808
+ .sg-wrapper-less .panel-body:after,
6809
+ .sg-wrapper-less .modal-footer:before,
6810
+ .sg-wrapper-less .modal-footer:after {
6811
+ content: " ";
6812
+ display: table;
6813
+ }
6814
+ .sg-wrapper-less .clearfix:after,
6815
+ .sg-wrapper-less .dl-horizontal dd:after,
6816
+ .sg-wrapper-less .container:after,
6817
+ .sg-wrapper-less .container-fluid:after,
6818
+ .sg-wrapper-less .row:after,
6819
+ .sg-wrapper-less .form-horizontal .form-group:after,
6820
+ .sg-wrapper-less .btn-toolbar:after,
6821
+ .sg-wrapper-less .btn-group-vertical > .btn-group:after,
6822
+ .sg-wrapper-less .nav:after,
6823
+ .sg-wrapper-less .navbar:after,
6824
+ .sg-wrapper-less .navbar-header:after,
6825
+ .sg-wrapper-less .navbar-collapse:after,
6826
+ .sg-wrapper-less .pager:after,
6827
+ .sg-wrapper-less .panel-body:after,
6828
+ .sg-wrapper-less .modal-footer:after {
6829
+ clear: both;
6830
+ }
6831
+ .sg-wrapper-less .center-block {
6832
+ display: block;
6833
+ margin-left: auto;
6834
+ margin-right: auto;
6835
+ }
6836
+ .sg-wrapper-less .pull-right {
6837
+ float: right !important;
6838
+ }
6839
+ .sg-wrapper-less .pull-left {
6840
+ float: left !important;
6841
+ }
6842
+ .sg-wrapper-less .hide {
6843
+ display: none !important;
6844
+ }
6845
+ .sg-wrapper-less .show {
6846
+ display: block !important;
6847
+ }
6848
+ .sg-wrapper-less .invisible {
6849
+ visibility: hidden;
6850
+ }
6851
+ .sg-wrapper-less .text-hide {
6852
+ font: 0/0 a;
6853
+ color: transparent;
6854
+ text-shadow: none;
6855
+ background-color: transparent;
6856
+ border: 0;
6857
+ }
6858
+ .sg-wrapper-less .hidden {
6859
+ display: none !important;
6860
+ }
6861
+ .sg-wrapper-less .affix {
6862
+ position: fixed;
6863
+ }
6864
+ @-ms-viewport {
6865
+ width: device-width;
6866
+ }
6867
+ .sg-wrapper-less .visible-xs,
6868
+ .sg-wrapper-less .visible-sm,
6869
+ .sg-wrapper-less .visible-md,
6870
+ .sg-wrapper-less .visible-lg {
6871
+ display: none !important;
6872
+ }
6873
+ .sg-wrapper-less .visible-xs-block,
6874
+ .sg-wrapper-less .visible-xs-inline,
6875
+ .sg-wrapper-less .visible-xs-inline-block,
6876
+ .sg-wrapper-less .visible-sm-block,
6877
+ .sg-wrapper-less .visible-sm-inline,
6878
+ .sg-wrapper-less .visible-sm-inline-block,
6879
+ .sg-wrapper-less .visible-md-block,
6880
+ .sg-wrapper-less .visible-md-inline,
6881
+ .sg-wrapper-less .visible-md-inline-block,
6882
+ .sg-wrapper-less .visible-lg-block,
6883
+ .sg-wrapper-less .visible-lg-inline,
6884
+ .sg-wrapper-less .visible-lg-inline-block {
6885
+ display: none !important;
6886
+ }
6887
+ @media (max-width: 767px) {
6888
+ .sg-wrapper-less .visible-xs {
6889
+ display: block !important;
6890
+ }
6891
+ .sg-wrapper-less table.visible-xs {
6892
+ display: table;
6893
+ }
6894
+ .sg-wrapper-less tr.visible-xs {
6895
+ display: table-row !important;
6896
+ }
6897
+ .sg-wrapper-less th.visible-xs,
6898
+ .sg-wrapper-less td.visible-xs {
6899
+ display: table-cell !important;
6900
+ }
6901
+ }
6902
+ @media (max-width: 767px) {
6903
+ .sg-wrapper-less .visible-xs-block {
6904
+ display: block !important;
6905
+ }
6906
+ }
6907
+ @media (max-width: 767px) {
6908
+ .sg-wrapper-less .visible-xs-inline {
6909
+ display: inline !important;
6910
+ }
6911
+ }
6912
+ @media (max-width: 767px) {
6913
+ .sg-wrapper-less .visible-xs-inline-block {
6914
+ display: inline-block !important;
6915
+ }
6916
+ }
6917
+ @media (min-width: 768px) and (max-width: 991px) {
6918
+ .sg-wrapper-less .visible-sm {
6919
+ display: block !important;
6920
+ }
6921
+ .sg-wrapper-less table.visible-sm {
6922
+ display: table;
6923
+ }
6924
+ .sg-wrapper-less tr.visible-sm {
6925
+ display: table-row !important;
6926
+ }
6927
+ .sg-wrapper-less th.visible-sm,
6928
+ .sg-wrapper-less td.visible-sm {
6929
+ display: table-cell !important;
6930
+ }
6931
+ }
6932
+ @media (min-width: 768px) and (max-width: 991px) {
6933
+ .sg-wrapper-less .visible-sm-block {
6934
+ display: block !important;
6935
+ }
6936
+ }
6937
+ @media (min-width: 768px) and (max-width: 991px) {
6938
+ .sg-wrapper-less .visible-sm-inline {
6939
+ display: inline !important;
6940
+ }
6941
+ }
6942
+ @media (min-width: 768px) and (max-width: 991px) {
6943
+ .sg-wrapper-less .visible-sm-inline-block {
6944
+ display: inline-block !important;
6945
+ }
6946
+ }
6947
+ @media (min-width: 992px) and (max-width: 1199px) {
6948
+ .sg-wrapper-less .visible-md {
6949
+ display: block !important;
6950
+ }
6951
+ .sg-wrapper-less table.visible-md {
6952
+ display: table;
6953
+ }
6954
+ .sg-wrapper-less tr.visible-md {
6955
+ display: table-row !important;
6956
+ }
6957
+ .sg-wrapper-less th.visible-md,
6958
+ .sg-wrapper-less td.visible-md {
6959
+ display: table-cell !important;
6960
+ }
6961
+ }
6962
+ @media (min-width: 992px) and (max-width: 1199px) {
6963
+ .sg-wrapper-less .visible-md-block {
6964
+ display: block !important;
6965
+ }
6966
+ }
6967
+ @media (min-width: 992px) and (max-width: 1199px) {
6968
+ .sg-wrapper-less .visible-md-inline {
6969
+ display: inline !important;
6970
+ }
6971
+ }
6972
+ @media (min-width: 992px) and (max-width: 1199px) {
6973
+ .sg-wrapper-less .visible-md-inline-block {
6974
+ display: inline-block !important;
6975
+ }
6976
+ }
6977
+ @media (min-width: 1200px) {
6978
+ .sg-wrapper-less .visible-lg {
6979
+ display: block !important;
6980
+ }
6981
+ .sg-wrapper-less table.visible-lg {
6982
+ display: table;
6983
+ }
6984
+ .sg-wrapper-less tr.visible-lg {
6985
+ display: table-row !important;
6986
+ }
6987
+ .sg-wrapper-less th.visible-lg,
6988
+ .sg-wrapper-less td.visible-lg {
6989
+ display: table-cell !important;
6990
+ }
6991
+ }
6992
+ @media (min-width: 1200px) {
6993
+ .sg-wrapper-less .visible-lg-block {
6994
+ display: block !important;
6995
+ }
6996
+ }
6997
+ @media (min-width: 1200px) {
6998
+ .sg-wrapper-less .visible-lg-inline {
6999
+ display: inline !important;
7000
+ }
7001
+ }
7002
+ @media (min-width: 1200px) {
7003
+ .sg-wrapper-less .visible-lg-inline-block {
7004
+ display: inline-block !important;
7005
+ }
7006
+ }
7007
+ @media (max-width: 767px) {
7008
+ .sg-wrapper-less .hidden-xs {
7009
+ display: none !important;
7010
+ }
7011
+ }
7012
+ @media (min-width: 768px) and (max-width: 991px) {
7013
+ .sg-wrapper-less .hidden-sm {
7014
+ display: none !important;
7015
+ }
7016
+ }
7017
+ @media (min-width: 992px) and (max-width: 1199px) {
7018
+ .sg-wrapper-less .hidden-md {
7019
+ display: none !important;
7020
+ }
7021
+ }
7022
+ @media (min-width: 1200px) {
7023
+ .sg-wrapper-less .hidden-lg {
7024
+ display: none !important;
7025
+ }
7026
+ }
7027
+ .sg-wrapper-less .visible-print {
7028
+ display: none !important;
7029
+ }
7030
+ @media print {
7031
+ .sg-wrapper-less .visible-print {
7032
+ display: block !important;
7033
+ }
7034
+ .sg-wrapper-less table.visible-print {
7035
+ display: table;
7036
+ }
7037
+ .sg-wrapper-less tr.visible-print {
7038
+ display: table-row !important;
7039
+ }
7040
+ .sg-wrapper-less th.visible-print,
7041
+ .sg-wrapper-less td.visible-print {
7042
+ display: table-cell !important;
7043
+ }
7044
+ }
7045
+ .sg-wrapper-less .visible-print-block {
7046
+ display: none !important;
7047
+ }
7048
+ @media print {
7049
+ .sg-wrapper-less .visible-print-block {
7050
+ display: block !important;
7051
+ }
7052
+ }
7053
+ .sg-wrapper-less .visible-print-inline {
7054
+ display: none !important;
7055
+ }
7056
+ @media print {
7057
+ .sg-wrapper-less .visible-print-inline {
7058
+ display: inline !important;
7059
+ }
7060
+ }
7061
+ .sg-wrapper-less .visible-print-inline-block {
7062
+ display: none !important;
7063
+ }
7064
+ @media print {
7065
+ .sg-wrapper-less .visible-print-inline-block {
7066
+ display: inline-block !important;
7067
+ }
7068
+ }
7069
+ @media print {
7070
+ .sg-wrapper-less .hidden-print {
7071
+ display: none !important;
7072
+ }
7073
+ }
7074
+ .sg-wrapper-less .navbar-inverse .badge {
7075
+ background-color: #fff;
7076
+ color: #2780e3;
7077
+ }
7078
+ .sg-wrapper-less body {
7079
+ -webkit-font-smoothing: antialiased;
7080
+ }
7081
+ .sg-wrapper-less .text-primary,
7082
+ .sg-wrapper-less .text-primary:hover {
7083
+ color: #2780e3;
7084
+ }
7085
+ .sg-wrapper-less .text-success,
7086
+ .sg-wrapper-less .text-success:hover {
7087
+ color: #3fb618;
7088
+ }
7089
+ .sg-wrapper-less .text-danger,
7090
+ .sg-wrapper-less .text-danger:hover {
7091
+ color: #ff0039;
7092
+ }
7093
+ .sg-wrapper-less .text-warning,
7094
+ .sg-wrapper-less .text-warning:hover {
7095
+ color: #ff7518;
7096
+ }
7097
+ .sg-wrapper-less .text-info,
7098
+ .sg-wrapper-less .text-info:hover {
7099
+ color: #9954bb;
7100
+ }
7101
+ .sg-wrapper-less table a:not(.btn),
7102
+ .sg-wrapper-less .table a:not(.btn) {
7103
+ text-decoration: underline;
7104
+ }
7105
+ .sg-wrapper-less table .dropdown-menu a,
7106
+ .sg-wrapper-less .table .dropdown-menu a {
7107
+ text-decoration: none;
7108
+ }
7109
+ .sg-wrapper-less table .success,
7110
+ .sg-wrapper-less .table .success,
7111
+ .sg-wrapper-less table .warning,
7112
+ .sg-wrapper-less .table .warning,
7113
+ .sg-wrapper-less table .danger,
7114
+ .sg-wrapper-less .table .danger,
7115
+ .sg-wrapper-less table .info,
7116
+ .sg-wrapper-less .table .info {
7117
+ color: #fff;
7118
+ }
7119
+ .sg-wrapper-less table .success a,
7120
+ .sg-wrapper-less .table .success a,
7121
+ .sg-wrapper-less table .warning a,
7122
+ .sg-wrapper-less .table .warning a,
7123
+ .sg-wrapper-less table .danger a,
7124
+ .sg-wrapper-less .table .danger a,
7125
+ .sg-wrapper-less table .info a,
7126
+ .sg-wrapper-less .table .info a {
7127
+ color: #fff;
7128
+ }
7129
+ .sg-wrapper-less .has-warning .help-block,
7130
+ .sg-wrapper-less .has-warning .control-label,
7131
+ .sg-wrapper-less .has-warning .form-control-feedback {
7132
+ color: #ff7518;
7133
+ }
7134
+ .sg-wrapper-less .has-warning .form-control,
7135
+ .sg-wrapper-less .has-warning .form-control:focus,
7136
+ .sg-wrapper-less .has-warning .input-group-addon {
7137
+ border: 1px solid #ff7518;
7138
+ }
7139
+ .sg-wrapper-less .has-error .help-block,
7140
+ .sg-wrapper-less .has-error .control-label,
7141
+ .sg-wrapper-less .has-error .form-control-feedback {
7142
+ color: #ff0039;
7143
+ }
7144
+ .sg-wrapper-less .has-error .form-control,
7145
+ .sg-wrapper-less .has-error .form-control:focus,
7146
+ .sg-wrapper-less .has-error .input-group-addon {
7147
+ border: 1px solid #ff0039;
7148
+ }
7149
+ .sg-wrapper-less .has-success .help-block,
7150
+ .sg-wrapper-less .has-success .control-label,
7151
+ .sg-wrapper-less .has-success .form-control-feedback {
7152
+ color: #3fb618;
7153
+ }
7154
+ .sg-wrapper-less .has-success .form-control,
7155
+ .sg-wrapper-less .has-success .form-control:focus,
7156
+ .sg-wrapper-less .has-success .input-group-addon {
7157
+ border: 1px solid #3fb618;
7158
+ }
7159
+ .sg-wrapper-less .nav-pills > li > a {
7160
+ border-radius: 0;
7161
+ }
7162
+ .sg-wrapper-less .dropdown-menu > li > a:hover,
7163
+ .sg-wrapper-less .dropdown-menu > li > a:focus {
7164
+ background-image: none;
7165
+ }
7166
+ .sg-wrapper-less .close {
7167
+ text-decoration: none;
7168
+ text-shadow: none;
7169
+ opacity: 0.4;
7170
+ }
7171
+ .sg-wrapper-less .close:hover,
7172
+ .sg-wrapper-less .close:focus {
7173
+ opacity: 1;
7174
+ }
7175
+ .sg-wrapper-less .alert {
7176
+ border: none;
7177
+ }
7178
+ .sg-wrapper-less .alert .alert-link {
7179
+ text-decoration: underline;
7180
+ color: #fff;
7181
+ }
7182
+ .sg-wrapper-less .label {
7183
+ border-radius: 0;
7184
+ }
7185
+ .sg-wrapper-less .progress {
7186
+ height: 8px;
7187
+ -webkit-box-shadow: none;
7188
+ box-shadow: none;
7189
+ }
7190
+ .sg-wrapper-less .progress .progress-bar {
7191
+ font-size: 8px;
7192
+ line-height: 8px;
7193
+ }
7194
+ .sg-wrapper-less .panel-heading,
7195
+ .sg-wrapper-less .panel-footer {
7196
+ border-top-right-radius: 0;
7197
+ border-top-left-radius: 0;
7198
+ }
7199
+ .sg-wrapper-less .panel-default .close {
7200
+ color: #333333;
7201
+ }
7202
+ .sg-wrapper-less a.list-group-item-success.active {
7203
+ background-color: #3fb618;
7204
+ }
7205
+ .sg-wrapper-less a.list-group-item-success.active:hover,
7206
+ .sg-wrapper-less a.list-group-item-success.active:focus {
7207
+ background-color: #379f15;
7208
+ }
7209
+ .sg-wrapper-less a.list-group-item-warning.active {
7210
+ background-color: #ff7518;
7211
+ }
7212
+ .sg-wrapper-less a.list-group-item-warning.active:hover,
7213
+ .sg-wrapper-less a.list-group-item-warning.active:focus {
7214
+ background-color: #fe6600;
7215
+ }
7216
+ .sg-wrapper-less a.list-group-item-danger.active {
7217
+ background-color: #ff0039;
7218
+ }
7219
+ .sg-wrapper-less a.list-group-item-danger.active:hover,
7220
+ .sg-wrapper-less a.list-group-item-danger.active:focus {
7221
+ background-color: #e60033;
7222
+ }
7223
+ .sg-wrapper-less .modal .close {
7224
+ color: #333333;
7225
+ }
7226
+ .sg-wrapper-less .popover {
7227
+ color: #333333;
7228
+ }
7229
+ .sg-wrapper-less .btn-file {
7230
+ position: relative;
7231
+ overflow: hidden;
7232
+ }
7233
+ .sg-wrapper-less .btn-file input[type=file] {
7234
+ position: absolute;
7235
+ top: 0;
7236
+ right: 0;
7237
+ min-width: 100%;
7238
+ min-height: 100%;
7239
+ font-size: 100px;
7240
+ text-align: right;
7241
+ filter: alpha(opacity=0);
7242
+ opacity: 0;
7243
+ outline: none;
7244
+ background: white;
7245
+ cursor: inherit;
7246
+ display: block;
7247
+ }
7248
+ .sg-wrapper-less select {
7249
+ background: #ffffff url("../img/sgselect.png") no-repeat !important;
7250
+ background-size: 24px 20px;
7251
+ background-position: right center !important;
7252
+ color: #888;
7253
+ outline: none;
7254
+ display: inline-block;
7255
+ -webkit-appearance: none;
7256
+ -moz-appearance: none;
7257
+ appearance: none;
7258
+ cursor: pointer;
7259
+ }
7260
+ .sg-wrapper-less #sg-wrapper {
7261
+ width: 100%;
7262
+ min-width: 650px;
7263
+ border: 1px #5c5c5c solid;
7264
+ background-color: #333333;
7265
+ }
7266
+ .sg-wrapper-less #sg-sidebar-wrapper {
7267
+ width: 210px;
7268
+ float: left;
7269
+ }
7270
+ .sg-wrapper-less #sg-content-wrapper {
7271
+ position: relative;
7272
+ float: left;
7273
+ width: calc(100% - 210px);
7274
+ /*Same as sidebar*/
7275
+ border-left: 1px #333333 solid;
7276
+ min-height: 675px;
7277
+ background-color: #ffffff;
7278
+ }
7279
+ .sg-wrapper-less .container-fluid {
7280
+ min-height: 380px;
7281
+ margin-top: 15px;
7282
+ }
7283
+ .sg-wrapper-less .metro .sidebar {
7284
+ margin: 0;
7285
+ padding: 0;
7286
+ background-color: #3D3D3D;
7287
+ width: 100%;
7288
+ /*height: 100%;*/
7289
+ }
7290
+ .sg-wrapper-less .metro .sidebar > ul {
7291
+ margin: 0;
7292
+ padding: 0;
7293
+ list-style: none;
7294
+ }
7295
+ .sg-wrapper-less .metro .sidebar > ul li {
7296
+ display: block;
7297
+ border: 0;
7298
+ border-bottom: 1px #5c5c5c solid;
7299
+ position: relative;
7300
+ }
7301
+ .sg-wrapper-less .metro .sidebar > ul li.title {
7302
+ padding: 20px 20px 10px 20px;
7303
+ font-weight: 300;
7304
+ letter-spacing: 0.00em;
7305
+ font-size: 2.5rem;
7306
+ line-height: 2.5rem;
7307
+ letter-spacing: 0.01em;
7308
+ color: #000000;
7309
+ font-size: 2.2rem;
7310
+ line-height: 2.2rem;
7311
+ color: #ffffff;
7312
+ height: 170px;
7313
+ background-image: url("../img/sglogo.png");
7314
+ background-size: 172px 85px;
7315
+ background-repeat: no-repeat;
7316
+ background-position: center 40px;
7317
+ }
7318
+ .sg-wrapper-less .metro .sidebar > ul li a {
7319
+ display: block;
7320
+ position: relative;
7321
+ padding: 10px 20px;
7322
+ text-decoration: none;
7323
+ color: #eeeeee;
7324
+ background-color: #3D3D3D;
7325
+ }
7326
+ .sg-wrapper-less .metro .sidebar > ul li a:hover {
7327
+ background-color: #262626;
7328
+ color: #ffffff;
7329
+ }
7330
+ .sg-wrapper-less .metro .sidebar > ul li a.dropdown-toggle:after {
7331
+ right: 10px;
7332
+ bottom: 5px;
7333
+ }
7334
+ .sg-wrapper-less .metro .sidebar > ul li a [class*="icon-"] {
7335
+ margin-right: 15px;
7336
+ }
7337
+ .sg-wrapper-less .metro .sidebar > ul li.stick {
7338
+ position: relative;
7339
+ }
7340
+ .sg-wrapper-less .metro .sidebar > ul li.stick:before {
7341
+ content: "";
7342
+ position: absolute;
7343
+ width: 7px;
7344
+ height: 40px;
7345
+ left: -7px;
7346
+ text-indent: -9999px;
7347
+ border-top-left-radius: 5px;
7348
+ border-bottom-left-radius: 5px;
7349
+ background-color: inherit;
7350
+ }
7351
+ .sg-wrapper-less .metro .sidebar > ul li.disabled a {
7352
+ background-color: #8a8a8a;
7353
+ cursor: default;
7354
+ color: #555555;
7355
+ }
7356
+ .sg-wrapper-less .metro .sidebar > ul li.active a {
7357
+ background-color: #9a1616;
7358
+ color: #ffffff;
7359
+ }
7360
+ .sg-wrapper-less .metro .sidebar > ul ul {
7361
+ margin: 0;
7362
+ padding: 0;
7363
+ list-style: none;
7364
+ position: absolute;
7365
+ display: none;
7366
+ z-index: 1000;
7367
+ background: #ffffff;
7368
+ min-width: 220px;
7369
+ width: auto;
7370
+ border: 1px solid #dcddde;
7371
+ box-shadow: none;
7372
+ position: relative !important;
7373
+ background-color: #e5e5e5;
7374
+ min-width: 100%;
7375
+ }
7376
+ .sg-wrapper-less .metro .sidebar > ul ul li {
7377
+ display: block;
7378
+ margin: 10px 0;
7379
+ padding: 0;
7380
+ vertical-align: baseline;
7381
+ position: relative;
7382
+ font-family: 'Segoe UI_', 'Open Sans', Verdana, Arial, Helvetica, sans-serif;
7383
+ }
7384
+ .sg-wrapper-less .metro .sidebar > ul ul li a {
7385
+ display: block;
7386
+ text-decoration: none;
7387
+ font-family: 'Segoe UI Light_', 'Open Sans Light', Verdana, Arial, Helvetica, sans-serif;
7388
+ font-weight: 300;
7389
+ letter-spacing: 0.00em;
7390
+ font-size: 2.5rem;
7391
+ line-height: 2.5rem;
7392
+ letter-spacing: 0.01em;
7393
+ color: #000000;
7394
+ line-height: 2.2rem;
7395
+ font-size: 2.2rem;
7396
+ color: inherit;
7397
+ }
7398
+ .sg-wrapper-less .metro .sidebar > ul ul li.title {
7399
+ font-family: 'Segoe UI Light_', 'Open Sans Light', Verdana, Arial, Helvetica, sans-serif;
7400
+ font-weight: 300;
7401
+ color: #000000;
7402
+ letter-spacing: 0.00em;
7403
+ font-size: 2.5rem;
7404
+ line-height: 2.5rem;
7405
+ letter-spacing: 0.01em;
7406
+ font-size: 4rem;
7407
+ margin-bottom: 20px;
7408
+ }
7409
+ .sg-wrapper-less .metro .sidebar > ul ul.compact a {
7410
+ font-weight: normal;
7411
+ font-size: 10.5pt;
7412
+ line-height: 12pt;
7413
+ color: inherit;
7414
+ }
7415
+ .sg-wrapper-less .metro .sidebar > ul ul.compact li.title {
7416
+ margin-bottom: 10px;
7417
+ font-family: 'Segoe UI Semibold_', 'Open Sans Bold', Verdana, Arial, Helvetica, sans-serif;
7418
+ font-weight: bold;
7419
+ color: #000000;
7420
+ font-size: 1.6rem;
7421
+ line-height: 1.6rem;
7422
+ letter-spacing: 0.02em;
7423
+ }
7424
+ .sg-wrapper-less .metro .sidebar > ul ul ul.secondary {
7425
+ margin: 0;
7426
+ padding: 0;
7427
+ list-style: none;
7428
+ margin-left: 15px;
7429
+ }
7430
+ .sg-wrapper-less .metro .sidebar > ul ul ul.secondary li a {
7431
+ font-family: 'Segoe UI Semibold_', 'Open Sans Bold', Verdana, Arial, Helvetica, sans-serif;
7432
+ font-weight: bold;
7433
+ color: #000000;
7434
+ font-size: 1.6rem;
7435
+ line-height: 1.6rem;
7436
+ letter-spacing: 0.02em;
7437
+ font-weight: normal;
7438
+ font-style: normal;
7439
+ line-height: 1.4rem;
7440
+ color: inherit;
7441
+ }
7442
+ .sg-wrapper-less .metro .sidebar > ul ul.shadow {
7443
+ box-shadow: 3px 3px 0 rgba(236, 236, 236, 0.7);
7444
+ }
7445
+ .sg-wrapper-less .metro .sidebar > ul ul li {
7446
+ margin: 5px 0 0;
7447
+ width: 100%;
7448
+ border: 1px transparent solid;
7449
+ }
7450
+ .sg-wrapper-less .metro .sidebar > ul ul li:last-child {
7451
+ margin-bottom: 5px;
7452
+ }
7453
+ .sg-wrapper-less .metro .sidebar > ul ul li.disabled,
7454
+ .sg-wrapper-less .metro .sidebar > ul ul li.disabled:hover {
7455
+ cursor: default !important;
7456
+ background: transparent !important;
7457
+ color: #eeeeee;
7458
+ }
7459
+ .sg-wrapper-less .metro .sidebar > ul ul li.disabled a,
7460
+ .sg-wrapper-less .metro .sidebar > ul ul li.disabled:hover a {
7461
+ color: inherit;
7462
+ cursor: inherit;
7463
+ background: inherit;
7464
+ }
7465
+ .sg-wrapper-less .metro .sidebar > ul ul a {
7466
+ padding: 8px 32px !important;
7467
+ color: inherit;
7468
+ font-size: 15px !important;
7469
+ line-height: 14px !important;
7470
+ cursor: pointer;
7471
+ }
7472
+ .sg-wrapper-less .metro .sidebar > ul ul li:hover {
7473
+ background: #edf4fc;
7474
+ border-color: #a8d2fd;
7475
+ }
7476
+ .sg-wrapper-less .metro .sidebar > ul ul li.checked a:before,
7477
+ .sg-wrapper-less .metro .sidebar > ul ul li.checked-partial a:before,
7478
+ .sg-wrapper-less .metro .sidebar > ul ul li.unchecked a:before {
7479
+ font-family: metroSysIcons;
7480
+ position: absolute;
7481
+ left: 10px;
7482
+ content: "\e004";
7483
+ }
7484
+ .sg-wrapper-less .metro .sidebar > ul ul li.checked-partial a:before {
7485
+ content: "\e005";
7486
+ }
7487
+ .sg-wrapper-less .metro .sidebar > ul ul li.unchecked a:before {
7488
+ content: "\e005";
7489
+ }
7490
+ .sg-wrapper-less .metro .sidebar > ul ul.place-right {
7491
+ right: -15px;
7492
+ left: auto;
7493
+ }
7494
+ .sg-wrapper-less .metro .sidebar > ul ul .divider {
7495
+ padding: 0;
7496
+ height: 1px;
7497
+ margin: 9px 1px;
7498
+ overflow: hidden;
7499
+ background-color: #e5e5e5;
7500
+ border-width: 0;
7501
+ }
7502
+ .sg-wrapper-less .metro .sidebar > ul ul .divider:hover {
7503
+ background: #e5e5e5;
7504
+ }
7505
+ .sg-wrapper-less .metro .sidebar > ul ul.open {
7506
+ display: block !important;
7507
+ }
7508
+ .sg-wrapper-less .metro .sidebar > ul ul .dropdown-menu {
7509
+ left: 100%;
7510
+ top: -10%;
7511
+ }
7512
+ .sg-wrapper-less .metro .sidebar > ul ul > li:hover > .dropdown-menu[data-show="hover"] {
7513
+ display: block;
7514
+ }
7515
+ .sg-wrapper-less .metro .sidebar > ul ul > li > a.dropdown-toggle:after {
7516
+ font-family: metroSysIcons;
7517
+ font-size: .7em;
7518
+ content: "\e001";
7519
+ left: 90%;
7520
+ top: 50%;
7521
+ margin-top: -1.4em;
7522
+ -webkit-transform: rotate(-90deg);
7523
+ -moz-transform: rotate(-90deg);
7524
+ -ms-transform: rotate(-90deg);
7525
+ -o-transform: rotate(-90deg);
7526
+ transform: rotate(-90deg);
7527
+ }
7528
+ .sg-wrapper-less .metro .sidebar > ul ul.drop-left {
7529
+ left: -100%;
7530
+ }
7531
+ .sg-wrapper-less .metro .sidebar > ul ul.drop-up {
7532
+ top: auto;
7533
+ bottom: 0;
7534
+ }
7535
+ .sg-wrapper-less .metro .sidebar > ul ul .menu-title {
7536
+ background-color: #f6f7f8;
7537
+ font-size: 12px;
7538
+ line-height: 14px;
7539
+ padding: 4px 8px;
7540
+ border: 0;
7541
+ border-bottom: 1px #dcddde solid;
7542
+ border-top: 1px #dcddde solid;
7543
+ color: #646464;
7544
+ }
7545
+ .sg-wrapper-less .metro .sidebar > ul ul .menu-title:first-child {
7546
+ margin: 0;
7547
+ border-top-width: 0;
7548
+ }
7549
+ .sg-wrapper-less .metro .sidebar > ul ul .menu-title:first-child:hover {
7550
+ border-top-width: 0;
7551
+ }
7552
+ .sg-wrapper-less .metro .sidebar > ul ul .menu-title:hover {
7553
+ background-color: #f6f7f8;
7554
+ cursor: default;
7555
+ border: 0;
7556
+ border-bottom: 1px #dcddde solid;
7557
+ border-top: 1px #dcddde solid;
7558
+ }
7559
+ .sg-wrapper-less .metro .sidebar > ul ul.inverse {
7560
+ border: 2px #3b3b3b solid;
7561
+ }
7562
+ .sg-wrapper-less .metro .sidebar > ul ul.inverse li {
7563
+ border: 0;
7564
+ }
7565
+ .sg-wrapper-less .metro .sidebar > ul ul.inverse li a {
7566
+ padding: 9px 32px !important;
7567
+ }
7568
+ .sg-wrapper-less .metro .sidebar > ul ul.inverse li:hover {
7569
+ border: 0;
7570
+ background-color: #e5e5e5;
7571
+ }
7572
+ .sg-wrapper-less .metro .sidebar > ul ul.inverse .menu-title:hover {
7573
+ background-color: #f6f7f8;
7574
+ }
7575
+ .sg-wrapper-less .metro .sidebar > ul ul.inverse .divider {
7576
+ margin-left: 0;
7577
+ margin-right: 0;
7578
+ }
7579
+ .sg-wrapper-less .metro .sidebar > ul ul.dark {
7580
+ background-color: #333333;
7581
+ border: 2px #333333 solid;
7582
+ color: #ffffff;
7583
+ }
7584
+ .sg-wrapper-less .metro .sidebar > ul ul.dark.opacity {
7585
+ background-color: rgba(61, 61, 61, 0.9);
7586
+ }
7587
+ .sg-wrapper-less .metro .sidebar > ul ul.dark li {
7588
+ border: 0;
7589
+ color: inherit;
7590
+ }
7591
+ .sg-wrapper-less .metro .sidebar > ul ul.dark li a {
7592
+ padding: 9px 32px !important;
7593
+ color: inherit;
7594
+ }
7595
+ .sg-wrapper-less .metro .sidebar > ul ul.dark li.disabled,
7596
+ .sg-wrapper-less .metro .sidebar > ul ul.dark li.disabled:hover {
7597
+ cursor: default !important;
7598
+ background: transparent !important;
7599
+ color: #555555;
7600
+ }
7601
+ .sg-wrapper-less .metro .sidebar > ul ul.dark li.disabled a,
7602
+ .sg-wrapper-less .metro .sidebar > ul ul.dark li.disabled:hover a {
7603
+ color: inherit;
7604
+ cursor: inherit;
7605
+ background: inherit;
7606
+ }
7607
+ .sg-wrapper-less .metro .sidebar > ul ul.dark li:hover {
7608
+ border: 0;
7609
+ background-color: #201a1a;
7610
+ color: #ffffff;
7611
+ }
7612
+ .sg-wrapper-less .metro .sidebar > ul ul.dark .menu-title {
7613
+ background-color: #3b3b3b;
7614
+ }
7615
+ .sg-wrapper-less .metro .sidebar > ul ul.dark .menu-title:hover {
7616
+ background-color: #3b3b3b;
7617
+ }
7618
+ .sg-wrapper-less .metro .sidebar > ul ul.dark .divider {
7619
+ margin-left: 0;
7620
+ margin-right: 0;
7621
+ background-color: #555555;
7622
+ }
7623
+ .sg-wrapper-less .metro .sidebar > ul ul.dark .divider:hover {
7624
+ background: #555555;
7625
+ }
7626
+ .sg-wrapper-less .metro .sidebar > ul ul li {
7627
+ border: 0;
7628
+ }
7629
+ .sg-wrapper-less .metro .sidebar > ul ul li a {
7630
+ background-color: #e5e5e5;
7631
+ }
7632
+ .sg-wrapper-less .metro .sidebar > ul ul li.divider {
7633
+ background-color: #c2c2c2;
7634
+ }
7635
+ .sg-wrapper-less .metro .sidebar > ul ul li.divider:hover {
7636
+ background-color: #c2c2c2;
7637
+ }
7638
+ .sg-wrapper-less .metro .sidebar > ul ul li.disabled a {
7639
+ color: #999999;
7640
+ }
7641
+ .sg-wrapper-less .metro .sidebar > ul ul li.disabled a:hover {
7642
+ color: #999999;
7643
+ }
7644
+ .sg-wrapper-less .metro .sidebar > ul ul.open {
7645
+ display: block;
7646
+ }
7647
+ .sg-wrapper-less .metro .sidebar.light {
7648
+ background-color: #ffffff;
7649
+ }
7650
+ .sg-wrapper-less .metro .sidebar.light li {
7651
+ border-bottom-color: #eeeeee;
7652
+ }
7653
+ .sg-wrapper-less .metro .sidebar.light li.title {
7654
+ color: #1d1d1d;
7655
+ }
7656
+ .sg-wrapper-less .metro .sidebar.light li a {
7657
+ color: #1d1d1d;
7658
+ background-color: #ffffff;
7659
+ }
7660
+ .sg-wrapper-less .metro .sidebar.light li a:hover {
7661
+ background-color: #00aff0;
7662
+ }
7663
+ .sg-wrapper-less .metro .sidebar.light li ul {
7664
+ background-color: #ffffff;
7665
+ border: 1px transparent solid;
7666
+ }
7667
+ .sg-wrapper-less .metro .sidebar.light li .divider {
7668
+ background-color: #eeeeee;
7669
+ }
7670
+ .sg-wrapper-less .metro .sidebar.light li .divider:hover {
7671
+ background-color: #eeeeee;
7672
+ }
7673
+ .sg-wrapper-less .metro .sidebar.light li.disabled a {
7674
+ background-color: #ffffff;
7675
+ cursor: default;
7676
+ color: #999999;
7677
+ }
7678
+ .sg-wrapper-less .metro .sidebar.light li.active a {
7679
+ background-color: #1ba1e2;
7680
+ color: #ffffff;
7681
+ }
7682
+ .sg-wrapper-less .sg-site-url {
7683
+ width: 100%;
7684
+ height: 100%;
7685
+ background-color: transparent !important;
7686
+ }
7687
+ .sg-wrapper-less .sg-footer {
7688
+ text-align: center;
7689
+ border-top: 1px #eaeaea solid;
7690
+ height: 45px;
7691
+ }
7692
+ .sg-wrapper-less .sg-footer .row {
7693
+ margin-left: 0;
7694
+ margin-right: 0;
7695
+ }
7696
+ .sg-wrapper-less .sg-footer .sg-version {
7697
+ position: absolute;
7698
+ right: 5px;
7699
+ }
7700
+ .sg-wrapper-less .sg-checkbox .checkbox,
7701
+ .sg-wrapper-less .sg-custom-backup .checkbox {
7702
+ padding-top: 2px;
7703
+ min-height: 10px;
7704
+ }
7705
+ .sg-wrapper-less .sg-close,
7706
+ .sg-wrapper-less .sg-custom-backup,
7707
+ .sg-wrapper-less .sg-custom-backup-files,
7708
+ .sg-wrapper-less .sg-custom-backup-tables,
7709
+ .sg-wrapper-less .sg-backup-db-options,
7710
+ .sg-wrapper-less .sg-custom-backup-cloud,
7711
+ .sg-wrapper-less .sg-schedule-settings-closed {
7712
+ display: none;
7713
+ }
7714
+ .sg-wrapper-less .sg-open {
7715
+ display: block;
7716
+ }
7717
+ .sg-wrapper-less .sg-switch-container {
7718
+ margin-top: 7px;
7719
+ }
7720
+ .sg-wrapper-less .sg-schedule-settings-opened {
7721
+ display: block;
7722
+ }
7723
+ .sg-wrapper-less .sg-custom-backup-schedule .checkbox:not:first-child {
7724
+ padding-top: 0 !important;
7725
+ }
7726
+ .sg-wrapper-less .sg-general-settings {
7727
+ display: none;
7728
+ }
7729
+ .sg-wrapper-less .sg-progress {
7730
+ height: 2px;
7731
+ margin: 0;
7732
+ margin-top: 1px;
7733
+ }
7734
+ .sg-wrapper-less #sg-status-tabe-data {
7735
+ padding: 7px;
7736
+ }
7737
+ .sg-wrapper-less .sg-status-icon {
7738
+ display: inline-block;
7739
+ width: 20px;
7740
+ height: 20px;
7741
+ background-image: url('../img/backup-icons.png');
7742
+ background-repeat: no-repeat;
7743
+ background-size: 220px 40px;
7744
+ }
7745
+ @media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min--moz-device-pixel-ratio: 1.5), only screen and (min-resolution: 240dpi) {
7746
+ .sg-wrapper-less .sg-status-icon {
7747
+ background-image: url('../img/backup-icons@2x.png');
7748
+ }
7749
+ }
7750
+ .sg-wrapper-less .sg-status-35 {
7751
+ background-position: -100px -20px;
7752
+ }
7753
+ .sg-wrapper-less .sg-status-35.active {
7754
+ background-position: -100px 0px;
7755
+ }
7756
+ .sg-wrapper-less .sg-status-34 {
7757
+ background-position: -80px -20px;
7758
+ }
7759
+ .sg-wrapper-less .sg-status-34.active {
7760
+ background-position: -80px 0px;
7761
+ }
7762
+ .sg-wrapper-less .sg-status-1 {
7763
+ background-position: -20px -20px;
7764
+ }
7765
+ .sg-wrapper-less .sg-status-1.active {
7766
+ background-position: -20px 0px;
7767
+ }
7768
+ .sg-wrapper-less .sg-status-2 {
7769
+ background-position: 0px -20px;
7770
+ }
7771
+ .sg-wrapper-less .sg-status-2.active {
7772
+ background-position: 0px 0px;
7773
+ }
7774
+ .sg-wrapper-less .sg-status-31 {
7775
+ background-position: -140px -20px;
7776
+ }
7777
+ .sg-wrapper-less .sg-status-31.active {
7778
+ background-position: -140px 0px;
7779
+ }
7780
+ .sg-wrapper-less .sg-status-32 {
7781
+ background-position: -40px -20px;
7782
+ }
7783
+ .sg-wrapper-less .sg-status-32.active {
7784
+ background-position: -40px 0px;
7785
+ }
7786
+ .sg-wrapper-less .sg-status-33 {
7787
+ background-position: -60px -20px;
7788
+ }
7789
+ .sg-wrapper-less .sg-status-33.active {
7790
+ background-position: -60px 0px;
7791
+ }
7792
+ .sg-wrapper-less .sg-status-22 {
7793
+ background-position: -180px -20px;
7794
+ }
7795
+ .sg-wrapper-less .sg-status-22.active {
7796
+ background-position: -180px 0px;
7797
+ }
7798
+ .sg-wrapper-less .sg-status-21 {
7799
+ background-position: -200px -20px;
7800
+ }
7801
+ .sg-wrapper-less .sg-status-21.active {
7802
+ background-position: -200px 0px;
7803
+ }
7804
+ .sg-wrapper-less .sg-helper-block {
7805
+ font-size: 12px;
7806
+ padding-left: 0px;
7807
+ text-align: left;
7808
+ display: block;
7809
+ margin-top: 0;
7810
+ }
7811
+ .sg-wrapper-less .sg-control-label {
7812
+ text-align: left;
7813
+ margin-bottom: 0;
7814
+ margin-top: 11px;
7815
+ }
7816
+ .sg-wrapper-less .sg-upload-label {
7817
+ padding-left: 0px;
7818
+ padding-top: 12px;
7819
+ }
7820
+ .sg-wrapper-less .sg-modal-body {
7821
+ max-height: calc(100vh - 210px);
7822
+ overflow-y: auto;
7823
+ }
7824
+
7825
+ .sg-wrapper-less .sg-justify {
7826
+ text-align: justify;
7827
+ }
7828
+ .sg-wrapper-less #sg-save-cloud-folder {
7829
+ margin-left: 5px;
7830
+ display: none;
7831
+ }
7832
+
7833
+ .sg-wrapper-less .sg-alert-pro {
7834
+ color: white;
7835
+ margin: 20px;
7836
+ text-align: center;
7837
+ }
7838
+
7839
+ .sg-wrapper-less .sg-star {
7840
+ color: gold;
7841
+ font-size: 24px;
7842
+ }
7843
+ .sg-wrapper-less .sg-no-margin-bottom {
7844
+ margin-bottom: 0 !important;
7845
+ }
7846
+ .sg-wrapper-less .sg-no-padding-left {
7847
+ padding-left: 0 !important;
7848
+ }
7849
+ .sg-wrapper-less .sg-btn-grey {
7850
+ background-color: #999;
7851
+ border-color: #999;
7852
+ color: #ffffff;
7853
+ }
7854
+ .sg-wrapper-less .sg-btn-grey:hover {
7855
+ background-color: #777;
7856
+ border-color: #777;
7857
+ }
7858
+
7859
+ .sg-custom-backup-tables .sg-disableText {
7860
+ color: #bbb;
7861
+ font-size: 12px;
7862
+ }
7863
+
7864
+ .sg-backup-db-options .checkbox .sg-backup-db-mode,
7865
+ .sg-restore-files-options .checkbox .sg-restore-files-mode {
7866
+ padding-left: 15px;
7867
+ }
7868
+ .sg-backup-db-options .checkbox .sg-backup-db-mode:first-child,
7869
+ .sg-restore-files-options .checkbox .sg-restore-files-mode:first-child {
7870
+ padding-left: 0px;
7871
+ }
7872
+
7873
+ .sg-backup-db-options .checkbox .sg-backup-db-mode input,
7874
+ .sg-restore-files-options .checkbox .sg-restore-files-mode input {
7875
+ margin: 0px;
7876
+ }
7877
+
7878
+ .sg-restore-files-options {
7879
+ display: none;
7880
+ }
7881
+
7882
+ .sg-custom-backup-schedule .col-md-8 {
7883
+ width: 100%;
7884
+ margin-left: 0px;
7885
+ }
7886
+
7887
+ .sg-file-selective-restore {
7888
+ display: none;
7889
+ }
7890
+ .form-group-google,
7891
+ .form-group-custom {
7892
+ display: none;
7893
+ }
public/css/bgstyle.wordpress.css ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .sg-wrapper-less{
2
+ width: calc(100% - 20px) !important;
3
+ margin-top: 20px !important;
4
+ }
5
+ .metro .sidebar > ul li{
6
+ margin-bottom: 0 !important;
7
+ }
8
+
9
+ #sg-modal-manual-backup-header {
10
+ padding-right: 15px;
11
+ padding-left: 15px;
12
+ }
13
+
14
+ /*first interaction popup*/
15
+
16
+ .bg-verify-user-info-error-message {
17
+ color: #F00;
18
+ display: none;
19
+ }
20
+
21
+ .bg-verify-user-info-container{
22
+ position:fixed;
23
+ top:0;
24
+ left:0;
25
+ right:0;
26
+ bottom:0;
27
+ /*display:none;*/
28
+ z-index: 100;
29
+ }
30
+ .bg-verify-user-info-overlay{
31
+ position:fixed;
32
+ top:0;
33
+ left:0;
34
+ right:0;
35
+ bottom:0;
36
+ background:rgba(0,0,0,0.5);
37
+ /*display:none;*/
38
+ }
39
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl{
40
+ display:table;
41
+ width:100%;
42
+ height:100%;
43
+ }
44
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl .bg-verify-user-info-popup-cel{
45
+ display:table-cell;
46
+ vertical-align:middle;
47
+ }
48
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl .bg-verify-user-info-popup-cel .bg-verify-user-info-popup-inner-content{
49
+ padding:0 40px;
50
+ }
51
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl .bg-verify-user-info-popup-cel .bg-verify-user-info-popup-content{
52
+ background:#fff;
53
+ max-width:700px;
54
+ margin:0 auto;
55
+ padding:30px;
56
+ position: relative;
57
+ text-align:center;
58
+ }
59
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl .bg-verify-user-info-popup-cel .bg-verify-user-info-popup-content .bg-verify-user-info-control-buttons-container{
60
+ margin-top:30px;
61
+ }
62
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl .bg-verify-user-info-popup-cel .bg-verify-user-info-popup-content a.bg-verify-user-info-cancel {
63
+ position: absolute;
64
+ right: 15px;
65
+ top: 15px;
66
+ text-decoration: none;
67
+ /* font-size: 24px; */
68
+ /* color: #016cb0; */
69
+ /* border: 2px solid #016cb0;
70
+ border-radius: 50%;
71
+ width: 28px;*/
72
+ /* height: 24px; */
73
+ /* line-height: 18px; */
74
+ /* text-align: center; */
75
+ /* font-weight: 600; */
76
+ transition: all 0.5s ease;
77
+ -webkit-transition: all 0.5s ease;
78
+ }
79
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl .bg-verify-user-info-popup-cel .bg-verify-user-info-popup-content .bg-verify-user-info-cancel img {
80
+
81
+ border: 2px solid grey;
82
+ border-radius: 50%;
83
+ width: 28px;
84
+ }
85
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl .bg-verify-user-info-popup-cel .bg-verify-user-info-popup-content a.bg-verify-user-info-cancel:hover{
86
+ /*color:#fff;
87
+ background:#016cb0;*/
88
+ opacity:0.8;
89
+ transition:all 0.5s ease;
90
+ -webkit-transition: all 0.5s ease;
91
+ }
92
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl .bg-verify-user-info-popup-cel .bg-verify-user-info-popup-content .bg-verify-user-info-desc {
93
+ /* text-transform: uppercase; */
94
+ font-size: 16px;
95
+ max-width: 450px;
96
+ margin: 0 auto;
97
+ margin-bottom: 30px;
98
+ color: #808080;
99
+ }
100
+ .bg-verify-user-info-container .bg-verify-user-info-popup-tbl .bg-verify-user-info-popup-cel .bg-verify-user-info-popup-content h3 {
101
+ font-size: 36px;
102
+ font-family:'Raleway';
103
+ font-weight:700;
104
+ color:#000;
105
+ margin-bottom: 25px;
106
+ }
107
+ .bg-verify-user-info-container .bg-verify-user-info-form-group{
108
+ overflow:auto;
109
+ margin-bottom: 15px;
110
+ }
111
+ .bg-verify-user-info-container .bg-verify-user-info-form-group .bg-verify-user-info-form-twocol{
112
+ width:50%;
113
+ float:left;
114
+ box-sizing:border-box;
115
+ padding:0 5px;
116
+ }
117
+ .bg-verify-user-info-container .bg-verify-user-info-form-group .bg-verify-user-info-form-onecol{
118
+ box-sizing: border-box;
119
+ padding: 0 5px;
120
+ }
121
+ .bg-verify-user-info-container .bg-verify-user-info-form-group input {
122
+ width: 100%;
123
+ border: 1px solid #ddd;
124
+ box-shadow: none !important;
125
+ padding: 10px;
126
+ }
127
+ .bg-verify-user-info-container .bg-verify-user-info-form-group select {
128
+ width: 100%;
129
+ border: 1px solid #ddd;
130
+ box-shadow: none !important;
131
+ height: 43px;
132
+ padding-left: 10px;
133
+ }
134
+ .bg-verify-user-info-container .bg-privacy-links-container {
135
+ border-top:1px solid #ddd;
136
+ padding-top:20px;
137
+ margin-top: 40px;
138
+ }
139
+ .bg-verify-user-info-container .bg-privacy-links-container a{
140
+ font-size:16px;
141
+ text-decoration:none;
142
+ margin: 0 15px;
143
+ color:#016cb0;
144
+ }
145
+ .bg-verify-user-info-container .bg-verify-user-info-control-buttons-container .bg-verify-user-info-verify-email {
146
+ background: #016cb0 !important;
147
+ width:165px;
148
+ height:50px;
149
+ padding: 0;
150
+ border: none;
151
+ font-size: 16px;
152
+ text-transform: uppercase;
153
+ margin-right: 15px;
154
+ font-weight: 700;
155
+ }
156
+ .bg-verify-user-info-container .bg-verify-user-info-control-buttons-container .bg-verify-user-info-verify-email .btn-text {
157
+ display: inline-block;
158
+ padding: 0 15px;
159
+ margin-right: 0;
160
+ vertical-align: middle;
161
+ float: left;
162
+ line-height: inherit;
163
+ height: 50px;
164
+ padding-top: 12px;
165
+ box-sizing: border-box;
166
+ width: 109px;
167
+ }
168
+ .bg-verify-user-info-container .bg-verify-user-info-control-buttons-container .bg-verify-user-info-verify-email .btn-text-icon {
169
+ display: inline-block;
170
+ width: 56px;
171
+ text-align: center;
172
+ vertical-align: middle;
173
+ float: left;
174
+ line-height: inherit;
175
+ border-radius: 0 3px 3px 0;
176
+ position: relative;
177
+ overflow: hidden;
178
+ background: #004270;
179
+ height: 50px;
180
+ padding-top: 14px;
181
+ box-sizing: border-box;
182
+ }
183
+ .bg-verify-user-info-container .bg-verify-user-info-control-buttons-container .bg-verify-user-info-verify-email:hover .btn-text-icon img{
184
+ -webkit-animation-name: moving;
185
+ -webkit-animation-duration: 0.8s;
186
+ }
187
+ .bg-verify-user-info-container .bg-verify-user-info-control-buttons-container .bg-verify-user-info-verify-email:hover .btn-text-icon {
188
+ background: #012842;
189
+ }
190
+ .bg-verify-user-info-container .bg-verify-user-info-control-buttons-container .bg-verify-user-info-cancel{
191
+ border:2px solid #016cb0;
192
+ font-size: 16px;
193
+ text-transform: uppercase;
194
+ height: inherit;
195
+ background:#fff;
196
+ width:165px;
197
+ height:50px;
198
+ margin-left: 15px;
199
+ font-weight: 700;
200
+ }
201
+ .bg-verify-user-info-container .bg-verify-user-info-control-buttons-container .bg-verify-user-info-cancel:hover{
202
+ border:2px solid #016cb0;
203
+ background:#fff;
204
+ }
public/css/bootstrap-switch.min.css ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ========================================================================
2
+ * bootstrap-switch - v3.3.2
3
+ * http://www.bootstrap-switch.org
4
+ * ========================================================================
5
+ * Copyright 2012-2013 Mattia Larentis
6
+ *
7
+ * ========================================================================
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ * ========================================================================
20
+ */
21
+
22
+ .bootstrap-switch{display:inline-block;direction:ltr;cursor:pointer;border-radius:4px;border:1px solid;border-color:#ccc;position:relative;text-align:left;overflow:hidden;line-height:8px;z-index:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle;-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.bootstrap-switch .bootstrap-switch-container{display:inline-block;top:0;border-radius:4px;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}.bootstrap-switch .bootstrap-switch-handle-on,.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-label{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;cursor:pointer;display:inline-block !important;padding:6px 12px;font-size:14px;line-height:20px}.bootstrap-switch .bootstrap-switch-handle-on,.bootstrap-switch .bootstrap-switch-handle-off{text-align:center;z-index:1}.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary,.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary{color:#fff;background:#428bca}.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info,.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info{color:#fff;background:#5bc0de}.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success,.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success{color:#fff;background:#5cb85c}.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning,.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning{background:#f0ad4e;color:#fff}.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger,.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger{color:#fff;background:#d9534f}.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default,.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default{color:#000;background:#eee}.bootstrap-switch .bootstrap-switch-label{text-align:center;margin-top:-1px;margin-bottom:-1px;z-index:100;color:#333;background:#fff}.bootstrap-switch .bootstrap-switch-handle-on{border-bottom-left-radius:3px;border-top-left-radius:3px}.bootstrap-switch .bootstrap-switch-handle-off{border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch input[type='radio'],.bootstrap-switch input[type='checkbox']{position:absolute !important;top:0;left:0;opacity:0;filter:alpha(opacity=0);z-index:-1}.bootstrap-switch input[type='radio'].form-control,.bootstrap-switch input[type='checkbox'].form-control{height:auto}.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-label{padding:1px 5px;font-size:12px;line-height:1.5}.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-label{padding:5px 10px;font-size:12px;line-height:1.5}.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-label{padding:6px 16px;font-size:18px;line-height:1.33}.bootstrap-switch.bootstrap-switch-disabled,.bootstrap-switch.bootstrap-switch-readonly,.bootstrap-switch.bootstrap-switch-indeterminate{cursor:default !important}.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-label{opacity:.5;filter:alpha(opacity=50);cursor:default !important}.bootstrap-switch.bootstrap-switch-animate .bootstrap-switch-container{-webkit-transition:margin-left .5s;transition:margin-left .5s}.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-on{border-bottom-left-radius:0;border-top-left-radius:0;border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-off{border-bottom-right-radius:0;border-top-right-radius:0;border-bottom-left-radius:3px;border-top-left-radius:3px}.bootstrap-switch.bootstrap-switch-focused{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.bootstrap-switch.bootstrap-switch-on .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-off .bootstrap-switch-label{border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-on .bootstrap-switch-label{border-bottom-left-radius:3px;border-top-left-radius:3px}
public/css/bootstrap.css ADDED
@@ -0,0 +1,6760 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
3
+ * Copyright 2011-2015 Twitter, Inc.
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5
+ */
6
+ /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
7
+ html {
8
+ font-family: sans-serif;
9
+ -webkit-text-size-adjust: 100%;
10
+ -ms-text-size-adjust: 100%;
11
+ }
12
+ body {
13
+ margin: 0;
14
+ }
15
+ article,
16
+ aside,
17
+ details,
18
+ figcaption,
19
+ figure,
20
+ footer,
21
+ header,
22
+ hgroup,
23
+ main,
24
+ menu,
25
+ nav,
26
+ section,
27
+ summary {
28
+ display: block;
29
+ }
30
+ audio,
31
+ canvas,
32
+ progress,
33
+ video {
34
+ display: inline-block;
35
+ vertical-align: baseline;
36
+ }
37
+ audio:not([controls]) {
38
+ display: none;
39
+ height: 0;
40
+ }
41
+ [hidden],
42
+ template {
43
+ display: none;
44
+ }
45
+ a {
46
+ background-color: transparent;
47
+ }
48
+ a:active,
49
+ a:hover {
50
+ outline: 0;
51
+ }
52
+ abbr[title] {
53
+ border-bottom: 1px dotted;
54
+ }
55
+ b,
56
+ strong {
57
+ font-weight: bold;
58
+ }
59
+ dfn {
60
+ font-style: italic;
61
+ }
62
+ h1 {
63
+ margin: .67em 0;
64
+ font-size: 2em;
65
+ }
66
+ mark {
67
+ color: #000;
68
+ background: #ff0;
69
+ }
70
+ small {
71
+ font-size: 80%;
72
+ }
73
+ sub,
74
+ sup {
75
+ position: relative;
76
+ font-size: 75%;
77
+ line-height: 0;
78
+ vertical-align: baseline;
79
+ }
80
+ sup {
81
+ top: -.5em;
82
+ }
83
+ sub {
84
+ bottom: -.25em;
85
+ }
86
+ img {
87
+ border: 0;
88
+ }
89
+ svg:not(:root) {
90
+ overflow: hidden;
91
+ }
92
+ figure {
93
+ margin: 1em 40px;
94
+ }
95
+ hr {
96
+ height: 0;
97
+ -webkit-box-sizing: content-box;
98
+ -moz-box-sizing: content-box;
99
+ box-sizing: content-box;
100
+ }
101
+ pre {
102
+ overflow: auto;
103
+ }
104
+ code,
105
+ kbd,
106
+ pre,
107
+ samp {
108
+ font-family: monospace, monospace;
109
+ font-size: 1em;
110
+ }
111
+ button,
112
+ input,
113
+ optgroup,
114
+ select,
115
+ textarea {
116
+ margin: 0;
117
+ font: inherit;
118
+ color: inherit;
119
+ }
120
+ button {
121
+ overflow: visible;
122
+ }
123
+ button,
124
+ select {
125
+ text-transform: none;
126
+ }
127
+ button,
128
+ html input[type="button"],
129
+ input[type="reset"],
130
+ input[type="submit"] {
131
+ -webkit-appearance: button;
132
+ cursor: pointer;
133
+ }
134
+ button[disabled],
135
+ html input[disabled] {
136
+ cursor: default;
137
+ }
138
+ button::-moz-focus-inner,
139
+ input::-moz-focus-inner {
140
+ padding: 0;
141
+ border: 0;
142
+ }
143
+ input {
144
+ line-height: normal;
145
+ }
146
+ input[type="checkbox"],
147
+ input[type="radio"] {
148
+ -webkit-box-sizing: border-box;
149
+ -moz-box-sizing: border-box;
150
+ box-sizing: border-box;
151
+ padding: 0;
152
+ }
153
+ input[type="number"]::-webkit-inner-spin-button,
154
+ input[type="number"]::-webkit-outer-spin-button {
155
+ height: auto;
156
+ }
157
+ input[type="search"] {
158
+ -webkit-box-sizing: content-box;
159
+ -moz-box-sizing: content-box;
160
+ box-sizing: content-box;
161
+ -webkit-appearance: textfield;
162
+ }
163
+ input[type="search"]::-webkit-search-cancel-button,
164
+ input[type="search"]::-webkit-search-decoration {
165
+ -webkit-appearance: none;
166
+ }
167
+ fieldset {
168
+ padding: .35em .625em .75em;
169
+ margin: 0 2px;
170
+ border: 1px solid #c0c0c0;
171
+ }
172
+ legend {
173
+ padding: 0;
174
+ border: 0;
175
+ }
176
+ textarea {
177
+ overflow: auto;
178
+ }
179
+ optgroup {
180
+ font-weight: bold;
181
+ }
182
+ table {
183
+ border-spacing: 0;
184
+ border-collapse: collapse;
185
+ }
186
+ td,
187
+ th {
188
+ padding: 0;
189
+ }
190
+ /*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
191
+ @media print {
192
+ *,
193
+ *:before,
194
+ *:after {
195
+ color: #000 !important;
196
+ text-shadow: none !important;
197
+ background: transparent !important;
198
+ -webkit-box-shadow: none !important;
199
+ box-shadow: none !important;
200
+ }
201
+ a,
202
+ a:visited {
203
+ text-decoration: underline;
204
+ }
205
+ a[href]:after {
206
+ content: " (" attr(href) ")";
207
+ }
208
+ abbr[title]:after {
209
+ content: " (" attr(title) ")";
210
+ }
211
+ a[href^="#"]:after,
212
+ a[href^="javascript:"]:after {
213
+ content: "";
214
+ }
215
+ pre,
216
+ blockquote {
217
+ border: 1px solid #999;
218
+
219
+ page-break-inside: avoid;
220
+ }
221
+ thead {
222
+ display: table-header-group;
223
+ }
224
+ tr,
225
+ img {
226
+ page-break-inside: avoid;
227
+ }
228
+ img {
229
+ max-width: 100% !important;
230
+ }
231
+ p,
232
+ h2,
233
+ h3 {
234
+ orphans: 3;
235
+ widows: 3;
236
+ }
237
+ h2,
238
+ h3 {
239
+ page-break-after: avoid;
240
+ }
241
+ .navbar {
242
+ display: none;
243
+ }
244
+ .btn > .caret,
245
+ .dropup > .btn > .caret {
246
+ border-top-color: #000 !important;
247
+ }
248
+ .label {
249
+ border: 1px solid #000;
250
+ }
251
+ .table {
252
+ border-collapse: collapse !important;
253
+ }
254
+ .table td,
255
+ .table th {
256
+ background-color: #fff !important;
257
+ }
258
+ .table-bordered th,
259
+ .table-bordered td {
260
+ border: 1px solid #ddd !important;
261
+ }
262
+ }
263
+ @font-face {
264
+ font-family: 'Glyphicons Halflings';
265
+
266
+ src: url('../fonts/glyphicons-halflings-regular.eot');
267
+ src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
268
+ }
269
+ .glyphicon {
270
+ position: relative;
271
+ top: 1px;
272
+ display: inline-block;
273
+ font-family: 'Glyphicons Halflings';
274
+ font-style: normal;
275
+ font-weight: normal;
276
+ line-height: 1;
277
+
278
+ -webkit-font-smoothing: antialiased;
279
+ -moz-osx-font-smoothing: grayscale;
280
+ }
281
+ .glyphicon-asterisk:before {
282
+ content: "\002a";
283
+ }
284
+ .glyphicon-plus:before {
285
+ content: "\002b";
286
+ }
287
+ .glyphicon-euro:before,
288
+ .glyphicon-eur:before {
289
+ content: "\20ac";
290
+ }
291
+ .glyphicon-minus:before {
292
+ content: "\2212";
293
+ }
294
+ .glyphicon-cloud:before {
295
+ content: "\2601";
296
+ }
297
+ .glyphicon-envelope:before {
298
+ content: "\2709";
299
+ }
300
+ .glyphicon-pencil:before {
301
+ content: "\270f";
302
+ }
303
+ .glyphicon-glass:before {
304
+ content: "\e001";
305
+ }
306
+ .glyphicon-music:before {
307
+ content: "\e002";
308
+ }
309
+ .glyphicon-search:before {
310
+ content: "\e003";
311
+ }
312
+ .glyphicon-heart:before {
313
+ content: "\e005";
314
+ }
315
+ .glyphicon-star:before {
316
+ content: "\e006";
317
+ }
318
+ .glyphicon-star-empty:before {
319
+ content: "\e007";
320
+ }
321
+ .glyphicon-user:before {
322
+ content: "\e008";
323
+ }
324
+ .glyphicon-film:before {
325
+ content: "\e009";
326
+ }
327
+ .glyphicon-th-large:before {
328
+ content: "\e010";
329
+ }
330
+ .glyphicon-th:before {
331
+ content: "\e011";
332
+ }
333
+ .glyphicon-th-list:before {
334
+ content: "\e012";
335
+ }
336
+ .glyphicon-ok:before {
337
+ content: "\e013";
338
+ }
339
+ .glyphicon-remove:before {
340
+ content: "\e014";
341
+ }
342
+ .glyphicon-zoom-in:before {
343
+ content: "\e015";
344
+ }
345
+ .glyphicon-zoom-out:before {
346
+ content: "\e016";
347
+ }
348
+ .glyphicon-off:before {
349
+ content: "\e017";
350
+ }
351
+ .glyphicon-signal:before {
352
+ content: "\e018";
353
+ }
354
+ .glyphicon-cog:before {
355
+ content: "\e019";
356
+ }
357
+ .glyphicon-trash:before {
358
+ content: "\e020";
359
+ }
360
+ .glyphicon-home:before {
361
+ content: "\e021";
362
+ }
363
+ .glyphicon-file:before {
364
+ content: "\e022";
365
+ }
366
+ .glyphicon-time:before {
367
+ content: "\e023";
368
+ }
369
+ .glyphicon-road:before {
370
+ content: "\e024";
371
+ }
372
+ .glyphicon-download-alt:before {
373
+ content: "\e025";
374
+ }
375
+ .glyphicon-download:before {
376
+ content: "\e026";
377
+ }
378
+ .glyphicon-upload:before {
379
+ content: "\e027";
380
+ }
381
+ .glyphicon-inbox:before {
382
+ content: "\e028";
383
+ }
384
+ .glyphicon-play-circle:before {
385
+ content: "\e029";
386
+ }
387
+ .glyphicon-repeat:before {
388
+ content: "\e030";
389
+ }
390
+ .glyphicon-refresh:before {
391
+ content: "\e031";
392
+ }
393
+ .glyphicon-list-alt:before {
394
+ content: "\e032";
395
+ }
396
+ .glyphicon-lock:before {
397
+ content: "\e033";
398
+ }
399
+ .glyphicon-flag:before {
400
+ content: "\e034";
401
+ }
402
+ .glyphicon-headphones:before {
403
+ content: "\e035";
404
+ }
405
+ .glyphicon-volume-off:before {
406
+ content: "\e036";
407
+ }
408
+ .glyphicon-volume-down:before {
409
+ content: "\e037";
410
+ }
411
+ .glyphicon-volume-up:before {
412
+ content: "\e038";
413
+ }
414
+ .glyphicon-qrcode:before {
415
+ content: "\e039";
416
+ }
417
+ .glyphicon-barcode:before {
418
+ content: "\e040";
419
+ }
420
+ .glyphicon-tag:before {
421
+ content: "\e041";
422
+ }
423
+ .glyphicon-tags:before {
424
+ content: "\e042";
425
+ }
426
+ .glyphicon-book:before {
427
+ content: "\e043";
428
+ }
429
+ .glyphicon-bookmark:before {
430
+ content: "\e044";
431
+ }
432
+ .glyphicon-print:before {
433
+ content: "\e045";
434
+ }
435
+ .glyphicon-camera:before {
436
+ content: "\e046";
437
+ }
438
+ .glyphicon-font:before {
439
+ content: "\e047";
440
+ }
441
+ .glyphicon-bold:before {
442
+ content: "\e048";
443
+ }
444
+ .glyphicon-italic:before {
445
+ content: "\e049";
446
+ }
447
+ .glyphicon-text-height:before {
448
+ content: "\e050";
449
+ }
450
+ .glyphicon-text-width:before {
451
+ content: "\e051";
452
+ }
453
+ .glyphicon-align-left:before {
454
+ content: "\e052";
455
+ }
456
+ .glyphicon-align-center:before {
457
+ content: "\e053";
458
+ }
459
+ .glyphicon-align-right:before {
460
+ content: "\e054";
461
+ }
462
+ .glyphicon-align-justify:before {
463
+ content: "\e055";
464
+ }
465
+ .glyphicon-list:before {
466
+ content: "\e056";
467
+ }
468
+ .glyphicon-indent-left:before {
469
+ content: "\e057";
470
+ }
471
+ .glyphicon-indent-right:before {
472
+ content: "\e058";
473
+ }
474
+ .glyphicon-facetime-video:before {
475
+ content: "\e059";
476
+ }
477
+ .glyphicon-picture:before {
478
+ content: "\e060";
479
+ }
480
+ .glyphicon-map-marker:before {
481
+ content: "\e062";
482
+ }
483
+ .glyphicon-adjust:before {
484
+ content: "\e063";
485
+ }
486
+ .glyphicon-tint:before {
487
+ content: "\e064";
488
+ }
489
+ .glyphicon-edit:before {
490
+ content: "\e065";
491
+ }
492
+ .glyphicon-share:before {
493
+ content: "\e066";
494
+ }
495
+ .glyphicon-check:before {
496
+ content: "\e067";
497
+ }
498
+ .glyphicon-move:before {
499
+ content: "\e068";
500
+ }
501
+ .glyphicon-step-backward:before {
502
+ content: "\e069";
503
+ }
504
+ .glyphicon-fast-backward:before {
505
+ content: "\e070";
506
+ }
507
+ .glyphicon-backward:before {
508
+ content: "\e071";
509
+ }
510
+ .glyphicon-play:before {
511
+ content: "\e072";
512
+ }
513
+ .glyphicon-pause:before {
514
+ content: "\e073";
515
+ }
516
+ .glyphicon-stop:before {
517
+ content: "\e074";
518
+ }
519
+ .glyphicon-forward:before {
520
+ content: "\e075";
521
+ }
522
+ .glyphicon-fast-forward:before {
523
+ content: "\e076";
524
+ }
525
+ .glyphicon-step-forward:before {
526
+ content: "\e077";
527
+ }
528
+ .glyphicon-eject:before {
529
+ content: "\e078";
530
+ }
531
+ .glyphicon-chevron-left:before {
532
+ content: "\e079";
533
+ }
534
+ .glyphicon-chevron-right:before {
535
+ content: "\e080";
536
+ }
537
+ .glyphicon-plus-sign:before {
538
+ content: "\e081";
539
+ }
540
+ .glyphicon-minus-sign:before {
541
+ content: "\e082";
542
+ }
543
+ .glyphicon-remove-sign:before {
544
+ content: "\e083";
545
+ }
546
+ .glyphicon-ok-sign:before {
547
+ content: "\e084";
548
+ }
549
+ .glyphicon-question-sign:before {
550
+ content: "\e085";
551
+ }
552
+ .glyphicon-info-sign:before {
553
+ content: "\e086";
554
+ }
555
+ .glyphicon-screenshot:before {
556
+ content: "\e087";
557
+ }
558
+ .glyphicon-remove-circle:before {
559
+ content: "\e088";
560
+ }
561
+ .glyphicon-ok-circle:before {
562
+ content: "\e089";
563
+ }
564
+ .glyphicon-ban-circle:before {
565
+ content: "\e090";
566
+ }
567
+ .glyphicon-arrow-left:before {
568
+ content: "\e091";
569
+ }
570
+ .glyphicon-arrow-right:before {
571
+ content: "\e092";
572
+ }
573
+ .glyphicon-arrow-up:before {
574
+ content: "\e093";
575
+ }
576
+ .glyphicon-arrow-down:before {
577
+ content: "\e094";
578
+ }
579
+ .glyphicon-share-alt:before {
580
+ content: "\e095";
581
+ }
582
+ .glyphicon-resize-full:before {
583
+ content: "\e096";
584
+ }
585
+ .glyphicon-resize-small:before {
586
+ content: "\e097";
587
+ }
588
+ .glyphicon-exclamation-sign:before {
589
+ content: "\e101";
590
+ }
591
+ .glyphicon-gift:before {
592
+ content: "\e102";
593
+ }
594
+ .glyphicon-leaf:before {
595
+ content: "\e103";
596
+ }
597
+ .glyphicon-fire:before {
598
+ content: "\e104";
599
+ }
600
+ .glyphicon-eye-open:before {
601
+ content: "\e105";
602
+ }
603
+ .glyphicon-eye-close:before {
604
+ content: "\e106";
605
+ }
606
+ .glyphicon-warning-sign:before {
607
+ content: "\e107";
608
+ }
609
+ .glyphicon-plane:before {
610
+ content: "\e108";
611
+ }
612
+ .glyphicon-calendar:before {
613
+ content: "\e109";
614
+ }
615
+ .glyphicon-random:before {
616
+ content: "\e110";
617
+ }
618
+ .glyphicon-comment:before {
619
+ content: "\e111";
620
+ }
621
+ .glyphicon-magnet:before {
622
+ content: "\e112";
623
+ }
624
+ .glyphicon-chevron-up:before {
625
+ content: "\e113";
626
+ }
627
+ .glyphicon-chevron-down:before {
628
+ content: "\e114";
629
+ }
630
+ .glyphicon-retweet:before {
631
+ content: "\e115";
632
+ }
633
+ .glyphicon-shopping-cart:before {
634
+ content: "\e116";
635
+ }
636
+ .glyphicon-folder-close:before {
637
+ content: "\e117";
638
+ }
639
+ .glyphicon-folder-open:before {
640
+ content: "\e118";
641
+ }
642
+ .glyphicon-resize-vertical:before {
643
+ content: "\e119";
644
+ }
645
+ .glyphicon-resize-horizontal:before {
646
+ content: "\e120";
647
+ }
648
+ .glyphicon-hdd:before {
649
+ content: "\e121";
650
+ }
651
+ .glyphicon-bullhorn:before {
652
+ content: "\e122";
653
+ }
654
+ .glyphicon-bell:before {
655
+ content: "\e123";
656
+ }
657
+ .glyphicon-certificate:before {
658
+ content: "\e124";
659
+ }
660
+ .glyphicon-thumbs-up:before {
661
+ content: "\e125";
662
+ }
663
+ .glyphicon-thumbs-down:before {
664
+ content: "\e126";
665
+ }
666
+ .glyphicon-hand-right:before {
667
+ content: "\e127";
668
+ }
669
+ .glyphicon-hand-left:before {
670
+ content: "\e128";
671
+ }
672
+ .glyphicon-hand-up:before {
673
+ content: "\e129";
674
+ }
675
+ .glyphicon-hand-down:before {
676
+ content: "\e130";
677
+ }
678
+ .glyphicon-circle-arrow-right:before {
679
+ content: "\e131";
680
+ }
681
+ .glyphicon-circle-arrow-left:before {
682
+ content: "\e132";
683
+ }
684
+ .glyphicon-circle-arrow-up:before {
685
+ content: "\e133";
686
+ }
687
+ .glyphicon-circle-arrow-down:before {
688
+ content: "\e134";
689
+ }
690
+ .glyphicon-globe:before {
691
+ content: "\e135";
692
+ }
693
+ .glyphicon-wrench:before {
694
+ content: "\e136";
695
+ }
696
+ .glyphicon-tasks:before {
697
+ content: "\e137";
698
+ }
699
+ .glyphicon-filter:before {
700
+ content: "\e138";
701
+ }
702
+ .glyphicon-briefcase:before {
703
+ content: "\e139";
704
+ }
705
+ .glyphicon-fullscreen:before {
706
+ content: "\e140";
707
+ }
708
+ .glyphicon-dashboard:before {
709
+ content: "\e141";
710
+ }
711
+ .glyphicon-paperclip:before {
712
+ content: "\e142";
713
+ }
714
+ .glyphicon-heart-empty:before {
715
+ content: "\e143";
716
+ }
717
+ .glyphicon-link:before {
718
+ content: "\e144";
719
+ }
720
+ .glyphicon-phone:before {
721
+ content: "\e145";
722
+ }
723
+ .glyphicon-pushpin:before {
724
+ content: "\e146";
725
+ }
726
+ .glyphicon-usd:before {
727
+ content: "\e148";
728
+ }
729
+ .glyphicon-gbp:before {
730
+ content: "\e149";
731
+ }
732
+ .glyphicon-sort:before {
733
+ content: "\e150";
734
+ }
735
+ .glyphicon-sort-by-alphabet:before {
736
+ content: "\e151";
737
+ }
738
+ .glyphicon-sort-by-alphabet-alt:before {
739
+ content: "\e152";
740
+ }
741
+ .glyphicon-sort-by-order:before {
742
+ content: "\e153";
743
+ }
744
+ .glyphicon-sort-by-order-alt:before {
745
+ content: "\e154";
746
+ }
747
+ .glyphicon-sort-by-attributes:before {
748
+ content: "\e155";
749
+ }
750
+ .glyphicon-sort-by-attributes-alt:before {
751
+ content: "\e156";
752
+ }
753
+ .glyphicon-unchecked:before {
754
+ content: "\e157";
755
+ }
756
+ .glyphicon-expand:before {
757
+ content: "\e158";
758
+ }
759
+ .glyphicon-collapse-down:before {
760
+ content: "\e159";
761
+ }
762
+ .glyphicon-collapse-up:before {
763
+ content: "\e160";
764
+ }
765
+ .glyphicon-log-in:before {
766
+ content: "\e161";
767
+ }
768
+ .glyphicon-flash:before {
769
+ content: "\e162";
770
+ }
771
+ .glyphicon-log-out:before {
772
+ content: "\e163";
773
+ }
774
+ .glyphicon-new-window:before {
775
+ content: "\e164";
776
+ }
777
+ .glyphicon-record:before {
778
+ content: "\e165";
779
+ }
780
+ .glyphicon-save:before {
781
+ content: "\e166";
782
+ }
783
+ .glyphicon-open:before {
784
+ content: "\e167";
785
+ }
786
+ .glyphicon-saved:before {
787
+ content: "\e168";
788
+ }
789
+ .glyphicon-import:before {
790
+ content: "\e169";
791
+ }
792
+ .glyphicon-export:before {
793
+ content: "\e170";
794
+ }
795
+ .glyphicon-send:before {
796
+ content: "\e171";
797
+ }
798
+ .glyphicon-floppy-disk:before {
799
+ content: "\e172";
800
+ }
801
+ .glyphicon-floppy-saved:before {
802
+ content: "\e173";
803
+ }
804
+ .glyphicon-floppy-remove:before {
805
+ content: "\e174";
806
+ }
807
+ .glyphicon-floppy-save:before {
808
+ content: "\e175";
809
+ }
810
+ .glyphicon-floppy-open:before {
811
+ content: "\e176";
812
+ }
813
+ .glyphicon-credit-card:before {
814
+ content: "\e177";
815
+ }
816
+ .glyphicon-transfer:before {
817
+ content: "\e178";
818
+ }
819
+ .glyphicon-cutlery:before {
820
+ content: "\e179";
821
+ }
822
+ .glyphicon-header:before {
823
+ content: "\e180";
824
+ }
825
+ .glyphicon-compressed:before {
826
+ content: "\e181";
827
+ }
828
+ .glyphicon-earphone:before {
829
+ content: "\e182";
830
+ }
831
+ .glyphicon-phone-alt:before {
832
+ content: "\e183";
833
+ }
834
+ .glyphicon-tower:before {
835
+ content: "\e184";
836
+ }
837
+ .glyphicon-stats:before {
838
+ content: "\e185";
839
+ }
840
+ .glyphicon-sd-video:before {
841
+ content: "\e186";
842
+ }
843
+ .glyphicon-hd-video:before {
844
+ content: "\e187";
845
+ }
846
+ .glyphicon-subtitles:before {
847
+ content: "\e188";
848
+ }
849
+ .glyphicon-sound-stereo:before {
850
+ content: "\e189";
851
+ }
852
+ .glyphicon-sound-dolby:before {
853
+ content: "\e190";
854
+ }
855
+ .glyphicon-sound-5-1:before {
856
+ content: "\e191";
857
+ }
858
+ .glyphicon-sound-6-1:before {
859
+ content: "\e192";
860
+ }
861
+ .glyphicon-sound-7-1:before {
862
+ content: "\e193";
863
+ }
864
+ .glyphicon-copyright-mark:before {
865
+ content: "\e194";
866
+ }
867
+ .glyphicon-registration-mark:before {
868
+ content: "\e195";
869
+ }
870
+ .glyphicon-cloud-download:before {
871
+ content: "\e197";
872
+ }
873
+ .glyphicon-cloud-upload:before {
874
+ content: "\e198";
875
+ }
876
+ .glyphicon-tree-conifer:before {
877
+ content: "\e199";
878
+ }
879
+ .glyphicon-tree-deciduous:before {
880
+ content: "\e200";
881
+ }
882
+ .glyphicon-cd:before {
883
+ content: "\e201";
884
+ }
885
+ .glyphicon-save-file:before {
886
+ content: "\e202";
887
+ }
888
+ .glyphicon-open-file:before {
889
+ content: "\e203";
890
+ }
891
+ .glyphicon-level-up:before {
892
+ content: "\e204";
893
+ }
894
+ .glyphicon-copy:before {
895
+ content: "\e205";
896
+ }
897
+ .glyphicon-paste:before {
898
+ content: "\e206";
899
+ }
900
+ .glyphicon-alert:before {
901
+ content: "\e209";
902
+ }
903
+ .glyphicon-equalizer:before {
904
+ content: "\e210";
905
+ }
906
+ .glyphicon-king:before {
907
+ content: "\e211";
908
+ }
909
+ .glyphicon-queen:before {
910
+ content: "\e212";
911
+ }
912
+ .glyphicon-pawn:before {
913
+ content: "\e213";
914
+ }
915
+ .glyphicon-bishop:before {
916
+ content: "\e214";
917
+ }
918
+ .glyphicon-knight:before {
919
+ content: "\e215";
920
+ }
921
+ .glyphicon-baby-formula:before {
922
+ content: "\e216";
923
+ }
924
+ .glyphicon-tent:before {
925
+ content: "\26fa";
926
+ }
927
+ .glyphicon-blackboard:before {
928
+ content: "\e218";
929
+ }
930
+ .glyphicon-bed:before {
931
+ content: "\e219";
932
+ }
933
+ .glyphicon-apple:before {
934
+ content: "\f8ff";
935
+ }
936
+ .glyphicon-erase:before {
937
+ content: "\e221";
938
+ }
939
+ .glyphicon-hourglass:before {
940
+ content: "\231b";
941
+ }
942
+ .glyphicon-lamp:before {
943
+ content: "\e223";
944
+ }
945
+ .glyphicon-duplicate:before {
946
+ content: "\e224";
947
+ }
948
+ .glyphicon-piggy-bank:before {
949
+ content: "\e225";
950
+ }
951
+ .glyphicon-scissors:before {
952
+ content: "\e226";
953
+ }
954
+ .glyphicon-bitcoin:before {
955
+ content: "\e227";
956
+ }
957
+ .glyphicon-btc:before {
958
+ content: "\e227";
959
+ }
960
+ .glyphicon-xbt:before {
961
+ content: "\e227";
962
+ }
963
+ .glyphicon-yen:before {
964
+ content: "\00a5";
965
+ }
966
+ .glyphicon-jpy:before {
967
+ content: "\00a5";
968
+ }
969
+ .glyphicon-ruble:before {
970
+ content: "\20bd";
971
+ }
972
+ .glyphicon-rub:before {
973
+ content: "\20bd";
974
+ }
975
+ .glyphicon-scale:before {
976
+ content: "\e230";
977
+ }
978
+ .glyphicon-ice-lolly:before {
979
+ content: "\e231";
980
+ }
981
+ .glyphicon-ice-lolly-tasted:before {
982
+ content: "\e232";
983
+ }
984
+ .glyphicon-education:before {
985
+ content: "\e233";
986
+ }
987
+ .glyphicon-option-horizontal:before {
988
+ content: "\e234";
989
+ }
990
+ .glyphicon-option-vertical:before {
991
+ content: "\e235";
992
+ }
993
+ .glyphicon-menu-hamburger:before {
994
+ content: "\e236";
995
+ }
996
+ .glyphicon-modal-window:before {
997
+ content: "\e237";
998
+ }
999
+ .glyphicon-oil:before {
1000
+ content: "\e238";
1001
+ }
1002
+ .glyphicon-grain:before {
1003
+ content: "\e239";
1004
+ }
1005
+ .glyphicon-sunglasses:before {
1006
+ content: "\e240";
1007
+ }
1008
+ .glyphicon-text-size:before {
1009
+ content: "\e241";
1010
+ }
1011
+ .glyphicon-text-color:before {
1012
+ content: "\e242";
1013
+ }
1014
+ .glyphicon-text-background:before {
1015
+ content: "\e243";
1016
+ }
1017
+ .glyphicon-object-align-top:before {
1018
+ content: "\e244";
1019
+ }
1020
+ .glyphicon-object-align-bottom:before {
1021
+ content: "\e245";
1022
+ }
1023
+ .glyphicon-object-align-horizontal:before {
1024
+ content: "\e246";
1025
+ }
1026
+ .glyphicon-object-align-left:before {
1027
+ content: "\e247";
1028
+ }
1029
+ .glyphicon-object-align-vertical:before {
1030
+ content: "\e248";
1031
+ }
1032
+ .glyphicon-object-align-right:before {
1033
+ content: "\e249";
1034
+ }
1035
+ .glyphicon-triangle-right:before {
1036
+ content: "\e250";
1037
+ }
1038
+ .glyphicon-triangle-left:before {
1039
+ content: "\e251";
1040
+ }
1041
+ .glyphicon-triangle-bottom:before {
1042
+ content: "\e252";
1043
+ }
1044
+ .glyphicon-triangle-top:before {
1045
+ content: "\e253";
1046
+ }
1047
+ .glyphicon-console:before {
1048
+ content: "\e254";
1049
+ }
1050
+ .glyphicon-superscript:before {
1051
+ content: "\e255";
1052
+ }
1053
+ .glyphicon-subscript:before {
1054
+ content: "\e256";
1055
+ }
1056
+ .glyphicon-menu-left:before {
1057
+ content: "\e257";
1058
+ }
1059
+ .glyphicon-menu-right:before {
1060
+ content: "\e258";
1061
+ }
1062
+ .glyphicon-menu-down:before {
1063
+ content: "\e259";
1064
+ }
1065
+ .glyphicon-menu-up:before {
1066
+ content: "\e260";
1067
+ }
1068
+ * {
1069
+ -webkit-box-sizing: border-box;
1070
+ -moz-box-sizing: border-box;
1071
+ box-sizing: border-box;
1072
+ }
1073
+ *:before,
1074
+ *:after {
1075
+ -webkit-box-sizing: border-box;
1076
+ -moz-box-sizing: border-box;
1077
+ box-sizing: border-box;
1078
+ }
1079
+ html {
1080
+ font-size: 10px;
1081
+
1082
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
1083
+ }
1084
+ body {
1085
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
1086
+ font-size: 14px;
1087
+ line-height: 1.42857143;
1088
+ color: #333;
1089
+ background-color: #fff;
1090
+ }
1091
+ input,
1092
+ button,
1093
+ select,
1094
+ textarea {
1095
+ font-family: inherit;
1096
+ font-size: inherit;
1097
+ line-height: inherit;
1098
+ }
1099
+ a {
1100
+ color: #337ab7;
1101
+ text-decoration: none;
1102
+ }
1103
+ a:hover,
1104
+ a:focus {
1105
+ color: #23527c;
1106
+ text-decoration: underline;
1107
+ }
1108
+ a:focus {
1109
+ outline: thin dotted;
1110
+ outline: 5px auto -webkit-focus-ring-color;
1111
+ outline-offset: -2px;
1112
+ }
1113
+ figure {
1114
+ margin: 0;
1115
+ }
1116
+ img {
1117
+ vertical-align: middle;
1118
+ }
1119
+ .img-responsive,
1120
+ .thumbnail > img,
1121
+ .thumbnail a > img,
1122
+ .carousel-inner > .item > img,
1123
+ .carousel-inner > .item > a > img {
1124
+ display: block;
1125
+ max-width: 100%;
1126
+ height: auto;
1127
+ }
1128
+ .img-rounded {
1129
+ border-radius: 6px;
1130
+ }
1131
+ .img-thumbnail {
1132
+ display: inline-block;
1133
+ max-width: 100%;
1134
+ height: auto;
1135
+ padding: 4px;
1136
+ line-height: 1.42857143;
1137
+ background-color: #fff;
1138
+ border: 1px solid #ddd;
1139
+ border-radius: 4px;
1140
+ -webkit-transition: all .2s ease-in-out;
1141
+ -o-transition: all .2s ease-in-out;
1142
+ transition: all .2s ease-in-out;
1143
+ }
1144
+ .img-circle {
1145
+ border-radius: 50%;
1146
+ }
1147
+ hr {
1148
+ margin-top: 20px;
1149
+ margin-bottom: 20px;
1150
+ border: 0;
1151
+ border-top: 1px solid #eee;
1152
+ }
1153
+ .sr-only {
1154
+ position: absolute;
1155
+ width: 1px;
1156
+ height: 1px;
1157
+ padding: 0;
1158
+ margin: -1px;
1159
+ overflow: hidden;
1160
+ clip: rect(0, 0, 0, 0);
1161
+ border: 0;
1162
+ }
1163
+ .sr-only-focusable:active,
1164
+ .sr-only-focusable:focus {
1165
+ position: static;
1166
+ width: auto;
1167
+ height: auto;
1168
+ margin: 0;
1169
+ overflow: visible;
1170
+ clip: auto;
1171
+ }
1172
+ [role="button"] {
1173
+ cursor: pointer;
1174
+ }
1175
+ h1,
1176
+ h2,
1177
+ h3,
1178
+ h4,
1179
+ h5,
1180
+ h6,
1181
+ .h1,
1182
+ .h2,
1183
+ .h3,
1184
+ .h4,
1185
+ .h5,
1186
+ .h6 {
1187
+ font-family: inherit;
1188
+ font-weight: 500;
1189
+ line-height: 1.1;
1190
+ color: inherit;
1191
+ }
1192
+ h1 small,
1193
+ h2 small,
1194
+ h3 small,
1195
+ h4 small,
1196
+ h5 small,
1197
+ h6 small,
1198
+ .h1 small,
1199
+ .h2 small,
1200
+ .h3 small,
1201
+ .h4 small,
1202
+ .h5 small,
1203
+ .h6 small,
1204
+ h1 .small,
1205
+ h2 .small,
1206
+ h3 .small,
1207
+ h4 .small,
1208
+ h5 .small,
1209
+ h6 .small,
1210
+ .h1 .small,
1211
+ .h2 .small,
1212
+ .h3 .small,
1213
+ .h4 .small,
1214
+ .h5 .small,
1215
+ .h6 .small {
1216
+ font-weight: normal;
1217
+ line-height: 1;
1218
+ color: #777;
1219
+ }
1220
+ h1,
1221
+ .h1,
1222
+ h2,
1223
+ .h2,
1224
+ h3,
1225
+ .h3 {
1226
+ margin-top: 20px;
1227
+ margin-bottom: 10px;
1228
+ }
1229
+ h1 small,
1230
+ .h1 small,
1231
+ h2 small,
1232
+ .h2 small,
1233
+ h3 small,
1234
+ .h3 small,
1235
+ h1 .small,
1236
+ .h1 .small,
1237
+ h2 .small,
1238
+ .h2 .small,
1239
+ h3 .small,
1240
+ .h3 .small {
1241
+ font-size: 65%;
1242
+ }
1243
+ h4,
1244
+ .h4,
1245
+ h5,
1246
+ .h5,
1247
+ h6,
1248
+ .h6 {
1249
+ margin-top: 10px;
1250
+ margin-bottom: 10px;
1251
+ }
1252
+ h4 small,
1253
+ .h4 small,
1254
+ h5 small,
1255
+ .h5 small,
1256
+ h6 small,
1257
+ .h6 small,
1258
+ h4 .small,
1259
+ .h4 .small,
1260
+ h5 .small,
1261
+ .h5 .small,
1262
+ h6 .small,
1263
+ .h6 .small {
1264
+ font-size: 75%;
1265
+ }
1266
+ h1,
1267
+ .h1 {
1268
+ font-size: 36px;
1269
+ }
1270
+ h2,
1271
+ .h2 {
1272
+ font-size: 30px;
1273
+ }
1274
+ h3,
1275
+ .h3 {
1276
+ font-size: 24px;
1277
+ }
1278
+ h4,
1279
+ .h4 {
1280
+ font-size: 18px;
1281
+ }
1282
+ h5,
1283
+ .h5 {
1284
+ font-size: 14px;
1285
+ }
1286
+ h6,
1287
+ .h6 {
1288
+ font-size: 12px;
1289
+ }
1290
+ p {
1291
+ margin: 0 0 10px;
1292
+ }
1293
+ .lead {
1294
+ margin-bottom: 20px;
1295
+ font-size: 16px;
1296
+ font-weight: 300;
1297
+ line-height: 1.4;
1298
+ }
1299
+ @media (min-width: 768px) {
1300
+ .lead {
1301
+ font-size: 21px;
1302
+ }
1303
+ }
1304
+ small,
1305
+ .small {
1306
+ font-size: 85%;
1307
+ }
1308
+ mark,
1309
+ .mark {
1310
+ padding: .2em;
1311
+ background-color: #fcf8e3;
1312
+ }
1313
+ .text-left {
1314
+ text-align: left;
1315
+ }
1316
+ .text-right {
1317
+ text-align: right;
1318
+ }
1319
+ .text-center {
1320
+ text-align: center;
1321
+ }
1322
+ .text-justify {
1323
+ text-align: justify;
1324
+ }
1325
+ .text-nowrap {
1326
+ white-space: nowrap;
1327
+ }
1328
+ .text-lowercase {
1329
+ text-transform: lowercase;
1330
+ }
1331
+ .text-uppercase {
1332
+ text-transform: uppercase;
1333
+ }
1334
+ .text-capitalize {
1335
+ text-transform: capitalize;
1336
+ }
1337
+ .text-muted {
1338
+ color: #777;
1339
+ }
1340
+ .text-primary {
1341
+ color: #337ab7;
1342
+ }
1343
+ a.text-primary:hover,
1344
+ a.text-primary:focus {
1345
+ color: #286090;
1346
+ }
1347
+ .text-success {
1348
+ color: #3c763d;
1349
+ }
1350
+ a.text-success:hover,
1351
+ a.text-success:focus {
1352
+ color: #2b542c;
1353
+ }
1354
+ .text-info {
1355
+ color: #31708f;
1356
+ }
1357
+ a.text-info:hover,
1358
+ a.text-info:focus {
1359
+ color: #245269;
1360
+ }
1361
+ .text-warning {
1362
+ color: #8a6d3b;
1363
+ }
1364
+ a.text-warning:hover,
1365
+ a.text-warning:focus {
1366
+ color: #66512c;
1367
+ }
1368
+ .text-danger {
1369
+ color: #a94442;
1370
+ }
1371
+ a.text-danger:hover,
1372
+ a.text-danger:focus {
1373
+ color: #843534;
1374
+ }
1375
+ .bg-primary {
1376
+ color: #fff;
1377
+ background-color: #337ab7;
1378
+ }
1379
+ a.bg-primary:hover,
1380
+ a.bg-primary:focus {
1381
+ background-color: #286090;
1382
+ }
1383
+ .bg-success {
1384
+ background-color: #dff0d8;
1385
+ }
1386
+ a.bg-success:hover,
1387
+ a.bg-success:focus {
1388
+ background-color: #c1e2b3;
1389
+ }
1390
+ .bg-info {
1391
+ background-color: #d9edf7;
1392
+ }
1393
+ a.bg-info:hover,
1394
+ a.bg-info:focus {
1395
+ background-color: #afd9ee;
1396
+ }
1397
+ .bg-warning {
1398
+ background-color: #fcf8e3;
1399
+ }
1400
+ a.bg-warning:hover,
1401
+ a.bg-warning:focus {
1402
+ background-color: #f7ecb5;
1403
+ }
1404
+ .bg-danger {
1405
+ background-color: #f2dede;
1406
+ }
1407
+ a.bg-danger:hover,
1408
+ a.bg-danger:focus {
1409
+ background-color: #e4b9b9;
1410
+ }
1411
+ .page-header {
1412
+ padding-bottom: 9px;
1413
+ margin: 40px 0 20px;
1414
+ border-bottom: 1px solid #eee;
1415
+ }
1416
+ ul,
1417
+ ol {
1418
+ margin-top: 0;
1419
+ margin-bottom: 10px;
1420
+ }
1421
+ ul ul,
1422
+ ol ul,
1423
+ ul ol,
1424
+ ol ol {
1425
+ margin-bottom: 0;
1426
+ }
1427
+ .list-unstyled {
1428
+ padding-left: 0;
1429
+ list-style: none;
1430
+ }
1431
+ .list-inline {
1432
+ padding-left: 0;
1433
+ margin-left: -5px;
1434
+ list-style: none;
1435
+ }
1436
+ .list-inline > li {
1437
+ display: inline-block;
1438
+ padding-right: 5px;
1439
+ padding-left: 5px;
1440
+ }
1441
+ dl {
1442
+ margin-top: 0;
1443
+ margin-bottom: 20px;
1444
+ }
1445
+ dt,
1446
+ dd {
1447
+ line-height: 1.42857143;
1448
+ }
1449
+ dt {
1450
+ font-weight: bold;
1451
+ }
1452
+ dd {
1453
+ margin-left: 0;
1454
+ }
1455
+ @media (min-width: 768px) {
1456
+ .dl-horizontal dt {
1457
+ float: left;
1458
+ width: 160px;
1459
+ overflow: hidden;
1460
+ clear: left;
1461
+ text-align: right;
1462
+ text-overflow: ellipsis;
1463
+ white-space: nowrap;
1464
+ }
1465
+ .dl-horizontal dd {
1466
+ margin-left: 180px;
1467
+ }
1468
+ }
1469
+ abbr[title],
1470
+ abbr[data-original-title] {
1471
+ cursor: help;
1472
+ border-bottom: 1px dotted #777;
1473
+ }
1474
+ .initialism {
1475
+ font-size: 90%;
1476
+ text-transform: uppercase;
1477
+ }
1478
+ blockquote {
1479
+ padding: 10px 20px;
1480
+ margin: 0 0 20px;
1481
+ font-size: 17.5px;
1482
+ border-left: 5px solid #eee;
1483
+ }
1484
+ blockquote p:last-child,
1485
+ blockquote ul:last-child,
1486
+ blockquote ol:last-child {
1487
+ margin-bottom: 0;
1488
+ }
1489
+ blockquote footer,
1490
+ blockquote small,
1491
+ blockquote .small {
1492
+ display: block;
1493
+ font-size: 80%;
1494
+ line-height: 1.42857143;
1495
+ color: #777;
1496
+ }
1497
+ blockquote footer:before,
1498
+ blockquote small:before,
1499
+ blockquote .small:before {
1500
+ content: '\2014 \00A0';
1501
+ }
1502
+ .blockquote-reverse,
1503
+ blockquote.pull-right {
1504
+ padding-right: 15px;
1505
+ padding-left: 0;
1506
+ text-align: right;
1507
+ border-right: 5px solid #eee;
1508
+ border-left: 0;
1509
+ }
1510
+ .blockquote-reverse footer:before,
1511
+ blockquote.pull-right footer:before,
1512
+ .blockquote-reverse small:before,
1513
+ blockquote.pull-right small:before,
1514
+ .blockquote-reverse .small:before,
1515
+ blockquote.pull-right .small:before {
1516
+ content: '';
1517
+ }
1518
+ .blockquote-reverse footer:after,
1519
+ blockquote.pull-right footer:after,
1520
+ .blockquote-reverse small:after,
1521
+ blockquote.pull-right small:after,
1522
+ .blockquote-reverse .small:after,
1523
+ blockquote.pull-right .small:after {
1524
+ content: '\00A0 \2014';
1525
+ }
1526
+ address {
1527
+ margin-bottom: 20px;
1528
+ font-style: normal;
1529
+ line-height: 1.42857143;
1530
+ }
1531
+ code,
1532
+ kbd,
1533
+ pre,
1534
+ samp {
1535
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
1536
+ }
1537
+ code {
1538
+ padding: 2px 4px;
1539
+ font-size: 90%;
1540
+ color: #c7254e;
1541
+ background-color: #f9f2f4;
1542
+ border-radius: 4px;
1543
+ }
1544
+ kbd {
1545
+ padding: 2px 4px;
1546
+ font-size: 90%;
1547
+ color: #fff;
1548
+ background-color: #333;
1549
+ border-radius: 3px;
1550
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
1551
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
1552
+ }
1553
+ kbd kbd {
1554
+ padding: 0;
1555
+ font-size: 100%;
1556
+ font-weight: bold;
1557
+ -webkit-box-shadow: none;
1558
+ box-shadow: none;
1559
+ }
1560
+ pre {
1561
+ display: block;
1562
+ padding: 9.5px;
1563
+ margin: 0 0 10px;
1564
+ font-size: 13px;
1565
+ line-height: 1.42857143;
1566
+ color: #333;
1567
+ word-break: break-all;
1568
+ word-wrap: break-word;
1569
+ background-color: #f5f5f5;
1570
+ border: 1px solid #ccc;
1571
+ border-radius: 4px;
1572
+ }
1573
+ pre code {
1574
+ padding: 0;
1575
+ font-size: inherit;
1576
+ color: inherit;
1577
+ white-space: pre-wrap;
1578
+ background-color: transparent;
1579
+ border-radius: 0;
1580
+ }
1581
+ .pre-scrollable {
1582
+ max-height: 340px;
1583
+ overflow-y: scroll;
1584
+ }
1585
+ .container {
1586
+ padding-right: 15px;
1587
+ padding-left: 15px;
1588
+ margin-right: auto;
1589
+ margin-left: auto;
1590
+ }
1591
+ @media (min-width: 768px) {
1592
+ .container {
1593
+ width: 750px;
1594
+ }
1595
+ }
1596
+ @media (min-width: 992px) {
1597
+ .container {
1598
+ width: 970px;
1599
+ }
1600
+ }
1601
+ @media (min-width: 1200px) {
1602
+ .container {
1603
+ width: 1170px;
1604
+ }
1605
+ }
1606
+ .container-fluid {
1607
+ padding-right: 15px;
1608
+ padding-left: 15px;
1609
+ margin-right: auto;
1610
+ margin-left: auto;
1611
+ }
1612
+ .row {
1613
+ margin-right: -15px;
1614
+ margin-left: -15px;
1615
+ }
1616
+ .col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
1617
+ position: relative;
1618
+ min-height: 1px;
1619
+ padding-right: 15px;
1620
+ padding-left: 15px;
1621
+ }
1622
+ .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
1623
+ float: left;
1624
+ }
1625
+ .col-xs-12 {
1626
+ width: 100%;
1627
+ }
1628
+ .col-xs-11 {
1629
+ width: 91.66666667%;
1630
+ }
1631
+ .col-xs-10 {
1632
+ width: 83.33333333%;
1633
+ }
1634
+ .col-xs-9 {
1635
+ width: 75%;
1636
+ }
1637
+ .col-xs-8 {
1638
+ width: 66.66666667%;
1639
+ }
1640
+ .col-xs-7 {
1641
+ width: 58.33333333%;
1642
+ }
1643
+ .col-xs-6 {
1644
+ width: 50%;
1645
+ }
1646
+ .col-xs-5 {
1647
+ width: 41.66666667%;
1648
+ }
1649
+ .col-xs-4 {
1650
+ width: 33.33333333%;
1651
+ }
1652
+ .col-xs-3 {
1653
+ width: 25%;
1654
+ }
1655
+ .col-xs-2 {
1656
+ width: 16.66666667%;
1657
+ }
1658
+ .col-xs-1 {
1659
+ width: 8.33333333%;
1660
+ }
1661
+ .col-xs-pull-12 {
1662
+ right: 100%;
1663
+ }
1664
+ .col-xs-pull-11 {
1665
+ right: 91.66666667%;
1666
+ }
1667
+ .col-xs-pull-10 {
1668
+ right: 83.33333333%;
1669
+ }
1670
+ .col-xs-pull-9 {
1671
+ right: 75%;
1672
+ }
1673
+ .col-xs-pull-8 {
1674
+ right: 66.66666667%;
1675
+ }
1676
+ .col-xs-pull-7 {
1677
+ right: 58.33333333%;
1678
+ }
1679
+ .col-xs-pull-6 {
1680
+ right: 50%;
1681
+ }
1682
+ .col-xs-pull-5 {
1683
+ right: 41.66666667%;
1684
+ }
1685
+ .col-xs-pull-4 {
1686
+ right: 33.33333333%;
1687
+ }
1688
+ .col-xs-pull-3 {
1689
+ right: 25%;
1690
+ }
1691
+ .col-xs-pull-2 {
1692
+ right: 16.66666667%;
1693
+ }
1694
+ .col-xs-pull-1 {
1695
+ right: 8.33333333%;
1696
+ }
1697
+ .col-xs-pull-0 {
1698
+ right: auto;
1699
+ }
1700
+ .col-xs-push-12 {
1701
+ left: 100%;
1702
+ }
1703
+ .col-xs-push-11 {
1704
+ left: 91.66666667%;
1705
+ }
1706
+ .col-xs-push-10 {
1707
+ left: 83.33333333%;
1708
+ }
1709
+ .col-xs-push-9 {
1710
+ left: 75%;
1711
+ }
1712
+ .col-xs-push-8 {
1713
+ left: 66.66666667%;
1714
+ }
1715
+ .col-xs-push-7 {
1716
+ left: 58.33333333%;
1717
+ }
1718
+ .col-xs-push-6 {
1719
+ left: 50%;
1720
+ }
1721
+ .col-xs-push-5 {
1722
+ left: 41.66666667%;
1723
+ }
1724
+ .col-xs-push-4 {
1725
+ left: 33.33333333%;
1726
+ }
1727
+ .col-xs-push-3 {
1728
+ left: 25%;
1729
+ }
1730
+ .col-xs-push-2 {
1731
+ left: 16.66666667%;
1732
+ }
1733
+ .col-xs-push-1 {
1734
+ left: 8.33333333%;
1735
+ }
1736
+ .col-xs-push-0 {
1737
+ left: auto;
1738
+ }
1739
+ .col-xs-offset-12 {
1740
+ margin-left: 100%;
1741
+ }
1742
+ .col-xs-offset-11 {
1743
+ margin-left: 91.66666667%;
1744
+ }
1745
+ .col-xs-offset-10 {
1746
+ margin-left: 83.33333333%;
1747
+ }
1748
+ .col-xs-offset-9 {
1749
+ margin-left: 75%;
1750
+ }
1751
+ .col-xs-offset-8 {
1752
+ margin-left: 66.66666667%;
1753
+ }
1754
+ .col-xs-offset-7 {
1755
+ margin-left: 58.33333333%;
1756
+ }
1757
+ .col-xs-offset-6 {
1758
+ margin-left: 50%;
1759
+ }
1760
+ .col-xs-offset-5 {
1761
+ margin-left: 41.66666667%;
1762
+ }
1763
+ .col-xs-offset-4 {
1764
+ margin-left: 33.33333333%;
1765
+ }
1766
+ .col-xs-offset-3 {
1767
+ margin-left: 25%;
1768
+ }
1769
+ .col-xs-offset-2 {
1770
+ margin-left: 16.66666667%;
1771
+ }
1772
+ .col-xs-offset-1 {
1773
+ margin-left: 8.33333333%;
1774
+ }
1775
+ .col-xs-offset-0 {
1776
+ margin-left: 0;
1777
+ }
1778
+ @media (min-width: 768px) {
1779
+ .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
1780
+ float: left;
1781
+ }
1782
+ .col-sm-12 {
1783
+ width: 100%;
1784
+ }
1785
+ .col-sm-11 {
1786
+ width: 91.66666667%;
1787
+ }
1788
+ .col-sm-10 {
1789
+ width: 83.33333333%;
1790
+ }
1791
+ .col-sm-9 {
1792
+ width: 75%;
1793
+ }
1794
+ .col-sm-8 {
1795
+ width: 66.66666667%;
1796
+ }
1797
+ .col-sm-7 {
1798
+ width: 58.33333333%;
1799
+ }
1800
+ .col-sm-6 {
1801
+ width: 50%;
1802
+ }
1803
+ .col-sm-5 {
1804
+ width: 41.66666667%;
1805
+ }
1806
+ .col-sm-4 {
1807
+ width: 33.33333333%;
1808
+ }
1809
+ .col-sm-3 {
1810
+ width: 25%;
1811
+ }
1812
+ .col-sm-2 {
1813
+ width: 16.66666667%;
1814
+ }
1815
+ .col-sm-1 {
1816
+ width: 8.33333333%;
1817
+ }
1818
+ .col-sm-pull-12 {
1819
+ right: 100%;
1820
+ }
1821
+ .col-sm-pull-11 {
1822
+ right: 91.66666667%;
1823
+ }
1824
+ .col-sm-pull-10 {
1825
+ right: 83.33333333%;
1826
+ }
1827
+ .col-sm-pull-9 {
1828
+ right: 75%;
1829
+ }
1830
+ .col-sm-pull-8 {
1831
+ right: 66.66666667%;
1832
+ }
1833
+ .col-sm-pull-7 {
1834
+ right: 58.33333333%;
1835
+ }
1836
+ .col-sm-pull-6 {
1837
+ right: 50%;
1838
+ }
1839
+ .col-sm-pull-5 {
1840
+ right: 41.66666667%;
1841
+ }
1842
+ .col-sm-pull-4 {
1843
+ right: 33.33333333%;
1844
+ }
1845
+ .col-sm-pull-3 {
1846
+ right: 25%;
1847
+ }
1848
+ .col-sm-pull-2 {
1849
+ right: 16.66666667%;
1850
+ }
1851
+ .col-sm-pull-1 {
1852
+ right: 8.33333333%;
1853
+ }
1854
+ .col-sm-pull-0 {
1855
+ right: auto;
1856
+ }
1857
+ .col-sm-push-12 {
1858
+ left: 100%;
1859
+ }
1860
+ .col-sm-push-11 {
1861
+ left: 91.66666667%;
1862
+ }
1863
+ .col-sm-push-10 {
1864
+ left: 83.33333333%;
1865
+ }
1866
+ .col-sm-push-9 {
1867
+ left: 75%;
1868
+ }
1869
+ .col-sm-push-8 {
1870
+ left: 66.66666667%;
1871
+ }
1872
+ .col-sm-push-7 {
1873
+ left: 58.33333333%;
1874
+ }
1875
+ .col-sm-push-6 {
1876
+ left: 50%;
1877
+ }
1878
+ .col-sm-push-5 {
1879
+ left: 41.66666667%;
1880
+ }
1881
+ .col-sm-push-4 {
1882
+ left: 33.33333333%;
1883
+ }
1884
+ .col-sm-push-3 {
1885
+ left: 25%;
1886
+ }
1887
+ .col-sm-push-2 {
1888
+ left: 16.66666667%;
1889
+ }
1890
+ .col-sm-push-1 {
1891
+ left: 8.33333333%;
1892
+ }
1893
+ .col-sm-push-0 {
1894
+ left: auto;
1895
+ }
1896
+ .col-sm-offset-12 {
1897
+ margin-left: 100%;
1898
+ }
1899
+ .col-sm-offset-11 {
1900
+ margin-left: 91.66666667%;
1901
+ }
1902
+ .col-sm-offset-10 {
1903
+ margin-left: 83.33333333%;
1904
+ }
1905
+ .col-sm-offset-9 {
1906
+ margin-left: 75%;
1907
+ }
1908
+ .col-sm-offset-8 {
1909
+ margin-left: 66.66666667%;
1910
+ }
1911
+ .col-sm-offset-7 {
1912
+ margin-left: 58.33333333%;
1913
+ }
1914
+ .col-sm-offset-6 {
1915
+ margin-left: 50%;
1916
+ }
1917
+ .col-sm-offset-5 {
1918
+ margin-left: 41.66666667%;
1919
+ }
1920
+ .col-sm-offset-4 {
1921
+ margin-left: 33.33333333%;
1922
+ }
1923
+ .col-sm-offset-3 {
1924
+ margin-left: 25%;
1925
+ }
1926
+ .col-sm-offset-2 {
1927
+ margin-left: 16.66666667%;
1928
+ }
1929
+ .col-sm-offset-1 {
1930
+ margin-left: 8.33333333%;
1931
+ }
1932
+ .col-sm-offset-0 {
1933
+ margin-left: 0;
1934
+ }
1935
+ }
1936
+ @media (min-width: 992px) {
1937
+ .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
1938
+ float: left;
1939
+ }
1940
+ .col-md-12 {
1941
+ width: 100%;
1942
+ }
1943
+ .col-md-11 {
1944
+ width: 91.66666667%;
1945
+ }
1946
+ .col-md-10 {
1947
+ width: 83.33333333%;
1948
+ }
1949
+ .col-md-9 {
1950
+ width: 75%;
1951
+ }
1952
+ .col-md-8 {
1953
+ width: 66.66666667%;
1954
+ }
1955
+ .col-md-7 {
1956
+ width: 58.33333333%;
1957
+ }
1958
+ .col-md-6 {
1959
+ width: 50%;
1960
+ }
1961
+ .col-md-5 {
1962
+ width: 41.66666667%;
1963
+ }
1964
+ .col-md-4 {
1965
+ width: 33.33333333%;
1966
+ }
1967
+ .col-md-3 {
1968
+ width: 25%;
1969
+ }
1970
+ .col-md-2 {
1971
+ width: 16.66666667%;
1972
+ }
1973
+ .col-md-1 {
1974
+ width: 8.33333333%;
1975
+ }
1976
+ .col-md-pull-12 {
1977
+ right: 100%;
1978
+ }
1979
+ .col-md-pull-11 {
1980
+ right: 91.66666667%;
1981
+ }
1982
+ .col-md-pull-10 {
1983
+ right: 83.33333333%;
1984
+ }
1985
+ .col-md-pull-9 {
1986
+ right: 75%;
1987
+ }
1988
+ .col-md-pull-8 {
1989
+ right: 66.66666667%;
1990
+ }
1991
+ .col-md-pull-7 {
1992
+ right: 58.33333333%;
1993
+ }
1994
+ .col-md-pull-6 {
1995
+ right: 50%;
1996
+ }
1997
+ .col-md-pull-5 {
1998
+ right: 41.66666667%;
1999
+ }
2000
+ .col-md-pull-4 {
2001
+ right: 33.33333333%;
2002
+ }
2003
+ .col-md-pull-3 {
2004
+ right: 25%;
2005
+ }
2006
+ .col-md-pull-2 {
2007
+ right: 16.66666667%;
2008
+ }
2009
+ .col-md-pull-1 {
2010
+ right: 8.33333333%;
2011
+ }
2012
+ .col-md-pull-0 {
2013
+ right: auto;
2014
+ }
2015
+ .col-md-push-12 {
2016
+ left: 100%;
2017
+ }
2018
+ .col-md-push-11 {
2019
+ left: 91.66666667%;
2020
+ }
2021
+ .col-md-push-10 {
2022
+ left: 83.33333333%;
2023
+ }
2024
+ .col-md-push-9 {
2025
+ left: 75%;
2026
+ }
2027
+ .col-md-push-8 {
2028
+ left: 66.66666667%;
2029
+ }
2030
+ .col-md-push-7 {
2031
+ left: 58.33333333%;
2032
+ }
2033
+ .col-md-push-6 {
2034
+ left: 50%;
2035
+ }
2036
+ .col-md-push-5 {
2037
+ left: 41.66666667%;
2038
+ }
2039
+ .col-md-push-4 {
2040
+ left: 33.33333333%;
2041
+ }
2042
+ .col-md-push-3 {
2043
+ left: 25%;
2044
+ }
2045
+ .col-md-push-2 {
2046
+ left: 16.66666667%;
2047
+ }
2048
+ .col-md-push-1 {
2049
+ left: 8.33333333%;
2050
+ }
2051
+ .col-md-push-0 {
2052
+ left: auto;
2053
+ }
2054
+ .col-md-offset-12 {
2055
+ margin-left: 100%;
2056
+ }
2057
+ .col-md-offset-11 {
2058
+ margin-left: 91.66666667%;
2059
+ }
2060
+ .col-md-offset-10 {
2061
+ margin-left: 83.33333333%;
2062
+ }
2063
+ .col-md-offset-9 {
2064
+ margin-left: 75%;
2065
+ }
2066
+ .col-md-offset-8 {
2067
+ margin-left: 66.66666667%;
2068
+ }
2069
+ .col-md-offset-7 {
2070
+ margin-left: 58.33333333%;
2071
+ }
2072
+ .col-md-offset-6 {
2073
+ margin-left: 50%;
2074
+ }
2075
+ .col-md-offset-5 {
2076
+ margin-left: 41.66666667%;
2077
+ }
2078
+ .col-md-offset-4 {
2079
+ margin-left: 33.33333333%;
2080
+ }
2081
+ .col-md-offset-3 {
2082
+ margin-left: 25%;
2083
+ }
2084
+ .col-md-offset-2 {
2085
+ margin-left: 16.66666667%;
2086
+ }
2087
+ .col-md-offset-1 {
2088
+ margin-left: 8.33333333%;
2089
+ }
2090
+ .col-md-offset-0 {
2091
+ margin-left: 0;
2092
+ }
2093
+ }
2094
+ @media (min-width: 1200px) {
2095
+ .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
2096
+ float: left;
2097
+ }
2098
+ .col-lg-12 {
2099
+ width: 100%;
2100
+ }
2101
+ .col-lg-11 {
2102
+ width: 91.66666667%;
2103
+ }
2104
+ .col-lg-10 {
2105
+ width: 83.33333333%;
2106
+ }
2107
+ .col-lg-9 {
2108
+ width: 75%;
2109
+ }
2110
+ .col-lg-8 {
2111
+ width: 66.66666667%;
2112
+ }
2113
+ .col-lg-7 {
2114
+ width: 58.33333333%;
2115
+ }
2116
+ .col-lg-6 {
2117
+ width: 50%;
2118
+ }
2119
+ .col-lg-5 {
2120
+ width: 41.66666667%;
2121
+ }
2122
+ .col-lg-4 {
2123
+ width: 33.33333333%;
2124
+ }
2125
+ .col-lg-3 {
2126
+ width: 25%;
2127
+ }
2128
+ .col-lg-2 {
2129
+ width: 16.66666667%;
2130
+ }
2131
+ .col-lg-1 {
2132
+ width: 8.33333333%;
2133
+ }
2134
+ .col-lg-pull-12 {
2135
+ right: 100%;
2136
+ }
2137
+ .col-lg-pull-11 {
2138
+ right: 91.66666667%;
2139
+ }
2140
+ .col-lg-pull-10 {
2141
+ right: 83.33333333%;
2142
+ }
2143
+ .col-lg-pull-9 {
2144
+ right: 75%;
2145
+ }
2146
+ .col-lg-pull-8 {
2147
+ right: 66.66666667%;
2148
+ }
2149
+ .col-lg-pull-7 {
2150
+ right: 58.33333333%;
2151
+ }
2152
+ .col-lg-pull-6 {
2153
+ right: 50%;
2154
+ }
2155
+ .col-lg-pull-5 {
2156
+ right: 41.66666667%;
2157
+ }
2158
+ .col-lg-pull-4 {
2159
+ right: 33.33333333%;
2160
+ }
2161
+ .col-lg-pull-3 {
2162
+ right: 25%;
2163
+ }
2164
+ .col-lg-pull-2 {
2165
+ right: 16.66666667%;
2166
+ }
2167
+ .col-lg-pull-1 {
2168
+ right: 8.33333333%;
2169
+ }
2170
+ .col-lg-pull-0 {
2171
+ right: auto;
2172
+ }
2173
+ .col-lg-push-12 {
2174
+ left: 100%;
2175
+ }
2176
+ .col-lg-push-11 {
2177
+ left: 91.66666667%;
2178
+ }
2179
+ .col-lg-push-10 {
2180
+ left: 83.33333333%;
2181
+ }
2182
+ .col-lg-push-9 {
2183
+ left: 75%;
2184
+ }
2185
+ .col-lg-push-8 {
2186
+ left: 66.66666667%;
2187
+ }
2188
+ .col-lg-push-7 {
2189
+ left: 58.33333333%;
2190
+ }
2191
+ .col-lg-push-6 {
2192
+ left: 50%;
2193
+ }
2194
+ .col-lg-push-5 {
2195
+ left: 41.66666667%;
2196
+ }
2197
+ .col-lg-push-4 {
2198
+ left: 33.33333333%;
2199
+ }
2200
+ .col-lg-push-3 {
2201
+ left: 25%;
2202
+ }
2203
+ .col-lg-push-2 {
2204
+ left: 16.66666667%;
2205
+ }
2206
+ .col-lg-push-1 {
2207
+ left: 8.33333333%;
2208
+ }
2209
+ .col-lg-push-0 {
2210
+ left: auto;
2211
+ }
2212
+ .col-lg-offset-12 {
2213
+ margin-left: 100%;
2214
+ }
2215
+ .col-lg-offset-11 {
2216
+ margin-left: 91.66666667%;
2217
+ }
2218
+ .col-lg-offset-10 {
2219
+ margin-left: 83.33333333%;
2220
+ }
2221
+ .col-lg-offset-9 {
2222
+ margin-left: 75%;
2223
+ }
2224
+ .col-lg-offset-8 {
2225
+ margin-left: 66.66666667%;
2226
+ }
2227
+ .col-lg-offset-7 {
2228
+ margin-left: 58.33333333%;
2229
+ }
2230
+ .col-lg-offset-6 {
2231
+ margin-left: 50%;
2232
+ }
2233
+ .col-lg-offset-5 {
2234
+ margin-left: 41.66666667%;
2235
+ }
2236
+ .col-lg-offset-4 {
2237
+ margin-left: 33.33333333%;
2238
+ }
2239
+ .col-lg-offset-3 {
2240
+ margin-left: 25%;
2241
+ }
2242
+ .col-lg-offset-2 {
2243
+ margin-left: 16.66666667%;
2244
+ }
2245
+ .col-lg-offset-1 {
2246
+ margin-left: 8.33333333%;
2247
+ }
2248
+ .col-lg-offset-0 {
2249
+ margin-left: 0;
2250
+ }
2251
+ }
2252
+ table {
2253
+ background-color: transparent;
2254
+ }
2255
+ caption {
2256
+ padding-top: 8px;
2257
+ padding-bottom: 8px;
2258
+ color: #777;
2259
+ text-align: left;
2260
+ }
2261
+ th {
2262
+ text-align: left;
2263
+ }
2264
+ .table {
2265
+ width: 100%;
2266
+ max-width: 100%;
2267
+ margin-bottom: 20px;
2268
+ }
2269
+ .table > thead > tr > th,
2270
+ .table > tbody > tr > th,
2271
+ .table > tfoot > tr > th,
2272
+ .table > thead > tr > td,
2273
+ .table > tbody > tr > td,
2274
+ .table > tfoot > tr > td {
2275
+ padding: 8px;
2276
+ line-height: 1.42857143;
2277
+ vertical-align: top;
2278
+ border-top: 1px solid #ddd;
2279
+ }
2280
+ .table > thead > tr > th {
2281
+ vertical-align: bottom;
2282
+ border-bottom: 2px solid #ddd;
2283
+ }
2284
+ .table > caption + thead > tr:first-child > th,
2285
+ .table > colgroup + thead > tr:first-child > th,
2286
+ .table > thead:first-child > tr:first-child > th,
2287
+ .table > caption + thead > tr:first-child > td,
2288
+ .table > colgroup + thead > tr:first-child > td,
2289
+ .table > thead:first-child > tr:first-child > td {
2290
+ border-top: 0;
2291
+ }
2292
+ .table > tbody + tbody {
2293
+ border-top: 2px solid #ddd;
2294
+ }
2295
+ .table .table {
2296
+ background-color: #fff;
2297
+ }
2298
+ .table-condensed > thead > tr > th,
2299
+ .table-condensed > tbody > tr > th,
2300
+ .table-condensed > tfoot > tr > th,
2301
+ .table-condensed > thead > tr > td,
2302
+ .table-condensed > tbody > tr > td,
2303
+ .table-condensed > tfoot > tr > td {
2304
+ padding: 5px;
2305
+ }
2306
+ .table-bordered {
2307
+ border: 1px solid #ddd;
2308
+ }
2309
+ .table-bordered > thead > tr > th,
2310
+ .table-bordered > tbody > tr > th,
2311
+ .table-bordered > tfoot > tr > th,
2312
+ .table-bordered > thead > tr > td,
2313
+ .table-bordered > tbody > tr > td,
2314
+ .table-bordered > tfoot > tr > td {
2315
+ border: 1px solid #ddd;
2316
+ }
2317
+ .table-bordered > thead > tr > th,
2318
+ .table-bordered > thead > tr > td {
2319
+ border-bottom-width: 2px;
2320
+ }
2321
+ .table-striped > tbody > tr:nth-of-type(odd) {
2322
+ background-color: #f9f9f9;
2323
+ }
2324
+ .table-hover > tbody > tr:hover {
2325
+ background-color: #f5f5f5;
2326
+ }
2327
+ table col[class*="col-"] {
2328
+ position: static;
2329
+ display: table-column;
2330
+ float: none;
2331
+ }
2332
+ table td[class*="col-"],
2333
+ table th[class*="col-"] {
2334
+ position: static;
2335
+ display: table-cell;
2336
+ float: none;
2337
+ }
2338
+ .table > thead > tr > td.active,
2339
+ .table > tbody > tr > td.active,
2340
+ .table > tfoot > tr > td.active,
2341
+ .table > thead > tr > th.active,
2342
+ .table > tbody > tr > th.active,
2343
+ .table > tfoot > tr > th.active,
2344
+ .table > thead > tr.active > td,
2345
+ .table > tbody > tr.active > td,
2346
+ .table > tfoot > tr.active > td,
2347
+ .table > thead > tr.active > th,
2348
+ .table > tbody > tr.active > th,
2349
+ .table > tfoot > tr.active > th {
2350
+ background-color: #f5f5f5;
2351
+ }
2352
+ .table-hover > tbody > tr > td.active:hover,
2353
+ .table-hover > tbody > tr > th.active:hover,
2354
+ .table-hover > tbody > tr.active:hover > td,
2355
+ .table-hover > tbody > tr:hover > .active,
2356
+ .table-hover > tbody > tr.active:hover > th {
2357
+ background-color: #e8e8e8;
2358
+ }
2359
+ .table > thead > tr > td.success,
2360
+ .table > tbody > tr > td.success,
2361
+ .table > tfoot > tr > td.success,
2362
+ .table > thead > tr > th.success,
2363
+ .table > tbody > tr > th.success,
2364
+ .table > tfoot > tr > th.success,
2365
+ .table > thead > tr.success > td,
2366
+ .table > tbody > tr.success > td,
2367
+ .table > tfoot > tr.success > td,
2368
+ .table > thead > tr.success > th,
2369
+ .table > tbody > tr.success > th,
2370
+ .table > tfoot > tr.success > th {
2371
+ background-color: #dff0d8;
2372
+ }
2373
+ .table-hover > tbody > tr > td.success:hover,
2374
+ .table-hover > tbody > tr > th.success:hover,
2375
+ .table-hover > tbody > tr.success:hover > td,
2376
+ .table-hover > tbody > tr:hover > .success,
2377
+ .table-hover > tbody > tr.success:hover > th {
2378
+ background-color: #d0e9c6;
2379
+ }
2380
+ .table > thead > tr > td.info,
2381
+ .table > tbody > tr > td.info,
2382
+ .table > tfoot > tr > td.info,
2383
+ .table > thead > tr > th.info,
2384
+ .table > tbody > tr > th.info,
2385
+ .table > tfoot > tr > th.info,
2386
+ .table > thead > tr.info > td,
2387
+ .table > tbody > tr.info > td,
2388
+ .table > tfoot > tr.info > td,
2389
+ .table > thead > tr.info > th,
2390
+ .table > tbody > tr.info > th,
2391
+ .table > tfoot > tr.info > th {
2392
+ background-color: #d9edf7;
2393
+ }
2394
+ .table-hover > tbody > tr > td.info:hover,
2395
+ .table-hover > tbody > tr > th.info:hover,
2396
+ .table-hover > tbody > tr.info:hover > td,
2397
+ .table-hover > tbody > tr:hover > .info,
2398
+ .table-hover > tbody > tr.info:hover > th {
2399
+ background-color: #c4e3f3;
2400
+ }
2401
+ .table > thead > tr > td.warning,
2402
+ .table > tbody > tr > td.warning,
2403
+ .table > tfoot > tr > td.warning,
2404
+ .table > thead > tr > th.warning,
2405
+ .table > tbody > tr > th.warning,
2406
+ .table > tfoot > tr > th.warning,
2407
+ .table > thead > tr.warning > td,
2408
+ .table > tbody > tr.warning > td,
2409
+ .table > tfoot > tr.warning > td,
2410
+ .table > thead > tr.warning > th,
2411
+ .table > tbody > tr.warning > th,
2412
+ .table > tfoot > tr.warning > th {
2413
+ background-color: #fcf8e3;
2414
+ }
2415
+ .table-hover > tbody > tr > td.warning:hover,
2416
+ .table-hover > tbody > tr > th.warning:hover,
2417
+ .table-hover > tbody > tr.warning:hover > td,
2418
+ .table-hover > tbody > tr:hover > .warning,
2419
+ .table-hover > tbody > tr.warning:hover > th {
2420
+ background-color: #faf2cc;
2421
+ }
2422
+ .table > thead > tr > td.danger,
2423
+ .table > tbody > tr > td.danger,
2424
+ .table > tfoot > tr > td.danger,
2425
+ .table > thead > tr > th.danger,
2426
+ .table > tbody > tr > th.danger,
2427
+ .table > tfoot > tr > th.danger,
2428
+ .table > thead > tr.danger > td,
2429
+ .table > tbody > tr.danger > td,
2430
+ .table > tfoot > tr.danger > td,
2431
+ .table > thead > tr.danger > th,
2432
+ .table > tbody > tr.danger > th,
2433
+ .table > tfoot > tr.danger > th {
2434
+ background-color: #f2dede;
2435
+ }
2436
+ .table-hover > tbody > tr > td.danger:hover,
2437
+ .table-hover > tbody > tr > th.danger:hover,
2438
+ .table-hover > tbody > tr.danger:hover > td,
2439
+ .table-hover > tbody > tr:hover > .danger,
2440
+ .table-hover > tbody > tr.danger:hover > th {
2441
+ background-color: #ebcccc;
2442
+ }
2443
+ .table-responsive {
2444
+ min-height: .01%;
2445
+ overflow-x: auto;
2446
+ }
2447
+ @media screen and (max-width: 767px) {
2448
+ .table-responsive {
2449
+ width: 100%;
2450
+ margin-bottom: 15px;
2451
+ overflow-y: hidden;
2452
+ -ms-overflow-style: -ms-autohiding-scrollbar;
2453
+ border: 1px solid #ddd;
2454
+ }
2455
+ .table-responsive > .table {
2456
+ margin-bottom: 0;
2457
+ }
2458
+ .table-responsive > .table > thead > tr > th,
2459
+ .table-responsive > .table > tbody > tr > th,
2460
+ .table-responsive > .table > tfoot > tr > th,
2461
+ .table-responsive > .table > thead > tr > td,
2462
+ .table-responsive > .table > tbody > tr > td,
2463
+ .table-responsive > .table > tfoot > tr > td {
2464
+ white-space: nowrap;
2465
+ }
2466
+ .table-responsive > .table-bordered {
2467
+ border: 0;
2468
+ }
2469
+ .table-responsive > .table-bordered > thead > tr > th:first-child,
2470
+ .table-responsive > .table-bordered > tbody > tr > th:first-child,
2471
+ .table-responsive > .table-bordered > tfoot > tr > th:first-child,
2472
+ .table-responsive > .table-bordered > thead > tr > td:first-child,
2473
+ .table-responsive > .table-bordered > tbody > tr > td:first-child,
2474
+ .table-responsive > .table-bordered > tfoot > tr > td:first-child {
2475
+ border-left: 0;
2476
+ }
2477
+ .table-responsive > .table-bordered > thead > tr > th:last-child,
2478
+ .table-responsive > .table-bordered > tbody > tr > th:last-child,
2479
+ .table-responsive > .table-bordered > tfoot > tr > th:last-child,
2480
+ .table-responsive > .table-bordered > thead > tr > td:last-child,
2481
+ .table-responsive > .table-bordered > tbody > tr > td:last-child,
2482
+ .table-responsive > .table-bordered > tfoot > tr > td:last-child {
2483
+ border-right: 0;
2484
+ }
2485
+ .table-responsive > .table-bordered > tbody > tr:last-child > th,
2486
+ .table-responsive > .table-bordered > tfoot > tr:last-child > th,
2487
+ .table-responsive > .table-bordered > tbody > tr:last-child > td,
2488
+ .table-responsive > .table-bordered > tfoot > tr:last-child > td {
2489
+ border-bottom: 0;
2490
+ }
2491
+ }
2492
+ fieldset {
2493
+ min-width: 0;
2494
+ padding: 0;
2495
+ margin: 0;
2496
+ border: 0;
2497
+ }
2498
+ legend {
2499
+ display: block;
2500
+ width: 100%;
2501
+ padding: 0;
2502
+ margin-bottom: 20px;
2503
+ font-size: 21px;
2504
+ line-height: inherit;
2505
+ color: #333;
2506
+ border: 0;
2507
+ border-bottom: 1px solid #e5e5e5;
2508
+ }
2509
+ label {
2510
+ display: inline-block;
2511
+ max-width: 100%;
2512
+ margin-bottom: 5px;
2513
+ font-weight: bold;
2514
+ }
2515
+ input[type="search"] {
2516
+ -webkit-box-sizing: border-box;
2517
+ -moz-box-sizing: border-box;
2518
+ box-sizing: border-box;
2519
+ }
2520
+ input[type="radio"],
2521
+ input[type="checkbox"] {
2522
+ margin: 4px 0 0;
2523
+ margin-top: 1px \9;
2524
+ line-height: normal;
2525
+ }
2526
+ input[type="file"] {
2527
+ display: block;
2528
+ }
2529
+ input[type="range"] {
2530
+ display: block;
2531
+ width: 100%;
2532
+ }
2533
+ select[multiple],
2534
+ select[size] {
2535
+ height: auto;
2536
+ }
2537
+ input[type="file"]:focus,
2538
+ input[type="radio"]:focus,
2539
+ input[type="checkbox"]:focus {
2540
+ outline: thin dotted;
2541
+ outline: 5px auto -webkit-focus-ring-color;
2542
+ outline-offset: -2px;
2543
+ }
2544
+ output {
2545
+ display: block;
2546
+ padding-top: 7px;
2547
+ font-size: 14px;
2548
+ line-height: 1.42857143;
2549
+ color: #555;
2550
+ }
2551
+ .form-control {
2552
+ display: block;
2553
+ width: 100%;
2554
+ height: 34px;
2555
+ padding: 6px 12px;
2556
+ font-size: 14px;
2557
+ line-height: 1.42857143;
2558
+ color: #555;
2559
+ background-color: #fff;
2560
+ background-image: none;
2561
+ border: 1px solid #ccc;
2562
+ border-radius: 4px;
2563
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
2564
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
2565
+ -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
2566
+ -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
2567
+ transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
2568
+ }
2569
+ .form-control:focus {
2570
+ border-color: #66afe9;
2571
+ outline: 0;
2572
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
2573
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
2574
+ }
2575
+ .form-control::-moz-placeholder {
2576
+ color: #999;
2577
+ opacity: 1;
2578
+ }
2579
+ .form-control:-ms-input-placeholder {
2580
+ color: #999;
2581
+ }
2582
+ .form-control::-webkit-input-placeholder {
2583
+ color: #999;
2584
+ }
2585
+ .form-control::-ms-expand {
2586
+ background-color: transparent;
2587
+ border: 0;
2588
+ }
2589
+ .form-control[disabled],
2590
+ .form-control[readonly],
2591
+ fieldset[disabled] .form-control {
2592
+ background-color: #eee;
2593
+ opacity: 1;
2594
+ }
2595
+ .form-control[disabled],
2596
+ fieldset[disabled] .form-control {
2597
+ cursor: not-allowed;
2598
+ }
2599
+ textarea.form-control {
2600
+ height: auto;
2601
+ }
2602
+ input[type="search"] {
2603
+ -webkit-appearance: none;
2604
+ }
2605
+ @media screen and (-webkit-min-device-pixel-ratio: 0) {
2606
+ input[type="date"].form-control,
2607
+ input[type="time"].form-control,
2608
+ input[type="datetime-local"].form-control,
2609
+ input[type="month"].form-control {
2610
+ line-height: 34px;
2611
+ }
2612
+ input[type="date"].input-sm,
2613
+ input[type="time"].input-sm,
2614
+ input[type="datetime-local"].input-sm,
2615
+ input[type="month"].input-sm,
2616
+ .input-group-sm input[type="date"],
2617
+ .input-group-sm input[type="time"],
2618
+ .input-group-sm input[type="datetime-local"],
2619
+ .input-group-sm input[type="month"] {
2620
+ line-height: 30px;
2621
+ }
2622
+ input[type="date"].input-lg,
2623
+ input[type="time"].input-lg,
2624
+ input[type="datetime-local"].input-lg,
2625
+ input[type="month"].input-lg,
2626
+ .input-group-lg input[type="date"],
2627
+ .input-group-lg input[type="time"],
2628
+ .input-group-lg input[type="datetime-local"],
2629
+ .input-group-lg input[type="month"] {
2630
+ line-height: 46px;
2631
+ }
2632
+ }
2633
+ .form-group {
2634
+ margin-bottom: 15px;
2635
+ }
2636
+ .radio,
2637
+ .checkbox {
2638
+ position: relative;
2639
+ display: block;
2640
+ margin-top: 10px;
2641
+ margin-bottom: 10px;
2642
+ }
2643
+ .radio label,
2644
+ .checkbox label {
2645
+ min-height: 20px;
2646
+ padding-left: 20px;
2647
+ margin-bottom: 0;
2648
+ font-weight: normal;
2649
+ cursor: pointer;
2650
+ }
2651
+ .radio input[type="radio"],
2652
+ .radio-inline input[type="radio"],
2653
+ .checkbox input[type="checkbox"],
2654
+ .checkbox-inline input[type="checkbox"] {
2655
+ position: absolute;
2656
+ margin-top: 4px \9;
2657
+ margin-left: -20px;
2658
+ }
2659
+ .radio + .radio,
2660
+ .checkbox + .checkbox {
2661
+ margin-top: -5px;
2662
+ }
2663
+ .radio-inline,
2664
+ .checkbox-inline {
2665
+ position: relative;
2666
+ display: inline-block;
2667
+ padding-left: 20px;
2668
+ margin-bottom: 0;
2669
+ font-weight: normal;
2670
+ vertical-align: middle;
2671
+ cursor: pointer;
2672
+ }
2673
+ .radio-inline + .radio-inline,
2674
+ .checkbox-inline + .checkbox-inline {
2675
+ margin-top: 0;
2676
+ margin-left: 10px;
2677
+ }
2678
+ input[type="radio"][disabled],
2679
+ input[type="checkbox"][disabled],
2680
+ input[type="radio"].disabled,
2681
+ input[type="checkbox"].disabled,
2682
+ fieldset[disabled] input[type="radio"],
2683
+ fieldset[disabled] input[type="checkbox"] {
2684
+ cursor: not-allowed;
2685
+ }
2686
+ .radio-inline.disabled,
2687
+ .checkbox-inline.disabled,
2688
+ fieldset[disabled] .radio-inline,
2689
+ fieldset[disabled] .checkbox-inline {
2690
+ cursor: not-allowed;
2691
+ }
2692
+ .radio.disabled label,
2693
+ .checkbox.disabled label,
2694
+ fieldset[disabled] .radio label,
2695
+ fieldset[disabled] .checkbox label {
2696
+ cursor: not-allowed;
2697
+ }
2698
+ .form-control-static {
2699
+ min-height: 34px;
2700
+ padding-top: 7px;
2701
+ padding-bottom: 7px;
2702
+ margin-bottom: 0;
2703
+ }
2704
+ .form-control-static.input-lg,
2705
+ .form-control-static.input-sm {
2706
+ padding-right: 0;
2707
+ padding-left: 0;
2708
+ }
2709
+ .input-sm {
2710
+ height: 30px;
2711
+ padding: 5px 10px;
2712
+ font-size: 12px;
2713
+ line-height: 1.5;
2714
+ border-radius: 3px;
2715
+ }
2716
+ select.input-sm {
2717
+ height: 30px;
2718
+ line-height: 30px;
2719
+ }
2720
+ textarea.input-sm,
2721
+ select[multiple].input-sm {
2722
+ height: auto;
2723
+ }
2724
+ .form-group-sm .form-control {
2725
+ height: 30px;
2726
+ padding: 5px 10px;
2727
+ font-size: 12px;
2728
+ line-height: 1.5;
2729
+ border-radius: 3px;
2730
+ }
2731
+ .form-group-sm select.form-control {
2732
+ height: 30px;
2733
+ line-height: 30px;
2734
+ }
2735
+ .form-group-sm textarea.form-control,
2736
+ .form-group-sm select[multiple].form-control {
2737
+ height: auto;
2738
+ }
2739
+ .form-group-sm .form-control-static {
2740
+ height: 30px;
2741
+ min-height: 32px;
2742
+ padding: 6px 10px;
2743
+ font-size: 12px;
2744
+ line-height: 1.5;
2745
+ }
2746
+ .input-lg {
2747
+ height: 46px;
2748
+ padding: 10px 16px;
2749
+ font-size: 18px;
2750
+ line-height: 1.3333333;
2751
+ border-radius: 6px;
2752
+ }
2753
+ select.input-lg {
2754
+ height: 46px;
2755
+ line-height: 46px;
2756
+ }
2757
+ textarea.input-lg,
2758
+ select[multiple].input-lg {
2759
+ height: auto;
2760
+ }
2761
+ .form-group-lg .form-control {
2762
+ height: 46px;
2763
+ padding: 10px 16px;
2764
+ font-size: 18px;
2765
+ line-height: 1.3333333;
2766
+ border-radius: 6px;
2767
+ }
2768
+ .form-group-lg select.form-control {
2769
+ height: 46px;
2770
+ line-height: 46px;
2771
+ }
2772
+ .form-group-lg textarea.form-control,
2773
+ .form-group-lg select[multiple].form-control {
2774
+ height: auto;
2775
+ }
2776
+ .form-group-lg .form-control-static {
2777
+ height: 46px;
2778
+ min-height: 38px;
2779
+ padding: 11px 16px;
2780
+ font-size: 18px;
2781
+ line-height: 1.3333333;
2782
+ }
2783
+ .has-feedback {
2784
+ position: relative;
2785
+ }
2786
+ .has-feedback .form-control {
2787
+ padding-right: 42.5px;
2788
+ }
2789
+ .form-control-feedback {
2790
+ position: absolute;
2791
+ top: 0;
2792
+ right: 0;
2793
+ z-index: 2;
2794
+ display: block;
2795
+ width: 34px;
2796
+ height: 34px;
2797
+ line-height: 34px;
2798
+ text-align: center;
2799
+ pointer-events: none;
2800
+ }
2801
+ .input-lg + .form-control-feedback,
2802
+ .input-group-lg + .form-control-feedback,
2803
+ .form-group-lg .form-control + .form-control-feedback {
2804
+ width: 46px;
2805
+ height: 46px;
2806
+ line-height: 46px;
2807
+ }
2808
+ .input-sm + .form-control-feedback,
2809
+ .input-group-sm + .form-control-feedback,
2810
+ .form-group-sm .form-control + .form-control-feedback {
2811
+ width: 30px;
2812
+ height: 30px;
2813
+ line-height: 30px;
2814
+ }
2815
+ .has-success .help-block,
2816
+ .has-success .control-label,
2817
+ .has-success .radio,
2818
+ .has-success .checkbox,
2819
+ .has-success .radio-inline,
2820
+ .has-success .checkbox-inline,
2821
+ .has-success.radio label,
2822
+ .has-success.checkbox label,
2823
+ .has-success.radio-inline label,
2824
+ .has-success.checkbox-inline label {
2825
+ color: #3c763d;
2826
+ }
2827
+ .has-success .form-control {
2828
+ border-color: #3c763d;
2829
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
2830
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
2831
+ }
2832
+ .has-success .form-control:focus {
2833
+ border-color: #2b542c;
2834
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
2835
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
2836
+ }
2837
+ .has-success .input-group-addon {
2838
+ color: #3c763d;
2839
+ background-color: #dff0d8;
2840
+ border-color: #3c763d;
2841
+ }
2842
+ .has-success .form-control-feedback {
2843
+ color: #3c763d;
2844
+ }
2845
+ .has-warning .help-block,
2846
+ .has-warning .control-label,
2847
+ .has-warning .radio,
2848
+ .has-warning .checkbox,
2849
+ .has-warning .radio-inline,
2850
+ .has-warning .checkbox-inline,
2851
+ .has-warning.radio label,
2852
+ .has-warning.checkbox label,
2853
+ .has-warning.radio-inline label,
2854
+ .has-warning.checkbox-inline label {
2855
+ color: #8a6d3b;
2856
+ }
2857
+ .has-warning .form-control {
2858
+ border-color: #8a6d3b;
2859
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
2860
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
2861
+ }
2862
+ .has-warning .form-control:focus {
2863
+ border-color: #66512c;
2864
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
2865
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
2866
+ }
2867
+ .has-warning .input-group-addon {
2868
+ color: #8a6d3b;
2869
+ background-color: #fcf8e3;
2870
+ border-color: #8a6d3b;
2871
+ }
2872
+ .has-warning .form-control-feedback {
2873
+ color: #8a6d3b;
2874
+ }
2875
+ .has-error .help-block,
2876
+ .has-error .control-label,
2877
+ .has-error .radio,
2878
+ .has-error .checkbox,
2879
+ .has-error .radio-inline,
2880
+ .has-error .checkbox-inline,
2881
+ .has-error.radio label,
2882
+ .has-error.checkbox label,
2883
+ .has-error.radio-inline label,
2884
+ .has-error.checkbox-inline label {
2885
+ color: #a94442;
2886
+ }
2887
+ .has-error .form-control {
2888
+ border-color: #a94442;
2889
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
2890
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
2891
+ }
2892
+ .has-error .form-control:focus {
2893
+ border-color: #843534;
2894
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
2895
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
2896
+ }
2897
+ .has-error .input-group-addon {
2898
+ color: #a94442;
2899
+ background-color: #f2dede;
2900
+ border-color: #a94442;
2901
+ }
2902
+ .has-error .form-control-feedback {
2903
+ color: #a94442;
2904
+ }
2905
+ .has-feedback label ~ .form-control-feedback {
2906
+ top: 25px;
2907
+ }
2908
+ .has-feedback label.sr-only ~ .form-control-feedback {
2909
+ top: 0;
2910
+ }
2911
+ .help-block {
2912
+ display: block;
2913
+ margin-top: 5px;
2914
+ margin-bottom: 10px;
2915
+ color: #737373;
2916
+ }
2917
+ @media (min-width: 768px) {
2918
+ .form-inline .form-group {
2919
+ display: inline-block;
2920
+ margin-bottom: 0;
2921
+ vertical-align: middle;
2922
+ }
2923
+ .form-inline .form-control {
2924
+ display: inline-block;
2925
+ width: auto;
2926
+ vertical-align: middle;
2927
+ }
2928
+ .form-inline .form-control-static {
2929
+ display: inline-block;
2930
+ }
2931
+ .form-inline .input-group {
2932
+ display: inline-table;
2933
+ vertical-align: middle;
2934
+ }
2935
+ .form-inline .input-group .input-group-addon,
2936
+ .form-inline .input-group .input-group-btn,
2937
+ .form-inline .input-group .form-control {
2938
+ width: auto;
2939
+ }
2940
+ .form-inline .input-group > .form-control {
2941
+ width: 100%;
2942
+ }
2943
+ .form-inline .control-label {
2944
+ margin-bottom: 0;
2945
+ vertical-align: middle;
2946
+ }
2947
+ .form-inline .radio,
2948
+ .form-inline .checkbox {
2949
+ display: inline-block;
2950
+ margin-top: 0;
2951
+ margin-bottom: 0;
2952
+ vertical-align: middle;
2953
+ }
2954
+ .form-inline .radio label,
2955
+ .form-inline .checkbox label {
2956
+ padding-left: 0;
2957
+ }
2958
+ .form-inline .radio input[type="radio"],
2959
+ .form-inline .checkbox input[type="checkbox"] {
2960
+ position: relative;
2961
+ margin-left: 0;
2962
+ }
2963
+ .form-inline .has-feedback .form-control-feedback {
2964
+ top: 0;
2965
+ }
2966
+ }
2967
+ .form-horizontal .radio,
2968
+ .form-horizontal .checkbox,
2969
+ .form-horizontal .radio-inline,
2970
+ .form-horizontal .checkbox-inline {
2971
+ padding-top: 7px;
2972
+ margin-top: 0;
2973
+ margin-bottom: 0;
2974
+ }
2975
+ .form-horizontal .radio,
2976
+ .form-horizontal .checkbox {
2977
+ min-height: 27px;
2978
+ }
2979
+ .form-horizontal .form-group {
2980
+ margin-right: -15px;
2981
+ margin-left: -15px;
2982
+ }
2983
+ @media (min-width: 768px) {
2984
+ .form-horizontal .control-label {
2985
+ padding-top: 7px;
2986
+ margin-bottom: 0;
2987
+ text-align: right;
2988
+ }
2989
+ }
2990
+ .form-horizontal .has-feedback .form-control-feedback {
2991
+ right: 15px;
2992
+ }
2993
+ @media (min-width: 768px) {
2994
+ .form-horizontal .form-group-lg .control-label {
2995
+ padding-top: 11px;
2996
+ font-size: 18px;
2997
+ }
2998
+ }
2999
+ @media (min-width: 768px) {
3000
+ .form-horizontal .form-group-sm .control-label {
3001
+ padding-top: 6px;
3002
+ font-size: 12px;
3003
+ }
3004
+ }
3005
+ .btn {
3006
+ display: inline-block;
3007
+ padding: 6px 12px;
3008
+ margin-bottom: 0;
3009
+ font-size: 14px;
3010
+ font-weight: normal;
3011
+ line-height: 1.42857143;
3012
+ text-align: center;
3013
+ white-space: nowrap;
3014
+ vertical-align: middle;
3015
+ -ms-touch-action: manipulation;
3016
+ touch-action: manipulation;
3017
+ cursor: pointer;
3018
+ -webkit-user-select: none;
3019
+ -moz-user-select: none;
3020
+ -ms-user-select: none;
3021
+ user-select: none;
3022
+ background-image: none;
3023
+ border: 1px solid transparent;
3024
+ border-radius: 4px;
3025
+ }
3026
+ .btn:focus,
3027
+ .btn:active:focus,
3028
+ .btn.active:focus,
3029
+ .btn.focus,
3030
+ .btn:active.focus,
3031
+ .btn.active.focus {
3032
+ outline: thin dotted;
3033
+ outline: 5px auto -webkit-focus-ring-color;
3034
+ outline-offset: -2px;
3035
+ }
3036
+ .btn:hover,
3037
+ .btn:focus,
3038
+ .btn.focus {
3039
+ color: #333;
3040
+ text-decoration: none;
3041
+ }
3042
+ .btn:active,
3043
+ .btn.active {
3044
+ background-image: none;
3045
+ outline: 0;
3046
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
3047
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
3048
+ }
3049
+ .btn.disabled,
3050
+ .btn[disabled],
3051
+ fieldset[disabled] .btn {
3052
+ cursor: not-allowed;
3053
+ filter: alpha(opacity=65);
3054
+ -webkit-box-shadow: none;
3055
+ box-shadow: none;
3056
+ opacity: .65;
3057
+ }
3058
+ a.btn.disabled,
3059
+ fieldset[disabled] a.btn {
3060
+ pointer-events: none;
3061
+ }
3062
+ .btn-default {
3063
+ color: #333;
3064
+ background-color: #fff;
3065
+ border-color: #ccc;
3066
+ }
3067
+ .btn-default:focus,
3068
+ .btn-default.focus {
3069
+ color: #333;
3070
+ background-color: #e6e6e6;
3071
+ border-color: #8c8c8c;
3072
+ }
3073
+ .btn-default:hover {
3074
+ color: #333;
3075
+ background-color: #e6e6e6;
3076
+ border-color: #adadad;
3077
+ }
3078
+ .btn-default:active,
3079
+ .btn-default.active,
3080
+ .open > .dropdown-toggle.btn-default {
3081
+ color: #333;
3082
+ background-color: #e6e6e6;
3083
+ border-color: #adadad;
3084
+ }
3085
+ .btn-default:active:hover,
3086
+ .btn-default.active:hover,
3087
+ .open > .dropdown-toggle.btn-default:hover,
3088
+ .btn-default:active:focus,
3089
+ .btn-default.active:focus,
3090
+ .open > .dropdown-toggle.btn-default:focus,
3091
+ .btn-default:active.focus,
3092
+ .btn-default.active.focus,
3093
+ .open > .dropdown-toggle.btn-default.focus {
3094
+ color: #333;
3095
+ background-color: #d4d4d4;
3096
+ border-color: #8c8c8c;
3097
+ }
3098
+ .btn-default:active,
3099
+ .btn-default.active,
3100
+ .open > .dropdown-toggle.btn-default {
3101
+ background-image: none;
3102
+ }
3103
+ .btn-default.disabled:hover,
3104
+ .btn-default[disabled]:hover,
3105
+ fieldset[disabled] .btn-default:hover,
3106
+ .btn-default.disabled:focus,
3107
+ .btn-default[disabled]:focus,
3108
+ fieldset[disabled] .btn-default:focus,
3109
+ .btn-default.disabled.focus,
3110
+ .btn-default[disabled].focus,
3111
+ fieldset[disabled] .btn-default.focus {
3112
+ background-color: #fff;
3113
+ border-color: #ccc;
3114
+ }
3115
+ .btn-default .badge {
3116
+ color: #fff;
3117
+ background-color: #333;
3118
+ }
3119
+ .btn-primary {
3120
+ color: #fff;
3121
+ background-color: #337ab7;
3122
+ border-color: #2e6da4;
3123
+ }
3124
+ .btn-primary:focus,
3125
+ .btn-primary.focus {
3126
+ color: #fff;
3127
+ background-color: #286090;
3128
+ border-color: #122b40;
3129
+ }
3130
+ .btn-primary:hover {
3131
+ color: #fff;
3132
+ background-color: #286090;
3133
+ border-color: #204d74;
3134
+ }
3135
+ .btn-primary:active,
3136
+ .btn-primary.active,
3137
+ .open > .dropdown-toggle.btn-primary {
3138
+ color: #fff;
3139
+ background-color: #286090;
3140
+ border-color: #204d74;
3141
+ }
3142
+ .btn-primary:active:hover,
3143
+ .btn-primary.active:hover,
3144
+ .open > .dropdown-toggle.btn-primary:hover,
3145
+ .btn-primary:active:focus,
3146
+ .btn-primary.active:focus,
3147
+ .open > .dropdown-toggle.btn-primary:focus,
3148
+ .btn-primary:active.focus,
3149
+ .btn-primary.active.focus,
3150
+ .open > .dropdown-toggle.btn-primary.focus {
3151
+ color: #fff;
3152
+ background-color: #204d74;
3153
+ border-color: #122b40;
3154
+ }
3155
+ .btn-primary:active,
3156
+ .btn-primary.active,
3157
+ .open > .dropdown-toggle.btn-primary {
3158
+ background-image: none;
3159
+ }
3160
+ .btn-primary.disabled:hover,
3161
+ .btn-primary[disabled]:hover,
3162
+ fieldset[disabled] .btn-primary:hover,
3163
+ .btn-primary.disabled:focus,
3164
+ .btn-primary[disabled]:focus,
3165
+ fieldset[disabled] .btn-primary:focus,
3166
+ .btn-primary.disabled.focus,
3167
+ .btn-primary[disabled].focus,
3168
+ fieldset[disabled] .btn-primary.focus {
3169
+ background-color: #337ab7;
3170
+ border-color: #2e6da4;
3171
+ }
3172
+ .btn-primary .badge {
3173
+ color: #337ab7;
3174
+ background-color: #fff;
3175
+ }
3176
+ .btn-success {
3177
+ color: #fff;
3178
+ background-color: #5cb85c;
3179
+ border-color: #4cae4c;
3180
+ }
3181
+ .btn-success:focus,
3182
+ .btn-success.focus {
3183
+ color: #fff;
3184
+ background-color: #449d44;
3185
+ border-color: #255625;
3186
+ }
3187
+ .btn-success:hover {
3188
+ color: #fff;
3189
+ background-color: #449d44;
3190
+ border-color: #398439;
3191
+ }
3192
+ .btn-success:active,
3193
+ .btn-success.active,
3194
+ .open > .dropdown-toggle.btn-success {
3195
+ color: #fff;
3196
+ background-color: #449d44;
3197
+ border-color: #398439;
3198
+ }
3199
+ .btn-success:active:hover,
3200
+ .btn-success.active:hover,
3201
+ .open > .dropdown-toggle.btn-success:hover,
3202
+ .btn-success:active:focus,
3203
+ .btn-success.active:focus,
3204
+ .open > .dropdown-toggle.btn-success:focus,
3205
+ .btn-success:active.focus,
3206
+ .btn-success.active.focus,
3207
+ .open > .dropdown-toggle.btn-success.focus {
3208
+ color: #fff;
3209
+ background-color: #398439;
3210
+ border-color: #255625;
3211
+ }
3212
+ .btn-success:active,
3213
+ .btn-success.active,
3214
+ .open > .dropdown-toggle.btn-success {
3215
+ background-image: none;
3216
+ }
3217
+ .btn-success.disabled:hover,
3218
+ .btn-success[disabled]:hover,
3219
+ fieldset[disabled] .btn-success:hover,
3220
+ .btn-success.disabled:focus,
3221
+ .btn-success[disabled]:focus,
3222
+ fieldset[disabled] .btn-success:focus,
3223
+ .btn-success.disabled.focus,
3224
+ .btn-success[disabled].focus,
3225
+ fieldset[disabled] .btn-success.focus {
3226
+ background-color: #5cb85c;
3227
+ border-color: #4cae4c;
3228
+ }
3229
+ .btn-success .badge {
3230
+ color: #5cb85c;
3231
+ background-color: #fff;
3232
+ }
3233
+ .btn-info {
3234
+ color: #fff;
3235
+ background-color: #5bc0de;
3236
+ border-color: #46b8da;
3237
+ }
3238
+ .btn-info:focus,
3239
+ .btn-info.focus {
3240
+ color: #fff;
3241
+ background-color: #31b0d5;
3242
+ border-color: #1b6d85;
3243
+ }
3244
+ .btn-info:hover {
3245
+ color: #fff;
3246
+ background-color: #31b0d5;
3247
+ border-color: #269abc;
3248
+ }
3249
+ .btn-info:active,
3250
+ .btn-info.active,
3251
+ .open > .dropdown-toggle.btn-info {
3252
+ color: #fff;
3253
+ background-color: #31b0d5;
3254
+ border-color: #269abc;
3255
+ }
3256
+ .btn-info:active:hover,
3257
+ .btn-info.active:hover,
3258
+ .open > .dropdown-toggle.btn-info:hover,
3259
+ .btn-info:active:focus,
3260
+ .btn-info.active:focus,
3261
+ .open > .dropdown-toggle.btn-info:focus,
3262
+ .btn-info:active.focus,
3263
+ .btn-info.active.focus,
3264
+ .open > .dropdown-toggle.btn-info.focus {
3265
+ color: #fff;
3266
+ background-color: #269abc;
3267
+ border-color: #1b6d85;
3268
+ }
3269
+ .btn-info:active,
3270
+ .btn-info.active,
3271
+ .open > .dropdown-toggle.btn-info {
3272
+ background-image: none;
3273
+ }
3274
+ .btn-info.disabled:hover,
3275
+ .btn-info[disabled]:hover,
3276
+ fieldset[disabled] .btn-info:hover,
3277
+ .btn-info.disabled:focus,
3278
+ .btn-info[disabled]:focus,
3279
+ fieldset[disabled] .btn-info:focus,
3280
+ .btn-info.disabled.focus,
3281
+ .btn-info[disabled].focus,
3282
+ fieldset[disabled] .btn-info.focus {
3283
+ background-color: #5bc0de;
3284
+ border-color: #46b8da;
3285
+ }
3286
+ .btn-info .badge {
3287
+ color: #5bc0de;
3288
+ background-color: #fff;
3289
+ }
3290
+ .btn-warning {
3291
+ color: #fff;
3292
+ background-color: #f0ad4e;
3293
+ border-color: #eea236;
3294
+ }
3295
+ .btn-warning:focus,
3296
+ .btn-warning.focus {
3297
+ color: #fff;
3298
+ background-color: #ec971f;
3299
+ border-color: #985f0d;
3300
+ }
3301
+ .btn-warning:hover {
3302
+ color: #fff;
3303
+ background-color: #ec971f;
3304
+ border-color: #d58512;
3305
+ }
3306
+ .btn-warning:active,
3307
+ .btn-warning.active,
3308
+ .open > .dropdown-toggle.btn-warning {
3309
+ color: #fff;
3310
+ background-color: #ec971f;
3311
+ border-color: #d58512;
3312
+ }
3313
+ .btn-warning:active:hover,
3314
+ .btn-warning.active:hover,
3315
+ .open > .dropdown-toggle.btn-warning:hover,
3316
+ .btn-warning:active:focus,
3317
+ .btn-warning.active:focus,
3318
+ .open > .dropdown-toggle.btn-warning:focus,
3319
+ .btn-warning:active.focus,
3320
+ .btn-warning.active.focus,
3321
+ .open > .dropdown-toggle.btn-warning.focus {
3322
+ color: #fff;
3323
+ background-color: #d58512;
3324
+ border-color: #985f0d;
3325
+ }
3326
+ .btn-warning:active,
3327
+ .btn-warning.active,
3328
+ .open > .dropdown-toggle.btn-warning {
3329
+ background-image: none;
3330
+ }
3331
+ .btn-warning.disabled:hover,
3332
+ .btn-warning[disabled]:hover,
3333
+ fieldset[disabled] .btn-warning:hover,
3334
+ .btn-warning.disabled:focus,
3335
+ .btn-warning[disabled]:focus,
3336
+ fieldset[disabled] .btn-warning:focus,
3337
+ .btn-warning.disabled.focus,
3338
+ .btn-warning[disabled].focus,
3339
+ fieldset[disabled] .btn-warning.focus {
3340
+ background-color: #f0ad4e;
3341
+ border-color: #eea236;
3342
+ }
3343
+ .btn-warning .badge {
3344
+ color: #f0ad4e;
3345
+ background-color: #fff;
3346
+ }
3347
+ .btn-danger {
3348
+ color: #fff;
3349
+ background-color: #d9534f;
3350
+ border-color: #d43f3a;
3351
+ }
3352
+ .btn-danger:focus,
3353
+ .btn-danger.focus {
3354
+ color: #fff;
3355
+ background-color: #c9302c;
3356
+ border-color: #761c19;
3357
+ }
3358
+ .btn-danger:hover {
3359
+ color: #fff;
3360
+ background-color: #c9302c;
3361
+ border-color: #ac2925;
3362
+ }
3363
+ .btn-danger:active,
3364
+ .btn-danger.active,
3365
+ .open > .dropdown-toggle.btn-danger {
3366
+ color: #fff;
3367
+ background-color: #c9302c;
3368
+ border-color: #ac2925;
3369
+ }
3370
+ .btn-danger:active:hover,
3371
+ .btn-danger.active:hover,
3372
+ .open > .dropdown-toggle.btn-danger:hover,
3373
+ .btn-danger:active:focus,
3374
+ .btn-danger.active:focus,
3375
+ .open > .dropdown-toggle.btn-danger:focus,
3376
+ .btn-danger:active.focus,
3377
+ .btn-danger.active.focus,
3378
+ .open > .dropdown-toggle.btn-danger.focus {
3379
+ color: #fff;
3380
+ background-color: #ac2925;
3381
+ border-color: #761c19;
3382
+ }
3383
+ .btn-danger:active,
3384
+ .btn-danger.active,
3385
+ .open > .dropdown-toggle.btn-danger {
3386
+ background-image: none;
3387
+ }
3388
+ .btn-danger.disabled:hover,
3389
+ .btn-danger[disabled]:hover,
3390
+ fieldset[disabled] .btn-danger:hover,
3391
+ .btn-danger.disabled:focus,
3392
+ .btn-danger[disabled]:focus,
3393
+ fieldset[disabled] .btn-danger:focus,
3394
+ .btn-danger.disabled.focus,
3395
+ .btn-danger[disabled].focus,
3396
+ fieldset[disabled] .btn-danger.focus {
3397
+ background-color: #d9534f;
3398
+ border-color: #d43f3a;
3399
+ }
3400
+ .btn-danger .badge {
3401
+ color: #d9534f;
3402
+ background-color: #fff;
3403
+ }
3404
+ .btn-link {
3405
+ font-weight: normal;
3406
+ color: #337ab7;
3407
+ border-radius: 0;
3408
+ }
3409
+ .btn-link,
3410
+ .btn-link:active,
3411
+ .btn-link.active,
3412
+ .btn-link[disabled],
3413
+ fieldset[disabled] .btn-link {
3414
+ background-color: transparent;
3415
+ -webkit-box-shadow: none;
3416
+ box-shadow: none;
3417
+ }
3418
+ .btn-link,
3419
+ .btn-link:hover,
3420
+ .btn-link:focus,
3421
+ .btn-link:active {
3422
+ border-color: transparent;
3423
+ }
3424
+ .btn-link:hover,
3425
+ .btn-link:focus {
3426
+ color: #23527c;
3427
+ text-decoration: underline;
3428
+ background-color: transparent;
3429
+ }
3430
+ .btn-link[disabled]:hover,
3431
+ fieldset[disabled] .btn-link:hover,
3432
+ .btn-link[disabled]:focus,
3433
+ fieldset[disabled] .btn-link:focus {
3434
+ color: #777;
3435
+ text-decoration: none;
3436
+ }
3437
+ .btn-lg,
3438
+ .btn-group-lg > .btn {
3439
+ padding: 10px 16px;
3440
+ font-size: 18px;
3441
+ line-height: 1.3333333;
3442
+ border-radius: 6px;
3443
+ }
3444
+ .btn-sm,
3445
+ .btn-group-sm > .btn {
3446
+ padding: 5px 10px;
3447
+ font-size: 12px;
3448
+ line-height: 1.5;
3449
+ border-radius: 3px;
3450
+ }
3451
+ .btn-xs,
3452
+ .btn-group-xs > .btn {
3453
+ padding: 1px 5px;
3454
+ font-size: 12px;
3455
+ line-height: 1.5;
3456
+ border-radius: 3px;
3457
+ }
3458
+ .btn-block {
3459
+ display: block;
3460
+ width: 100%;
3461
+ }
3462
+ .btn-block + .btn-block {
3463
+ margin-top: 5px;
3464
+ }
3465
+ input[type="submit"].btn-block,
3466
+ input[type="reset"].btn-block,
3467
+ input[type="button"].btn-block {
3468
+ width: 100%;
3469
+ }
3470
+ .fade {
3471
+ opacity: 0;
3472
+ -webkit-transition: opacity .15s linear;
3473
+ -o-transition: opacity .15s linear;
3474
+ transition: opacity .15s linear;
3475
+ }
3476
+ .fade.in {
3477
+ opacity: 1;
3478
+ }
3479
+ .collapse {
3480
+ display: none;
3481
+ }
3482
+ .collapse.in {
3483
+ display: block;
3484
+ }
3485
+ tr.collapse.in {
3486
+ display: table-row;
3487
+ }
3488
+ tbody.collapse.in {
3489
+ display: table-row-group;
3490
+ }
3491
+ .collapsing {
3492
+ position: relative;
3493
+ height: 0;
3494
+ overflow: hidden;
3495
+ -webkit-transition-timing-function: ease;
3496
+ -o-transition-timing-function: ease;
3497
+ transition-timing-function: ease;
3498
+ -webkit-transition-duration: .35s;
3499
+ -o-transition-duration: .35s;
3500
+ transition-duration: .35s;
3501
+ -webkit-transition-property: height, visibility;
3502
+ -o-transition-property: height, visibility;
3503
+ transition-property: height, visibility;
3504
+ }
3505
+ .caret {
3506
+ display: inline-block;
3507
+ width: 0;
3508
+ height: 0;
3509
+ margin-left: 2px;
3510
+ vertical-align: middle;
3511
+ border-top: 4px dashed;
3512
+ border-top: 4px solid \9;
3513
+ border-right: 4px solid transparent;
3514
+ border-left: 4px solid transparent;
3515
+ }
3516
+ .dropup,
3517
+ .dropdown {
3518
+ position: relative;
3519
+ }
3520
+ .dropdown-toggle:focus {
3521
+ outline: 0;
3522
+ }
3523
+ .dropdown-menu {
3524
+ position: absolute;
3525
+ top: 100%;
3526
+ left: 0;
3527
+ z-index: 1000;
3528
+ display: none;
3529
+ float: left;
3530
+ min-width: 160px;
3531
+ padding: 5px 0;
3532
+ margin: 2px 0 0;
3533
+ font-size: 14px;
3534
+ text-align: left;
3535
+ list-style: none;
3536
+ background-color: #fff;
3537
+ -webkit-background-clip: padding-box;
3538
+ background-clip: padding-box;
3539
+ border: 1px solid #ccc;
3540
+ border: 1px solid rgba(0, 0, 0, .15);
3541
+ border-radius: 4px;
3542
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
3543
+ box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
3544
+ }
3545
+ .dropdown-menu.pull-right {
3546
+ right: 0;
3547
+ left: auto;
3548
+ }
3549
+ .dropdown-menu .divider {
3550
+ height: 1px;
3551
+ margin: 9px 0;
3552
+ overflow: hidden;
3553
+ background-color: #e5e5e5;
3554
+ }
3555
+ .dropdown-menu > li > a {
3556
+ display: block;
3557
+ padding: 3px 20px;
3558
+ clear: both;
3559
+ font-weight: normal;
3560
+ line-height: 1.42857143;
3561
+ color: #333;
3562
+ white-space: nowrap;
3563
+ }
3564
+ .dropdown-menu > li > a:hover,
3565
+ .dropdown-menu > li > a:focus {
3566
+ color: #262626;
3567
+ text-decoration: none;
3568
+ background-color: #f5f5f5;
3569
+ }
3570
+ .dropdown-menu > .active > a,
3571
+ .dropdown-menu > .active > a:hover,
3572
+ .dropdown-menu > .active > a:focus {
3573
+ color: #fff;
3574
+ text-decoration: none;
3575
+ background-color: #337ab7;
3576
+ outline: 0;
3577
+ }
3578
+ .dropdown-menu > .disabled > a,
3579
+ .dropdown-menu > .disabled > a:hover,
3580
+ .dropdown-menu > .disabled > a:focus {
3581
+ color: #777;
3582
+ }
3583
+ .dropdown-menu > .disabled > a:hover,
3584
+ .dropdown-menu > .disabled > a:focus {
3585
+ text-decoration: none;
3586
+ cursor: not-allowed;
3587
+ background-color: transparent;
3588
+ background-image: none;
3589
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
3590
+ }
3591
+ .open > .dropdown-menu {
3592
+ display: block;
3593
+ }
3594
+ .open > a {
3595
+ outline: 0;
3596
+ }
3597
+ .dropdown-menu-right {
3598
+ right: 0;
3599
+ left: auto;
3600
+ }
3601
+ .dropdown-menu-left {
3602
+ right: auto;
3603
+ left: 0;
3604
+ }
3605
+ .dropdown-header {
3606
+ display: block;
3607
+ padding: 3px 20px;
3608
+ font-size: 12px;
3609
+ line-height: 1.42857143;
3610
+ color: #777;
3611
+ white-space: nowrap;
3612
+ }
3613
+ .dropdown-backdrop {
3614
+ position: fixed;
3615
+ top: 0;
3616
+ right: 0;
3617
+ bottom: 0;
3618
+ left: 0;
3619
+ z-index: 990;
3620
+ }
3621
+ .pull-right > .dropdown-menu {
3622
+ right: 0;
3623
+ left: auto;
3624
+ }
3625
+ .dropup .caret,
3626
+ .navbar-fixed-bottom .dropdown .caret {
3627
+ content: "";
3628
+ border-top: 0;
3629
+ border-bottom: 4px dashed;
3630
+ border-bottom: 4px solid \9;
3631
+ }
3632
+ .dropup .dropdown-menu,
3633
+ .navbar-fixed-bottom .dropdown .dropdown-menu {
3634
+ top: auto;
3635
+ bottom: 100%;
3636
+ margin-bottom: 2px;
3637
+ }
3638
+ @media (min-width: 768px) {
3639
+ .navbar-right .dropdown-menu {
3640
+ right: 0;
3641
+ left: auto;
3642
+ }
3643
+ .navbar-right .dropdown-menu-left {
3644
+ right: auto;
3645
+ left: 0;
3646
+ }
3647
+ }
3648
+ .btn-group,
3649
+ .btn-group-vertical {
3650
+ position: relative;
3651
+ display: inline-block;
3652
+ vertical-align: middle;
3653
+ }
3654
+ .btn-group > .btn,
3655
+ .btn-group-vertical > .btn {
3656
+ position: relative;
3657
+ float: left;
3658
+ }
3659
+ .btn-group > .btn:hover,
3660
+ .btn-group-vertical > .btn:hover,
3661
+ .btn-group > .btn:focus,
3662
+ .btn-group-vertical > .btn:focus,
3663
+ .btn-group > .btn:active,
3664
+ .btn-group-vertical > .btn:active,
3665
+ .btn-group > .btn.active,
3666
+ .btn-group-vertical > .btn.active {
3667
+ z-index: 2;
3668
+ }
3669
+ .btn-group .btn + .btn,
3670
+ .btn-group .btn + .btn-group,
3671
+ .btn-group .btn-group + .btn,
3672
+ .btn-group .btn-group + .btn-group {
3673
+ margin-left: -1px;
3674
+ }
3675
+ .btn-toolbar {
3676
+ margin-left: -5px;
3677
+ }
3678
+ .btn-toolbar .btn,
3679
+ .btn-toolbar .btn-group,
3680
+ .btn-toolbar .input-group {
3681
+ float: left;
3682
+ }
3683
+ .btn-toolbar > .btn,
3684
+ .btn-toolbar > .btn-group,
3685
+ .btn-toolbar > .input-group {
3686
+ margin-left: 5px;
3687
+ }
3688
+ .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
3689
+ border-radius: 0;
3690
+ }
3691
+ .btn-group > .btn:first-child {
3692
+ margin-left: 0;
3693
+ }
3694
+ .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
3695
+ border-top-right-radius: 0;
3696
+ border-bottom-right-radius: 0;
3697
+ }
3698
+ .btn-group > .btn:last-child:not(:first-child),
3699
+ .btn-group > .dropdown-toggle:not(:first-child) {
3700
+ border-top-left-radius: 0;
3701
+ border-bottom-left-radius: 0;
3702
+ }
3703
+ .btn-group > .btn-group {
3704
+ float: left;
3705
+ }
3706
+ .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
3707
+ border-radius: 0;
3708
+ }
3709
+ .btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
3710
+ .btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
3711
+ border-top-right-radius: 0;
3712
+ border-bottom-right-radius: 0;
3713
+ }
3714
+ .btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
3715
+ border-top-left-radius: 0;
3716
+ border-bottom-left-radius: 0;
3717
+ }
3718
+ .btn-group .dropdown-toggle:active,
3719
+ .btn-group.open .dropdown-toggle {
3720
+ outline: 0;
3721
+ }
3722
+ .btn-group > .btn + .dropdown-toggle {
3723
+ padding-right: 8px;
3724
+ padding-left: 8px;
3725
+ }
3726
+ .btn-group > .btn-lg + .dropdown-toggle {
3727
+ padding-right: 12px;
3728
+ padding-left: 12px;
3729
+ }
3730
+ .btn-group.open .dropdown-toggle {
3731
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
3732
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
3733
+ }
3734
+ .btn-group.open .dropdown-toggle.btn-link {
3735
+ -webkit-box-shadow: none;
3736
+ box-shadow: none;
3737
+ }
3738
+ .btn .caret {
3739
+ margin-left: 0;
3740
+ }
3741
+ .btn-lg .caret {
3742
+ border-width: 5px 5px 0;
3743
+ border-bottom-width: 0;
3744
+ }
3745
+ .dropup .btn-lg .caret {
3746
+ border-width: 0 5px 5px;
3747
+ }
3748
+ .btn-group-vertical > .btn,
3749
+ .btn-group-vertical > .btn-group,
3750
+ .btn-group-vertical > .btn-group > .btn {
3751
+ display: block;
3752
+ float: none;
3753
+ width: 100%;
3754
+ max-width: 100%;
3755
+ }
3756
+ .btn-group-vertical > .btn-group > .btn {
3757
+ float: none;
3758
+ }
3759
+ .btn-group-vertical > .btn + .btn,
3760
+ .btn-group-vertical > .btn + .btn-group,
3761
+ .btn-group-vertical > .btn-group + .btn,
3762
+ .btn-group-vertical > .btn-group + .btn-group {
3763
+ margin-top: -1px;
3764
+ margin-left: 0;
3765
+ }
3766
+ .btn-group-vertical > .btn:not(:first-child):not(:last-child) {
3767
+ border-radius: 0;
3768
+ }
3769
+ .btn-group-vertical > .btn:first-child:not(:last-child) {
3770
+ border-top-left-radius: 4px;
3771
+ border-top-right-radius: 4px;
3772
+ border-bottom-right-radius: 0;
3773
+ border-bottom-left-radius: 0;
3774
+ }
3775
+ .btn-group-vertical > .btn:last-child:not(:first-child) {
3776
+ border-top-left-radius: 0;
3777
+ border-top-right-radius: 0;
3778
+ border-bottom-right-radius: 4px;
3779
+ border-bottom-left-radius: 4px;
3780
+ }
3781
+ .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
3782
+ border-radius: 0;
3783
+ }
3784
+ .btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
3785
+ .btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
3786
+ border-bottom-right-radius: 0;
3787
+ border-bottom-left-radius: 0;
3788
+ }
3789
+ .btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
3790
+ border-top-left-radius: 0;
3791
+ border-top-right-radius: 0;
3792
+ }
3793
+ .btn-group-justified {
3794
+ display: table;
3795
+ width: 100%;
3796
+ table-layout: fixed;
3797
+ border-collapse: separate;
3798
+ }
3799
+ .btn-group-justified > .btn,
3800
+ .btn-group-justified > .btn-group {
3801
+ display: table-cell;
3802
+ float: none;
3803
+ width: 1%;
3804
+ }
3805
+ .btn-group-justified > .btn-group .btn {
3806
+ width: 100%;
3807
+ }
3808
+ .btn-group-justified > .btn-group .dropdown-menu {
3809
+ left: auto;
3810
+ }
3811
+ [data-toggle="buttons"] > .btn input[type="radio"],
3812
+ [data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
3813
+ [data-toggle="buttons"] > .btn input[type="checkbox"],
3814
+ [data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
3815
+ position: absolute;
3816
+ clip: rect(0, 0, 0, 0);
3817
+ pointer-events: none;
3818
+ }
3819
+ .input-group {
3820
+ position: relative;
3821
+ display: table;
3822
+ border-collapse: separate;
3823
+ }
3824
+ .input-group[class*="col-"] {
3825
+ float: none;
3826
+ padding-right: 0;
3827
+ padding-left: 0;
3828
+ }
3829
+ .input-group .form-control {
3830
+ position: relative;
3831
+ z-index: 2;
3832
+ float: left;
3833
+ width: 100%;
3834
+ margin-bottom: 0;
3835
+ }
3836
+ .input-group .form-control:focus {
3837
+ z-index: 3;
3838
+ }
3839
+ .input-group-lg > .form-control,
3840
+ .input-group-lg > .input-group-addon,
3841
+ .input-group-lg > .input-group-btn > .btn {
3842
+ height: 46px;
3843
+ padding: 10px 16px;
3844
+ font-size: 18px;
3845
+ line-height: 1.3333333;
3846
+ border-radius: 6px;
3847
+ }
3848
+ select.input-group-lg > .form-control,
3849
+ select.input-group-lg > .input-group-addon,
3850
+ select.input-group-lg > .input-group-btn > .btn {
3851
+ height: 46px;
3852
+ line-height: 46px;
3853
+ }
3854
+ textarea.input-group-lg > .form-control,
3855
+ textarea.input-group-lg > .input-group-addon,
3856
+ textarea.input-group-lg > .input-group-btn > .btn,
3857
+ select[multiple].input-group-lg > .form-control,
3858
+ select[multiple].input-group-lg > .input-group-addon,
3859
+ select[multiple].input-group-lg > .input-group-btn > .btn {
3860
+ height: auto;
3861
+ }
3862
+ .input-group-sm > .form-control,
3863
+ .input-group-sm > .input-group-addon,
3864
+ .input-group-sm > .input-group-btn > .btn {
3865
+ height: 30px;
3866
+ padding: 5px 10px;
3867
+ font-size: 12px;
3868
+ line-height: 1.5;
3869
+ border-radius: 3px;
3870
+ }
3871
+ select.input-group-sm > .form-control,
3872
+ select.input-group-sm > .input-group-addon,
3873
+ select.input-group-sm > .input-group-btn > .btn {
3874
+ height: 30px;
3875
+ line-height: 30px;
3876
+ }
3877
+ textarea.input-group-sm > .form-control,
3878
+ textarea.input-group-sm > .input-group-addon,
3879
+ textarea.input-group-sm > .input-group-btn > .btn,
3880
+ select[multiple].input-group-sm > .form-control,
3881
+ select[multiple].input-group-sm > .input-group-addon,
3882
+ select[multiple].input-group-sm > .input-group-btn > .btn {
3883
+ height: auto;
3884
+ }
3885
+ .input-group-addon,
3886
+ .input-group-btn,
3887
+ .input-group .form-control {
3888
+ display: table-cell;
3889
+ }
3890
+ .input-group-addon:not(:first-child):not(:last-child),
3891
+ .input-group-btn:not(:first-child):not(:last-child),
3892
+ .input-group .form-control:not(:first-child):not(:last-child) {
3893
+ border-radius: 0;
3894
+ }
3895
+ .input-group-addon,
3896
+ .input-group-btn {
3897
+ width: 1%;
3898
+ white-space: nowrap;
3899
+ vertical-align: middle;
3900
+ }
3901
+ .input-group-addon {
3902
+ padding: 6px 12px;
3903
+ font-size: 14px;
3904
+ font-weight: normal;
3905
+ line-height: 1;
3906
+ color: #555;
3907
+ text-align: center;
3908
+ background-color: #eee;
3909
+ border: 1px solid #ccc;
3910
+ border-radius: 4px;
3911
+ }
3912
+ .input-group-addon.input-sm {
3913
+ padding: 5px 10px;
3914
+ font-size: 12px;
3915
+ border-radius: 3px;
3916
+ }
3917
+ .input-group-addon.input-lg {
3918
+ padding: 10px 16px;
3919
+ font-size: 18px;
3920
+ border-radius: 6px;
3921
+ }
3922
+ .input-group-addon input[type="radio"],
3923
+ .input-group-addon input[type="checkbox"] {
3924
+ margin-top: 0;
3925
+ }
3926
+ .input-group .form-control:first-child,
3927
+ .input-group-addon:first-child,
3928
+ .input-group-btn:first-child > .btn,
3929
+ .input-group-btn:first-child > .btn-group > .btn,
3930
+ .input-group-btn:first-child > .dropdown-toggle,
3931
+ .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
3932
+ .input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
3933
+ border-top-right-radius: 0;
3934
+ border-bottom-right-radius: 0;
3935
+ }
3936
+ .input-group-addon:first-child {
3937
+ border-right: 0;
3938
+ }
3939
+ .input-group .form-control:last-child,
3940
+ .input-group-addon:last-child,
3941
+ .input-group-btn:last-child > .btn,
3942
+ .input-group-btn:last-child > .btn-group > .btn,
3943
+ .input-group-btn:last-child > .dropdown-toggle,
3944
+ .input-group-btn:first-child > .btn:not(:first-child),
3945
+ .input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
3946
+ border-top-left-radius: 0;
3947
+ border-bottom-left-radius: 0;
3948
+ }
3949
+ .input-group-addon:last-child {
3950
+ border-left: 0;
3951
+ }
3952
+ .input-group-btn {
3953
+ position: relative;
3954
+ font-size: 0;
3955
+ white-space: nowrap;
3956
+ }
3957
+ .input-group-btn > .btn {
3958
+ position: relative;
3959
+ }
3960
+ .input-group-btn > .btn + .btn {
3961
+ margin-left: -1px;
3962
+ }
3963
+ .input-group-btn > .btn:hover,
3964
+ .input-group-btn > .btn:focus,
3965
+ .input-group-btn > .btn:active {
3966
+ z-index: 2;
3967
+ }
3968
+ .input-group-btn:first-child > .btn,
3969
+ .input-group-btn:first-child > .btn-group {
3970
+ margin-right: -1px;
3971
+ }
3972
+ .input-group-btn:last-child > .btn,
3973
+ .input-group-btn:last-child > .btn-group {
3974
+ z-index: 2;
3975
+ margin-left: -1px;
3976
+ }
3977
+ .nav {
3978
+ padding-left: 0;
3979
+ margin-bottom: 0;
3980
+ list-style: none;
3981
+ }
3982
+ .nav > li {
3983
+ position: relative;
3984
+ display: block;
3985
+ }
3986
+ .nav > li > a {
3987
+ position: relative;
3988
+ display: block;
3989
+ padding: 10px 15px;
3990
+ }
3991
+ .nav > li > a:hover,
3992
+ .nav > li > a:focus {
3993
+ text-decoration: none;
3994
+ background-color: #eee;
3995
+ }
3996
+ .nav > li.disabled > a {
3997
+ color: #777;
3998
+ }
3999
+ .nav > li.disabled > a:hover,
4000
+ .nav > li.disabled > a:focus {
4001
+ color: #777;
4002
+ text-decoration: none;
4003
+ cursor: not-allowed;
4004
+ background-color: transparent;
4005
+ }
4006
+ .nav .open > a,
4007
+ .nav .open > a:hover,
4008
+ .nav .open > a:focus {
4009
+ background-color: #eee;
4010
+ border-color: #337ab7;
4011
+ }
4012
+ .nav .nav-divider {
4013
+ height: 1px;
4014
+ margin: 9px 0;
4015
+ overflow: hidden;
4016
+ background-color: #e5e5e5;
4017
+ }
4018
+ .nav > li > a > img {
4019
+ max-width: none;
4020
+ }
4021
+ .nav-tabs {
4022
+ border-bottom: 1px solid #ddd;
4023
+ }
4024
+ .nav-tabs > li {
4025
+ float: left;
4026
+ margin-bottom: -1px;
4027
+ }
4028
+ .nav-tabs > li > a {
4029
+ margin-right: 2px;
4030
+ line-height: 1.42857143;
4031
+ border: 1px solid transparent;
4032
+ border-radius: 4px 4px 0 0;
4033
+ }
4034
+ .nav-tabs > li > a:hover {
4035
+ border-color: #eee #eee #ddd;
4036
+ }
4037
+ .nav-tabs > li.active > a,
4038
+ .nav-tabs > li.active > a:hover,
4039
+ .nav-tabs > li.active > a:focus {
4040
+ color: #555;
4041
+ cursor: default;
4042
+ background-color: #fff;
4043
+ border: 1px solid #ddd;
4044
+ border-bottom-color: transparent;
4045
+ }
4046
+ .nav-tabs.nav-justified {
4047
+ width: 100%;
4048
+ border-bottom: 0;
4049
+ }
4050
+ .nav-tabs.nav-justified > li {
4051
+ float: none;
4052
+ }
4053
+ .nav-tabs.nav-justified > li > a {
4054
+ margin-bottom: 5px;
4055
+ text-align: center;
4056
+ }
4057
+ .nav-tabs.nav-justified > .dropdown .dropdown-menu {
4058
+ top: auto;
4059
+ left: auto;
4060
+ }
4061
+ @media (min-width: 768px) {
4062
+ .nav-tabs.nav-justified > li {
4063
+ display: table-cell;
4064
+ width: 1%;
4065
+ }
4066
+ .nav-tabs.nav-justified > li > a {
4067
+ margin-bottom: 0;
4068
+ }
4069
+ }
4070
+ .nav-tabs.nav-justified > li > a {
4071
+ margin-right: 0;
4072
+ border-radius: 4px;
4073
+ }
4074
+ .nav-tabs.nav-justified > .active > a,
4075
+ .nav-tabs.nav-justified > .active > a:hover,
4076
+ .nav-tabs.nav-justified > .active > a:focus {
4077
+ border: 1px solid #ddd;
4078
+ }
4079
+ @media (min-width: 768px) {
4080
+ .nav-tabs.nav-justified > li > a {
4081
+ border-bottom: 1px solid #ddd;
4082
+ border-radius: 4px 4px 0 0;
4083
+ }
4084
+ .nav-tabs.nav-justified > .active > a,
4085
+ .nav-tabs.nav-justified > .active > a:hover,
4086
+ .nav-tabs.nav-justified > .active > a:focus {
4087
+ border-bottom-color: #fff;
4088
+ }
4089
+ }
4090
+ .nav-pills > li {
4091
+ float: left;
4092
+ }
4093
+ .nav-pills > li > a {
4094
+ border-radius: 4px;
4095
+ }
4096
+ .nav-pills > li + li {
4097
+ margin-left: 2px;
4098
+ }
4099
+ .nav-pills > li.active > a,
4100
+ .nav-pills > li.active > a:hover,
4101
+ .nav-pills > li.active > a:focus {
4102
+ color: #fff;
4103
+ background-color: #337ab7;
4104
+ }
4105
+ .nav-stacked > li {
4106
+ float: none;
4107
+ }
4108
+ .nav-stacked > li + li {
4109
+ margin-top: 2px;
4110
+ margin-left: 0;
4111
+ }
4112
+ .nav-justified {
4113
+ width: 100%;
4114
+ }
4115
+ .nav-justified > li {
4116
+ float: none;
4117
+ }
4118
+ .nav-justified > li > a {
4119
+ margin-bottom: 5px;
4120
+ text-align: center;
4121
+ }
4122
+ .nav-justified > .dropdown .dropdown-menu {
4123
+ top: auto;
4124
+ left: auto;
4125
+ }
4126
+ @media (min-width: 768px) {
4127
+ .nav-justified > li {
4128
+ display: table-cell;
4129
+ width: 1%;
4130
+ }
4131
+ .nav-justified > li > a {
4132
+ margin-bottom: 0;
4133
+ }
4134
+ }
4135
+ .nav-tabs-justified {
4136
+ border-bottom: 0;
4137
+ }
4138
+ .nav-tabs-justified > li > a {
4139
+ margin-right: 0;
4140
+ border-radius: 4px;
4141
+ }
4142
+ .nav-tabs-justified > .active > a,
4143
+ .nav-tabs-justified > .active > a:hover,
4144
+ .nav-tabs-justified > .active > a:focus {
4145
+ border: 1px solid #ddd;
4146
+ }
4147
+ @media (min-width: 768px) {
4148
+ .nav-tabs-justified > li > a {
4149
+ border-bottom: 1px solid #ddd;
4150
+ border-radius: 4px 4px 0 0;
4151
+ }
4152
+ .nav-tabs-justified > .active > a,
4153
+ .nav-tabs-justified > .active > a:hover,
4154
+ .nav-tabs-justified > .active > a:focus {
4155
+ border-bottom-color: #fff;
4156
+ }
4157
+ }
4158
+ .tab-content > .tab-pane {
4159
+ display: none;
4160
+ }
4161
+ .tab-content > .active {
4162
+ display: block;
4163
+ }
4164
+ .nav-tabs .dropdown-menu {
4165
+ margin-top: -1px;
4166
+ border-top-left-radius: 0;
4167
+ border-top-right-radius: 0;
4168
+ }
4169
+ .navbar {
4170
+ position: relative;
4171
+ min-height: 50px;
4172
+ margin-bottom: 20px;
4173
+ border: 1px solid transparent;
4174
+ }
4175
+ @media (min-width: 768px) {
4176
+ .navbar {
4177
+ border-radius: 4px;
4178
+ }
4179
+ }
4180
+ @media (min-width: 768px) {
4181
+ .navbar-header {
4182
+ float: left;
4183
+ }
4184
+ }
4185
+ .navbar-collapse {
4186
+ padding-right: 15px;
4187
+ padding-left: 15px;
4188
+ overflow-x: visible;
4189
+ -webkit-overflow-scrolling: touch;
4190
+ border-top: 1px solid transparent;
4191
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
4192
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
4193
+ }
4194
+ .navbar-collapse.in {
4195
+ overflow-y: auto;
4196
+ }
4197
+ @media (min-width: 768px) {
4198
+ .navbar-collapse {
4199
+ width: auto;
4200
+ border-top: 0;
4201
+ -webkit-box-shadow: none;
4202
+ box-shadow: none;
4203
+ }
4204
+ .navbar-collapse.collapse {
4205
+ display: block !important;
4206
+ height: auto !important;
4207
+ padding-bottom: 0;
4208
+ overflow: visible !important;
4209
+ }
4210
+ .navbar-collapse.in {
4211
+ overflow-y: visible;
4212
+ }
4213
+ .navbar-fixed-top .navbar-collapse,
4214
+ .navbar-static-top .navbar-collapse,
4215
+ .navbar-fixed-bottom .navbar-collapse {
4216
+ padding-right: 0;
4217
+ padding-left: 0;
4218
+ }
4219
+ }
4220
+ .navbar-fixed-top .navbar-collapse,
4221
+ .navbar-fixed-bottom .navbar-collapse {
4222
+ max-height: 340px;
4223
+ }
4224
+ @media (max-device-width: 480px) and (orientation: landscape) {
4225
+ .navbar-fixed-top .navbar-collapse,
4226
+ .navbar-fixed-bottom .navbar-collapse {
4227
+ max-height: 200px;
4228
+ }
4229
+ }
4230
+ .container > .navbar-header,
4231
+ .container-fluid > .navbar-header,
4232
+ .container > .navbar-collapse,
4233
+ .container-fluid > .navbar-collapse {
4234
+ margin-right: -15px;
4235
+ margin-left: -15px;
4236
+ }
4237
+ @media (min-width: 768px) {
4238
+ .container > .navbar-header,
4239
+ .container-fluid > .navbar-header,
4240
+ .container > .navbar-collapse,
4241
+ .container-fluid > .navbar-collapse {
4242
+ margin-right: 0;
4243
+ margin-left: 0;
4244
+ }
4245
+ }
4246
+ .navbar-static-top {
4247
+ z-index: 1000;
4248
+ border-width: 0 0 1px;
4249
+ }
4250
+ @media (min-width: 768px) {
4251
+ .navbar-static-top {
4252
+ border-radius: 0;
4253
+ }
4254
+ }
4255
+ .navbar-fixed-top,
4256
+ .navbar-fixed-bottom {
4257
+ position: fixed;
4258
+ right: 0;
4259
+ left: 0;
4260
+ z-index: 1030;
4261
+ }
4262
+ @media (min-width: 768px) {
4263
+ .navbar-fixed-top,
4264
+ .navbar-fixed-bottom {
4265
+ border-radius: 0;
4266
+ }
4267
+ }
4268
+ .navbar-fixed-top {
4269
+ top: 0;
4270
+ border-width: 0 0 1px;
4271
+ }
4272
+ .navbar-fixed-bottom {
4273
+ bottom: 0;
4274
+ margin-bottom: 0;
4275
+ border-width: 1px 0 0;
4276
+ }
4277
+ .navbar-brand {
4278
+ float: left;
4279
+ height: 50px;
4280
+ padding: 15px 15px;
4281
+ font-size: 18px;
4282
+ line-height: 20px;
4283
+ }
4284
+ .navbar-brand:hover,
4285
+ .navbar-brand:focus {
4286
+ text-decoration: none;
4287
+ }
4288
+ .navbar-brand > img {
4289
+ display: block;
4290
+ }
4291
+ @media (min-width: 768px) {
4292
+ .navbar > .container .navbar-brand,
4293
+ .navbar > .container-fluid .navbar-brand {
4294
+ margin-left: -15px;
4295
+ }
4296
+ }
4297
+ .navbar-toggle {
4298
+ position: relative;
4299
+ float: right;
4300
+ padding: 9px 10px;
4301
+ margin-top: 8px;
4302
+ margin-right: 15px;
4303
+ margin-bottom: 8px;
4304
+ background-color: transparent;
4305
+ background-image: none;
4306
+ border: 1px solid transparent;
4307
+ border-radius: 4px;
4308
+ }
4309
+ .navbar-toggle:focus {
4310
+ outline: 0;
4311
+ }
4312
+ .navbar-toggle .icon-bar {
4313
+ display: block;
4314
+ width: 22px;
4315
+ height: 2px;
4316
+ border-radius: 1px;
4317
+ }
4318
+ .navbar-toggle .icon-bar + .icon-bar {
4319
+ margin-top: 4px;
4320
+ }
4321
+ @media (min-width: 768px) {
4322
+ .navbar-toggle {
4323
+ display: none;
4324
+ }
4325
+ }
4326
+ .navbar-nav {
4327
+ margin: 7.5px -15px;
4328
+ }
4329
+ .navbar-nav > li > a {
4330
+ padding-top: 10px;
4331
+ padding-bottom: 10px;
4332
+ line-height: 20px;
4333
+ }
4334
+ @media (max-width: 767px) {
4335
+ .navbar-nav .open .dropdown-menu {
4336
+ position: static;
4337
+ float: none;
4338
+ width: auto;
4339
+ margin-top: 0;
4340
+ background-color: transparent;
4341
+ border: 0;
4342
+ -webkit-box-shadow: none;
4343
+ box-shadow: none;
4344
+ }
4345
+ .navbar-nav .open .dropdown-menu > li > a,
4346
+ .navbar-nav .open .dropdown-menu .dropdown-header {
4347
+ padding: 5px 15px 5px 25px;
4348
+ }
4349
+ .navbar-nav .open .dropdown-menu > li > a {
4350
+ line-height: 20px;
4351
+ }
4352
+ .navbar-nav .open .dropdown-menu > li > a:hover,
4353
+ .navbar-nav .open .dropdown-menu > li > a:focus {
4354
+ background-image: none;
4355
+ }
4356
+ }
4357
+ @media (min-width: 768px) {
4358
+ .navbar-nav {
4359
+ float: left;
4360
+ margin: 0;
4361
+ }
4362
+ .navbar-nav > li {
4363
+ float: left;
4364
+ }
4365
+ .navbar-nav > li > a {
4366
+ padding-top: 15px;
4367
+ padding-bottom: 15px;
4368
+ }
4369
+ }
4370
+ .navbar-form {
4371
+ padding: 10px 15px;
4372
+ margin-top: 8px;
4373
+ margin-right: -15px;
4374
+ margin-bottom: 8px;
4375
+ margin-left: -15px;
4376
+ border-top: 1px solid transparent;
4377
+ border-bottom: 1px solid transparent;
4378
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
4379
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
4380
+ }
4381
+ @media (min-width: 768px) {
4382
+ .navbar-form .form-group {
4383
+ display: inline-block;
4384
+ margin-bottom: 0;
4385
+ vertical-align: middle;
4386
+ }
4387
+ .navbar-form .form-control {
4388
+ display: inline-block;
4389
+ width: auto;
4390
+ vertical-align: middle;
4391
+ }
4392
+ .navbar-form .form-control-static {
4393
+ display: inline-block;
4394
+ }
4395
+ .navbar-form .input-group {
4396
+ display: inline-table;
4397
+ vertical-align: middle;
4398
+ }
4399
+ .navbar-form .input-group .input-group-addon,
4400
+ .navbar-form .input-group .input-group-btn,
4401
+ .navbar-form .input-group .form-control {
4402
+ width: auto;
4403
+ }
4404
+ .navbar-form .input-group > .form-control {
4405
+ width: 100%;
4406
+ }
4407
+ .navbar-form .control-label {
4408
+ margin-bottom: 0;
4409
+ vertical-align: middle;
4410
+ }
4411
+ .navbar-form .radio,
4412
+ .navbar-for