├── README.md
├── app.js
├── index.php
├── rew.phps
└── style.css
/README.md:
--------------------------------------------------------------------------------
1 | apache2nginx
2 | ============
3 |
4 | Converts apache rewrite rules to nginx rewrite rules
5 |
6 | for more information please visit http://www.anilcetin.com/convert-apache-htaccess-to-nginx/
7 |
8 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var textarea;
2 | var results;
3 | var loader;
4 |
5 | function convertRules() {
6 |
7 | if ($(this).data('oldVal') == $(this).val()) {
8 | return;
9 | }
10 |
11 | var rules = $(this).val();
12 |
13 | if (rules != '') {
14 | loader.addClass('visible');
15 | $.ajax({
16 | type: 'POST',
17 | data: {rules: rules}
18 | }).done(function (result) {
19 | loader.removeClass('visible');
20 | results.val(result);
21 | })
22 | } else {
23 | results.val('');
24 | }
25 |
26 | $(this).data('oldVal', $(this).val());
27 | }
28 |
29 | $(function () {
30 | textarea = $('#apache').find('textarea');
31 | results = $('#nginx').find('textarea');
32 | loader = $('#loader');
33 | textarea.on('propertychange change click keyup input paste', convertRules).data('oldVal', textarea.val());
34 | });
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | parseContent();
9 | $RC->writeConfig();
10 | exit($RC->confOk);
11 | }
12 | ?>
13 |
14 |
15 |
16 | Rule convertor, convert apache htaccess rewrite rules to nginx rewrite rules automatically
17 |
18 |
19 |
20 |
21 |
22 | Apache2Nginx rules converter
23 | attention: not so much beta, but check twice before using!
24 |
25 |
26 |
27 | Apache Rewrite Rules
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Nginx converted Rules
41 |
42 |
43 |
44 |
60 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/rew.phps:
--------------------------------------------------------------------------------
1 | htContent = $htContent;
6 | }
7 | */
8 | function parseLine($line){
9 | list($cmd,$regex,$rew,$flags) = explode(" ",$line);
10 | if(!empty($flags)){
11 | $flagsArray = explode(",",trim(substr(substr(trim($flags),strpos($flags,'[')+1),0,strpos($flags,']')-1)));
12 | $flagsArray = array_map("trim",$flagsArray);
13 | }
14 | return array(trim($regex),trim($rew),$flagsArray);
15 | }
16 |
17 | function readRules(){
18 | $lines = explode("\n",$this->htContent);
19 | $i = 0;
20 | foreach($lines as $line){
21 | $line = trim($line);
22 | if($line[0] != '#' && !empty($line[0])){
23 | if(strpos($line,"RewriteCond") !== false){
24 | if(!isset($k))$k = 0;
25 | if(!isset($p))$p = 0;
26 | $parsedLine = $this->parseLine($line);
27 | $conds[$p] = array(
28 | 'match' => $parsedLine[0],
29 | 'rule' => $parsedLine[1],
30 | 'flags' => $parsedLine[2]
31 | );
32 | $p++;
33 | }
34 | if(strpos($line,"RewriteRule") !== false){
35 | if(!isset($k))$k = 0;
36 | $parsedLine = $this->parseLine($line);
37 | $condBit = 'AND';
38 | if(is_array($conds[0]["flags"]) && in_array('OR',$conds[0]["flags"]))$condBit = 'OR';
39 | $rules[$k] = array(
40 | 'rule' => array(
41 | 'regex' => $parsedLine[0],
42 | 'rew' => $parsedLine[1],
43 | 'flags' => $parsedLine[2]
44 | ),
45 | 'condBit' => $condBit,
46 | 'conditions' => $conds
47 | );
48 | unset($p,$conds,$parsedLine,$condBit);
49 | $k++;
50 | }
51 | }
52 | }
53 | return $rules;
54 | }
55 |
56 |
57 | function parseFlags($flagArray,$type,$r,$c){
58 | //type: 0 -> rule 1-> condition
59 | //this function returns an array;
60 | /*
61 | array(
62 | return => 0|return code
63 | break => 0|1
64 | appendEnd => last|permanent|redirect|break
65 | env => var=value
66 | matchOperator => ~*|~
67 | unknown => 0|1
68 | set => key:var
69 | )
70 | */
71 | $returnArray = array('return' => '0','break' => '0','appendEnd' => '', 'env' => '', 'matchOperator' => '~');
72 | foreach($flagArray as $flag){
73 | switch($flag[0]){
74 | case 'N':
75 | case 'n':
76 | $returnArray["matchOperator"] = '~*';
77 | if(!isset($returnArray["unknown"]))$returnArray["unknown"] = '0';
78 | break;
79 | case 'F':
80 | case 'f':
81 | $returnArray["return"] = '403';
82 | $returnArray["break"] = '1';
83 | if(!isset($returnArray["unknown"]))$returnArray["unknown"] = '0';
84 | break;
85 | case 'G':
86 | case 'g':
87 | $returnArray["return"] = '410';
88 | $returnArray["break"] = '1';
89 | if(!isset($returnArray["unknown"]))$returnArray["unknown"] = '0';
90 | break;
91 | case 'R':
92 | case 'r':
93 | list($flaga,$rcode) = explode("=",$flag);
94 | if($rcode == '301' || $rcode == 'permanent'){
95 | $returnArray["appendEnd"] = 'permanent';
96 | } else {
97 | $returnArray["appendEnd"] = 'redirect';
98 | }
99 | $returnArray["break"] = '1';
100 | if(!isset($returnArray["unknown"]))$returnArray["unknown"] = '0';
101 | break;
102 | case 'L':
103 | case 'l':
104 | if(empty($returnArray["appendEnd"])){
105 | $returnArray["appendEnd"] = 'last';
106 | }
107 | if(!isset($returnArray["unknown"]))$returnArray["unknown"] = '0';
108 | break;
109 | case 'E':
110 | case 'e':
111 | list($cmd,$envvar) = explode("=",$flag);
112 | //list($ekey,$evar) = explode(":",$envvar);
113 | $returnArray["env"][] = $envvar;
114 | break;
115 | case 'O':
116 | case 'o':
117 | $returnArray["set"][] = '$rule_'.$r.' 1';
118 | break;
119 | case 'A':
120 | $returnArray["set"][] = '$rule_'.$r.' '.($c+1).'$rule_'.$r;
121 | break;
122 | }
123 | }
124 | if(count($flagArray) > 1){
125 | if(!isset($returnArray["unknown"]))$returnArray["unknown"] = '1';
126 | } else {
127 | $returnArray["unknown"] = '0';
128 | }
129 | return $returnArray;
130 |
131 | }
132 |
133 | function parseCondMatch($condition,$r,$c,$condBit){
134 | $matchOperator = '~';
135 |
136 | if($condition["rule"][0] == '!'){
137 | $nomatch = '!';
138 | $condition["rule"] = substr($condition["rule"],1);
139 | }
140 |
141 | $condition["flags"][] = $condBit;
142 | $condition["flags"] = array_unique($condition["flags"]);
143 |
144 |
145 | $fromFlags = $this->parseFlags($condition["flags"],1,$r,$c);
146 |
147 |
148 | if($fromFlags["matchOperator"]){
149 | $matchOperator = $fromFlags["matchOperator"];
150 | }
151 |
152 | switch($condition["rule"]){
153 | case "-f":
154 | case "-F":
155 | $left = $nomatch.'-f';
156 | $right = $condition["match"];
157 | $operand = '';
158 | break;
159 | case "-d":
160 | $left = $nomatch.'-d';
161 | $right = $condition["match"];
162 | $operand = '';
163 | break;
164 | case "-s":
165 | $left = $nomatch.'-e';
166 | $right = $condition["match"];
167 | $operand = '';
168 | break;
169 | default:
170 | $left = $condition["match"];
171 | $right = $condition["rule"];
172 | $operand = $nomatch.$matchOperator;
173 |
174 | break;
175 | }
176 |
177 | $returnArray = array(
178 | 'left' => $left,
179 | 'right' => $right,
180 | 'operand' => $operand,
181 | 'flags' => $fromFlags
182 | );
183 | return $returnArray;
184 | }
185 |
186 | function parseRewirteCond($rule,$r){
187 | $c = 0;
188 | if(is_array($rule["conditions"])){
189 | foreach($rule["conditions"] as $condition){
190 |
191 | $condResult[$c] = $this->parseCondMatch($condition,$r,$c,$rule["condBit"]);
192 | $c++;
193 | }
194 | }
195 | return $condResult;
196 | }
197 |
198 | function mustSkipForCond($conditions){
199 | if(count($conditions)==0){
200 | return 0;
201 | } elseif(count($conditions) == 1) {
202 | if($conditions[0]["flags"]["unknown"] == 1){
203 | return "skipped because all flags in condition are unknown";
204 | }
205 | return 0;
206 | } else {
207 | $unknown = 0;
208 | foreach($conditions as $cond){
209 | if($cond["flags"]["unknown"] == 1){
210 | $unknown++;
211 | }
212 | }
213 | if(count($conditions) == $unknown){
214 | return "skipped because all flags for all conditions are unknown";
215 | }
216 | return 0;
217 | }
218 | }
219 |
220 | function setBackRef(&$rule,&$condsParsed){
221 | if(preg_match_all('/\%([0-9])/',$rule["rule"]["regex"],$matchesRule)!=0){
222 | $rule["rule"]["regex"] = preg_replace('/\%([0-9])/','$bref_$1',$rule["rule"]["regex"]);
223 | }
224 |
225 | if(preg_match_all('/\%([0-9])/',$rule["rule"]["rew"],$matchesRew)!=0){
226 | $rule["rule"]["rew"] = preg_replace('/\%([0-9])/','$bref_$1',$rule["rule"]["rew"]);
227 | }
228 |
229 | $totalMatches = array_merge($matchesRule[1],$matchesRew[1]);
230 |
231 |
232 | if(is_array($rule["rule"]["flags"])){
233 | $i=0;
234 | foreach($rule["rule"]["flags"] as $flags){
235 | if(preg_match_all('/\%([0-9])/',$rule["rule"]["flags"][$i],$matchesFlag)!=0){
236 | $rule["rule"]["flags"][$i] = preg_replace('/\%([0-9])/','$bref_$1',$rule["rule"]["flags"][$i]);
237 | $totalMatches = array_merge($totalMatches,$matchesFlag[1]);
238 | }
239 | $i++;
240 | }
241 | }
242 |
243 | $totalMatches = array_unique($totalMatches);
244 | if(is_array($totalMatches)){
245 | foreach($totalMatches as $match){
246 | $i=0;
247 | if($rule["condBit"] == 'OR'){
248 | foreach($condsParsed as $cond){
249 | array_push($condsParsed[$i]["flags"]["set"], '$bref_'.$match.' $'.$match);
250 | $i++;
251 | }
252 | } else {
253 | array_push($condsParsed[count($condsParsed)-1]["flags"]["set"], '$bref_'.$match.' $'.$match);
254 | }
255 | }
256 | }
257 |
258 |
259 | }
260 |
261 | function parseRule(&$rule,$c){
262 |
263 | if($rule["rule"]["regex"][0] == '^'){
264 | if($rule["rule"]["regex"][1]!='/'){
265 | $rule["rule"]["regex"] = '^/'.substr($rule["rule"]["regex"],1);
266 | }
267 | } else {
268 | if($rule["rule"]["regex"][0]!='/'){
269 | $rule["rule"]["regex"] = '/'.$rule["rule"]["regex"];
270 | }
271 | }
272 |
273 | if($rule["rule"]["rew"][0] == '^' && substr($rule["rule"]["rew"],0,4) != 'http'){
274 | if($rule["rule"]["rew"][1]!='/'){
275 | $rule["rule"]["rew"] = '^/'.substr($rule["rule"]["rew"],1);
276 | }
277 | } else {
278 | if($rule["rule"]["rew"][0]!='/' && substr($rule["rule"]["rew"],0,4) != 'http'){
279 | $rule["rule"]["rew"] = '/'.$rule["rule"]["rew"];
280 | }
281 | }
282 |
283 | if($rule["rule"]["rew"] == '/-'){
284 | unset($rule["rule"]["rew"],$rule["rule"]["regex"]);
285 | }
286 |
287 |
288 | if($c != 0){
289 |
290 | if($rule["condBit"] == 'OR'){
291 | $rule["rule"]["trueExp"] = '1';
292 | } else {
293 | $i=0;
294 | while($i < $c){
295 | $backme = ($i+1).$backme;
296 | $i++;
297 | }
298 | $rule["rule"]["trueExp"] = $backme;
299 | }
300 | }
301 | }
302 |
303 | function replaceVariables(&$val,&$key){
304 |
305 | if(preg_match_all('/\%\{HTTP\:(.*)\}/',$val,$matches)){
306 | foreach($matches[1] as $match){
307 | $val = str_replace('%{HTTP:'.$match.'}','$http_'.str_replace('-','_',strtolower($match)),$val);
308 | }
309 | }
310 |
311 |
312 | $pat = array(
313 | '%{HTTP_USER_AGENT}',
314 | '%{HTTP_REFERER}',
315 | '%{HTTP_COOKIE}',
316 | '%{HTTP_FORWARDED}',
317 | '%{HTTP_HOST}',
318 | '%{HTTP_PROXY_CONNECTION}',
319 | '%{HTTP_ACCEPT}',
320 | '%{REMOTE_ADDR}',
321 | '%{REMOTE_PORT}',
322 | '%{REMOTE_USER}',
323 | '%{REQUEST_METHOD}',
324 | '%{SCRIPT_FILENAME}',
325 | '%{PATH_INFO}',
326 | '%{QUERY_STRING}',
327 | '%{DOCUMENT_ROOT}',
328 | '%{SERVER_NAME}',
329 | '%{SERVER_ADDR}',
330 | '%{SERVER_PORT}',
331 | '%{SERVER_PROTOCOL}',
332 | '%{REQUEST_URI}',
333 | '%{REQUEST_FILENAME}'
334 | );
335 |
336 | $rep = array(
337 | '$http_user_agent',
338 | '$http_referer',
339 | '$http_cookie',
340 | '$http_forwarded',
341 | '$http_host',
342 | '$http_proxy_connection',
343 | '$http_accept',
344 | '$remote_addr',
345 | '$remote_port',
346 | '$remote_user',
347 | '$request_method',
348 | '$uri',
349 | '$uri',
350 | '$args',
351 | '$document_root',
352 | '$server_name',
353 | '$server_addr',
354 | '$server_port',
355 | '$server_protocol',
356 | '$uri',
357 | '$request_filename'
358 | );
359 | $oldVal = $val;
360 | $val = str_replace($pat,$rep,$val);
361 |
362 | if($oldVal == $val && preg_match('/\%\{(.*)\}/i',$val)!=0){
363 | $val = "IGNORE";
364 | }
365 | }
366 |
367 |
368 | function walkRecursive(&$input, $funcname, $userdata = ""){
369 |
370 | if (!is_array($input)){
371 | return false;
372 | }
373 |
374 | foreach ($input AS $key => $value){
375 | if(is_array($input[$key])){
376 | $this->walkRecursive($input[$key], $funcname, $userdata);
377 | } else {
378 | $saved_value = $value;
379 | if(!empty($userdata)){
380 | $this->$funcname($value, $key, $userdata);
381 | } else {
382 | $this->$funcname($value, $key);
383 | }
384 |
385 | if($value != $saved_value){
386 | if($value == 'IGNORE'){
387 | unset($input[$key]);
388 | } else {
389 | $input[$key] = $value;
390 | }
391 | }
392 | }
393 | }
394 | return true;
395 | }
396 |
397 | function writeConfig(){
398 | $r = 0;
399 | foreach($this->conf as $conf){
400 | if(is_array($conf)){
401 | //array_walk_recursive($conf,'rewriteConf::replaceVariables');
402 | $this->walkRecursive($conf,'replaceVariables');
403 | //print_r($conf);
404 | //exit;
405 | $c = 0;
406 | if(is_array($conf["conds"])){
407 | foreach($conf["conds"] as $cond){
408 | if($cond["flags"]["unknown"]!=1 && isset($cond["left"]) && isset($cond["right"])){
409 | if($cond["operand"] == ''){
410 | $ret.= 'if ('.$cond["left"].' '.$cond["right"].'){
411 | ';
412 | } else {
413 | $ret.= 'if ('.$cond["left"].' '.$cond["operand"].' "'.$cond["right"].'"){
414 | ';
415 | }
416 | if(is_array($cond["flags"]["set"])){
417 | foreach($cond["flags"]["set"] as $set){
418 | $ret.= ' set '.$set.';
419 | ';
420 | }
421 | }
422 |
423 | if(is_array($cond["flags"]["env"])){
424 | foreach($cond["flags"]["env"] as $env){
425 | $ret.= ' setenv '.$env.';
426 | ';
427 | }
428 | }
429 | if($conf["condBit"] == 'OR'){
430 | if($conf["rule"]["flags"]["return"] > 0){
431 | $ret.= ' return '.$conf["rule"]["flags"]["return"].';
432 | ';
433 | $isReturned = 1;
434 | }
435 | if($conf["rule"]["flags"]["break"] == 1){
436 | $ret.= ' break;
437 | ';
438 | }
439 | }
440 | $ret.='}
441 | ';
442 |
443 | } else {
444 | $conf["rule"]["trueExp"] = str_replace($c,'',$conf["rule"]["trueExp"]);
445 | $ret.= '#ignored: condition '.$c.'
446 | ';
447 | }
448 | $c++;
449 | }
450 | }
451 | if(!isset($isReturned)){
452 | if($conf["rule"]["flags"]["unknown"] != 1){
453 |
454 | if(!empty($conf["rule"]["trueExp"]))
455 | {
456 | $ret.= 'if ($rule_'.$r.' = "'.$conf["rule"]["trueExp"].'"){
457 | ';
458 | }
459 |
460 | if($conf["rule"]["flags"]["return"] < 1){
461 |
462 | if(is_array($conf["rule"]["flags"]["set"])){
463 | foreach($conf["rule"]["flags"]["set"] as $set){
464 | $ret.= ' set '.$set.';
465 | ';
466 | }
467 | }
468 |
469 | if(is_array($conf["rule"]["flags"]["env"])){
470 | foreach($conf["rule"]["flags"]["env"] as $env){
471 | $ret.= ' setenv '.$env.';
472 | ';
473 | }
474 | }
475 | if(isset($conf["rule"]["regex"]) && isset($conf["rule"]["rew"])){
476 | if(!empty($conf["rule"]["flags"]["appendEnd"])){
477 | $conf["rule"]["flags"]["appendEnd"] = ' '.$conf["rule"]["flags"]["appendEnd"];
478 | }
479 |
480 | // Check if we need to escape the regex
481 | $to_escape = array('{', '}', ';');
482 | $quotes = '';
483 |
484 | foreach($to_escape as $escape)
485 | {
486 | if (strpos($conf["rule"]["regex"], $escape) !== false) {
487 | $quotes = '"';
488 | break;
489 | }
490 | }
491 |
492 | $ret.= ' rewrite '.$quotes.$conf["rule"]["regex"].$quotes.' '.$conf["rule"]["rew"].''.$conf["rule"]["flags"]["appendEnd"].';
493 | ';
494 | } else {
495 | $ret.= '#ignored: "-" thing used or unknown variable in regex/rew
496 | ';
497 | }
498 | } else {
499 | $ret.= ' return '.$conf["rule"]["flags"]["return"].';
500 | ';
501 | if($conf["rule"]["flags"]["break"] == 1){
502 | $ret.= ' break;
503 | ';
504 | }
505 | }
506 | if(!empty($conf["rule"]["trueExp"]))
507 | {
508 | $ret.='}
509 | ';
510 | }
511 | } else {
512 | $ret.= '#ignored: unknown variable in rule flag
513 | ';
514 | }
515 | }
516 | unset($isReturned,$cond,$env,$set);
517 | } else {
518 | $ret.= $conf.'
519 | ';
520 | }
521 | $r++;
522 | }
523 | $this->confOk = $ret;
524 | }
525 |
526 | function parseContent(){
527 | $this->rules = $this->readRules();
528 | $r = 0;
529 | foreach($this->rules as $rule){
530 | $condsParsed = $this->parseRewirteCond($rule,$r);
531 | $beforeMscr = $mscr;
532 | if(($mscr = $this->mustSkipForCond($condsParsed))!=0){
533 | $conf[$r]["conds"] = $mscr;
534 | $conf[$r]["rule"] = $mscr;
535 | } else {
536 | if($beforeMscr != 0){
537 | //set last|break to before rule if any
538 | }
539 | $this->setBackRef($rule,$condsParsed);
540 | if(is_array($rule["rule"]["flags"])){
541 | $rule["rule"]["flags"] = $this->parseFlags($rule["rule"]["flags"],0,$r,0);
542 | } else {
543 | unset($rule["rule"]["flags"]);
544 | }
545 | $this->parseRule($rule,count($condsParsed));
546 | $conf[$r]["conds"] = $condsParsed;
547 | $conf[$r]["rule"] = $rule["rule"];
548 | }
549 | $conf[$r]["condBit"] = $rule["condBit"];
550 | $r++;
551 | }
552 | $this->conf = $conf;
553 | }
554 |
555 | }
556 | ?>
557 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | article, aside, dialog, figure, footer, header, hgroup, nav, section {
2 | display: block;
3 | zoom: 1;
4 | }
5 |
6 | html {
7 | box-sizing: border-box;
8 | }
9 |
10 | *, *:before, *:after {
11 | box-sizing: inherit;
12 | }
13 |
14 | html, body {
15 | width: 100%;
16 | height: 100%;
17 |
18 | margin: 0;
19 | padding: 0;
20 | }
21 |
22 | body {
23 | background: #2c3e50;
24 | font-family: 'Roboto', sans-serif;
25 | display: -webkit-box;
26 | display: -webkit-flex;
27 | display: -ms-flexbox;
28 | display: flex;
29 | margin: 0;
30 | padding: 0;
31 | height: 100vh;
32 | -webkit-box-orient: vertical;
33 | -webkit-box-direction: normal;
34 | -webkit-flex-direction: column;
35 | -ms-flex-direction: column;
36 | flex-direction: column;
37 |
38 | -webkit-box-pack: start;
39 |
40 | -webkit-justify-content: flex-start;
41 |
42 | -ms-flex-pack: start;
43 |
44 | justify-content: flex-start; /* align items in Main Axis */
45 | -webkit-box-align: stretch;
46 | -webkit-align-items: stretch;
47 | -ms-flex-align: stretch;
48 | align-items: stretch; /* align items in Cross Axis */
49 | -webkit-align-content: stretch;
50 | -ms-flex-line-pack: stretch;
51 | align-content: stretch; /* Extra space in Cross Axis */
52 | }
53 |
54 | header, footer {
55 | background: white;
56 | margin: 0;
57 | padding: 20px;
58 | text-align: center;
59 | box-shadow: 0 0 30px rgba(0, 0, 0, .3);
60 | max-height: 60px;
61 | }
62 |
63 | header {
64 | max-height: 180px;
65 | }
66 |
67 | h1, footer, section {
68 | -webkit-box-flex: 1;
69 | -webkit-flex: 1;
70 | -ms-flex: 1;
71 | flex: 1;
72 | }
73 |
74 | h1, h2 {
75 | font-weight: 300;
76 | }
77 |
78 | h1 {
79 | margin-bottom: 8px;
80 | }
81 |
82 | h2 {
83 | color: white;
84 | }
85 |
86 | p a {
87 | color: white;
88 | }
89 |
90 | i {
91 | color: #ccc;
92 | }
93 |
94 | footer a {
95 | color: black;
96 | }
97 |
98 | article {
99 | -webkit-box-flex: 1;
100 | -webkit-flex: 1 auto;
101 | -ms-flex: 1 auto;
102 | flex: 1 auto;
103 | padding: 30px;
104 | -webkit-box-orient: vertical;
105 | -webkit-box-direction: normal;
106 | -webkit-flex-direction: column;
107 | -ms-flex-direction: column;
108 | flex-direction: column;
109 | display: -webkit-box;
110 | display: -webkit-flex;
111 | display: -ms-flexbox;
112 | display: flex;
113 |
114 | -webkit-box-pack: start;
115 |
116 | -webkit-justify-content: flex-start;
117 |
118 | -ms-flex-pack: start;
119 |
120 | justify-content: flex-start; /* align items in Main Axis */
121 | -webkit-box-align: stretch;
122 | -webkit-align-items: stretch;
123 | -ms-flex-align: stretch;
124 | align-items: stretch; /* align items in Cross Axis */
125 | -webkit-align-content: stretch;
126 | -ms-flex-line-pack: stretch;
127 | align-content: stretch; /* Extra space in Cross Axis */
128 | }
129 |
130 | section {
131 | display: -webkit-box;
132 | display: -webkit-flex;
133 | display: -ms-flexbox;
134 | display: flex;
135 | -webkit-box-orient: horizontal;
136 | -webkit-box-direction: normal;
137 | -webkit-flex-direction: row;
138 | -ms-flex-direction: row;
139 | flex-direction: row;
140 | position: relative;
141 | }
142 |
143 | textarea, h2 {
144 | -webkit-box-flex: 1;
145 | -webkit-flex: 1 auto;
146 | -ms-flex: 1 auto;
147 | flex: 1 auto;
148 | }
149 |
150 | h2 {
151 | max-height: 50px;
152 | }
153 |
154 | textarea {
155 | width: 100%;
156 | display: block;
157 | padding: 20px;
158 | color: white;
159 |
160 | background: none;
161 | border: 1px solid #ccc;
162 | }
163 |
164 | section:first-of-type {
165 | border-right: 1px solid white;
166 | }
167 |
168 | aside {
169 | padding: 40px;
170 | background: rgba(0, 0, 0, .3);
171 | display: -webkit-box;
172 | display: -webkit-flex;
173 | display: -ms-flexbox;
174 | display: flex;
175 | }
176 |
177 | aside p {
178 | -webkit-box-flex: 1;
179 | -webkit-flex-grow: 1;
180 | -ms-flex-positive: 1;
181 | flex-grow: 1;
182 | color: #ccc;
183 | padding: 0 20px;
184 | line-height: 1.6;
185 | }
186 |
187 | aside p:last-child {
188 | -webkit-box-flex: 2;
189 | -webkit-flex-grow: 2;
190 | -ms-flex-positive: 2;
191 | flex-grow: 2;
192 | }
193 |
194 | aside p strong {
195 | text-transform: uppercase;
196 | display: block;
197 | margin-bottom: 20px;
198 | }
199 |
200 | @-webkit-keyframes rotate_pacman_half_up {
201 | 0% {
202 | -webkit-transform: rotate(270deg);
203 | transform: rotate(270deg);
204 | }
205 | 50% {
206 | -webkit-transform: rotate(360deg);
207 | transform: rotate(360deg);
208 | }
209 | 100% {
210 | -webkit-transform: rotate(270deg);
211 | transform: rotate(270deg);
212 | }
213 | }
214 |
215 | @keyframes rotate_pacman_half_up {
216 | 0% {
217 | -webkit-transform: rotate(270deg);
218 | transform: rotate(270deg);
219 | }
220 | 50% {
221 | -webkit-transform: rotate(360deg);
222 | transform: rotate(360deg);
223 | }
224 | 100% {
225 | -webkit-transform: rotate(270deg);
226 | transform: rotate(270deg);
227 | }
228 | }
229 |
230 | @-webkit-keyframes rotate_pacman_half_down {
231 | 0% {
232 | -webkit-transform: rotate(90deg);
233 | transform: rotate(90deg);
234 | }
235 | 50% {
236 | -webkit-transform: rotate(0deg);
237 | transform: rotate(0deg);
238 | }
239 | 100% {
240 | -webkit-transform: rotate(90deg);
241 | transform: rotate(90deg);
242 | }
243 | }
244 |
245 | @keyframes rotate_pacman_half_down {
246 | 0% {
247 | -webkit-transform: rotate(90deg);
248 | transform: rotate(90deg);
249 | }
250 | 50% {
251 | -webkit-transform: rotate(0deg);
252 | transform: rotate(0deg);
253 | }
254 | 100% {
255 | -webkit-transform: rotate(90deg);
256 | transform: rotate(90deg);
257 | }
258 | }
259 |
260 | @-webkit-keyframes pacman-balls {
261 | 75% {
262 | opacity: 0.7;
263 | }
264 | 100% {
265 | -webkit-transform: translate(-100px, -6.25px);
266 | transform: translate(-100px, -6.25px);
267 | }
268 | }
269 |
270 | @keyframes pacman-balls {
271 | 75% {
272 | opacity: 0.7;
273 | }
274 | 100% {
275 | -webkit-transform: translate(-100px, -6.25px);
276 | transform: translate(-100px, -6.25px);
277 | }
278 | }
279 |
280 | #loader {
281 | position: absolute;
282 | top: 50%;
283 | left: 50%;
284 | background: white;
285 | height: 160px;
286 | width: 160px;
287 | margin-left: -80px;
288 | margin-top: -80px;
289 | display: -webkit-box;
290 | display: -webkit-flex;
291 | display: -ms-flexbox;
292 | display: flex;
293 | -webkit-align-content: center;
294 | -ms-flex-line-pack: center;
295 | align-content: center;
296 | -webkit-box-pack: center;
297 | -webkit-justify-content: center;
298 | -ms-flex-pack: center;
299 | justify-content: center;
300 | -webkit-box-align: center;
301 | -webkit-align-items: center;
302 | -ms-flex-align: center;
303 | align-items: center;
304 | border-radius: 100%;
305 | opacity: 0;
306 | pointer-events: none;
307 | -webkit-transition: .3s;
308 | transition: .3s;
309 | }
310 |
311 | #loader.visible {
312 | opacity: 1;
313 | }
314 |
315 | .pacman {
316 | position: relative;
317 | -webkit-transform: scale(-1, 1);
318 | transform: scale(-1, 1);
319 | }
320 |
321 | .pacman > div:nth-child(2) {
322 | -webkit-animation: pacman-balls 1s -0.99s infinite linear;
323 | animation: pacman-balls 1s -0.99s infinite linear;
324 | }
325 |
326 | .pacman > div:nth-child(3) {
327 | -webkit-animation: pacman-balls 1s -0.66s infinite linear;
328 | animation: pacman-balls 1s -0.66s infinite linear;
329 | }
330 |
331 | .pacman > div:nth-child(4) {
332 | -webkit-animation: pacman-balls 1s -0.33s infinite linear;
333 | animation: pacman-balls 1s -0.33s infinite linear;
334 | }
335 |
336 | .pacman > div:nth-child(5) {
337 | -webkit-animation: pacman-balls 1s 0s infinite linear;
338 | animation: pacman-balls 1s 0s infinite linear;
339 | }
340 |
341 | .pacman > div:first-of-type {
342 | width: 0px;
343 | height: 0px;
344 | border-right: 25px solid transparent;
345 | border-top: 25px solid #2c3e50;
346 | border-left: 25px solid #2c3e50;
347 | border-bottom: 25px solid #2c3e50;
348 | border-radius: 25px;
349 | -webkit-animation: rotate_pacman_half_up 0.5s 0s infinite;
350 | animation: rotate_pacman_half_up 0.5s 0s infinite;
351 | position: relative;
352 | left: -30px;
353 | }
354 |
355 | .pacman > div:nth-child(2) {
356 | width: 0px;
357 | height: 0px;
358 | border-right: 25px solid transparent;
359 | border-top: 25px solid #2c3e50;
360 | border-left: 25px solid #2c3e50;
361 | border-bottom: 25px solid #2c3e50;
362 | border-radius: 25px;
363 | -webkit-animation: rotate_pacman_half_down 0.5s 0s infinite;
364 | animation: rotate_pacman_half_down 0.5s 0s infinite;
365 | margin-top: -50px;
366 | position: relative;
367 | left: -30px;
368 | }
369 |
370 | .pacman > div:nth-child(3),
371 | .pacman > div:nth-child(4),
372 | .pacman > div:nth-child(5),
373 | .pacman > div:nth-child(6) {
374 | background-color: #2c3e50;
375 | width: 15px;
376 | height: 15px;
377 | border-radius: 100%;
378 | margin: 2px;
379 | width: 10px;
380 | height: 10px;
381 | position: absolute;
382 | -webkit-transform: translate(0, -6.25px);
383 | transform: translate(0, -6.25px);
384 | top: 25px;
385 | left: 70px;
386 | }
--------------------------------------------------------------------------------