├── .gitignore
├── .gitmodules
├── .htaccess
├── README.md
├── app
├── .htaccess
├── config.ini
├── controller
│ ├── Api.php
│ ├── Error.php
│ ├── HasLayout.php
│ ├── Home.php
│ ├── Link.php
│ └── Statistics.php
├── font
│ └── DroidSans.ttf
├── model
│ └── EzLink.php
└── view
│ ├── error
│ ├── 404.php
│ ├── 500.php
│ └── fatal.php
│ ├── layout
│ └── main.php
│ └── pages
│ ├── api.php
│ ├── home.php
│ ├── statistics.php
│ └── submit.php
├── example.sql
├── images
├── logo.png
├── tumblbeast-404.png
└── tumblbeast-500.png
├── index.php
└── styles
└── style.css
/.gitignore:
--------------------------------------------------------------------------------
1 | app/cache/*.cache
2 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "system"]
2 | path = system
3 | url = git@github.com:tlhunter/sleekmvc.git
4 |
--------------------------------------------------------------------------------
/.htaccess:
--------------------------------------------------------------------------------
1 | #Uncomment for mediatemple
2 | #AddHandler php5latest-script .php
3 |
4 | # while bad for normal use, it makes view files prettier, e.g. =$title?>
5 |
6 |
7 | php_flag short_open_tags on
8 |
9 |
10 |
11 | # Prevent browser from downloading hidden (.something) files
12 |
13 | Order Deny,Allow
14 | Deny From All
15 |
16 |
17 | # Prevent directory listings
18 | Options -Indexes
19 |
20 | # This line sends requests for documents Apache can't find to an fake controller (causing a 404 in SleekMVC)
21 | # If your app isn't installed in the root directory of the server, you'll need to update the following line
22 | ErrorDocument 404 /index.php
23 | # ErrorDocument 404 /path/to/site/index.php
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | SleekMVC: A Simple PHP MVC Framework
2 | ===
3 | SleekMVC is first and foremost a simple framework, meant to be easily consumed by the most novice of
4 | PHP developers. It was specifically built to be used by first year PHP students while being flexible
5 | enough to work for large scale applications. You won't find any useless classes shipped with Sleek.
6 |
7 | [SleekMVC Documentation](https://github.com/tlhunter/sleekmvc-app/wiki)
8 |
9 | SleekMVC requires namespaces and therefore requires PHP 5.3+. Sleek has a similar syntax to the two
10 | well known PHP frameworks Kohana and CodeIgniter. The views are very similar, it uses convenient
11 | autoloading like with Kohana, and doesn't require the hacky class loading of CodeIgniter left over
12 | from it's PHP 4 compatible days.
13 |
14 | SleekMVC is currently in beta stages and is highly recommended not to be used for productions sites.
15 | When it is ready for public consumption, there will be documentation explaining every facet of the
16 | framework, and detailing all of the provided classes.
17 |
18 | Goals for SleekMVC:
19 | ==
20 | * So easy to use, first year PHP developers can become proficient
21 | * Secure variables and prevent XSS and injection attacks
22 | * Core framework remain small and lightweight
23 | * Don't prevent access to $_GET (or any super global) variables (e.g. CodeIgniter)
24 | * Don't require a ton of 'empty' class files (e.g. Kohana)
25 | * Provide a easily understood autoloader which handles namespaces
26 | * Work with IDE autocomplete features out of the box
27 | * Use raw PHP files for views (but allow template engine usage if desired)
28 | * View files won't need to execute classes to access data
29 | * Provide extensive, clear documentation, for every single developer exposed feature
30 | * Provide request and response objects for handling related superglobals
31 |
--------------------------------------------------------------------------------
/app/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | Deny from all
3 |
4 |
--------------------------------------------------------------------------------
/app/config.ini:
--------------------------------------------------------------------------------
1 | ; List your different server names here, as server[domain name]
2 | server[localhost] = 'development_server'
3 | server[sleekmvc.local] = 'test_server'
4 | server[nucleoci.de] = 'production_server'
5 | server[www.example.com] = 'production_server'
6 |
7 |
8 |
9 | ; Settings from here are available to every server
10 | [global]
11 | error_controller = 'Error'
12 | use_sessions = true
13 |
14 |
15 |
16 | ; Configure your development server here (e.g. your laptop)
17 | [development_server]
18 | environment = 'DEVELOPMENT'
19 |
20 | ; The location of your app. If in the root, set to ''. If in a subfolder, use /path/to/site
21 | base_url = '/sleekmvc-app'
22 | ; cache_method = false | 'apc' | 'memcache' | 'file'
23 | cache_method = 'file'
24 | ; If using the memcache caching method, define the server:ports here
25 | cache_memcache_servers[] = 'localhost:11211'
26 | ; This is the default value for how long to maintain the cache (0 = infinite)
27 | cache_expiretime = 0
28 | ; If using the file caching method, this is the directory (with trailing slash)
29 | cache_file_directory = 'app/cache/'
30 |
31 | database[host] = 'localhost'
32 | database[user] = 'annarbor'
33 | database[pass] = 'ufvNyp78N8LQdwHR'
34 | database[name] = 'sleekmvc'
35 |
36 |
37 |
38 | ; Configure your test server here (if applicable)
39 | [test_server]
40 | environment = 'TEST'
41 |
42 | base_url = ''
43 | cache_method = 'file'
44 | cache_memcache_servers[] = 'localhost:11211'
45 | cache_expiretime = 0
46 | cache_file_directory = 'app/cache/'
47 |
48 | database[host] = 'localhost'
49 | database[user] = 'annarbor'
50 | database[pass] = 'ufvNyp78N8LQdwHR'
51 | database[name] = 'sleekmvc'
52 |
53 |
54 |
55 | ; Configure your production server here (e.g. the live website)
56 | [production_server]
57 | environment = 'PRODUCTION'
58 |
59 | base_url = ''
60 | cache_method = 'file'
61 | cache_expiretime = 0
62 | cache_file_directory = 'app/cache/'
63 |
64 | database[host] = false
65 | database[user] = false
66 | database[pass] = false
67 | database[name] = false
68 |
69 |
--------------------------------------------------------------------------------
/app/controller/Api.php:
--------------------------------------------------------------------------------
1 | page_data['content'] = \Sleek\View::render('pages/api', $this->page_data, TRUE);
23 | }
24 |
25 | /**
26 | * Program visits /api/create?url=http://www.example.com
27 | * @return void
28 | */
29 | public function action_create() {
30 | // Disables the layout stuff
31 | $this->auto_render_layout = FALSE;
32 |
33 | // Get the ?url= parameter
34 | $url = $this->request->get('url');
35 |
36 | if (!$url) {
37 | echo "ERROR: Empty URL";
38 | } else if (!filter_var($url, FILTER_VALIDATE_URL)) {
39 | echo "ERROR: Invalid URL";
40 | } else {
41 | $EzLink = new Model_EzLink();
42 | $id = $EzLink->insertUrl($url);
43 | // Controllers shouldn't really output directly, but it seems like a waste of a view file otherwise
44 | echo 'http://' . $this->request->server('HTTP_HOST') . '/link/' . Model_EzLink::integerToCode($id);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/controller/Error.php:
--------------------------------------------------------------------------------
1 | response->status(404);
17 | $this->response->view('error/404');
18 | }
19 |
20 | /**
21 | * Use this for a custom 500 error page. Note that depending on how severe you blow up the
22 | * application, it may not always work.
23 | * @param bool $number
24 | * @param string $text
25 | * @param string $filename
26 | * @param int $linenumber
27 | * @param string $context
28 | * @return void
29 | */
30 | public function action_500($number = FALSE, $text = '', $filename = '', $linenumber = 0, $context = '') {
31 | $this->response->status(500);
32 | $data = array(
33 | 'number' => $number,
34 | 'text' => $text,
35 | 'filename' => $filename,
36 | 'linenumber' => $linenumber,
37 | 'context' => $context,
38 | );
39 | $this->response->view('error/500', $data);
40 | }
41 |
42 | /**
43 | * Use this for throwing PHP fatal errors.
44 | * @param string $error
45 | * @return void
46 | */
47 | public function action_fatal($error) {
48 | $this->response->status(500);
49 | $data['error'] = $error;
50 | $this->response->view('error/fatal', $data);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/controller/HasLayout.php:
--------------------------------------------------------------------------------
1 | page_data['title'] = 'EzLink';
36 | $this->page_data['server'] = $this->request->server('HTTP_HOST');
37 | $this->page_data['base_url'] = \Sleek\Config::get('base_url');
38 | }
39 |
40 | /**
41 | * Runs after the action. Executes the layout/main view file.
42 | * @return void
43 | */
44 | public function postAction() {
45 | if ($this->auto_render_layout) {
46 | $EzLink = new Model_EzLink();
47 | $this->page_data['count_urls'] = $EzLink->countUrls();
48 | $this->page_data['count_clicks'] = $EzLink->countClicks();
49 | $this->response->view('layout/main', $this->page_data);
50 | }
51 | }
52 |
53 |
54 | }
--------------------------------------------------------------------------------
/app/controller/Home.php:
--------------------------------------------------------------------------------
1 | page_data['content'] = \Sleek\View::render('pages/home', $this->page_data, TRUE);
16 | }
17 |
18 | /**
19 | * This is the page the user hits when submitting a URL via their browser.
20 | * @return void
21 | */
22 | public function action_submit() {
23 | $url = $this->request->post('url');
24 | $this->page_data['code'] = FALSE;
25 |
26 | if ($url && filter_var($url, FILTER_VALIDATE_URL)) {
27 | $EzLink = new Model_EzLink();
28 | $id = $EzLink->insertUrl($url);
29 | $this->page_data['code'] = Model_EzLink::integerToCode($id);
30 | }
31 |
32 | $this->page_data['content'] = \Sleek\View::render('pages/submit', $this->page_data, TRUE);
33 | }
34 |
35 | public function action_test($arguments) {
36 | echo "
";
37 | echo "Arguments:\n";
38 | var_dump($arguments);
39 | echo "\n\nTest Param:\n";
40 | $gets = $this->request->get('testParam');
41 | var_dump($gets);
42 | echo "\n\nGlobal GET:\n";
43 | var_dump($_GET);
44 | echo "\n\nSERVER:\n";
45 | var_dump($_SERVER);
46 | echo " ";
47 | exit();
48 | }
49 |
50 | public function action_view_user($arguments) {
51 | die($arguments['user_id']);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/app/controller/Link.php:
--------------------------------------------------------------------------------
1 | request->urlAction());
12 | $hidden = $this->request->get('h') !== NULL;
13 |
14 | $EzLink = new Model_EzLink();
15 | $url = $EzLink->getUrlById($id);
16 | $EzLink->clickUrl($id, date("Y"), date("n"));
17 |
18 | if ($hidden) {
19 | echo " ";
20 | } else {
21 | $this->response->redirect($url);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/controller/Statistics.php:
--------------------------------------------------------------------------------
1 | page_data['content'] = \Sleek\View::render('pages/statistics', $this->page_data, TRUE);
11 | }
12 |
13 | /**
14 | * This is an interesting method. It returns an image, not HTML!
15 | * @return void
16 | */
17 | public function action_image() {
18 | $this->auto_render_layout = FALSE;
19 | $EzLink = new Model_EzLink();
20 | $image = $EzLink->getStatisticsImage();
21 |
22 | $this->response->header('Content-type', 'image/png');
23 | imagepng($image);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/font/DroidSans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tlhunter/sleekmvc-app/76128491248922140e1e75c25276fa9159eb11bf/app/font/DroidSans.ttf
--------------------------------------------------------------------------------
/app/model/EzLink.php:
--------------------------------------------------------------------------------
1 | db->query("SELECT SUM(count) AS count FROM {$this->click_table}");
33 | if (count($result)) {
34 | $data = $result->row();
35 | return $data['count'];
36 | }
37 | return 0;
38 | }
39 |
40 | /**
41 | * Counts the number of urls in the database
42 | * @return int
43 | */
44 | public function countUrls() {
45 | $result = $this->db->query("SELECT COUNT(*) AS count FROM {$this->url_table}");
46 | if (count($result)) {
47 | $data = $result->row();
48 | return $data['count'];
49 | }
50 | return 0;
51 | }
52 |
53 | /**
54 | * Inserts the provided URL into the database and returns the result
55 | * @param string $url
56 | * @return bool|int
57 | */
58 | public function insertUrl($url) {
59 | if ($this->db->insert($this->url_table, array('url' => $url))) {
60 | return $this->db->lastId();
61 | } else {
62 | return FALSE;
63 | }
64 | }
65 |
66 | /**
67 | * Gets a URL from the database with the provided numerical ID
68 | * @param int $id
69 | * @return string|bool
70 | */
71 | public function getUrlById($id) {
72 | $result = $this->db->select($this->url_table, array('url'), array('id' => $id), 1);
73 | if (count($result)) {
74 | $row = $result->row();
75 | return $row['url'];
76 | }
77 | return FALSE;
78 | }
79 |
80 | /**
81 | * Increments a URLs click count by one. It will run an UPDATE or an INSERT to do this.
82 | * @param int $id
83 | * @param string $year
84 | * @param string $month
85 | * @return int|bool
86 | */
87 | public function clickUrl($id, $year, $month) {
88 | $sql = "SELECT * FROM clicks WHERE url_id = $id AND year = '$year' AND month = '$month' LIMIT 1";
89 | $result = $this->db->query($sql);
90 | if (count($result)) {
91 | $sql = "UPDATE clicks SET count = count + 1 WHERE url_id = $id AND year = '$year' AND month = '$month' LIMIT 1";
92 | return $this->db->querySimple($sql);
93 | } else {
94 | $sql = "INSERT INTO clicks SET count = 1, url_id = $id, year = '$year', month = '$month'";
95 | return $this->db->querySimple($sql);
96 | }
97 | }
98 |
99 | /**
100 | * Executes SQL and returns an image resource (PNG)
101 | * @return \resource
102 | */
103 | public function getStatisticsImage() {
104 | $result = $this->db->query("SELECT COUNT(*) AS count, MONTH(added) AS month, YEAR(added) AS year FROM url GROUP BY CONCAT(MONTH(added), YEAR(added)) ORDER BY year DESC, month DESC");
105 | $data = array();
106 | $maxv = 0;
107 | foreach($result AS $row) {
108 | $count = (int) $row['count'];
109 | if ($count > $maxv) {
110 | $maxv = $count;
111 | }
112 | $data[ $row['year'] . '-' . $row['month'] ] = $count;
113 | }
114 |
115 | $columns = 13;
116 | $width = 550;
117 | $height = 200;
118 | $padding = 5;
119 |
120 | $column_width = $width / $columns;
121 |
122 | $year = date('Y') - 1;
123 | $month = date('n');
124 |
125 | $image = imagecreate($width, $height + 20);
126 | $gray = imagecolorallocate($image, 0xcc, 0xcc, 0xcc);
127 | $gray_lite = imagecolorallocate($image, 0xee, 0xee, 0xee);
128 | $gray_dark = imagecolorallocate($image, 0x7f, 0x7f, 0x7f);
129 | $white = imagecolorallocate($image, 0xff, 0xff, 0xff);
130 |
131 | imagefilledrectangle($image, 0, 0, $width, $height + 20, $white);
132 |
133 | for ($i = 0; $i < 12; $i++) {
134 | $month++;
135 | if ($month > 12) {
136 | $month = 1;
137 | $year++;
138 | }
139 | $val = isset($data[$year . '-' . $month]) ? $data[$year . '-' . $month] : 0;
140 | $column_height = ($height / 100) * (( $val / $maxv) * 100) * 2;
141 |
142 | $x1 = $i * $column_width;
143 | $y1 = $height - $column_height;
144 | $x2 = (($i + 1) * $column_width) - $padding;
145 | $y2 = $height;
146 |
147 | imagefilledrectangle($image, $x1, $y1, $x2, $y2, $gray);
148 |
149 | imageline($image, $x1, $y1, $x1, $y2, $gray_lite);
150 | imageline($image, $x1, $y2, $x2, $y2, $gray_lite);
151 | imageline($image, $x2, $y1, $x2, $y2, $gray_dark);
152 | imagettftext($image, 10, 0, $x1, $height + 15, $gray_dark, APP_DIR . 'font/DroidSans.ttf', $month . '/' . substr($year, 2, 2));
153 | imagettftext($image, 10, 0, $x1 + 6, $y1 + 12, $gray_dark, APP_DIR . 'font/DroidSans.ttf', $val);
154 | }
155 |
156 | return $image;
157 | }
158 |
159 | /**
160 | * Converts an EzLink code to an integer
161 | * @static
162 | * @param string $string
163 | * @return int
164 | */
165 | static function codeToInteger($string) {
166 | $string = strrev($string) . '';
167 | $total = 0.0;
168 | for ($i = 0; $i < strlen($string); $i++) {
169 | $base = pow(64,$i);
170 | $thischar = substr($string, $i, 1);
171 | $myval = strpos(self::$characters, $thischar);
172 | $total += $base * $myval;
173 | }
174 | return $total;
175 | }
176 |
177 | /**
178 | * Converts an integer into an EzLink code
179 | * @static
180 | * @param int $number
181 | * @return string
182 | */
183 | static function integerToCode($number) {
184 | $number = (float) $number;
185 | $holder = array();
186 | $i = 0;
187 | while ($number > 63) {
188 | $quotient = floor($number / 64);
189 | $remainder = $number % 64;
190 | $holder[$i] = $remainder;
191 | $number = $quotient;
192 | $i++;
193 | }
194 | $holder[$i] = $number;
195 | $output = "";
196 | for ($i = sizeof($holder) - 1; $i >= 0; $i--) {
197 | $output .= substr(self::$characters, $holder[$i], 1);
198 | }
199 | return $output;
200 | }
201 |
202 | }
203 |
--------------------------------------------------------------------------------
/app/view/error/404.php:
--------------------------------------------------------------------------------
1 | 404: File Not Found
2 | You attempted to grab something we don't have to give. It's okay, it happens.
--------------------------------------------------------------------------------
/app/view/error/500.php:
--------------------------------------------------------------------------------
1 | 500: Internal Server Error
2 | WTF did you do?!
3 | =$text?>
4 | =$filename?>:=$linenumber?>
5 |
--------------------------------------------------------------------------------
/app/view/error/fatal.php:
--------------------------------------------------------------------------------
1 | 500: Internal Server Error
2 | You caused a fatal error! ZOMGZ!
3 | =$error?>
--------------------------------------------------------------------------------
/app/view/layout/main.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | =$title?>
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Totals: =$count_urls?> Pages / =$count_clicks?> Clicks
11 |
12 |
13 |
14 | =$content?>
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/view/pages/api.php:
--------------------------------------------------------------------------------
1 | The ezlink.info API is extremely easy to work with. All you need to do is request the following url using your language of choice and the page returns the newly generated URL.
2 | This is very useful for programmatically turning a list of long or complex URLs into a list of short ones for your visitor's convenience.
3 |
4 | Request: http://=$server?>/api/create?url=http://www.example.com
5 | Returns: http://=$server?>/link/b
6 |
7 | Here is an example in PHP for generating shorter URLs:
8 |
9 | $longurl = "http://www.example.com/location.php?asdf=jkl";
10 | $safeurl = urlencode($longurl);
11 | $shorturl = file_get_contents("http://=$server?>/api/create?url=$safeurl");
12 | echo $shorturl;
13 |
--------------------------------------------------------------------------------
/app/view/pages/home.php:
--------------------------------------------------------------------------------
1 |
4 | How to use: Simply paste the URL that you would like to make shorter into the blue box above and click Go. The website will generate a shorter link for you and display it on screen.
5 | New: We're now offering an API for programatically creating shorter URLs. Includes an example in PHP.
--------------------------------------------------------------------------------
/app/view/pages/statistics.php:
--------------------------------------------------------------------------------
1 |
2 | This graph shows how many links were added over the previous twelve months.
--------------------------------------------------------------------------------
/app/view/pages/submit.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | http://=$server?>=$base_url?>link/=$code?>
6 |
7 | (Fast Redirect)
8 |
9 |
10 | http://=$server?>=$base_url?>link/=$code?>?h
11 |
12 | (Hides Referrer ezlink.info)
13 |
14 |
15 |
16 |
17 | Please submit a valid URL
18 |
19 | Convert another link
--------------------------------------------------------------------------------
/example.sql:
--------------------------------------------------------------------------------
1 | -- Data for the sample SleekMVC app
2 |
3 | CREATE TABLE `clicks` (
4 | `url_id` bigint(20) NOT NULL,
5 | `year` year(4) NOT NULL,
6 | `month` tinyint(4) NOT NULL,
7 | `count` int(11) NOT NULL,
8 | KEY `url_id` (`url_id`,`year`,`month`,`count`)
9 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
10 |
11 | CREATE TABLE `url` (
12 | `id` bigint(20) NOT NULL AUTO_INCREMENT,
13 | `url` varchar(511) COLLATE latin1_general_ci NOT NULL,
14 | `added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
15 | PRIMARY KEY (`id`)
16 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tlhunter/sleekmvc-app/76128491248922140e1e75c25276fa9159eb11bf/images/logo.png
--------------------------------------------------------------------------------
/images/tumblbeast-404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tlhunter/sleekmvc-app/76128491248922140e1e75c25276fa9159eb11bf/images/tumblbeast-404.png
--------------------------------------------------------------------------------
/images/tumblbeast-500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tlhunter/sleekmvc-app/76128491248922140e1e75c25276fa9159eb11bf/images/tumblbeast-500.png
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | '100'));
39 | \Sleek\Request::addRoute('/users/:user_id', array(
40 | 'controller' => 'home',
41 | 'action' => 'view_user',
42 |
43 | 'user_id' => NULL
44 | ));
45 |
46 | // This is a "catch all" route; in many cases it will be all you need.
47 |
48 | // www.example.com/root/
49 | // www.example.com/root/controllerName
50 | // www.example.com/root/controllerName/actionName
51 | // www.example.com/root/controllerName/actionName/something
52 | \Sleek\Request::addRoute('(/:controller(/:action(/:id)))', array(
53 | 'controller' => 'home',
54 | 'action' => 'index',
55 |
56 | 'id' => NULL
57 | ));
58 |
59 | // Executes SleekMVC
60 | new \Sleek\Core();
61 |
--------------------------------------------------------------------------------
/styles/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | text-align: center;
4 | font-family: verdana, sans-serif;
5 | font-size: 11px;
6 | }
7 | #container {
8 | margin: 0 auto 0 auto;
9 | width: 600px;
10 | text-align: left;
11 | }
12 | #top {
13 | padding: 10px 0 10px 0;
14 | height: 20px;
15 | margin: 0 0 10px 0;
16 | border-bottom: 1px dotted #ccc;
17 | }
18 | #ie-wrapper {
19 | text-align: center;
20 | }
21 | h1#header {
22 | width: 356px; height: 102px;
23 | background-image: url("../images/logo.png");
24 | margin: 0 auto 0 auto; padding: 0;
25 | clear: both;
26 | }
27 | h1#header span {
28 | display: none;
29 | }
30 | #footer {
31 | text-align: center;
32 | border-top: 1px dotted #ccc;
33 | padding-top: 10px;
34 | color: #999;
35 | margin-top: 20px;
36 | }
37 | a {
38 | color: #51bafc;
39 | }
40 | #url {
41 | border: 1px solid #109df6;
42 | padding: 4px 0 0 4px;
43 | font-size: 12px;
44 | width: 400px;
45 | height: 28px;
46 | vertical-align: middle;
47 | }
48 | #convert {
49 | border: 1px solid #109df6;
50 | font-size: 12px;
51 | width: 40px; height: 28px;
52 | vertical-align: middle;
53 | margin-left: 10px;
54 | }
55 | form {
56 | margin: 0;
57 | padding: 0;
58 | text-align: center;
59 | }
60 | p {
61 | text-align: justify;
62 | color: #666;
63 | margin: 20px 0 20px 0;
64 | padding: 0;
65 | line-height: 16px;
66 | }
67 | .error {
68 | border: 1px solid red;
69 | color: red;
70 | padding: 10px;
71 | }
72 | .success {
73 | border: 1px solid green;
74 | color: green;
75 | padding: 10px;
76 | }
77 | #lefty {
78 | width: 300px;
79 | float: left;
80 | text-align: left;
81 | }
82 | #righty {
83 | width: 190px;
84 | float: right;
85 | text-align: right;
86 | }
87 | pre {
88 | font-family: consolas, "courier new", monospace;
89 | font-size: 12px;
90 | color: #666;
91 | border-left: 2px solid #51bafc;
92 | padding: 4px 0 4px 8px;
93 | background-color: #eee;
94 | }
--------------------------------------------------------------------------------