├── .gitignore
├── README.md
├── config.php
├── controller.php
├── framework.php
├── functions.php
├── i18n
    ├── README.md
    ├── fr_FR
    │   └── LC_MESSAGES
    │   │   ├── localization.mo
    │   │   └── localization.po
    └── localization.pot
├── index.php
├── lib
    ├── limonade.php
    ├── limonade
    │   ├── abstract.php
    │   ├── assertions.php
    │   ├── public
    │   │   ├── css
    │   │   │   └── screen.css
    │   │   └── img
    │   │   │   └── bg_header.png
    │   ├── tests.php
    │   └── views
    │   │   ├── _debug.html.php
    │   │   ├── _notices.html.php
    │   │   ├── default_layout.php
    │   │   └── error.html.php
    └── unix_func.php
├── public
    ├── bootstrap
    │   ├── css
    │   │   ├── bootstrap-theme.css
    │   │   ├── bootstrap-theme.css.map
    │   │   ├── bootstrap-theme.min.css
    │   │   ├── bootstrap.css
    │   │   ├── bootstrap.css.map
    │   │   └── bootstrap.min.css
    │   ├── fonts
    │   │   ├── glyphicons-halflings-regular.eot
    │   │   ├── glyphicons-halflings-regular.svg
    │   │   ├── glyphicons-halflings-regular.ttf
    │   │   └── glyphicons-halflings-regular.woff
    │   └── js
    │   │   ├── bootstrap.js
    │   │   ├── bootstrap.min.js
    │   │   └── npm.js
    ├── chat
    │   └── .gitfile
    ├── css
    │   ├── contextMenu.css
    │   ├── filedrop.css
    │   └── style.css
    ├── img
    │   ├── extensions
    │   │   ├── archive.png
    │   │   ├── audio.png
    │   │   ├── authors.png
    │   │   ├── bin.png
    │   │   ├── blank.png
    │   │   ├── bmp.png
    │   │   ├── c.png
    │   │   ├── calc.png
    │   │   ├── cd.png
    │   │   ├── copying.png
    │   │   ├── cpp.png
    │   │   ├── css.png
    │   │   ├── deb.png
    │   │   ├── default.png
    │   │   ├── doc.png
    │   │   ├── draw.png
    │   │   ├── eps.png
    │   │   ├── exe.png
    │   │   ├── folder-home.png
    │   │   ├── folder-open.png
    │   │   ├── folder-page.png
    │   │   ├── folder-parent.png
    │   │   ├── gif.png
    │   │   ├── gzip.png
    │   │   ├── h.png
    │   │   ├── hpp.png
    │   │   ├── html.png
    │   │   ├── ico.png
    │   │   ├── image.png
    │   │   ├── install.png
    │   │   ├── java.png
    │   │   ├── jpg.png
    │   │   ├── js.png
    │   │   ├── log.png
    │   │   ├── makefile.png
    │   │   ├── package.png
    │   │   ├── pdf.png
    │   │   ├── php.png
    │   │   ├── playlist.png
    │   │   ├── png.png
    │   │   ├── pres.png
    │   │   ├── psd.png
    │   │   ├── py.png
    │   │   ├── rar.png
    │   │   ├── rb.png
    │   │   ├── readme.png
    │   │   ├── rpm.png
    │   │   ├── rss.png
    │   │   ├── rtf.png
    │   │   ├── script.png
    │   │   ├── source.png
    │   │   ├── sql.png
    │   │   ├── svg.png
    │   │   ├── tar.png
    │   │   ├── tex.png
    │   │   ├── tiff.png
    │   │   ├── txt.png
    │   │   ├── unknown.png
    │   │   ├── vcal.png
    │   │   ├── video.png
    │   │   ├── xml.png
    │   │   └── zip.png
    │   ├── github.png
    │   └── loading.gif
    ├── jquery
    │   ├── jquery-2.1.1.min.js
    │   └── jquery.ui.position.js
    ├── js
    │   ├── contextMenu.js
    │   ├── events.js
    │   ├── filedrop.min.js
    │   └── functions.js
    └── uploads
    │   └── .gitfile
├── screenshots
    ├── piratebox1.png
    ├── piratebox10.png
    ├── piratebox2.png
    ├── piratebox3.png
    ├── piratebox4.png
    ├── piratebox5.png
    ├── piratebox6.png
    ├── piratebox7.png
    ├── piratebox8.png
    └── piratebox9.png
└── views
    ├── _file.html.php
    ├── _folder.html.php
    ├── home.html.php
    └── layout.html.php
/.gitignore:
--------------------------------------------------------------------------------
1 | config.php
2 | public/uploads/*
3 | public/chat/*
4 | *.swp
5 | 
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | # php-piratebox
  2 | ## Project
  3 | 
  4 | A PirateBox is an anonymous offline file-sharing communications system, according to the [PirateBox project](http://www.piratebox.cc).
  5 | 
  6 | This project is just a powerful web interface, conceived in this spirit. You can use it on any hardware configured with an HTTP server and a PHP backend.
  7 | 
  8 | If you want to use it like a real PirateBox, you need to configure a wifi hotspot with a captive portal redirecting all web requests on it. For example, this project is also available as a [YunoHost](http://yunohost.org) application for this purpose. Thus, installing the [corresponding Yunohost application](https://github.com/labriqueinternet/piratebox_ynh) sets up all the necessary stuff for you, including the HTTP/PHP server side configurations. This last was integrated in the "[La Brique Internet](http://labriqueinter.net)" project.
  9 | 
 10 | This project is not affiliated with the official PirateBox project.
 11 | 
 12 | ## Features
 13 | ### Overview
 14 | 
 15 | * File-sharing without authentication
 16 | * Integrated web chat (can be disabled)
 17 | * Drag and drop supported with multiple files
 18 | * Folders browsing
 19 | * Pinned files or folders (marked with a star and cannot be deleted nor renamed)
 20 | * Free folders creation (can be disabled)
 21 | * Free files and folders renaming (can be disabled)
 22 | * Free files and (empty) folders deleting (can be disabled)
 23 | * Fancy URLs (can be disabled)
 24 | * Keyboard shortcuts and context menus
 25 | * Full AJAX with direct URLs and browser history
 26 | * Do not require a database
 27 | * Completely translatable with gettext
 28 | * Responsive design (mobile-friendly)
 29 | 
 30 | Some [screenshots](#screenshots) are available.
 31 | 
 32 | ### Main shortcuts
 33 | 
 34 | On the files tab:
 35 | 
 36 | * **Right/Left arrows**: browses between files and folders
 37 | * **Enter**: downloads the selected file or gets into the selected folder
 38 | * **Del**: deletes the selected file
 39 | * **F2**: renames the selected file or folder
 40 | * **Escape**: unselects the selected file or folder
 41 | * **Insert**: uploads files
 42 | * **Page Down**: creates a folder
 43 | * **F4**: shows the chat tab
 44 | 
 45 | You also can directly download a file by double-clicking it.
 46 | 
 47 | On the chat tab:
 48 | 
 49 | * **Up arrow**: completes the input field with the last posted message
 50 | * **Down arrow**: cleans the input field
 51 | * **F3**: shows the files tab
 52 | 
 53 | ### Options
 54 | 
 55 | All options are available in */config.php*:
 56 | 
 57 | * **app_name**: name of the service ("PirateBox" by default but brandable)
 58 | * **enable_chat**: boolean for enabling the web chat or not
 59 | * **allow_renaming**: boolean for allowing free renaming of the existing files or not
 60 | * **allow_deleting**: boolean for allowing free deleting of the existing files or not
 61 | * **default_pseudo**: default pseudo in the chat when the user has not defined one ("anonymous" by default, completed with a random number)
 62 | * **time_format**: format to use for displaying dates, using the [PHP date](https://php.net/manual/en/function.date.php) syntax
 63 | * **fancyurls**: boolean for enabling fancy URLs or not (see below the required specific configuration at the HTTP server side)
 64 | * **base_path**: unix path of the root of the interface in the server
 65 | * **base_uri**: root of the interface regarding the URLs (folders to add after the domain name)
 66 | * **base_uploads**: optional unix path in case of the *uploads/* folder is located elsewhere in the server (see HTTP configuration below)
 67 | * **base_chat**: optional unix path in case of the *chat/* folder (containing the chat log file) is located elsewhere in the server (see HTTP configuration below)
 68 | * **max_space**: maximum available space in percent for the data, on the partition where *base_uploads* is located
 69 | 
 70 | For pinning a file or a folder, just remove the write permission for the owner on the server:
 71 | 
 72 |     # chmod u-w /var/www/piratebox/public/uploads/foo.bar
 73 | 
 74 | ## Server configuration
 75 | ### HTTP server
 76 | 
 77 | Example with nginx:
 78 | 
 79 |     # Max file size
 80 |     client_max_body_size 10G;
 81 |     
 82 |     # OPTIONAL
 83 |     location /public/uploads/ {
 84 |     
 85 |       # OPTIONAL: use a public/uploads/ folder located elsewhere
 86 |       # WITH: $options['base_uploads'] = '/var/spool/piratebox/public/uploads/'
 87 |       root /var/spool/piratebox/;
 88 |   
 89 |       # OPTIONAL: force download for all files
 90 |       add_header Content-Type "application/octet-stream";
 91 |       add_header Content-Disposition "attachment; filename=$1";
 92 |     }
 93 |     
 94 |     # OPTIONAL
 95 |     location /public/chat/ {
 96 |     
 97 |       # OPTIONAL: use a public/chat/ folder located elsewhere
 98 |       # WITH: $options['base_chat'] = '/var/spool/piratebox/public/chat/'
 99 |       root /var/spool/piratebox/;
100 | 
101 |       # OPTIONAL: deny direct access to the chat log
102 |       deny all;
103 |       return 403;
104 |     }
105 |     
106 |     # PHP
107 |     location ~ \.php {
108 |       include /etc/nginx/fastcgi_params;
109 |     
110 |       fastcgi_index index.php;
111 |       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
112 |       fastcgi_pass unix:/var/run/php.sock;
113 | 
114 |       # 10 minutes max for uploading a file
115 |       fastcgi_send_timeout 600;
116 |     }
117 |     
118 |     # OPTIONAL: use fancy urls
119 |     # WITH: $options['fancyurls'] = true
120 |     location @piratebox {
121 |     
122 |       # WITH: $options['base_uri'] = '/foobar/'
123 |       rewrite ^/foobar/(.*)$ /foobar/?/get&dir=$1;
124 |     }
125 |     
126 |     location / {
127 |       index index.html index.php;
128 |     
129 |       # OPTIONAL: use fancy urls
130 |       try_files $uri $uri/ @piratebox;
131 |     }
132 | 
133 | ### PHP backend
134 | 
135 | Example with php-fpm:
136 | 
137 |     ; Max file size
138 |     php_value[upload_max_filesize] = 10G
139 |     php_value[post_max_size] = 10G
140 |     
141 |     ; 10 minutes max for uploading a file
142 |     php_value[max_execution_time] = 600
143 | 
144 | ### Permissions
145 | 
146 | For example, if your PHP pool uses *www-data* as unix user:
147 | 
148 |     # chown www-data: public/uploads/
149 |     # chown www-data: public/chat/
150 | 
151 | ## Screenshots
152 | 
153 | 
154 | ")
155 | 
156 | 
157 | ")
158 | ")
159 | 
160 | 
161 | ")
162 | ")
163 | 
--------------------------------------------------------------------------------
/config.php:
--------------------------------------------------------------------------------
 1 |  "PirateBox",
 5 | 
 6 |   'base_path'          => "/var/www/piratebox/",
 7 |   'base_uri'           => "/",
 8 |   'max_space'          => 90, // in percent of the partition usage
 9 | 
10 |   #'base_uploads'       => "/var/spool/piratebox/public/uploads/",
11 |   #'base_chat'          => "/var/spool/piratebox/public/chat/",
12 | 
13 |   'allow_renaming'     => true,
14 |   'allow_deleting'     => true,
15 |   'allow_newfolders'   => true,
16 | 
17 |   'enable_chat'        => true,
18 |   'default_pseudo'     => "anonymous",
19 | 
20 |   'time_format'        => "d/m/y H:i",
21 |   'fancyurls'          => true,
22 | ];
23 | 
24 | ?>
25 | 
--------------------------------------------------------------------------------
/controller.php:
--------------------------------------------------------------------------------
  1 | 
  5 |  * Contribute at https://github.com/jvaubourg/php-piratebox
  6 |  * 
  7 |  * This program is free software: you can redistribute it and/or modify
  8 |  * it under the terms of the GNU Affero General Public License as published by
  9 |  * the Free Software Foundation, either version 3 of the License, or
 10 |  * (at your option) any later version.
 11 |  * 
 12 |  * This program is distributed in the hope that it will be useful,
 13 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 |  * GNU Affero General Public License for more details.
 16 |  * 
 17 |  * You should have received a copy of the GNU Affero General Public License
 18 |  * along with this program.  If not, see  .
 19 |  */
 20 | 
 21 | require_once('functions.php');
 22 | 
 23 | dispatch('/', function() {
 24 |   set('files', getFiles('/'));
 25 |   set('tab', 'files');
 26 |   set('locked', true);
 27 |   set('cdir', '/');
 28 | 
 29 |   header('Content-Type: text/html; charset=utf-8');
 30 | 
 31 |   return render('home.html.php');
 32 | });
 33 | 
 34 | dispatch('/get', function() {
 35 |   $dir = sanitizeDirpath(urldecode($_GET['dir']));
 36 |   $ajax = isset($_GET['ajax']) && $_GET['ajax'];
 37 | 
 38 |   if($ajax) {
 39 |     header('Content-Type: text/plain; charset=utf-8');
 40 |   } else {
 41 |     header('Content-Type: text/html; charset=utf-8');
 42 |   }
 43 | 
 44 |   if(empty($dir) || !is_dir(UPLOADS_PATH.$dir)) {
 45 |     if($ajax) {
 46 |       exit('ERR:'._("Invalid destination.".UPLOADS_PATH.$dir));
 47 | 
 48 |     } else {
 49 |       header('Location: '.ROOT_DIR);
 50 |       exit();
 51 |     }
 52 |   }
 53 | 
 54 |   if($ajax) {
 55 |     return getFiles($dir, true);
 56 |   }
 57 | 
 58 |   $perms = fileperms(UPLOADS_PATH.$dir);
 59 |   $locked = !($perms & 0x0080) || $dir == '/';
 60 | 
 61 |   set('files', getFiles($dir));
 62 |   set('tab', 'files');
 63 |   set('locked', $locked);
 64 |   set('cdir', $dir);
 65 | 
 66 |   return render('home.html.php');
 67 | });
 68 | 
 69 | dispatch_post('/rename', function() {
 70 |   $cdir = sanitizeDirpath($_POST['cdir']);
 71 |   $oldName = sanitizeFilename($_POST['oldName']);
 72 |   $newName = sanitizeFilename($_POST['newName']);
 73 | 
 74 |   $oldFilePath = UPLOADS_PATH."$cdir/$oldName";
 75 |   $newFilePath = UPLOADS_PATH."$cdir/$newName";
 76 | 
 77 |   header('Content-Type: text/plain; charset=utf-8');
 78 | 
 79 |   if(!option('allow_renaming')) {
 80 |     exit('ERR:'._("Unauthorized."));
 81 |   }
 82 | 
 83 |   if(empty($oldName) || empty($newName)) {
 84 |     exit('ERR:'._("Invalid filename."));
 85 |   }
 86 | 
 87 |   if(!file_exists($oldFilePath)) {
 88 |     exit('ERR:'._("File not found."));
 89 |   }
 90 | 
 91 |   if(file_exists($newFilePath)) {
 92 |     exit('ERR:'._("File already exists."));
 93 |   }
 94 | 
 95 |   if(!rename($oldFilePath, $newFilePath)) {
 96 |     exit('ERR:'._("Renaming failed."));
 97 |   }
 98 | 
 99 |   if(is_dir($newFilePath)) {
100 |     $folder = array(
101 |       'name' => $newName,
102 |       'dir'  => "$cdir/$newName",
103 |     );
104 | 
105 |     set('folder', $folder);
106 |     set('locked', false);
107 |     set('newfolder', true);
108 | 
109 |     echo partial('_folder.html.php');
110 | 
111 |   } else {
112 |     $file = array(
113 |       'filename'  => UPLOADS_DIR.str_replace('%2F', '/', rawurlencode($cdir)).'/'.rawurlencode($newName),
114 |       'name'      => $newName,
115 |       'shortname' => getShortname($newName),
116 |       'img'       => getExtensionImage($newFilePath),
117 |       'size'      => fileSizeConvert(filesize($newFilePath)),
118 |       'date'      => dateConvert(filemtime($newFilePath)),
119 |     );
120 | 
121 |     set('file', $file);
122 |     set('locked', false);
123 |     set('newfile', true);
124 | 
125 |     echo partial('_file.html.php');
126 |   }
127 | });
128 | 
129 | dispatch_post('/delete', function() {
130 |   $cdir = sanitizeDirpath($_POST['cdir']);
131 |   $name = sanitizeFilename($_POST['name']);
132 | 
133 |   $filePath = UPLOADS_PATH."$cdir/$name";
134 | 
135 |   header('Content-Type: text/plain; charset=utf-8');
136 | 
137 |   if(!option('allow_deleting')) {
138 |     exit('ERR:'._("Unauthorized."));
139 |   }
140 | 
141 |   if(!file_exists($filePath)) {
142 |     exit('ERR:'._("File not found."));
143 |   }
144 | 
145 |   if(is_dir($filePath)) {
146 |     $files = scandir($filePath);
147 | 
148 |     if(!$files) {
149 |       exit('ERR:'._("Cannot read this directory."));
150 |     }
151 | 
152 |     if(count($files) > 2) {
153 |       exit('ERR:'._("Not empty directory."));
154 |     }
155 | 
156 |     if(!rmdir($filePath)) {
157 |       exit('ERR:'._("Cannot delete this directory."));
158 |     }
159 | 
160 |   } else {
161 |     if(!unlink($filePath)) {
162 |       exit('ERR:'._("Cannot delete this file."));
163 |     }
164 |   }
165 | });
166 | 
167 | dispatch_post('/upload', function() {
168 |   $cdir = sanitizeDirpath(urldecode($_GET['cdir']));
169 |   $name = sanitizeFilename(urldecode(@$_SERVER['HTTP_X_FILE_NAME']));
170 | 
171 |   $dirpath = UPLOADS_PATH."$cdir";
172 |   $filename = "$dirpath/$name";
173 | 
174 |   header('Content-Type: text/plain; charset=utf-8');
175 | 
176 |   if(empty($cdir) || !is_dir($dirpath)) {
177 |     exit('ERR:'._("Invalid directory."));
178 |   }
179 | 
180 |   if(!hasAvailableSpace()) {
181 |     exit('ERR:'._("The file system has reached the maximum limit of space."));
182 |   }
183 | 
184 |   if(empty($name)) {
185 |     exit('ERR:'._("Invalid filename."));
186 |   }
187 | 
188 |   if(file_exists($filename)) {
189 |     exit('ERR:'._("File already exists."));
190 |   }
191 | 
192 |   $src = fopen('php://input', 'r');
193 |   $dst = fopen($filename, 'w');
194 | 
195 |   if(!$src || !$dst) {
196 |     exit('ERR:'._("Uploading failed."));
197 |   }
198 | 
199 |   stream_copy_to_stream($src, $dst);
200 | 
201 |   $file = array(
202 |     'filename'  => UPLOADS_DIR.str_replace('%2F', '/', rawurlencode($cdir)).'/'.rawurlencode($name),
203 |     'name'      => $name,
204 |     'shortname' => getShortname($name),
205 |     'img'       => getExtensionImage($filename),
206 |     'size'      => fileSizeConvert(filesize($filename)),
207 |     'date'      => dateConvert(filemtime($filename)),
208 |   );
209 | 
210 |   set('file', $file);
211 |   set('locked', false);
212 |   set('newfile', true);
213 | 
214 |   echo partial('_file.html.php');
215 | });
216 | 
217 | dispatch_post('/createfolder', function() {
218 |   $name = sanitizeDirname($_POST['name']);
219 |   $cdir = sanitizeDirpath($_POST['cdir']);
220 | 
221 |   $dirpath = UPLOADS_PATH."$cdir";
222 |   $filename = "$dirpath/$name";
223 | 
224 |   header('Content-Type: text/plain; charset=utf-8');
225 | 
226 |   if(!option('allow_newfolders')) {
227 |     exit('ERR:'._("Unauthorized."));
228 |   }
229 | 
230 |   if(!hasAvailableSpace()) {
231 |     exit('ERR:'._("The file system has reached the maximum limit of space."));
232 |   }
233 | 
234 |   if(empty($cdir) || !is_dir($dirpath)) {
235 |     exit('ERR:'._("Invalid directory."));
236 |   }
237 | 
238 |   if(empty($name)) {
239 |     exit('ERR:'._("Invalid directory name."));
240 |   }
241 | 
242 |   if(file_exists($filename)) {
243 |     exit('ERR:'._("File already exists."));
244 |   }
245 | 
246 |   if(!mkdir(UPLOADS_PATH."$cdir/$name")) {
247 |     exit('ERR:'._("Creating folder failed."));
248 |   }
249 | 
250 |   $folder = array(
251 |     'name' => $name,
252 |     'dir'  => "$cdir/$name",
253 |   );
254 | 
255 |   set('folder', $folder);
256 |   set('locked', false);
257 |   set('newfolder', true);
258 | 
259 |   echo partial('_folder.html.php');
260 | });
261 | 
262 | dispatch('/chat', function() {
263 |   header('Content-Type: text/html; charset=utf-8');
264 | 
265 |   if(!option('enable_chat')) {
266 |     exit('ERR:'._("Unauthorized."));
267 |   }
268 | 
269 |   set('files', getFiles('/'));
270 |   set('tab', 'chat');
271 |   set('locked', true);
272 |   set('cdir', '/');
273 | 
274 |   return render('home.html.php');
275 | });
276 | 
277 | dispatch_post('/chat', function() {
278 |   $action = $_POST['action'];
279 |   $logpath = CHAT_PATH.'log.html';
280 | 
281 |   header('Content-Type: text/plain; charset=utf-8');
282 | 
283 |   if(!option('enable_chat')) {
284 |     exit('ERR:'._("Unauthorized."));
285 |   }
286 | 
287 |   switch($action) {
288 |     case 'getLog':
289 |       if(file_exists($logpath)) {
290 |         $count = intval($_POST['count']);
291 | 
292 |         $log = file($logpath);
293 |         $logSize = count($log);
294 | 
295 |         if(!$log) {
296 |           exit('ERR:'._("Failed to open chat log."));
297 |         }
298 | 
299 |         if($count > $logSize) {
300 |           exit('ERR:'._("Invalid count number."));
301 |         }
302 | 
303 |         if(!empty($log) && $count != $logSize) {
304 |           $logDiff = array();
305 | 
306 |           if($count < 1) {
307 |             $logDiff = $log;
308 |   
309 |           } else {
310 |             for($i = $count; $i < $logSize; $i++) {
311 |               array_push($logDiff, $log[$i]);
312 |             }
313 |           }
314 | 
315 |           echo implode($logDiff);
316 |         }
317 |       }
318 |     break;
319 | 
320 |     case 'post':
321 |       $pseudo = substr(trim($_POST['pseudo']), 0, 12);
322 |       $pseudo = htmlentities($pseudo);
323 |       $comment = htmlentities(trim($_POST['comment']));
324 |       $date = date('d/m/y H:i');
325 | 
326 |       if(empty($pseudo) || empty($comment)) {
327 |         exit();
328 |       }
329 | 
330 |       $comment = preg_replace('/([\w\d]+\:\/\/(?:[\w\-\d]+\.)+[\w\-\d]+(?:\/[\w\-\d]+)*(?:\/|\.[\w\-\d]+)?(?:\?[\w\-\d]+\=[\w\-\d]+\&?)?(?:\#[\w\-\d]*)?)/i', '$1 ', $comment);
331 | 
332 |       $line = "
$pseudo  $comment
\n";
333 |       $flog = fopen($logpath, 'a') or die("Can't open chat log.");
334 | 
335 |       fwrite($flog, $line);
336 |       fclose($flog);
337 |     break;
338 | 
339 |     case 'getLineCount':
340 |       $count = intval(exec('wc -l '.escapeshellarg($logpath).' 2> /dev/null'));
341 | 
342 |       echo ($count >= 0) ? $count : 0;
343 |     break;
344 |   }
345 | });
346 | 
347 | dispatch('/lang/:locale', function($locale = 'en') {
348 |   switch($locale) {
349 |     case 'fr':
350 |       $_SESSION['locale'] = 'fr';
351 |     break;
352 | 
353 |     default:
354 |       $_SESSION['locale'] = 'en';
355 |   }
356 | 
357 |   redirect_to('/');
358 | });
359 | 
--------------------------------------------------------------------------------
/framework.php:
--------------------------------------------------------------------------------
  1 | 
  5 |  * Contribute at https://github.com/jvaubourg/php-piratebox
  6 |  * 
  7 |  * This program is free software: you can redistribute it and/or modify
  8 |  * it under the terms of the GNU Affero General Public License as published by
  9 |  * the Free Software Foundation, either version 3 of the License, or
 10 |  * (at your option) any later version.
 11 |  * 
 12 |  * This program is distributed in the hope that it will be useful,
 13 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 |  * GNU Affero General Public License for more details.
 16 |  * 
 17 |  * You should have received a copy of the GNU Affero General Public License
 18 |  * along with this program.  If not, see  .
 19 |  */
 20 | 
 21 | require('config.php');
 22 | 
 23 | // Limonade configuration
 24 | function configure() {
 25 |   $GLOBALS['options']['public_dir'] = "public";
 26 |   $GLOBALS['options']['public_uploads_dir'] = "uploads";
 27 |   $GLOBALS['options']['public_chat_dir'] = "chat";
 28 | 
 29 |   $GLOBALS['options']['base_path'] = preg_replace('/\/+$/', '', $GLOBALS['options']['base_path']);
 30 |   $GLOBALS['options']['base_uri'] = preg_replace('/\/+$/', '', $GLOBALS['options']['base_uri']);
 31 | 
 32 |   option('app_name', $GLOBALS['options']['app_name']);
 33 |   option('env', ENV_PRODUCTION);
 34 |   option('debug', false);
 35 |   option('base_path', $GLOBALS['options']['base_path'].'/');
 36 |   option('base_uri', $GLOBALS['options']['base_uri'].'/');
 37 |   option('max_space', $GLOBALS['options']['max_space']);
 38 | 
 39 |   option('allow_renaming', $GLOBALS['options']['allow_renaming']);
 40 |   option('allow_deleting', $GLOBALS['options']['allow_deleting']);
 41 |   option('allow_newfolders', $GLOBALS['options']['allow_newfolders']);
 42 |   option('enable_chat', $GLOBALS['options']['enable_chat']);
 43 |   option('default_pseudo', $GLOBALS['options']['default_pseudo']);
 44 |   option('time_format', $GLOBALS['options']['time_format']);
 45 |   option('fancyurls', $GLOBALS['options']['fancyurls']);
 46 | 
 47 |   layout("layout.html.php");
 48 | 
 49 |   define('ROOT_DIR', option('base_uri'));
 50 |   define('PUBLIC_DIR', $GLOBALS['options']['public_dir'].'/');
 51 |   define('UPLOADS_DIR', PUBLIC_DIR.$GLOBALS['options']['public_uploads_dir'].'/');
 52 |   define('CHAT_DIR', PUBLIC_DIR.$GLOBALS['options']['public_chat_dir'].'/');
 53 | 
 54 |   $uploads_path = isset($GLOBALS['options']['base_uploads']) ? $GLOBALS['options']['base_uploads'] : option('base_path').UPLOADS_DIR;
 55 |   $chat_path = isset($GLOBALS['options']['base_chat']) ? $GLOBALS['options']['base_chat'] : option('base_path').CHAT_DIR;
 56 | 
 57 |   $uploads_path = preg_replace('/\/+$/', '', $uploads_path);
 58 |   $chat_path = preg_replace('/\/+$/', '', $chat_path);
 59 | 
 60 |   define('UPLOADS_PATH', "$uploads_path/");
 61 |   define('CHAT_PATH', "$chat_path/");
 62 | }
 63 | 
 64 | // Before routing
 65 | function before($route) {
 66 |   $lang_mapping = array(
 67 |     'fr' => 'fr_FR'
 68 |   );
 69 | 
 70 |   if(!isset($_SESSION['locale'])) {
 71 |     $locale = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
 72 |     $_SESSION['locale'] = strtolower(substr(chop($locale[0]), 0, 2));
 73 |   }
 74 | 
 75 |   $lang = $_SESSION['locale'];
 76 | 
 77 |   // Convert simple language code into full language code
 78 |   if(array_key_exists($lang, $lang_mapping)) {
 79 |     $lang = $lang_mapping[$lang];
 80 |   }
 81 | 
 82 |   $lang = "$lang.utf8";
 83 |   $textdomain = "localization";
 84 | 
 85 |   putenv("LANGUAGE=$lang");
 86 |   putenv("LANG=$lang");
 87 |   putenv("LC_ALL=$lang");
 88 |   putenv("LC_MESSAGES=$lang");
 89 | 
 90 |   setlocale(LC_ALL, $lang);
 91 |   setlocale(LC_CTYPE, $lang);
 92 | 
 93 |   $locales_dir = dirname(__FILE__).'/i18n';
 94 | 
 95 |   bindtextdomain($textdomain, $locales_dir);
 96 |   bind_textdomain_codeset($textdomain, 'UTF-8');
 97 |   textdomain($textdomain);
 98 | 
 99 |   set('locale', $lang);
100 | }
101 | 
102 | // After routing
103 | function after($output, $route) {
104 |   return $output;
105 | }
106 | 
--------------------------------------------------------------------------------
/functions.php:
--------------------------------------------------------------------------------
  1 | 
  5 |  * Contribute at https://github.com/jvaubourg/php-piratebox
  6 |  * 
  7 |  * This program is free software: you can redistribute it and/or modify
  8 |  * it under the terms of the GNU Affero General Public License as published by
  9 |  * the Free Software Foundation, either version 3 of the License, or
 10 |  * (at your option) any later version.
 11 |  * 
 12 |  * This program is distributed in the hope that it will be useful,
 13 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 |  * GNU Affero General Public License for more details.
 16 |  * 
 17 |  * You should have received a copy of the GNU Affero General Public License
 18 |  * along with this program.  If not, see  .
 19 |  */
 20 | 
 21 | $extensionsImages = [
 22 |   'sql'   => 'sql.png',
 23 |   'zip'   => 'zip.png',
 24 |   'rar'   => 'rar.png',
 25 |   'gz'    => 'archive.png',
 26 |   'tgz'   => 'archive.png',
 27 |   '7z'    => 'zip.png',
 28 |   'gzip'  => 'gzip.png',
 29 |   'php'   => 'php.png',
 30 |   'py'    => 'py.png',
 31 |   'jsp'   => 'html.png',
 32 |   'html'  => 'html.png',
 33 |   'htm'   => 'html.png',
 34 |   'css'   => 'css.png',
 35 |   'java'  => 'java.png',
 36 |   'jar'   => 'java.png',
 37 |   'cpp'   => 'cpp.png',
 38 |   'cc'    => 'cpp.png',
 39 |   'c'     => 'c.png',
 40 |   'h'     => 'h.png',
 41 |   'hpp'   => 'hpp.png',
 42 |   'js'    => 'js.png',
 43 |   'rss'   => 'rss.png',
 44 |   'rb'    => 'rb.png',
 45 |   'vcard' => 'authors.png',
 46 |   'exe'   => 'exe.png',
 47 |   'deb'   => 'package.png',
 48 |   'psd'   => 'psd.png',
 49 |   'nfo'   => 'readme.png',
 50 |   'csv'   => 'calc.png',
 51 |   'xls'   => 'calc.png',
 52 |   'xlsx'  => 'calc.png',
 53 |   'ppt'   => 'pres.png',
 54 |   'pptx'  => 'pres.png',
 55 |   'doc'   => 'doc.png',
 56 |   'odf'   => 'doc.png',
 57 |   'docx'  => 'doc.png',
 58 |   'otf'   => 'doc.png',
 59 |   'rtf'   => 'rtf.png',
 60 |   'txt'   => 'txt.png',
 61 |   'log'   => 'log.png',
 62 |   'src'   => 'source.png',
 63 |   'tex'   => 'tex.png',
 64 |   'bin'   => 'bin.png',
 65 |   'cd'    => 'cd.png',
 66 |   'sh'    => 'script.png',
 67 |   'bash'  => 'script.png',
 68 |   'bat'   => 'script.png',
 69 |   'vcal'  => 'vcal.png',
 70 |   'ical'  => 'vcal.png',
 71 |   'mp3'   => 'playlist.png',
 72 |   'avi'   => 'playlist.png',
 73 |   'mp4'   => 'video.png',
 74 |   'webm'  => 'video.png',
 75 |   'wmv'   => 'video.png',
 76 |   'mkv'   => 'video.png',
 77 |   'rpm'   => 'rpm.png',
 78 |   'tiff'  => 'tiff.png',
 79 |   'jpg'   => 'jpg.png',
 80 |   'jpeg'  => 'jpg.png',
 81 |   'png'   => 'png.png',
 82 |   'gif'   => 'gif.png',
 83 |   'bmp'   => 'bmp.png',
 84 |   'ico'   => 'ico.png',
 85 |   'eps'   => 'draw.png',
 86 |   'ai'    => 'eps.png',
 87 |   'pdf'   => 'pdf.png',
 88 |   'xml'   => 'xml.png',
 89 |   'fla'   => 'makefile.png',
 90 |   'swf'   => 'makefile.png',
 91 |   'svg'   => 'svg.png',
 92 | ];
 93 | 
 94 | function sanitizeFilename($name) {
 95 |   $name = str_replace('/', '', $name);
 96 |   $name = preg_replace('/^\.+/', '', $name);
 97 |   $name = substr($name, 0, 100);
 98 | 
 99 |   return $name;
100 | }
101 | 
102 | function sanitizeDirpath($path) {
103 |   $path = str_replace('..', '', $path);
104 |   $path = trim($path);
105 | 
106 |   return $path;
107 | }
108 | 
109 | function sanitizeDirname($name) {
110 |   $name = sanitizeFilename($name);
111 |   $name = substr($name, 0, 16);
112 | 
113 |   return $name;
114 | }
115 | 
116 | function getShortname($name) {
117 |   if(strpos($name, '.') === false) {
118 |     $extension = '';
119 |     $shortname = $name;
120 | 
121 |   } else {
122 |     $namecut = explode('.', $name);
123 |     $extension = array_pop($namecut);
124 |     $shortname = implode('.', $namecut);
125 |   }
126 | 
127 |   $shortname = substr($shortname, 0, 17);
128 |   $extension = substr($extension, -4);
129 | 
130 |   if(empty($extension)) {
131 |     $shortname = ($shortname == $name) ? $name : "$shortname...";
132 |   } else {
133 |     $shortname = ("$shortname.$extension" == $name) ? $name : "$shortname...$extension";
134 |   }
135 | 
136 |   return $shortname;
137 | }
138 | 
139 | function getExtensionImage($filepath) {
140 |   $extension = explode('.', $filepath);
141 |   $extension = array_pop($extension);
142 | 
143 |   if(isset($GLOBALS['extensionsImages'][$extension])) {
144 |     return $GLOBALS['extensionsImages'][$extension];
145 |   }
146 | 
147 |   return 'unknown.png';
148 | }
149 | 
150 | function fileSizeConvert($bytes) {
151 |   $units = [
152 |     0 => [
153 |       'unit'  => 'TB',
154 |       'value' => pow(1024, 4),
155 |     ],
156 |     1 => [
157 |         'unit'  => 'GB',
158 |         'value' => pow(1024, 3),
159 |     ],
160 |     2 => [
161 |         'unit'  => 'MB',
162 |         'value' => pow(1024, 2),
163 |     ],
164 |     3 => [
165 |         'unit'  => 'KB',
166 |         'value' => 1024,
167 |     ],
168 |     4 => [
169 |       'unit'  => 'B',
170 |       'value' => 1,
171 |     ],
172 |   ];
173 | 
174 |   $bytes = floatval($bytes);
175 | 
176 |   foreach($units as $unit) {
177 |     if($bytes > $unit['value']) {
178 |       $size = $bytes / $unit['value'];
179 |       $size = strval(round($size, 2));
180 |       $size .= $unit['unit'];
181 | 
182 |       break;
183 |     }
184 |   }
185 | 
186 |   return $size;
187 | }
188 | 
189 | function dateConvert($timestamp) {
190 |   return date(option('time_format'), $timestamp);
191 | }
192 | 
193 | function getFiles($dir, $newfiles = false) {
194 |   $files = "";
195 |   $finfo = new finfo;
196 | 
197 |   set('cdir', $dir);
198 | 
199 |   foreach(scandir(UPLOADS_PATH."$dir") as $name) {
200 |     $filepath = UPLOADS_PATH."$dir/$name";
201 | 
202 |     if(preg_match('/^\./', $name)) {
203 |       continue;
204 |     }
205 | 
206 |     $perms = fileperms($filepath);
207 |     $locked = !($perms & 0x0080);
208 | 
209 |     set('locked', $locked);
210 | 
211 |     if(is_dir($filepath)) {
212 |       $folder = array(
213 |         'name' => $name,
214 |         'dir' => "$dir/$name",
215 |       );
216 |     
217 |       set('newfolder', $newfiles);
218 |       set('folder', $folder);
219 | 
220 |       $files .= partial('_folder.html.php');
221 | 
222 |     } else {
223 |       $file = array(
224 |         'filename'  => ROOT_DIR.UPLOADS_DIR."$dir/".rawurlencode($name),
225 |         'name'      => $name,
226 |         'shortname' => getShortname($name),
227 |         'img'       => getExtensionImage($filepath),
228 |         'size'      => fileSizeConvert(filesize($filepath)),
229 |         'date'      => dateConvert(filemtime($filepath)),
230 |       );
231 | 
232 |       set('newfile', $newfiles);
233 |       set('file', $file);
234 | 
235 |       $files .= partial('_file.html.php');
236 |     }
237 |   }
238 | 
239 |   return $files;
240 | }
241 | 
242 | function hasAvailableSpace() {
243 |   exec('df '.escapeshellarg(UPLOADS_PATH), $output, $retcode);
244 | 
245 |   if($retcode == 0) {
246 |     $usage = $output[count($output) - 1];
247 |     $percent = preg_replace('/^.*([0-9]+)%.*$/', '$1', $usage);
248 | 
249 |     if(is_numeric($percent)) {
250 |       return $percent < option('max_space');
251 |     }
252 |   }
253 | 
254 |   return false;
255 | }
256 | 
--------------------------------------------------------------------------------
/i18n/README.md:
--------------------------------------------------------------------------------
 1 | ## Force language
 2 | 
 3 | The default language of the web admin depends on your browser language.
 4 | 
 5 | You can force a language by using (e.g. for French):
 6 | ```
 7 | /?/lang/fr
 8 | ```
 9 | 
10 | English is the default language when the browser language is not available.
11 | 
12 | ## Update the default string list
13 | 
14 | Updating the pot file from template files:
15 | ```
16 | xgettext views/* -o i18n/localization.pot
17 | xgettext *.php views/*.php -o i18n/localization.pot
18 | ```
19 | 
20 | ## Add a new language
21 | 
22 | Create a new directory path (e.g. for French):
23 | ```
24 | mkdir -p i18n/fr_FR/LC_MESSAGES/
25 | ```
26 | 
27 | Generate the po file:
28 | ```
29 | msginit --locale=fr_FR.UTF-8 --no-translator -i i18n/localization.pot -o i18n/fr_FR/LC_MESSAGES/localization.po
30 | ```
31 | 
32 | You can use poedit for translating the po:
33 | ```
34 | poedit i18n/fr_FR/LC_MESSAGES/localization.po
35 | ```
36 | 
37 | With poedit, just save your modifications with the button and the *localization.mo* (compiled version of the po) file will automatically be created or updated.
38 | 
39 | If you edited the po by hand, you have to compile the mo file:
40 | ```
41 | msgfmt i18n/fr_FR/localization.po -o i18n/fr_FR/LC_MESSAGES/localization.mo
42 | ```
43 | 
44 | Change the default language of your browser, and test this new translation.
45 | 
46 | You should add the locale to the list at the end of *controller.php*.
47 | 
--------------------------------------------------------------------------------
/i18n/fr_FR/LC_MESSAGES/localization.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvaubourg/php-piratebox/d9cc1a57b9b99a0e4d63d0e518193f70876b221d/i18n/fr_FR/LC_MESSAGES/localization.mo
--------------------------------------------------------------------------------
/i18n/fr_FR/LC_MESSAGES/localization.po:
--------------------------------------------------------------------------------
  1 | # SOME DESCRIPTIVE TITLE.
  2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
  3 | # This file is distributed under the same license as the PACKAGE package.
  4 | # FIRST AUTHOR , YEAR.
  5 | # Simon Vieille , 2015.
  6 | #
  7 | msgid ""
  8 | msgstr ""
  9 | "Project-Id-Version: \n"
 10 | "Report-Msgid-Bugs-To: \n"
 11 | "POT-Creation-Date: 2015-07-25 13:39+0200\n"
 12 | "PO-Revision-Date: 2015-07-25 13:41+0100\n"
 13 | "Last-Translator: Simon Vieille \n"
 14 | "Language-Team: français <>\n"
 15 | "Language: fr_FR\n"
 16 | "MIME-Version: 1.0\n"
 17 | "Content-Type: text/plain; charset=UTF-8\n"
 18 | "Content-Transfer-Encoding: 8bit\n"
 19 | "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 20 | "X-Generator: Poedit 1.6.10\n"
 21 | 
 22 | #: controller.php:46
 23 | msgid "Invalid destination."
 24 | msgstr "Destination incorrecte."
 25 | 
 26 | #: controller.php:80 controller.php:138 controller.php:227 controller.php:266
 27 | #: controller.php:284
 28 | msgid "Unauthorized."
 29 | msgstr "Non autorisé."
 30 | 
 31 | #: controller.php:84 controller.php:185
 32 | msgid "Invalid filename."
 33 | msgstr "Nom de fichier invalide."
 34 | 
 35 | #: controller.php:88 controller.php:142
 36 | msgid "File not found."
 37 | msgstr "Fichier non trouvé."
 38 | 
 39 | #: controller.php:92 controller.php:189 controller.php:243
 40 | msgid "File already exists."
 41 | msgstr "Le fichier existe déjà."
 42 | 
 43 | #: controller.php:96
 44 | msgid "Renaming failed."
 45 | msgstr "Le renommage a échoué."
 46 | 
 47 | #: controller.php:149
 48 | msgid "Cannot read this directory."
 49 | msgstr "Impossible de lire le répertoire."
 50 | 
 51 | #: controller.php:153
 52 | msgid "Not empty directory."
 53 | msgstr "Le répertoire n'est pas vide."
 54 | 
 55 | #: controller.php:157
 56 | msgid "Cannot delete this directory."
 57 | msgstr "Impossible de supprimer ce répertoire."
 58 | 
 59 | #: controller.php:162
 60 | msgid "Cannot delete this file."
 61 | msgstr "Impossible de supprimer ce fichier."
 62 | 
 63 | #: controller.php:177 controller.php:235
 64 | msgid "Invalid directory."
 65 | msgstr "Répertoire invalide."
 66 | 
 67 | #: controller.php:181 controller.php:231
 68 | msgid "The file system has reached the maximum limit of space."
 69 | msgstr "Le système de fichiers a atteint la limite de la place disponible."
 70 | 
 71 | #: controller.php:196
 72 | msgid "Uploading failed."
 73 | msgstr "Le téléversement a échoué."
 74 | 
 75 | #: controller.php:239
 76 | msgid "Invalid directory name."
 77 | msgstr "Nom de répertoire invalide."
 78 | 
 79 | #: controller.php:247
 80 | msgid "Creating folder failed."
 81 | msgstr "La création du répertoire a échoué."
 82 | 
 83 | #: controller.php:296
 84 | msgid "Failed to open chat log."
 85 | msgstr "Impossible d'ouvrir l'historique du chat."
 86 | 
 87 | #: controller.php:300
 88 | msgid "Invalid count number."
 89 | msgstr "Nombre invalide."
 90 | 
 91 | #: views/home.html.php:34
 92 | msgid "Files"
 93 | msgstr "Fichiers"
 94 | 
 95 | #: views/home.html.php:35
 96 | msgid "Chat"
 97 | msgstr "Chat"
 98 | 
 99 | #: views/home.html.php:39
100 | msgid "Upload a new file"
101 | msgstr "Téléverser un fichier"
102 | 
103 | #: views/home.html.php:40
104 | msgid "Pseudo"
105 | msgstr "Pseudo"
106 | 
107 | #: views/home.html.php:48
108 | msgid "Are you sure you want to delete this file?"
109 | msgstr "Êtes-vous certain de vouloir supprimer ce fichier ?"
110 | 
111 | #: views/home.html.php:49
112 | msgid "Are you sure you want to delete this folder?"
113 | msgstr "Êtes-vous certain de vouloir supprimer ce répertoire ?"
114 | 
115 | #: views/home.html.php:50
116 | msgid "Open"
117 | msgstr "Ouvrir"
118 | 
119 | #: views/home.html.php:51 views/home.html.php:61
120 | msgid "Download"
121 | msgstr "Télécharger"
122 | 
123 | #: views/home.html.php:52 views/home.html.php:64
124 | msgid "Rename"
125 | msgstr "Renommer"
126 | 
127 | #: views/home.html.php:53 views/home.html.php:65
128 | msgid "Delete"
129 | msgstr "Supprimer"
130 | 
131 | #: views/home.html.php:70
132 | msgid "Download the others' files"
133 | msgstr "Télécharger les fichiers des autres"
134 | 
135 | #: views/home.html.php:75
136 | msgid "Root"
137 | msgstr "Racine"
138 | 
139 | #: views/home.html.php:83
140 | msgid "No files yet."
141 | msgstr "Aucun fichier."
142 | 
143 | #: views/home.html.php:84
144 | msgid "Delete this folder"
145 | msgstr "Supprimer ce répertoire"
146 | 
147 | #: views/home.html.php:91
148 | msgid "Share your own files"
149 | msgstr "Partager vos propres fichiers"
150 | 
151 | #: views/home.html.php:96
152 | msgid "Drag & drop here"
153 | msgstr "Glissez/déposez ici"
154 | 
155 | #: views/home.html.php:97
156 | msgid "or"
157 | msgstr "ou"
158 | 
159 | #: views/home.html.php:98
160 | msgid "Click to open the file browser"
161 | msgstr "Cliquer pour sélectionner un fichier"
162 | 
163 | #: views/home.html.php:104
164 | msgid "Create a folder"
165 | msgstr "Créer un répertoire"
166 | 
167 | #: views/home.html.php:108
168 | msgid "Folder name"
169 | msgstr "Nom du répertoire"
170 | 
171 | #: views/home.html.php:110
172 | msgid "OK"
173 | msgstr "OK"
174 | 
175 | #: views/home.html.php:123
176 | msgid "No messages. You are the first!"
177 | msgstr "Aucun message. Vous êtes le premier !"
178 | 
179 | #: views/home.html.php:126
180 | msgid "Comment"
181 | msgstr "Commenter"
182 | 
183 | #: views/home.html.php:128
184 | msgid "Send"
185 | msgstr "Envoyer"
186 | 
187 | #: views/layout.html.php:53
188 | msgid "Any problem? Contribute!"
189 | msgstr "Un problème ? Contribuez !"
190 | 
--------------------------------------------------------------------------------
/i18n/localization.pot:
--------------------------------------------------------------------------------
  1 | # SOME DESCRIPTIVE TITLE.
  2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
  3 | # This file is distributed under the same license as the PACKAGE package.
  4 | # FIRST AUTHOR , YEAR.
  5 | #
  6 | #, fuzzy
  7 | msgid ""
  8 | msgstr ""
  9 | "Project-Id-Version: PACKAGE VERSION\n"
 10 | "Report-Msgid-Bugs-To: \n"
 11 | "POT-Creation-Date: 2015-07-25 13:39+0200\n"
 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 13 | "Last-Translator: FULL NAME \n"
 14 | "Language-Team: LANGUAGE \n"
 15 | "Language: \n"
 16 | "MIME-Version: 1.0\n"
 17 | "Content-Type: text/plain; charset=CHARSET\n"
 18 | "Content-Transfer-Encoding: 8bit\n"
 19 | 
 20 | #: controller.php:46
 21 | msgid "Invalid destination."
 22 | msgstr ""
 23 | 
 24 | #: controller.php:80 controller.php:138 controller.php:227 controller.php:266
 25 | #: controller.php:284
 26 | msgid "Unauthorized."
 27 | msgstr ""
 28 | 
 29 | #: controller.php:84 controller.php:185
 30 | msgid "Invalid filename."
 31 | msgstr ""
 32 | 
 33 | #: controller.php:88 controller.php:142
 34 | msgid "File not found."
 35 | msgstr ""
 36 | 
 37 | #: controller.php:92 controller.php:189 controller.php:243
 38 | msgid "File already exists."
 39 | msgstr ""
 40 | 
 41 | #: controller.php:96
 42 | msgid "Renaming failed."
 43 | msgstr ""
 44 | 
 45 | #: controller.php:149
 46 | msgid "Cannot read this directory."
 47 | msgstr ""
 48 | 
 49 | #: controller.php:153
 50 | msgid "Not empty directory."
 51 | msgstr ""
 52 | 
 53 | #: controller.php:157
 54 | msgid "Cannot delete this directory."
 55 | msgstr ""
 56 | 
 57 | #: controller.php:162
 58 | msgid "Cannot delete this file."
 59 | msgstr ""
 60 | 
 61 | #: controller.php:177 controller.php:235
 62 | msgid "Invalid directory."
 63 | msgstr ""
 64 | 
 65 | #: controller.php:181 controller.php:231
 66 | msgid "The file system has reached the maximum limit of space."
 67 | msgstr ""
 68 | 
 69 | #: controller.php:196
 70 | msgid "Uploading failed."
 71 | msgstr ""
 72 | 
 73 | #: controller.php:239
 74 | msgid "Invalid directory name."
 75 | msgstr ""
 76 | 
 77 | #: controller.php:247
 78 | msgid "Creating folder failed."
 79 | msgstr ""
 80 | 
 81 | #: controller.php:296
 82 | msgid "Failed to open chat log."
 83 | msgstr ""
 84 | 
 85 | #: controller.php:300
 86 | msgid "Invalid count number."
 87 | msgstr ""
 88 | 
 89 | #: views/home.html.php:34
 90 | msgid "Files"
 91 | msgstr ""
 92 | 
 93 | #: views/home.html.php:35
 94 | msgid "Chat"
 95 | msgstr ""
 96 | 
 97 | #: views/home.html.php:39
 98 | msgid "Upload a new file"
 99 | msgstr ""
100 | 
101 | #: views/home.html.php:40
102 | msgid "Pseudo"
103 | msgstr ""
104 | 
105 | #: views/home.html.php:48
106 | msgid "Are you sure you want to delete this file?"
107 | msgstr ""
108 | 
109 | #: views/home.html.php:49
110 | msgid "Are you sure you want to delete this folder?"
111 | msgstr ""
112 | 
113 | #: views/home.html.php:50
114 | msgid "Open"
115 | msgstr ""
116 | 
117 | #: views/home.html.php:51 views/home.html.php:61
118 | msgid "Download"
119 | msgstr ""
120 | 
121 | #: views/home.html.php:52 views/home.html.php:64
122 | msgid "Rename"
123 | msgstr ""
124 | 
125 | #: views/home.html.php:53 views/home.html.php:65
126 | msgid "Delete"
127 | msgstr ""
128 | 
129 | #: views/home.html.php:70
130 | msgid "Download the others' files"
131 | msgstr ""
132 | 
133 | #: views/home.html.php:75
134 | msgid "Root"
135 | msgstr ""
136 | 
137 | #: views/home.html.php:83
138 | msgid "No files yet."
139 | msgstr ""
140 | 
141 | #: views/home.html.php:84
142 | msgid "Delete this folder"
143 | msgstr ""
144 | 
145 | #: views/home.html.php:91
146 | msgid "Share your own files"
147 | msgstr ""
148 | 
149 | #: views/home.html.php:96
150 | msgid "Drag & drop here"
151 | msgstr ""
152 | 
153 | #: views/home.html.php:97
154 | msgid "or"
155 | msgstr ""
156 | 
157 | #: views/home.html.php:98
158 | msgid "Click to open the file browser"
159 | msgstr ""
160 | 
161 | #: views/home.html.php:104
162 | msgid "Create a folder"
163 | msgstr ""
164 | 
165 | #: views/home.html.php:108
166 | msgid "Folder name"
167 | msgstr ""
168 | 
169 | #: views/home.html.php:110
170 | msgid "OK"
171 | msgstr ""
172 | 
173 | #: views/home.html.php:123
174 | msgid "No messages. You are the first!"
175 | msgstr ""
176 | 
177 | #: views/home.html.php:126
178 | msgid "Comment"
179 | msgstr ""
180 | 
181 | #: views/home.html.php:128
182 | msgid "Send"
183 | msgstr ""
184 | 
185 | #: views/layout.html.php:53
186 | msgid "Any problem? Contribute!"
187 | msgstr ""
188 | 
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
 1 | 
 5 |  * Contribute at https://github.com/jvaubourg/php-piratebox
 6 |  * 
 7 |  * This program is free software: you can redistribute it and/or modify
 8 |  * it under the terms of the GNU Affero General Public License as published by
 9 |  * the Free Software Foundation, either version 3 of the License, or
10 |  * (at your option) any later version.
11 |  * 
12 |  * This program is distributed in the hope that it will be useful,
13 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 |  * GNU Affero General Public License for more details.
16 |  * 
17 |  * You should have received a copy of the GNU Affero General Public License
18 |  * along with this program.  If not, see  .
19 |  */
20 | 
21 | require dirname(__FILE__).'/lib/limonade.php';
22 | require dirname(__FILE__).'/controller.php';
23 | require dirname(__FILE__).'/lib/unix_func.php';
24 | //require '/usr/share/php/php-gettext/gettext.inc';
25 | require dirname(__FILE__).'/framework.php';
26 | 
27 | run();
28 | 
--------------------------------------------------------------------------------
/lib/limonade/abstract.php:
--------------------------------------------------------------------------------
  1 | 
 40 |  * function autoload_controller($callback)
 41 |  * {
 42 |  *   require_once_dir(option('controllers_dir'));
 43 |  * }
 44 |  * 
 45 |  * 
 46 |  *
 47 |  * @param string $callback the callback defined in matching route
 48 |  * @return void
 49 |  */
 50 | function autoload_controller($callback)
 51 | {
 52 |   return;
 53 | }
 54 |  
 55 | /**
 56 |  * Called before each request.
 57 |  * This is very useful to define a default layout or passing common variables
 58 |  * to the templates.
 59 |  *
 60 |  * @abstract this function might be redefined by user
 61 |  * @param array() $route array (like returned by {@link route_build()},
 62 |  *   with keys "method", "pattern", "names", "callback", "options")
 63 |  * @return void 
 64 |  */
 65 | function before($route)
 66 | {
 67 |   
 68 | }
 69 |  
 70 | /**
 71 |  * An `after` output filter
 72 |  * 
 73 |  * Called after each request and can apply a transformation to the output
 74 |  * (except for `render_file` outputs  which are sent directly to the output buffer).
 75 |  *
 76 |  * @abstract this function might be redefined by user
 77 |  * @param string $output 
 78 |  * @param array() $route array (like returned by {@link route_find()},
 79 |  *   with keys "method", "pattern", "names", "callback", "params", "options")
 80 |  * @return string 
 81 |  */
 82 | function after($output, $route)
 83 | {
 84 |   # Call functions...
 85 |   # .. modifies $output...
 86 |   return $output;
 87 | }
 88 |  
 89 | /**
 90 |  * Not found error output
 91 |  *
 92 |  * @abstract this function might be redefined by user
 93 |  * @param string $errno 
 94 |  * @param string $errstr 
 95 |  * @param string $errfile 
 96 |  * @param string $errline 
 97 |  * @return string "not found" output string
 98 |  */
 99 | function not_found($errno, $errstr, $errfile=null, $errline=null)
100 | {
101 |  
102 | }
103 |  
104 | /**
105 |  * Server error output
106 |  *
107 |  * @abstract this function might be redefined by user
108 |  * @param string $errno 
109 |  * @param string $errstr 
110 |  * @param string $errfile 
111 |  * @param string $errline 
112 |  * @return string "server error" output string
113 |  */
114 | function server_error($errno, $errstr, $errfile=null, $errline=null)
115 | {
116 |   
117 | }
118 |  
119 | /**
120 |  * Called when a route is not found.
121 |  * 
122 |  * 
123 |  * @abstract this function might be redefined by user
124 |  * @param string $request_method 
125 |  * @param string $request_uri 
126 |  * @return void 
127 |  */
128 | function route_missing($request_method, $request_uri)
129 | {
130 |   halt(NOT_FOUND, "($request_method) $request_uri"); # by default
131 | }
132 | 
133 | /**
134 |  * Called before stoppping and exiting application.
135 |  *
136 |  * @abstract this function might be redefined by user
137 |  * @param boolean exit or not
138 |  * @return void 
139 |  */
140 | function before_exit($exit)
141 | {
142 |   
143 | }
144 | 
145 | /**
146 |  * Rendering prefilter.
147 |  * Useful if you want to transform your views before rendering.
148 |  * The first three parameters are the same as those provided 
149 |  * to the `render` function.
150 |  *
151 |  * @abstract this function might be redefined by user
152 |  * @param string $content_or_func a function, a file in current views dir or a string
153 |  * @param string $layout 
154 |  * @param array $locals 
155 |  * @param array $view_path (by default file_path(option('views_dir'),$content_or_func);)
156 |  * @return array with, in order, $content_or_func, $layout, $locals vars
157 |  *  and the calculated $view_path
158 |  */
159 | function before_render($content_or_func, $layout, $locals, $view_path)
160 | {
161 |   # transform $content_or_func, $layout, $locals or $view_path…
162 |   return array($content_or_func, $layout, $locals, $view_path);
163 | }
164 | 
165 | 
166 | /**
167 |  * Called only if rendering $output is_null,
168 |  * like in a controller with no return statement.
169 |  *
170 |  * @abstract this function might be defined by user
171 |  * @param array() $route array (like returned by {@link route_build()},
172 |  *   with keys "method", "pattern", "names", "callback", "options")
173 |  * @return string
174 |  */
175 | function autorender($route)
176 | {
177 |   # process output depending on $route
178 |   return $output;
179 | }
180 | 
181 | /**
182 |  * Called if a header is about to be sent
183 |  *
184 |  * @abstract this function might be defined by user
185 |  * @param string the headers that limonade will send
186 |  * @return void
187 |  */
188 | function before_sending_header($header)
189 | {
190 | 
191 | }
192 | 
193 | 
194 | 
--------------------------------------------------------------------------------
/lib/limonade/assertions.php:
--------------------------------------------------------------------------------
  1 |  should be TRUE')
 18 | {
 19 |    test_run_assertion();
 20 |    return assert('$value === TRUE; //'.$message);
 21 | }
 22 | 
 23 | function assert_false($value, $message = '<1> should be FALSE')
 24 | {
 25 |    test_run_assertion();
 26 |    return assert('$value === FALSE; //'.$message);
 27 | }
 28 | 
 29 | function assert_null($value, $message = '<1> should be NULL')
 30 | {
 31 |    test_run_assertion();
 32 |    return assert('$value === NULL; //'.$message);
 33 | }
 34 | 
 35 | function assert_not_null($value, $message = '<1> should not be NULL')
 36 | {
 37 |    test_run_assertion();
 38 |    return assert('$value !== NULL; //'.$message);
 39 | }
 40 | 
 41 | function assert_empty($value, $message = '<1> should be empty')
 42 | {
 43 |    test_run_assertion();
 44 |    return assert('empty($value); //'.$message);
 45 | }
 46 | 
 47 | function assert_not_empty($value, $message = '<1> should not be empty')
 48 | {
 49 |    test_run_assertion();
 50 |    return assert('!empty($value); //'.$message);
 51 | }
 52 | 
 53 | function assert_equal($expected, $value, $message = '<1> should be equal to <2>')
 54 | {
 55 |    test_run_assertion();
 56 |    return assert('$expected == $value; //'.$message);
 57 | }
 58 | 
 59 | function assert_not_equal($expected, $value, $message = '<1> should not equal to <2>')
 60 | {
 61 |    test_run_assertion();
 62 |    return assert('$expected != $value; //'.$message);
 63 | }
 64 | 
 65 | function assert_identical($expected, $value, $message = '<1> should be identical to <2>')
 66 | {
 67 |    test_run_assertion();
 68 |    return assert('$expected === $value; //'.$message);
 69 | }
 70 | 
 71 | function assert_not_identical($expected, $value, $message = '<1> should not be identical to <2>')
 72 | {
 73 |    test_run_assertion();
 74 |    return assert('$expected !== $value; //'.$message);
 75 | }
 76 | 
 77 | function assert_match($pattern, $string, $message = '<2> expected to match regular expression <1>') {
 78 |    test_run_assertion();
 79 |    return assert('preg_match($pattern, $string); //'.$message);
 80 | }
 81 |  
 82 | function assert_no_match($pattern, $string, $message = '<2> expected to not match regular expression <1>') {
 83 |    test_run_assertion();
 84 |    return assert('!preg_match($pattern, $string); //'.$message);
 85 | }
 86 | 
 87 | function assert_type($type, $value, $message = '<1> is not of type <2>') {
 88 |   test_run_assertion();
 89 |   $predicate = 'is_' . strtolower(is_string($type) ? $type : gettype($type));
 90 |   return assert('$predicate($value); //'.$message);
 91 | }
 92 |  
 93 | function assert_instance_of($class, $object, $message = '<2> is not an instance of class <1>') {
 94 |    test_run_assertion();
 95 |    return assert('$object instanceof $class; //'.$message);
 96 | }
 97 |  
 98 | function assert_length_of($value, $length, $message = '<1> expected to be of length <2>') {
 99 |    test_run_assertion();
100 |    $count = is_string($value) ? 'strlen' : 'count';
101 |    return assert('$count($value) == $length; //'.$message);
102 | }
103 | 
104 | function assert_trigger_error($callable, $args = array(), $message = '<1> should trigger an error') {
105 |   test_run_assertion();
106 |   $trigger_errors = count($GLOBALS["limonade"]["test_errors"]);
107 |   set_error_handler("test_error_handler");
108 |   $result = call_user_func_array($callable, $args);
109 |   restore_error_handler();
110 |   return assert('$trigger_errors < count($GLOBALS["limonade"]["test_errors"]); //'.$message);
111 | }
112 | 
113 | # TODO add web browser assertions assert_http_get, assert_http_response... as in SimpleTest (http://www.simpletest.org/en/web_tester_documentation.html)
114 | 
115 | function assert_header($response, $expected_name, $expected_value = null, $message = "expected header '%s' to be equal to '%s' but received '%s: %s'")
116 | {
117 |   test_run_assertion();
118 |   # see assert_header in http://github.com/fnando/voodoo-test/blob/f3b0994ef138a6ba94d5e7cef6c1fb1720797a86/lib/assertions.php
119 |   $headers = preg_split("/^\s*$/ms", $response);
120 |   //var_dump($headers);    
121 |   $headers = preg_replace("/\s*$/sm", "", $headers[0]);
122 |   //var_dump($headers);   
123 |   
124 |   $regex_header = str_replace("/", "\\/", $expected_name);
125 |   $regex_header = str_replace(".", "\\.", $regex_header);
126 |   
127 |   $header = $expected_name;
128 |   
129 |   # from http://www.faqs.org/rfcs/rfc2616
130 |   # Field names are case-insensitive
131 |   if ($expected_value) {
132 |       $regex = "/^{$regex_header}:(.*?)$/ism";
133 |       $header .= ": {$expected_value}";
134 |   } else {
135 |       $regex = "/^{$regex_header}(:.*?)?$/ism";
136 |   }
137 |   
138 |   $has_header = preg_match($regex, $headers, $matches);    
139 |   $sent_header = trim((string)$matches[1]);
140 | 
141 |   
142 |   if(empty($sent_header))
143 |   {
144 |     if(is_null($expected_value))
145 |     {
146 |       $message = "expected header '%s' but header has not been sent";
147 |     }
148 |     else
149 |     {
150 |       $message = "expected header '%s' to be equal to '%s' but header has not been sent";
151 |     }
152 |     
153 |     $message = sprintf($message, $expected_name, $expected_value);
154 |     return assert("false; //".$message);
155 |   }
156 |   else if($expected_value)
157 |   {
158 |     $message = sprintf($message, $expected_name, $expected_value, $expected_name, $sent_header);
159 |     return assert('$expected_value && $sent_header == $expected_value; //'.$message);
160 |   }
161 |   return assert("true; //");
162 | }
163 | 
164 | function assert_status($response, $expected_status, $message = "expected status code to be equal to '%s' but received '%s'")
165 | {
166 |   $lines = explode('\n', trim($response));
167 |   if (preg_match('/HTTP\/(\d+\.\d+)\s+(\d+)/i', $lines[0], $matches))
168 |   {
169 |       $status = $matches[2];
170 |       return assert('$expected_status == $status; //'.sprintf($message, $expected_status, $status));
171 |   }
172 |   return assert("false; //no status code returned in this response string");
173 | }
174 | 
--------------------------------------------------------------------------------
/lib/limonade/public/css/screen.css:
--------------------------------------------------------------------------------
  1 | /* -----------------------------------------------------------------------
  2 | 
  3 | 
  4 |  Blueprint CSS Framework 0.8
  5 |  http://blueprintcss.org
  6 | 
  7 |    * Copyright (c) 2007-Present. See LICENSE for more info.
  8 |    * See README for instructions on how to use Blueprint.
  9 |    * For credits and origins, see AUTHORS.
 10 |    * This is a compressed file. See the sources in the 'src' directory.
 11 | 
 12 | ----------------------------------------------------------------------- */
 13 | 
 14 | /* reset.css */
 15 | html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;}
 16 | body {line-height:1.5;}
 17 | table {border-collapse:separate;border-spacing:0;}
 18 | caption, th, td {text-align:left;font-weight:normal;}
 19 | table, td, th {vertical-align:middle;}
 20 | blockquote:before, blockquote:after, q:before, q:after {content:"";}
 21 | blockquote, q {quotes:"" "";}
 22 | a img {border:none;}
 23 | 
 24 | /* typography.css */
 25 | body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;}
 26 | h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;}
 27 | h1 {font-size:3em;line-height:1;margin-bottom:0.5em;}
 28 | h2 {font-size:2em;margin-bottom:0.75em;}
 29 | h3 {font-size:1.5em;line-height:1;margin-bottom:1em;}
 30 | h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;}
 31 | h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;}
 32 | h6 {font-size:1em;font-weight:bold;}
 33 | h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;}
 34 | p {margin:0 0 1.5em;}
 35 | p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;}
 36 | p img.right {float:right;margin:1.5em 0 1.5em 1.5em;}
 37 | a:focus, a:hover {color:#000;}
 38 | a {color:#009;text-decoration:underline;}
 39 | blockquote {margin:1.5em;color:#666;font-style:italic;}
 40 | strong {font-weight:bold;}
 41 | em, dfn {font-style:italic;}
 42 | dfn {font-weight:bold;}
 43 | sup, sub {line-height:0;}
 44 | abbr, acronym {border-bottom:1px dotted #666;}
 45 | address {margin:0 0 1.5em;font-style:italic;}
 46 | del {color:#666;}
 47 | pre {margin:1.5em 0;white-space:pre;}
 48 | pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;}
 49 | li ul, li ol {margin:0 1.5em;}
 50 | ul, ol {margin:0 1.5em 1.5em 1.5em;}
 51 | ul {list-style-type:disc;}
 52 | ol {list-style-type:decimal;}
 53 | dl {margin:0 0 1.5em 0;}
 54 | dl dt {font-weight:bold;}
 55 | dd {margin-left:1.5em;}
 56 | table {margin-bottom:1.4em;width:100%;}
 57 | th {font-weight:bold;}
 58 | thead th {background:#c3d9ff;}
 59 | th, td, caption {padding:4px 10px 4px 5px;}
 60 | tr.even td {background:#e5ecf9;}
 61 | tfoot {font-style:italic;}
 62 | caption {background:#eee;}
 63 | .small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;}
 64 | .large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;}
 65 | .hide {display:none;}
 66 | .quiet {color:#666;}
 67 | .loud {color:#000;}
 68 | .highlight {background:#ff0;}
 69 | .added {background:#060;color:#fff;}
 70 | .removed {background:#900;color:#fff;}
 71 | .first {margin-left:0;padding-left:0;}
 72 | .last {margin-right:0;padding-right:0;}
 73 | .top {margin-top:0;padding-top:0;}
 74 | .bottom {margin-bottom:0;padding-bottom:0;}
 75 | 
 76 | /* forms.css */
 77 | label {font-weight:bold;}
 78 | fieldset {padding:1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;}
 79 | legend {font-weight:bold;font-size:1.2em;}
 80 | input.text, input.title, textarea, select {margin:0.5em 0;border:1px solid #bbb;}
 81 | input.text:focus, input.title:focus, textarea:focus, select:focus {border:1px solid #666;}
 82 | input.text, input.title {width:300px;padding:5px;}
 83 | input.title {font-size:1.5em;}
 84 | textarea {width:390px;height:250px;padding:5px;}
 85 | .error, .notice, .success {padding:.8em;margin-bottom:1em;border:2px solid #ddd;}
 86 | .error {background:#FBE3E4;color:#8a1f11;border-color:#FBC2C4;}
 87 | .notice {background:#FFF6BF;color:#514721;border-color:#FFD324;}
 88 | .success {background:#E6EFC2;color:#264409;border-color:#C6D880;}
 89 | .error a {color:#8a1f11;}
 90 | .notice a {color:#514721;}
 91 | .success a {color:#264409;}
 92 | 
 93 | .box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;}
 94 | hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;}
 95 | hr.space {background:#fff;color:#fff;}
 96 | .clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;}
 97 | .clearfix, .container {display:block;}
 98 | .clear {clear:both;}
 99 | 
100 | /* -----------------------------------------------------------------------
101 | 
102 |  LIMONADE
103 |  
104 |  Design and logo by Minimau 
105 | 
106 | ----------------------------------------------------------------------- */
107 | 
108 | html {
109 |  	background-color: #b4a689;
110 |  	text-align: center;
111 |  	}
112 |  	body {
113 |  		width: auto; /* 16 col */
114 |  		margin: 0 20px;
115 |  		text-align: left;
116 |  		/*background: #fff url(blueprint/src/grid.png);*/
117 |  		font-family: Verdana, Geneva, sans-serif;
118 |  		color: #303030;
119 |  		}
120 |  		a, a:hover, a:visited {
121 |  			color: #4596cd;
122 |  			}
123 |  		a:hover {
124 |  			text-decoration: none;
125 |  			}
126 |  		#header, h1, h2, h3, h4 {
127 |  			font-family: "Arial Black", Gadget, sans-serif;
128 |  			}
129 |  		h1 {
130 |  			color: #b4a689;
131 |  			font-size: 2em;
132 |  			line-height: 2;
133 |  			border-bottom: 7px solid #000;
134 |  			margin-bottom: 0.75em;
135 |  			margin-top:0;
136 |  			}
137 |  		h2 {
138 |  			font-size: 1.5em;
139 |  			color: #cddb12;
140 |  			margin-top: 2em;
141 |  			line-height: 0.8;
142 |  			margin-bottom: 1.2em;
143 |  			}
144 |  		h3 {
145 |  			font-size: 1.33em;
146 |  			line-height: 0.89;
147 |  			margin-top: 2.66em;
148 |  			margin-bottom: 1.33em;
149 |  			color:#95b383;
150 |  			}
151 |  		pre {
152 |  			background-color: #cddb12;
153 |  			font-size: 12px;
154 |  			padding: 1.5em;
155 |  			margin-bottom: 1.5em;
156 |  			overflow: auto;
157 |  			}
158 |  		code {
159 |  			font: 10px Monaco, "Courier New", Courier, monospace;
160 |  			color: #0d562a;
161 |  			}
162 |  		#header {
163 |  			/*position:relative;*/
164 |  			height: 187px; /* 12 lines */
165 |  			background: #fff url(=url_for('/_lim_public/img/bg_header.png')?>) no-repeat 0 0;
166 |  			margin-top: 10px;
167 |       padding:0;
168 |  			}
169 |  			#header h1 {
170 |  				position: absolute;
171 |  				left:-9999px;
172 |  				   			margin:0;
173 |  				}
174 |  		#footer {
175 |  			padding: 0 55px;
176 |  			background-color: #1a1818;
177 |  			color: #999;
178 |  			height: 2em;
179 |  			line-height: 2em;
180 |  			text-align: right;
181 |  			}
182 |  			#footer a {
183 |  				color: #a3d8de;
184 |  				text-decoration: none;
185 |  				}
186 |  			#footer a:hover {
187 |  				color: #fff;
188 |  				}
189 |  		#content {
190 |  		  background-color: #fff;
191 |  			padding: 0 55px;
192 |  			min-height: 400px;
193 |  			}
194 |     		p.bt {
195 |     		   text-align:right;
196 |     		   }
197 |        		p.bt a {
198 |        		   text-decoration:none;
199 |        		   padding: 2px 4px;
200 |        		   }
201 |        		p.bt a:hover {
202 |       	      background-color: #4596cd;
203 |       	      color: #fff;
204 |       	      }
205 |       	#debug-menu {
206 |       	   position: fixed;
207 |       	   top: 0px;
208 |       	   right:20px;
209 |       	   background-color: rgba(100,100,100, 0.7);
210 |       	   padding:5px;
211 |       	}
212 |       	#debug-menu a {
213 |       	   color: #fff;
214 |       	   font-size: 90%;
215 |       	   text-decoration:none;
216 |    	   }
217 |    	   #debug-menu a:hover {
218 |    	      text-decoration: underline;
219 | 	      }
220 |    	
--------------------------------------------------------------------------------
/lib/limonade/public/img/bg_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvaubourg/php-piratebox/d9cc1a57b9b99a0e4d63d0e518193f70876b221d/lib/limonade/public/img/bg_header.png
--------------------------------------------------------------------------------
/lib/limonade/tests.php:
--------------------------------------------------------------------------------
  1 | >>> START $name tests suites\n", 'white');
 57 |   echo test_cli_format("-----------------------------------------------------------\n", 'white');
 58 | }
 59 | 
 60 | /**
 61 |  * Ends the last group of test suites
 62 |  *
 63 |  * @return void
 64 |  */
 65 | function end_test_suite()
 66 | {
 67 |   $name         = $GLOBALS["limonade"]["test_suites"];
 68 |   $failures     = 0;
 69 |   $tests        = 0;
 70 |   $passed_tests = 0;
 71 |   $assertions   = 0;
 72 | 
 73 |   foreach($GLOBALS["limonade"]["test_cases"] as $test)
 74 |   {
 75 |     $failures += $test['failures'];
 76 |     $assertions += $test['assertions'];
 77 |     if(empty($test['failures'])) $passed_tests++;
 78 |     $tests++;
 79 |   }
 80 |   echo ">> ENDING $name tests suites\n  ";
 81 |   echo $failures > 0 ? test_cli_format("|FAILED!|", "red") : test_cli_format("|PASSED|", "green");;
 82 |   echo " Passes ".$passed_tests."/".$tests.", ";
 83 |   echo " {$failures} failures for {$assertions} assertions.\n";
 84 |   echo test_cli_format("===========================================================\n", 'white');
 85 | }
 86 | 
 87 | /**
 88 |  * Starting a new test case
 89 |  *
 90 |  * @param string $name 
 91 |  * @return void
 92 |  */
 93 | function test_case($name)
 94 | {
 95 |    $name = strtolower($name); // TODO: normalize name
 96 |    
 97 |    if(!array_key_exists($name, $GLOBALS["limonade"]["test_cases"]))
 98 |    {
 99 |       $GLOBALS["limonade"]["test_cases"][$name] = array( 
100 |                                                       "name" => $name,
101 |                                                       "assertions" => 0, 
102 |                                                       "failures" => 0,
103 |                                                       "description" => NULL
104 |                                                    );      
105 |       $GLOBALS["limonade"]["test_case_current"] = $name;
106 |    }
107 |    else
108 |    {
109 |       
110 |    }
111 | }
112 | 
113 | /**
114 |  * Displays and ending the current tests suite
115 |  * 
116 |  * @return void
117 |  */
118 | function end_test_case()
119 | {
120 |    $name = $GLOBALS["limonade"]["test_case_current"];
121 |    echo "## ".strtoupper($name)."\n";
122 |       
123 |    $desc = test_case_describe();
124 |    if(!is_null($desc)) echo $desc."\n";
125 | 
126 |    echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n";
127 |    
128 |    test_case_execute_current();
129 |    
130 |    
131 |    if(!is_null($name))
132 |    {
133 |       $test = $GLOBALS["limonade"]["test_cases"][$name];
134 |       // closing previous test
135 |       echo "\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n";
136 |       echo $test['failures'] > 0 ? test_cli_format("|FAILED!|", "red") : test_cli_format("|PASSED|", "green");
137 |       echo " Test case '$name' finished: ";
138 |       echo count(test_case_all_func())." tests, ";
139 |       echo " {$test['failures']} failures for {$test['assertions']} assertions.\n";
140 |       
141 |       echo "-----------------------------------------------------------\n";
142 |    }
143 |    $GLOBALS["limonade"]["test_case_current"] = null;
144 | }
145 | 
146 | /**
147 |  * Describes the current tests suite
148 |  *
149 |  * @param string $msg 
150 |  * @return string tests description
151 |  */
152 | function test_case_describe($msg = NULL)
153 | {
154 |    $test =& test_case_current();
155 |    if(!is_null($msg))
156 |    {
157 |       $test["description"] = $msg;
158 |    }
159 |    //var_dump($test["description"]);
160 |    return $test["description"];
161 | }
162 | 
163 | /**
164 |  * Returns all user test case functions
165 |  *
166 |  * @access private
167 |  * @return void
168 |  */
169 | function test_case_all_func()
170 | {
171 |    $functions = get_defined_functions();
172 |    $functions = $functions['user'];
173 |    $tests = array();
174 |    $name = $GLOBALS["limonade"]["test_case_current"];
175 |    while ($func = array_shift($functions)) {
176 |       $regexp = "/^test_{$name}_(.*)$/";
177 |       if(!preg_match($regexp, $func)) continue;
178 |       if($func == test_before_func_name()) continue;
179 |       // TODO: adding break for all test api methods
180 |       
181 |       $tests[] = $func;
182 |    }
183 |    return $tests;
184 | }
185 | 
186 | /**
187 |  * Execute current test case
188 |  *
189 |  * @access private
190 |  * @return void
191 |  */
192 | function test_case_execute_current()
193 | {
194 |    $tests = test_case_all_func();
195 |    while($func = array_shift($tests))
196 |    {
197 |       test_call_func(test_before_func_name());
198 |       call_user_func($func);
199 |    }
200 | }
201 | 
202 | 
203 | function &test_case_current()
204 | {
205 |    $name = $GLOBALS["limonade"]["test_case_current"];
206 |    return $GLOBALS["limonade"]["test_cases"][$name];
207 | }
208 | 
209 | 
210 | 
211 | function test_before_func_name()
212 | {
213 |    $test = test_case_current();
214 |    $func = "before_each_test_in_".$test["name"];
215 |    return $func;
216 | }
217 | 
218 | function test_before_assert_func_name()
219 | {
220 |    $test = test_case_current();
221 |    $func = "before_each_assert_in_$name".$test["name"];
222 |    return $func;
223 | }
224 | 
225 | function test_run_assertion()
226 | {
227 |    $name = $GLOBALS["limonade"]["test_case_current"];
228 |    $GLOBALS["limonade"]["test_cases"][$name]['assertions']++;
229 |    test_call_func(test_before_assert_func_name());
230 | }
231 | 
232 | /**
233 |  * Calls a function if exists
234 |  *
235 |  * @param string $func the function name
236 |  * @param mixed $arg,.. (optional)
237 |  * @return mixed
238 |  */
239 | function test_call_func($func)
240 | {
241 |   if(empty($func)) return;
242 |   $args = func_get_args();
243 |   $func = array_shift($args);
244 |   if(function_exists($func)) return call_user_func_array($func, $args);
245 |   return;
246 | }
247 | 
248 | /**
249 |  * Error handler 
250 |  * 
251 |  * @access private
252 |  * @return boolean true
253 |  */
254 | function test_error_handler($errno, $errstr, $errfile, $errline)
255 | {
256 | 	if($errno < E_USER_ERROR || $errno > E_USER_NOTICE) 
257 | 	   echo test_cli_format("!!! ERROR", "red") . " [$errno], $errstr in $errfile at line $errline\n";
258 | 	$GLOBALS["limonade"]["test_errors"][] = array($errno, $errstr, $errfile, $errline);
259 |    return true;
260 | }
261 | 
262 | /**
263 |  * Assert callback
264 |  * 
265 |  * @access private
266 |  * @param string $script 
267 |  * @param string $line 
268 |  * @param string $message 
269 |  * @return void
270 |  */
271 | function test_assert_failure($script, $line, $message)
272 | {
273 |    // Using the stack trace, find the outermost assert*() call
274 |    $stacktrace = array_slice(debug_backtrace(), 1); // skip self
275 |    $assertion = reset($stacktrace);
276 |    while ($stackframe = array_shift($stacktrace)) {
277 |     if (!preg_match('/^assert/', $stackframe['function']))
278 |       break;
279 |     $assertion = $stackframe;
280 |    }
281 | 
282 |    extract($assertion, EXTR_PREFIX_ALL, 'assert');
283 |    $code = explode("\n", file_get_contents($assert_file));
284 |    $code = trim($code[$assert_line - 1]);
285 |    
286 |    list($assert_code, $message) = explode("//", $message);
287 |    echo test_cli_format("Assertion failed", "yellow");
288 |    echo " in script *{$assert_file}* (line {$assert_line}):\n";
289 |    echo "   * assertion: $code\n";
290 |    echo "   * message:   $message\n";
291 |    $name = $GLOBALS["limonade"]["test_case_current"];
292 |    $GLOBALS["limonade"]["test_cases"][$name]['failures']++;
293 | }
294 | 
295 | function test_cli_format($text, $format) {
296 |     $formats = array(
297 |         "blue"       => 34,
298 |         "bold"       => 1,
299 |         "green"      => 32,
300 |         "highlight"  => 7,
301 |         "light_blue" => 36,
302 |         "purple"     => 35,
303 |         "red"        => 31,
304 |         "underline"  => 4,
305 |         "white"      => 37,
306 |         "yellow"     => 33
307 |     );
308 | 
309 |     if (array_key_exists($format, $formats)) $format = $formats[$format];
310 |     return chr(27) . "[01;{$format} m{$text}" . chr(27) . "[00m";
311 | }
312 | 
313 | /**
314 |  * Do HTTP request and return the response content.
315 |  * 
316 |  * @param string $url
317 |  * @param string $method
318 |  * @param bool $include_header
319 |  * @return string
320 |  * @author Nando Vieira
321 |  */
322 | function test_request($url, $method="GET", $include_header=false, $post_data=array(), $http_header=array()) {
323 |     $method = strtoupper($method);
324 |     $allowed_methods = array("GET", "PUT", "POST", "DELETE", "HEAD");
325 |     if(!in_array($method, $allowed_methods))
326 |     {
327 |       $message = "The requested method '$method' is not allowed";
328 |       return assert('false; //'.$message);
329 |     }
330 |     
331 |     $curl = curl_init($url);
332 |     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
333 |     curl_setopt($curl, CURLOPT_HEADER, $include_header);
334 |     curl_setopt($curl, CURLOPT_HTTPHEADER, $http_header);
335 |     curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
336 |     curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); 
337 |     if($method == 'POST' || $method == 'PUT')
338 |     {
339 |       curl_setopt($curl, CURLOPT_POST, 1);
340 |       curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
341 |     }
342 |     if($method == 'HEAD')
343 |     {
344 |       curl_setopt($curl, CURLOPT_NOBODY, true);
345 |     }
346 |     $response = curl_exec($curl);
347 |     curl_close($curl);
348 | 
349 |     return $response;
350 | }
351 | 
--------------------------------------------------------------------------------
/lib/limonade/views/_debug.html.php:
--------------------------------------------------------------------------------
 1 |  ENV_PRODUCTION && option('debug')): ?>
 2 |   
 3 |   []
 4 |   	 (in   line  )
 5 |   	
 6 |   	
 7 | 
 8 | 
 9 |   
10 |   Debug arguments 
11 |   	 
12 |   
13 |   
14 |   Options 
15 |    
16 |   [ ↑ ] 
17 |   
18 |   Environment 
19 |    
20 |   [ ↑ ] 
21 |   
22 |   Backtrace 
23 |    
24 |   [ ↑ ] 
25 | 
26 |   
36 |   
37 | 
--------------------------------------------------------------------------------
/lib/limonade/views/_notices.html.php:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 → Notices and warnings 
 4 |   
 5 |   
 6 |     [] 
 7 |     
 8 |      in   
 9 |     line  
10 |      
11 |   
12 |    
13 |   
14 | 
 
15 | 
--------------------------------------------------------------------------------
/lib/limonade/views/default_layout.php:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 | 	 
 5 | 	Limonade, the fizzy PHP micro-framework 
 6 | 	 
 7 | 
 8 | 
 9 |   
12 |   
13 |   
14 |     
15 |     
16 |       
17 |       
 
18 |     
19 |   
 
20 | 
21 | 
22 | 
23 | 
--------------------------------------------------------------------------------
/lib/limonade/views/error.html.php:
--------------------------------------------------------------------------------
1 |    
2 |   
3 |   
4 |   
5 |   
6 |   
--------------------------------------------------------------------------------
/lib/unix_func.php:
--------------------------------------------------------------------------------
 1 | 
 6 |   *
 7 |   *  This program is free software: you can redistribute it and/or modify
 8 |   *  it under the terms of the GNU Affero General Public License as
 9 |   *  published by the Free Software Foundation, either version 3 of the
10 |   *  License, or (at your option) any later version.
11 |   *
12 |   *  This program is distributed in the hope that it will be useful,
13 |   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 |   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 |   *  GNU Affero General Public License for more details.
16 |   *
17 |   *  You should have received a copy of the GNU Affero General Public License
18 |   *  along with this program.  If not, see  .
19 |   */
20 |   
21 | function read_file($file, $lines = 20) {
22 | 
23 |     if (!$handle = fopen($file, "r"))
24 |         return false;
25 |     $linecounter = $lines;
26 |     $pos = -2;
27 |     $beginning = false;
28 |     $text = array();
29 |     while ($linecounter > 0) {
30 |         $t = " ";
31 |         while ($t != "\n") {
32 |             if(fseek($handle, $pos, SEEK_END) == -1) {
33 |                 $beginning = true;
34 |                 break;
35 |             }
36 |             $t = fgetc($handle);
37 |             $pos --;
38 |         }
39 |         $linecounter --;
40 |         if ($beginning) {
41 |             rewind($handle);
42 |         }
43 |         $text[$lines-$linecounter-1] = fgets($handle);
44 |         if ($beginning) break;
45 |     }
46 |     fclose ($handle);
47 |     return array_reverse($text);
48 | }
49 | 
50 | 
--------------------------------------------------------------------------------
/public/bootstrap/css/bootstrap-theme.css:
--------------------------------------------------------------------------------
  1 | /*!
  2 |  * Bootstrap v3.3.0 (http://getbootstrap.com)
  3 |  * Copyright 2011-2014 Twitter, Inc.
  4 |  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  5 |  */
  6 | 
  7 | .btn-default,
  8 | .btn-primary,
  9 | .btn-success,
 10 | .btn-info,
 11 | .btn-warning,
 12 | .btn-danger {
 13 |   text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
 14 |   -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
 15 |           box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
 16 | }
 17 | .btn-default:active,
 18 | .btn-primary:active,
 19 | .btn-success:active,
 20 | .btn-info:active,
 21 | .btn-warning:active,
 22 | .btn-danger:active,
 23 | .btn-default.active,
 24 | .btn-primary.active,
 25 | .btn-success.active,
 26 | .btn-info.active,
 27 | .btn-warning.active,
 28 | .btn-danger.active {
 29 |   -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
 30 |           box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
 31 | }
 32 | .btn-default .badge,
 33 | .btn-primary .badge,
 34 | .btn-success .badge,
 35 | .btn-info .badge,
 36 | .btn-warning .badge,
 37 | .btn-danger .badge {
 38 |   text-shadow: none;
 39 | }
 40 | .btn:active,
 41 | .btn.active {
 42 |   background-image: none;
 43 | }
 44 | .btn-default {
 45 |   text-shadow: 0 1px 0 #fff;
 46 |   background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
 47 |   background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
 48 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
 49 |   background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
 50 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
 51 |   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
 52 |   background-repeat: repeat-x;
 53 |   border-color: #dbdbdb;
 54 |   border-color: #ccc;
 55 | }
 56 | .btn-default:hover,
 57 | .btn-default:focus {
 58 |   background-color: #e0e0e0;
 59 |   background-position: 0 -15px;
 60 | }
 61 | .btn-default:active,
 62 | .btn-default.active {
 63 |   background-color: #e0e0e0;
 64 |   border-color: #dbdbdb;
 65 | }
 66 | .btn-default:disabled,
 67 | .btn-default[disabled] {
 68 |   background-color: #e0e0e0;
 69 |   background-image: none;
 70 | }
 71 | .btn-primary {
 72 |   background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
 73 |   background-image:      -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
 74 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2));
 75 |   background-image:         linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
 76 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
 77 |   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
 78 |   background-repeat: repeat-x;
 79 |   border-color: #2b669a;
 80 | }
 81 | .btn-primary:hover,
 82 | .btn-primary:focus {
 83 |   background-color: #2d6ca2;
 84 |   background-position: 0 -15px;
 85 | }
 86 | .btn-primary:active,
 87 | .btn-primary.active {
 88 |   background-color: #2d6ca2;
 89 |   border-color: #2b669a;
 90 | }
 91 | .btn-primary:disabled,
 92 | .btn-primary[disabled] {
 93 |   background-color: #2d6ca2;
 94 |   background-image: none;
 95 | }
 96 | .btn-success {
 97 |   background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
 98 |   background-image:      -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
 99 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
100 |   background-image:         linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
101 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
102 |   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
103 |   background-repeat: repeat-x;
104 |   border-color: #3e8f3e;
105 | }
106 | .btn-success:hover,
107 | .btn-success:focus {
108 |   background-color: #419641;
109 |   background-position: 0 -15px;
110 | }
111 | .btn-success:active,
112 | .btn-success.active {
113 |   background-color: #419641;
114 |   border-color: #3e8f3e;
115 | }
116 | .btn-success:disabled,
117 | .btn-success[disabled] {
118 |   background-color: #419641;
119 |   background-image: none;
120 | }
121 | .btn-info {
122 |   background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
123 |   background-image:      -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
124 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
125 |   background-image:         linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
126 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
127 |   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
128 |   background-repeat: repeat-x;
129 |   border-color: #28a4c9;
130 | }
131 | .btn-info:hover,
132 | .btn-info:focus {
133 |   background-color: #2aabd2;
134 |   background-position: 0 -15px;
135 | }
136 | .btn-info:active,
137 | .btn-info.active {
138 |   background-color: #2aabd2;
139 |   border-color: #28a4c9;
140 | }
141 | .btn-info:disabled,
142 | .btn-info[disabled] {
143 |   background-color: #2aabd2;
144 |   background-image: none;
145 | }
146 | .btn-warning {
147 |   background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
148 |   background-image:      -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
149 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
150 |   background-image:         linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
151 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
152 |   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
153 |   background-repeat: repeat-x;
154 |   border-color: #e38d13;
155 | }
156 | .btn-warning:hover,
157 | .btn-warning:focus {
158 |   background-color: #eb9316;
159 |   background-position: 0 -15px;
160 | }
161 | .btn-warning:active,
162 | .btn-warning.active {
163 |   background-color: #eb9316;
164 |   border-color: #e38d13;
165 | }
166 | .btn-warning:disabled,
167 | .btn-warning[disabled] {
168 |   background-color: #eb9316;
169 |   background-image: none;
170 | }
171 | .btn-danger {
172 |   background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
173 |   background-image:      -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
174 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
175 |   background-image:         linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
176 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
177 |   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
178 |   background-repeat: repeat-x;
179 |   border-color: #b92c28;
180 | }
181 | .btn-danger:hover,
182 | .btn-danger:focus {
183 |   background-color: #c12e2a;
184 |   background-position: 0 -15px;
185 | }
186 | .btn-danger:active,
187 | .btn-danger.active {
188 |   background-color: #c12e2a;
189 |   border-color: #b92c28;
190 | }
191 | .btn-danger:disabled,
192 | .btn-danger[disabled] {
193 |   background-color: #c12e2a;
194 |   background-image: none;
195 | }
196 | .thumbnail,
197 | .img-thumbnail {
198 |   -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
199 |           box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
200 | }
201 | .dropdown-menu > li > a:hover,
202 | .dropdown-menu > li > a:focus {
203 |   background-color: #e8e8e8;
204 |   background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
205 |   background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
206 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
207 |   background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
208 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
209 |   background-repeat: repeat-x;
210 | }
211 | .dropdown-menu > .active > a,
212 | .dropdown-menu > .active > a:hover,
213 | .dropdown-menu > .active > a:focus {
214 |   background-color: #357ebd;
215 |   background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
216 |   background-image:      -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
217 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
218 |   background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
219 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
220 |   background-repeat: repeat-x;
221 | }
222 | .navbar-default {
223 |   background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
224 |   background-image:      -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
225 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
226 |   background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
227 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
228 |   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
229 |   background-repeat: repeat-x;
230 |   border-radius: 4px;
231 |   -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
232 |           box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
233 | }
234 | .navbar-default .navbar-nav > .open > a,
235 | .navbar-default .navbar-nav > .active > a {
236 |   background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
237 |   background-image:      -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
238 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
239 |   background-image:         linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
240 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
241 |   background-repeat: repeat-x;
242 |   -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
243 |           box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
244 | }
245 | .navbar-brand,
246 | .navbar-nav > li > a {
247 |   text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
248 | }
249 | .navbar-inverse {
250 |   background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
251 |   background-image:      -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
252 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
253 |   background-image:         linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
254 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
255 |   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
256 |   background-repeat: repeat-x;
257 | }
258 | .navbar-inverse .navbar-nav > .open > a,
259 | .navbar-inverse .navbar-nav > .active > a {
260 |   background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
261 |   background-image:      -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
262 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
263 |   background-image:         linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
264 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
265 |   background-repeat: repeat-x;
266 |   -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
267 |           box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
268 | }
269 | .navbar-inverse .navbar-brand,
270 | .navbar-inverse .navbar-nav > li > a {
271 |   text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
272 | }
273 | .navbar-static-top,
274 | .navbar-fixed-top,
275 | .navbar-fixed-bottom {
276 |   border-radius: 0;
277 | }
278 | .alert {
279 |   text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
280 |   -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
281 |           box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
282 | }
283 | .alert-success {
284 |   background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
285 |   background-image:      -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
286 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
287 |   background-image:         linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
288 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
289 |   background-repeat: repeat-x;
290 |   border-color: #b2dba1;
291 | }
292 | .alert-info {
293 |   background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
294 |   background-image:      -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
295 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
296 |   background-image:         linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
297 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
298 |   background-repeat: repeat-x;
299 |   border-color: #9acfea;
300 | }
301 | .alert-warning {
302 |   background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
303 |   background-image:      -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
304 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
305 |   background-image:         linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
306 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
307 |   background-repeat: repeat-x;
308 |   border-color: #f5e79e;
309 | }
310 | .alert-danger {
311 |   background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
312 |   background-image:      -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
313 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
314 |   background-image:         linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
315 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
316 |   background-repeat: repeat-x;
317 |   border-color: #dca7a7;
318 | }
319 | .progress {
320 |   background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
321 |   background-image:      -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
322 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
323 |   background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
324 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
325 |   background-repeat: repeat-x;
326 | }
327 | .progress-bar {
328 |   background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
329 |   background-image:      -o-linear-gradient(top, #428bca 0%, #3071a9 100%);
330 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9));
331 |   background-image:         linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
332 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
333 |   background-repeat: repeat-x;
334 | }
335 | .progress-bar-success {
336 |   background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
337 |   background-image:      -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
338 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
339 |   background-image:         linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
340 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
341 |   background-repeat: repeat-x;
342 | }
343 | .progress-bar-info {
344 |   background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
345 |   background-image:      -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
346 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
347 |   background-image:         linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
348 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
349 |   background-repeat: repeat-x;
350 | }
351 | .progress-bar-warning {
352 |   background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
353 |   background-image:      -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
354 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
355 |   background-image:         linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
356 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
357 |   background-repeat: repeat-x;
358 | }
359 | .progress-bar-danger {
360 |   background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
361 |   background-image:      -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
362 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
363 |   background-image:         linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
364 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
365 |   background-repeat: repeat-x;
366 | }
367 | .progress-bar-striped {
368 |   background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
369 |   background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
370 |   background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
371 | }
372 | .list-group {
373 |   border-radius: 4px;
374 |   -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
375 |           box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
376 | }
377 | .list-group-item.active,
378 | .list-group-item.active:hover,
379 | .list-group-item.active:focus {
380 |   text-shadow: 0 -1px 0 #3071a9;
381 |   background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
382 |   background-image:      -o-linear-gradient(top, #428bca 0%, #3278b3 100%);
383 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3));
384 |   background-image:         linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
385 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
386 |   background-repeat: repeat-x;
387 |   border-color: #3278b3;
388 | }
389 | .list-group-item.active .badge,
390 | .list-group-item.active:hover .badge,
391 | .list-group-item.active:focus .badge {
392 |   text-shadow: none;
393 | }
394 | .panel {
395 |   -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
396 |           box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
397 | }
398 | .panel-default > .panel-heading {
399 |   background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
400 |   background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
401 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
402 |   background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
403 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
404 |   background-repeat: repeat-x;
405 | }
406 | .panel-primary > .panel-heading {
407 |   background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
408 |   background-image:      -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
409 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
410 |   background-image:         linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
411 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
412 |   background-repeat: repeat-x;
413 | }
414 | .panel-success > .panel-heading {
415 |   background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
416 |   background-image:      -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
417 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
418 |   background-image:         linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
419 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
420 |   background-repeat: repeat-x;
421 | }
422 | .panel-info > .panel-heading {
423 |   background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
424 |   background-image:      -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
425 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
426 |   background-image:         linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
427 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
428 |   background-repeat: repeat-x;
429 | }
430 | .panel-warning > .panel-heading {
431 |   background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
432 |   background-image:      -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
433 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
434 |   background-image:         linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
435 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
436 |   background-repeat: repeat-x;
437 | }
438 | .panel-danger > .panel-heading {
439 |   background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
440 |   background-image:      -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
441 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
442 |   background-image:         linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
443 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
444 |   background-repeat: repeat-x;
445 | }
446 | .well {
447 |   background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
448 |   background-image:      -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
449 |   background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
450 |   background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
451 |   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
452 |   background-repeat: repeat-x;
453 |   border-color: #dcdcdc;
454 |   -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
455 |           box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
456 | }
457 | /*# sourceMappingURL=bootstrap-theme.css.map */
458 | 
--------------------------------------------------------------------------------
/public/bootstrap/css/bootstrap-theme.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 |  * Bootstrap v3.3.0 (http://getbootstrap.com)
3 |  * Copyright 2011-2014 Twitter, Inc.
4 |  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 |  */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-default .badge,.btn-primary .badge,.btn-success .badge,.btn-info .badge,.btn-warning .badge,.btn-danger .badge{text-shadow:none}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-primary:disabled,.btn-primary[disabled]{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.list-group-item.active .badge,.list-group-item.active:hover .badge,.list-group-item.active:focus .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}
--------------------------------------------------------------------------------
/public/bootstrap/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvaubourg/php-piratebox/d9cc1a57b9b99a0e4d63d0e518193f70876b221d/public/bootstrap/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/public/bootstrap/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvaubourg/php-piratebox/d9cc1a57b9b99a0e4d63d0e518193f70876b221d/public/bootstrap/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/public/bootstrap/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvaubourg/php-piratebox/d9cc1a57b9b99a0e4d63d0e518193f70876b221d/public/bootstrap/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/public/bootstrap/js/npm.js:
--------------------------------------------------------------------------------
 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
 2 | require('../../js/transition.js')
 3 | require('../../js/alert.js')
 4 | require('../../js/button.js')
 5 | require('../../js/carousel.js')
 6 | require('../../js/collapse.js')
 7 | require('../../js/dropdown.js')
 8 | require('../../js/modal.js')
 9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/public/chat/.gitfile:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvaubourg/php-piratebox/d9cc1a57b9b99a0e4d63d0e518193f70876b221d/public/chat/.gitfile
--------------------------------------------------------------------------------
/public/css/contextMenu.css:
--------------------------------------------------------------------------------
  1 | /*!
  2 |  * jQuery contextMenu - Plugin for simple contextMenu handling
  3 |  *
  4 |  * Version: 1.6.6
  5 |  *
  6 |  * Authors: Rodney Rehm, Addy Osmani (patches for FF)
  7 |  * Web: http://medialize.github.com/jQuery-contextMenu/
  8 |  *
  9 |  * Licensed under
 10 |  *   MIT License http://www.opensource.org/licenses/mit-license
 11 |  *   GPL v3 http://opensource.org/licenses/GPL-3.0
 12 |  *
 13 |  */
 14 | 
 15 | .context-menu-list {
 16 |     margin:0; 
 17 |     padding:0; 
 18 |     
 19 |     min-width: 120px;
 20 |     max-width: 250px;
 21 |     display: inline-block;
 22 |     position: absolute;
 23 |     list-style-type: none;
 24 |     
 25 |     border: 1px solid #000;
 26 |     background: #111;
 27 |     
 28 |     -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
 29 |        -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
 30 |         -ms-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
 31 |          -o-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
 32 |             box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
 33 |     
 34 |     font-size: 1em;
 35 |     text-shadow: .1em .1em #000;
 36 |     border-radius: 2px;
 37 |     opacity: .98;
 38 |     display: none;
 39 | }
 40 | 
 41 | .context-menu-item {
 42 |     padding: 3px 3px 7px 7px;
 43 |     background-color: #111;
 44 |     position: relative;
 45 |     -webkit-user-select: none;
 46 |        -moz-user-select: -moz-none;
 47 |         -ms-user-select: none;
 48 |             user-select: none;
 49 | }
 50 | 
 51 | .context-menu-separator {
 52 |     padding-bottom:0;
 53 |     border-bottom: 1px solid #000;
 54 | }
 55 | 
 56 | .context-menu-item > label > input,
 57 | .context-menu-item > label > textarea {
 58 |     -webkit-user-select: text;
 59 |        -moz-user-select: text;
 60 |         -ms-user-select: text;
 61 |             user-select: text;
 62 | }
 63 | 
 64 | .context-menu-item.hover {
 65 |     cursor: pointer;
 66 |     background-color: #222;
 67 | }
 68 | 
 69 | .context-menu-item.disabled {
 70 |     color: #666;
 71 | }
 72 | 
 73 | .context-menu-input.hover,
 74 | .context-menu-item.disabled.hover {
 75 |     cursor: default;
 76 |     background-color: #EEE;
 77 | }
 78 | 
 79 | .context-menu-submenu:after {
 80 |     content: ">";
 81 |     color: #666;
 82 |     position: absolute;
 83 |     top: 0;
 84 |     right: 3px;
 85 |     z-index: 1;
 86 | }
 87 | 
 88 | /* icons
 89 |     #protip:
 90 |     In case you want to use sprites for icons (which I would suggest you do) have a look at
 91 |     http://css-tricks.com/13224-pseudo-spriting/ to get an idea of how to implement 
 92 |     .context-menu-item.icon:before {}
 93 |  */
 94 | .context-menu-item.icon { min-height: 18px; background-repeat: no-repeat; background-position: 4px 2px; }
 95 | .context-menu-item.icon-edit { background-image: url(../img/page_white_edit.png); }
 96 | .context-menu-item.icon-cut { background-image: url(../img/cut.png); }
 97 | .context-menu-item.icon-copy { background-image: url(../img/page_white_copy.png); }
 98 | .context-menu-item.icon-paste { background-image: url(../img/page_white_paste.png); }
 99 | .context-menu-item.icon-delete { background-image: url(../img/page_white_delete.png); }
100 | .context-menu-item.icon-add { background-image: url(../img/page_white_add.png); }
101 | .context-menu-item.icon-quit { background-image: url(../img/door.png); }
102 | 
103 | /* vertically align inside labels */
104 | .context-menu-input > label > * { vertical-align: top; }
105 | 
106 | /* position checkboxes and radios as icons */
107 | .context-menu-input > label > input[type="checkbox"],
108 | .context-menu-input > label > input[type="radio"] {
109 |     margin-left: -17px;
110 | }
111 | .context-menu-input > label > span {
112 |     margin-left: 5px;
113 | }
114 | 
115 | .context-menu-input > label,
116 | .context-menu-input > label > input[type="text"],
117 | .context-menu-input > label > textarea,
118 | .context-menu-input > label > select {
119 |     display: block;
120 |     width: 100%;
121 |     
122 |     -webkit-box-sizing: border-box;
123 |        -moz-box-sizing: border-box;
124 |         -ms-box-sizing: border-box;
125 |          -o-box-sizing: border-box;
126 |             box-sizing: border-box;
127 | }
128 | 
129 | .context-menu-input > label > textarea {
130 |     height: 100px;
131 | }
132 | .context-menu-item > .context-menu-list {
133 |     display: none;
134 |     /* re-positioned by js */
135 |     right: -5px;
136 |     top: 5px;
137 | }
138 | 
139 | .context-menu-item.hover > .context-menu-list {
140 |     display: block;
141 | }
142 | 
143 | .context-menu-accesskey {
144 |     text-decoration: underline;
145 | }
146 | 
--------------------------------------------------------------------------------
/public/css/filedrop.css:
--------------------------------------------------------------------------------
 1 | /***
 2 |   Styles below are only required if you're using '+'",i.firstChild.setAttribute("id",t),i.firstChild.style.display="none",i.lastChild.setAttribute("target",t);var s=e.firstChild;while(s&&(!n.isTag(s)||n.isTag(s,"legend")))s=s.nextSibling;return s?e.insertBefore(i,s):e.appendChild(i),i.lastChild.lastChild},r.abortIFrame=function(){if(r.opt.input.form){var e=n.byID(r.opt.input.form.getAttribute("target"));e&&e.setAttribute("src","javascript:false")}},r.sendViaIFrame=function(e){e=e||r.opt.iframe.url;var t=(r.opt.input||{}).form;if(e&&t){do var i=n.randomID();while(i in window);window[i]=function(t){typeof t!="object"&&(t={response:t,responseXML:"",responseText:(t||"").toString(),readyState:4,status:200,statusText:"OK",getAllResponseHeaders:function(){return""},getResponseHeader:function(){return""},setRequestHeader:function(){return this},statusCode:function(){return this},abort:function(){return this}}),n.extend(t,{iframe:!0,url:e}),n.callAllOfObject(r,"iframeDone",t)};var s=t.firstChild;while(s&&(!n.isTag(s,"input")||s.name!=r.opt.iframe.callbackParam))s=s.nextSibling;return s?s.value=i:e=e.replace(/[?&]+$/,"")+(e.indexOf("?")==-1?"?":"&")+r.opt.iframe.callbackParam+"="+i,t.setAttribute("action",e),n.callAllOfObject(r,"iframeSetup",t),t.submit(),setTimeout(r.resetForm,300),!0}},r.resetForm=function(){var e=r.opt.input&&r.opt.input.file;if(e){e.value="";if(r.opt.recreateInput){var t=r.opt.input.file=e.cloneNode(!0);e.parentNode.replaceChild(t,e),n.callAllOfObject(r,"inputSetup",[r.opt.input,e])}}},r.multiple=function(e){return r.opt.input&&typeof e!="undefined"&&(e?r.opt.input.file.setAttribute("multiple","multiple"):r.opt.input.file.removeAttribute("multiple")),r.opt.input&&!!r.opt.input.file.getAttribute("multiple")},r.event=function(e,t){return n.appendEventsToObject.apply(r,arguments)},r.preview=function(e,t){return n.previewToObject.apply(r,arguments)},r.onInputSetup=function(t,i){i?(t.file.clearAttributes&&t.file.clearAttributes(),t.file.mergeAttributes&&t.file.mergeAttributes(i)):r.multiple(r.opt.multiple),n.setClass(t.file,r.opt.inputClass),r.delegate(t.file,"change","upload");var s=t.file.parentNode;s&&s.style.display.match(/^(static)?$/)&&(s.style.position="relative");if(n.isTag(e,"fieldset")){var o=document.createElement("div");o.style.position="relative",o.style.overflow="hidden",e.parentNode.insertBefore(o,e),o.appendChild(e)}},r.onDragOver=function(e){n.stopEvent(e),e.dataTransfer&&(e.dataTransfer.dropEffect=r.opt.dropEffect)},r.onUpload=function(){for(var e=0;e0&&n.callAllOfObject(r,"send",[t]):!r.handle.sendViaIFrame()&&n.hasConsole&&console.warn("FileDrop fallback upload triggered but iframe options were not configured - doing nothing.")},r.eventFiles=function(e,t){var i=new n.FileList(e);if(e.dataTransfer&&(e.dataTransfer.length||e.dataTransfer.files))var s=e.dataTransfer;else var s=e.target&&e.target.files||e.srcElement&&e.srcElement.files;if(s){var o=s.items||[];s.files&&(s=s.files);var u={};for(var a=0;a0||f.nativeEntry)&&i.push(f)}}else t&&(i=!1);return i},n.extend(r,r.handle),r.event({upload:r.onUpload,send:r.resetForm,dragEnter:i(!0),dragLeave:i(!1),uploadElsewhere:i(!1)}),r.preview({upload:i(!1)})},n.FileList=function(e){var t=this;t.dropEffect=e&&e.dropEffect||"",t.length=0,e=null,t.push=function(e){return t[t.length++]=e,t},t.pop=function(){if(t.length>0){var e=t.last();return delete t[--t.length],e}},t.first=function(){return t[0]},t.last=function(){return t[t.length-1]},t.remove=function(e){for(;et[1]?1:e[1]0||t.end!=null&&t.end)t.blob.slice?(t.end==null&&(t.end=t.blob.size||t.blob.fileSize),t.blob=t.blob.slice(t.start,t.end,t.mime)):n.hasConsole&&console.warn("File Blob/slice() are unsupported - operating on entire File.");var s=new FileReader;s.onerror=function(e){i("read",e)},s.onload=function(e){e.target&&e.target.result?(t.func=="readAsBinaryString"&&(e.target.result=String.fromCharCode.apply(null,new Uint8Array(e.target.result))),t.onDone(e.target.result)):s.onerror(e)};var o=t.func;if(n.isArray(o)){var u=o[0];return o[0]=t.blob,s[u].apply(s,o)}if(!o||o=="bin")o="readAsBinaryString";else if(o=="url"||o=="uri"||o=="src")o="readAsDataURL";else if(o=="array")o="readAsArrayBuffer";else if(o=="text")o="readAsText";else if(o.substr(0,4)!="read")return s.readAsText(t.blob,o);return o=="readAsBinaryString"&&(o="readAsArrayBuffer"),s[o](t.blob)},r.listEntries=function(e,t){if(r.nativeEntry&&r.nativeEntry.isDirectory){t=t||new Function;var i=r.nativeEntry.createReader(),s=new n.FileList,o=0;function u(t){o-=t,o==0&&e&&(e(s),e=null)}return i.readEntries(function(e){for(var r=0;r
 4 |  * Contribute at https://github.com/jvaubourg/php-piratebox
 5 |  * 
 6 |  * This program is free software: you can redistribute it and/or modify
 7 |  * it under the terms of the GNU Affero General Public License as published by
 8 |  * the Free Software Foundation, either version 3 of the License, or
 9 |  * (at your option) any later version.
10 |  * 
11 |  * This program is distributed in the hope that it will be useful,
12 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 |  * GNU Affero General Public License for more details.
15 |  * 
16 |  * You should have received a copy of the GNU Affero General Public License
17 |  * along with this program.  If not, see  .
18 |  */
19 | ?>
20 | 
21 | 
22 |   data-locked="= $locked ? 'true' : 'false' ?>"
23 |   data-name="= htmlentities($file['name']) ?>"
24 |   data-filename="= htmlentities(preg_replace('|/+|', '/', $file['filename'])) ?>"
25 |   data-size="= $file['size'] ?>"
26 |   data-date="= str_replace(' ', ' ', $file['date']) ?>">
27 | 
28 |   
29 | 
30 |   
31 |     
32 |   
33 | 
34 |   
35 |     
= str_replace('...', '…', htmlentities($file['shortname'])) ?> 
36 |   
37 |     
= str_replace('...', '…', htmlentities($file['shortname'])) ?> 
38 |   
39 | 
 
40 | 
--------------------------------------------------------------------------------
/views/_folder.html.php:
--------------------------------------------------------------------------------
 1 | 
 4 |  * Contribute at https://github.com/jvaubourg/php-piratebox
 5 |  * 
 6 |  * This program is free software: you can redistribute it and/or modify
 7 |  * it under the terms of the GNU Affero General Public License as published by
 8 |  * the Free Software Foundation, either version 3 of the License, or
 9 |  * (at your option) any later version.
10 |  * 
11 |  * This program is distributed in the hope that it will be useful,
12 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 |  * GNU Affero General Public License for more details.
15 |  * 
16 |  * You should have received a copy of the GNU Affero General Public License
17 |  * along with this program.  If not, see  .
18 |  */
19 | ?>
20 | 
21 | 
22 |   data-locked="= $locked ? 'true' : 'false' ?>"
23 |   data-dir="= rawurlencode($folder['dir'])  ?>">
24 | 
25 |   
26 | 
27 |   
28 |     
29 |   
30 | 
31 |   
= htmlentities($folder['name']) ?> 
32 | 
 
33 | 
--------------------------------------------------------------------------------
/views/home.html.php:
--------------------------------------------------------------------------------
  1 | 
  4 |  * Contribute at https://github.com/jvaubourg/php-piratebox
  5 |  * 
  6 |  * This program is free software: you can redistribute it and/or modify
  7 |  * it under the terms of the GNU Affero General Public License as published by
  8 |  * the Free Software Foundation, either version 3 of the License, or
  9 |  * (at your option) any later version.
 10 |  * 
 11 |  * This program is distributed in the hope that it will be useful,
 12 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 |  * GNU Affero General Public License for more details.
 15 |  * 
 16 |  * You should have received a copy of the GNU Affero General Public License
 17 |  * along with this program.  If not, see  .
 18 |  */
 19 | ?>
 20 | 
 21 | 
 22 |   
 23 |     
 31 | 
 32 |     
 44 |   
 45 |  
 46 | 
 47 | " 
 49 |   data-txt-delfolder="= _("Are you sure you want to delete this folder?") ?>"
 50 |   data-txt-open="= _("Open") ?>"
 51 |   data-txt-download="= _("Download") ?>"
 52 |   data-txt-rename="= _("Rename") ?>"
 53 |   data-txt-delete="= _("Delete") ?>"
 54 |   data-opt-allow-renaming="= option('allow_renaming') ? 'true' : 'false' ?>"
 55 |   data-opt-allow-deleting="= option('allow_deleting') ? 'true' : 'false' ?>"
 56 |   data-opt-allow-newfolders="= option('allow_newfolders') ? 'true' : 'false' ?>">
 57 | 
 58 |   
 59 |     
 60 |     
 61 |     
= _("Download") ?> 
 62 |     
 63 |     
 64 |     
" = option('allow_renaming') ? '' : 'style="display: none"' ?>> 
 65 |     
" = option('allow_deleting') ? '' : 'style="display: none"' ?>> 
 66 |   
 67 | 
 68 |   
 
 69 |     
 70 |       
= _("Download the others' files") ?> 
 71 |     
 72 |   
 73 |     
 74 |       
 75 |         = _("Root") ?> 
 76 |        
 77 | 
 78 |       
 79 |         = $files ?>
 80 |       
 81 | 
 82 |       
>
 83 |         = _("No files yet.") ?>
 84 |         >  = _("Delete this folder") ?> 
 85 |        
 86 |     
 87 |   
 88 | 
 89 |   
 
 90 |     
 91 |       
= _("Share your own files") ?> 
 92 |     
 93 | 
 94 |     
 95 |       
 96 |         = _("Drag & drop here") ?> 
 97 |         -= _("or") ?>- 
 98 |         = _('Click to open the file browser') ?> 
 99 |       
100 | 
101 |       
102 | 
103 |       
115 |     
116 |   
117 | 
 
118 | 
119 | 
120 |   data-opt-enable-chat="= option('enable_chat') ? 'true' : 'false' ?>"
121 |   data-opt-default-pseudo="= option('default_pseudo') ?>">
122 | 
123 |   
= _("No messages. You are the first!") ?>
124 |   
125 |       
126 |         ">
127 |         
128 |           = _("Send") ?> 
129 |          
130 |       
131 |   
132 | 
 
133 | 
--------------------------------------------------------------------------------
/views/layout.html.php:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
21 | 
22 | 
23 | 
24 | 
25 |   
26 | 
27 |   = option('app_name') ?> 
28 | 
29 |    
30 |    
31 |    
32 | 
33 |    
34 |    
35 |    
36 |    
37 |    
38 | 
39 |   
40 |   
41 |   
42 |   
43 |   
44 |   
45 | 
46 | 
47 | 
48 |   
49 |     = $content?>
50 | 
51 |     
55 |   
56 | 
57 | 
58 | 
59 | 
--------------------------------------------------------------------------------