summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--codemirror_ui/.gitignore5
-rw-r--r--codemirror_ui/.htaccess3
-rw-r--r--codemirror_ui/CHANGELOG5
-rw-r--r--codemirror_ui/LICENSE45
-rw-r--r--codemirror_ui/README8
-rw-r--r--codemirror_ui/README.md66
-rw-r--r--codemirror_ui/VERSION3
-rw-r--r--codemirror_ui/codemirror_ui.php153
-rw-r--r--codemirror_ui/css/codemirror-ui-find.css19
-rw-r--r--codemirror_ui/css/codemirror-ui.css122
-rw-r--r--codemirror_ui/images/octologo.pngbin0 -> 37704 bytes
-rw-r--r--codemirror_ui/images/silk/accept.pngbin0 -> 781 bytes
-rw-r--r--codemirror_ui/images/silk/add.pngbin0 -> 733 bytes
-rw-r--r--codemirror_ui/images/silk/anchor.pngbin0 -> 523 bytes
-rw-r--r--codemirror_ui/images/silk/application.pngbin0 -> 464 bytes
-rw-r--r--codemirror_ui/images/silk/application_add.pngbin0 -> 619 bytes
-rw-r--r--codemirror_ui/images/silk/application_cascade.pngbin0 -> 524 bytes
-rw-r--r--codemirror_ui/images/silk/application_delete.pngbin0 -> 610 bytes
-rw-r--r--codemirror_ui/images/silk/application_double.pngbin0 -> 533 bytes
-rw-r--r--codemirror_ui/images/silk/application_edit.pngbin0 -> 703 bytes
-rw-r--r--codemirror_ui/images/silk/application_error.pngbin0 -> 656 bytes
-rw-r--r--codemirror_ui/images/silk/application_form.pngbin0 -> 467 bytes
-rw-r--r--codemirror_ui/images/silk/application_form_add.pngbin0 -> 592 bytes
-rw-r--r--codemirror_ui/images/silk/application_form_delete.pngbin0 -> 605 bytes
-rw-r--r--codemirror_ui/images/silk/application_form_edit.pngbin0 -> 714 bytes
-rw-r--r--codemirror_ui/images/silk/application_form_magnify.pngbin0 -> 612 bytes
-rw-r--r--codemirror_ui/images/silk/application_get.pngbin0 -> 581 bytes
-rw-r--r--codemirror_ui/images/silk/application_go.pngbin0 -> 634 bytes
-rw-r--r--codemirror_ui/images/silk/application_home.pngbin0 -> 685 bytes
-rw-r--r--codemirror_ui/images/silk/application_key.pngbin0 -> 670 bytes
-rw-r--r--codemirror_ui/images/silk/application_lightning.pngbin0 -> 656 bytes
-rw-r--r--codemirror_ui/images/silk/application_link.pngbin0 -> 701 bytes
-rw-r--r--codemirror_ui/images/silk/application_osx.pngbin0 -> 487 bytes
-rw-r--r--codemirror_ui/images/silk/application_osx_terminal.pngbin0 -> 525 bytes
-rw-r--r--codemirror_ui/images/silk/application_put.pngbin0 -> 585 bytes
-rw-r--r--codemirror_ui/images/silk/application_side_boxes.pngbin0 -> 478 bytes
-rw-r--r--codemirror_ui/images/silk/application_side_contract.pngbin0 -> 547 bytes
-rw-r--r--codemirror_ui/images/silk/application_side_expand.pngbin0 -> 581 bytes
-rw-r--r--codemirror_ui/images/silk/application_side_list.pngbin0 -> 510 bytes
-rw-r--r--codemirror_ui/images/silk/application_side_tree.pngbin0 -> 483 bytes
-rw-r--r--codemirror_ui/images/silk/application_split.pngbin0 -> 520 bytes
-rw-r--r--codemirror_ui/images/silk/application_tile_horizontal.pngbin0 -> 432 bytes
-rw-r--r--codemirror_ui/images/silk/application_tile_vertical.pngbin0 -> 492 bytes
-rw-r--r--codemirror_ui/images/silk/application_view_columns.pngbin0 -> 493 bytes
-rw-r--r--codemirror_ui/images/silk/application_view_detail.pngbin0 -> 576 bytes
-rw-r--r--codemirror_ui/images/silk/application_view_gallery.pngbin0 -> 555 bytes
-rw-r--r--codemirror_ui/images/silk/application_view_icons.pngbin0 -> 476 bytes
-rw-r--r--codemirror_ui/images/silk/application_view_list.pngbin0 -> 473 bytes
-rw-r--r--codemirror_ui/images/silk/application_view_tile.pngbin0 -> 465 bytes
-rw-r--r--codemirror_ui/images/silk/application_xp.pngbin0 -> 426 bytes
-rw-r--r--codemirror_ui/images/silk/application_xp_terminal.pngbin0 -> 507 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_branch.pngbin0 -> 582 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_divide.pngbin0 -> 677 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_down.pngbin0 -> 379 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_in.pngbin0 -> 600 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_inout.pngbin0 -> 551 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_join.pngbin0 -> 626 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_left.pngbin0 -> 345 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_merge.pngbin0 -> 484 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_out.pngbin0 -> 594 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_out_diag.pngbin0 -> 1129 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_redo.pngbin0 -> 625 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_refresh.pngbin0 -> 685 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_refresh_small.pngbin0 -> 506 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_right.pngbin0 -> 349 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_rotate_anticlockwise.pngbin0 -> 608 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_rotate_clockwise.pngbin0 -> 602 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_switch.pngbin0 -> 683 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_turn_left.pngbin0 -> 516 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_turn_right.pngbin0 -> 489 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_undo.pngbin0 -> 631 bytes
-rw-r--r--codemirror_ui/images/silk/arrow_up.pngbin0 -> 372 bytes
-rw-r--r--codemirror_ui/images/silk/asterisk_orange.pngbin0 -> 760 bytes
-rw-r--r--codemirror_ui/images/silk/asterisk_yellow.pngbin0 -> 743 bytes
-rw-r--r--codemirror_ui/images/silk/attach.pngbin0 -> 391 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_add.pngbin0 -> 853 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_bronze_1.pngbin0 -> 733 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_bronze_2.pngbin0 -> 755 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_bronze_3.pngbin0 -> 754 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_delete.pngbin0 -> 849 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_gold_1.pngbin0 -> 753 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_gold_2.pngbin0 -> 770 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_gold_3.pngbin0 -> 781 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_silver_1.pngbin0 -> 714 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_silver_2.pngbin0 -> 734 bytes
-rw-r--r--codemirror_ui/images/silk/award_star_silver_3.pngbin0 -> 738 bytes
-rw-r--r--codemirror_ui/images/silk/basket.pngbin0 -> 669 bytes
-rw-r--r--codemirror_ui/images/silk/basket_add.pngbin0 -> 752 bytes
-rw-r--r--codemirror_ui/images/silk/basket_delete.pngbin0 -> 773 bytes
-rw-r--r--codemirror_ui/images/silk/basket_edit.pngbin0 -> 811 bytes
-rw-r--r--codemirror_ui/images/silk/basket_error.pngbin0 -> 794 bytes
-rw-r--r--codemirror_ui/images/silk/basket_go.pngbin0 -> 777 bytes
-rw-r--r--codemirror_ui/images/silk/basket_put.pngbin0 -> 733 bytes
-rw-r--r--codemirror_ui/images/silk/basket_remove.pngbin0 -> 738 bytes
-rw-r--r--codemirror_ui/images/silk/bell.pngbin0 -> 789 bytes
-rw-r--r--codemirror_ui/images/silk/bell_add.pngbin0 -> 816 bytes
-rw-r--r--codemirror_ui/images/silk/bell_delete.pngbin0 -> 824 bytes
-rw-r--r--codemirror_ui/images/silk/bell_error.pngbin0 -> 813 bytes
-rw-r--r--codemirror_ui/images/silk/bell_go.pngbin0 -> 836 bytes
-rw-r--r--codemirror_ui/images/silk/bell_link.pngbin0 -> 850 bytes
-rw-r--r--codemirror_ui/images/silk/bin.pngbin0 -> 476 bytes
-rw-r--r--codemirror_ui/images/silk/bin_closed.pngbin0 -> 363 bytes
-rw-r--r--codemirror_ui/images/silk/bin_empty.pngbin0 -> 475 bytes
-rw-r--r--codemirror_ui/images/silk/bomb.pngbin0 -> 793 bytes
-rw-r--r--codemirror_ui/images/silk/book.pngbin0 -> 593 bytes
-rw-r--r--codemirror_ui/images/silk/book_add.pngbin0 -> 714 bytes
-rw-r--r--codemirror_ui/images/silk/book_addresses.pngbin0 -> 770 bytes
-rw-r--r--codemirror_ui/images/silk/book_delete.pngbin0 -> 719 bytes
-rw-r--r--codemirror_ui/images/silk/book_edit.pngbin0 -> 813 bytes
-rw-r--r--codemirror_ui/images/silk/book_error.pngbin0 -> 734 bytes
-rw-r--r--codemirror_ui/images/silk/book_go.pngbin0 -> 745 bytes
-rw-r--r--codemirror_ui/images/silk/book_key.pngbin0 -> 779 bytes
-rw-r--r--codemirror_ui/images/silk/book_link.pngbin0 -> 789 bytes
-rw-r--r--codemirror_ui/images/silk/book_next.pngbin0 -> 702 bytes
-rw-r--r--codemirror_ui/images/silk/book_open.pngbin0 -> 622 bytes
-rw-r--r--codemirror_ui/images/silk/book_previous.pngbin0 -> 680 bytes
-rw-r--r--codemirror_ui/images/silk/box.pngbin0 -> 555 bytes
-rw-r--r--codemirror_ui/images/silk/brick.pngbin0 -> 452 bytes
-rw-r--r--codemirror_ui/images/silk/brick_add.pngbin0 -> 729 bytes
-rw-r--r--codemirror_ui/images/silk/brick_delete.pngbin0 -> 745 bytes
-rw-r--r--codemirror_ui/images/silk/brick_edit.pngbin0 -> 775 bytes
-rw-r--r--codemirror_ui/images/silk/brick_error.pngbin0 -> 798 bytes
-rw-r--r--codemirror_ui/images/silk/brick_go.pngbin0 -> 790 bytes
-rw-r--r--codemirror_ui/images/silk/brick_link.pngbin0 -> 764 bytes
-rw-r--r--codemirror_ui/images/silk/bricks.pngbin0 -> 825 bytes
-rw-r--r--codemirror_ui/images/silk/briefcase.pngbin0 -> 793 bytes
-rw-r--r--codemirror_ui/images/silk/bug.pngbin0 -> 774 bytes
-rw-r--r--codemirror_ui/images/silk/bug_add.pngbin0 -> 806 bytes
-rw-r--r--codemirror_ui/images/silk/bug_delete.pngbin0 -> 836 bytes
-rw-r--r--codemirror_ui/images/silk/bug_edit.pngbin0 -> 873 bytes
-rw-r--r--codemirror_ui/images/silk/bug_error.pngbin0 -> 841 bytes
-rw-r--r--codemirror_ui/images/silk/bug_go.pngbin0 -> 831 bytes
-rw-r--r--codemirror_ui/images/silk/bug_link.pngbin0 -> 847 bytes
-rw-r--r--codemirror_ui/images/silk/building.pngbin0 -> 556 bytes
-rw-r--r--codemirror_ui/images/silk/building_add.pngbin0 -> 631 bytes
-rw-r--r--codemirror_ui/images/silk/building_delete.pngbin0 -> 633 bytes
-rw-r--r--codemirror_ui/images/silk/building_edit.pngbin0 -> 731 bytes
-rw-r--r--codemirror_ui/images/silk/building_error.pngbin0 -> 653 bytes
-rw-r--r--codemirror_ui/images/silk/building_go.pngbin0 -> 665 bytes
-rw-r--r--codemirror_ui/images/silk/building_key.pngbin0 -> 705 bytes
-rw-r--r--codemirror_ui/images/silk/building_link.pngbin0 -> 668 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_add.pngbin0 -> 286 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_arrow_bottom.pngbin0 -> 229 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_arrow_down.pngbin0 -> 201 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_arrow_top.pngbin0 -> 230 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_arrow_up.pngbin0 -> 201 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_black.pngbin0 -> 211 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_blue.pngbin0 -> 289 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_delete.pngbin0 -> 308 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_disk.pngbin0 -> 483 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_error.pngbin0 -> 454 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_feed.pngbin0 -> 262 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_go.pngbin0 -> 410 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_green.pngbin0 -> 295 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_key.pngbin0 -> 436 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_orange.pngbin0 -> 283 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_picture.pngbin0 -> 470 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_pink.pngbin0 -> 286 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_purple.pngbin0 -> 294 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_red.pngbin0 -> 287 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_star.pngbin0 -> 331 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_toggle_minus.pngbin0 -> 207 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_toggle_plus.pngbin0 -> 209 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_white.pngbin0 -> 201 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_wrench.pngbin0 -> 448 bytes
-rw-r--r--codemirror_ui/images/silk/bullet_yellow.pngbin0 -> 287 bytes
-rw-r--r--codemirror_ui/images/silk/cake.pngbin0 -> 676 bytes
-rw-r--r--codemirror_ui/images/silk/calculator.pngbin0 -> 543 bytes
-rw-r--r--codemirror_ui/images/silk/calculator_add.pngbin0 -> 660 bytes
-rw-r--r--codemirror_ui/images/silk/calculator_delete.pngbin0 -> 692 bytes
-rw-r--r--codemirror_ui/images/silk/calculator_edit.pngbin0 -> 767 bytes
-rw-r--r--codemirror_ui/images/silk/calculator_error.pngbin0 -> 731 bytes
-rw-r--r--codemirror_ui/images/silk/calculator_link.pngbin0 -> 723 bytes
-rw-r--r--codemirror_ui/images/silk/calendar.pngbin0 -> 675 bytes
-rw-r--r--codemirror_ui/images/silk/calendar_add.pngbin0 -> 723 bytes
-rw-r--r--codemirror_ui/images/silk/calendar_delete.pngbin0 -> 742 bytes
-rw-r--r--codemirror_ui/images/silk/calendar_edit.pngbin0 -> 777 bytes
-rw-r--r--codemirror_ui/images/silk/calendar_link.pngbin0 -> 795 bytes
-rw-r--r--codemirror_ui/images/silk/calendar_view_day.pngbin0 -> 572 bytes
-rw-r--r--codemirror_ui/images/silk/calendar_view_month.pngbin0 -> 595 bytes
-rw-r--r--codemirror_ui/images/silk/calendar_view_week.pngbin0 -> 480 bytes
-rw-r--r--codemirror_ui/images/silk/camera.pngbin0 -> 665 bytes
-rw-r--r--codemirror_ui/images/silk/camera_add.pngbin0 -> 800 bytes
-rw-r--r--codemirror_ui/images/silk/camera_delete.pngbin0 -> 797 bytes
-rw-r--r--codemirror_ui/images/silk/camera_edit.pngbin0 -> 872 bytes
-rw-r--r--codemirror_ui/images/silk/camera_error.pngbin0 -> 835 bytes
-rw-r--r--codemirror_ui/images/silk/camera_go.pngbin0 -> 809 bytes
-rw-r--r--codemirror_ui/images/silk/camera_link.pngbin0 -> 839 bytes
-rw-r--r--codemirror_ui/images/silk/camera_small.pngbin0 -> 489 bytes
-rw-r--r--codemirror_ui/images/silk/cancel.pngbin0 -> 587 bytes
-rw-r--r--codemirror_ui/images/silk/car.pngbin0 -> 610 bytes
-rw-r--r--codemirror_ui/images/silk/car_add.pngbin0 -> 677 bytes
-rw-r--r--codemirror_ui/images/silk/car_delete.pngbin0 -> 689 bytes
-rw-r--r--codemirror_ui/images/silk/cart.pngbin0 -> 421 bytes
-rw-r--r--codemirror_ui/images/silk/cart_add.pngbin0 -> 711 bytes
-rw-r--r--codemirror_ui/images/silk/cart_delete.pngbin0 -> 742 bytes
-rw-r--r--codemirror_ui/images/silk/cart_edit.pngbin0 -> 789 bytes
-rw-r--r--codemirror_ui/images/silk/cart_error.pngbin0 -> 790 bytes
-rw-r--r--codemirror_ui/images/silk/cart_go.pngbin0 -> 763 bytes
-rw-r--r--codemirror_ui/images/silk/cart_put.pngbin0 -> 763 bytes
-rw-r--r--codemirror_ui/images/silk/cart_remove.pngbin0 -> 769 bytes
-rw-r--r--codemirror_ui/images/silk/cd.pngbin0 -> 673 bytes
-rw-r--r--codemirror_ui/images/silk/cd_add.pngbin0 -> 758 bytes
-rw-r--r--codemirror_ui/images/silk/cd_burn.pngbin0 -> 756 bytes
-rw-r--r--codemirror_ui/images/silk/cd_delete.pngbin0 -> 767 bytes
-rw-r--r--codemirror_ui/images/silk/cd_edit.pngbin0 -> 790 bytes
-rw-r--r--codemirror_ui/images/silk/cd_eject.pngbin0 -> 786 bytes
-rw-r--r--codemirror_ui/images/silk/cd_go.pngbin0 -> 793 bytes
-rw-r--r--codemirror_ui/images/silk/chart_bar.pngbin0 -> 541 bytes
-rw-r--r--codemirror_ui/images/silk/chart_bar_add.pngbin0 -> 626 bytes
-rw-r--r--codemirror_ui/images/silk/chart_bar_delete.pngbin0 -> 636 bytes
-rw-r--r--codemirror_ui/images/silk/chart_bar_edit.pngbin0 -> 754 bytes
-rw-r--r--codemirror_ui/images/silk/chart_bar_error.pngbin0 -> 671 bytes
-rw-r--r--codemirror_ui/images/silk/chart_bar_link.pngbin0 -> 712 bytes
-rw-r--r--codemirror_ui/images/silk/chart_curve.pngbin0 -> 710 bytes
-rw-r--r--codemirror_ui/images/silk/chart_curve_add.pngbin0 -> 761 bytes
-rw-r--r--codemirror_ui/images/silk/chart_curve_delete.pngbin0 -> 782 bytes
-rw-r--r--codemirror_ui/images/silk/chart_curve_edit.pngbin0 -> 822 bytes
-rw-r--r--codemirror_ui/images/silk/chart_curve_error.pngbin0 -> 837 bytes
-rw-r--r--codemirror_ui/images/silk/chart_curve_go.pngbin0 -> 823 bytes
-rw-r--r--codemirror_ui/images/silk/chart_curve_link.pngbin0 -> 829 bytes
-rw-r--r--codemirror_ui/images/silk/chart_line.pngbin0 -> 526 bytes
-rw-r--r--codemirror_ui/images/silk/chart_line_add.pngbin0 -> 655 bytes
-rw-r--r--codemirror_ui/images/silk/chart_line_delete.pngbin0 -> 675 bytes
-rw-r--r--codemirror_ui/images/silk/chart_line_edit.pngbin0 -> 718 bytes
-rw-r--r--codemirror_ui/images/silk/chart_line_error.pngbin0 -> 741 bytes
-rw-r--r--codemirror_ui/images/silk/chart_line_link.pngbin0 -> 749 bytes
-rw-r--r--codemirror_ui/images/silk/chart_organisation.pngbin0 -> 444 bytes
-rw-r--r--codemirror_ui/images/silk/chart_organisation_add.pngbin0 -> 551 bytes
-rw-r--r--codemirror_ui/images/silk/chart_organisation_delete.pngbin0 -> 563 bytes
-rw-r--r--codemirror_ui/images/silk/chart_pie.pngbin0 -> 918 bytes
-rw-r--r--codemirror_ui/images/silk/chart_pie_add.pngbin0 -> 975 bytes
-rw-r--r--codemirror_ui/images/silk/chart_pie_delete.pngbin0 -> 983 bytes
-rw-r--r--codemirror_ui/images/silk/chart_pie_edit.pngbin0 -> 986 bytes
-rw-r--r--codemirror_ui/images/silk/chart_pie_error.pngbin0 -> 989 bytes
-rw-r--r--codemirror_ui/images/silk/chart_pie_link.pngbin0 -> 1021 bytes
-rw-r--r--codemirror_ui/images/silk/clock.pngbin0 -> 882 bytes
-rw-r--r--codemirror_ui/images/silk/clock_add.pngbin0 -> 925 bytes
-rw-r--r--codemirror_ui/images/silk/clock_delete.pngbin0 -> 952 bytes
-rw-r--r--codemirror_ui/images/silk/clock_edit.pngbin0 -> 967 bytes
-rw-r--r--codemirror_ui/images/silk/clock_error.pngbin0 -> 953 bytes
-rw-r--r--codemirror_ui/images/silk/clock_go.pngbin0 -> 959 bytes
-rw-r--r--codemirror_ui/images/silk/clock_link.pngbin0 -> 961 bytes
-rw-r--r--codemirror_ui/images/silk/clock_pause.pngbin0 -> 927 bytes
-rw-r--r--codemirror_ui/images/silk/clock_play.pngbin0 -> 943 bytes
-rw-r--r--codemirror_ui/images/silk/clock_red.pngbin0 -> 889 bytes
-rw-r--r--codemirror_ui/images/silk/clock_stop.pngbin0 -> 922 bytes
-rw-r--r--codemirror_ui/images/silk/cog.pngbin0 -> 512 bytes
-rw-r--r--codemirror_ui/images/silk/cog_add.pngbin0 -> 814 bytes
-rw-r--r--codemirror_ui/images/silk/cog_delete.pngbin0 -> 847 bytes
-rw-r--r--codemirror_ui/images/silk/cog_edit.pngbin0 -> 865 bytes
-rw-r--r--codemirror_ui/images/silk/cog_error.pngbin0 -> 869 bytes
-rw-r--r--codemirror_ui/images/silk/cog_go.pngbin0 -> 859 bytes
-rw-r--r--codemirror_ui/images/silk/coins.pngbin0 -> 732 bytes
-rw-r--r--codemirror_ui/images/silk/coins_add.pngbin0 -> 789 bytes
-rw-r--r--codemirror_ui/images/silk/coins_delete.pngbin0 -> 775 bytes
-rw-r--r--codemirror_ui/images/silk/color_swatch.pngbin0 -> 209 bytes
-rw-r--r--codemirror_ui/images/silk/color_wheel.pngbin0 -> 892 bytes
-rw-r--r--codemirror_ui/images/silk/comment.pngbin0 -> 413 bytes
-rw-r--r--codemirror_ui/images/silk/comment_add.pngbin0 -> 530 bytes
-rw-r--r--codemirror_ui/images/silk/comment_delete.pngbin0 -> 548 bytes
-rw-r--r--codemirror_ui/images/silk/comment_edit.pngbin0 -> 644 bytes
-rw-r--r--codemirror_ui/images/silk/comments.pngbin0 -> 557 bytes
-rw-r--r--codemirror_ui/images/silk/comments_add.pngbin0 -> 648 bytes
-rw-r--r--codemirror_ui/images/silk/comments_delete.pngbin0 -> 670 bytes
-rw-r--r--codemirror_ui/images/silk/compress.pngbin0 -> 766 bytes
-rw-r--r--codemirror_ui/images/silk/computer.pngbin0 -> 667 bytes
-rw-r--r--codemirror_ui/images/silk/computer_add.pngbin0 -> 781 bytes
-rw-r--r--codemirror_ui/images/silk/computer_delete.pngbin0 -> 775 bytes
-rw-r--r--codemirror_ui/images/silk/computer_edit.pngbin0 -> 792 bytes
-rw-r--r--codemirror_ui/images/silk/computer_error.pngbin0 -> 784 bytes
-rw-r--r--codemirror_ui/images/silk/computer_go.pngbin0 -> 777 bytes
-rw-r--r--codemirror_ui/images/silk/computer_key.pngbin0 -> 771 bytes
-rw-r--r--codemirror_ui/images/silk/computer_link.pngbin0 -> 792 bytes
-rw-r--r--codemirror_ui/images/silk/connect.pngbin0 -> 748 bytes
-rw-r--r--codemirror_ui/images/silk/contrast.pngbin0 -> 434 bytes
-rw-r--r--codemirror_ui/images/silk/contrast_decrease.pngbin0 -> 695 bytes
-rw-r--r--codemirror_ui/images/silk/contrast_high.pngbin0 -> 435 bytes
-rw-r--r--codemirror_ui/images/silk/contrast_increase.pngbin0 -> 717 bytes
-rw-r--r--codemirror_ui/images/silk/contrast_low.pngbin0 -> 421 bytes
-rw-r--r--codemirror_ui/images/silk/control_eject.pngbin0 -> 603 bytes
-rw-r--r--codemirror_ui/images/silk/control_eject_blue.pngbin0 -> 727 bytes
-rw-r--r--codemirror_ui/images/silk/control_end.pngbin0 -> 621 bytes
-rw-r--r--codemirror_ui/images/silk/control_end_blue.pngbin0 -> 737 bytes
-rw-r--r--codemirror_ui/images/silk/control_equalizer.pngbin0 -> 432 bytes
-rw-r--r--codemirror_ui/images/silk/control_equalizer_blue.pngbin0 -> 764 bytes
-rw-r--r--codemirror_ui/images/silk/control_fastforward.pngbin0 -> 607 bytes
-rw-r--r--codemirror_ui/images/silk/control_fastforward_blue.pngbin0 -> 736 bytes
-rw-r--r--codemirror_ui/images/silk/control_pause.pngbin0 -> 598 bytes
-rw-r--r--codemirror_ui/images/silk/control_pause_blue.pngbin0 -> 721 bytes
-rw-r--r--codemirror_ui/images/silk/control_play.pngbin0 -> 592 bytes
-rw-r--r--codemirror_ui/images/silk/control_play_blue.pngbin0 -> 717 bytes
-rw-r--r--codemirror_ui/images/silk/control_repeat.pngbin0 -> 422 bytes
-rw-r--r--codemirror_ui/images/silk/control_repeat_blue.pngbin0 -> 750 bytes
-rw-r--r--codemirror_ui/images/silk/control_rewind.pngbin0 -> 614 bytes
-rw-r--r--codemirror_ui/images/silk/control_rewind_blue.pngbin0 -> 745 bytes
-rw-r--r--codemirror_ui/images/silk/control_start.pngbin0 -> 604 bytes
-rw-r--r--codemirror_ui/images/silk/control_start_blue.pngbin0 -> 720 bytes
-rw-r--r--codemirror_ui/images/silk/control_stop.pngbin0 -> 403 bytes
-rw-r--r--codemirror_ui/images/silk/control_stop_blue.pngbin0 -> 695 bytes
-rw-r--r--codemirror_ui/images/silk/controller.pngbin0 -> 666 bytes
-rw-r--r--codemirror_ui/images/silk/controller_add.pngbin0 -> 759 bytes
-rw-r--r--codemirror_ui/images/silk/controller_delete.pngbin0 -> 770 bytes
-rw-r--r--codemirror_ui/images/silk/controller_error.pngbin0 -> 815 bytes
-rw-r--r--codemirror_ui/images/silk/creditcards.pngbin0 -> 693 bytes
-rw-r--r--codemirror_ui/images/silk/cross.pngbin0 -> 655 bytes
-rw-r--r--codemirror_ui/images/silk/css.pngbin0 -> 524 bytes
-rw-r--r--codemirror_ui/images/silk/css_add.pngbin0 -> 666 bytes
-rw-r--r--codemirror_ui/images/silk/css_delete.pngbin0 -> 654 bytes
-rw-r--r--codemirror_ui/images/silk/css_go.pngbin0 -> 655 bytes
-rw-r--r--codemirror_ui/images/silk/css_valid.pngbin0 -> 661 bytes
-rw-r--r--codemirror_ui/images/silk/cup.pngbin0 -> 633 bytes
-rw-r--r--codemirror_ui/images/silk/cup_add.pngbin0 -> 715 bytes
-rw-r--r--codemirror_ui/images/silk/cup_delete.pngbin0 -> 731 bytes
-rw-r--r--codemirror_ui/images/silk/cup_edit.pngbin0 -> 778 bytes
-rw-r--r--codemirror_ui/images/silk/cup_error.pngbin0 -> 790 bytes
-rw-r--r--codemirror_ui/images/silk/cup_go.pngbin0 -> 780 bytes
-rw-r--r--codemirror_ui/images/silk/cup_key.pngbin0 -> 776 bytes
-rw-r--r--codemirror_ui/images/silk/cup_link.pngbin0 -> 760 bytes
-rw-r--r--codemirror_ui/images/silk/cursor.pngbin0 -> 354 bytes
-rw-r--r--codemirror_ui/images/silk/cut.pngbin0 -> 648 bytes
-rw-r--r--codemirror_ui/images/silk/cut_red.pngbin0 -> 650 bytes
-rw-r--r--codemirror_ui/images/silk/database.pngbin0 -> 390 bytes
-rw-r--r--codemirror_ui/images/silk/database_add.pngbin0 -> 658 bytes
-rw-r--r--codemirror_ui/images/silk/database_connect.pngbin0 -> 763 bytes
-rw-r--r--codemirror_ui/images/silk/database_delete.pngbin0 -> 659 bytes
-rw-r--r--codemirror_ui/images/silk/database_edit.pngbin0 -> 767 bytes
-rw-r--r--codemirror_ui/images/silk/database_error.pngbin0 -> 682 bytes
-rw-r--r--codemirror_ui/images/silk/database_gear.pngbin0 -> 468 bytes
-rw-r--r--codemirror_ui/images/silk/database_go.pngbin0 -> 698 bytes
-rw-r--r--codemirror_ui/images/silk/database_key.pngbin0 -> 764 bytes
-rw-r--r--codemirror_ui/images/silk/database_lightning.pngbin0 -> 775 bytes
-rw-r--r--codemirror_ui/images/silk/database_link.pngbin0 -> 679 bytes
-rw-r--r--codemirror_ui/images/silk/database_refresh.pngbin0 -> 770 bytes
-rw-r--r--codemirror_ui/images/silk/database_save.pngbin0 -> 755 bytes
-rw-r--r--codemirror_ui/images/silk/database_table.pngbin0 -> 726 bytes
-rw-r--r--codemirror_ui/images/silk/date.pngbin0 -> 626 bytes
-rw-r--r--codemirror_ui/images/silk/date_add.pngbin0 -> 703 bytes
-rw-r--r--codemirror_ui/images/silk/date_delete.pngbin0 -> 716 bytes
-rw-r--r--codemirror_ui/images/silk/date_edit.pngbin0 -> 799 bytes
-rw-r--r--codemirror_ui/images/silk/date_error.pngbin0 -> 753 bytes
-rw-r--r--codemirror_ui/images/silk/date_go.pngbin0 -> 753 bytes
-rw-r--r--codemirror_ui/images/silk/date_link.pngbin0 -> 764 bytes
-rw-r--r--codemirror_ui/images/silk/date_magnify.pngbin0 -> 711 bytes
-rw-r--r--codemirror_ui/images/silk/date_next.pngbin0 -> 688 bytes
-rw-r--r--codemirror_ui/images/silk/date_previous.pngbin0 -> 720 bytes
-rw-r--r--codemirror_ui/images/silk/delete.pngbin0 -> 715 bytes
-rw-r--r--codemirror_ui/images/silk/disconnect.pngbin0 -> 796 bytes
-rw-r--r--codemirror_ui/images/silk/disk.pngbin0 -> 620 bytes
-rw-r--r--codemirror_ui/images/silk/disk_multiple.pngbin0 -> 691 bytes
-rw-r--r--codemirror_ui/images/silk/door.pngbin0 -> 412 bytes
-rw-r--r--codemirror_ui/images/silk/door_in.pngbin0 -> 693 bytes
-rw-r--r--codemirror_ui/images/silk/door_open.pngbin0 -> 508 bytes
-rw-r--r--codemirror_ui/images/silk/door_out.pngbin0 -> 688 bytes
-rw-r--r--codemirror_ui/images/silk/drink.pngbin0 -> 692 bytes
-rw-r--r--codemirror_ui/images/silk/drink_empty.pngbin0 -> 433 bytes
-rw-r--r--codemirror_ui/images/silk/drive.pngbin0 -> 346 bytes
-rw-r--r--codemirror_ui/images/silk/drive_add.pngbin0 -> 623 bytes
-rw-r--r--codemirror_ui/images/silk/drive_burn.pngbin0 -> 608 bytes
-rw-r--r--codemirror_ui/images/silk/drive_cd.pngbin0 -> 734 bytes
-rw-r--r--codemirror_ui/images/silk/drive_cd_empty.pngbin0 -> 341 bytes
-rw-r--r--codemirror_ui/images/silk/drive_delete.pngbin0 -> 628 bytes
-rw-r--r--codemirror_ui/images/silk/drive_disk.pngbin0 -> 695 bytes
-rw-r--r--codemirror_ui/images/silk/drive_edit.pngbin0 -> 714 bytes
-rw-r--r--codemirror_ui/images/silk/drive_error.pngbin0 -> 705 bytes
-rw-r--r--codemirror_ui/images/silk/drive_go.pngbin0 -> 661 bytes
-rw-r--r--codemirror_ui/images/silk/drive_key.pngbin0 -> 681 bytes
-rw-r--r--codemirror_ui/images/silk/drive_link.pngbin0 -> 679 bytes
-rw-r--r--codemirror_ui/images/silk/drive_magnify.pngbin0 -> 641 bytes
-rw-r--r--codemirror_ui/images/silk/drive_network.pngbin0 -> 585 bytes
-rw-r--r--codemirror_ui/images/silk/drive_rename.pngbin0 -> 494 bytes
-rw-r--r--codemirror_ui/images/silk/drive_user.pngbin0 -> 712 bytes
-rw-r--r--codemirror_ui/images/silk/drive_web.pngbin0 -> 686 bytes
-rw-r--r--codemirror_ui/images/silk/dvd.pngbin0 -> 764 bytes
-rw-r--r--codemirror_ui/images/silk/dvd_add.pngbin0 -> 788 bytes
-rw-r--r--codemirror_ui/images/silk/dvd_delete.pngbin0 -> 800 bytes
-rw-r--r--codemirror_ui/images/silk/dvd_edit.pngbin0 -> 844 bytes
-rw-r--r--codemirror_ui/images/silk/dvd_error.pngbin0 -> 854 bytes
-rw-r--r--codemirror_ui/images/silk/dvd_go.pngbin0 -> 854 bytes
-rw-r--r--codemirror_ui/images/silk/dvd_key.pngbin0 -> 816 bytes
-rw-r--r--codemirror_ui/images/silk/dvd_link.pngbin0 -> 819 bytes
-rw-r--r--codemirror_ui/images/silk/email.pngbin0 -> 641 bytes
-rw-r--r--codemirror_ui/images/silk/email_add.pngbin0 -> 761 bytes
-rw-r--r--codemirror_ui/images/silk/email_attach.pngbin0 -> 793 bytes
-rw-r--r--codemirror_ui/images/silk/email_delete.pngbin0 -> 756 bytes
-rw-r--r--codemirror_ui/images/silk/email_edit.pngbin0 -> 756 bytes
-rw-r--r--codemirror_ui/images/silk/email_error.pngbin0 -> 792 bytes
-rw-r--r--codemirror_ui/images/silk/email_go.pngbin0 -> 754 bytes
-rw-r--r--codemirror_ui/images/silk/email_link.pngbin0 -> 821 bytes
-rw-r--r--codemirror_ui/images/silk/email_open.pngbin0 -> 783 bytes
-rw-r--r--codemirror_ui/images/silk/email_open_image.pngbin0 -> 811 bytes
-rw-r--r--codemirror_ui/images/silk/emoticon_evilgrin.pngbin0 -> 727 bytes
-rw-r--r--codemirror_ui/images/silk/emoticon_grin.pngbin0 -> 714 bytes
-rw-r--r--codemirror_ui/images/silk/emoticon_happy.pngbin0 -> 731 bytes
-rw-r--r--codemirror_ui/images/silk/emoticon_smile.pngbin0 -> 725 bytes
-rw-r--r--codemirror_ui/images/silk/emoticon_surprised.pngbin0 -> 741 bytes
-rw-r--r--codemirror_ui/images/silk/emoticon_tongue.pngbin0 -> 727 bytes
-rw-r--r--codemirror_ui/images/silk/emoticon_unhappy.pngbin0 -> 723 bytes
-rw-r--r--codemirror_ui/images/silk/emoticon_waii.pngbin0 -> 737 bytes
-rw-r--r--codemirror_ui/images/silk/emoticon_wink.pngbin0 -> 712 bytes
-rw-r--r--codemirror_ui/images/silk/error.pngbin0 -> 666 bytes
-rw-r--r--codemirror_ui/images/silk/error_add.pngbin0 -> 710 bytes
-rw-r--r--codemirror_ui/images/silk/error_delete.pngbin0 -> 729 bytes
-rw-r--r--codemirror_ui/images/silk/error_go.pngbin0 -> 734 bytes
-rw-r--r--codemirror_ui/images/silk/exclamation.pngbin0 -> 701 bytes
-rw-r--r--codemirror_ui/images/silk/eye.pngbin0 -> 750 bytes
-rw-r--r--codemirror_ui/images/silk/feed.pngbin0 -> 691 bytes
-rw-r--r--codemirror_ui/images/silk/feed_add.pngbin0 -> 763 bytes
-rw-r--r--codemirror_ui/images/silk/feed_delete.pngbin0 -> 746 bytes
-rw-r--r--codemirror_ui/images/silk/feed_disk.pngbin0 -> 738 bytes
-rw-r--r--codemirror_ui/images/silk/feed_edit.pngbin0 -> 801 bytes
-rw-r--r--codemirror_ui/images/silk/feed_error.pngbin0 -> 770 bytes
-rw-r--r--codemirror_ui/images/silk/feed_go.pngbin0 -> 761 bytes
-rw-r--r--codemirror_ui/images/silk/feed_key.pngbin0 -> 771 bytes
-rw-r--r--codemirror_ui/images/silk/feed_link.pngbin0 -> 806 bytes
-rw-r--r--codemirror_ui/images/silk/feed_magnify.pngbin0 -> 737 bytes
-rw-r--r--codemirror_ui/images/silk/female.pngbin0 -> 590 bytes
-rw-r--r--codemirror_ui/images/silk/film.pngbin0 -> 653 bytes
-rw-r--r--codemirror_ui/images/silk/film_add.pngbin0 -> 739 bytes
-rw-r--r--codemirror_ui/images/silk/film_delete.pngbin0 -> 730 bytes
-rw-r--r--codemirror_ui/images/silk/film_edit.pngbin0 -> 855 bytes
-rw-r--r--codemirror_ui/images/silk/film_error.pngbin0 -> 800 bytes
-rw-r--r--codemirror_ui/images/silk/film_go.pngbin0 -> 813 bytes
-rw-r--r--codemirror_ui/images/silk/film_key.pngbin0 -> 835 bytes
-rw-r--r--codemirror_ui/images/silk/film_link.pngbin0 -> 830 bytes
-rw-r--r--codemirror_ui/images/silk/film_save.pngbin0 -> 806 bytes
-rw-r--r--codemirror_ui/images/silk/find.pngbin0 -> 659 bytes
-rw-r--r--codemirror_ui/images/silk/flag_blue.pngbin0 -> 671 bytes
-rw-r--r--codemirror_ui/images/silk/flag_green.pngbin0 -> 672 bytes
-rw-r--r--codemirror_ui/images/silk/flag_orange.pngbin0 -> 669 bytes
-rw-r--r--codemirror_ui/images/silk/flag_pink.pngbin0 -> 651 bytes
-rw-r--r--codemirror_ui/images/silk/flag_purple.pngbin0 -> 656 bytes
-rw-r--r--codemirror_ui/images/silk/flag_red.pngbin0 -> 665 bytes
-rw-r--r--codemirror_ui/images/silk/flag_yellow.pngbin0 -> 671 bytes
-rw-r--r--codemirror_ui/images/silk/folder.pngbin0 -> 537 bytes
-rw-r--r--codemirror_ui/images/silk/folder_add.pngbin0 -> 668 bytes
-rw-r--r--codemirror_ui/images/silk/folder_bell.pngbin0 -> 781 bytes
-rw-r--r--codemirror_ui/images/silk/folder_brick.pngbin0 -> 735 bytes
-rw-r--r--codemirror_ui/images/silk/folder_bug.pngbin0 -> 829 bytes
-rw-r--r--codemirror_ui/images/silk/folder_camera.pngbin0 -> 729 bytes
-rw-r--r--codemirror_ui/images/silk/folder_database.pngbin0 -> 687 bytes
-rw-r--r--codemirror_ui/images/silk/folder_delete.pngbin0 -> 666 bytes
-rw-r--r--codemirror_ui/images/silk/folder_edit.pngbin0 -> 733 bytes
-rw-r--r--codemirror_ui/images/silk/folder_error.pngbin0 -> 727 bytes
-rw-r--r--codemirror_ui/images/silk/folder_explore.pngbin0 -> 679 bytes
-rw-r--r--codemirror_ui/images/silk/folder_feed.pngbin0 -> 691 bytes
-rw-r--r--codemirror_ui/images/silk/folder_find.pngbin0 -> 795 bytes
-rw-r--r--codemirror_ui/images/silk/folder_go.pngbin0 -> 694 bytes
-rw-r--r--codemirror_ui/images/silk/folder_heart.pngbin0 -> 741 bytes
-rw-r--r--codemirror_ui/images/silk/folder_image.pngbin0 -> 677 bytes
-rw-r--r--codemirror_ui/images/silk/folder_key.pngbin0 -> 720 bytes
-rw-r--r--codemirror_ui/images/silk/folder_lightbulb.pngbin0 -> 741 bytes
-rw-r--r--codemirror_ui/images/silk/folder_link.pngbin0 -> 785 bytes
-rw-r--r--codemirror_ui/images/silk/folder_magnify.pngbin0 -> 686 bytes
-rw-r--r--codemirror_ui/images/silk/folder_page.pngbin0 -> 688 bytes
-rw-r--r--codemirror_ui/images/silk/folder_page_white.pngbin0 -> 639 bytes
-rw-r--r--codemirror_ui/images/silk/folder_palette.pngbin0 -> 822 bytes
-rw-r--r--codemirror_ui/images/silk/folder_picture.pngbin0 -> 713 bytes
-rw-r--r--codemirror_ui/images/silk/folder_star.pngbin0 -> 755 bytes
-rw-r--r--codemirror_ui/images/silk/folder_table.pngbin0 -> 675 bytes
-rw-r--r--codemirror_ui/images/silk/folder_user.pngbin0 -> 730 bytes
-rw-r--r--codemirror_ui/images/silk/folder_wrench.pngbin0 -> 740 bytes
-rw-r--r--codemirror_ui/images/silk/font.pngbin0 -> 567 bytes
-rw-r--r--codemirror_ui/images/silk/font_add.pngbin0 -> 634 bytes
-rw-r--r--codemirror_ui/images/silk/font_delete.pngbin0 -> 661 bytes
-rw-r--r--codemirror_ui/images/silk/font_go.pngbin0 -> 700 bytes
-rw-r--r--codemirror_ui/images/silk/group.pngbin0 -> 753 bytes
-rw-r--r--codemirror_ui/images/silk/group_add.pngbin0 -> 807 bytes
-rw-r--r--codemirror_ui/images/silk/group_delete.pngbin0 -> 827 bytes
-rw-r--r--codemirror_ui/images/silk/group_edit.pngbin0 -> 785 bytes
-rw-r--r--codemirror_ui/images/silk/group_error.pngbin0 -> 842 bytes
-rw-r--r--codemirror_ui/images/silk/group_gear.pngbin0 -> 824 bytes
-rw-r--r--codemirror_ui/images/silk/group_go.pngbin0 -> 842 bytes
-rw-r--r--codemirror_ui/images/silk/group_key.pngbin0 -> 813 bytes
-rw-r--r--codemirror_ui/images/silk/group_link.pngbin0 -> 858 bytes
-rw-r--r--codemirror_ui/images/silk/heart.pngbin0 -> 749 bytes
-rw-r--r--codemirror_ui/images/silk/heart_add.pngbin0 -> 820 bytes
-rw-r--r--codemirror_ui/images/silk/heart_delete.pngbin0 -> 823 bytes
-rw-r--r--codemirror_ui/images/silk/help.pngbin0 -> 786 bytes
-rw-r--r--codemirror_ui/images/silk/hourglass.pngbin0 -> 744 bytes
-rw-r--r--codemirror_ui/images/silk/hourglass_add.pngbin0 -> 814 bytes
-rw-r--r--codemirror_ui/images/silk/hourglass_delete.pngbin0 -> 829 bytes
-rw-r--r--codemirror_ui/images/silk/hourglass_go.pngbin0 -> 866 bytes
-rw-r--r--codemirror_ui/images/silk/hourglass_link.pngbin0 -> 871 bytes
-rw-r--r--codemirror_ui/images/silk/house.pngbin0 -> 806 bytes
-rw-r--r--codemirror_ui/images/silk/house_go.pngbin0 -> 861 bytes
-rw-r--r--codemirror_ui/images/silk/house_link.pngbin0 -> 868 bytes
-rw-r--r--codemirror_ui/images/silk/html.pngbin0 -> 578 bytes
-rw-r--r--codemirror_ui/images/silk/html_add.pngbin0 -> 698 bytes
-rw-r--r--codemirror_ui/images/silk/html_delete.pngbin0 -> 688 bytes
-rw-r--r--codemirror_ui/images/silk/html_go.pngbin0 -> 692 bytes
-rw-r--r--codemirror_ui/images/silk/html_valid.pngbin0 -> 704 bytes
-rw-r--r--codemirror_ui/images/silk/image.pngbin0 -> 516 bytes
-rw-r--r--codemirror_ui/images/silk/image_add.pngbin0 -> 653 bytes
-rw-r--r--codemirror_ui/images/silk/image_delete.pngbin0 -> 653 bytes
-rw-r--r--codemirror_ui/images/silk/image_edit.pngbin0 -> 783 bytes
-rw-r--r--codemirror_ui/images/silk/image_link.pngbin0 -> 773 bytes
-rw-r--r--codemirror_ui/images/silk/images.pngbin0 -> 661 bytes
-rw-r--r--codemirror_ui/images/silk/information.pngbin0 -> 778 bytes
-rw-r--r--codemirror_ui/images/silk/ipod.pngbin0 -> 463 bytes
-rw-r--r--codemirror_ui/images/silk/ipod_cast.pngbin0 -> 711 bytes
-rw-r--r--codemirror_ui/images/silk/ipod_cast_add.pngbin0 -> 796 bytes
-rw-r--r--codemirror_ui/images/silk/ipod_cast_delete.pngbin0 -> 809 bytes
-rw-r--r--codemirror_ui/images/silk/ipod_sound.pngbin0 -> 678 bytes
-rw-r--r--codemirror_ui/images/silk/joystick.pngbin0 -> 559 bytes
-rw-r--r--codemirror_ui/images/silk/joystick_add.pngbin0 -> 669 bytes
-rw-r--r--codemirror_ui/images/silk/joystick_delete.pngbin0 -> 671 bytes
-rw-r--r--codemirror_ui/images/silk/joystick_error.pngbin0 -> 711 bytes
-rw-r--r--codemirror_ui/images/silk/key.pngbin0 -> 612 bytes
-rw-r--r--codemirror_ui/images/silk/key_add.pngbin0 -> 703 bytes
-rw-r--r--codemirror_ui/images/silk/key_delete.pngbin0 -> 724 bytes
-rw-r--r--codemirror_ui/images/silk/key_go.pngbin0 -> 744 bytes
-rw-r--r--codemirror_ui/images/silk/keyboard.pngbin0 -> 570 bytes
-rw-r--r--codemirror_ui/images/silk/keyboard_add.pngbin0 -> 683 bytes
-rw-r--r--codemirror_ui/images/silk/keyboard_delete.pngbin0 -> 681 bytes
-rw-r--r--codemirror_ui/images/silk/keyboard_magnify.pngbin0 -> 651 bytes
-rw-r--r--codemirror_ui/images/silk/layers.pngbin0 -> 597 bytes
-rw-r--r--codemirror_ui/images/silk/layout.pngbin0 -> 480 bytes
-rw-r--r--codemirror_ui/images/silk/layout_add.pngbin0 -> 577 bytes
-rw-r--r--codemirror_ui/images/silk/layout_content.pngbin0 -> 519 bytes
-rw-r--r--codemirror_ui/images/silk/layout_delete.pngbin0 -> 608 bytes
-rw-r--r--codemirror_ui/images/silk/layout_edit.pngbin0 -> 716 bytes
-rw-r--r--codemirror_ui/images/silk/layout_error.pngbin0 -> 666 bytes
-rw-r--r--codemirror_ui/images/silk/layout_header.pngbin0 -> 500 bytes
-rw-r--r--codemirror_ui/images/silk/layout_link.pngbin0 -> 660 bytes
-rw-r--r--codemirror_ui/images/silk/layout_sidebar.pngbin0 -> 479 bytes
-rw-r--r--codemirror_ui/images/silk/lightbulb.pngbin0 -> 782 bytes
-rw-r--r--codemirror_ui/images/silk/lightbulb_add.pngbin0 -> 839 bytes
-rw-r--r--codemirror_ui/images/silk/lightbulb_delete.pngbin0 -> 857 bytes
-rw-r--r--codemirror_ui/images/silk/lightbulb_off.pngbin0 -> 700 bytes
-rw-r--r--codemirror_ui/images/silk/lightning.pngbin0 -> 634 bytes
-rw-r--r--codemirror_ui/images/silk/lightning_add.pngbin0 -> 746 bytes
-rw-r--r--codemirror_ui/images/silk/lightning_delete.pngbin0 -> 745 bytes
-rw-r--r--codemirror_ui/images/silk/lightning_go.pngbin0 -> 739 bytes
-rw-r--r--codemirror_ui/images/silk/link.pngbin0 -> 343 bytes
-rw-r--r--codemirror_ui/images/silk/link_add.pngbin0 -> 570 bytes
-rw-r--r--codemirror_ui/images/silk/link_break.pngbin0 -> 657 bytes
-rw-r--r--codemirror_ui/images/silk/link_delete.pngbin0 -> 600 bytes
-rw-r--r--codemirror_ui/images/silk/link_edit.pngbin0 -> 703 bytes
-rw-r--r--codemirror_ui/images/silk/link_error.pngbin0 -> 698 bytes
-rw-r--r--codemirror_ui/images/silk/link_go.pngbin0 -> 655 bytes
-rw-r--r--codemirror_ui/images/silk/lock.pngbin0 -> 749 bytes
-rw-r--r--codemirror_ui/images/silk/lock_add.pngbin0 -> 824 bytes
-rw-r--r--codemirror_ui/images/silk/lock_break.pngbin0 -> 771 bytes
-rw-r--r--codemirror_ui/images/silk/lock_delete.pngbin0 -> 815 bytes
-rw-r--r--codemirror_ui/images/silk/lock_edit.pngbin0 -> 861 bytes
-rw-r--r--codemirror_ui/images/silk/lock_go.pngbin0 -> 829 bytes
-rw-r--r--codemirror_ui/images/silk/lock_open.pngbin0 -> 727 bytes
-rw-r--r--codemirror_ui/images/silk/lorry.pngbin0 -> 582 bytes
-rw-r--r--codemirror_ui/images/silk/lorry_add.pngbin0 -> 689 bytes
-rw-r--r--codemirror_ui/images/silk/lorry_delete.pngbin0 -> 683 bytes
-rw-r--r--codemirror_ui/images/silk/lorry_error.pngbin0 -> 739 bytes
-rw-r--r--codemirror_ui/images/silk/lorry_flatbed.pngbin0 -> 450 bytes
-rw-r--r--codemirror_ui/images/silk/lorry_go.pngbin0 -> 699 bytes
-rw-r--r--codemirror_ui/images/silk/lorry_link.pngbin0 -> 775 bytes
-rw-r--r--codemirror_ui/images/silk/magifier_zoom_out.pngbin0 -> 657 bytes
-rw-r--r--codemirror_ui/images/silk/magnifier.pngbin0 -> 615 bytes
-rw-r--r--codemirror_ui/images/silk/magnifier_zoom_in.pngbin0 -> 680 bytes
-rw-r--r--codemirror_ui/images/silk/male.pngbin0 -> 629 bytes
-rw-r--r--codemirror_ui/images/silk/map.pngbin0 -> 804 bytes
-rw-r--r--codemirror_ui/images/silk/map_add.pngbin0 -> 836 bytes
-rw-r--r--codemirror_ui/images/silk/map_delete.pngbin0 -> 835 bytes
-rw-r--r--codemirror_ui/images/silk/map_edit.pngbin0 -> 876 bytes
-rw-r--r--codemirror_ui/images/silk/map_go.pngbin0 -> 842 bytes
-rw-r--r--codemirror_ui/images/silk/map_magnify.pngbin0 -> 797 bytes
-rw-r--r--codemirror_ui/images/silk/medal_bronze_1.pngbin0 -> 640 bytes
-rw-r--r--codemirror_ui/images/silk/medal_bronze_2.pngbin0 -> 654 bytes
-rw-r--r--codemirror_ui/images/silk/medal_bronze_3.pngbin0 -> 646 bytes
-rw-r--r--codemirror_ui/images/silk/medal_bronze_add.pngbin0 -> 747 bytes
-rw-r--r--codemirror_ui/images/silk/medal_bronze_delete.pngbin0 -> 730 bytes
-rw-r--r--codemirror_ui/images/silk/medal_gold_1.pngbin0 -> 629 bytes
-rw-r--r--codemirror_ui/images/silk/medal_gold_2.pngbin0 -> 641 bytes
-rw-r--r--codemirror_ui/images/silk/medal_gold_3.pngbin0 -> 634 bytes
-rw-r--r--codemirror_ui/images/silk/medal_gold_add.pngbin0 -> 733 bytes
-rw-r--r--codemirror_ui/images/silk/medal_gold_delete.pngbin0 -> 724 bytes
-rw-r--r--codemirror_ui/images/silk/medal_silver_1.pngbin0 -> 589 bytes
-rw-r--r--codemirror_ui/images/silk/medal_silver_2.pngbin0 -> 600 bytes
-rw-r--r--codemirror_ui/images/silk/medal_silver_3.pngbin0 -> 597 bytes
-rw-r--r--codemirror_ui/images/silk/medal_silver_add.pngbin0 -> 727 bytes
-rw-r--r--codemirror_ui/images/silk/medal_silver_delete.pngbin0 -> 714 bytes
-rw-r--r--codemirror_ui/images/silk/money.pngbin0 -> 738 bytes
-rw-r--r--codemirror_ui/images/silk/money_add.pngbin0 -> 784 bytes
-rw-r--r--codemirror_ui/images/silk/money_delete.pngbin0 -> 806 bytes
-rw-r--r--codemirror_ui/images/silk/money_dollar.pngbin0 -> 630 bytes
-rw-r--r--codemirror_ui/images/silk/money_euro.pngbin0 -> 605 bytes
-rw-r--r--codemirror_ui/images/silk/money_pound.pngbin0 -> 565 bytes
-rw-r--r--codemirror_ui/images/silk/money_yen.pngbin0 -> 562 bytes
-rw-r--r--codemirror_ui/images/silk/monitor.pngbin0 -> 612 bytes
-rw-r--r--codemirror_ui/images/silk/monitor_add.pngbin0 -> 692 bytes
-rw-r--r--codemirror_ui/images/silk/monitor_delete.pngbin0 -> 691 bytes
-rw-r--r--codemirror_ui/images/silk/monitor_edit.pngbin0 -> 769 bytes
-rw-r--r--codemirror_ui/images/silk/monitor_error.pngbin0 -> 714 bytes
-rw-r--r--codemirror_ui/images/silk/monitor_go.pngbin0 -> 696 bytes
-rw-r--r--codemirror_ui/images/silk/monitor_lightning.pngbin0 -> 768 bytes
-rw-r--r--codemirror_ui/images/silk/monitor_link.pngbin0 -> 736 bytes
-rw-r--r--codemirror_ui/images/silk/mouse.pngbin0 -> 634 bytes
-rw-r--r--codemirror_ui/images/silk/mouse_add.pngbin0 -> 729 bytes
-rw-r--r--codemirror_ui/images/silk/mouse_delete.pngbin0 -> 741 bytes
-rw-r--r--codemirror_ui/images/silk/mouse_error.pngbin0 -> 790 bytes
-rw-r--r--codemirror_ui/images/silk/music.pngbin0 -> 385 bytes
-rw-r--r--codemirror_ui/images/silk/new.pngbin0 -> 378 bytes
-rw-r--r--codemirror_ui/images/silk/newspaper.pngbin0 -> 658 bytes
-rw-r--r--codemirror_ui/images/silk/newspaper_add.pngbin0 -> 750 bytes
-rw-r--r--codemirror_ui/images/silk/newspaper_delete.pngbin0 -> 775 bytes
-rw-r--r--codemirror_ui/images/silk/newspaper_go.pngbin0 -> 779 bytes
-rw-r--r--codemirror_ui/images/silk/newspaper_link.pngbin0 -> 787 bytes
-rw-r--r--codemirror_ui/images/silk/note.pngbin0 -> 500 bytes
-rw-r--r--codemirror_ui/images/silk/note_add.pngbin0 -> 641 bytes
-rw-r--r--codemirror_ui/images/silk/note_delete.pngbin0 -> 631 bytes
-rw-r--r--codemirror_ui/images/silk/note_edit.pngbin0 -> 731 bytes
-rw-r--r--codemirror_ui/images/silk/note_error.pngbin0 -> 680 bytes
-rw-r--r--codemirror_ui/images/silk/note_go.pngbin0 -> 661 bytes
-rw-r--r--codemirror_ui/images/silk/overlays.pngbin0 -> 716 bytes
-rw-r--r--codemirror_ui/images/silk/package.pngbin0 -> 853 bytes
-rw-r--r--codemirror_ui/images/silk/package_add.pngbin0 -> 899 bytes
-rw-r--r--codemirror_ui/images/silk/package_delete.pngbin0 -> 891 bytes
-rw-r--r--codemirror_ui/images/silk/package_go.pngbin0 -> 898 bytes
-rw-r--r--codemirror_ui/images/silk/package_green.pngbin0 -> 896 bytes
-rw-r--r--codemirror_ui/images/silk/package_link.pngbin0 -> 939 bytes
-rw-r--r--codemirror_ui/images/silk/page.pngbin0 -> 635 bytes
-rw-r--r--codemirror_ui/images/silk/page_add.pngbin0 -> 739 bytes
-rw-r--r--codemirror_ui/images/silk/page_attach.pngbin0 -> 794 bytes
-rw-r--r--codemirror_ui/images/silk/page_code.pngbin0 -> 818 bytes
-rw-r--r--codemirror_ui/images/silk/page_copy.pngbin0 -> 663 bytes
-rw-r--r--codemirror_ui/images/silk/page_delete.pngbin0 -> 740 bytes
-rw-r--r--codemirror_ui/images/silk/page_edit.pngbin0 -> 807 bytes
-rw-r--r--codemirror_ui/images/silk/page_error.pngbin0 -> 793 bytes
-rw-r--r--codemirror_ui/images/silk/page_excel.pngbin0 -> 817 bytes
-rw-r--r--codemirror_ui/images/silk/page_find.pngbin0 -> 879 bytes
-rw-r--r--codemirror_ui/images/silk/page_gear.pngbin0 -> 833 bytes
-rw-r--r--codemirror_ui/images/silk/page_go.pngbin0 -> 779 bytes
-rw-r--r--codemirror_ui/images/silk/page_green.pngbin0 -> 621 bytes
-rw-r--r--codemirror_ui/images/silk/page_key.pngbin0 -> 801 bytes
-rw-r--r--codemirror_ui/images/silk/page_lightning.pngbin0 -> 839 bytes
-rw-r--r--codemirror_ui/images/silk/page_link.pngbin0 -> 830 bytes
-rw-r--r--codemirror_ui/images/silk/page_paintbrush.pngbin0 -> 813 bytes
-rw-r--r--codemirror_ui/images/silk/page_paste.pngbin0 -> 703 bytes
-rw-r--r--codemirror_ui/images/silk/page_red.pngbin0 -> 641 bytes
-rw-r--r--codemirror_ui/images/silk/page_refresh.pngbin0 -> 858 bytes
-rw-r--r--codemirror_ui/images/silk/page_save.pngbin0 -> 774 bytes
-rw-r--r--codemirror_ui/images/silk/page_white.pngbin0 -> 294 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_acrobat.pngbin0 -> 591 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_actionscript.pngbin0 -> 664 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_add.pngbin0 -> 512 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_c.pngbin0 -> 587 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_camera.pngbin0 -> 656 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_cd.pngbin0 -> 666 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_code.pngbin0 -> 603 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_code_red.pngbin0 -> 587 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_coldfusion.pngbin0 -> 592 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_compressed.pngbin0 -> 724 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_copy.pngbin0 -> 309 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_cplusplus.pngbin0 -> 621 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_csharp.pngbin0 -> 700 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_cup.pngbin0 -> 639 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_database.pngbin0 -> 579 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_delete.pngbin0 -> 536 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_dvd.pngbin0 -> 638 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_edit.pngbin0 -> 618 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_error.pngbin0 -> 623 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_excel.pngbin0 -> 663 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_find.pngbin0 -> 676 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_flash.pngbin0 -> 582 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_freehand.pngbin0 -> 639 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_gear.pngbin0 -> 402 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_get.pngbin0 -> 516 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_go.pngbin0 -> 612 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_h.pngbin0 -> 603 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_horizontal.pngbin0 -> 296 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_key.pngbin0 -> 616 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_lightning.pngbin0 -> 669 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_link.pngbin0 -> 614 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_magnify.pngbin0 -> 554 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_medal.pngbin0 -> 706 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_office.pngbin0 -> 779 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_paint.pngbin0 -> 688 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_paintbrush.pngbin0 -> 618 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_paste.pngbin0 -> 620 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_php.pngbin0 -> 538 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_picture.pngbin0 -> 650 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_powerpoint.pngbin0 -> 588 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_put.pngbin0 -> 523 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_ruby.pngbin0 -> 626 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_stack.pngbin0 -> 317 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_star.pngbin0 -> 565 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_swoosh.pngbin0 -> 634 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_text.pngbin0 -> 342 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_text_width.pngbin0 -> 315 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_tux.pngbin0 -> 668 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_vector.pngbin0 -> 644 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_visualstudio.pngbin0 -> 702 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_width.pngbin0 -> 309 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_word.pngbin0 -> 651 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_world.pngbin0 -> 734 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_wrench.pngbin0 -> 613 bytes
-rw-r--r--codemirror_ui/images/silk/page_white_zip.pngbin0 -> 386 bytes
-rw-r--r--codemirror_ui/images/silk/page_word.pngbin0 -> 777 bytes
-rw-r--r--codemirror_ui/images/silk/page_world.pngbin0 -> 903 bytes
-rw-r--r--codemirror_ui/images/silk/paintbrush.pngbin0 -> 548 bytes
-rw-r--r--codemirror_ui/images/silk/paintcan.pngbin0 -> 707 bytes
-rw-r--r--codemirror_ui/images/silk/palette.pngbin0 -> 856 bytes
-rw-r--r--codemirror_ui/images/silk/paste_plain.pngbin0 -> 605 bytes
-rw-r--r--codemirror_ui/images/silk/paste_word.pngbin0 -> 701 bytes
-rw-r--r--codemirror_ui/images/silk/pencil.pngbin0 -> 450 bytes
-rw-r--r--codemirror_ui/images/silk/pencil_add.pngbin0 -> 589 bytes
-rw-r--r--codemirror_ui/images/silk/pencil_delete.pngbin0 -> 603 bytes
-rw-r--r--codemirror_ui/images/silk/pencil_go.pngbin0 -> 666 bytes
-rw-r--r--codemirror_ui/images/silk/phone.pngbin0 -> 488 bytes
-rw-r--r--codemirror_ui/images/silk/phone_add.pngbin0 -> 621 bytes
-rw-r--r--codemirror_ui/images/silk/phone_delete.pngbin0 -> 615 bytes
-rw-r--r--codemirror_ui/images/silk/phone_sound.pngbin0 -> 703 bytes
-rw-r--r--codemirror_ui/images/silk/photo.pngbin0 -> 589 bytes
-rw-r--r--codemirror_ui/images/silk/photo_add.pngbin0 -> 707 bytes
-rw-r--r--codemirror_ui/images/silk/photo_delete.pngbin0 -> 703 bytes
-rw-r--r--codemirror_ui/images/silk/photo_link.pngbin0 -> 784 bytes
-rw-r--r--codemirror_ui/images/silk/photos.pngbin0 -> 647 bytes
-rw-r--r--codemirror_ui/images/silk/picture.pngbin0 -> 606 bytes
-rw-r--r--codemirror_ui/images/silk/picture_add.pngbin0 -> 745 bytes
-rw-r--r--codemirror_ui/images/silk/picture_delete.pngbin0 -> 744 bytes
-rw-r--r--codemirror_ui/images/silk/picture_edit.pngbin0 -> 826 bytes
-rw-r--r--codemirror_ui/images/silk/picture_empty.pngbin0 -> 463 bytes
-rw-r--r--codemirror_ui/images/silk/picture_error.pngbin0 -> 755 bytes
-rw-r--r--codemirror_ui/images/silk/picture_go.pngbin0 -> 758 bytes
-rw-r--r--codemirror_ui/images/silk/picture_key.pngbin0 -> 794 bytes
-rw-r--r--codemirror_ui/images/silk/picture_link.pngbin0 -> 835 bytes
-rw-r--r--codemirror_ui/images/silk/picture_save.pngbin0 -> 755 bytes
-rw-r--r--codemirror_ui/images/silk/pictures.pngbin0 -> 704 bytes
-rw-r--r--codemirror_ui/images/silk/pilcrow.pngbin0 -> 361 bytes
-rw-r--r--codemirror_ui/images/silk/pill.pngbin0 -> 719 bytes
-rw-r--r--codemirror_ui/images/silk/pill_add.pngbin0 -> 797 bytes
-rw-r--r--codemirror_ui/images/silk/pill_delete.pngbin0 -> 805 bytes
-rw-r--r--codemirror_ui/images/silk/pill_go.pngbin0 -> 817 bytes
-rw-r--r--codemirror_ui/images/silk/plugin.pngbin0 -> 591 bytes
-rw-r--r--codemirror_ui/images/silk/plugin_add.pngbin0 -> 691 bytes
-rw-r--r--codemirror_ui/images/silk/plugin_delete.pngbin0 -> 692 bytes
-rw-r--r--codemirror_ui/images/silk/plugin_disabled.pngbin0 -> 347 bytes
-rw-r--r--codemirror_ui/images/silk/plugin_edit.pngbin0 -> 746 bytes
-rw-r--r--codemirror_ui/images/silk/plugin_error.pngbin0 -> 702 bytes
-rw-r--r--codemirror_ui/images/silk/plugin_go.pngbin0 -> 694 bytes
-rw-r--r--codemirror_ui/images/silk/plugin_link.pngbin0 -> 759 bytes
-rw-r--r--codemirror_ui/images/silk/printer.pngbin0 -> 731 bytes
-rw-r--r--codemirror_ui/images/silk/printer_add.pngbin0 -> 782 bytes
-rw-r--r--codemirror_ui/images/silk/printer_delete.pngbin0 -> 792 bytes
-rw-r--r--codemirror_ui/images/silk/printer_empty.pngbin0 -> 350 bytes
-rw-r--r--codemirror_ui/images/silk/printer_error.pngbin0 -> 854 bytes
-rw-r--r--codemirror_ui/images/silk/rainbow.pngbin0 -> 655 bytes
-rw-r--r--codemirror_ui/images/silk/report.pngbin0 -> 649 bytes
-rw-r--r--codemirror_ui/images/silk/report_add.pngbin0 -> 714 bytes
-rw-r--r--codemirror_ui/images/silk/report_delete.pngbin0 -> 729 bytes
-rw-r--r--codemirror_ui/images/silk/report_disk.pngbin0 -> 760 bytes
-rw-r--r--codemirror_ui/images/silk/report_edit.pngbin0 -> 762 bytes
-rw-r--r--codemirror_ui/images/silk/report_go.pngbin0 -> 756 bytes
-rw-r--r--codemirror_ui/images/silk/report_key.pngbin0 -> 760 bytes
-rw-r--r--codemirror_ui/images/silk/report_link.pngbin0 -> 754 bytes
-rw-r--r--codemirror_ui/images/silk/report_magnify.pngbin0 -> 738 bytes
-rw-r--r--codemirror_ui/images/silk/report_picture.pngbin0 -> 733 bytes
-rw-r--r--codemirror_ui/images/silk/report_user.pngbin0 -> 785 bytes
-rw-r--r--codemirror_ui/images/silk/report_word.pngbin0 -> 731 bytes
-rw-r--r--codemirror_ui/images/silk/resultset_first.pngbin0 -> 522 bytes
-rw-r--r--codemirror_ui/images/silk/resultset_last.pngbin0 -> 524 bytes
-rw-r--r--codemirror_ui/images/silk/resultset_next.pngbin0 -> 395 bytes
-rw-r--r--codemirror_ui/images/silk/resultset_previous.pngbin0 -> 389 bytes
-rw-r--r--codemirror_ui/images/silk/rosette.pngbin0 -> 673 bytes
-rw-r--r--codemirror_ui/images/silk/rss.pngbin0 -> 530 bytes
-rw-r--r--codemirror_ui/images/silk/rss_add.pngbin0 -> 649 bytes
-rw-r--r--codemirror_ui/images/silk/rss_delete.pngbin0 -> 633 bytes
-rw-r--r--codemirror_ui/images/silk/rss_go.pngbin0 -> 635 bytes
-rw-r--r--codemirror_ui/images/silk/rss_valid.pngbin0 -> 660 bytes
-rw-r--r--codemirror_ui/images/silk/ruby.pngbin0 -> 592 bytes
-rw-r--r--codemirror_ui/images/silk/ruby_add.pngbin0 -> 691 bytes
-rw-r--r--codemirror_ui/images/silk/ruby_delete.pngbin0 -> 704 bytes
-rw-r--r--codemirror_ui/images/silk/ruby_gear.pngbin0 -> 716 bytes
-rw-r--r--codemirror_ui/images/silk/ruby_get.pngbin0 -> 692 bytes
-rw-r--r--codemirror_ui/images/silk/ruby_go.pngbin0 -> 720 bytes
-rw-r--r--codemirror_ui/images/silk/ruby_key.pngbin0 -> 732 bytes
-rw-r--r--codemirror_ui/images/silk/ruby_link.pngbin0 -> 767 bytes
-rw-r--r--codemirror_ui/images/silk/ruby_put.pngbin0 -> 694 bytes
-rw-r--r--codemirror_ui/images/silk/script.pngbin0 -> 748 bytes
-rw-r--r--codemirror_ui/images/silk/script_add.pngbin0 -> 811 bytes
-rw-r--r--codemirror_ui/images/silk/script_code.pngbin0 -> 859 bytes
-rw-r--r--codemirror_ui/images/silk/script_code_red.pngbin0 -> 868 bytes
-rw-r--r--codemirror_ui/images/silk/script_delete.pngbin0 -> 811 bytes
-rw-r--r--codemirror_ui/images/silk/script_edit.pngbin0 -> 880 bytes
-rw-r--r--codemirror_ui/images/silk/script_error.pngbin0 -> 861 bytes
-rw-r--r--codemirror_ui/images/silk/script_gear.pngbin0 -> 861 bytes
-rw-r--r--codemirror_ui/images/silk/script_go.pngbin0 -> 839 bytes
-rw-r--r--codemirror_ui/images/silk/script_key.pngbin0 -> 853 bytes
-rw-r--r--codemirror_ui/images/silk/script_lightning.pngbin0 -> 879 bytes
-rw-r--r--codemirror_ui/images/silk/script_link.pngbin0 -> 876 bytes
-rw-r--r--codemirror_ui/images/silk/script_palette.pngbin0 -> 917 bytes
-rw-r--r--codemirror_ui/images/silk/script_save.pngbin0 -> 804 bytes
-rw-r--r--codemirror_ui/images/silk/server.pngbin0 -> 530 bytes
-rw-r--r--codemirror_ui/images/silk/server_add.pngbin0 -> 676 bytes
-rw-r--r--codemirror_ui/images/silk/server_chart.pngbin0 -> 673 bytes
-rw-r--r--codemirror_ui/images/silk/server_compressed.pngbin0 -> 721 bytes
-rw-r--r--codemirror_ui/images/silk/server_connect.pngbin0 -> 755 bytes
-rw-r--r--codemirror_ui/images/silk/server_database.pngbin0 -> 666 bytes
-rw-r--r--codemirror_ui/images/silk/server_delete.pngbin0 -> 668 bytes
-rw-r--r--codemirror_ui/images/silk/server_edit.pngbin0 -> 749 bytes
-rw-r--r--codemirror_ui/images/silk/server_error.pngbin0 -> 678 bytes
-rw-r--r--codemirror_ui/images/silk/server_go.pngbin0 -> 706 bytes
-rw-r--r--codemirror_ui/images/silk/server_key.pngbin0 -> 746 bytes
-rw-r--r--codemirror_ui/images/silk/server_lightning.pngbin0 -> 729 bytes
-rw-r--r--codemirror_ui/images/silk/server_link.pngbin0 -> 706 bytes
-rw-r--r--codemirror_ui/images/silk/server_uncompressed.pngbin0 -> 669 bytes
-rw-r--r--codemirror_ui/images/silk/shading.pngbin0 -> 225 bytes
-rw-r--r--codemirror_ui/images/silk/shape_align_bottom.pngbin0 -> 398 bytes
-rw-r--r--codemirror_ui/images/silk/shape_align_center.pngbin0 -> 384 bytes
-rw-r--r--codemirror_ui/images/silk/shape_align_left.pngbin0 -> 402 bytes
-rw-r--r--codemirror_ui/images/silk/shape_align_middle.pngbin0 -> 414 bytes
-rw-r--r--codemirror_ui/images/silk/shape_align_right.pngbin0 -> 401 bytes
-rw-r--r--codemirror_ui/images/silk/shape_align_top.pngbin0 -> 406 bytes
-rw-r--r--codemirror_ui/images/silk/shape_flip_horizontal.pngbin0 -> 403 bytes
-rw-r--r--codemirror_ui/images/silk/shape_flip_vertical.pngbin0 -> 418 bytes
-rw-r--r--codemirror_ui/images/silk/shape_group.pngbin0 -> 553 bytes
-rw-r--r--codemirror_ui/images/silk/shape_handles.pngbin0 -> 538 bytes
-rw-r--r--codemirror_ui/images/silk/shape_move_back.pngbin0 -> 395 bytes
-rw-r--r--codemirror_ui/images/silk/shape_move_backwards.pngbin0 -> 358 bytes
-rw-r--r--codemirror_ui/images/silk/shape_move_forwards.pngbin0 -> 381 bytes
-rw-r--r--codemirror_ui/images/silk/shape_move_front.pngbin0 -> 435 bytes
-rw-r--r--codemirror_ui/images/silk/shape_rotate_anticlockwise.pngbin0 -> 657 bytes
-rw-r--r--codemirror_ui/images/silk/shape_rotate_clockwise.pngbin0 -> 673 bytes
-rw-r--r--codemirror_ui/images/silk/shape_square.pngbin0 -> 353 bytes
-rw-r--r--codemirror_ui/images/silk/shape_square_add.pngbin0 -> 539 bytes
-rw-r--r--codemirror_ui/images/silk/shape_square_delete.pngbin0 -> 537 bytes
-rw-r--r--codemirror_ui/images/silk/shape_square_edit.pngbin0 -> 660 bytes
-rw-r--r--codemirror_ui/images/silk/shape_square_error.pngbin0 -> 570 bytes
-rw-r--r--codemirror_ui/images/silk/shape_square_go.pngbin0 -> 566 bytes
-rw-r--r--codemirror_ui/images/silk/shape_square_key.pngbin0 -> 607 bytes
-rw-r--r--codemirror_ui/images/silk/shape_square_link.pngbin0 -> 642 bytes
-rw-r--r--codemirror_ui/images/silk/shape_ungroup.pngbin0 -> 666 bytes
-rw-r--r--codemirror_ui/images/silk/shield.pngbin0 -> 702 bytes
-rw-r--r--codemirror_ui/images/silk/shield_add.pngbin0 -> 758 bytes
-rw-r--r--codemirror_ui/images/silk/shield_delete.pngbin0 -> 768 bytes
-rw-r--r--codemirror_ui/images/silk/shield_go.pngbin0 -> 775 bytes
-rw-r--r--codemirror_ui/images/silk/sitemap.pngbin0 -> 278 bytes
-rw-r--r--codemirror_ui/images/silk/sitemap_color.pngbin0 -> 406 bytes
-rw-r--r--codemirror_ui/images/silk/sound.pngbin0 -> 610 bytes
-rw-r--r--codemirror_ui/images/silk/sound_add.pngbin0 -> 684 bytes
-rw-r--r--codemirror_ui/images/silk/sound_delete.pngbin0 -> 711 bytes
-rw-r--r--codemirror_ui/images/silk/sound_low.pngbin0 -> 524 bytes
-rw-r--r--codemirror_ui/images/silk/sound_mute.pngbin0 -> 474 bytes
-rw-r--r--codemirror_ui/images/silk/sound_none.pngbin0 -> 417 bytes
-rw-r--r--codemirror_ui/images/silk/spellcheck.pngbin0 -> 603 bytes
-rw-r--r--codemirror_ui/images/silk/sport_8ball.pngbin0 -> 490 bytes
-rw-r--r--codemirror_ui/images/silk/sport_basketball.pngbin0 -> 977 bytes
-rw-r--r--codemirror_ui/images/silk/sport_football.pngbin0 -> 875 bytes
-rw-r--r--codemirror_ui/images/silk/sport_golf.pngbin0 -> 504 bytes
-rw-r--r--codemirror_ui/images/silk/sport_raquet.pngbin0 -> 719 bytes
-rw-r--r--codemirror_ui/images/silk/sport_shuttlecock.pngbin0 -> 683 bytes
-rw-r--r--codemirror_ui/images/silk/sport_soccer.pngbin0 -> 517 bytes
-rw-r--r--codemirror_ui/images/silk/sport_tennis.pngbin0 -> 884 bytes
-rw-r--r--codemirror_ui/images/silk/star.pngbin0 -> 670 bytes
-rw-r--r--codemirror_ui/images/silk/status_away.pngbin0 -> 794 bytes
-rw-r--r--codemirror_ui/images/silk/status_busy.pngbin0 -> 751 bytes
-rw-r--r--codemirror_ui/images/silk/status_offline.pngbin0 -> 422 bytes
-rw-r--r--codemirror_ui/images/silk/status_online.pngbin0 -> 722 bytes
-rw-r--r--codemirror_ui/images/silk/stop.pngbin0 -> 700 bytes
-rw-r--r--codemirror_ui/images/silk/style.pngbin0 -> 813 bytes
-rw-r--r--codemirror_ui/images/silk/style_add.pngbin0 -> 844 bytes
-rw-r--r--codemirror_ui/images/silk/style_delete.pngbin0 -> 865 bytes
-rw-r--r--codemirror_ui/images/silk/style_edit.pngbin0 -> 927 bytes
-rw-r--r--codemirror_ui/images/silk/style_go.pngbin0 -> 862 bytes
-rw-r--r--codemirror_ui/images/silk/sum.pngbin0 -> 289 bytes
-rw-r--r--codemirror_ui/images/silk/tab.pngbin0 -> 323 bytes
-rw-r--r--codemirror_ui/images/silk/tab_add.pngbin0 -> 488 bytes
-rw-r--r--codemirror_ui/images/silk/tab_delete.pngbin0 -> 493 bytes
-rw-r--r--codemirror_ui/images/silk/tab_edit.pngbin0 -> 580 bytes
-rw-r--r--codemirror_ui/images/silk/tab_go.pngbin0 -> 552 bytes
-rw-r--r--codemirror_ui/images/silk/table.pngbin0 -> 566 bytes
-rw-r--r--codemirror_ui/images/silk/table_add.pngbin0 -> 663 bytes
-rw-r--r--codemirror_ui/images/silk/table_delete.pngbin0 -> 660 bytes
-rw-r--r--codemirror_ui/images/silk/table_edit.pngbin0 -> 744 bytes
-rw-r--r--codemirror_ui/images/silk/table_error.pngbin0 -> 687 bytes
-rw-r--r--codemirror_ui/images/silk/table_gear.pngbin0 -> 714 bytes
-rw-r--r--codemirror_ui/images/silk/table_go.pngbin0 -> 683 bytes
-rw-r--r--codemirror_ui/images/silk/table_key.pngbin0 -> 746 bytes
-rw-r--r--codemirror_ui/images/silk/table_lightning.pngbin0 -> 736 bytes
-rw-r--r--codemirror_ui/images/silk/table_link.pngbin0 -> 728 bytes
-rw-r--r--codemirror_ui/images/silk/table_multiple.pngbin0 -> 612 bytes
-rw-r--r--codemirror_ui/images/silk/table_refresh.pngbin0 -> 795 bytes
-rw-r--r--codemirror_ui/images/silk/table_relationship.pngbin0 -> 663 bytes
-rw-r--r--codemirror_ui/images/silk/table_row_delete.pngbin0 -> 629 bytes
-rw-r--r--codemirror_ui/images/silk/table_row_insert.pngbin0 -> 641 bytes
-rw-r--r--codemirror_ui/images/silk/table_save.pngbin0 -> 723 bytes
-rw-r--r--codemirror_ui/images/silk/table_sort.pngbin0 -> 678 bytes
-rw-r--r--codemirror_ui/images/silk/tag.pngbin0 -> 389 bytes
-rw-r--r--codemirror_ui/images/silk/tag_blue.pngbin0 -> 586 bytes
-rw-r--r--codemirror_ui/images/silk/tag_blue_add.pngbin0 -> 671 bytes
-rw-r--r--codemirror_ui/images/silk/tag_blue_delete.pngbin0 -> 701 bytes
-rw-r--r--codemirror_ui/images/silk/tag_blue_edit.pngbin0 -> 748 bytes
-rw-r--r--codemirror_ui/images/silk/tag_green.pngbin0 -> 613 bytes
-rw-r--r--codemirror_ui/images/silk/tag_orange.pngbin0 -> 586 bytes
-rw-r--r--codemirror_ui/images/silk/tag_pink.pngbin0 -> 579 bytes
-rw-r--r--codemirror_ui/images/silk/tag_purple.pngbin0 -> 599 bytes
-rw-r--r--codemirror_ui/images/silk/tag_red.pngbin0 -> 592 bytes
-rw-r--r--codemirror_ui/images/silk/tag_yellow.pngbin0 -> 586 bytes
-rw-r--r--codemirror_ui/images/silk/telephone.pngbin0 -> 791 bytes
-rw-r--r--codemirror_ui/images/silk/telephone_add.pngbin0 -> 860 bytes
-rw-r--r--codemirror_ui/images/silk/telephone_delete.pngbin0 -> 856 bytes
-rw-r--r--codemirror_ui/images/silk/telephone_edit.pngbin0 -> 893 bytes
-rw-r--r--codemirror_ui/images/silk/telephone_error.pngbin0 -> 884 bytes
-rw-r--r--codemirror_ui/images/silk/telephone_go.pngbin0 -> 865 bytes
-rw-r--r--codemirror_ui/images/silk/telephone_key.pngbin0 -> 881 bytes
-rw-r--r--codemirror_ui/images/silk/telephone_link.pngbin0 -> 909 bytes
-rw-r--r--codemirror_ui/images/silk/television.pngbin0 -> 696 bytes
-rw-r--r--codemirror_ui/images/silk/television_add.pngbin0 -> 809 bytes
-rw-r--r--codemirror_ui/images/silk/television_delete.pngbin0 -> 810 bytes
-rw-r--r--codemirror_ui/images/silk/text_align_center.pngbin0 -> 234 bytes
-rw-r--r--codemirror_ui/images/silk/text_align_justify.pngbin0 -> 209 bytes
-rw-r--r--codemirror_ui/images/silk/text_align_left.pngbin0 -> 209 bytes
-rw-r--r--codemirror_ui/images/silk/text_align_right.pngbin0 -> 209 bytes
-rw-r--r--codemirror_ui/images/silk/text_allcaps.pngbin0 -> 284 bytes
-rw-r--r--codemirror_ui/images/silk/text_bold.pngbin0 -> 304 bytes
-rw-r--r--codemirror_ui/images/silk/text_columns.pngbin0 -> 246 bytes
-rw-r--r--codemirror_ui/images/silk/text_dropcaps.pngbin0 -> 314 bytes
-rw-r--r--codemirror_ui/images/silk/text_heading_1.pngbin0 -> 276 bytes
-rw-r--r--codemirror_ui/images/silk/text_heading_2.pngbin0 -> 304 bytes
-rw-r--r--codemirror_ui/images/silk/text_heading_3.pngbin0 -> 306 bytes
-rw-r--r--codemirror_ui/images/silk/text_heading_4.pngbin0 -> 293 bytes
-rw-r--r--codemirror_ui/images/silk/text_heading_5.pngbin0 -> 304 bytes
-rw-r--r--codemirror_ui/images/silk/text_heading_6.pngbin0 -> 310 bytes
-rw-r--r--codemirror_ui/images/silk/text_horizontalrule.pngbin0 -> 317 bytes
-rw-r--r--codemirror_ui/images/silk/text_indent.pngbin0 -> 353 bytes
-rw-r--r--codemirror_ui/images/silk/text_indent_remove.pngbin0 -> 351 bytes
-rw-r--r--codemirror_ui/images/silk/text_italic.pngbin0 -> 223 bytes
-rw-r--r--codemirror_ui/images/silk/text_kerning.pngbin0 -> 495 bytes
-rw-r--r--codemirror_ui/images/silk/text_letter_omega.pngbin0 -> 541 bytes
-rw-r--r--codemirror_ui/images/silk/text_letterspacing.pngbin0 -> 503 bytes
-rw-r--r--codemirror_ui/images/silk/text_linespacing.pngbin0 -> 363 bytes
-rw-r--r--codemirror_ui/images/silk/text_list_bullets.pngbin0 -> 344 bytes
-rw-r--r--codemirror_ui/images/silk/text_list_numbers.pngbin0 -> 357 bytes
-rw-r--r--codemirror_ui/images/silk/text_lowercase.pngbin0 -> 709 bytes
-rw-r--r--codemirror_ui/images/silk/text_padding_bottom.pngbin0 -> 237 bytes
-rw-r--r--codemirror_ui/images/silk/text_padding_left.pngbin0 -> 271 bytes
-rw-r--r--codemirror_ui/images/silk/text_padding_right.pngbin0 -> 271 bytes
-rw-r--r--codemirror_ui/images/silk/text_padding_top.pngbin0 -> 236 bytes
-rw-r--r--codemirror_ui/images/silk/text_replace.pngbin0 -> 691 bytes
-rw-r--r--codemirror_ui/images/silk/text_signature.pngbin0 -> 524 bytes
-rw-r--r--codemirror_ui/images/silk/text_smallcaps.pngbin0 -> 260 bytes
-rw-r--r--codemirror_ui/images/silk/text_strikethrough.pngbin0 -> 269 bytes
-rw-r--r--codemirror_ui/images/silk/text_subscript.pngbin0 -> 422 bytes
-rw-r--r--codemirror_ui/images/silk/text_superscript.pngbin0 -> 421 bytes
-rw-r--r--codemirror_ui/images/silk/text_underline.pngbin0 -> 273 bytes
-rw-r--r--codemirror_ui/images/silk/text_uppercase.pngbin0 -> 747 bytes
-rw-r--r--codemirror_ui/images/silk/textfield.pngbin0 -> 153 bytes
-rw-r--r--codemirror_ui/images/silk/textfield_add.pngbin0 -> 321 bytes
-rw-r--r--codemirror_ui/images/silk/textfield_delete.pngbin0 -> 335 bytes
-rw-r--r--codemirror_ui/images/silk/textfield_key.pngbin0 -> 455 bytes
-rw-r--r--codemirror_ui/images/silk/textfield_rename.pngbin0 -> 273 bytes
-rw-r--r--codemirror_ui/images/silk/thumb_down.pngbin0 -> 601 bytes
-rw-r--r--codemirror_ui/images/silk/thumb_up.pngbin0 -> 619 bytes
-rw-r--r--codemirror_ui/images/silk/tick.pngbin0 -> 537 bytes
-rw-r--r--codemirror_ui/images/silk/time.pngbin0 -> 793 bytes
-rw-r--r--codemirror_ui/images/silk/time_add.pngbin0 -> 827 bytes
-rw-r--r--codemirror_ui/images/silk/time_delete.pngbin0 -> 853 bytes
-rw-r--r--codemirror_ui/images/silk/time_go.pngbin0 -> 882 bytes
-rw-r--r--codemirror_ui/images/silk/timeline_marker.pngbin0 -> 327 bytes
-rw-r--r--codemirror_ui/images/silk/transmit.pngbin0 -> 749 bytes
-rw-r--r--codemirror_ui/images/silk/transmit_add.pngbin0 -> 803 bytes
-rw-r--r--codemirror_ui/images/silk/transmit_blue.pngbin0 -> 814 bytes
-rw-r--r--codemirror_ui/images/silk/transmit_delete.pngbin0 -> 827 bytes
-rw-r--r--codemirror_ui/images/silk/transmit_edit.pngbin0 -> 848 bytes
-rw-r--r--codemirror_ui/images/silk/transmit_error.pngbin0 -> 883 bytes
-rw-r--r--codemirror_ui/images/silk/transmit_go.pngbin0 -> 842 bytes
-rw-r--r--codemirror_ui/images/silk/tux.pngbin0 -> 696 bytes
-rw-r--r--codemirror_ui/images/silk/user.pngbin0 -> 741 bytes
-rw-r--r--codemirror_ui/images/silk/user_add.pngbin0 -> 746 bytes
-rw-r--r--codemirror_ui/images/silk/user_comment.pngbin0 -> 743 bytes
-rw-r--r--codemirror_ui/images/silk/user_delete.pngbin0 -> 767 bytes
-rw-r--r--codemirror_ui/images/silk/user_edit.pngbin0 -> 833 bytes
-rw-r--r--codemirror_ui/images/silk/user_female.pngbin0 -> 663 bytes
-rw-r--r--codemirror_ui/images/silk/user_go.pngbin0 -> 793 bytes
-rw-r--r--codemirror_ui/images/silk/user_gray.pngbin0 -> 706 bytes
-rw-r--r--codemirror_ui/images/silk/user_green.pngbin0 -> 722 bytes
-rw-r--r--codemirror_ui/images/silk/user_orange.pngbin0 -> 723 bytes
-rw-r--r--codemirror_ui/images/silk/user_red.pngbin0 -> 717 bytes
-rw-r--r--codemirror_ui/images/silk/user_suit.pngbin0 -> 748 bytes
-rw-r--r--codemirror_ui/images/silk/vcard.pngbin0 -> 533 bytes
-rw-r--r--codemirror_ui/images/silk/vcard_add.pngbin0 -> 661 bytes
-rw-r--r--codemirror_ui/images/silk/vcard_delete.pngbin0 -> 651 bytes
-rw-r--r--codemirror_ui/images/silk/vcard_edit.pngbin0 -> 775 bytes
-rw-r--r--codemirror_ui/images/silk/vector.pngbin0 -> 481 bytes
-rw-r--r--codemirror_ui/images/silk/vector_add.pngbin0 -> 616 bytes
-rw-r--r--codemirror_ui/images/silk/vector_delete.pngbin0 -> 635 bytes
-rw-r--r--codemirror_ui/images/silk/wand.pngbin0 -> 570 bytes
-rw-r--r--codemirror_ui/images/silk/weather_clouds.pngbin0 -> 581 bytes
-rw-r--r--codemirror_ui/images/silk/weather_cloudy.pngbin0 -> 694 bytes
-rw-r--r--codemirror_ui/images/silk/weather_lightning.pngbin0 -> 641 bytes
-rw-r--r--codemirror_ui/images/silk/weather_rain.pngbin0 -> 626 bytes
-rw-r--r--codemirror_ui/images/silk/weather_snow.pngbin0 -> 341 bytes
-rw-r--r--codemirror_ui/images/silk/weather_sun.pngbin0 -> 623 bytes
-rw-r--r--codemirror_ui/images/silk/webcam.pngbin0 -> 728 bytes
-rw-r--r--codemirror_ui/images/silk/webcam_add.pngbin0 -> 786 bytes
-rw-r--r--codemirror_ui/images/silk/webcam_delete.pngbin0 -> 805 bytes
-rw-r--r--codemirror_ui/images/silk/webcam_error.pngbin0 -> 821 bytes
-rw-r--r--codemirror_ui/images/silk/world.pngbin0 -> 923 bytes
-rw-r--r--codemirror_ui/images/silk/world_add.pngbin0 -> 940 bytes
-rw-r--r--codemirror_ui/images/silk/world_delete.pngbin0 -> 945 bytes
-rw-r--r--codemirror_ui/images/silk/world_edit.pngbin0 -> 945 bytes
-rw-r--r--codemirror_ui/images/silk/world_go.pngbin0 -> 944 bytes
-rw-r--r--codemirror_ui/images/silk/world_link.pngbin0 -> 957 bytes
-rw-r--r--codemirror_ui/images/silk/wrench.pngbin0 -> 610 bytes
-rw-r--r--codemirror_ui/images/silk/wrench_orange.pngbin0 -> 584 bytes
-rw-r--r--codemirror_ui/images/silk/xhtml.pngbin0 -> 595 bytes
-rw-r--r--codemirror_ui/images/silk/xhtml_add.pngbin0 -> 703 bytes
-rw-r--r--codemirror_ui/images/silk/xhtml_delete.pngbin0 -> 696 bytes
-rw-r--r--codemirror_ui/images/silk/xhtml_go.pngbin0 -> 697 bytes
-rw-r--r--codemirror_ui/images/silk/xhtml_valid.pngbin0 -> 718 bytes
-rw-r--r--codemirror_ui/images/silk/zoom.pngbin0 -> 692 bytes
-rw-r--r--codemirror_ui/images/silk/zoom_in.pngbin0 -> 725 bytes
-rw-r--r--codemirror_ui/images/silk/zoom_out.pngbin0 -> 708 bytes
-rw-r--r--codemirror_ui/index.html340
-rw-r--r--codemirror_ui/js/codemirror-ui-find.js89
-rw-r--r--codemirror_ui/js/codemirror-ui.js505
-rw-r--r--codemirror_ui/js/find_replace.html68
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/README.md8
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/activeline.html72
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/changemode.html50
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/closetag.html65
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/complete.html70
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/emacs.html59
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/folding.html61
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/formatting.html80
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/fullscreen.html152
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/loadmode.html39
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/marker.html52
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/matchhighlighter.html37
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/multiplex.html59
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/mustache.html57
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/preview.html76
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/resize.html41
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/runmode.html49
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/search.html83
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/theme.html78
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/vim.html50
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/demo/visibletabs.html61
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/doc/baboon.pngbin0 -> 23299 bytes
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/doc/baboon_vector.svg153
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/doc/compress.html148
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/doc/docs.css154
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/doc/internals.html494
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/doc/manual.html1128
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/doc/oldrelease.html267
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/doc/reporting.html57
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/doc/upgrade_v2.2.html95
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/index.html417
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/keymap/emacs.js29
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/keymap/vim.js766
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.css168
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.js3181
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/closetag.js146
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/dialog.css23
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/dialog.js63
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/foldcode.js196
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/formatting.js297
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/javascript-hint.js134
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/loadmode.js51
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/match-highlighter.js44
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/multiplex.js72
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/overlay.js52
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/pig-hint.js123
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/runmode.js49
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/search.js118
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/searchcursor.js117
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/simple-hint.css16
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/lib/util/simple-hint.js72
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/clike/clike.js271
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/clike/index.html101
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/clike/scala.html765
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/clojure/clojure.js207
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/clojure/index.html66
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/coffeescript/coffeescript.js347
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/coffeescript/index.html727
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/css/css.js124
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/css/index.html55
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/diff/diff.js32
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/diff/index.html104
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/ecl/ecl.js203
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/ecl/index.html42
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/erlang/erlang.js251
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/erlang/index.html61
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/gfm/gfm.js144
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/gfm/index.html47
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/go/go.js170
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/go/index.html72
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/groovy/groovy.js210
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/groovy/index.html71
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/haskell/haskell.js242
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/haskell/index.html60
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/htmlembedded/htmlembedded.js68
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/htmlembedded/index.html49
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/htmlmixed/htmlmixed.js85
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/htmlmixed/index.html51
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/javascript/index.html77
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/javascript/javascript.js361
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/jinja2/index.html37
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/jinja2/jinja2.js42
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/less/index.html618
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/less/less.js232
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/lua/index.html72
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/lua/lua.js140
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/markdown/index.html338
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/markdown/markdown.js245
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/mysql/index.html41
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/mysql/mysql.js188
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/ntriples/index.html32
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/ntriples/ntriples.js172
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/pascal/index.html48
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/pascal/pascal.js94
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/perl/index.html62
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/perl/perl.js816
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/php/index.html48
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/php/php.js150
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/pig/index.html42
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/pig/pig.js172
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/plsql/index.html62
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/plsql/plsql.js217
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/properties/index.html40
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/properties/properties.js63
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/python/LICENSE.txt21
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/python/index.html122
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/python/python.js338
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/r/index.html73
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/r/r.js141
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/rpm/changes/changes.js19
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/rpm/changes/index.html53
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/index.html99
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/spec.css5
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/spec.js66
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/rst/index.html525
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/rst/rst.js326
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/ruby/index.html171
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/ruby/ruby.js195
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/rust/index.html48
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/rust/rust.js432
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/scheme/index.html64
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/scheme/scheme.js230
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/shell/index.html50
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/shell/shell.js103
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/smalltalk/index.html55
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/smalltalk/smalltalk.js139
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/smarty/index.html82
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/smarty/smarty.js148
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/sparql/index.html40
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/sparql/sparql.js143
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/stex/index.html95
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/stex/stex.js182
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/stex/test.html263
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/index.html140
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/tiddlywiki.css14
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/tiddlywiki.js384
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/tiki/index.html82
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/tiki/tiki.css26
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/tiki/tiki.js316
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/vbscript/index.html42
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/vbscript/vbscript.js26
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/velocity/index.html103
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/velocity/velocity.js146
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/verilog/index.html210
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/verilog/verilog.js194
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xml/index.html44
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xml/xml.js325
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xquery/index.html222
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/index.html27
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testBase.js42
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testEmptySequenceKeyword.js16
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testMultiAttr.js16
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testNamespaces.js91
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testProcessingInstructions.js16
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testQuotes.js19
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/xquery/xquery.js448
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/yaml/index.html67
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/mode/yaml/yaml.js95
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/package.json29
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/test/index.html28
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/test/mode_test.css22
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/test/mode_test.js164
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/test/test.js344
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/ambiance.css81
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/blackboard.css25
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/cobalt.css18
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/eclipse.css25
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/elegant.css10
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/erlang-dark.css21
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/lesser-dark.css44
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/monokai.css28
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/neat.css9
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/night.css21
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/rubyblue.css21
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/vibrant-ink.css27
-rw-r--r--codemirror_ui/lib/CodeMirror-2.3/theme/xq-dark.css46
-rw-r--r--codemirror_ui/localization/cs_CZ.inc18
-rw-r--r--codemirror_ui/localization/da_DK.inc20
-rw-r--r--codemirror_ui/localization/de_DE.inc18
-rw-r--r--codemirror_ui/localization/en_US.inc5
-rw-r--r--codemirror_ui/localization/es_ES.inc18
-rw-r--r--codemirror_ui/localization/fi_FI.inc18
-rw-r--r--codemirror_ui/localization/pl_PL.inc18
-rw-r--r--codemirror_ui/localization/revision.inc.php11
-rw-r--r--codemirror_ui/package.xml22
m---------compose_addressbook0
m---------contextmenu0
-rw-r--r--db_config/CHANGELOG19
-rw-r--r--db_config/LICENSE71
-rw-r--r--db_config/README8
-rw-r--r--db_config/SQL/mssql.20131110.sql2
-rw-r--r--db_config/SQL/mssql.20141115.sql2
-rw-r--r--db_config/SQL/mssql.initial.sql12
-rw-r--r--db_config/SQL/mysql.20131110.sql2
-rw-r--r--db_config/SQL/mysql.20141115.sql4
-rw-r--r--db_config/SQL/mysql.initial.sql15
-rw-r--r--db_config/SQL/pgsql.20131110.sql1
-rw-r--r--db_config/SQL/pgsql.20141115.sql1
-rw-r--r--db_config/SQL/pgsql.initial.sql13
-rw-r--r--db_config/SQL/sqlite.20131110.sql1
-rw-r--r--db_config/SQL/sqlite.20141115.sql1
-rw-r--r--db_config/SQL/sqlite.initial.sql13
-rw-r--r--db_config/config.inc.php.dist86
-rw-r--r--db_config/db_config.php15
-rw-r--r--db_config/localization/cs_CZ.inc15
-rw-r--r--db_config/localization/da_DK.inc15
-rw-r--r--db_config/localization/de_DE.inc15
-rw-r--r--db_config/localization/en_US.inc15
-rw-r--r--db_config/localization/es_ES.inc15
-rw-r--r--db_config/localization/fi_FI.inc15
-rw-r--r--db_config/localization/fr_FR.inc15
-rw-r--r--db_config/localization/revision.inc.php11
-rw-r--r--db_config/localization/tr_TR.inc15
-rw-r--r--db_config/package.xml22
-rw-r--r--db_version/CHANGELOG21
-rw-r--r--db_version/LICENSE84
-rw-r--r--db_version/README8
-rw-r--r--db_version/SQL/mssql.initial.sql5
-rw-r--r--db_version/SQL/mysql.initial.sql13
-rw-r--r--db_version/SQL/pgsql.initial.sql12
-rw-r--r--db_version/SQL/sqlite.initial.sql12
-rw-r--r--db_version/db_version.php474
-rw-r--r--db_version/package.xml22
-rw-r--r--db_version/skins/classic/sql.html31
-rw-r--r--db_version/skins/larry/sql.html48
-rw-r--r--libgpl/CHANGELOG39
-rw-r--r--libgpl/LICENSE671
-rw-r--r--libgpl/README8
-rw-r--r--libgpl/caldav/caldav-client.php468
-rw-r--r--libgpl/caldav/caldav_sync.php284
-rw-r--r--libgpl/caldav/vobject_sanitize.php110
-rw-r--r--libgpl/contextmenu/jquery.contextMenu.js1686
-rw-r--r--libgpl/contextmenu/jquery.ui.position.js497
-rw-r--r--libgpl/date/date.js335
-rw-r--r--libgpl/dialogextend/jquery.dialogextend.js509
-rw-r--r--libgpl/dialogextend/jquery.dialogextend.min.js2
-rw-r--r--libgpl/encryption/encryption.php166
-rw-r--r--libgpl/fancybox/blank.gifbin0 -> 43 bytes
-rw-r--r--libgpl/fancybox/fancy_close.pngbin0 -> 1517 bytes
-rw-r--r--libgpl/fancybox/fancy_closebox.pngbin0 -> 1910 bytes
-rw-r--r--libgpl/fancybox/fancy_left.pngbin0 -> 1623 bytes
-rw-r--r--libgpl/fancybox/fancy_loading.pngbin0 -> 10195 bytes
-rw-r--r--libgpl/fancybox/fancy_nav_left.pngbin0 -> 1446 bytes
-rw-r--r--libgpl/fancybox/fancy_nav_right.pngbin0 -> 1454 bytes
-rw-r--r--libgpl/fancybox/fancy_progress.pngbin0 -> 12412 bytes
-rw-r--r--libgpl/fancybox/fancy_right.pngbin0 -> 1645 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_e.pngbin0 -> 107 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_n.pngbin0 -> 106 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_ne.pngbin0 -> 347 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_nw.pngbin0 -> 324 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_s.pngbin0 -> 111 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_se.pngbin0 -> 352 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_sw.pngbin0 -> 340 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_w.pngbin0 -> 103 bytes
-rw-r--r--libgpl/fancybox/fancy_title_left.pngbin0 -> 503 bytes
-rw-r--r--libgpl/fancybox/fancy_title_main.pngbin0 -> 96 bytes
-rw-r--r--libgpl/fancybox/fancy_title_over.pngbin0 -> 70 bytes
-rw-r--r--libgpl/fancybox/fancy_title_right.pngbin0 -> 506 bytes
-rw-r--r--libgpl/fancybox/fancybox-x.pngbin0 -> 203 bytes
-rw-r--r--libgpl/fancybox/fancybox-y.pngbin0 -> 176 bytes
-rw-r--r--libgpl/fancybox/fancybox.pngbin0 -> 15287 bytes
-rw-r--r--libgpl/fancybox/jquery.easing-1.3.pack.js72
-rw-r--r--libgpl/fancybox/jquery.fancybox-1.3.4.css359
-rw-r--r--libgpl/fancybox/jquery.fancybox-1.3.4.js1156
-rw-r--r--libgpl/fancybox/jquery.fancybox-1.3.4.pack.js46
-rw-r--r--libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js14
-rw-r--r--libgpl/flashclipboard/clipboard.swfbin0 -> 1071 bytes
-rw-r--r--libgpl/flashclipboard/flashclipboard_libgpl.js309
-rw-r--r--libgpl/flashclipboard/flashclipboard_moreuserinfo.js290
-rw-r--r--libgpl/gibberish/GibberishAES.php213
-rw-r--r--libgpl/gibberish/gibberish-aes.js36
-rw-r--r--libgpl/gibberish/gibberish-aes.js.comp.src1017
-rw-r--r--libgpl/http_request/class.http.php1190
-rw-r--r--libgpl/ical/ical_sync.php144
-rw-r--r--libgpl/jquery_migrate/jquery.migrate.js521
-rw-r--r--libgpl/libcalendaring/libcalendaring.js676
-rw-r--r--libgpl/libgpl.php189
-rw-r--r--libgpl/localization/cs_CZ.inc48
-rw-r--r--libgpl/localization/en_US.inc36
-rw-r--r--libgpl/localization/es_ES.inc48
-rw-r--r--libgpl/localization/fi_FI.inc48
-rw-r--r--libgpl/localization/fr_FR.inc51
-rw-r--r--libgpl/localization/revision.inc.php11
-rw-r--r--libgpl/package.xml22
-rw-r--r--libgpl/password/password.js36
-rw-r--r--libgpl/qtip/qtip.css1
-rw-r--r--libgpl/qtip/qtip.js68
-rw-r--r--libgpl/querystring/querystring.js34
-rw-r--r--libgpl/skins/classic/calendar.css4
-rw-r--r--libgpl/skins/classic/images/convert.pngbin0 -> 709 bytes
-rw-r--r--libgpl/skins/classic/images/delete.pngbin0 -> 536 bytes
-rw-r--r--libgpl/skins/classic/images/door.pngbin0 -> 412 bytes
-rw-r--r--libgpl/skins/classic/images/edit.pngbin0 -> 618 bytes
-rw-r--r--libgpl/skins/classic/images/message.pngbin0 -> 376 bytes
-rw-r--r--libgpl/skins/classic/images/note.pngbin0 -> 844 bytes
-rw-r--r--libgpl/skins/classic/images/task.pngbin0 -> 684 bytes
-rw-r--r--libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.pngbin0 -> 88 bytes
-rw-r--r--libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.pngbin0 -> 101 bytes
-rw-r--r--libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.pngbin0 -> 111 bytes
-rw-r--r--libgpl/skins/classic/images/ui-icons_004458_256x240.pngbin0 -> 4369 bytes
-rw-r--r--libgpl/skins/classic/jquery.contextMenu.css141
-rw-r--r--libgpl/skins/classic/timepicker2.css10
-rw-r--r--libgpl/skins/larry/calendar.css6
-rw-r--r--libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.pngbin0 -> 88 bytes
-rw-r--r--libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.pngbin0 -> 111 bytes
-rw-r--r--libgpl/skins/larry/images/ui-icons_004458_256x240.pngbin0 -> 4369 bytes
-rw-r--r--libgpl/skins/larry/jquery.contextMenu.css154
-rw-r--r--libgpl/skins/larry/timepicker2.css13
-rw-r--r--libgpl/timepicker/jquery.timepicker.css72
-rw-r--r--libgpl/timepicker/jquery.timepicker.js1149
-rw-r--r--libgpl/timepicker/jquery.timepicker.min.js7
-rw-r--r--libgpl/timepicker2/jquery.timepicker.js2223
m---------listcommands0
m---------markasjunk20
m---------message_highlight0
-rw-r--r--myrc_branch/CHANGELOG7
-rw-r--r--myrc_branch/LICENSE671
-rw-r--r--myrc_branch/README8
-rw-r--r--myrc_branch/localization/cs_CZ.inc18
-rw-r--r--myrc_branch/localization/en_US.inc18
-rw-r--r--myrc_branch/localization/es_ES.inc18
-rw-r--r--myrc_branch/localization/revision.inc.php11
-rw-r--r--myrc_branch/myrc_branch.php65
-rw-r--r--myrc_branch/package.xml22
-rw-r--r--myrc_sprites/CHANGELOG4
-rw-r--r--myrc_sprites/LICENSE671
-rw-r--r--myrc_sprites/README8
-rw-r--r--myrc_sprites/localization/cs_CZ.inc18
-rw-r--r--myrc_sprites/localization/en_US.inc18
-rw-r--r--myrc_sprites/localization/es_ES.inc18
-rw-r--r--myrc_sprites/localization/fi_FI.inc18
-rw-r--r--myrc_sprites/localization/revision.inc.php11
-rw-r--r--myrc_sprites/myrc_sprites.php91
-rw-r--r--myrc_sprites/package.xml22
-rw-r--r--myrc_sprites/skins/classic/images/myrc_watermark.pngbin0 -> 4644 bytes
-rw-r--r--myrc_sprites/skins/larry/images/myrc_ajax_loading.gifbin0 -> 1187 bytes
-rw-r--r--myrc_sprites/skins/larry/images/myrc_linen_bg.jpgbin0 -> 330 bytes
-rw-r--r--myrc_sprites/skins/larry/images/myrc_loading.gifbin0 -> 2262 bytes
-rw-r--r--myrc_sprites/skins/larry/images/myrc_loading_small.gifbin0 -> 688 bytes
-rw-r--r--myrc_sprites/skins/larry/images/myrc_login_shadow.pngbin0 -> 1267 bytes
-rw-r--r--myrc_sprites/skins/larry/images/myrc_sprites.pngbin0 -> 27826 bytes
-rw-r--r--myrc_sprites/skins/larry/images/myrc_watermark.pngbin0 -> 4644 bytes
-rw-r--r--myrc_sprites/skins/larry/images/offsets.txt21
-rw-r--r--myrc_sprites/skins/larry/myrc_sprites.css30
-rw-r--r--plugin_manager/CHANGELOG145
-rw-r--r--plugin_manager/COMMENTS8
-rw-r--r--plugin_manager/CONFIGHEADER9
-rw-r--r--plugin_manager/EXAMPLE36
-rw-r--r--plugin_manager/LICENSE84
-rw-r--r--plugin_manager/README8
-rw-r--r--plugin_manager/SQL/mssql.20131209.sql4
-rw-r--r--plugin_manager/SQL/mssql.initial.sql20
-rw-r--r--plugin_manager/SQL/mysql.20131209.sql4
-rw-r--r--plugin_manager/SQL/mysql.initial.sql21
-rw-r--r--plugin_manager/SQL/pgsql.20131209.sql3
-rw-r--r--plugin_manager/SQL/pgsql.initial.sql17
-rw-r--r--plugin_manager/SQL/sqlite.20131209.sql48
-rw-r--r--plugin_manager/SQL/sqlite.initial.sql11
-rw-r--r--plugin_manager/defaults.inc.php654
-rw-r--r--plugin_manager/localization/bg_BG.inc134
-rw-r--r--plugin_manager/localization/cs_CZ.inc346
-rw-r--r--plugin_manager/localization/de_CH.inc244
-rw-r--r--plugin_manager/localization/de_DE.inc346
-rw-r--r--plugin_manager/localization/el_GR.inc74
-rw-r--r--plugin_manager/localization/en_GB.inc139
-rw-r--r--plugin_manager/localization/en_US.inc346
-rw-r--r--plugin_manager/localization/es_ES.inc346
-rw-r--r--plugin_manager/localization/fi_FI.inc252
-rw-r--r--plugin_manager/localization/fr_FR.inc346
-rw-r--r--plugin_manager/localization/hu_HU.inc154
-rw-r--r--plugin_manager/localization/it_IT.inc170
-rw-r--r--plugin_manager/localization/nl_NL.inc201
-rw-r--r--plugin_manager/localization/pl_PL.inc275
-rw-r--r--plugin_manager/localization/pt_BR.inc182
-rw-r--r--plugin_manager/localization/pt_PT.inc116
-rw-r--r--plugin_manager/localization/revision.inc.php11
-rw-r--r--plugin_manager/localization/ru_RU.inc205
-rw-r--r--plugin_manager/package.xml24
-rw-r--r--plugin_manager/plugin_manager.js372
-rw-r--r--plugin_manager/plugin_manager.php4554
-rw-r--r--plugin_manager/plugin_manager_fixes.js19
-rw-r--r--plugin_manager/plugin_manager_update.js325
-rw-r--r--plugin_manager/skins/classic/blank.html15
-rw-r--r--plugin_manager/skins/classic/download.pngbin0 -> 601 bytes
-rw-r--r--plugin_manager/skins/classic/myroundcube.html19
-rw-r--r--plugin_manager/skins/classic/plugin_manager.css178
-rw-r--r--plugin_manager/skins/classic/plugin_manager_update.css69
-rw-r--r--plugin_manager/skins/classic/templates/config.html11
-rw-r--r--plugin_manager/skins/classic/templates/error.html14
-rw-r--r--plugin_manager/skins/classic/templates/transfer.html10
-rw-r--r--plugin_manager/skins/classic/traffic-light-exclamation.pngbin0 -> 690 bytes
-rw-r--r--plugin_manager/skins/classic/traffic-light-off.pngbin0 -> 401 bytes
-rw-r--r--plugin_manager/skins/classic/traffic-light-pencil.pngbin0 -> 646 bytes
-rw-r--r--plugin_manager/skins/classic/traffic-light-plus.pngbin0 -> 610 bytes
-rw-r--r--plugin_manager/skins/classic/traffic-light.pngbin0 -> 512 bytes
-rw-r--r--plugin_manager/skins/classic/watermark.gifbin0 -> 4644 bytes
-rw-r--r--plugin_manager/skins/larry/blank.html16
-rw-r--r--plugin_manager/skins/larry/download.pngbin0 -> 601 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-bg_flat_0_aaaaaa_40x100.pngbin0 -> 212 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-bg_flat_75_ffffff_40x100.pngbin0 -> 208 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-bg_glass_55_fbf9ee_1x400.pngbin0 -> 335 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-bg_glass_65_ffffff_1x400.pngbin0 -> 207 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-bg_glass_75_dadada_1x400.pngbin0 -> 262 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-bg_glass_75_e6e6e6_1x400.pngbin0 -> 262 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-bg_glass_95_fef1ec_1x400.pngbin0 -> 332 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-bg_highlight-soft_75_cccccc_1x100.pngbin0 -> 280 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-icons_222222_256x240.pngbin0 -> 6922 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-icons_2e83ff_256x240.pngbin0 -> 4549 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-icons_454545_256x240.pngbin0 -> 6992 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-icons_888888_256x240.pngbin0 -> 6999 bytes
-rw-r--r--plugin_manager/skins/larry/images/ui-icons_cd0a0a_256x240.pngbin0 -> 4549 bytes
-rw-r--r--plugin_manager/skins/larry/jqueryui.css462
-rw-r--r--plugin_manager/skins/larry/manage-plugins-col.pngbin0 -> 1995 bytes
-rw-r--r--plugin_manager/skins/larry/myroundcube.html20
-rw-r--r--plugin_manager/skins/larry/plugin_manager.css208
-rw-r--r--plugin_manager/skins/larry/plugin_manager_update.css66
-rw-r--r--plugin_manager/skins/larry/templates/config.html11
-rw-r--r--plugin_manager/skins/larry/templates/error.html13
-rw-r--r--plugin_manager/skins/larry/templates/transfer.html10
-rw-r--r--plugin_manager/skins/larry/traffic-light-exclamation.pngbin0 -> 690 bytes
-rw-r--r--plugin_manager/skins/larry/traffic-light-off.pngbin0 -> 401 bytes
-rw-r--r--plugin_manager/skins/larry/traffic-light-pencil.pngbin0 -> 646 bytes
-rw-r--r--plugin_manager/skins/larry/traffic-light-plus.pngbin0 -> 610 bytes
-rw-r--r--plugin_manager/skins/larry/traffic-light.pngbin0 -> 512 bytes
-rw-r--r--settings/CHANGELOG11
-rw-r--r--settings/LICENSE84
-rw-r--r--settings/README8
-rw-r--r--settings/config.inc.php.dist25
-rw-r--r--settings/localization/bg_BG.inc26
-rw-r--r--settings/localization/ca_ES.inc12
-rw-r--r--settings/localization/cs_CZ.inc27
-rw-r--r--settings/localization/da_DK.inc15
-rw-r--r--settings/localization/de_CH.inc24
-rw-r--r--settings/localization/de_DE.inc27
-rw-r--r--settings/localization/en_GB.inc26
-rw-r--r--settings/localization/en_US.inc16
-rw-r--r--settings/localization/es_ES.inc27
-rw-r--r--settings/localization/fi_FI.inc27
-rw-r--r--settings/localization/fr_FR.inc27
-rw-r--r--settings/localization/gl_ES.inc12
-rw-r--r--settings/localization/hu_HU.inc26
-rw-r--r--settings/localization/it_IT.inc26
-rw-r--r--settings/localization/nl_NL.inc27
-rw-r--r--settings/localization/pl_PL.inc29
-rw-r--r--settings/localization/pt_BR.inc25
-rw-r--r--settings/localization/pt_PT.inc26
-rw-r--r--settings/localization/revision.inc.php11
-rw-r--r--settings/localization/ru_RU.inc26
-rw-r--r--settings/localization/sk_SK.inc28
-rw-r--r--settings/localization/sv_SE.inc11
-rw-r--r--settings/localization/zh_CN.inc10
-rw-r--r--settings/localization/zh_TW.inc11
-rw-r--r--settings/settings.js27
-rw-r--r--settings/settings.php282
-rw-r--r--settings/skins/classic/settings.css52
-rw-r--r--settings/skins/larry/images/account-admin-col.pngbin0 -> 1895 bytes
-rw-r--r--settings/skins/larry/settings.css65
m---------show_pgp_mime0
1474 files changed, 59401 insertions, 0 deletions
diff --git a/codemirror_ui/.gitignore b/codemirror_ui/.gitignore
new file mode 100644
index 0000000..3f2795b
--- /dev/null
+++ b/codemirror_ui/.gitignore
@@ -0,0 +1,5 @@
+*~
+.project
+.redcar/
+**/.DS_Store
+.DS_Store
diff --git a/codemirror_ui/.htaccess b/codemirror_ui/.htaccess
new file mode 100644
index 0000000..fec8135
--- /dev/null
+++ b/codemirror_ui/.htaccess
@@ -0,0 +1,3 @@
+<Files index.html>
+ #Deny from all
+</Files> \ No newline at end of file
diff --git a/codemirror_ui/CHANGELOG b/codemirror_ui/CHANGELOG
new file mode 100644
index 0000000..b3e1322
--- /dev/null
+++ b/codemirror_ui/CHANGELOG
@@ -0,0 +1,5 @@
+VERSION COMMENT
+-----------------------------------------------------------------------------------------------------------------
+1.0.3 - It's time for a Changelog
+1.0.4 - Roundcube 1.0 compatibility
+1.0.5 - MySQL implementation \ No newline at end of file
diff --git a/codemirror_ui/LICENSE b/codemirror_ui/LICENSE
new file mode 100644
index 0000000..be51135
--- /dev/null
+++ b/codemirror_ui/LICENSE
@@ -0,0 +1,45 @@
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+
+
+
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+
+
+
+Copyright (C) 2011 by Jeremy Green <jeremy@octolabs.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/codemirror_ui/README b/codemirror_ui/README
new file mode 100644
index 0000000..d4f13ea
--- /dev/null
+++ b/codemirror_ui/README
@@ -0,0 +1,8 @@
+codemirror_ui
+-------------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/
+
+
+MyRoundcube Dev Team
+www.myroundcube.com \ No newline at end of file
diff --git a/codemirror_ui/README.md b/codemirror_ui/README.md
new file mode 100644
index 0000000..3a8d49e
--- /dev/null
+++ b/codemirror_ui/README.md
@@ -0,0 +1,66 @@
+CodeMirror UI
+=============
+
+CodeMirrorUI is a simple interface written by Jeremy Green to act as a
+wrapper around the [CodeMirror](http://codemirror.net/) text editor widget by Marijn Haverbeke.
+CodeMirror is a syntax highlighter and formatter that makes it much easier to edit source code in a browser.
+CodeMirrorUI is a wrapper that adds interface functionality for many functions that are already built into CodeMirror itself.
+Functionality includes undo, redo, jump to line, reindent selection, and reindent entire document.
+Two options for find/replace are also available. It is based on the MirrorFrame example that Marijn included with CodeMirror.
+
+Demo
+-------------------
+
+[http://www.octolabs.com/javascripts/codemirror-ui/index.html](http://www.octolabs.com/javascripts/codemirror-ui/index.html)
+
+Upgrading
+-------------------
+*Note* Starting with version 0.0.17 CodeMirror-UI upgraded to CodeMirror-2.3. The find and replace functionality relies
+on the searchcursor add-on for CodeMirror. Make sure to add the searchcursor line from the installation instructions if
+the search/replace is not working.
+
+Easily Configurable
+--------------------
+
+It's easy to configure an editor with something like this:
+
+ //first set up some variables
+ var textarea = document.getElementById('code1');
+ var uiOptions = { path : 'js/', searchMode: 'popup' }
+ var codeMirrorOptions = {
+ mode: "javascript" // all your normal CodeMirror options go here
+ }
+
+ //then create the editor
+ var editor = new CodeMirrorUI(textarea,uiOptions,codeMirrorOptions);
+
+Installation
+--------------------
+
+ // First the CodeMirror stuff
+ <script src="lib/CodeMirror-2.3/lib/codemirror.js" type="text/javascript"></script>
+ <script src="lib/CodeMirror-2.3/lib/util/searchcursor.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="lib/CodeMirror-2.3/lib/codemirror.css">
+ <script src="lib/CodeMirror-2.3/mode/javascript/javascript.js"></script>
+ <link rel="stylesheet" href="lib/CodeMirror-2.3/mode/javascript/javascript.css">
+
+ //Then the CodeMirrorUI stuff
+ <script src="js/codemirror-ui.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="css/codemirror-ui.css" type="text/css" media="screen" />
+
+You'll probably need to adjust the paths to fit your situation.
+
+Please see index.html for examples and many additional details.
+
+Acknowledgements
+----------------------
+
+Thanks to Marijn Haverbeke for creating and releasing [CodeMirror](http://codemirror.net/) in the first place.
+Without his excellent contribution to the community this project would have no reason to exist.
+
+Thanks to Mark James of famfamfam.com for his [Silk Icons](http://www.famfamfam.com/lab/icons/silk/).
+
+License
+----------------------
+
+CodeMirror UI is provided under the MIT License. See the LICENSE file for full details. \ No newline at end of file
diff --git a/codemirror_ui/VERSION b/codemirror_ui/VERSION
new file mode 100644
index 0000000..e923bd0
--- /dev/null
+++ b/codemirror_ui/VERSION
@@ -0,0 +1,3 @@
+0.0.19
+
+
diff --git a/codemirror_ui/codemirror_ui.php b/codemirror_ui/codemirror_ui.php
new file mode 100644
index 0000000..1493048
--- /dev/null
+++ b/codemirror_ui/codemirror_ui.php
@@ -0,0 +1,153 @@
+<?php
+/**
+ * codemirror_ui
+ *
+ * @version 1.0.5 - 08.05.2014
+ * @author Roland 'rosali' Liebl
+ * @website http://myroundcube.com
+ *
+ **/
+
+class codemirror_ui extends rcube_plugin{
+
+ public $noajax = true;
+
+ /* unified plugin properties */
+ static private $plugin = 'codemirror_ui';
+ static private $author = 'myroundcube@mail4us.net';
+ static private $authors_comments = '<a href="http://myroundcube.com/myroundcube-plugins/helper-plugin?codemirror_ui" target="_blank">Documentation</a>';
+ static private $version = '1.0.5';
+ static private $date = '08-05-2014';
+ static private $licence = 'GPL';
+ static private $requirements = array(
+ 'Roundcube' => '1.0',
+ 'PHP' => '5.3'
+ );
+
+ private $rcmail;
+
+ function init(){
+ $this->rcmail = rcmail::get_instance();
+ switch($GLOBALS['codemirror']['mode']){
+ case 'PHP':
+ $this->rcmail->output->add_header('<style type="text/css">.CodeMirror {height: 90%} .CodeMirror-scroll {height: 100%} </style>');
+ break;
+ case 'SQL':
+ $this->rcmail->output->add_header('<style type="text/css">.CodeMirror {height: auto} .CodeMirror-scroll {overflow-y: hidden; overflow-x: auto;} </style>');
+ }
+ $this->include_stylesheet('lib/CodeMirror-2.3/lib/codemirror.css');
+ $this->include_script('lib/CodeMirror-2.3/lib/codemirror.js');
+ $this->include_script('lib/CodeMirror-2.3/lib/util/searchcursor.js');
+ switch($GLOBALS['codemirror']['mode']){
+ case 'PHP':
+ $this->PHP($GLOBALS['codemirror']['elem']);
+ break;
+ case 'SQL':
+ $this->SQL($GLOBALS['codemirror']['elem']);
+ }
+ $this->include_stylesheet('css/codemirror-ui.css');
+ $this->include_script('js/codemirror-ui.js');
+ }
+
+ function PHP($elem){
+ $this->include_script('lib/CodeMirror-2.3/mode/htmlmixed/htmlmixed.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/xml/xml.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/javascript/javascript.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/css/css.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/clike/clike.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/php/php.js');
+ $this->rcmail->output->add_script('
+ var textarea = document.getElementById("' . $elem . '");
+ var uiOptions = {
+ path : "js/",
+ searchMode : "popup",
+ mode: "php",
+ imagePath : "plugins/codemirror_ui/images/silk",
+ buttons : ' . $GLOBALS['codemirror']['buttons'] . ',
+ saveCallback : ' . $GLOBALS['codemirror']['save'] . '
+ }
+ var codeMirrorOptions = {
+ readOnly: ' . ($GLOBALS['codemirror']['readonly'] ? 'true' : 'false') . ',
+ lineNumbers: true,
+ matchBrackets: true,
+ mode: "application/x-httpd-php",
+ indentUnit: 2,
+ indentWithTabs: true,
+ enterMode: "keep",
+ tabMode: "shift",
+ tabSize: 2
+ }
+ var editor = new CodeMirrorUI(textarea, uiOptions, codeMirrorOptions);
+ ', 'docready'
+ );
+ }
+
+ function SQL($elem){
+ $this->include_script('lib/CodeMirror-2.3/mode/htmlmixed/htmlmixed.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/xml/xml.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/javascript/javascript.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/css/css.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/clike/clike.js');
+ $this->include_script('lib/CodeMirror-2.3/mode/mysql/mysql.js');
+ $this->rcmail->output->add_script('
+ var textarea = document.getElementById("' . $elem . '");
+ var uiOptions = {
+ path : "js/",
+ searchMode : "popup",
+ mode: "mysql",
+ imagePath : "plugins/codemirror_ui/images/silk",
+ buttons : ' . $GLOBALS['codemirror']['buttons'] . ',
+ saveCallback : ' . $GLOBALS['codemirror']['save'] . '
+ }
+ var codeMirrorOptions = {
+ readOnly: ' . ($GLOBALS['codemirror']['readonly'] ? 'true' : 'false') . ',
+ lineNumbers: true,
+ matchBrackets: true,
+ mode: "text/x-mysql",
+ indentUnit: 2,
+ indentWithTabs: true,
+ enterMode: "keep",
+ tabMode: "shift",
+ fixedGutter: true,
+ tabSize: 2
+ }
+ var editor = new CodeMirrorUI(textarea, uiOptions, codeMirrorOptions);
+ ', 'docready'
+ );
+ }
+
+ static public function about($keys = false){
+ $requirements = self::$requirements;
+ foreach(array('required_', 'recommended_') as $prefix){
+ if(is_array($requirements[$prefix.'plugins'])){
+ foreach($requirements[$prefix.'plugins'] as $plugin => $method){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $class->about($keys),
+ );
+ }
+ else{
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $plugin,
+ );
+ }
+ }
+ }
+ }
+ return array(
+ 'plugin' => self::$plugin,
+ 'version' => self::$version,
+ 'date' => self::$date,
+ 'author' => self::$author,
+ 'comments' => self::$authors_comments,
+ 'licence' => self::$licence,
+ 'requirements' => $requirements,
+ );
+ }
+}
+
+?> \ No newline at end of file
diff --git a/codemirror_ui/css/codemirror-ui-find.css b/codemirror_ui/css/codemirror-ui-find.css
new file mode 100644
index 0000000..fd37a5f
--- /dev/null
+++ b/codemirror_ui/css/codemirror-ui-find.css
@@ -0,0 +1,19 @@
+#buttons{
+ float:right;
+}
+
+#buttons a{
+
+ display:block;
+ text-align:center;
+ background:#ddd;
+ border:1px solid black;
+ color:black;
+ text-decoration:none;
+ padding:3px;
+
+}
+
+#buttons a:hover{
+ background:white;
+} \ No newline at end of file
diff --git a/codemirror_ui/css/codemirror-ui.css b/codemirror_ui/css/codemirror-ui.css
new file mode 100644
index 0000000..ee0efcd
--- /dev/null
+++ b/codemirror_ui/css/codemirror-ui.css
@@ -0,0 +1,122 @@
+.codemirror-ui-button-frame{
+ border-top:1px solid #ccc;
+ border-left:1px solid #ccc;
+ border-right:1px solid #ccc;
+ background:#eee;
+ position:relative;
+}
+
+.codemirror-ui-button-frame input,.codemirror-ui-button-frame label{
+ font-size:0.9em;
+}
+
+.codemirror-ui-button-frame label input{
+ margin:0px 2px;
+ vertical-align:middle;
+}
+.codemirror-ui-button-frame label{
+ padding:0px;
+ margin:2px 5px;
+ margin-top:0px;
+ display:inline-block;
+}
+
+input.codemirror-ui-checkbox{
+
+}
+
+.codemirror-ui-button{
+ display:block;
+ float:left;
+ padding:3px;
+ line-height:0;
+ margin:1px;
+ margin-right:0px;
+}
+
+.codemirror-ui-button:hover{
+ padding:2px;
+ border:1px solid #ccc;
+}
+
+.codemirror-ui-button img{
+ line-height:0;
+}
+
+.codemirror-ui-button.inactive{
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+
+.codemirror-ui-wrap{
+ float:right;
+}
+
+.codemirror-find-replace{
+ border:1px solid black;
+ background : #ddd;
+ padding:10px;
+ position:absolute;
+ width:300px;
+ top:0%;
+ left:50%;
+ margin-left:-150px;
+}
+
+iframe{
+ /*border:1px solid green !important;*/
+}
+
+.codemirror-ui-find-bar{
+ text-align:center;
+}
+
+.codemirror-ui-popup-find-wrap{
+ position:absolute;
+ bottom:100%;
+ left:-1px;
+ border:1px solid #ccc;
+ background:#eee;
+ padding:2px 5px;
+ border-bottom:0px;
+ margin-bottom:-1px;
+ display:none;
+}
+
+.codemirror-ui-popup-find-wrap.active{
+ display:block;
+}
+
+
+.codemirror-ui-popup-find-wrap .codemirror-ui-button{
+ float:left;
+}
+
+.codemirror-ui-popup-find-wrap .codemirror-ui-find-bar{
+ float:left;
+}
+
+.CodeMirror{
+ border:1px solid #ccc;
+ background:white;
+}
+
+/*
+ * This lets us make sure that the fancy-tab-gutter will always enclose the tabs inside it.
+ * We're namspcing it since many frameworks include a .clearfix rule of somesort.
+ */
+
+.codemirror-ui-clearfix:after {
+ visibility: hidden;
+ display: block;
+ font-size: 0;
+ content:"\0020";
+ clear: both;
+ height: 0;
+ }
+.codemirror-ui-clearfix { display: inline-block; }
+/* start commented backslash hack \*/
+* html .codemirror-ui-clearfix { height: 1%; }
+.codemirror-ui-clearfix { display: block; }
+/* close commented backslash hack */
diff --git a/codemirror_ui/images/octologo.png b/codemirror_ui/images/octologo.png
new file mode 100644
index 0000000..f6f97e9
--- /dev/null
+++ b/codemirror_ui/images/octologo.png
Binary files differ
diff --git a/codemirror_ui/images/silk/accept.png b/codemirror_ui/images/silk/accept.png
new file mode 100644
index 0000000..89c8129
--- /dev/null
+++ b/codemirror_ui/images/silk/accept.png
Binary files differ
diff --git a/codemirror_ui/images/silk/add.png b/codemirror_ui/images/silk/add.png
new file mode 100644
index 0000000..6332fef
--- /dev/null
+++ b/codemirror_ui/images/silk/add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/anchor.png b/codemirror_ui/images/silk/anchor.png
new file mode 100644
index 0000000..9b3422c
--- /dev/null
+++ b/codemirror_ui/images/silk/anchor.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application.png b/codemirror_ui/images/silk/application.png
new file mode 100644
index 0000000..1dee9e3
--- /dev/null
+++ b/codemirror_ui/images/silk/application.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_add.png b/codemirror_ui/images/silk/application_add.png
new file mode 100644
index 0000000..2e94507
--- /dev/null
+++ b/codemirror_ui/images/silk/application_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_cascade.png b/codemirror_ui/images/silk/application_cascade.png
new file mode 100644
index 0000000..da5c622
--- /dev/null
+++ b/codemirror_ui/images/silk/application_cascade.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_delete.png b/codemirror_ui/images/silk/application_delete.png
new file mode 100644
index 0000000..0a335ac
--- /dev/null
+++ b/codemirror_ui/images/silk/application_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_double.png b/codemirror_ui/images/silk/application_double.png
new file mode 100644
index 0000000..647592f
--- /dev/null
+++ b/codemirror_ui/images/silk/application_double.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_edit.png b/codemirror_ui/images/silk/application_edit.png
new file mode 100644
index 0000000..fb2efb8
--- /dev/null
+++ b/codemirror_ui/images/silk/application_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_error.png b/codemirror_ui/images/silk/application_error.png
new file mode 100644
index 0000000..b35fa57
--- /dev/null
+++ b/codemirror_ui/images/silk/application_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_form.png b/codemirror_ui/images/silk/application_form.png
new file mode 100644
index 0000000..807b862
--- /dev/null
+++ b/codemirror_ui/images/silk/application_form.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_form_add.png b/codemirror_ui/images/silk/application_form_add.png
new file mode 100644
index 0000000..28c2175
--- /dev/null
+++ b/codemirror_ui/images/silk/application_form_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_form_delete.png b/codemirror_ui/images/silk/application_form_delete.png
new file mode 100644
index 0000000..cd305ec
--- /dev/null
+++ b/codemirror_ui/images/silk/application_form_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_form_edit.png b/codemirror_ui/images/silk/application_form_edit.png
new file mode 100644
index 0000000..af486c9
--- /dev/null
+++ b/codemirror_ui/images/silk/application_form_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_form_magnify.png b/codemirror_ui/images/silk/application_form_magnify.png
new file mode 100644
index 0000000..7b7fbd1
--- /dev/null
+++ b/codemirror_ui/images/silk/application_form_magnify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_get.png b/codemirror_ui/images/silk/application_get.png
new file mode 100644
index 0000000..28e41ea
--- /dev/null
+++ b/codemirror_ui/images/silk/application_get.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_go.png b/codemirror_ui/images/silk/application_go.png
new file mode 100644
index 0000000..5cc2b0d
--- /dev/null
+++ b/codemirror_ui/images/silk/application_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_home.png b/codemirror_ui/images/silk/application_home.png
new file mode 100644
index 0000000..b60d0c8
--- /dev/null
+++ b/codemirror_ui/images/silk/application_home.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_key.png b/codemirror_ui/images/silk/application_key.png
new file mode 100644
index 0000000..998d65c
--- /dev/null
+++ b/codemirror_ui/images/silk/application_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_lightning.png b/codemirror_ui/images/silk/application_lightning.png
new file mode 100644
index 0000000..7e91545
--- /dev/null
+++ b/codemirror_ui/images/silk/application_lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_link.png b/codemirror_ui/images/silk/application_link.png
new file mode 100644
index 0000000..f8fbb3e
--- /dev/null
+++ b/codemirror_ui/images/silk/application_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_osx.png b/codemirror_ui/images/silk/application_osx.png
new file mode 100644
index 0000000..9f022ec
--- /dev/null
+++ b/codemirror_ui/images/silk/application_osx.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_osx_terminal.png b/codemirror_ui/images/silk/application_osx_terminal.png
new file mode 100644
index 0000000..b3d8ce0
--- /dev/null
+++ b/codemirror_ui/images/silk/application_osx_terminal.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_put.png b/codemirror_ui/images/silk/application_put.png
new file mode 100644
index 0000000..c30cf59
--- /dev/null
+++ b/codemirror_ui/images/silk/application_put.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_side_boxes.png b/codemirror_ui/images/silk/application_side_boxes.png
new file mode 100644
index 0000000..efbf3c4
--- /dev/null
+++ b/codemirror_ui/images/silk/application_side_boxes.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_side_contract.png b/codemirror_ui/images/silk/application_side_contract.png
new file mode 100644
index 0000000..3585f94
--- /dev/null
+++ b/codemirror_ui/images/silk/application_side_contract.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_side_expand.png b/codemirror_ui/images/silk/application_side_expand.png
new file mode 100644
index 0000000..030cf7c
--- /dev/null
+++ b/codemirror_ui/images/silk/application_side_expand.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_side_list.png b/codemirror_ui/images/silk/application_side_list.png
new file mode 100644
index 0000000..248eaf1
--- /dev/null
+++ b/codemirror_ui/images/silk/application_side_list.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_side_tree.png b/codemirror_ui/images/silk/application_side_tree.png
new file mode 100644
index 0000000..f04a52b
--- /dev/null
+++ b/codemirror_ui/images/silk/application_side_tree.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_split.png b/codemirror_ui/images/silk/application_split.png
new file mode 100644
index 0000000..a91c78a
--- /dev/null
+++ b/codemirror_ui/images/silk/application_split.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_tile_horizontal.png b/codemirror_ui/images/silk/application_tile_horizontal.png
new file mode 100644
index 0000000..8a1191c
--- /dev/null
+++ b/codemirror_ui/images/silk/application_tile_horizontal.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_tile_vertical.png b/codemirror_ui/images/silk/application_tile_vertical.png
new file mode 100644
index 0000000..1d40383
--- /dev/null
+++ b/codemirror_ui/images/silk/application_tile_vertical.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_view_columns.png b/codemirror_ui/images/silk/application_view_columns.png
new file mode 100644
index 0000000..dc2e9d5
--- /dev/null
+++ b/codemirror_ui/images/silk/application_view_columns.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_view_detail.png b/codemirror_ui/images/silk/application_view_detail.png
new file mode 100644
index 0000000..aba044b
--- /dev/null
+++ b/codemirror_ui/images/silk/application_view_detail.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_view_gallery.png b/codemirror_ui/images/silk/application_view_gallery.png
new file mode 100644
index 0000000..851950d
--- /dev/null
+++ b/codemirror_ui/images/silk/application_view_gallery.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_view_icons.png b/codemirror_ui/images/silk/application_view_icons.png
new file mode 100644
index 0000000..6a93cda
--- /dev/null
+++ b/codemirror_ui/images/silk/application_view_icons.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_view_list.png b/codemirror_ui/images/silk/application_view_list.png
new file mode 100644
index 0000000..acc30b8
--- /dev/null
+++ b/codemirror_ui/images/silk/application_view_list.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_view_tile.png b/codemirror_ui/images/silk/application_view_tile.png
new file mode 100644
index 0000000..3bc0bd3
--- /dev/null
+++ b/codemirror_ui/images/silk/application_view_tile.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_xp.png b/codemirror_ui/images/silk/application_xp.png
new file mode 100644
index 0000000..d22860a
--- /dev/null
+++ b/codemirror_ui/images/silk/application_xp.png
Binary files differ
diff --git a/codemirror_ui/images/silk/application_xp_terminal.png b/codemirror_ui/images/silk/application_xp_terminal.png
new file mode 100644
index 0000000..c28dd63
--- /dev/null
+++ b/codemirror_ui/images/silk/application_xp_terminal.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_branch.png b/codemirror_ui/images/silk/arrow_branch.png
new file mode 100644
index 0000000..7542db1
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_branch.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_divide.png b/codemirror_ui/images/silk/arrow_divide.png
new file mode 100644
index 0000000..61a7b1d
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_divide.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_down.png b/codemirror_ui/images/silk/arrow_down.png
new file mode 100644
index 0000000..2c4e279
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_down.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_in.png b/codemirror_ui/images/silk/arrow_in.png
new file mode 100644
index 0000000..745c651
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_in.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_inout.png b/codemirror_ui/images/silk/arrow_inout.png
new file mode 100644
index 0000000..1b76367
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_inout.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_join.png b/codemirror_ui/images/silk/arrow_join.png
new file mode 100644
index 0000000..a128413
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_join.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_left.png b/codemirror_ui/images/silk/arrow_left.png
new file mode 100644
index 0000000..5dc6967
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_left.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_merge.png b/codemirror_ui/images/silk/arrow_merge.png
new file mode 100644
index 0000000..7502dbb
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_merge.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_out.png b/codemirror_ui/images/silk/arrow_out.png
new file mode 100644
index 0000000..2e9bc42
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_out.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_out_diag.png b/codemirror_ui/images/silk/arrow_out_diag.png
new file mode 100644
index 0000000..c10bbaf
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_out_diag.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_redo.png b/codemirror_ui/images/silk/arrow_redo.png
new file mode 100644
index 0000000..fdc394c
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_redo.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_refresh.png b/codemirror_ui/images/silk/arrow_refresh.png
new file mode 100644
index 0000000..0de2656
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_refresh.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_refresh_small.png b/codemirror_ui/images/silk/arrow_refresh_small.png
new file mode 100644
index 0000000..d3087df
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_refresh_small.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_right.png b/codemirror_ui/images/silk/arrow_right.png
new file mode 100644
index 0000000..b1a1819
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_right.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_rotate_anticlockwise.png b/codemirror_ui/images/silk/arrow_rotate_anticlockwise.png
new file mode 100644
index 0000000..46c75aa
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_rotate_anticlockwise.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_rotate_clockwise.png b/codemirror_ui/images/silk/arrow_rotate_clockwise.png
new file mode 100644
index 0000000..aa65210
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_rotate_clockwise.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_switch.png b/codemirror_ui/images/silk/arrow_switch.png
new file mode 100644
index 0000000..258c16c
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_switch.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_turn_left.png b/codemirror_ui/images/silk/arrow_turn_left.png
new file mode 100644
index 0000000..a3d6c9e
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_turn_left.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_turn_right.png b/codemirror_ui/images/silk/arrow_turn_right.png
new file mode 100644
index 0000000..629f20d
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_turn_right.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_undo.png b/codemirror_ui/images/silk/arrow_undo.png
new file mode 100644
index 0000000..6972c5e
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_undo.png
Binary files differ
diff --git a/codemirror_ui/images/silk/arrow_up.png b/codemirror_ui/images/silk/arrow_up.png
new file mode 100644
index 0000000..1ebb193
--- /dev/null
+++ b/codemirror_ui/images/silk/arrow_up.png
Binary files differ
diff --git a/codemirror_ui/images/silk/asterisk_orange.png b/codemirror_ui/images/silk/asterisk_orange.png
new file mode 100644
index 0000000..1ebebde
--- /dev/null
+++ b/codemirror_ui/images/silk/asterisk_orange.png
Binary files differ
diff --git a/codemirror_ui/images/silk/asterisk_yellow.png b/codemirror_ui/images/silk/asterisk_yellow.png
new file mode 100644
index 0000000..bab7cc9
--- /dev/null
+++ b/codemirror_ui/images/silk/asterisk_yellow.png
Binary files differ
diff --git a/codemirror_ui/images/silk/attach.png b/codemirror_ui/images/silk/attach.png
new file mode 100644
index 0000000..ea897cc
--- /dev/null
+++ b/codemirror_ui/images/silk/attach.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_add.png b/codemirror_ui/images/silk/award_star_add.png
new file mode 100644
index 0000000..9c4be9b
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_bronze_1.png b/codemirror_ui/images/silk/award_star_bronze_1.png
new file mode 100644
index 0000000..658c711
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_bronze_1.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_bronze_2.png b/codemirror_ui/images/silk/award_star_bronze_2.png
new file mode 100644
index 0000000..e47babd
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_bronze_2.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_bronze_3.png b/codemirror_ui/images/silk/award_star_bronze_3.png
new file mode 100644
index 0000000..396e4b3
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_bronze_3.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_delete.png b/codemirror_ui/images/silk/award_star_delete.png
new file mode 100644
index 0000000..4721b15
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_gold_1.png b/codemirror_ui/images/silk/award_star_gold_1.png
new file mode 100644
index 0000000..97a22b7
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_gold_1.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_gold_2.png b/codemirror_ui/images/silk/award_star_gold_2.png
new file mode 100644
index 0000000..0eaa571
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_gold_2.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_gold_3.png b/codemirror_ui/images/silk/award_star_gold_3.png
new file mode 100644
index 0000000..124c991
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_gold_3.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_silver_1.png b/codemirror_ui/images/silk/award_star_silver_1.png
new file mode 100644
index 0000000..028a546
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_silver_1.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_silver_2.png b/codemirror_ui/images/silk/award_star_silver_2.png
new file mode 100644
index 0000000..e487c3a
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_silver_2.png
Binary files differ
diff --git a/codemirror_ui/images/silk/award_star_silver_3.png b/codemirror_ui/images/silk/award_star_silver_3.png
new file mode 100644
index 0000000..1d72d47
--- /dev/null
+++ b/codemirror_ui/images/silk/award_star_silver_3.png
Binary files differ
diff --git a/codemirror_ui/images/silk/basket.png b/codemirror_ui/images/silk/basket.png
new file mode 100644
index 0000000..b0686d7
--- /dev/null
+++ b/codemirror_ui/images/silk/basket.png
Binary files differ
diff --git a/codemirror_ui/images/silk/basket_add.png b/codemirror_ui/images/silk/basket_add.png
new file mode 100644
index 0000000..3554368
--- /dev/null
+++ b/codemirror_ui/images/silk/basket_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/basket_delete.png b/codemirror_ui/images/silk/basket_delete.png
new file mode 100644
index 0000000..1349974
--- /dev/null
+++ b/codemirror_ui/images/silk/basket_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/basket_edit.png b/codemirror_ui/images/silk/basket_edit.png
new file mode 100644
index 0000000..8138bbd
--- /dev/null
+++ b/codemirror_ui/images/silk/basket_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/basket_error.png b/codemirror_ui/images/silk/basket_error.png
new file mode 100644
index 0000000..3978b29
--- /dev/null
+++ b/codemirror_ui/images/silk/basket_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/basket_go.png b/codemirror_ui/images/silk/basket_go.png
new file mode 100644
index 0000000..ed8b9a5
--- /dev/null
+++ b/codemirror_ui/images/silk/basket_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/basket_put.png b/codemirror_ui/images/silk/basket_put.png
new file mode 100644
index 0000000..be62faa
--- /dev/null
+++ b/codemirror_ui/images/silk/basket_put.png
Binary files differ
diff --git a/codemirror_ui/images/silk/basket_remove.png b/codemirror_ui/images/silk/basket_remove.png
new file mode 100644
index 0000000..04dd7fd
--- /dev/null
+++ b/codemirror_ui/images/silk/basket_remove.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bell.png b/codemirror_ui/images/silk/bell.png
new file mode 100644
index 0000000..6e0015d
--- /dev/null
+++ b/codemirror_ui/images/silk/bell.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bell_add.png b/codemirror_ui/images/silk/bell_add.png
new file mode 100644
index 0000000..7db01d6
--- /dev/null
+++ b/codemirror_ui/images/silk/bell_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bell_delete.png b/codemirror_ui/images/silk/bell_delete.png
new file mode 100644
index 0000000..23907bb
--- /dev/null
+++ b/codemirror_ui/images/silk/bell_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bell_error.png b/codemirror_ui/images/silk/bell_error.png
new file mode 100644
index 0000000..a0ddc00
--- /dev/null
+++ b/codemirror_ui/images/silk/bell_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bell_go.png b/codemirror_ui/images/silk/bell_go.png
new file mode 100644
index 0000000..b89bb34
--- /dev/null
+++ b/codemirror_ui/images/silk/bell_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bell_link.png b/codemirror_ui/images/silk/bell_link.png
new file mode 100644
index 0000000..b8c64af
--- /dev/null
+++ b/codemirror_ui/images/silk/bell_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bin.png b/codemirror_ui/images/silk/bin.png
new file mode 100644
index 0000000..ebad933
--- /dev/null
+++ b/codemirror_ui/images/silk/bin.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bin_closed.png b/codemirror_ui/images/silk/bin_closed.png
new file mode 100644
index 0000000..afe22ba
--- /dev/null
+++ b/codemirror_ui/images/silk/bin_closed.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bin_empty.png b/codemirror_ui/images/silk/bin_empty.png
new file mode 100644
index 0000000..375b8bf
--- /dev/null
+++ b/codemirror_ui/images/silk/bin_empty.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bomb.png b/codemirror_ui/images/silk/bomb.png
new file mode 100644
index 0000000..1be3797
--- /dev/null
+++ b/codemirror_ui/images/silk/bomb.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book.png b/codemirror_ui/images/silk/book.png
new file mode 100644
index 0000000..b0f4dd7
--- /dev/null
+++ b/codemirror_ui/images/silk/book.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_add.png b/codemirror_ui/images/silk/book_add.png
new file mode 100644
index 0000000..e2f0847
--- /dev/null
+++ b/codemirror_ui/images/silk/book_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_addresses.png b/codemirror_ui/images/silk/book_addresses.png
new file mode 100644
index 0000000..b73419b
--- /dev/null
+++ b/codemirror_ui/images/silk/book_addresses.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_delete.png b/codemirror_ui/images/silk/book_delete.png
new file mode 100644
index 0000000..d9a6340
--- /dev/null
+++ b/codemirror_ui/images/silk/book_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_edit.png b/codemirror_ui/images/silk/book_edit.png
new file mode 100644
index 0000000..6e756cc
--- /dev/null
+++ b/codemirror_ui/images/silk/book_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_error.png b/codemirror_ui/images/silk/book_error.png
new file mode 100644
index 0000000..f3fbed0
--- /dev/null
+++ b/codemirror_ui/images/silk/book_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_go.png b/codemirror_ui/images/silk/book_go.png
new file mode 100644
index 0000000..cd4e196
--- /dev/null
+++ b/codemirror_ui/images/silk/book_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_key.png b/codemirror_ui/images/silk/book_key.png
new file mode 100644
index 0000000..d8e23ec
--- /dev/null
+++ b/codemirror_ui/images/silk/book_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_link.png b/codemirror_ui/images/silk/book_link.png
new file mode 100644
index 0000000..dd0820e
--- /dev/null
+++ b/codemirror_ui/images/silk/book_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_next.png b/codemirror_ui/images/silk/book_next.png
new file mode 100644
index 0000000..ff2ea1a
--- /dev/null
+++ b/codemirror_ui/images/silk/book_next.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_open.png b/codemirror_ui/images/silk/book_open.png
new file mode 100644
index 0000000..7d863f9
--- /dev/null
+++ b/codemirror_ui/images/silk/book_open.png
Binary files differ
diff --git a/codemirror_ui/images/silk/book_previous.png b/codemirror_ui/images/silk/book_previous.png
new file mode 100644
index 0000000..2e53c69
--- /dev/null
+++ b/codemirror_ui/images/silk/book_previous.png
Binary files differ
diff --git a/codemirror_ui/images/silk/box.png b/codemirror_ui/images/silk/box.png
new file mode 100644
index 0000000..8443c23
--- /dev/null
+++ b/codemirror_ui/images/silk/box.png
Binary files differ
diff --git a/codemirror_ui/images/silk/brick.png b/codemirror_ui/images/silk/brick.png
new file mode 100644
index 0000000..7851cf3
--- /dev/null
+++ b/codemirror_ui/images/silk/brick.png
Binary files differ
diff --git a/codemirror_ui/images/silk/brick_add.png b/codemirror_ui/images/silk/brick_add.png
new file mode 100644
index 0000000..fac186b
--- /dev/null
+++ b/codemirror_ui/images/silk/brick_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/brick_delete.png b/codemirror_ui/images/silk/brick_delete.png
new file mode 100644
index 0000000..3a8c373
--- /dev/null
+++ b/codemirror_ui/images/silk/brick_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/brick_edit.png b/codemirror_ui/images/silk/brick_edit.png
new file mode 100644
index 0000000..eb06df3
--- /dev/null
+++ b/codemirror_ui/images/silk/brick_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/brick_error.png b/codemirror_ui/images/silk/brick_error.png
new file mode 100644
index 0000000..18ab01e
--- /dev/null
+++ b/codemirror_ui/images/silk/brick_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/brick_go.png b/codemirror_ui/images/silk/brick_go.png
new file mode 100644
index 0000000..fe0d335
--- /dev/null
+++ b/codemirror_ui/images/silk/brick_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/brick_link.png b/codemirror_ui/images/silk/brick_link.png
new file mode 100644
index 0000000..9ebf013
--- /dev/null
+++ b/codemirror_ui/images/silk/brick_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bricks.png b/codemirror_ui/images/silk/bricks.png
new file mode 100644
index 0000000..0905f93
--- /dev/null
+++ b/codemirror_ui/images/silk/bricks.png
Binary files differ
diff --git a/codemirror_ui/images/silk/briefcase.png b/codemirror_ui/images/silk/briefcase.png
new file mode 100644
index 0000000..05c5649
--- /dev/null
+++ b/codemirror_ui/images/silk/briefcase.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bug.png b/codemirror_ui/images/silk/bug.png
new file mode 100644
index 0000000..2d5fb90
--- /dev/null
+++ b/codemirror_ui/images/silk/bug.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bug_add.png b/codemirror_ui/images/silk/bug_add.png
new file mode 100644
index 0000000..ced7817
--- /dev/null
+++ b/codemirror_ui/images/silk/bug_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bug_delete.png b/codemirror_ui/images/silk/bug_delete.png
new file mode 100644
index 0000000..e81d757
--- /dev/null
+++ b/codemirror_ui/images/silk/bug_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bug_edit.png b/codemirror_ui/images/silk/bug_edit.png
new file mode 100644
index 0000000..e5c7dc0
--- /dev/null
+++ b/codemirror_ui/images/silk/bug_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bug_error.png b/codemirror_ui/images/silk/bug_error.png
new file mode 100644
index 0000000..c4e8c28
--- /dev/null
+++ b/codemirror_ui/images/silk/bug_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bug_go.png b/codemirror_ui/images/silk/bug_go.png
new file mode 100644
index 0000000..4e4ae99
--- /dev/null
+++ b/codemirror_ui/images/silk/bug_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bug_link.png b/codemirror_ui/images/silk/bug_link.png
new file mode 100644
index 0000000..30e25ab
--- /dev/null
+++ b/codemirror_ui/images/silk/bug_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/building.png b/codemirror_ui/images/silk/building.png
new file mode 100644
index 0000000..11a017c
--- /dev/null
+++ b/codemirror_ui/images/silk/building.png
Binary files differ
diff --git a/codemirror_ui/images/silk/building_add.png b/codemirror_ui/images/silk/building_add.png
new file mode 100644
index 0000000..d88e2b9
--- /dev/null
+++ b/codemirror_ui/images/silk/building_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/building_delete.png b/codemirror_ui/images/silk/building_delete.png
new file mode 100644
index 0000000..db6455d
--- /dev/null
+++ b/codemirror_ui/images/silk/building_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/building_edit.png b/codemirror_ui/images/silk/building_edit.png
new file mode 100644
index 0000000..646db36
--- /dev/null
+++ b/codemirror_ui/images/silk/building_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/building_error.png b/codemirror_ui/images/silk/building_error.png
new file mode 100644
index 0000000..a342eef
--- /dev/null
+++ b/codemirror_ui/images/silk/building_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/building_go.png b/codemirror_ui/images/silk/building_go.png
new file mode 100644
index 0000000..cdcbcb3
--- /dev/null
+++ b/codemirror_ui/images/silk/building_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/building_key.png b/codemirror_ui/images/silk/building_key.png
new file mode 100644
index 0000000..8b79e30
--- /dev/null
+++ b/codemirror_ui/images/silk/building_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/building_link.png b/codemirror_ui/images/silk/building_link.png
new file mode 100644
index 0000000..a340629
--- /dev/null
+++ b/codemirror_ui/images/silk/building_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_add.png b/codemirror_ui/images/silk/bullet_add.png
new file mode 100644
index 0000000..41ff833
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_arrow_bottom.png b/codemirror_ui/images/silk/bullet_arrow_bottom.png
new file mode 100644
index 0000000..1a28d82
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_arrow_bottom.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_arrow_down.png b/codemirror_ui/images/silk/bullet_arrow_down.png
new file mode 100644
index 0000000..9b23c06
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_arrow_down.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_arrow_top.png b/codemirror_ui/images/silk/bullet_arrow_top.png
new file mode 100644
index 0000000..0ce86d2
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_arrow_top.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_arrow_up.png b/codemirror_ui/images/silk/bullet_arrow_up.png
new file mode 100644
index 0000000..24df0f4
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_arrow_up.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_black.png b/codemirror_ui/images/silk/bullet_black.png
new file mode 100644
index 0000000..5761970
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_black.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_blue.png b/codemirror_ui/images/silk/bullet_blue.png
new file mode 100644
index 0000000..a7651ec
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_delete.png b/codemirror_ui/images/silk/bullet_delete.png
new file mode 100644
index 0000000..bd6271b
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_disk.png b/codemirror_ui/images/silk/bullet_disk.png
new file mode 100644
index 0000000..209c6a7
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_disk.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_error.png b/codemirror_ui/images/silk/bullet_error.png
new file mode 100644
index 0000000..bca2b49
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_feed.png b/codemirror_ui/images/silk/bullet_feed.png
new file mode 100644
index 0000000..1a0e0f1
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_feed.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_go.png b/codemirror_ui/images/silk/bullet_go.png
new file mode 100644
index 0000000..bc4faa7
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_green.png b/codemirror_ui/images/silk/bullet_green.png
new file mode 100644
index 0000000..058ad26
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_green.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_key.png b/codemirror_ui/images/silk/bullet_key.png
new file mode 100644
index 0000000..3d37f2e
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_orange.png b/codemirror_ui/images/silk/bullet_orange.png
new file mode 100644
index 0000000..fa63024
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_orange.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_picture.png b/codemirror_ui/images/silk/bullet_picture.png
new file mode 100644
index 0000000..386cb30
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_picture.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_pink.png b/codemirror_ui/images/silk/bullet_pink.png
new file mode 100644
index 0000000..0c9f73e
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_pink.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_purple.png b/codemirror_ui/images/silk/bullet_purple.png
new file mode 100644
index 0000000..52ba503
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_purple.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_red.png b/codemirror_ui/images/silk/bullet_red.png
new file mode 100644
index 0000000..0cd8031
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_red.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_star.png b/codemirror_ui/images/silk/bullet_star.png
new file mode 100644
index 0000000..fab774a
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_star.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_toggle_minus.png b/codemirror_ui/images/silk/bullet_toggle_minus.png
new file mode 100644
index 0000000..b47ce55
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_toggle_minus.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_toggle_plus.png b/codemirror_ui/images/silk/bullet_toggle_plus.png
new file mode 100644
index 0000000..9ab4a89
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_toggle_plus.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_white.png b/codemirror_ui/images/silk/bullet_white.png
new file mode 100644
index 0000000..a9af8d4
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_white.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_wrench.png b/codemirror_ui/images/silk/bullet_wrench.png
new file mode 100644
index 0000000..67817e6
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_wrench.png
Binary files differ
diff --git a/codemirror_ui/images/silk/bullet_yellow.png b/codemirror_ui/images/silk/bullet_yellow.png
new file mode 100644
index 0000000..6469cea
--- /dev/null
+++ b/codemirror_ui/images/silk/bullet_yellow.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cake.png b/codemirror_ui/images/silk/cake.png
new file mode 100644
index 0000000..4ef151a
--- /dev/null
+++ b/codemirror_ui/images/silk/cake.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calculator.png b/codemirror_ui/images/silk/calculator.png
new file mode 100644
index 0000000..701a60a
--- /dev/null
+++ b/codemirror_ui/images/silk/calculator.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calculator_add.png b/codemirror_ui/images/silk/calculator_add.png
new file mode 100644
index 0000000..fd377bd
--- /dev/null
+++ b/codemirror_ui/images/silk/calculator_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calculator_delete.png b/codemirror_ui/images/silk/calculator_delete.png
new file mode 100644
index 0000000..ac96170
--- /dev/null
+++ b/codemirror_ui/images/silk/calculator_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calculator_edit.png b/codemirror_ui/images/silk/calculator_edit.png
new file mode 100644
index 0000000..63b06b9
--- /dev/null
+++ b/codemirror_ui/images/silk/calculator_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calculator_error.png b/codemirror_ui/images/silk/calculator_error.png
new file mode 100644
index 0000000..0bc4288
--- /dev/null
+++ b/codemirror_ui/images/silk/calculator_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calculator_link.png b/codemirror_ui/images/silk/calculator_link.png
new file mode 100644
index 0000000..a2a8fe6
--- /dev/null
+++ b/codemirror_ui/images/silk/calculator_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calendar.png b/codemirror_ui/images/silk/calendar.png
new file mode 100644
index 0000000..6589138
--- /dev/null
+++ b/codemirror_ui/images/silk/calendar.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calendar_add.png b/codemirror_ui/images/silk/calendar_add.png
new file mode 100644
index 0000000..17679db
--- /dev/null
+++ b/codemirror_ui/images/silk/calendar_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calendar_delete.png b/codemirror_ui/images/silk/calendar_delete.png
new file mode 100644
index 0000000..69a3b10
--- /dev/null
+++ b/codemirror_ui/images/silk/calendar_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calendar_edit.png b/codemirror_ui/images/silk/calendar_edit.png
new file mode 100644
index 0000000..d1d2d6e
--- /dev/null
+++ b/codemirror_ui/images/silk/calendar_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calendar_link.png b/codemirror_ui/images/silk/calendar_link.png
new file mode 100644
index 0000000..6b106b9
--- /dev/null
+++ b/codemirror_ui/images/silk/calendar_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calendar_view_day.png b/codemirror_ui/images/silk/calendar_view_day.png
new file mode 100644
index 0000000..9740f76
--- /dev/null
+++ b/codemirror_ui/images/silk/calendar_view_day.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calendar_view_month.png b/codemirror_ui/images/silk/calendar_view_month.png
new file mode 100644
index 0000000..6cff76c
--- /dev/null
+++ b/codemirror_ui/images/silk/calendar_view_month.png
Binary files differ
diff --git a/codemirror_ui/images/silk/calendar_view_week.png b/codemirror_ui/images/silk/calendar_view_week.png
new file mode 100644
index 0000000..8fe695f
--- /dev/null
+++ b/codemirror_ui/images/silk/calendar_view_week.png
Binary files differ
diff --git a/codemirror_ui/images/silk/camera.png b/codemirror_ui/images/silk/camera.png
new file mode 100644
index 0000000..8536d1a
--- /dev/null
+++ b/codemirror_ui/images/silk/camera.png
Binary files differ
diff --git a/codemirror_ui/images/silk/camera_add.png b/codemirror_ui/images/silk/camera_add.png
new file mode 100644
index 0000000..08b5da9
--- /dev/null
+++ b/codemirror_ui/images/silk/camera_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/camera_delete.png b/codemirror_ui/images/silk/camera_delete.png
new file mode 100644
index 0000000..3846d74
--- /dev/null
+++ b/codemirror_ui/images/silk/camera_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/camera_edit.png b/codemirror_ui/images/silk/camera_edit.png
new file mode 100644
index 0000000..b5015b1
--- /dev/null
+++ b/codemirror_ui/images/silk/camera_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/camera_error.png b/codemirror_ui/images/silk/camera_error.png
new file mode 100644
index 0000000..3c1bc95
--- /dev/null
+++ b/codemirror_ui/images/silk/camera_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/camera_go.png b/codemirror_ui/images/silk/camera_go.png
new file mode 100644
index 0000000..94ce2b2
--- /dev/null
+++ b/codemirror_ui/images/silk/camera_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/camera_link.png b/codemirror_ui/images/silk/camera_link.png
new file mode 100644
index 0000000..d2ac9f9
--- /dev/null
+++ b/codemirror_ui/images/silk/camera_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/camera_small.png b/codemirror_ui/images/silk/camera_small.png
new file mode 100644
index 0000000..454b0b0
--- /dev/null
+++ b/codemirror_ui/images/silk/camera_small.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cancel.png b/codemirror_ui/images/silk/cancel.png
new file mode 100644
index 0000000..c149c2b
--- /dev/null
+++ b/codemirror_ui/images/silk/cancel.png
Binary files differ
diff --git a/codemirror_ui/images/silk/car.png b/codemirror_ui/images/silk/car.png
new file mode 100644
index 0000000..4f3a770
--- /dev/null
+++ b/codemirror_ui/images/silk/car.png
Binary files differ
diff --git a/codemirror_ui/images/silk/car_add.png b/codemirror_ui/images/silk/car_add.png
new file mode 100644
index 0000000..1215a51
--- /dev/null
+++ b/codemirror_ui/images/silk/car_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/car_delete.png b/codemirror_ui/images/silk/car_delete.png
new file mode 100644
index 0000000..2803b56
--- /dev/null
+++ b/codemirror_ui/images/silk/car_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cart.png b/codemirror_ui/images/silk/cart.png
new file mode 100644
index 0000000..1baf7b9
--- /dev/null
+++ b/codemirror_ui/images/silk/cart.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cart_add.png b/codemirror_ui/images/silk/cart_add.png
new file mode 100644
index 0000000..45c2900
--- /dev/null
+++ b/codemirror_ui/images/silk/cart_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cart_delete.png b/codemirror_ui/images/silk/cart_delete.png
new file mode 100644
index 0000000..ac5bce5
--- /dev/null
+++ b/codemirror_ui/images/silk/cart_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cart_edit.png b/codemirror_ui/images/silk/cart_edit.png
new file mode 100644
index 0000000..b94ff88
--- /dev/null
+++ b/codemirror_ui/images/silk/cart_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cart_error.png b/codemirror_ui/images/silk/cart_error.png
new file mode 100644
index 0000000..144c835
--- /dev/null
+++ b/codemirror_ui/images/silk/cart_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cart_go.png b/codemirror_ui/images/silk/cart_go.png
new file mode 100644
index 0000000..20ee058
--- /dev/null
+++ b/codemirror_ui/images/silk/cart_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cart_put.png b/codemirror_ui/images/silk/cart_put.png
new file mode 100644
index 0000000..3aec353
--- /dev/null
+++ b/codemirror_ui/images/silk/cart_put.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cart_remove.png b/codemirror_ui/images/silk/cart_remove.png
new file mode 100644
index 0000000..360217b
--- /dev/null
+++ b/codemirror_ui/images/silk/cart_remove.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cd.png b/codemirror_ui/images/silk/cd.png
new file mode 100644
index 0000000..ef43223
--- /dev/null
+++ b/codemirror_ui/images/silk/cd.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cd_add.png b/codemirror_ui/images/silk/cd_add.png
new file mode 100644
index 0000000..b0254ef
--- /dev/null
+++ b/codemirror_ui/images/silk/cd_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cd_burn.png b/codemirror_ui/images/silk/cd_burn.png
new file mode 100644
index 0000000..157cb0b
--- /dev/null
+++ b/codemirror_ui/images/silk/cd_burn.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cd_delete.png b/codemirror_ui/images/silk/cd_delete.png
new file mode 100644
index 0000000..7d7b3d5
--- /dev/null
+++ b/codemirror_ui/images/silk/cd_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cd_edit.png b/codemirror_ui/images/silk/cd_edit.png
new file mode 100644
index 0000000..b0dc194
--- /dev/null
+++ b/codemirror_ui/images/silk/cd_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cd_eject.png b/codemirror_ui/images/silk/cd_eject.png
new file mode 100644
index 0000000..762932f
--- /dev/null
+++ b/codemirror_ui/images/silk/cd_eject.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cd_go.png b/codemirror_ui/images/silk/cd_go.png
new file mode 100644
index 0000000..13e0499
--- /dev/null
+++ b/codemirror_ui/images/silk/cd_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_bar.png b/codemirror_ui/images/silk/chart_bar.png
new file mode 100644
index 0000000..9051fbc
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_bar.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_bar_add.png b/codemirror_ui/images/silk/chart_bar_add.png
new file mode 100644
index 0000000..d283e84
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_bar_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_bar_delete.png b/codemirror_ui/images/silk/chart_bar_delete.png
new file mode 100644
index 0000000..259f686
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_bar_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_bar_edit.png b/codemirror_ui/images/silk/chart_bar_edit.png
new file mode 100644
index 0000000..df64d97
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_bar_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_bar_error.png b/codemirror_ui/images/silk/chart_bar_error.png
new file mode 100644
index 0000000..bdacea5
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_bar_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_bar_link.png b/codemirror_ui/images/silk/chart_bar_link.png
new file mode 100644
index 0000000..bf18aed
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_bar_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_curve.png b/codemirror_ui/images/silk/chart_curve.png
new file mode 100644
index 0000000..01e933a
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_curve.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_curve_add.png b/codemirror_ui/images/silk/chart_curve_add.png
new file mode 100644
index 0000000..f9e2050
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_curve_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_curve_delete.png b/codemirror_ui/images/silk/chart_curve_delete.png
new file mode 100644
index 0000000..b411391
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_curve_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_curve_edit.png b/codemirror_ui/images/silk/chart_curve_edit.png
new file mode 100644
index 0000000..bd07673
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_curve_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_curve_error.png b/codemirror_ui/images/silk/chart_curve_error.png
new file mode 100644
index 0000000..906dd03
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_curve_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_curve_go.png b/codemirror_ui/images/silk/chart_curve_go.png
new file mode 100644
index 0000000..ac9eda5
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_curve_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_curve_link.png b/codemirror_ui/images/silk/chart_curve_link.png
new file mode 100644
index 0000000..144eafe
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_curve_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_line.png b/codemirror_ui/images/silk/chart_line.png
new file mode 100644
index 0000000..85020f3
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_line.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_line_add.png b/codemirror_ui/images/silk/chart_line_add.png
new file mode 100644
index 0000000..5571a5e
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_line_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_line_delete.png b/codemirror_ui/images/silk/chart_line_delete.png
new file mode 100644
index 0000000..5b0aa90
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_line_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_line_edit.png b/codemirror_ui/images/silk/chart_line_edit.png
new file mode 100644
index 0000000..9cf6607
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_line_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_line_error.png b/codemirror_ui/images/silk/chart_line_error.png
new file mode 100644
index 0000000..ff23c03
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_line_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_line_link.png b/codemirror_ui/images/silk/chart_line_link.png
new file mode 100644
index 0000000..f3727d2
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_line_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_organisation.png b/codemirror_ui/images/silk/chart_organisation.png
new file mode 100644
index 0000000..c32d25c
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_organisation.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_organisation_add.png b/codemirror_ui/images/silk/chart_organisation_add.png
new file mode 100644
index 0000000..f0dba4a
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_organisation_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_organisation_delete.png b/codemirror_ui/images/silk/chart_organisation_delete.png
new file mode 100644
index 0000000..7dc8dca
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_organisation_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_pie.png b/codemirror_ui/images/silk/chart_pie.png
new file mode 100644
index 0000000..fe00fa0
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_pie.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_pie_add.png b/codemirror_ui/images/silk/chart_pie_add.png
new file mode 100644
index 0000000..bf0822e
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_pie_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_pie_delete.png b/codemirror_ui/images/silk/chart_pie_delete.png
new file mode 100644
index 0000000..5ab9efd
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_pie_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_pie_edit.png b/codemirror_ui/images/silk/chart_pie_edit.png
new file mode 100644
index 0000000..3debc12
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_pie_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_pie_error.png b/codemirror_ui/images/silk/chart_pie_error.png
new file mode 100644
index 0000000..7344174
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_pie_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/chart_pie_link.png b/codemirror_ui/images/silk/chart_pie_link.png
new file mode 100644
index 0000000..c072f8e
--- /dev/null
+++ b/codemirror_ui/images/silk/chart_pie_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock.png b/codemirror_ui/images/silk/clock.png
new file mode 100644
index 0000000..e2672c2
--- /dev/null
+++ b/codemirror_ui/images/silk/clock.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_add.png b/codemirror_ui/images/silk/clock_add.png
new file mode 100644
index 0000000..598b839
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_delete.png b/codemirror_ui/images/silk/clock_delete.png
new file mode 100644
index 0000000..8bf9efe
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_edit.png b/codemirror_ui/images/silk/clock_edit.png
new file mode 100644
index 0000000..7d35718
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_error.png b/codemirror_ui/images/silk/clock_error.png
new file mode 100644
index 0000000..a7c461b
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_go.png b/codemirror_ui/images/silk/clock_go.png
new file mode 100644
index 0000000..a1a24d3
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_link.png b/codemirror_ui/images/silk/clock_link.png
new file mode 100644
index 0000000..481cf04
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_pause.png b/codemirror_ui/images/silk/clock_pause.png
new file mode 100644
index 0000000..ba74725
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_pause.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_play.png b/codemirror_ui/images/silk/clock_play.png
new file mode 100644
index 0000000..fb4ebc8
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_play.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_red.png b/codemirror_ui/images/silk/clock_red.png
new file mode 100644
index 0000000..2842cc3
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_red.png
Binary files differ
diff --git a/codemirror_ui/images/silk/clock_stop.png b/codemirror_ui/images/silk/clock_stop.png
new file mode 100644
index 0000000..6fe8a6f
--- /dev/null
+++ b/codemirror_ui/images/silk/clock_stop.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cog.png b/codemirror_ui/images/silk/cog.png
new file mode 100644
index 0000000..67de2c6
--- /dev/null
+++ b/codemirror_ui/images/silk/cog.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cog_add.png b/codemirror_ui/images/silk/cog_add.png
new file mode 100644
index 0000000..04f22ba
--- /dev/null
+++ b/codemirror_ui/images/silk/cog_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cog_delete.png b/codemirror_ui/images/silk/cog_delete.png
new file mode 100644
index 0000000..8ce71c4
--- /dev/null
+++ b/codemirror_ui/images/silk/cog_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cog_edit.png b/codemirror_ui/images/silk/cog_edit.png
new file mode 100644
index 0000000..47b75a4
--- /dev/null
+++ b/codemirror_ui/images/silk/cog_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cog_error.png b/codemirror_ui/images/silk/cog_error.png
new file mode 100644
index 0000000..4766743
--- /dev/null
+++ b/codemirror_ui/images/silk/cog_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cog_go.png b/codemirror_ui/images/silk/cog_go.png
new file mode 100644
index 0000000..3262767
--- /dev/null
+++ b/codemirror_ui/images/silk/cog_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/coins.png b/codemirror_ui/images/silk/coins.png
new file mode 100644
index 0000000..0ca9074
--- /dev/null
+++ b/codemirror_ui/images/silk/coins.png
Binary files differ
diff --git a/codemirror_ui/images/silk/coins_add.png b/codemirror_ui/images/silk/coins_add.png
new file mode 100644
index 0000000..cdff5d3
--- /dev/null
+++ b/codemirror_ui/images/silk/coins_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/coins_delete.png b/codemirror_ui/images/silk/coins_delete.png
new file mode 100644
index 0000000..18e0c0f
--- /dev/null
+++ b/codemirror_ui/images/silk/coins_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/color_swatch.png b/codemirror_ui/images/silk/color_swatch.png
new file mode 100644
index 0000000..6e6e852
--- /dev/null
+++ b/codemirror_ui/images/silk/color_swatch.png
Binary files differ
diff --git a/codemirror_ui/images/silk/color_wheel.png b/codemirror_ui/images/silk/color_wheel.png
new file mode 100644
index 0000000..809fb00
--- /dev/null
+++ b/codemirror_ui/images/silk/color_wheel.png
Binary files differ
diff --git a/codemirror_ui/images/silk/comment.png b/codemirror_ui/images/silk/comment.png
new file mode 100644
index 0000000..7bc9233
--- /dev/null
+++ b/codemirror_ui/images/silk/comment.png
Binary files differ
diff --git a/codemirror_ui/images/silk/comment_add.png b/codemirror_ui/images/silk/comment_add.png
new file mode 100644
index 0000000..75e78de
--- /dev/null
+++ b/codemirror_ui/images/silk/comment_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/comment_delete.png b/codemirror_ui/images/silk/comment_delete.png
new file mode 100644
index 0000000..643fdbe
--- /dev/null
+++ b/codemirror_ui/images/silk/comment_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/comment_edit.png b/codemirror_ui/images/silk/comment_edit.png
new file mode 100644
index 0000000..73db110
--- /dev/null
+++ b/codemirror_ui/images/silk/comment_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/comments.png b/codemirror_ui/images/silk/comments.png
new file mode 100644
index 0000000..39433cf
--- /dev/null
+++ b/codemirror_ui/images/silk/comments.png
Binary files differ
diff --git a/codemirror_ui/images/silk/comments_add.png b/codemirror_ui/images/silk/comments_add.png
new file mode 100644
index 0000000..b325634
--- /dev/null
+++ b/codemirror_ui/images/silk/comments_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/comments_delete.png b/codemirror_ui/images/silk/comments_delete.png
new file mode 100644
index 0000000..6df7376
--- /dev/null
+++ b/codemirror_ui/images/silk/comments_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/compress.png b/codemirror_ui/images/silk/compress.png
new file mode 100644
index 0000000..8606ff0
--- /dev/null
+++ b/codemirror_ui/images/silk/compress.png
Binary files differ
diff --git a/codemirror_ui/images/silk/computer.png b/codemirror_ui/images/silk/computer.png
new file mode 100644
index 0000000..9bc37dc
--- /dev/null
+++ b/codemirror_ui/images/silk/computer.png
Binary files differ
diff --git a/codemirror_ui/images/silk/computer_add.png b/codemirror_ui/images/silk/computer_add.png
new file mode 100644
index 0000000..db604ee
--- /dev/null
+++ b/codemirror_ui/images/silk/computer_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/computer_delete.png b/codemirror_ui/images/silk/computer_delete.png
new file mode 100644
index 0000000..5e9b268
--- /dev/null
+++ b/codemirror_ui/images/silk/computer_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/computer_edit.png b/codemirror_ui/images/silk/computer_edit.png
new file mode 100644
index 0000000..34c72fe
--- /dev/null
+++ b/codemirror_ui/images/silk/computer_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/computer_error.png b/codemirror_ui/images/silk/computer_error.png
new file mode 100644
index 0000000..b2c3ed5
--- /dev/null
+++ b/codemirror_ui/images/silk/computer_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/computer_go.png b/codemirror_ui/images/silk/computer_go.png
new file mode 100644
index 0000000..0b26144
--- /dev/null
+++ b/codemirror_ui/images/silk/computer_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/computer_key.png b/codemirror_ui/images/silk/computer_key.png
new file mode 100644
index 0000000..eca5430
--- /dev/null
+++ b/codemirror_ui/images/silk/computer_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/computer_link.png b/codemirror_ui/images/silk/computer_link.png
new file mode 100644
index 0000000..3859db2
--- /dev/null
+++ b/codemirror_ui/images/silk/computer_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/connect.png b/codemirror_ui/images/silk/connect.png
new file mode 100644
index 0000000..024138e
--- /dev/null
+++ b/codemirror_ui/images/silk/connect.png
Binary files differ
diff --git a/codemirror_ui/images/silk/contrast.png b/codemirror_ui/images/silk/contrast.png
new file mode 100644
index 0000000..adcc004
--- /dev/null
+++ b/codemirror_ui/images/silk/contrast.png
Binary files differ
diff --git a/codemirror_ui/images/silk/contrast_decrease.png b/codemirror_ui/images/silk/contrast_decrease.png
new file mode 100644
index 0000000..0155bf5
--- /dev/null
+++ b/codemirror_ui/images/silk/contrast_decrease.png
Binary files differ
diff --git a/codemirror_ui/images/silk/contrast_high.png b/codemirror_ui/images/silk/contrast_high.png
new file mode 100644
index 0000000..d87c8cb
--- /dev/null
+++ b/codemirror_ui/images/silk/contrast_high.png
Binary files differ
diff --git a/codemirror_ui/images/silk/contrast_increase.png b/codemirror_ui/images/silk/contrast_increase.png
new file mode 100644
index 0000000..a3e7f52
--- /dev/null
+++ b/codemirror_ui/images/silk/contrast_increase.png
Binary files differ
diff --git a/codemirror_ui/images/silk/contrast_low.png b/codemirror_ui/images/silk/contrast_low.png
new file mode 100644
index 0000000..dc9f4b1
--- /dev/null
+++ b/codemirror_ui/images/silk/contrast_low.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_eject.png b/codemirror_ui/images/silk/control_eject.png
new file mode 100644
index 0000000..924d817
--- /dev/null
+++ b/codemirror_ui/images/silk/control_eject.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_eject_blue.png b/codemirror_ui/images/silk/control_eject_blue.png
new file mode 100644
index 0000000..2bd4963
--- /dev/null
+++ b/codemirror_ui/images/silk/control_eject_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_end.png b/codemirror_ui/images/silk/control_end.png
new file mode 100644
index 0000000..036e04d
--- /dev/null
+++ b/codemirror_ui/images/silk/control_end.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_end_blue.png b/codemirror_ui/images/silk/control_end_blue.png
new file mode 100644
index 0000000..7207935
--- /dev/null
+++ b/codemirror_ui/images/silk/control_end_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_equalizer.png b/codemirror_ui/images/silk/control_equalizer.png
new file mode 100644
index 0000000..4606087
--- /dev/null
+++ b/codemirror_ui/images/silk/control_equalizer.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_equalizer_blue.png b/codemirror_ui/images/silk/control_equalizer_blue.png
new file mode 100644
index 0000000..1b2e6a3
--- /dev/null
+++ b/codemirror_ui/images/silk/control_equalizer_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_fastforward.png b/codemirror_ui/images/silk/control_fastforward.png
new file mode 100644
index 0000000..31f7fd3
--- /dev/null
+++ b/codemirror_ui/images/silk/control_fastforward.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_fastforward_blue.png b/codemirror_ui/images/silk/control_fastforward_blue.png
new file mode 100644
index 0000000..4a2f9d4
--- /dev/null
+++ b/codemirror_ui/images/silk/control_fastforward_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_pause.png b/codemirror_ui/images/silk/control_pause.png
new file mode 100644
index 0000000..2d9ce9c
--- /dev/null
+++ b/codemirror_ui/images/silk/control_pause.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_pause_blue.png b/codemirror_ui/images/silk/control_pause_blue.png
new file mode 100644
index 0000000..ec61099
--- /dev/null
+++ b/codemirror_ui/images/silk/control_pause_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_play.png b/codemirror_ui/images/silk/control_play.png
new file mode 100644
index 0000000..0846555
--- /dev/null
+++ b/codemirror_ui/images/silk/control_play.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_play_blue.png b/codemirror_ui/images/silk/control_play_blue.png
new file mode 100644
index 0000000..f8c8ec6
--- /dev/null
+++ b/codemirror_ui/images/silk/control_play_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_repeat.png b/codemirror_ui/images/silk/control_repeat.png
new file mode 100644
index 0000000..1c4f57a
--- /dev/null
+++ b/codemirror_ui/images/silk/control_repeat.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_repeat_blue.png b/codemirror_ui/images/silk/control_repeat_blue.png
new file mode 100644
index 0000000..406ec33
--- /dev/null
+++ b/codemirror_ui/images/silk/control_repeat_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_rewind.png b/codemirror_ui/images/silk/control_rewind.png
new file mode 100644
index 0000000..c029447
--- /dev/null
+++ b/codemirror_ui/images/silk/control_rewind.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_rewind_blue.png b/codemirror_ui/images/silk/control_rewind_blue.png
new file mode 100644
index 0000000..15d1584
--- /dev/null
+++ b/codemirror_ui/images/silk/control_rewind_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_start.png b/codemirror_ui/images/silk/control_start.png
new file mode 100644
index 0000000..7dd1c07
--- /dev/null
+++ b/codemirror_ui/images/silk/control_start.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_start_blue.png b/codemirror_ui/images/silk/control_start_blue.png
new file mode 100644
index 0000000..6f11fcb
--- /dev/null
+++ b/codemirror_ui/images/silk/control_start_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_stop.png b/codemirror_ui/images/silk/control_stop.png
new file mode 100644
index 0000000..893bb60
--- /dev/null
+++ b/codemirror_ui/images/silk/control_stop.png
Binary files differ
diff --git a/codemirror_ui/images/silk/control_stop_blue.png b/codemirror_ui/images/silk/control_stop_blue.png
new file mode 100644
index 0000000..e6f75d2
--- /dev/null
+++ b/codemirror_ui/images/silk/control_stop_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/controller.png b/codemirror_ui/images/silk/controller.png
new file mode 100644
index 0000000..5cf76ed
--- /dev/null
+++ b/codemirror_ui/images/silk/controller.png
Binary files differ
diff --git a/codemirror_ui/images/silk/controller_add.png b/codemirror_ui/images/silk/controller_add.png
new file mode 100644
index 0000000..efecb38
--- /dev/null
+++ b/codemirror_ui/images/silk/controller_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/controller_delete.png b/codemirror_ui/images/silk/controller_delete.png
new file mode 100644
index 0000000..3d83bc7
--- /dev/null
+++ b/codemirror_ui/images/silk/controller_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/controller_error.png b/codemirror_ui/images/silk/controller_error.png
new file mode 100644
index 0000000..7f17c0c
--- /dev/null
+++ b/codemirror_ui/images/silk/controller_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/creditcards.png b/codemirror_ui/images/silk/creditcards.png
new file mode 100644
index 0000000..4eae583
--- /dev/null
+++ b/codemirror_ui/images/silk/creditcards.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cross.png b/codemirror_ui/images/silk/cross.png
new file mode 100644
index 0000000..1514d51
--- /dev/null
+++ b/codemirror_ui/images/silk/cross.png
Binary files differ
diff --git a/codemirror_ui/images/silk/css.png b/codemirror_ui/images/silk/css.png
new file mode 100644
index 0000000..23f3101
--- /dev/null
+++ b/codemirror_ui/images/silk/css.png
Binary files differ
diff --git a/codemirror_ui/images/silk/css_add.png b/codemirror_ui/images/silk/css_add.png
new file mode 100644
index 0000000..e8ea10f
--- /dev/null
+++ b/codemirror_ui/images/silk/css_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/css_delete.png b/codemirror_ui/images/silk/css_delete.png
new file mode 100644
index 0000000..326aba4
--- /dev/null
+++ b/codemirror_ui/images/silk/css_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/css_go.png b/codemirror_ui/images/silk/css_go.png
new file mode 100644
index 0000000..6cdf38c
--- /dev/null
+++ b/codemirror_ui/images/silk/css_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/css_valid.png b/codemirror_ui/images/silk/css_valid.png
new file mode 100644
index 0000000..4c72ca5
--- /dev/null
+++ b/codemirror_ui/images/silk/css_valid.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cup.png b/codemirror_ui/images/silk/cup.png
new file mode 100644
index 0000000..b7bfcd1
--- /dev/null
+++ b/codemirror_ui/images/silk/cup.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cup_add.png b/codemirror_ui/images/silk/cup_add.png
new file mode 100644
index 0000000..4ecaece
--- /dev/null
+++ b/codemirror_ui/images/silk/cup_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cup_delete.png b/codemirror_ui/images/silk/cup_delete.png
new file mode 100644
index 0000000..59a6d9c
--- /dev/null
+++ b/codemirror_ui/images/silk/cup_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cup_edit.png b/codemirror_ui/images/silk/cup_edit.png
new file mode 100644
index 0000000..0b8f1e1
--- /dev/null
+++ b/codemirror_ui/images/silk/cup_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cup_error.png b/codemirror_ui/images/silk/cup_error.png
new file mode 100644
index 0000000..6879874
--- /dev/null
+++ b/codemirror_ui/images/silk/cup_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cup_go.png b/codemirror_ui/images/silk/cup_go.png
new file mode 100644
index 0000000..9527efb
--- /dev/null
+++ b/codemirror_ui/images/silk/cup_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cup_key.png b/codemirror_ui/images/silk/cup_key.png
new file mode 100644
index 0000000..7ae160c
--- /dev/null
+++ b/codemirror_ui/images/silk/cup_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cup_link.png b/codemirror_ui/images/silk/cup_link.png
new file mode 100644
index 0000000..41d1ace
--- /dev/null
+++ b/codemirror_ui/images/silk/cup_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cursor.png b/codemirror_ui/images/silk/cursor.png
new file mode 100644
index 0000000..532f532
--- /dev/null
+++ b/codemirror_ui/images/silk/cursor.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cut.png b/codemirror_ui/images/silk/cut.png
new file mode 100644
index 0000000..f215d6f
--- /dev/null
+++ b/codemirror_ui/images/silk/cut.png
Binary files differ
diff --git a/codemirror_ui/images/silk/cut_red.png b/codemirror_ui/images/silk/cut_red.png
new file mode 100644
index 0000000..85bb2f0
--- /dev/null
+++ b/codemirror_ui/images/silk/cut_red.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database.png b/codemirror_ui/images/silk/database.png
new file mode 100644
index 0000000..3d09261
--- /dev/null
+++ b/codemirror_ui/images/silk/database.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_add.png b/codemirror_ui/images/silk/database_add.png
new file mode 100644
index 0000000..802bd6c
--- /dev/null
+++ b/codemirror_ui/images/silk/database_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_connect.png b/codemirror_ui/images/silk/database_connect.png
new file mode 100644
index 0000000..3a11197
--- /dev/null
+++ b/codemirror_ui/images/silk/database_connect.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_delete.png b/codemirror_ui/images/silk/database_delete.png
new file mode 100644
index 0000000..cce652e
--- /dev/null
+++ b/codemirror_ui/images/silk/database_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_edit.png b/codemirror_ui/images/silk/database_edit.png
new file mode 100644
index 0000000..e501b66
--- /dev/null
+++ b/codemirror_ui/images/silk/database_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_error.png b/codemirror_ui/images/silk/database_error.png
new file mode 100644
index 0000000..578221a
--- /dev/null
+++ b/codemirror_ui/images/silk/database_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_gear.png b/codemirror_ui/images/silk/database_gear.png
new file mode 100644
index 0000000..7c0ab2b
--- /dev/null
+++ b/codemirror_ui/images/silk/database_gear.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_go.png b/codemirror_ui/images/silk/database_go.png
new file mode 100644
index 0000000..61a8556
--- /dev/null
+++ b/codemirror_ui/images/silk/database_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_key.png b/codemirror_ui/images/silk/database_key.png
new file mode 100644
index 0000000..3334147
--- /dev/null
+++ b/codemirror_ui/images/silk/database_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_lightning.png b/codemirror_ui/images/silk/database_lightning.png
new file mode 100644
index 0000000..d9eefc2
--- /dev/null
+++ b/codemirror_ui/images/silk/database_lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_link.png b/codemirror_ui/images/silk/database_link.png
new file mode 100644
index 0000000..4c8204a
--- /dev/null
+++ b/codemirror_ui/images/silk/database_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_refresh.png b/codemirror_ui/images/silk/database_refresh.png
new file mode 100644
index 0000000..ff803be
--- /dev/null
+++ b/codemirror_ui/images/silk/database_refresh.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_save.png b/codemirror_ui/images/silk/database_save.png
new file mode 100644
index 0000000..44c06dd
--- /dev/null
+++ b/codemirror_ui/images/silk/database_save.png
Binary files differ
diff --git a/codemirror_ui/images/silk/database_table.png b/codemirror_ui/images/silk/database_table.png
new file mode 100644
index 0000000..693709c
--- /dev/null
+++ b/codemirror_ui/images/silk/database_table.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date.png b/codemirror_ui/images/silk/date.png
new file mode 100644
index 0000000..783c833
--- /dev/null
+++ b/codemirror_ui/images/silk/date.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date_add.png b/codemirror_ui/images/silk/date_add.png
new file mode 100644
index 0000000..6a7ae02
--- /dev/null
+++ b/codemirror_ui/images/silk/date_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date_delete.png b/codemirror_ui/images/silk/date_delete.png
new file mode 100644
index 0000000..969a6b7
--- /dev/null
+++ b/codemirror_ui/images/silk/date_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date_edit.png b/codemirror_ui/images/silk/date_edit.png
new file mode 100644
index 0000000..e681065
--- /dev/null
+++ b/codemirror_ui/images/silk/date_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date_error.png b/codemirror_ui/images/silk/date_error.png
new file mode 100644
index 0000000..442cd97
--- /dev/null
+++ b/codemirror_ui/images/silk/date_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date_go.png b/codemirror_ui/images/silk/date_go.png
new file mode 100644
index 0000000..52dd9f3
--- /dev/null
+++ b/codemirror_ui/images/silk/date_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date_link.png b/codemirror_ui/images/silk/date_link.png
new file mode 100644
index 0000000..9f0aada
--- /dev/null
+++ b/codemirror_ui/images/silk/date_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date_magnify.png b/codemirror_ui/images/silk/date_magnify.png
new file mode 100644
index 0000000..cd05f19
--- /dev/null
+++ b/codemirror_ui/images/silk/date_magnify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date_next.png b/codemirror_ui/images/silk/date_next.png
new file mode 100644
index 0000000..48d740a
--- /dev/null
+++ b/codemirror_ui/images/silk/date_next.png
Binary files differ
diff --git a/codemirror_ui/images/silk/date_previous.png b/codemirror_ui/images/silk/date_previous.png
new file mode 100644
index 0000000..e117a83
--- /dev/null
+++ b/codemirror_ui/images/silk/date_previous.png
Binary files differ
diff --git a/codemirror_ui/images/silk/delete.png b/codemirror_ui/images/silk/delete.png
new file mode 100644
index 0000000..08f2493
--- /dev/null
+++ b/codemirror_ui/images/silk/delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/disconnect.png b/codemirror_ui/images/silk/disconnect.png
new file mode 100644
index 0000000..b335cb1
--- /dev/null
+++ b/codemirror_ui/images/silk/disconnect.png
Binary files differ
diff --git a/codemirror_ui/images/silk/disk.png b/codemirror_ui/images/silk/disk.png
new file mode 100644
index 0000000..99d532e
--- /dev/null
+++ b/codemirror_ui/images/silk/disk.png
Binary files differ
diff --git a/codemirror_ui/images/silk/disk_multiple.png b/codemirror_ui/images/silk/disk_multiple.png
new file mode 100644
index 0000000..fc5a52f
--- /dev/null
+++ b/codemirror_ui/images/silk/disk_multiple.png
Binary files differ
diff --git a/codemirror_ui/images/silk/door.png b/codemirror_ui/images/silk/door.png
new file mode 100644
index 0000000..369fc46
--- /dev/null
+++ b/codemirror_ui/images/silk/door.png
Binary files differ
diff --git a/codemirror_ui/images/silk/door_in.png b/codemirror_ui/images/silk/door_in.png
new file mode 100644
index 0000000..41676a0
--- /dev/null
+++ b/codemirror_ui/images/silk/door_in.png
Binary files differ
diff --git a/codemirror_ui/images/silk/door_open.png b/codemirror_ui/images/silk/door_open.png
new file mode 100644
index 0000000..64bab57
--- /dev/null
+++ b/codemirror_ui/images/silk/door_open.png
Binary files differ
diff --git a/codemirror_ui/images/silk/door_out.png b/codemirror_ui/images/silk/door_out.png
new file mode 100644
index 0000000..2541d2b
--- /dev/null
+++ b/codemirror_ui/images/silk/door_out.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drink.png b/codemirror_ui/images/silk/drink.png
new file mode 100644
index 0000000..d98359c
--- /dev/null
+++ b/codemirror_ui/images/silk/drink.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drink_empty.png b/codemirror_ui/images/silk/drink_empty.png
new file mode 100644
index 0000000..a40211e
--- /dev/null
+++ b/codemirror_ui/images/silk/drink_empty.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive.png b/codemirror_ui/images/silk/drive.png
new file mode 100644
index 0000000..37b7c9b
--- /dev/null
+++ b/codemirror_ui/images/silk/drive.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_add.png b/codemirror_ui/images/silk/drive_add.png
new file mode 100644
index 0000000..29a35d5
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_burn.png b/codemirror_ui/images/silk/drive_burn.png
new file mode 100644
index 0000000..80fd79f
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_burn.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_cd.png b/codemirror_ui/images/silk/drive_cd.png
new file mode 100644
index 0000000..1850b70
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_cd.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_cd_empty.png b/codemirror_ui/images/silk/drive_cd_empty.png
new file mode 100644
index 0000000..8df38d9
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_cd_empty.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_delete.png b/codemirror_ui/images/silk/drive_delete.png
new file mode 100644
index 0000000..e6eb186
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_disk.png b/codemirror_ui/images/silk/drive_disk.png
new file mode 100644
index 0000000..5a51e81
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_disk.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_edit.png b/codemirror_ui/images/silk/drive_edit.png
new file mode 100644
index 0000000..7923fad
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_error.png b/codemirror_ui/images/silk/drive_error.png
new file mode 100644
index 0000000..309f639
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_go.png b/codemirror_ui/images/silk/drive_go.png
new file mode 100644
index 0000000..fc53379
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_key.png b/codemirror_ui/images/silk/drive_key.png
new file mode 100644
index 0000000..d0b3c67
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_link.png b/codemirror_ui/images/silk/drive_link.png
new file mode 100644
index 0000000..8679c4b
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_magnify.png b/codemirror_ui/images/silk/drive_magnify.png
new file mode 100644
index 0000000..0f0f444
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_magnify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_network.png b/codemirror_ui/images/silk/drive_network.png
new file mode 100644
index 0000000..63d2d5d
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_network.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_rename.png b/codemirror_ui/images/silk/drive_rename.png
new file mode 100644
index 0000000..2a9f38b
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_rename.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_user.png b/codemirror_ui/images/silk/drive_user.png
new file mode 100644
index 0000000..0b4751c
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_user.png
Binary files differ
diff --git a/codemirror_ui/images/silk/drive_web.png b/codemirror_ui/images/silk/drive_web.png
new file mode 100644
index 0000000..8850a83
--- /dev/null
+++ b/codemirror_ui/images/silk/drive_web.png
Binary files differ
diff --git a/codemirror_ui/images/silk/dvd.png b/codemirror_ui/images/silk/dvd.png
new file mode 100644
index 0000000..9d94de5
--- /dev/null
+++ b/codemirror_ui/images/silk/dvd.png
Binary files differ
diff --git a/codemirror_ui/images/silk/dvd_add.png b/codemirror_ui/images/silk/dvd_add.png
new file mode 100644
index 0000000..517d112
--- /dev/null
+++ b/codemirror_ui/images/silk/dvd_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/dvd_delete.png b/codemirror_ui/images/silk/dvd_delete.png
new file mode 100644
index 0000000..87bed22
--- /dev/null
+++ b/codemirror_ui/images/silk/dvd_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/dvd_edit.png b/codemirror_ui/images/silk/dvd_edit.png
new file mode 100644
index 0000000..d6330aa
--- /dev/null
+++ b/codemirror_ui/images/silk/dvd_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/dvd_error.png b/codemirror_ui/images/silk/dvd_error.png
new file mode 100644
index 0000000..8f6d4be
--- /dev/null
+++ b/codemirror_ui/images/silk/dvd_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/dvd_go.png b/codemirror_ui/images/silk/dvd_go.png
new file mode 100644
index 0000000..ef6959f
--- /dev/null
+++ b/codemirror_ui/images/silk/dvd_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/dvd_key.png b/codemirror_ui/images/silk/dvd_key.png
new file mode 100644
index 0000000..da9307f
--- /dev/null
+++ b/codemirror_ui/images/silk/dvd_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/dvd_link.png b/codemirror_ui/images/silk/dvd_link.png
new file mode 100644
index 0000000..caad726
--- /dev/null
+++ b/codemirror_ui/images/silk/dvd_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email.png b/codemirror_ui/images/silk/email.png
new file mode 100644
index 0000000..7348aed
--- /dev/null
+++ b/codemirror_ui/images/silk/email.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email_add.png b/codemirror_ui/images/silk/email_add.png
new file mode 100644
index 0000000..6c93368
--- /dev/null
+++ b/codemirror_ui/images/silk/email_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email_attach.png b/codemirror_ui/images/silk/email_attach.png
new file mode 100644
index 0000000..1f99485
--- /dev/null
+++ b/codemirror_ui/images/silk/email_attach.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email_delete.png b/codemirror_ui/images/silk/email_delete.png
new file mode 100644
index 0000000..a9932b1
--- /dev/null
+++ b/codemirror_ui/images/silk/email_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email_edit.png b/codemirror_ui/images/silk/email_edit.png
new file mode 100644
index 0000000..244f04a
--- /dev/null
+++ b/codemirror_ui/images/silk/email_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email_error.png b/codemirror_ui/images/silk/email_error.png
new file mode 100644
index 0000000..8bdd330
--- /dev/null
+++ b/codemirror_ui/images/silk/email_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email_go.png b/codemirror_ui/images/silk/email_go.png
new file mode 100644
index 0000000..4a6c5d3
--- /dev/null
+++ b/codemirror_ui/images/silk/email_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email_link.png b/codemirror_ui/images/silk/email_link.png
new file mode 100644
index 0000000..2c49f78
--- /dev/null
+++ b/codemirror_ui/images/silk/email_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email_open.png b/codemirror_ui/images/silk/email_open.png
new file mode 100644
index 0000000..7b6f981
--- /dev/null
+++ b/codemirror_ui/images/silk/email_open.png
Binary files differ
diff --git a/codemirror_ui/images/silk/email_open_image.png b/codemirror_ui/images/silk/email_open_image.png
new file mode 100644
index 0000000..e588e2f
--- /dev/null
+++ b/codemirror_ui/images/silk/email_open_image.png
Binary files differ
diff --git a/codemirror_ui/images/silk/emoticon_evilgrin.png b/codemirror_ui/images/silk/emoticon_evilgrin.png
new file mode 100644
index 0000000..817bd50
--- /dev/null
+++ b/codemirror_ui/images/silk/emoticon_evilgrin.png
Binary files differ
diff --git a/codemirror_ui/images/silk/emoticon_grin.png b/codemirror_ui/images/silk/emoticon_grin.png
new file mode 100644
index 0000000..fc60c5e
--- /dev/null
+++ b/codemirror_ui/images/silk/emoticon_grin.png
Binary files differ
diff --git a/codemirror_ui/images/silk/emoticon_happy.png b/codemirror_ui/images/silk/emoticon_happy.png
new file mode 100644
index 0000000..6b7336e
--- /dev/null
+++ b/codemirror_ui/images/silk/emoticon_happy.png
Binary files differ
diff --git a/codemirror_ui/images/silk/emoticon_smile.png b/codemirror_ui/images/silk/emoticon_smile.png
new file mode 100644
index 0000000..ade4318
--- /dev/null
+++ b/codemirror_ui/images/silk/emoticon_smile.png
Binary files differ
diff --git a/codemirror_ui/images/silk/emoticon_surprised.png b/codemirror_ui/images/silk/emoticon_surprised.png
new file mode 100644
index 0000000..4520cfc
--- /dev/null
+++ b/codemirror_ui/images/silk/emoticon_surprised.png
Binary files differ
diff --git a/codemirror_ui/images/silk/emoticon_tongue.png b/codemirror_ui/images/silk/emoticon_tongue.png
new file mode 100644
index 0000000..ecafd2f
--- /dev/null
+++ b/codemirror_ui/images/silk/emoticon_tongue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/emoticon_unhappy.png b/codemirror_ui/images/silk/emoticon_unhappy.png
new file mode 100644
index 0000000..fd5d030
--- /dev/null
+++ b/codemirror_ui/images/silk/emoticon_unhappy.png
Binary files differ
diff --git a/codemirror_ui/images/silk/emoticon_waii.png b/codemirror_ui/images/silk/emoticon_waii.png
new file mode 100644
index 0000000..458f936
--- /dev/null
+++ b/codemirror_ui/images/silk/emoticon_waii.png
Binary files differ
diff --git a/codemirror_ui/images/silk/emoticon_wink.png b/codemirror_ui/images/silk/emoticon_wink.png
new file mode 100644
index 0000000..a631949
--- /dev/null
+++ b/codemirror_ui/images/silk/emoticon_wink.png
Binary files differ
diff --git a/codemirror_ui/images/silk/error.png b/codemirror_ui/images/silk/error.png
new file mode 100644
index 0000000..628cf2d
--- /dev/null
+++ b/codemirror_ui/images/silk/error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/error_add.png b/codemirror_ui/images/silk/error_add.png
new file mode 100644
index 0000000..4c97484
--- /dev/null
+++ b/codemirror_ui/images/silk/error_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/error_delete.png b/codemirror_ui/images/silk/error_delete.png
new file mode 100644
index 0000000..7f78bcc
--- /dev/null
+++ b/codemirror_ui/images/silk/error_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/error_go.png b/codemirror_ui/images/silk/error_go.png
new file mode 100644
index 0000000..caa1838
--- /dev/null
+++ b/codemirror_ui/images/silk/error_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/exclamation.png b/codemirror_ui/images/silk/exclamation.png
new file mode 100644
index 0000000..c37bd06
--- /dev/null
+++ b/codemirror_ui/images/silk/exclamation.png
Binary files differ
diff --git a/codemirror_ui/images/silk/eye.png b/codemirror_ui/images/silk/eye.png
new file mode 100644
index 0000000..564a1a9
--- /dev/null
+++ b/codemirror_ui/images/silk/eye.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed.png b/codemirror_ui/images/silk/feed.png
new file mode 100644
index 0000000..315c4f4
--- /dev/null
+++ b/codemirror_ui/images/silk/feed.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed_add.png b/codemirror_ui/images/silk/feed_add.png
new file mode 100644
index 0000000..e77d46e
--- /dev/null
+++ b/codemirror_ui/images/silk/feed_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed_delete.png b/codemirror_ui/images/silk/feed_delete.png
new file mode 100644
index 0000000..5e332b4
--- /dev/null
+++ b/codemirror_ui/images/silk/feed_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed_disk.png b/codemirror_ui/images/silk/feed_disk.png
new file mode 100644
index 0000000..a158c99
--- /dev/null
+++ b/codemirror_ui/images/silk/feed_disk.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed_edit.png b/codemirror_ui/images/silk/feed_edit.png
new file mode 100644
index 0000000..f1fde7a
--- /dev/null
+++ b/codemirror_ui/images/silk/feed_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed_error.png b/codemirror_ui/images/silk/feed_error.png
new file mode 100644
index 0000000..c0a801c
--- /dev/null
+++ b/codemirror_ui/images/silk/feed_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed_go.png b/codemirror_ui/images/silk/feed_go.png
new file mode 100644
index 0000000..f2eed1e
--- /dev/null
+++ b/codemirror_ui/images/silk/feed_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed_key.png b/codemirror_ui/images/silk/feed_key.png
new file mode 100644
index 0000000..156bfa9
--- /dev/null
+++ b/codemirror_ui/images/silk/feed_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed_link.png b/codemirror_ui/images/silk/feed_link.png
new file mode 100644
index 0000000..c45a534
--- /dev/null
+++ b/codemirror_ui/images/silk/feed_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/feed_magnify.png b/codemirror_ui/images/silk/feed_magnify.png
new file mode 100644
index 0000000..3023695
--- /dev/null
+++ b/codemirror_ui/images/silk/feed_magnify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/female.png b/codemirror_ui/images/silk/female.png
new file mode 100644
index 0000000..f92958e
--- /dev/null
+++ b/codemirror_ui/images/silk/female.png
Binary files differ
diff --git a/codemirror_ui/images/silk/film.png b/codemirror_ui/images/silk/film.png
new file mode 100644
index 0000000..b0ce7bb
--- /dev/null
+++ b/codemirror_ui/images/silk/film.png
Binary files differ
diff --git a/codemirror_ui/images/silk/film_add.png b/codemirror_ui/images/silk/film_add.png
new file mode 100644
index 0000000..40d681f
--- /dev/null
+++ b/codemirror_ui/images/silk/film_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/film_delete.png b/codemirror_ui/images/silk/film_delete.png
new file mode 100644
index 0000000..23a2508
--- /dev/null
+++ b/codemirror_ui/images/silk/film_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/film_edit.png b/codemirror_ui/images/silk/film_edit.png
new file mode 100644
index 0000000..af66b73
--- /dev/null
+++ b/codemirror_ui/images/silk/film_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/film_error.png b/codemirror_ui/images/silk/film_error.png
new file mode 100644
index 0000000..88f3d69
--- /dev/null
+++ b/codemirror_ui/images/silk/film_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/film_go.png b/codemirror_ui/images/silk/film_go.png
new file mode 100644
index 0000000..dd0168e
--- /dev/null
+++ b/codemirror_ui/images/silk/film_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/film_key.png b/codemirror_ui/images/silk/film_key.png
new file mode 100644
index 0000000..5892162
--- /dev/null
+++ b/codemirror_ui/images/silk/film_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/film_link.png b/codemirror_ui/images/silk/film_link.png
new file mode 100644
index 0000000..0f24e86
--- /dev/null
+++ b/codemirror_ui/images/silk/film_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/film_save.png b/codemirror_ui/images/silk/film_save.png
new file mode 100644
index 0000000..bc8c0d3
--- /dev/null
+++ b/codemirror_ui/images/silk/film_save.png
Binary files differ
diff --git a/codemirror_ui/images/silk/find.png b/codemirror_ui/images/silk/find.png
new file mode 100644
index 0000000..1547479
--- /dev/null
+++ b/codemirror_ui/images/silk/find.png
Binary files differ
diff --git a/codemirror_ui/images/silk/flag_blue.png b/codemirror_ui/images/silk/flag_blue.png
new file mode 100644
index 0000000..003924f
--- /dev/null
+++ b/codemirror_ui/images/silk/flag_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/flag_green.png b/codemirror_ui/images/silk/flag_green.png
new file mode 100644
index 0000000..e4bc611
--- /dev/null
+++ b/codemirror_ui/images/silk/flag_green.png
Binary files differ
diff --git a/codemirror_ui/images/silk/flag_orange.png b/codemirror_ui/images/silk/flag_orange.png
new file mode 100644
index 0000000..e632024
--- /dev/null
+++ b/codemirror_ui/images/silk/flag_orange.png
Binary files differ
diff --git a/codemirror_ui/images/silk/flag_pink.png b/codemirror_ui/images/silk/flag_pink.png
new file mode 100644
index 0000000..5f15e52
--- /dev/null
+++ b/codemirror_ui/images/silk/flag_pink.png
Binary files differ
diff --git a/codemirror_ui/images/silk/flag_purple.png b/codemirror_ui/images/silk/flag_purple.png
new file mode 100644
index 0000000..d069866
--- /dev/null
+++ b/codemirror_ui/images/silk/flag_purple.png
Binary files differ
diff --git a/codemirror_ui/images/silk/flag_red.png b/codemirror_ui/images/silk/flag_red.png
new file mode 100644
index 0000000..e8a602d
--- /dev/null
+++ b/codemirror_ui/images/silk/flag_red.png
Binary files differ
diff --git a/codemirror_ui/images/silk/flag_yellow.png b/codemirror_ui/images/silk/flag_yellow.png
new file mode 100644
index 0000000..14c89a5
--- /dev/null
+++ b/codemirror_ui/images/silk/flag_yellow.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder.png b/codemirror_ui/images/silk/folder.png
new file mode 100644
index 0000000..784e8fa
--- /dev/null
+++ b/codemirror_ui/images/silk/folder.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_add.png b/codemirror_ui/images/silk/folder_add.png
new file mode 100644
index 0000000..529fe8f
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_bell.png b/codemirror_ui/images/silk/folder_bell.png
new file mode 100644
index 0000000..d04dd7f
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_bell.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_brick.png b/codemirror_ui/images/silk/folder_brick.png
new file mode 100644
index 0000000..5dea976
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_brick.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_bug.png b/codemirror_ui/images/silk/folder_bug.png
new file mode 100644
index 0000000..4f791b6
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_bug.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_camera.png b/codemirror_ui/images/silk/folder_camera.png
new file mode 100644
index 0000000..c951941
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_camera.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_database.png b/codemirror_ui/images/silk/folder_database.png
new file mode 100644
index 0000000..5193e2e
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_database.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_delete.png b/codemirror_ui/images/silk/folder_delete.png
new file mode 100644
index 0000000..112b016
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_edit.png b/codemirror_ui/images/silk/folder_edit.png
new file mode 100644
index 0000000..ad669cc
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_error.png b/codemirror_ui/images/silk/folder_error.png
new file mode 100644
index 0000000..1af8809
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_explore.png b/codemirror_ui/images/silk/folder_explore.png
new file mode 100644
index 0000000..0ba9391
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_explore.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_feed.png b/codemirror_ui/images/silk/folder_feed.png
new file mode 100644
index 0000000..d06ee51
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_feed.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_find.png b/codemirror_ui/images/silk/folder_find.png
new file mode 100644
index 0000000..c64e2ee
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_find.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_go.png b/codemirror_ui/images/silk/folder_go.png
new file mode 100644
index 0000000..34a736f
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_heart.png b/codemirror_ui/images/silk/folder_heart.png
new file mode 100644
index 0000000..56d7da1
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_heart.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_image.png b/codemirror_ui/images/silk/folder_image.png
new file mode 100644
index 0000000..d5df75b
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_image.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_key.png b/codemirror_ui/images/silk/folder_key.png
new file mode 100644
index 0000000..fb9b4c2
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_lightbulb.png b/codemirror_ui/images/silk/folder_lightbulb.png
new file mode 100644
index 0000000..f367a51
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_lightbulb.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_link.png b/codemirror_ui/images/silk/folder_link.png
new file mode 100644
index 0000000..b9b75f6
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_magnify.png b/codemirror_ui/images/silk/folder_magnify.png
new file mode 100644
index 0000000..0a3e798
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_magnify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_page.png b/codemirror_ui/images/silk/folder_page.png
new file mode 100644
index 0000000..1ef6e11
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_page.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_page_white.png b/codemirror_ui/images/silk/folder_page_white.png
new file mode 100644
index 0000000..14d6b61
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_page_white.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_palette.png b/codemirror_ui/images/silk/folder_palette.png
new file mode 100644
index 0000000..ba12fe8
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_palette.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_picture.png b/codemirror_ui/images/silk/folder_picture.png
new file mode 100644
index 0000000..052b336
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_picture.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_star.png b/codemirror_ui/images/silk/folder_star.png
new file mode 100644
index 0000000..448e46f
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_star.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_table.png b/codemirror_ui/images/silk/folder_table.png
new file mode 100644
index 0000000..473cee3
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_table.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_user.png b/codemirror_ui/images/silk/folder_user.png
new file mode 100644
index 0000000..f021c3e
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_user.png
Binary files differ
diff --git a/codemirror_ui/images/silk/folder_wrench.png b/codemirror_ui/images/silk/folder_wrench.png
new file mode 100644
index 0000000..ea3404e
--- /dev/null
+++ b/codemirror_ui/images/silk/folder_wrench.png
Binary files differ
diff --git a/codemirror_ui/images/silk/font.png b/codemirror_ui/images/silk/font.png
new file mode 100644
index 0000000..b7960db
--- /dev/null
+++ b/codemirror_ui/images/silk/font.png
Binary files differ
diff --git a/codemirror_ui/images/silk/font_add.png b/codemirror_ui/images/silk/font_add.png
new file mode 100644
index 0000000..b709eba
--- /dev/null
+++ b/codemirror_ui/images/silk/font_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/font_delete.png b/codemirror_ui/images/silk/font_delete.png
new file mode 100644
index 0000000..1d6124d
--- /dev/null
+++ b/codemirror_ui/images/silk/font_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/font_go.png b/codemirror_ui/images/silk/font_go.png
new file mode 100644
index 0000000..75eba80
--- /dev/null
+++ b/codemirror_ui/images/silk/font_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/group.png b/codemirror_ui/images/silk/group.png
new file mode 100644
index 0000000..7fb4e1f
--- /dev/null
+++ b/codemirror_ui/images/silk/group.png
Binary files differ
diff --git a/codemirror_ui/images/silk/group_add.png b/codemirror_ui/images/silk/group_add.png
new file mode 100644
index 0000000..06c5350
--- /dev/null
+++ b/codemirror_ui/images/silk/group_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/group_delete.png b/codemirror_ui/images/silk/group_delete.png
new file mode 100644
index 0000000..4489ca2
--- /dev/null
+++ b/codemirror_ui/images/silk/group_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/group_edit.png b/codemirror_ui/images/silk/group_edit.png
new file mode 100644
index 0000000..c88b945
--- /dev/null
+++ b/codemirror_ui/images/silk/group_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/group_error.png b/codemirror_ui/images/silk/group_error.png
new file mode 100644
index 0000000..7364a13
--- /dev/null
+++ b/codemirror_ui/images/silk/group_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/group_gear.png b/codemirror_ui/images/silk/group_gear.png
new file mode 100644
index 0000000..2544f2e
--- /dev/null
+++ b/codemirror_ui/images/silk/group_gear.png
Binary files differ
diff --git a/codemirror_ui/images/silk/group_go.png b/codemirror_ui/images/silk/group_go.png
new file mode 100644
index 0000000..1f52333
--- /dev/null
+++ b/codemirror_ui/images/silk/group_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/group_key.png b/codemirror_ui/images/silk/group_key.png
new file mode 100644
index 0000000..257f111
--- /dev/null
+++ b/codemirror_ui/images/silk/group_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/group_link.png b/codemirror_ui/images/silk/group_link.png
new file mode 100644
index 0000000..c77ed88
--- /dev/null
+++ b/codemirror_ui/images/silk/group_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/heart.png b/codemirror_ui/images/silk/heart.png
new file mode 100644
index 0000000..d9ee53e
--- /dev/null
+++ b/codemirror_ui/images/silk/heart.png
Binary files differ
diff --git a/codemirror_ui/images/silk/heart_add.png b/codemirror_ui/images/silk/heart_add.png
new file mode 100644
index 0000000..d4195ff
--- /dev/null
+++ b/codemirror_ui/images/silk/heart_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/heart_delete.png b/codemirror_ui/images/silk/heart_delete.png
new file mode 100644
index 0000000..ce523e3
--- /dev/null
+++ b/codemirror_ui/images/silk/heart_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/help.png b/codemirror_ui/images/silk/help.png
new file mode 100644
index 0000000..5c87017
--- /dev/null
+++ b/codemirror_ui/images/silk/help.png
Binary files differ
diff --git a/codemirror_ui/images/silk/hourglass.png b/codemirror_ui/images/silk/hourglass.png
new file mode 100644
index 0000000..57b03ce
--- /dev/null
+++ b/codemirror_ui/images/silk/hourglass.png
Binary files differ
diff --git a/codemirror_ui/images/silk/hourglass_add.png b/codemirror_ui/images/silk/hourglass_add.png
new file mode 100644
index 0000000..170dfff
--- /dev/null
+++ b/codemirror_ui/images/silk/hourglass_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/hourglass_delete.png b/codemirror_ui/images/silk/hourglass_delete.png
new file mode 100644
index 0000000..4b1337b
--- /dev/null
+++ b/codemirror_ui/images/silk/hourglass_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/hourglass_go.png b/codemirror_ui/images/silk/hourglass_go.png
new file mode 100644
index 0000000..b2d3a98
--- /dev/null
+++ b/codemirror_ui/images/silk/hourglass_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/hourglass_link.png b/codemirror_ui/images/silk/hourglass_link.png
new file mode 100644
index 0000000..ecc59b0
--- /dev/null
+++ b/codemirror_ui/images/silk/hourglass_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/house.png b/codemirror_ui/images/silk/house.png
new file mode 100644
index 0000000..fed6221
--- /dev/null
+++ b/codemirror_ui/images/silk/house.png
Binary files differ
diff --git a/codemirror_ui/images/silk/house_go.png b/codemirror_ui/images/silk/house_go.png
new file mode 100644
index 0000000..5457dbd
--- /dev/null
+++ b/codemirror_ui/images/silk/house_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/house_link.png b/codemirror_ui/images/silk/house_link.png
new file mode 100644
index 0000000..be2c271
--- /dev/null
+++ b/codemirror_ui/images/silk/house_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/html.png b/codemirror_ui/images/silk/html.png
new file mode 100644
index 0000000..55d1072
--- /dev/null
+++ b/codemirror_ui/images/silk/html.png
Binary files differ
diff --git a/codemirror_ui/images/silk/html_add.png b/codemirror_ui/images/silk/html_add.png
new file mode 100644
index 0000000..f1c08b7
--- /dev/null
+++ b/codemirror_ui/images/silk/html_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/html_delete.png b/codemirror_ui/images/silk/html_delete.png
new file mode 100644
index 0000000..1bd2848
--- /dev/null
+++ b/codemirror_ui/images/silk/html_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/html_go.png b/codemirror_ui/images/silk/html_go.png
new file mode 100644
index 0000000..a95cede
--- /dev/null
+++ b/codemirror_ui/images/silk/html_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/html_valid.png b/codemirror_ui/images/silk/html_valid.png
new file mode 100644
index 0000000..71cec92
--- /dev/null
+++ b/codemirror_ui/images/silk/html_valid.png
Binary files differ
diff --git a/codemirror_ui/images/silk/image.png b/codemirror_ui/images/silk/image.png
new file mode 100644
index 0000000..fc3c393
--- /dev/null
+++ b/codemirror_ui/images/silk/image.png
Binary files differ
diff --git a/codemirror_ui/images/silk/image_add.png b/codemirror_ui/images/silk/image_add.png
new file mode 100644
index 0000000..fc5d613
--- /dev/null
+++ b/codemirror_ui/images/silk/image_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/image_delete.png b/codemirror_ui/images/silk/image_delete.png
new file mode 100644
index 0000000..c260e1d
--- /dev/null
+++ b/codemirror_ui/images/silk/image_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/image_edit.png b/codemirror_ui/images/silk/image_edit.png
new file mode 100644
index 0000000..0aa4cc6
--- /dev/null
+++ b/codemirror_ui/images/silk/image_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/image_link.png b/codemirror_ui/images/silk/image_link.png
new file mode 100644
index 0000000..4bdb354
--- /dev/null
+++ b/codemirror_ui/images/silk/image_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/images.png b/codemirror_ui/images/silk/images.png
new file mode 100644
index 0000000..184860d
--- /dev/null
+++ b/codemirror_ui/images/silk/images.png
Binary files differ
diff --git a/codemirror_ui/images/silk/information.png b/codemirror_ui/images/silk/information.png
new file mode 100644
index 0000000..12cd1ae
--- /dev/null
+++ b/codemirror_ui/images/silk/information.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ipod.png b/codemirror_ui/images/silk/ipod.png
new file mode 100644
index 0000000..3f768da
--- /dev/null
+++ b/codemirror_ui/images/silk/ipod.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ipod_cast.png b/codemirror_ui/images/silk/ipod_cast.png
new file mode 100644
index 0000000..6f6d340
--- /dev/null
+++ b/codemirror_ui/images/silk/ipod_cast.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ipod_cast_add.png b/codemirror_ui/images/silk/ipod_cast_add.png
new file mode 100644
index 0000000..c3257f5
--- /dev/null
+++ b/codemirror_ui/images/silk/ipod_cast_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ipod_cast_delete.png b/codemirror_ui/images/silk/ipod_cast_delete.png
new file mode 100644
index 0000000..377ab69
--- /dev/null
+++ b/codemirror_ui/images/silk/ipod_cast_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ipod_sound.png b/codemirror_ui/images/silk/ipod_sound.png
new file mode 100644
index 0000000..fef6e8b
--- /dev/null
+++ b/codemirror_ui/images/silk/ipod_sound.png
Binary files differ
diff --git a/codemirror_ui/images/silk/joystick.png b/codemirror_ui/images/silk/joystick.png
new file mode 100644
index 0000000..62168f5
--- /dev/null
+++ b/codemirror_ui/images/silk/joystick.png
Binary files differ
diff --git a/codemirror_ui/images/silk/joystick_add.png b/codemirror_ui/images/silk/joystick_add.png
new file mode 100644
index 0000000..77e7107
--- /dev/null
+++ b/codemirror_ui/images/silk/joystick_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/joystick_delete.png b/codemirror_ui/images/silk/joystick_delete.png
new file mode 100644
index 0000000..5d44b59
--- /dev/null
+++ b/codemirror_ui/images/silk/joystick_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/joystick_error.png b/codemirror_ui/images/silk/joystick_error.png
new file mode 100644
index 0000000..b32149e
--- /dev/null
+++ b/codemirror_ui/images/silk/joystick_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/key.png b/codemirror_ui/images/silk/key.png
new file mode 100644
index 0000000..4ec1a92
--- /dev/null
+++ b/codemirror_ui/images/silk/key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/key_add.png b/codemirror_ui/images/silk/key_add.png
new file mode 100644
index 0000000..d407403
--- /dev/null
+++ b/codemirror_ui/images/silk/key_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/key_delete.png b/codemirror_ui/images/silk/key_delete.png
new file mode 100644
index 0000000..00dec80
--- /dev/null
+++ b/codemirror_ui/images/silk/key_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/key_go.png b/codemirror_ui/images/silk/key_go.png
new file mode 100644
index 0000000..30b0dc3
--- /dev/null
+++ b/codemirror_ui/images/silk/key_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/keyboard.png b/codemirror_ui/images/silk/keyboard.png
new file mode 100644
index 0000000..898d402
--- /dev/null
+++ b/codemirror_ui/images/silk/keyboard.png
Binary files differ
diff --git a/codemirror_ui/images/silk/keyboard_add.png b/codemirror_ui/images/silk/keyboard_add.png
new file mode 100644
index 0000000..26938dd
--- /dev/null
+++ b/codemirror_ui/images/silk/keyboard_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/keyboard_delete.png b/codemirror_ui/images/silk/keyboard_delete.png
new file mode 100644
index 0000000..1786ed5
--- /dev/null
+++ b/codemirror_ui/images/silk/keyboard_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/keyboard_magnify.png b/codemirror_ui/images/silk/keyboard_magnify.png
new file mode 100644
index 0000000..928fc17
--- /dev/null
+++ b/codemirror_ui/images/silk/keyboard_magnify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layers.png b/codemirror_ui/images/silk/layers.png
new file mode 100644
index 0000000..00818f6
--- /dev/null
+++ b/codemirror_ui/images/silk/layers.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layout.png b/codemirror_ui/images/silk/layout.png
new file mode 100644
index 0000000..ea086b0
--- /dev/null
+++ b/codemirror_ui/images/silk/layout.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layout_add.png b/codemirror_ui/images/silk/layout_add.png
new file mode 100644
index 0000000..6203722
--- /dev/null
+++ b/codemirror_ui/images/silk/layout_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layout_content.png b/codemirror_ui/images/silk/layout_content.png
new file mode 100644
index 0000000..b4aaad9
--- /dev/null
+++ b/codemirror_ui/images/silk/layout_content.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layout_delete.png b/codemirror_ui/images/silk/layout_delete.png
new file mode 100644
index 0000000..4bd45f1
--- /dev/null
+++ b/codemirror_ui/images/silk/layout_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layout_edit.png b/codemirror_ui/images/silk/layout_edit.png
new file mode 100644
index 0000000..ab3100b
--- /dev/null
+++ b/codemirror_ui/images/silk/layout_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layout_error.png b/codemirror_ui/images/silk/layout_error.png
new file mode 100644
index 0000000..5b5acea
--- /dev/null
+++ b/codemirror_ui/images/silk/layout_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layout_header.png b/codemirror_ui/images/silk/layout_header.png
new file mode 100644
index 0000000..c6ea7f2
--- /dev/null
+++ b/codemirror_ui/images/silk/layout_header.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layout_link.png b/codemirror_ui/images/silk/layout_link.png
new file mode 100644
index 0000000..3445d42
--- /dev/null
+++ b/codemirror_ui/images/silk/layout_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/layout_sidebar.png b/codemirror_ui/images/silk/layout_sidebar.png
new file mode 100644
index 0000000..3be27bb
--- /dev/null
+++ b/codemirror_ui/images/silk/layout_sidebar.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lightbulb.png b/codemirror_ui/images/silk/lightbulb.png
new file mode 100644
index 0000000..d22fde8
--- /dev/null
+++ b/codemirror_ui/images/silk/lightbulb.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lightbulb_add.png b/codemirror_ui/images/silk/lightbulb_add.png
new file mode 100644
index 0000000..0dd848b
--- /dev/null
+++ b/codemirror_ui/images/silk/lightbulb_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lightbulb_delete.png b/codemirror_ui/images/silk/lightbulb_delete.png
new file mode 100644
index 0000000..f4781da
--- /dev/null
+++ b/codemirror_ui/images/silk/lightbulb_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lightbulb_off.png b/codemirror_ui/images/silk/lightbulb_off.png
new file mode 100644
index 0000000..e95b8c5
--- /dev/null
+++ b/codemirror_ui/images/silk/lightbulb_off.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lightning.png b/codemirror_ui/images/silk/lightning.png
new file mode 100644
index 0000000..9680afd
--- /dev/null
+++ b/codemirror_ui/images/silk/lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lightning_add.png b/codemirror_ui/images/silk/lightning_add.png
new file mode 100644
index 0000000..dac3c90
--- /dev/null
+++ b/codemirror_ui/images/silk/lightning_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lightning_delete.png b/codemirror_ui/images/silk/lightning_delete.png
new file mode 100644
index 0000000..dfe2770
--- /dev/null
+++ b/codemirror_ui/images/silk/lightning_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lightning_go.png b/codemirror_ui/images/silk/lightning_go.png
new file mode 100644
index 0000000..29039e6
--- /dev/null
+++ b/codemirror_ui/images/silk/lightning_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/link.png b/codemirror_ui/images/silk/link.png
new file mode 100644
index 0000000..25eacb7
--- /dev/null
+++ b/codemirror_ui/images/silk/link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/link_add.png b/codemirror_ui/images/silk/link_add.png
new file mode 100644
index 0000000..00be352
--- /dev/null
+++ b/codemirror_ui/images/silk/link_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/link_break.png b/codemirror_ui/images/silk/link_break.png
new file mode 100644
index 0000000..5235753
--- /dev/null
+++ b/codemirror_ui/images/silk/link_break.png
Binary files differ
diff --git a/codemirror_ui/images/silk/link_delete.png b/codemirror_ui/images/silk/link_delete.png
new file mode 100644
index 0000000..f66e297
--- /dev/null
+++ b/codemirror_ui/images/silk/link_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/link_edit.png b/codemirror_ui/images/silk/link_edit.png
new file mode 100644
index 0000000..5b3aed0
--- /dev/null
+++ b/codemirror_ui/images/silk/link_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/link_error.png b/codemirror_ui/images/silk/link_error.png
new file mode 100644
index 0000000..ab694b1
--- /dev/null
+++ b/codemirror_ui/images/silk/link_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/link_go.png b/codemirror_ui/images/silk/link_go.png
new file mode 100644
index 0000000..ae8cae8
--- /dev/null
+++ b/codemirror_ui/images/silk/link_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lock.png b/codemirror_ui/images/silk/lock.png
new file mode 100644
index 0000000..2ebc4f6
--- /dev/null
+++ b/codemirror_ui/images/silk/lock.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lock_add.png b/codemirror_ui/images/silk/lock_add.png
new file mode 100644
index 0000000..a7b566b
--- /dev/null
+++ b/codemirror_ui/images/silk/lock_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lock_break.png b/codemirror_ui/images/silk/lock_break.png
new file mode 100644
index 0000000..13578ab
--- /dev/null
+++ b/codemirror_ui/images/silk/lock_break.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lock_delete.png b/codemirror_ui/images/silk/lock_delete.png
new file mode 100644
index 0000000..ecb50a9
--- /dev/null
+++ b/codemirror_ui/images/silk/lock_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lock_edit.png b/codemirror_ui/images/silk/lock_edit.png
new file mode 100644
index 0000000..116aa5b
--- /dev/null
+++ b/codemirror_ui/images/silk/lock_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lock_go.png b/codemirror_ui/images/silk/lock_go.png
new file mode 100644
index 0000000..8c7c89b
--- /dev/null
+++ b/codemirror_ui/images/silk/lock_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lock_open.png b/codemirror_ui/images/silk/lock_open.png
new file mode 100644
index 0000000..a471765
--- /dev/null
+++ b/codemirror_ui/images/silk/lock_open.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lorry.png b/codemirror_ui/images/silk/lorry.png
new file mode 100644
index 0000000..8f95f5a
--- /dev/null
+++ b/codemirror_ui/images/silk/lorry.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lorry_add.png b/codemirror_ui/images/silk/lorry_add.png
new file mode 100644
index 0000000..a2c5124
--- /dev/null
+++ b/codemirror_ui/images/silk/lorry_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lorry_delete.png b/codemirror_ui/images/silk/lorry_delete.png
new file mode 100644
index 0000000..66217f5
--- /dev/null
+++ b/codemirror_ui/images/silk/lorry_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lorry_error.png b/codemirror_ui/images/silk/lorry_error.png
new file mode 100644
index 0000000..3619ead
--- /dev/null
+++ b/codemirror_ui/images/silk/lorry_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lorry_flatbed.png b/codemirror_ui/images/silk/lorry_flatbed.png
new file mode 100644
index 0000000..8b20f55
--- /dev/null
+++ b/codemirror_ui/images/silk/lorry_flatbed.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lorry_go.png b/codemirror_ui/images/silk/lorry_go.png
new file mode 100644
index 0000000..1c296a6
--- /dev/null
+++ b/codemirror_ui/images/silk/lorry_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/lorry_link.png b/codemirror_ui/images/silk/lorry_link.png
new file mode 100644
index 0000000..5e6663e
--- /dev/null
+++ b/codemirror_ui/images/silk/lorry_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/magifier_zoom_out.png b/codemirror_ui/images/silk/magifier_zoom_out.png
new file mode 100644
index 0000000..81f2819
--- /dev/null
+++ b/codemirror_ui/images/silk/magifier_zoom_out.png
Binary files differ
diff --git a/codemirror_ui/images/silk/magnifier.png b/codemirror_ui/images/silk/magnifier.png
new file mode 100644
index 0000000..cf3d97f
--- /dev/null
+++ b/codemirror_ui/images/silk/magnifier.png
Binary files differ
diff --git a/codemirror_ui/images/silk/magnifier_zoom_in.png b/codemirror_ui/images/silk/magnifier_zoom_in.png
new file mode 100644
index 0000000..af4fe07
--- /dev/null
+++ b/codemirror_ui/images/silk/magnifier_zoom_in.png
Binary files differ
diff --git a/codemirror_ui/images/silk/male.png b/codemirror_ui/images/silk/male.png
new file mode 100644
index 0000000..25d6ea9
--- /dev/null
+++ b/codemirror_ui/images/silk/male.png
Binary files differ
diff --git a/codemirror_ui/images/silk/map.png b/codemirror_ui/images/silk/map.png
new file mode 100644
index 0000000..f90ef25
--- /dev/null
+++ b/codemirror_ui/images/silk/map.png
Binary files differ
diff --git a/codemirror_ui/images/silk/map_add.png b/codemirror_ui/images/silk/map_add.png
new file mode 100644
index 0000000..2b72da0
--- /dev/null
+++ b/codemirror_ui/images/silk/map_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/map_delete.png b/codemirror_ui/images/silk/map_delete.png
new file mode 100644
index 0000000..e74402f
--- /dev/null
+++ b/codemirror_ui/images/silk/map_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/map_edit.png b/codemirror_ui/images/silk/map_edit.png
new file mode 100644
index 0000000..93d4d7e
--- /dev/null
+++ b/codemirror_ui/images/silk/map_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/map_go.png b/codemirror_ui/images/silk/map_go.png
new file mode 100644
index 0000000..11eab26
--- /dev/null
+++ b/codemirror_ui/images/silk/map_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/map_magnify.png b/codemirror_ui/images/silk/map_magnify.png
new file mode 100644
index 0000000..7184c9d
--- /dev/null
+++ b/codemirror_ui/images/silk/map_magnify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_bronze_1.png b/codemirror_ui/images/silk/medal_bronze_1.png
new file mode 100644
index 0000000..5f8a6d6
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_bronze_1.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_bronze_2.png b/codemirror_ui/images/silk/medal_bronze_2.png
new file mode 100644
index 0000000..623d68c
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_bronze_2.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_bronze_3.png b/codemirror_ui/images/silk/medal_bronze_3.png
new file mode 100644
index 0000000..ed3f43e
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_bronze_3.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_bronze_add.png b/codemirror_ui/images/silk/medal_bronze_add.png
new file mode 100644
index 0000000..8487b2c
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_bronze_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_bronze_delete.png b/codemirror_ui/images/silk/medal_bronze_delete.png
new file mode 100644
index 0000000..d32aed7
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_bronze_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_gold_1.png b/codemirror_ui/images/silk/medal_gold_1.png
new file mode 100644
index 0000000..87584dc
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_gold_1.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_gold_2.png b/codemirror_ui/images/silk/medal_gold_2.png
new file mode 100644
index 0000000..fa3a15d
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_gold_2.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_gold_3.png b/codemirror_ui/images/silk/medal_gold_3.png
new file mode 100644
index 0000000..ef1b08b
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_gold_3.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_gold_add.png b/codemirror_ui/images/silk/medal_gold_add.png
new file mode 100644
index 0000000..dcade0d
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_gold_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_gold_delete.png b/codemirror_ui/images/silk/medal_gold_delete.png
new file mode 100644
index 0000000..84b06d5
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_gold_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_silver_1.png b/codemirror_ui/images/silk/medal_silver_1.png
new file mode 100644
index 0000000..75a64da
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_silver_1.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_silver_2.png b/codemirror_ui/images/silk/medal_silver_2.png
new file mode 100644
index 0000000..2e0fe75
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_silver_2.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_silver_3.png b/codemirror_ui/images/silk/medal_silver_3.png
new file mode 100644
index 0000000..e385b54
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_silver_3.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_silver_add.png b/codemirror_ui/images/silk/medal_silver_add.png
new file mode 100644
index 0000000..b0633fa
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_silver_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/medal_silver_delete.png b/codemirror_ui/images/silk/medal_silver_delete.png
new file mode 100644
index 0000000..06cab46
--- /dev/null
+++ b/codemirror_ui/images/silk/medal_silver_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/money.png b/codemirror_ui/images/silk/money.png
new file mode 100644
index 0000000..42c52d0
--- /dev/null
+++ b/codemirror_ui/images/silk/money.png
Binary files differ
diff --git a/codemirror_ui/images/silk/money_add.png b/codemirror_ui/images/silk/money_add.png
new file mode 100644
index 0000000..588fa9d
--- /dev/null
+++ b/codemirror_ui/images/silk/money_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/money_delete.png b/codemirror_ui/images/silk/money_delete.png
new file mode 100644
index 0000000..eae2c52
--- /dev/null
+++ b/codemirror_ui/images/silk/money_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/money_dollar.png b/codemirror_ui/images/silk/money_dollar.png
new file mode 100644
index 0000000..59af163
--- /dev/null
+++ b/codemirror_ui/images/silk/money_dollar.png
Binary files differ
diff --git a/codemirror_ui/images/silk/money_euro.png b/codemirror_ui/images/silk/money_euro.png
new file mode 100644
index 0000000..b322ba9
--- /dev/null
+++ b/codemirror_ui/images/silk/money_euro.png
Binary files differ
diff --git a/codemirror_ui/images/silk/money_pound.png b/codemirror_ui/images/silk/money_pound.png
new file mode 100644
index 0000000..b711364
--- /dev/null
+++ b/codemirror_ui/images/silk/money_pound.png
Binary files differ
diff --git a/codemirror_ui/images/silk/money_yen.png b/codemirror_ui/images/silk/money_yen.png
new file mode 100644
index 0000000..228a677
--- /dev/null
+++ b/codemirror_ui/images/silk/money_yen.png
Binary files differ
diff --git a/codemirror_ui/images/silk/monitor.png b/codemirror_ui/images/silk/monitor.png
new file mode 100644
index 0000000..d040bd0
--- /dev/null
+++ b/codemirror_ui/images/silk/monitor.png
Binary files differ
diff --git a/codemirror_ui/images/silk/monitor_add.png b/codemirror_ui/images/silk/monitor_add.png
new file mode 100644
index 0000000..a818066
--- /dev/null
+++ b/codemirror_ui/images/silk/monitor_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/monitor_delete.png b/codemirror_ui/images/silk/monitor_delete.png
new file mode 100644
index 0000000..3733256
--- /dev/null
+++ b/codemirror_ui/images/silk/monitor_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/monitor_edit.png b/codemirror_ui/images/silk/monitor_edit.png
new file mode 100644
index 0000000..f772c56
--- /dev/null
+++ b/codemirror_ui/images/silk/monitor_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/monitor_error.png b/codemirror_ui/images/silk/monitor_error.png
new file mode 100644
index 0000000..270c501
--- /dev/null
+++ b/codemirror_ui/images/silk/monitor_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/monitor_go.png b/codemirror_ui/images/silk/monitor_go.png
new file mode 100644
index 0000000..8af3eda
--- /dev/null
+++ b/codemirror_ui/images/silk/monitor_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/monitor_lightning.png b/codemirror_ui/images/silk/monitor_lightning.png
new file mode 100644
index 0000000..06e53a9
--- /dev/null
+++ b/codemirror_ui/images/silk/monitor_lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/monitor_link.png b/codemirror_ui/images/silk/monitor_link.png
new file mode 100644
index 0000000..a014b02
--- /dev/null
+++ b/codemirror_ui/images/silk/monitor_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/mouse.png b/codemirror_ui/images/silk/mouse.png
new file mode 100644
index 0000000..63a92fa
--- /dev/null
+++ b/codemirror_ui/images/silk/mouse.png
Binary files differ
diff --git a/codemirror_ui/images/silk/mouse_add.png b/codemirror_ui/images/silk/mouse_add.png
new file mode 100644
index 0000000..65bcab5
--- /dev/null
+++ b/codemirror_ui/images/silk/mouse_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/mouse_delete.png b/codemirror_ui/images/silk/mouse_delete.png
new file mode 100644
index 0000000..7286566
--- /dev/null
+++ b/codemirror_ui/images/silk/mouse_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/mouse_error.png b/codemirror_ui/images/silk/mouse_error.png
new file mode 100644
index 0000000..bcc1562
--- /dev/null
+++ b/codemirror_ui/images/silk/mouse_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/music.png b/codemirror_ui/images/silk/music.png
new file mode 100644
index 0000000..a8b3ede
--- /dev/null
+++ b/codemirror_ui/images/silk/music.png
Binary files differ
diff --git a/codemirror_ui/images/silk/new.png b/codemirror_ui/images/silk/new.png
new file mode 100644
index 0000000..6a9bf03
--- /dev/null
+++ b/codemirror_ui/images/silk/new.png
Binary files differ
diff --git a/codemirror_ui/images/silk/newspaper.png b/codemirror_ui/images/silk/newspaper.png
new file mode 100644
index 0000000..6a2ecce
--- /dev/null
+++ b/codemirror_ui/images/silk/newspaper.png
Binary files differ
diff --git a/codemirror_ui/images/silk/newspaper_add.png b/codemirror_ui/images/silk/newspaper_add.png
new file mode 100644
index 0000000..8140e8c
--- /dev/null
+++ b/codemirror_ui/images/silk/newspaper_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/newspaper_delete.png b/codemirror_ui/images/silk/newspaper_delete.png
new file mode 100644
index 0000000..bde96ce
--- /dev/null
+++ b/codemirror_ui/images/silk/newspaper_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/newspaper_go.png b/codemirror_ui/images/silk/newspaper_go.png
new file mode 100644
index 0000000..fd61428
--- /dev/null
+++ b/codemirror_ui/images/silk/newspaper_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/newspaper_link.png b/codemirror_ui/images/silk/newspaper_link.png
new file mode 100644
index 0000000..99e57cb
--- /dev/null
+++ b/codemirror_ui/images/silk/newspaper_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/note.png b/codemirror_ui/images/silk/note.png
new file mode 100644
index 0000000..244e6ca
--- /dev/null
+++ b/codemirror_ui/images/silk/note.png
Binary files differ
diff --git a/codemirror_ui/images/silk/note_add.png b/codemirror_ui/images/silk/note_add.png
new file mode 100644
index 0000000..abdad91
--- /dev/null
+++ b/codemirror_ui/images/silk/note_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/note_delete.png b/codemirror_ui/images/silk/note_delete.png
new file mode 100644
index 0000000..8a1f0ff
--- /dev/null
+++ b/codemirror_ui/images/silk/note_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/note_edit.png b/codemirror_ui/images/silk/note_edit.png
new file mode 100644
index 0000000..291bfc7
--- /dev/null
+++ b/codemirror_ui/images/silk/note_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/note_error.png b/codemirror_ui/images/silk/note_error.png
new file mode 100644
index 0000000..896dadf
--- /dev/null
+++ b/codemirror_ui/images/silk/note_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/note_go.png b/codemirror_ui/images/silk/note_go.png
new file mode 100644
index 0000000..49e54fd
--- /dev/null
+++ b/codemirror_ui/images/silk/note_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/overlays.png b/codemirror_ui/images/silk/overlays.png
new file mode 100644
index 0000000..ab3100b
--- /dev/null
+++ b/codemirror_ui/images/silk/overlays.png
Binary files differ
diff --git a/codemirror_ui/images/silk/package.png b/codemirror_ui/images/silk/package.png
new file mode 100644
index 0000000..da3c2a2
--- /dev/null
+++ b/codemirror_ui/images/silk/package.png
Binary files differ
diff --git a/codemirror_ui/images/silk/package_add.png b/codemirror_ui/images/silk/package_add.png
new file mode 100644
index 0000000..9c8a9da
--- /dev/null
+++ b/codemirror_ui/images/silk/package_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/package_delete.png b/codemirror_ui/images/silk/package_delete.png
new file mode 100644
index 0000000..86f7fbc
--- /dev/null
+++ b/codemirror_ui/images/silk/package_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/package_go.png b/codemirror_ui/images/silk/package_go.png
new file mode 100644
index 0000000..aace63a
--- /dev/null
+++ b/codemirror_ui/images/silk/package_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/package_green.png b/codemirror_ui/images/silk/package_green.png
new file mode 100644
index 0000000..25b28bb
--- /dev/null
+++ b/codemirror_ui/images/silk/package_green.png
Binary files differ
diff --git a/codemirror_ui/images/silk/package_link.png b/codemirror_ui/images/silk/package_link.png
new file mode 100644
index 0000000..48e7ab5
--- /dev/null
+++ b/codemirror_ui/images/silk/package_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page.png b/codemirror_ui/images/silk/page.png
new file mode 100644
index 0000000..03ddd79
--- /dev/null
+++ b/codemirror_ui/images/silk/page.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_add.png b/codemirror_ui/images/silk/page_add.png
new file mode 100644
index 0000000..d5bfa07
--- /dev/null
+++ b/codemirror_ui/images/silk/page_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_attach.png b/codemirror_ui/images/silk/page_attach.png
new file mode 100644
index 0000000..89ee2da
--- /dev/null
+++ b/codemirror_ui/images/silk/page_attach.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_code.png b/codemirror_ui/images/silk/page_code.png
new file mode 100644
index 0000000..f7ea904
--- /dev/null
+++ b/codemirror_ui/images/silk/page_code.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_copy.png b/codemirror_ui/images/silk/page_copy.png
new file mode 100644
index 0000000..195dc6d
--- /dev/null
+++ b/codemirror_ui/images/silk/page_copy.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_delete.png b/codemirror_ui/images/silk/page_delete.png
new file mode 100644
index 0000000..3141467
--- /dev/null
+++ b/codemirror_ui/images/silk/page_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_edit.png b/codemirror_ui/images/silk/page_edit.png
new file mode 100644
index 0000000..046811e
--- /dev/null
+++ b/codemirror_ui/images/silk/page_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_error.png b/codemirror_ui/images/silk/page_error.png
new file mode 100644
index 0000000..f07f449
--- /dev/null
+++ b/codemirror_ui/images/silk/page_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_excel.png b/codemirror_ui/images/silk/page_excel.png
new file mode 100644
index 0000000..eb6158e
--- /dev/null
+++ b/codemirror_ui/images/silk/page_excel.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_find.png b/codemirror_ui/images/silk/page_find.png
new file mode 100644
index 0000000..2f19388
--- /dev/null
+++ b/codemirror_ui/images/silk/page_find.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_gear.png b/codemirror_ui/images/silk/page_gear.png
new file mode 100644
index 0000000..8e83281
--- /dev/null
+++ b/codemirror_ui/images/silk/page_gear.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_go.png b/codemirror_ui/images/silk/page_go.png
new file mode 100644
index 0000000..80fe1ed
--- /dev/null
+++ b/codemirror_ui/images/silk/page_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_green.png b/codemirror_ui/images/silk/page_green.png
new file mode 100644
index 0000000..de8e003
--- /dev/null
+++ b/codemirror_ui/images/silk/page_green.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_key.png b/codemirror_ui/images/silk/page_key.png
new file mode 100644
index 0000000..d6626cb
--- /dev/null
+++ b/codemirror_ui/images/silk/page_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_lightning.png b/codemirror_ui/images/silk/page_lightning.png
new file mode 100644
index 0000000..7e56870
--- /dev/null
+++ b/codemirror_ui/images/silk/page_lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_link.png b/codemirror_ui/images/silk/page_link.png
new file mode 100644
index 0000000..312eab0
--- /dev/null
+++ b/codemirror_ui/images/silk/page_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_paintbrush.png b/codemirror_ui/images/silk/page_paintbrush.png
new file mode 100644
index 0000000..246a2f0
--- /dev/null
+++ b/codemirror_ui/images/silk/page_paintbrush.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_paste.png b/codemirror_ui/images/silk/page_paste.png
new file mode 100644
index 0000000..968f073
--- /dev/null
+++ b/codemirror_ui/images/silk/page_paste.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_red.png b/codemirror_ui/images/silk/page_red.png
new file mode 100644
index 0000000..0b18247
--- /dev/null
+++ b/codemirror_ui/images/silk/page_red.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_refresh.png b/codemirror_ui/images/silk/page_refresh.png
new file mode 100644
index 0000000..cf347c7
--- /dev/null
+++ b/codemirror_ui/images/silk/page_refresh.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_save.png b/codemirror_ui/images/silk/page_save.png
new file mode 100644
index 0000000..caea546
--- /dev/null
+++ b/codemirror_ui/images/silk/page_save.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white.png b/codemirror_ui/images/silk/page_white.png
new file mode 100644
index 0000000..8b8b1ca
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_acrobat.png b/codemirror_ui/images/silk/page_white_acrobat.png
new file mode 100644
index 0000000..8f8095e
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_acrobat.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_actionscript.png b/codemirror_ui/images/silk/page_white_actionscript.png
new file mode 100644
index 0000000..159b240
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_actionscript.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_add.png b/codemirror_ui/images/silk/page_white_add.png
new file mode 100644
index 0000000..aa23dde
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_c.png b/codemirror_ui/images/silk/page_white_c.png
new file mode 100644
index 0000000..34a05cc
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_c.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_camera.png b/codemirror_ui/images/silk/page_white_camera.png
new file mode 100644
index 0000000..f501a59
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_camera.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_cd.png b/codemirror_ui/images/silk/page_white_cd.png
new file mode 100644
index 0000000..848bdaf
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_cd.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_code.png b/codemirror_ui/images/silk/page_white_code.png
new file mode 100644
index 0000000..0c76bd1
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_code.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_code_red.png b/codemirror_ui/images/silk/page_white_code_red.png
new file mode 100644
index 0000000..87a6914
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_code_red.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_coldfusion.png b/codemirror_ui/images/silk/page_white_coldfusion.png
new file mode 100644
index 0000000..c66011f
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_coldfusion.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_compressed.png b/codemirror_ui/images/silk/page_white_compressed.png
new file mode 100644
index 0000000..2b6b100
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_compressed.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_copy.png b/codemirror_ui/images/silk/page_white_copy.png
new file mode 100644
index 0000000..a9f31a2
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_copy.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_cplusplus.png b/codemirror_ui/images/silk/page_white_cplusplus.png
new file mode 100644
index 0000000..a87cf84
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_cplusplus.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_csharp.png b/codemirror_ui/images/silk/page_white_csharp.png
new file mode 100644
index 0000000..ffb8fc9
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_csharp.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_cup.png b/codemirror_ui/images/silk/page_white_cup.png
new file mode 100644
index 0000000..0a7d6f4
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_cup.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_database.png b/codemirror_ui/images/silk/page_white_database.png
new file mode 100644
index 0000000..bddba1f
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_database.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_delete.png b/codemirror_ui/images/silk/page_white_delete.png
new file mode 100644
index 0000000..af1ecaf
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_dvd.png b/codemirror_ui/images/silk/page_white_dvd.png
new file mode 100644
index 0000000..4cc537a
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_dvd.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_edit.png b/codemirror_ui/images/silk/page_white_edit.png
new file mode 100644
index 0000000..b93e776
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_error.png b/codemirror_ui/images/silk/page_white_error.png
new file mode 100644
index 0000000..9fc5a0a
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_excel.png b/codemirror_ui/images/silk/page_white_excel.png
new file mode 100644
index 0000000..b977d7e
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_excel.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_find.png b/codemirror_ui/images/silk/page_white_find.png
new file mode 100644
index 0000000..5818436
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_find.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_flash.png b/codemirror_ui/images/silk/page_white_flash.png
new file mode 100644
index 0000000..5769120
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_flash.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_freehand.png b/codemirror_ui/images/silk/page_white_freehand.png
new file mode 100644
index 0000000..8d719df
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_freehand.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_gear.png b/codemirror_ui/images/silk/page_white_gear.png
new file mode 100644
index 0000000..106f5aa
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_gear.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_get.png b/codemirror_ui/images/silk/page_white_get.png
new file mode 100644
index 0000000..e4a1ecb
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_get.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_go.png b/codemirror_ui/images/silk/page_white_go.png
new file mode 100644
index 0000000..7e62a92
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_h.png b/codemirror_ui/images/silk/page_white_h.png
new file mode 100644
index 0000000..e902abb
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_h.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_horizontal.png b/codemirror_ui/images/silk/page_white_horizontal.png
new file mode 100644
index 0000000..1d2d0a4
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_horizontal.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_key.png b/codemirror_ui/images/silk/page_white_key.png
new file mode 100644
index 0000000..d616484
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_lightning.png b/codemirror_ui/images/silk/page_white_lightning.png
new file mode 100644
index 0000000..7215d1e
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_link.png b/codemirror_ui/images/silk/page_white_link.png
new file mode 100644
index 0000000..bf7bd1c
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_magnify.png b/codemirror_ui/images/silk/page_white_magnify.png
new file mode 100644
index 0000000..f6b74cc
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_magnify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_medal.png b/codemirror_ui/images/silk/page_white_medal.png
new file mode 100644
index 0000000..d3fffb6
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_medal.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_office.png b/codemirror_ui/images/silk/page_white_office.png
new file mode 100644
index 0000000..a65bcb3
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_office.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_paint.png b/codemirror_ui/images/silk/page_white_paint.png
new file mode 100644
index 0000000..23a37b8
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_paint.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_paintbrush.png b/codemirror_ui/images/silk/page_white_paintbrush.png
new file mode 100644
index 0000000..f907e44
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_paintbrush.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_paste.png b/codemirror_ui/images/silk/page_white_paste.png
new file mode 100644
index 0000000..5b2cbb3
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_paste.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_php.png b/codemirror_ui/images/silk/page_white_php.png
new file mode 100644
index 0000000..7868a25
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_php.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_picture.png b/codemirror_ui/images/silk/page_white_picture.png
new file mode 100644
index 0000000..134b669
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_picture.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_powerpoint.png b/codemirror_ui/images/silk/page_white_powerpoint.png
new file mode 100644
index 0000000..c4eff03
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_powerpoint.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_put.png b/codemirror_ui/images/silk/page_white_put.png
new file mode 100644
index 0000000..884ffd6
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_put.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_ruby.png b/codemirror_ui/images/silk/page_white_ruby.png
new file mode 100644
index 0000000..f59b7c4
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_ruby.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_stack.png b/codemirror_ui/images/silk/page_white_stack.png
new file mode 100644
index 0000000..44084ad
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_stack.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_star.png b/codemirror_ui/images/silk/page_white_star.png
new file mode 100644
index 0000000..3a1441c
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_star.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_swoosh.png b/codemirror_ui/images/silk/page_white_swoosh.png
new file mode 100644
index 0000000..e770829
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_swoosh.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_text.png b/codemirror_ui/images/silk/page_white_text.png
new file mode 100644
index 0000000..813f712
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_text.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_text_width.png b/codemirror_ui/images/silk/page_white_text_width.png
new file mode 100644
index 0000000..d9cf132
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_text_width.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_tux.png b/codemirror_ui/images/silk/page_white_tux.png
new file mode 100644
index 0000000..52699bf
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_tux.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_vector.png b/codemirror_ui/images/silk/page_white_vector.png
new file mode 100644
index 0000000..4a05955
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_vector.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_visualstudio.png b/codemirror_ui/images/silk/page_white_visualstudio.png
new file mode 100644
index 0000000..a0a433d
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_visualstudio.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_width.png b/codemirror_ui/images/silk/page_white_width.png
new file mode 100644
index 0000000..1eb8809
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_width.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_word.png b/codemirror_ui/images/silk/page_white_word.png
new file mode 100644
index 0000000..ae8ecbf
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_word.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_world.png b/codemirror_ui/images/silk/page_white_world.png
new file mode 100644
index 0000000..6ed2490
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_world.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_wrench.png b/codemirror_ui/images/silk/page_white_wrench.png
new file mode 100644
index 0000000..fecadd0
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_wrench.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_white_zip.png b/codemirror_ui/images/silk/page_white_zip.png
new file mode 100644
index 0000000..fd4bbcc
--- /dev/null
+++ b/codemirror_ui/images/silk/page_white_zip.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_word.png b/codemirror_ui/images/silk/page_word.png
new file mode 100644
index 0000000..834cdfa
--- /dev/null
+++ b/codemirror_ui/images/silk/page_word.png
Binary files differ
diff --git a/codemirror_ui/images/silk/page_world.png b/codemirror_ui/images/silk/page_world.png
new file mode 100644
index 0000000..b8895dd
--- /dev/null
+++ b/codemirror_ui/images/silk/page_world.png
Binary files differ
diff --git a/codemirror_ui/images/silk/paintbrush.png b/codemirror_ui/images/silk/paintbrush.png
new file mode 100644
index 0000000..a3ecf87
--- /dev/null
+++ b/codemirror_ui/images/silk/paintbrush.png
Binary files differ
diff --git a/codemirror_ui/images/silk/paintcan.png b/codemirror_ui/images/silk/paintcan.png
new file mode 100644
index 0000000..f82a886
--- /dev/null
+++ b/codemirror_ui/images/silk/paintcan.png
Binary files differ
diff --git a/codemirror_ui/images/silk/palette.png b/codemirror_ui/images/silk/palette.png
new file mode 100644
index 0000000..73c5b3f
--- /dev/null
+++ b/codemirror_ui/images/silk/palette.png
Binary files differ
diff --git a/codemirror_ui/images/silk/paste_plain.png b/codemirror_ui/images/silk/paste_plain.png
new file mode 100644
index 0000000..c0490eb
--- /dev/null
+++ b/codemirror_ui/images/silk/paste_plain.png
Binary files differ
diff --git a/codemirror_ui/images/silk/paste_word.png b/codemirror_ui/images/silk/paste_word.png
new file mode 100644
index 0000000..f6b87f8
--- /dev/null
+++ b/codemirror_ui/images/silk/paste_word.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pencil.png b/codemirror_ui/images/silk/pencil.png
new file mode 100644
index 0000000..0bfecd5
--- /dev/null
+++ b/codemirror_ui/images/silk/pencil.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pencil_add.png b/codemirror_ui/images/silk/pencil_add.png
new file mode 100644
index 0000000..902bbe6
--- /dev/null
+++ b/codemirror_ui/images/silk/pencil_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pencil_delete.png b/codemirror_ui/images/silk/pencil_delete.png
new file mode 100644
index 0000000..d8944e6
--- /dev/null
+++ b/codemirror_ui/images/silk/pencil_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pencil_go.png b/codemirror_ui/images/silk/pencil_go.png
new file mode 100644
index 0000000..937bded
--- /dev/null
+++ b/codemirror_ui/images/silk/pencil_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/phone.png b/codemirror_ui/images/silk/phone.png
new file mode 100644
index 0000000..c39f162
--- /dev/null
+++ b/codemirror_ui/images/silk/phone.png
Binary files differ
diff --git a/codemirror_ui/images/silk/phone_add.png b/codemirror_ui/images/silk/phone_add.png
new file mode 100644
index 0000000..d3555e0
--- /dev/null
+++ b/codemirror_ui/images/silk/phone_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/phone_delete.png b/codemirror_ui/images/silk/phone_delete.png
new file mode 100644
index 0000000..bbe4f8a
--- /dev/null
+++ b/codemirror_ui/images/silk/phone_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/phone_sound.png b/codemirror_ui/images/silk/phone_sound.png
new file mode 100644
index 0000000..7fdf1c5
--- /dev/null
+++ b/codemirror_ui/images/silk/phone_sound.png
Binary files differ
diff --git a/codemirror_ui/images/silk/photo.png b/codemirror_ui/images/silk/photo.png
new file mode 100644
index 0000000..6c2aaaa
--- /dev/null
+++ b/codemirror_ui/images/silk/photo.png
Binary files differ
diff --git a/codemirror_ui/images/silk/photo_add.png b/codemirror_ui/images/silk/photo_add.png
new file mode 100644
index 0000000..63cc355
--- /dev/null
+++ b/codemirror_ui/images/silk/photo_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/photo_delete.png b/codemirror_ui/images/silk/photo_delete.png
new file mode 100644
index 0000000..18b67df
--- /dev/null
+++ b/codemirror_ui/images/silk/photo_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/photo_link.png b/codemirror_ui/images/silk/photo_link.png
new file mode 100644
index 0000000..e6bb35f
--- /dev/null
+++ b/codemirror_ui/images/silk/photo_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/photos.png b/codemirror_ui/images/silk/photos.png
new file mode 100644
index 0000000..8836fe6
--- /dev/null
+++ b/codemirror_ui/images/silk/photos.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture.png b/codemirror_ui/images/silk/picture.png
new file mode 100644
index 0000000..4a158fe
--- /dev/null
+++ b/codemirror_ui/images/silk/picture.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture_add.png b/codemirror_ui/images/silk/picture_add.png
new file mode 100644
index 0000000..d6d3f85
--- /dev/null
+++ b/codemirror_ui/images/silk/picture_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture_delete.png b/codemirror_ui/images/silk/picture_delete.png
new file mode 100644
index 0000000..cca9f53
--- /dev/null
+++ b/codemirror_ui/images/silk/picture_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture_edit.png b/codemirror_ui/images/silk/picture_edit.png
new file mode 100644
index 0000000..9a70c34
--- /dev/null
+++ b/codemirror_ui/images/silk/picture_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture_empty.png b/codemirror_ui/images/silk/picture_empty.png
new file mode 100644
index 0000000..abd2b9b
--- /dev/null
+++ b/codemirror_ui/images/silk/picture_empty.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture_error.png b/codemirror_ui/images/silk/picture_error.png
new file mode 100644
index 0000000..d41d90d
--- /dev/null
+++ b/codemirror_ui/images/silk/picture_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture_go.png b/codemirror_ui/images/silk/picture_go.png
new file mode 100644
index 0000000..27c63c5
--- /dev/null
+++ b/codemirror_ui/images/silk/picture_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture_key.png b/codemirror_ui/images/silk/picture_key.png
new file mode 100644
index 0000000..667086c
--- /dev/null
+++ b/codemirror_ui/images/silk/picture_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture_link.png b/codemirror_ui/images/silk/picture_link.png
new file mode 100644
index 0000000..42dca74
--- /dev/null
+++ b/codemirror_ui/images/silk/picture_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/picture_save.png b/codemirror_ui/images/silk/picture_save.png
new file mode 100644
index 0000000..777fb5d
--- /dev/null
+++ b/codemirror_ui/images/silk/picture_save.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pictures.png b/codemirror_ui/images/silk/pictures.png
new file mode 100644
index 0000000..d9591c1
--- /dev/null
+++ b/codemirror_ui/images/silk/pictures.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pilcrow.png b/codemirror_ui/images/silk/pilcrow.png
new file mode 100644
index 0000000..95704fb
--- /dev/null
+++ b/codemirror_ui/images/silk/pilcrow.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pill.png b/codemirror_ui/images/silk/pill.png
new file mode 100644
index 0000000..f2bdef6
--- /dev/null
+++ b/codemirror_ui/images/silk/pill.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pill_add.png b/codemirror_ui/images/silk/pill_add.png
new file mode 100644
index 0000000..ac9c2df
--- /dev/null
+++ b/codemirror_ui/images/silk/pill_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pill_delete.png b/codemirror_ui/images/silk/pill_delete.png
new file mode 100644
index 0000000..c61592e
--- /dev/null
+++ b/codemirror_ui/images/silk/pill_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/pill_go.png b/codemirror_ui/images/silk/pill_go.png
new file mode 100644
index 0000000..e5c07d4
--- /dev/null
+++ b/codemirror_ui/images/silk/pill_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/plugin.png b/codemirror_ui/images/silk/plugin.png
new file mode 100644
index 0000000..6187b15
--- /dev/null
+++ b/codemirror_ui/images/silk/plugin.png
Binary files differ
diff --git a/codemirror_ui/images/silk/plugin_add.png b/codemirror_ui/images/silk/plugin_add.png
new file mode 100644
index 0000000..ae43690
--- /dev/null
+++ b/codemirror_ui/images/silk/plugin_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/plugin_delete.png b/codemirror_ui/images/silk/plugin_delete.png
new file mode 100644
index 0000000..d9c3376
--- /dev/null
+++ b/codemirror_ui/images/silk/plugin_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/plugin_disabled.png b/codemirror_ui/images/silk/plugin_disabled.png
new file mode 100644
index 0000000..f4f6be5
--- /dev/null
+++ b/codemirror_ui/images/silk/plugin_disabled.png
Binary files differ
diff --git a/codemirror_ui/images/silk/plugin_edit.png b/codemirror_ui/images/silk/plugin_edit.png
new file mode 100644
index 0000000..b6cb0ec
--- /dev/null
+++ b/codemirror_ui/images/silk/plugin_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/plugin_error.png b/codemirror_ui/images/silk/plugin_error.png
new file mode 100644
index 0000000..cff65d7
--- /dev/null
+++ b/codemirror_ui/images/silk/plugin_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/plugin_go.png b/codemirror_ui/images/silk/plugin_go.png
new file mode 100644
index 0000000..41da991
--- /dev/null
+++ b/codemirror_ui/images/silk/plugin_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/plugin_link.png b/codemirror_ui/images/silk/plugin_link.png
new file mode 100644
index 0000000..445c188
--- /dev/null
+++ b/codemirror_ui/images/silk/plugin_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/printer.png b/codemirror_ui/images/silk/printer.png
new file mode 100644
index 0000000..a350d18
--- /dev/null
+++ b/codemirror_ui/images/silk/printer.png
Binary files differ
diff --git a/codemirror_ui/images/silk/printer_add.png b/codemirror_ui/images/silk/printer_add.png
new file mode 100644
index 0000000..d228d05
--- /dev/null
+++ b/codemirror_ui/images/silk/printer_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/printer_delete.png b/codemirror_ui/images/silk/printer_delete.png
new file mode 100644
index 0000000..1d8605f
--- /dev/null
+++ b/codemirror_ui/images/silk/printer_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/printer_empty.png b/codemirror_ui/images/silk/printer_empty.png
new file mode 100644
index 0000000..94e8c16
--- /dev/null
+++ b/codemirror_ui/images/silk/printer_empty.png
Binary files differ
diff --git a/codemirror_ui/images/silk/printer_error.png b/codemirror_ui/images/silk/printer_error.png
new file mode 100644
index 0000000..279ebb0
--- /dev/null
+++ b/codemirror_ui/images/silk/printer_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/rainbow.png b/codemirror_ui/images/silk/rainbow.png
new file mode 100644
index 0000000..5ede989
--- /dev/null
+++ b/codemirror_ui/images/silk/rainbow.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report.png b/codemirror_ui/images/silk/report.png
new file mode 100644
index 0000000..779ad58
--- /dev/null
+++ b/codemirror_ui/images/silk/report.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_add.png b/codemirror_ui/images/silk/report_add.png
new file mode 100644
index 0000000..d5eac9b
--- /dev/null
+++ b/codemirror_ui/images/silk/report_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_delete.png b/codemirror_ui/images/silk/report_delete.png
new file mode 100644
index 0000000..dcce0b6
--- /dev/null
+++ b/codemirror_ui/images/silk/report_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_disk.png b/codemirror_ui/images/silk/report_disk.png
new file mode 100644
index 0000000..1c856cd
--- /dev/null
+++ b/codemirror_ui/images/silk/report_disk.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_edit.png b/codemirror_ui/images/silk/report_edit.png
new file mode 100644
index 0000000..c61a6d8
--- /dev/null
+++ b/codemirror_ui/images/silk/report_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_go.png b/codemirror_ui/images/silk/report_go.png
new file mode 100644
index 0000000..f35a979
--- /dev/null
+++ b/codemirror_ui/images/silk/report_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_key.png b/codemirror_ui/images/silk/report_key.png
new file mode 100644
index 0000000..90b758e
--- /dev/null
+++ b/codemirror_ui/images/silk/report_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_link.png b/codemirror_ui/images/silk/report_link.png
new file mode 100644
index 0000000..23f2611
--- /dev/null
+++ b/codemirror_ui/images/silk/report_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_magnify.png b/codemirror_ui/images/silk/report_magnify.png
new file mode 100644
index 0000000..aeaa889
--- /dev/null
+++ b/codemirror_ui/images/silk/report_magnify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_picture.png b/codemirror_ui/images/silk/report_picture.png
new file mode 100644
index 0000000..3a9a7e5
--- /dev/null
+++ b/codemirror_ui/images/silk/report_picture.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_user.png b/codemirror_ui/images/silk/report_user.png
new file mode 100644
index 0000000..7766edd
--- /dev/null
+++ b/codemirror_ui/images/silk/report_user.png
Binary files differ
diff --git a/codemirror_ui/images/silk/report_word.png b/codemirror_ui/images/silk/report_word.png
new file mode 100644
index 0000000..9951342
--- /dev/null
+++ b/codemirror_ui/images/silk/report_word.png
Binary files differ
diff --git a/codemirror_ui/images/silk/resultset_first.png b/codemirror_ui/images/silk/resultset_first.png
new file mode 100644
index 0000000..b03eaf8
--- /dev/null
+++ b/codemirror_ui/images/silk/resultset_first.png
Binary files differ
diff --git a/codemirror_ui/images/silk/resultset_last.png b/codemirror_ui/images/silk/resultset_last.png
new file mode 100644
index 0000000..8ec8947
--- /dev/null
+++ b/codemirror_ui/images/silk/resultset_last.png
Binary files differ
diff --git a/codemirror_ui/images/silk/resultset_next.png b/codemirror_ui/images/silk/resultset_next.png
new file mode 100644
index 0000000..e252606
--- /dev/null
+++ b/codemirror_ui/images/silk/resultset_next.png
Binary files differ
diff --git a/codemirror_ui/images/silk/resultset_previous.png b/codemirror_ui/images/silk/resultset_previous.png
new file mode 100644
index 0000000..18f9cc1
--- /dev/null
+++ b/codemirror_ui/images/silk/resultset_previous.png
Binary files differ
diff --git a/codemirror_ui/images/silk/rosette.png b/codemirror_ui/images/silk/rosette.png
new file mode 100644
index 0000000..f233bc7
--- /dev/null
+++ b/codemirror_ui/images/silk/rosette.png
Binary files differ
diff --git a/codemirror_ui/images/silk/rss.png b/codemirror_ui/images/silk/rss.png
new file mode 100644
index 0000000..1dc6ff3
--- /dev/null
+++ b/codemirror_ui/images/silk/rss.png
Binary files differ
diff --git a/codemirror_ui/images/silk/rss_add.png b/codemirror_ui/images/silk/rss_add.png
new file mode 100644
index 0000000..b590beb
--- /dev/null
+++ b/codemirror_ui/images/silk/rss_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/rss_delete.png b/codemirror_ui/images/silk/rss_delete.png
new file mode 100644
index 0000000..9deb738
--- /dev/null
+++ b/codemirror_ui/images/silk/rss_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/rss_go.png b/codemirror_ui/images/silk/rss_go.png
new file mode 100644
index 0000000..43a86bf
--- /dev/null
+++ b/codemirror_ui/images/silk/rss_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/rss_valid.png b/codemirror_ui/images/silk/rss_valid.png
new file mode 100644
index 0000000..a6d0b0e
--- /dev/null
+++ b/codemirror_ui/images/silk/rss_valid.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ruby.png b/codemirror_ui/images/silk/ruby.png
new file mode 100644
index 0000000..f763a16
--- /dev/null
+++ b/codemirror_ui/images/silk/ruby.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ruby_add.png b/codemirror_ui/images/silk/ruby_add.png
new file mode 100644
index 0000000..a2cd648
--- /dev/null
+++ b/codemirror_ui/images/silk/ruby_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ruby_delete.png b/codemirror_ui/images/silk/ruby_delete.png
new file mode 100644
index 0000000..3002263
--- /dev/null
+++ b/codemirror_ui/images/silk/ruby_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ruby_gear.png b/codemirror_ui/images/silk/ruby_gear.png
new file mode 100644
index 0000000..4a10590
--- /dev/null
+++ b/codemirror_ui/images/silk/ruby_gear.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ruby_get.png b/codemirror_ui/images/silk/ruby_get.png
new file mode 100644
index 0000000..f5203c7
--- /dev/null
+++ b/codemirror_ui/images/silk/ruby_get.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ruby_go.png b/codemirror_ui/images/silk/ruby_go.png
new file mode 100644
index 0000000..d8d276e
--- /dev/null
+++ b/codemirror_ui/images/silk/ruby_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ruby_key.png b/codemirror_ui/images/silk/ruby_key.png
new file mode 100644
index 0000000..451cfeb
--- /dev/null
+++ b/codemirror_ui/images/silk/ruby_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ruby_link.png b/codemirror_ui/images/silk/ruby_link.png
new file mode 100644
index 0000000..bf4be52
--- /dev/null
+++ b/codemirror_ui/images/silk/ruby_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/ruby_put.png b/codemirror_ui/images/silk/ruby_put.png
new file mode 100644
index 0000000..e026323
--- /dev/null
+++ b/codemirror_ui/images/silk/ruby_put.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script.png b/codemirror_ui/images/silk/script.png
new file mode 100644
index 0000000..0f9ed4d
--- /dev/null
+++ b/codemirror_ui/images/silk/script.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_add.png b/codemirror_ui/images/silk/script_add.png
new file mode 100644
index 0000000..d650552
--- /dev/null
+++ b/codemirror_ui/images/silk/script_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_code.png b/codemirror_ui/images/silk/script_code.png
new file mode 100644
index 0000000..63fe6ce
--- /dev/null
+++ b/codemirror_ui/images/silk/script_code.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_code_red.png b/codemirror_ui/images/silk/script_code_red.png
new file mode 100644
index 0000000..8fcf0f0
--- /dev/null
+++ b/codemirror_ui/images/silk/script_code_red.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_delete.png b/codemirror_ui/images/silk/script_delete.png
new file mode 100644
index 0000000..e6500ce
--- /dev/null
+++ b/codemirror_ui/images/silk/script_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_edit.png b/codemirror_ui/images/silk/script_edit.png
new file mode 100644
index 0000000..b4d31ce
--- /dev/null
+++ b/codemirror_ui/images/silk/script_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_error.png b/codemirror_ui/images/silk/script_error.png
new file mode 100644
index 0000000..0491954
--- /dev/null
+++ b/codemirror_ui/images/silk/script_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_gear.png b/codemirror_ui/images/silk/script_gear.png
new file mode 100644
index 0000000..56fcf84
--- /dev/null
+++ b/codemirror_ui/images/silk/script_gear.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_go.png b/codemirror_ui/images/silk/script_go.png
new file mode 100644
index 0000000..8e154e2
--- /dev/null
+++ b/codemirror_ui/images/silk/script_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_key.png b/codemirror_ui/images/silk/script_key.png
new file mode 100644
index 0000000..49bb24d
--- /dev/null
+++ b/codemirror_ui/images/silk/script_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_lightning.png b/codemirror_ui/images/silk/script_lightning.png
new file mode 100644
index 0000000..b3fa18c
--- /dev/null
+++ b/codemirror_ui/images/silk/script_lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_link.png b/codemirror_ui/images/silk/script_link.png
new file mode 100644
index 0000000..bdeb985
--- /dev/null
+++ b/codemirror_ui/images/silk/script_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_palette.png b/codemirror_ui/images/silk/script_palette.png
new file mode 100644
index 0000000..6d46962
--- /dev/null
+++ b/codemirror_ui/images/silk/script_palette.png
Binary files differ
diff --git a/codemirror_ui/images/silk/script_save.png b/codemirror_ui/images/silk/script_save.png
new file mode 100644
index 0000000..36216d8
--- /dev/null
+++ b/codemirror_ui/images/silk/script_save.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server.png b/codemirror_ui/images/silk/server.png
new file mode 100644
index 0000000..720a237
--- /dev/null
+++ b/codemirror_ui/images/silk/server.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_add.png b/codemirror_ui/images/silk/server_add.png
new file mode 100644
index 0000000..3f10a3a
--- /dev/null
+++ b/codemirror_ui/images/silk/server_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_chart.png b/codemirror_ui/images/silk/server_chart.png
new file mode 100644
index 0000000..1128d3f
--- /dev/null
+++ b/codemirror_ui/images/silk/server_chart.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_compressed.png b/codemirror_ui/images/silk/server_compressed.png
new file mode 100644
index 0000000..bf49fad
--- /dev/null
+++ b/codemirror_ui/images/silk/server_compressed.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_connect.png b/codemirror_ui/images/silk/server_connect.png
new file mode 100644
index 0000000..49b2691
--- /dev/null
+++ b/codemirror_ui/images/silk/server_connect.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_database.png b/codemirror_ui/images/silk/server_database.png
new file mode 100644
index 0000000..b24e826
--- /dev/null
+++ b/codemirror_ui/images/silk/server_database.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_delete.png b/codemirror_ui/images/silk/server_delete.png
new file mode 100644
index 0000000..61e740f
--- /dev/null
+++ b/codemirror_ui/images/silk/server_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_edit.png b/codemirror_ui/images/silk/server_edit.png
new file mode 100644
index 0000000..dc76253
--- /dev/null
+++ b/codemirror_ui/images/silk/server_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_error.png b/codemirror_ui/images/silk/server_error.png
new file mode 100644
index 0000000..f640256
--- /dev/null
+++ b/codemirror_ui/images/silk/server_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_go.png b/codemirror_ui/images/silk/server_go.png
new file mode 100644
index 0000000..540c8e2
--- /dev/null
+++ b/codemirror_ui/images/silk/server_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_key.png b/codemirror_ui/images/silk/server_key.png
new file mode 100644
index 0000000..ecd5174
--- /dev/null
+++ b/codemirror_ui/images/silk/server_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_lightning.png b/codemirror_ui/images/silk/server_lightning.png
new file mode 100644
index 0000000..b0f4e46
--- /dev/null
+++ b/codemirror_ui/images/silk/server_lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_link.png b/codemirror_ui/images/silk/server_link.png
new file mode 100644
index 0000000..e8821df
--- /dev/null
+++ b/codemirror_ui/images/silk/server_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/server_uncompressed.png b/codemirror_ui/images/silk/server_uncompressed.png
new file mode 100644
index 0000000..86e8325
--- /dev/null
+++ b/codemirror_ui/images/silk/server_uncompressed.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shading.png b/codemirror_ui/images/silk/shading.png
new file mode 100644
index 0000000..09275f9
--- /dev/null
+++ b/codemirror_ui/images/silk/shading.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_align_bottom.png b/codemirror_ui/images/silk/shape_align_bottom.png
new file mode 100644
index 0000000..55d2694
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_align_bottom.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_align_center.png b/codemirror_ui/images/silk/shape_align_center.png
new file mode 100644
index 0000000..efe9a98
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_align_center.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_align_left.png b/codemirror_ui/images/silk/shape_align_left.png
new file mode 100644
index 0000000..aaedc41
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_align_left.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_align_middle.png b/codemirror_ui/images/silk/shape_align_middle.png
new file mode 100644
index 0000000..d350dd8
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_align_middle.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_align_right.png b/codemirror_ui/images/silk/shape_align_right.png
new file mode 100644
index 0000000..ff556b6
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_align_right.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_align_top.png b/codemirror_ui/images/silk/shape_align_top.png
new file mode 100644
index 0000000..1181b43
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_align_top.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_flip_horizontal.png b/codemirror_ui/images/silk/shape_flip_horizontal.png
new file mode 100644
index 0000000..8667c81
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_flip_horizontal.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_flip_vertical.png b/codemirror_ui/images/silk/shape_flip_vertical.png
new file mode 100644
index 0000000..0bd66d1
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_flip_vertical.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_group.png b/codemirror_ui/images/silk/shape_group.png
new file mode 100644
index 0000000..bb2ff51
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_group.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_handles.png b/codemirror_ui/images/silk/shape_handles.png
new file mode 100644
index 0000000..ce27fe3
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_handles.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_move_back.png b/codemirror_ui/images/silk/shape_move_back.png
new file mode 100644
index 0000000..a216ffd
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_move_back.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_move_backwards.png b/codemirror_ui/images/silk/shape_move_backwards.png
new file mode 100644
index 0000000..ee3f9b2
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_move_backwards.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_move_forwards.png b/codemirror_ui/images/silk/shape_move_forwards.png
new file mode 100644
index 0000000..cfe4493
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_move_forwards.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_move_front.png b/codemirror_ui/images/silk/shape_move_front.png
new file mode 100644
index 0000000..b4a4e3b
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_move_front.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_rotate_anticlockwise.png b/codemirror_ui/images/silk/shape_rotate_anticlockwise.png
new file mode 100644
index 0000000..07a3020
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_rotate_anticlockwise.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_rotate_clockwise.png b/codemirror_ui/images/silk/shape_rotate_clockwise.png
new file mode 100644
index 0000000..b99db7d
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_rotate_clockwise.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_square.png b/codemirror_ui/images/silk/shape_square.png
new file mode 100644
index 0000000..33af046
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_square.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_square_add.png b/codemirror_ui/images/silk/shape_square_add.png
new file mode 100644
index 0000000..31edfce
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_square_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_square_delete.png b/codemirror_ui/images/silk/shape_square_delete.png
new file mode 100644
index 0000000..ede912d
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_square_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_square_edit.png b/codemirror_ui/images/silk/shape_square_edit.png
new file mode 100644
index 0000000..d28dc6b
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_square_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_square_error.png b/codemirror_ui/images/silk/shape_square_error.png
new file mode 100644
index 0000000..0d0dcfa
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_square_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_square_go.png b/codemirror_ui/images/silk/shape_square_go.png
new file mode 100644
index 0000000..5a2ad90
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_square_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_square_key.png b/codemirror_ui/images/silk/shape_square_key.png
new file mode 100644
index 0000000..c34b982
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_square_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_square_link.png b/codemirror_ui/images/silk/shape_square_link.png
new file mode 100644
index 0000000..b885fcc
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_square_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shape_ungroup.png b/codemirror_ui/images/silk/shape_ungroup.png
new file mode 100644
index 0000000..3a6f369
--- /dev/null
+++ b/codemirror_ui/images/silk/shape_ungroup.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shield.png b/codemirror_ui/images/silk/shield.png
new file mode 100644
index 0000000..3cb4e25
--- /dev/null
+++ b/codemirror_ui/images/silk/shield.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shield_add.png b/codemirror_ui/images/silk/shield_add.png
new file mode 100644
index 0000000..e20a1b4
--- /dev/null
+++ b/codemirror_ui/images/silk/shield_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shield_delete.png b/codemirror_ui/images/silk/shield_delete.png
new file mode 100644
index 0000000..22823a7
--- /dev/null
+++ b/codemirror_ui/images/silk/shield_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/shield_go.png b/codemirror_ui/images/silk/shield_go.png
new file mode 100644
index 0000000..e9bd852
--- /dev/null
+++ b/codemirror_ui/images/silk/shield_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sitemap.png b/codemirror_ui/images/silk/sitemap.png
new file mode 100644
index 0000000..ca779f3
--- /dev/null
+++ b/codemirror_ui/images/silk/sitemap.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sitemap_color.png b/codemirror_ui/images/silk/sitemap_color.png
new file mode 100644
index 0000000..c64582b
--- /dev/null
+++ b/codemirror_ui/images/silk/sitemap_color.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sound.png b/codemirror_ui/images/silk/sound.png
new file mode 100644
index 0000000..6056d23
--- /dev/null
+++ b/codemirror_ui/images/silk/sound.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sound_add.png b/codemirror_ui/images/silk/sound_add.png
new file mode 100644
index 0000000..965c503
--- /dev/null
+++ b/codemirror_ui/images/silk/sound_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sound_delete.png b/codemirror_ui/images/silk/sound_delete.png
new file mode 100644
index 0000000..ab9577a
--- /dev/null
+++ b/codemirror_ui/images/silk/sound_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sound_low.png b/codemirror_ui/images/silk/sound_low.png
new file mode 100644
index 0000000..4d91863
--- /dev/null
+++ b/codemirror_ui/images/silk/sound_low.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sound_mute.png b/codemirror_ui/images/silk/sound_mute.png
new file mode 100644
index 0000000..b652d2a
--- /dev/null
+++ b/codemirror_ui/images/silk/sound_mute.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sound_none.png b/codemirror_ui/images/silk/sound_none.png
new file mode 100644
index 0000000..b497ebd
--- /dev/null
+++ b/codemirror_ui/images/silk/sound_none.png
Binary files differ
diff --git a/codemirror_ui/images/silk/spellcheck.png b/codemirror_ui/images/silk/spellcheck.png
new file mode 100644
index 0000000..ebc632d
--- /dev/null
+++ b/codemirror_ui/images/silk/spellcheck.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sport_8ball.png b/codemirror_ui/images/silk/sport_8ball.png
new file mode 100644
index 0000000..4f627b7
--- /dev/null
+++ b/codemirror_ui/images/silk/sport_8ball.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sport_basketball.png b/codemirror_ui/images/silk/sport_basketball.png
new file mode 100644
index 0000000..f7a000b
--- /dev/null
+++ b/codemirror_ui/images/silk/sport_basketball.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sport_football.png b/codemirror_ui/images/silk/sport_football.png
new file mode 100644
index 0000000..199f0f7
--- /dev/null
+++ b/codemirror_ui/images/silk/sport_football.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sport_golf.png b/codemirror_ui/images/silk/sport_golf.png
new file mode 100644
index 0000000..e21fa44
--- /dev/null
+++ b/codemirror_ui/images/silk/sport_golf.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sport_raquet.png b/codemirror_ui/images/silk/sport_raquet.png
new file mode 100644
index 0000000..f5e0f0c
--- /dev/null
+++ b/codemirror_ui/images/silk/sport_raquet.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sport_shuttlecock.png b/codemirror_ui/images/silk/sport_shuttlecock.png
new file mode 100644
index 0000000..917287f
--- /dev/null
+++ b/codemirror_ui/images/silk/sport_shuttlecock.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sport_soccer.png b/codemirror_ui/images/silk/sport_soccer.png
new file mode 100644
index 0000000..3eb1828
--- /dev/null
+++ b/codemirror_ui/images/silk/sport_soccer.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sport_tennis.png b/codemirror_ui/images/silk/sport_tennis.png
new file mode 100644
index 0000000..e88a6ef
--- /dev/null
+++ b/codemirror_ui/images/silk/sport_tennis.png
Binary files differ
diff --git a/codemirror_ui/images/silk/star.png b/codemirror_ui/images/silk/star.png
new file mode 100644
index 0000000..b88c857
--- /dev/null
+++ b/codemirror_ui/images/silk/star.png
Binary files differ
diff --git a/codemirror_ui/images/silk/status_away.png b/codemirror_ui/images/silk/status_away.png
new file mode 100644
index 0000000..70bcbcc
--- /dev/null
+++ b/codemirror_ui/images/silk/status_away.png
Binary files differ
diff --git a/codemirror_ui/images/silk/status_busy.png b/codemirror_ui/images/silk/status_busy.png
new file mode 100644
index 0000000..987c806
--- /dev/null
+++ b/codemirror_ui/images/silk/status_busy.png
Binary files differ
diff --git a/codemirror_ui/images/silk/status_offline.png b/codemirror_ui/images/silk/status_offline.png
new file mode 100644
index 0000000..a88261a
--- /dev/null
+++ b/codemirror_ui/images/silk/status_offline.png
Binary files differ
diff --git a/codemirror_ui/images/silk/status_online.png b/codemirror_ui/images/silk/status_online.png
new file mode 100644
index 0000000..947bd4b
--- /dev/null
+++ b/codemirror_ui/images/silk/status_online.png
Binary files differ
diff --git a/codemirror_ui/images/silk/stop.png b/codemirror_ui/images/silk/stop.png
new file mode 100644
index 0000000..0cfd585
--- /dev/null
+++ b/codemirror_ui/images/silk/stop.png
Binary files differ
diff --git a/codemirror_ui/images/silk/style.png b/codemirror_ui/images/silk/style.png
new file mode 100644
index 0000000..81e41de
--- /dev/null
+++ b/codemirror_ui/images/silk/style.png
Binary files differ
diff --git a/codemirror_ui/images/silk/style_add.png b/codemirror_ui/images/silk/style_add.png
new file mode 100644
index 0000000..e0369c6
--- /dev/null
+++ b/codemirror_ui/images/silk/style_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/style_delete.png b/codemirror_ui/images/silk/style_delete.png
new file mode 100644
index 0000000..640f187
--- /dev/null
+++ b/codemirror_ui/images/silk/style_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/style_edit.png b/codemirror_ui/images/silk/style_edit.png
new file mode 100644
index 0000000..25bb5b6
--- /dev/null
+++ b/codemirror_ui/images/silk/style_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/style_go.png b/codemirror_ui/images/silk/style_go.png
new file mode 100644
index 0000000..25d6181
--- /dev/null
+++ b/codemirror_ui/images/silk/style_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/sum.png b/codemirror_ui/images/silk/sum.png
new file mode 100644
index 0000000..fd7b32e
--- /dev/null
+++ b/codemirror_ui/images/silk/sum.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tab.png b/codemirror_ui/images/silk/tab.png
new file mode 100644
index 0000000..3d8207f
--- /dev/null
+++ b/codemirror_ui/images/silk/tab.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tab_add.png b/codemirror_ui/images/silk/tab_add.png
new file mode 100644
index 0000000..d3b9936
--- /dev/null
+++ b/codemirror_ui/images/silk/tab_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tab_delete.png b/codemirror_ui/images/silk/tab_delete.png
new file mode 100644
index 0000000..100da2f
--- /dev/null
+++ b/codemirror_ui/images/silk/tab_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tab_edit.png b/codemirror_ui/images/silk/tab_edit.png
new file mode 100644
index 0000000..4c09c0f
--- /dev/null
+++ b/codemirror_ui/images/silk/tab_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tab_go.png b/codemirror_ui/images/silk/tab_go.png
new file mode 100644
index 0000000..844ce04
--- /dev/null
+++ b/codemirror_ui/images/silk/tab_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table.png b/codemirror_ui/images/silk/table.png
new file mode 100644
index 0000000..abcd936
--- /dev/null
+++ b/codemirror_ui/images/silk/table.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_add.png b/codemirror_ui/images/silk/table_add.png
new file mode 100644
index 0000000..2a3e5c4
--- /dev/null
+++ b/codemirror_ui/images/silk/table_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_delete.png b/codemirror_ui/images/silk/table_delete.png
new file mode 100644
index 0000000..b85916d
--- /dev/null
+++ b/codemirror_ui/images/silk/table_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_edit.png b/codemirror_ui/images/silk/table_edit.png
new file mode 100644
index 0000000..bfcb024
--- /dev/null
+++ b/codemirror_ui/images/silk/table_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_error.png b/codemirror_ui/images/silk/table_error.png
new file mode 100644
index 0000000..589e92b
--- /dev/null
+++ b/codemirror_ui/images/silk/table_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_gear.png b/codemirror_ui/images/silk/table_gear.png
new file mode 100644
index 0000000..cfc2702
--- /dev/null
+++ b/codemirror_ui/images/silk/table_gear.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_go.png b/codemirror_ui/images/silk/table_go.png
new file mode 100644
index 0000000..0528dfa
--- /dev/null
+++ b/codemirror_ui/images/silk/table_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_key.png b/codemirror_ui/images/silk/table_key.png
new file mode 100644
index 0000000..34e23e2
--- /dev/null
+++ b/codemirror_ui/images/silk/table_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_lightning.png b/codemirror_ui/images/silk/table_lightning.png
new file mode 100644
index 0000000..612612b
--- /dev/null
+++ b/codemirror_ui/images/silk/table_lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_link.png b/codemirror_ui/images/silk/table_link.png
new file mode 100644
index 0000000..decac8a
--- /dev/null
+++ b/codemirror_ui/images/silk/table_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_multiple.png b/codemirror_ui/images/silk/table_multiple.png
new file mode 100644
index 0000000..d76448e
--- /dev/null
+++ b/codemirror_ui/images/silk/table_multiple.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_refresh.png b/codemirror_ui/images/silk/table_refresh.png
new file mode 100644
index 0000000..ab92010
--- /dev/null
+++ b/codemirror_ui/images/silk/table_refresh.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_relationship.png b/codemirror_ui/images/silk/table_relationship.png
new file mode 100644
index 0000000..28b8505
--- /dev/null
+++ b/codemirror_ui/images/silk/table_relationship.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_row_delete.png b/codemirror_ui/images/silk/table_row_delete.png
new file mode 100644
index 0000000..54c6969
--- /dev/null
+++ b/codemirror_ui/images/silk/table_row_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_row_insert.png b/codemirror_ui/images/silk/table_row_insert.png
new file mode 100644
index 0000000..ff5925e
--- /dev/null
+++ b/codemirror_ui/images/silk/table_row_insert.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_save.png b/codemirror_ui/images/silk/table_save.png
new file mode 100644
index 0000000..25b74d1
--- /dev/null
+++ b/codemirror_ui/images/silk/table_save.png
Binary files differ
diff --git a/codemirror_ui/images/silk/table_sort.png b/codemirror_ui/images/silk/table_sort.png
new file mode 100644
index 0000000..ed6785a
--- /dev/null
+++ b/codemirror_ui/images/silk/table_sort.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag.png b/codemirror_ui/images/silk/tag.png
new file mode 100644
index 0000000..e093032
--- /dev/null
+++ b/codemirror_ui/images/silk/tag.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_blue.png b/codemirror_ui/images/silk/tag_blue.png
new file mode 100644
index 0000000..9757fc6
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_blue_add.png b/codemirror_ui/images/silk/tag_blue_add.png
new file mode 100644
index 0000000..f135248
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_blue_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_blue_delete.png b/codemirror_ui/images/silk/tag_blue_delete.png
new file mode 100644
index 0000000..9fbae67
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_blue_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_blue_edit.png b/codemirror_ui/images/silk/tag_blue_edit.png
new file mode 100644
index 0000000..2a9f626
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_blue_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_green.png b/codemirror_ui/images/silk/tag_green.png
new file mode 100644
index 0000000..83ec984
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_green.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_orange.png b/codemirror_ui/images/silk/tag_orange.png
new file mode 100644
index 0000000..454a59f
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_orange.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_pink.png b/codemirror_ui/images/silk/tag_pink.png
new file mode 100644
index 0000000..76e2296
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_pink.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_purple.png b/codemirror_ui/images/silk/tag_purple.png
new file mode 100644
index 0000000..ebaf0e8
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_purple.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_red.png b/codemirror_ui/images/silk/tag_red.png
new file mode 100644
index 0000000..6ebb37d
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_red.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tag_yellow.png b/codemirror_ui/images/silk/tag_yellow.png
new file mode 100644
index 0000000..83d1292
--- /dev/null
+++ b/codemirror_ui/images/silk/tag_yellow.png
Binary files differ
diff --git a/codemirror_ui/images/silk/telephone.png b/codemirror_ui/images/silk/telephone.png
new file mode 100644
index 0000000..cecc436
--- /dev/null
+++ b/codemirror_ui/images/silk/telephone.png
Binary files differ
diff --git a/codemirror_ui/images/silk/telephone_add.png b/codemirror_ui/images/silk/telephone_add.png
new file mode 100644
index 0000000..5591cfc
--- /dev/null
+++ b/codemirror_ui/images/silk/telephone_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/telephone_delete.png b/codemirror_ui/images/silk/telephone_delete.png
new file mode 100644
index 0000000..0013268
--- /dev/null
+++ b/codemirror_ui/images/silk/telephone_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/telephone_edit.png b/codemirror_ui/images/silk/telephone_edit.png
new file mode 100644
index 0000000..bcf6d7e
--- /dev/null
+++ b/codemirror_ui/images/silk/telephone_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/telephone_error.png b/codemirror_ui/images/silk/telephone_error.png
new file mode 100644
index 0000000..d3ec3a1
--- /dev/null
+++ b/codemirror_ui/images/silk/telephone_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/telephone_go.png b/codemirror_ui/images/silk/telephone_go.png
new file mode 100644
index 0000000..395c8fb
--- /dev/null
+++ b/codemirror_ui/images/silk/telephone_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/telephone_key.png b/codemirror_ui/images/silk/telephone_key.png
new file mode 100644
index 0000000..cef5dec
--- /dev/null
+++ b/codemirror_ui/images/silk/telephone_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/telephone_link.png b/codemirror_ui/images/silk/telephone_link.png
new file mode 100644
index 0000000..ef1ee5d
--- /dev/null
+++ b/codemirror_ui/images/silk/telephone_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/television.png b/codemirror_ui/images/silk/television.png
new file mode 100644
index 0000000..1738a4f
--- /dev/null
+++ b/codemirror_ui/images/silk/television.png
Binary files differ
diff --git a/codemirror_ui/images/silk/television_add.png b/codemirror_ui/images/silk/television_add.png
new file mode 100644
index 0000000..2baaad9
--- /dev/null
+++ b/codemirror_ui/images/silk/television_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/television_delete.png b/codemirror_ui/images/silk/television_delete.png
new file mode 100644
index 0000000..b9a5860
--- /dev/null
+++ b/codemirror_ui/images/silk/television_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_align_center.png b/codemirror_ui/images/silk/text_align_center.png
new file mode 100644
index 0000000..57beb38
--- /dev/null
+++ b/codemirror_ui/images/silk/text_align_center.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_align_justify.png b/codemirror_ui/images/silk/text_align_justify.png
new file mode 100644
index 0000000..2fbdd69
--- /dev/null
+++ b/codemirror_ui/images/silk/text_align_justify.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_align_left.png b/codemirror_ui/images/silk/text_align_left.png
new file mode 100644
index 0000000..6c8fcc1
--- /dev/null
+++ b/codemirror_ui/images/silk/text_align_left.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_align_right.png b/codemirror_ui/images/silk/text_align_right.png
new file mode 100644
index 0000000..a150257
--- /dev/null
+++ b/codemirror_ui/images/silk/text_align_right.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_allcaps.png b/codemirror_ui/images/silk/text_allcaps.png
new file mode 100644
index 0000000..280fd44
--- /dev/null
+++ b/codemirror_ui/images/silk/text_allcaps.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_bold.png b/codemirror_ui/images/silk/text_bold.png
new file mode 100644
index 0000000..889ae80
--- /dev/null
+++ b/codemirror_ui/images/silk/text_bold.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_columns.png b/codemirror_ui/images/silk/text_columns.png
new file mode 100644
index 0000000..97b2e03
--- /dev/null
+++ b/codemirror_ui/images/silk/text_columns.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_dropcaps.png b/codemirror_ui/images/silk/text_dropcaps.png
new file mode 100644
index 0000000..dd65786
--- /dev/null
+++ b/codemirror_ui/images/silk/text_dropcaps.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_heading_1.png b/codemirror_ui/images/silk/text_heading_1.png
new file mode 100644
index 0000000..9c122e9
--- /dev/null
+++ b/codemirror_ui/images/silk/text_heading_1.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_heading_2.png b/codemirror_ui/images/silk/text_heading_2.png
new file mode 100644
index 0000000..fbd8765
--- /dev/null
+++ b/codemirror_ui/images/silk/text_heading_2.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_heading_3.png b/codemirror_ui/images/silk/text_heading_3.png
new file mode 100644
index 0000000..c7836cf
--- /dev/null
+++ b/codemirror_ui/images/silk/text_heading_3.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_heading_4.png b/codemirror_ui/images/silk/text_heading_4.png
new file mode 100644
index 0000000..4e929ea
--- /dev/null
+++ b/codemirror_ui/images/silk/text_heading_4.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_heading_5.png b/codemirror_ui/images/silk/text_heading_5.png
new file mode 100644
index 0000000..30cabeb
--- /dev/null
+++ b/codemirror_ui/images/silk/text_heading_5.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_heading_6.png b/codemirror_ui/images/silk/text_heading_6.png
new file mode 100644
index 0000000..058170a
--- /dev/null
+++ b/codemirror_ui/images/silk/text_heading_6.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_horizontalrule.png b/codemirror_ui/images/silk/text_horizontalrule.png
new file mode 100644
index 0000000..8dd1da1
--- /dev/null
+++ b/codemirror_ui/images/silk/text_horizontalrule.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_indent.png b/codemirror_ui/images/silk/text_indent.png
new file mode 100644
index 0000000..9364532
--- /dev/null
+++ b/codemirror_ui/images/silk/text_indent.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_indent_remove.png b/codemirror_ui/images/silk/text_indent_remove.png
new file mode 100644
index 0000000..1651b07
--- /dev/null
+++ b/codemirror_ui/images/silk/text_indent_remove.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_italic.png b/codemirror_ui/images/silk/text_italic.png
new file mode 100644
index 0000000..8482ac8
--- /dev/null
+++ b/codemirror_ui/images/silk/text_italic.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_kerning.png b/codemirror_ui/images/silk/text_kerning.png
new file mode 100644
index 0000000..377def6
--- /dev/null
+++ b/codemirror_ui/images/silk/text_kerning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_letter_omega.png b/codemirror_ui/images/silk/text_letter_omega.png
new file mode 100644
index 0000000..5075ec6
--- /dev/null
+++ b/codemirror_ui/images/silk/text_letter_omega.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_letterspacing.png b/codemirror_ui/images/silk/text_letterspacing.png
new file mode 100644
index 0000000..41390f5
--- /dev/null
+++ b/codemirror_ui/images/silk/text_letterspacing.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_linespacing.png b/codemirror_ui/images/silk/text_linespacing.png
new file mode 100644
index 0000000..1a91cbd
--- /dev/null
+++ b/codemirror_ui/images/silk/text_linespacing.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_list_bullets.png b/codemirror_ui/images/silk/text_list_bullets.png
new file mode 100644
index 0000000..4a8672b
--- /dev/null
+++ b/codemirror_ui/images/silk/text_list_bullets.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_list_numbers.png b/codemirror_ui/images/silk/text_list_numbers.png
new file mode 100644
index 0000000..33b0b8d
--- /dev/null
+++ b/codemirror_ui/images/silk/text_list_numbers.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_lowercase.png b/codemirror_ui/images/silk/text_lowercase.png
new file mode 100644
index 0000000..382a102
--- /dev/null
+++ b/codemirror_ui/images/silk/text_lowercase.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_padding_bottom.png b/codemirror_ui/images/silk/text_padding_bottom.png
new file mode 100644
index 0000000..4880c43
--- /dev/null
+++ b/codemirror_ui/images/silk/text_padding_bottom.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_padding_left.png b/codemirror_ui/images/silk/text_padding_left.png
new file mode 100644
index 0000000..b55482e
--- /dev/null
+++ b/codemirror_ui/images/silk/text_padding_left.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_padding_right.png b/codemirror_ui/images/silk/text_padding_right.png
new file mode 100644
index 0000000..106edae
--- /dev/null
+++ b/codemirror_ui/images/silk/text_padding_right.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_padding_top.png b/codemirror_ui/images/silk/text_padding_top.png
new file mode 100644
index 0000000..c5c45b2
--- /dev/null
+++ b/codemirror_ui/images/silk/text_padding_top.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_replace.png b/codemirror_ui/images/silk/text_replace.png
new file mode 100644
index 0000000..877f82f
--- /dev/null
+++ b/codemirror_ui/images/silk/text_replace.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_signature.png b/codemirror_ui/images/silk/text_signature.png
new file mode 100644
index 0000000..c72fd80
--- /dev/null
+++ b/codemirror_ui/images/silk/text_signature.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_smallcaps.png b/codemirror_ui/images/silk/text_smallcaps.png
new file mode 100644
index 0000000..5b98a6e
--- /dev/null
+++ b/codemirror_ui/images/silk/text_smallcaps.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_strikethrough.png b/codemirror_ui/images/silk/text_strikethrough.png
new file mode 100644
index 0000000..612058a
--- /dev/null
+++ b/codemirror_ui/images/silk/text_strikethrough.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_subscript.png b/codemirror_ui/images/silk/text_subscript.png
new file mode 100644
index 0000000..1a2b010
--- /dev/null
+++ b/codemirror_ui/images/silk/text_subscript.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_superscript.png b/codemirror_ui/images/silk/text_superscript.png
new file mode 100644
index 0000000..2fb2a7c
--- /dev/null
+++ b/codemirror_ui/images/silk/text_superscript.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_underline.png b/codemirror_ui/images/silk/text_underline.png
new file mode 100644
index 0000000..90d0df2
--- /dev/null
+++ b/codemirror_ui/images/silk/text_underline.png
Binary files differ
diff --git a/codemirror_ui/images/silk/text_uppercase.png b/codemirror_ui/images/silk/text_uppercase.png
new file mode 100644
index 0000000..8dcc2db
--- /dev/null
+++ b/codemirror_ui/images/silk/text_uppercase.png
Binary files differ
diff --git a/codemirror_ui/images/silk/textfield.png b/codemirror_ui/images/silk/textfield.png
new file mode 100644
index 0000000..d37e730
--- /dev/null
+++ b/codemirror_ui/images/silk/textfield.png
Binary files differ
diff --git a/codemirror_ui/images/silk/textfield_add.png b/codemirror_ui/images/silk/textfield_add.png
new file mode 100644
index 0000000..204de72
--- /dev/null
+++ b/codemirror_ui/images/silk/textfield_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/textfield_delete.png b/codemirror_ui/images/silk/textfield_delete.png
new file mode 100644
index 0000000..c7bd58b
--- /dev/null
+++ b/codemirror_ui/images/silk/textfield_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/textfield_key.png b/codemirror_ui/images/silk/textfield_key.png
new file mode 100644
index 0000000..a9d5e4f
--- /dev/null
+++ b/codemirror_ui/images/silk/textfield_key.png
Binary files differ
diff --git a/codemirror_ui/images/silk/textfield_rename.png b/codemirror_ui/images/silk/textfield_rename.png
new file mode 100644
index 0000000..4e3688e
--- /dev/null
+++ b/codemirror_ui/images/silk/textfield_rename.png
Binary files differ
diff --git a/codemirror_ui/images/silk/thumb_down.png b/codemirror_ui/images/silk/thumb_down.png
new file mode 100644
index 0000000..3c832d4
--- /dev/null
+++ b/codemirror_ui/images/silk/thumb_down.png
Binary files differ
diff --git a/codemirror_ui/images/silk/thumb_up.png b/codemirror_ui/images/silk/thumb_up.png
new file mode 100644
index 0000000..2bd16cc
--- /dev/null
+++ b/codemirror_ui/images/silk/thumb_up.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tick.png b/codemirror_ui/images/silk/tick.png
new file mode 100644
index 0000000..a9925a0
--- /dev/null
+++ b/codemirror_ui/images/silk/tick.png
Binary files differ
diff --git a/codemirror_ui/images/silk/time.png b/codemirror_ui/images/silk/time.png
new file mode 100644
index 0000000..911da3f
--- /dev/null
+++ b/codemirror_ui/images/silk/time.png
Binary files differ
diff --git a/codemirror_ui/images/silk/time_add.png b/codemirror_ui/images/silk/time_add.png
new file mode 100644
index 0000000..dcc45cb
--- /dev/null
+++ b/codemirror_ui/images/silk/time_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/time_delete.png b/codemirror_ui/images/silk/time_delete.png
new file mode 100644
index 0000000..5bf8313
--- /dev/null
+++ b/codemirror_ui/images/silk/time_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/time_go.png b/codemirror_ui/images/silk/time_go.png
new file mode 100644
index 0000000..d451ee0
--- /dev/null
+++ b/codemirror_ui/images/silk/time_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/timeline_marker.png b/codemirror_ui/images/silk/timeline_marker.png
new file mode 100644
index 0000000..a3fbddf
--- /dev/null
+++ b/codemirror_ui/images/silk/timeline_marker.png
Binary files differ
diff --git a/codemirror_ui/images/silk/transmit.png b/codemirror_ui/images/silk/transmit.png
new file mode 100644
index 0000000..f54bf73
--- /dev/null
+++ b/codemirror_ui/images/silk/transmit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/transmit_add.png b/codemirror_ui/images/silk/transmit_add.png
new file mode 100644
index 0000000..b7fd4e6
--- /dev/null
+++ b/codemirror_ui/images/silk/transmit_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/transmit_blue.png b/codemirror_ui/images/silk/transmit_blue.png
new file mode 100644
index 0000000..7b1142f
--- /dev/null
+++ b/codemirror_ui/images/silk/transmit_blue.png
Binary files differ
diff --git a/codemirror_ui/images/silk/transmit_delete.png b/codemirror_ui/images/silk/transmit_delete.png
new file mode 100644
index 0000000..3d72be2
--- /dev/null
+++ b/codemirror_ui/images/silk/transmit_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/transmit_edit.png b/codemirror_ui/images/silk/transmit_edit.png
new file mode 100644
index 0000000..eb9a3dd
--- /dev/null
+++ b/codemirror_ui/images/silk/transmit_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/transmit_error.png b/codemirror_ui/images/silk/transmit_error.png
new file mode 100644
index 0000000..fd1d449
--- /dev/null
+++ b/codemirror_ui/images/silk/transmit_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/transmit_go.png b/codemirror_ui/images/silk/transmit_go.png
new file mode 100644
index 0000000..10137e5
--- /dev/null
+++ b/codemirror_ui/images/silk/transmit_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/tux.png b/codemirror_ui/images/silk/tux.png
new file mode 100644
index 0000000..bbefe2e
--- /dev/null
+++ b/codemirror_ui/images/silk/tux.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user.png b/codemirror_ui/images/silk/user.png
new file mode 100644
index 0000000..79f35cc
--- /dev/null
+++ b/codemirror_ui/images/silk/user.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_add.png b/codemirror_ui/images/silk/user_add.png
new file mode 100644
index 0000000..deae99b
--- /dev/null
+++ b/codemirror_ui/images/silk/user_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_comment.png b/codemirror_ui/images/silk/user_comment.png
new file mode 100644
index 0000000..e54ebeb
--- /dev/null
+++ b/codemirror_ui/images/silk/user_comment.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_delete.png b/codemirror_ui/images/silk/user_delete.png
new file mode 100644
index 0000000..acbb563
--- /dev/null
+++ b/codemirror_ui/images/silk/user_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_edit.png b/codemirror_ui/images/silk/user_edit.png
new file mode 100644
index 0000000..c1974cd
--- /dev/null
+++ b/codemirror_ui/images/silk/user_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_female.png b/codemirror_ui/images/silk/user_female.png
new file mode 100644
index 0000000..7c71de0
--- /dev/null
+++ b/codemirror_ui/images/silk/user_female.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_go.png b/codemirror_ui/images/silk/user_go.png
new file mode 100644
index 0000000..0468cf0
--- /dev/null
+++ b/codemirror_ui/images/silk/user_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_gray.png b/codemirror_ui/images/silk/user_gray.png
new file mode 100644
index 0000000..8fd539e
--- /dev/null
+++ b/codemirror_ui/images/silk/user_gray.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_green.png b/codemirror_ui/images/silk/user_green.png
new file mode 100644
index 0000000..30383c2
--- /dev/null
+++ b/codemirror_ui/images/silk/user_green.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_orange.png b/codemirror_ui/images/silk/user_orange.png
new file mode 100644
index 0000000..b818127
--- /dev/null
+++ b/codemirror_ui/images/silk/user_orange.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_red.png b/codemirror_ui/images/silk/user_red.png
new file mode 100644
index 0000000..c6f66e8
--- /dev/null
+++ b/codemirror_ui/images/silk/user_red.png
Binary files differ
diff --git a/codemirror_ui/images/silk/user_suit.png b/codemirror_ui/images/silk/user_suit.png
new file mode 100644
index 0000000..b3454e1
--- /dev/null
+++ b/codemirror_ui/images/silk/user_suit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/vcard.png b/codemirror_ui/images/silk/vcard.png
new file mode 100644
index 0000000..c02f315
--- /dev/null
+++ b/codemirror_ui/images/silk/vcard.png
Binary files differ
diff --git a/codemirror_ui/images/silk/vcard_add.png b/codemirror_ui/images/silk/vcard_add.png
new file mode 100644
index 0000000..2a68453
--- /dev/null
+++ b/codemirror_ui/images/silk/vcard_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/vcard_delete.png b/codemirror_ui/images/silk/vcard_delete.png
new file mode 100644
index 0000000..b194b97
--- /dev/null
+++ b/codemirror_ui/images/silk/vcard_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/vcard_edit.png b/codemirror_ui/images/silk/vcard_edit.png
new file mode 100644
index 0000000..ab0f6e7
--- /dev/null
+++ b/codemirror_ui/images/silk/vcard_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/vector.png b/codemirror_ui/images/silk/vector.png
new file mode 100644
index 0000000..a1291c2
--- /dev/null
+++ b/codemirror_ui/images/silk/vector.png
Binary files differ
diff --git a/codemirror_ui/images/silk/vector_add.png b/codemirror_ui/images/silk/vector_add.png
new file mode 100644
index 0000000..988770f
--- /dev/null
+++ b/codemirror_ui/images/silk/vector_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/vector_delete.png b/codemirror_ui/images/silk/vector_delete.png
new file mode 100644
index 0000000..ca139e0
--- /dev/null
+++ b/codemirror_ui/images/silk/vector_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/wand.png b/codemirror_ui/images/silk/wand.png
new file mode 100644
index 0000000..44ccbf8
--- /dev/null
+++ b/codemirror_ui/images/silk/wand.png
Binary files differ
diff --git a/codemirror_ui/images/silk/weather_clouds.png b/codemirror_ui/images/silk/weather_clouds.png
new file mode 100644
index 0000000..3f73eaa
--- /dev/null
+++ b/codemirror_ui/images/silk/weather_clouds.png
Binary files differ
diff --git a/codemirror_ui/images/silk/weather_cloudy.png b/codemirror_ui/images/silk/weather_cloudy.png
new file mode 100644
index 0000000..5856e1d
--- /dev/null
+++ b/codemirror_ui/images/silk/weather_cloudy.png
Binary files differ
diff --git a/codemirror_ui/images/silk/weather_lightning.png b/codemirror_ui/images/silk/weather_lightning.png
new file mode 100644
index 0000000..1d42b36
--- /dev/null
+++ b/codemirror_ui/images/silk/weather_lightning.png
Binary files differ
diff --git a/codemirror_ui/images/silk/weather_rain.png b/codemirror_ui/images/silk/weather_rain.png
new file mode 100644
index 0000000..cb3d54d
--- /dev/null
+++ b/codemirror_ui/images/silk/weather_rain.png
Binary files differ
diff --git a/codemirror_ui/images/silk/weather_snow.png b/codemirror_ui/images/silk/weather_snow.png
new file mode 100644
index 0000000..45bbdf1
--- /dev/null
+++ b/codemirror_ui/images/silk/weather_snow.png
Binary files differ
diff --git a/codemirror_ui/images/silk/weather_sun.png b/codemirror_ui/images/silk/weather_sun.png
new file mode 100644
index 0000000..0156c26
--- /dev/null
+++ b/codemirror_ui/images/silk/weather_sun.png
Binary files differ
diff --git a/codemirror_ui/images/silk/webcam.png b/codemirror_ui/images/silk/webcam.png
new file mode 100644
index 0000000..af71c30
--- /dev/null
+++ b/codemirror_ui/images/silk/webcam.png
Binary files differ
diff --git a/codemirror_ui/images/silk/webcam_add.png b/codemirror_ui/images/silk/webcam_add.png
new file mode 100644
index 0000000..f02fcfa
--- /dev/null
+++ b/codemirror_ui/images/silk/webcam_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/webcam_delete.png b/codemirror_ui/images/silk/webcam_delete.png
new file mode 100644
index 0000000..bd6277f
--- /dev/null
+++ b/codemirror_ui/images/silk/webcam_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/webcam_error.png b/codemirror_ui/images/silk/webcam_error.png
new file mode 100644
index 0000000..2faa706
--- /dev/null
+++ b/codemirror_ui/images/silk/webcam_error.png
Binary files differ
diff --git a/codemirror_ui/images/silk/world.png b/codemirror_ui/images/silk/world.png
new file mode 100644
index 0000000..68f21d3
--- /dev/null
+++ b/codemirror_ui/images/silk/world.png
Binary files differ
diff --git a/codemirror_ui/images/silk/world_add.png b/codemirror_ui/images/silk/world_add.png
new file mode 100644
index 0000000..6d0d7f7
--- /dev/null
+++ b/codemirror_ui/images/silk/world_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/world_delete.png b/codemirror_ui/images/silk/world_delete.png
new file mode 100644
index 0000000..ffcd115
--- /dev/null
+++ b/codemirror_ui/images/silk/world_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/world_edit.png b/codemirror_ui/images/silk/world_edit.png
new file mode 100644
index 0000000..00794d4
--- /dev/null
+++ b/codemirror_ui/images/silk/world_edit.png
Binary files differ
diff --git a/codemirror_ui/images/silk/world_go.png b/codemirror_ui/images/silk/world_go.png
new file mode 100644
index 0000000..aee9c97
--- /dev/null
+++ b/codemirror_ui/images/silk/world_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/world_link.png b/codemirror_ui/images/silk/world_link.png
new file mode 100644
index 0000000..b8edc12
--- /dev/null
+++ b/codemirror_ui/images/silk/world_link.png
Binary files differ
diff --git a/codemirror_ui/images/silk/wrench.png b/codemirror_ui/images/silk/wrench.png
new file mode 100644
index 0000000..5c8213f
--- /dev/null
+++ b/codemirror_ui/images/silk/wrench.png
Binary files differ
diff --git a/codemirror_ui/images/silk/wrench_orange.png b/codemirror_ui/images/silk/wrench_orange.png
new file mode 100644
index 0000000..565a933
--- /dev/null
+++ b/codemirror_ui/images/silk/wrench_orange.png
Binary files differ
diff --git a/codemirror_ui/images/silk/xhtml.png b/codemirror_ui/images/silk/xhtml.png
new file mode 100644
index 0000000..da5dbf2
--- /dev/null
+++ b/codemirror_ui/images/silk/xhtml.png
Binary files differ
diff --git a/codemirror_ui/images/silk/xhtml_add.png b/codemirror_ui/images/silk/xhtml_add.png
new file mode 100644
index 0000000..bbaf784
--- /dev/null
+++ b/codemirror_ui/images/silk/xhtml_add.png
Binary files differ
diff --git a/codemirror_ui/images/silk/xhtml_delete.png b/codemirror_ui/images/silk/xhtml_delete.png
new file mode 100644
index 0000000..157b520
--- /dev/null
+++ b/codemirror_ui/images/silk/xhtml_delete.png
Binary files differ
diff --git a/codemirror_ui/images/silk/xhtml_go.png b/codemirror_ui/images/silk/xhtml_go.png
new file mode 100644
index 0000000..43cf814
--- /dev/null
+++ b/codemirror_ui/images/silk/xhtml_go.png
Binary files differ
diff --git a/codemirror_ui/images/silk/xhtml_valid.png b/codemirror_ui/images/silk/xhtml_valid.png
new file mode 100644
index 0000000..d2e1cfb
--- /dev/null
+++ b/codemirror_ui/images/silk/xhtml_valid.png
Binary files differ
diff --git a/codemirror_ui/images/silk/zoom.png b/codemirror_ui/images/silk/zoom.png
new file mode 100644
index 0000000..908612e
--- /dev/null
+++ b/codemirror_ui/images/silk/zoom.png
Binary files differ
diff --git a/codemirror_ui/images/silk/zoom_in.png b/codemirror_ui/images/silk/zoom_in.png
new file mode 100644
index 0000000..cdf0a52
--- /dev/null
+++ b/codemirror_ui/images/silk/zoom_in.png
Binary files differ
diff --git a/codemirror_ui/images/silk/zoom_out.png b/codemirror_ui/images/silk/zoom_out.png
new file mode 100644
index 0000000..07bf98a
--- /dev/null
+++ b/codemirror_ui/images/silk/zoom_out.png
Binary files differ
diff --git a/codemirror_ui/index.html b/codemirror_ui/index.html
new file mode 100644
index 0000000..d09647b
--- /dev/null
+++ b/codemirror_ui/index.html
@@ -0,0 +1,340 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+<head>
+
+ <title>CodeMirror UI | Test Page</title>
+ <script src="http://svn.myroundcube.com/program/js/jquery.min.js" type="text/javascript"></script>
+ <script src="lib/CodeMirror-2.3/lib/codemirror.js" type="text/javascript"></script>
+ <script src="lib/CodeMirror-2.3/lib/util/searchcursor.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="lib/CodeMirror-2.3/lib/codemirror.css">
+ <script src="lib/CodeMirror-2.3/mode/javascript/javascript.js"></script>
+ <link rel="stylesheet" href="lib/CodeMirror-2.3/mode/javascript/javascript.css">
+
+
+ <script src="js/codemirror-ui.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="css/codemirror-ui.css" type="text/css" media="screen" />
+
+ <style type="text/css">
+ body{
+ background:#0d4664;
+ text-align:center;
+ }
+
+ #pageBody{
+ width:930px;
+ padding:10px;
+ background:white;
+ text-align:left;
+ margin:10px auto;
+ padding-top:0px;
+ border:1px solid black;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+ -moz-box-shadow: 3px 3px 14px #000;
+ -webkit-box-shadow: 3px 3px 14px #000;
+ box-shadow: 3px 3px 14px #000;
+ }
+
+ pre{
+ border:1px solid #ccc;
+ background:#eee;
+ padding:10px;
+ }
+
+ #footer{
+ font-size:0.9em;
+ color:white;
+ }
+ #footer a{
+ color:white;
+ }
+ </style>
+
+
+</head>
+<body>
+
+<div id="pageBody">
+ <h1>CodeMirror UI</h1>
+
+ <p>
+ CodeMirrorUI is a simple interface written by Jeremy Green to act as a
+ wrapper around the <a href="http://codemirror.net/">CodeMirror</a> text editor widget by Marijn Haverbeke.
+ CodeMirror is a syntax highlighter and formatter that makes it much easier to edit source code in a browser.
+ ComeMirrorUI is a wrapper that adds interface functionality for many functions that are already built into CodeMirror itself.
+ Functionality includes undo, redo, jump to line, reindent selection, and reindent entire document.
+ Two options for find/replace are also available. It is based on the MirrorFrame example that Marijn included with CodeMirror.
+ </p>
+ <p>
+ This editor is enabled with the pop up find/replace widget.
+ </p>
+ <!--
+ <textarea id="code0" cols="120" rows="20">
+ // Line Numbers Here you see some JavaScript code. Mess around with it to get
+ // acquainted with CodeMirror's features.
+
+ // Press enter inside the object and your new line will be suitably
+ // indented.
+ var keyBindings = {
+ enter: "newline-and-indent",
+ tab: "reindent-selection",
+ ctrl_z: "undo",
+ ctrl_y: "redo",
+ ctrl_backspace: "undo-for-safari (which blocks ctrl-z)",
+ ctrl_bracket: "highlight-brackets",
+ ctrl_shift_bracket: "jump-to-matching-bracket"
+ };
+
+ // Press tab on the next line and the wrong indentation will be fixed.
+ var regex = /foo|bar/i;
+
+ function example(x) {
+ // Local variables get a different colour than global ones.
+ var y = 44.4;
+ return x + y - z;
+ }
+ </textarea>
+ -->
+
+ <textarea id="code1" cols="120" rows="20">
+ // Here you see some JavaScript code. Mess around with it to get
+ // acquainted with CodeMirror's features.
+
+ // Press enter inside the object and your new line will be suitably
+ // indented.
+ var keyBindings = {
+ enter: "newline-and-indent",
+ tab: "reindent-selection",
+ ctrl_z: "undo",
+ ctrl_y: "redo",
+ ctrl_backspace: "undo-for-safari (which blocks ctrl-z)",
+ ctrl_bracket: "highlight-brackets",
+ ctrl_shift_bracket: "jump-to-matching-bracket"
+ };
+
+ // Press tab on the next line and the wrong indentation will be fixed.
+ var regex = /foo|bar/i;
+
+ function example(x) {
+ // Local variables get a different colour than global ones.
+ var y = 44.4;
+ return x + y - z;
+ }
+ </textarea>
+
+ <h2>Easily Configurable</h2>
+
+ <p>
+ The editor above was created with code like this:
+ </p>
+
+ <pre>
+//first set up some variables
+var textarea = document.getElementById('code1');
+var uiOptions = { path : 'js/', searchMode : 'popup' }
+var codeMirrorOptions = { mode: "javascript" }
+
+//then create the editor
+var editor = new CodeMirrorUI(textarea,uiOptions,codeMirrorOptions); </pre>
+
+ <p>
+ Creating a new CodeMirrorUI is easy, you just call:
+ </p>
+ <pre>new CodeMirrorUI(textarea,uiOptions,codeMirrorOptions);</pre>
+
+ <h3>Params for new CodeMirrorUI()</h3>
+ <ul>
+ <li>
+ textarea - Either a DOM element of the ID of a DOM element that should be replaced with the editor UI.
+ </li>
+ <li>
+ uiOptions - Options for the CodeMirrorUI object.
+ <ul>
+ <li>
+ path - String - The path to the codemirror-ui js directory (relative to the current document).
+ </li>
+ <li>
+ searchMode - String - Options are 'inline' or 'popup'
+ </li>
+ <li>
+ buttons - Array - An array of button names that should be included in the button bar.
+ </li>
+ </ul>
+ </li>
+ <li>
+ codeMirrorOptions - Standard optiosn that you would pass to any CodeMirror constructor. See the <a href="http://codemirror.net/manual.html">CodeMirror manual</a> for more details;
+ </li>
+ </ul>
+ <h2>Installing</h2>
+
+ <p>
+ To install CodeMirrorUI you can just copy the codemirror-ui directory into your web app.
+ It includes a version of CodeMirror, or you can use your own version if you'd prefer.
+ </p>
+ <p>
+ Then include a link to the stylesheet and javascript files in your document. Something like this:
+ </p>
+
+<pre class="code">
+// First the CodeMirror stuff
+&lt;script src="lib/CodeMirror-2.3/lib/codemirror.js" type="text/javascript"&gt;&lt;/script&gt;
+&lt;script src="lib/CodeMirror-2.3/lib/util/searchcursor.js" type="text/javascript"&gt;&lt;/script&gt;
+&lt;link rel="stylesheet" href="lib/CodeMirror-2.3/lib/codemirror.css"&gt;
+&lt;script src="lib/CodeMirror-2.3/mode/javascript/javascript.js"&gt;&lt;/script&gt;
+&lt;link rel="stylesheet" href="lib/CodeMirror-2.3/mode/javascript/javascript.css"&gt;
+
+//Then the CodeMirrorUI stuff
+&lt;script src="js/codemirror-ui.js" type="text/javascript"&gt;&lt;/script&gt;
+&lt;link rel="stylesheet" href="css/codemirror-ui.css" type="text/css" media="screen" /&gt;
+</pre>
+
+ <p>
+ <b>Note:</b> The find/replace functionality relies on the searchcursor add on.
+ </p>
+
+ <p>
+ From there you can create an editor as shown above. It is especially easy to replace any calls to
+ "CodeMirror.fromTextArea(...)" with a "new CodeMirrorUI(...)".
+ </p>
+
+ <h2>Another example</h2>
+
+ <p>
+ This editor is enabled with a save button and the 'inline' search widget.
+ You can pass a function as the 'saveCallback' option which will be called when the save button is clicked.
+ </p>
+ <p>
+ The button for the popup search widget has been removed,
+ along with the button for 'reindent selection'.
+ </p>
+ <textarea id="code2" cols="120" rows="30">
+ // Here you see some JavaScript code. Mess around with it to get
+ // acquainted with CodeMirror's features.
+
+ // Press enter inside the object and your new line will be suitably
+ // indented.
+ var keyBindings = {
+ enter: "newline-and-indent",
+ tab: "reindent-selection",
+ ctrl_z: "undo",
+ ctrl_y: "redo",
+ ctrl_backspace: "undo-for-safari (which blocks ctrl-z)",
+ ctrl_bracket: "highlight-brackets",
+ ctrl_shift_bracket: "jump-to-matching-bracket"
+ };
+
+ // Press tab on the next line and the wrong indentation will be fixed.
+ var regex = /foo|bar/i;
+
+ function example(x) {
+ // Local variables get a different colour than global ones.
+ var y = 44.4;
+ return x + y - z;
+ }
+ </textarea>
+
+ <p>
+ The uiOptions param for the editor above looks like this:
+ </p>
+
+
+<pre class="code">
+var uiOptions = {
+ path : 'js/',
+ searchMode = 'inline',
+ buttons : ['save','undo','redo','jump','reindent','about'],
+ saveCallback : function(){ alert("Some saving goes here. Probably AJAX or something fancy."); }
+}
+</pre>
+
+ <p>
+ View the source of this page to see the actual code used to get these editors in action.
+ </p>
+
+
+ <h2>Find the code @ Github</h2>
+ <a href="https://github.com/jagthedrummer/codemirror-ui">https://github.com/jagthedrummer/codemirror-ui</a>
+
+ <h2>Acknowledgements</h2>
+ <h3><a href="http://codemirror.net/">Marijn Haverbeke - CodeMirror</a></h3>
+ <p>
+ Thanks to Marijn Haverbeke for creating and releasing CodeMirror in the first place.
+ Whithout his excellent contribution to the community this project would have no reason to exist.
+ </p>
+
+ <h3><a href="http://www.famfamfam.com/lab/icons/silk/">Mark James - Silk Icons</a></h3>
+ <p>
+ I used the Silk icon set from Mark James of <a href="http://www.famfamfam.com/">famfamfam.com</a> fame.
+ </p>
+
+ <h2>Versions</h2>
+ <p>
+ All version up to and including 0.0.7 are based on CodeMirror 1.
+ </p>
+ <p>
+ Versions 0.0.8 and newer are based on CodeMirror 2.
+ </p>
+
+ <h2>License</h2>
+
+ <p>
+ CodeMirror UI is provided under the MIT License. See the LICENSE file for full details.
+ </p>
+
+ <h2>Known Usage</h2>
+ <p>
+ The following sites/apps are using CodeMirrorUI.
+ Please let me know if you'd like to be added to this list.
+ </p>
+ <ul>
+ <li><a href="http://www.webapeel.com/">aPeel</a></li>
+ </ul>
+</div>
+
+
+ <div id="footer">
+ CodeMirrorUI is a production of <a href="http://www.octolabs.com/">OctoLabs</a>
+ <br/>
+ <a href="http://www.octolabs.com/"><img src="images/octologo.png" border="0"></a>
+ </div>
+
+
+<script type="text/javascript">
+
+ /*
+ var textarea = document.getElementById('code0');
+ var myCodeMirror = CodeMirror.fromTextArea(textarea, {mode: "javascript", lineNumbers: true,} );
+ */
+
+ var textarea = document.getElementById('code1');
+ var editor = new CodeMirrorUI(textarea,
+ {
+ path : 'js/',
+ searchMode : 'popup'
+ },
+ {
+ mode: "javascript"
+ });
+
+
+ var textarea2 = document.getElementById('code2');
+ //CodeMirror.replace(textarea);
+
+ var editor2 = new CodeMirrorUI(textarea2,
+ {
+ path : 'js/',
+ searchMode : 'inline',
+ buttons : ['save','undo','redo','jump','reindent','about'],
+ saveCallback : function(){ alert("Some saving goes here. Probably AJAX or something fancy."); }
+ },
+ {
+ mode: "php"
+ });
+
+</script>
+
+
+</body>
+</html>
diff --git a/codemirror_ui/js/codemirror-ui-find.js b/codemirror_ui/js/codemirror-ui-find.js
new file mode 100644
index 0000000..c1cc8c5
--- /dev/null
+++ b/codemirror_ui/js/codemirror-ui-find.js
@@ -0,0 +1,89 @@
+/**
+ * @author jgreen
+ */
+var cursor = null;
+
+function setupFindReplace(){
+ document.getElementById('closeButton').onclick = closeWindow;
+ document.getElementById('findButton').onclick = find;
+ document.getElementById('replaceButton').onclick = replace;
+ document.getElementById('replaceAllButton').onclick = replaceAll;
+ document.getElementById('replaceFindButton').onclick = replaceFind;
+}
+
+function closeWindow(){
+ codeMirrorUI.searchWindow = null;
+ window.close();
+}
+
+function find(){
+ var findString = document.getElementById('find').value;
+ if (findString == null || findString == '') {
+ alert('You must enter something to search for.');
+ return;
+ }
+
+ if(document.getElementById('regex').checked){
+ findString = new RegExp(findString);
+ }
+
+ cursor = codeMirrorUI.mirror.getSearchCursor(findString, true);
+ var found = moveCursor(cursor);
+
+ //if we didn't find anything, let's check to see if we should start from the top
+ if(!found && document.getElementById('wrap').checked){
+ cursor = codeMirrorUI.mirror.getSearchCursor(findString, false);
+ found = moveCursor(cursor);
+ }
+
+ if(found){
+ cursor.select();
+ }else{
+ alert("No instances found. (Maybe you need to enable 'Wrap Search'?)");
+ }
+
+}
+
+function moveCursor(cursor){
+ var found = false;
+ if( getFindDirection() == "forward" ){
+ found = cursor.findNext();
+ }else{
+ found = cursor.findPrevious();
+ }
+ return found;
+}
+
+
+function getFindDirection(){
+ var dRadio = document.forms[0].elements['direction'];
+
+ for (var i = 0; i < dRadio.length; i++) {
+ if (dRadio[i].checked) {
+ return dRadio[i].value;
+ }
+ }
+
+ return 'no-value?';
+
+}
+
+
+function replaceAll(){
+ var cursor = codeMirrorUI.mirror.getSearchCursor(document.getElementById('find').value, false);
+ while (cursor.findNext())
+ cursor.replace(document.getElementById('replace').value);
+}
+
+
+function replace(){
+ cursor.replace(document.getElementById('replace').value);
+ //codeMirrorUI.replaceSelection(document.getElementById('replace').value);
+ setTimeout(window.focus, 100);
+ //alert('replaced!');
+}
+
+function replaceFind(){
+ replace();
+ find();
+}
diff --git a/codemirror_ui/js/codemirror-ui.js b/codemirror_ui/js/codemirror-ui.js
new file mode 100644
index 0000000..d246132
--- /dev/null
+++ b/codemirror_ui/js/codemirror-ui.js
@@ -0,0 +1,505 @@
+/* Demonstration of embedding CodeMirror in a bigger application. The
+* interface defined here is a mess of prompts and confirms, and
+* should probably not be used in a real project.
+*/
+//var CodeMirrorUI = Class.create();
+
+function CodeMirrorUI(place, options, mirrorOptions) {
+ this.initialize(place, options, mirrorOptions);
+}
+
+CodeMirrorUI.prototype = {
+
+ initialize: function(textarea, options, mirrorOptions) {
+ var defaultOptions = {
+ searchMode: 'popup', // other options are 'inline' and 'dialog'. The 'dialog' option needs work.
+ imagePath: 'images/silk',
+ path: 'js',
+ buttons: ['search', 'undo', 'redo', 'jump', 'reindentSelection', 'reindent','about'],
+ saveCallback: function() {},
+ }
+ this.textarea = textarea
+ this.options = options;
+ this.setDefaults(this.options, defaultOptions);
+
+ this.buttonDefs = {
+ 'save': ["Save", "save", this.options.imagePath + "/page_save.png", this.save],
+ 'search': ["Search/Replace", "find_replace_popup", this.options.imagePath + "/find.png", this.find_replace_popup],
+ 'searchClose': ["Close", "find_replace_popup_close", this.options.imagePath + "/cancel.png", this.find_replace_popup_close],
+ 'searchDialog': ["Search/Replace", "find_replace_window", this.options.imagePath + "/find.png", this.find_replace_window],
+ 'undo': ["Undo", "undo", this.options.imagePath + "/arrow_undo.png", this.undo],
+ 'redo': ["Redo", "redo", this.options.imagePath + "/arrow_redo.png", this.redo],
+ 'jump': ["Jump to line #", "jump", this.options.imagePath + "/page_go.png", this.jump],
+ 'reindentSelection': ["Reformat selection", "reindentSelect", this.options.imagePath + "/text_indent.png", this.reindentSelection],
+ 'reindent': ["Reformat whole document", "reindent", this.options.imagePath + "/page_refresh.png", this.reindent],
+ 'about': ["About CodeMirror-UI", "about", this.options.imagePath + "/help.png", this.about]
+ };
+
+ //place = CodeMirror.replace(place)
+
+ this.home = document.createElement("div");
+ this.textarea.parentNode.insertBefore(this.home, this.textarea);
+ /*if (place.appendChild)
+ place.appendChild(this.home);
+ else
+ place(this.home);
+ */
+ this.self = this;
+
+ var onChange = this.editorChanged.cmuiBind(this);
+ // preserve custom onChance handler
+ if (mirrorOptions.onChange) {
+ mirrorOptions.onChange = function() {
+ mirrorOptions.onChange();
+ onChange();
+ }
+ } else {
+ mirrorOptions.onChange = onChange;
+ }
+ mir = CodeMirror.fromTextArea(this.textarea, mirrorOptions);
+ //console.log(mir);
+ this.mirror = mir;
+
+ this.initButtons();
+
+ //this.initWordWrapControl(); // CodeMirror v2 does not support word wrapping
+
+ if (this.options.searchMode == 'inline') {
+ this.initFindControl();
+ } else if (this.options.searchMode == 'popup') {
+ this.initPopupFindControl();
+ }
+
+ if (this.saveButton) this.addClass(this.saveButton,'inactive');
+ if (this.undoButton) this.addClass(this.undoButton,'inactive');
+ if (this.redoButton) this.addClass(this.redoButton,'inactive');
+ },
+ setDefaults: function(object, defaults) {
+ for (var option in defaults) {
+ if (!object.hasOwnProperty(option))
+ object[option] = defaults[option];
+ }
+ },
+ toTextArea: function() {
+ this.home.parentNode.removeChild(this.home);
+ this.mirror.toTextArea();
+ },
+ initButtons: function() {
+ this.buttonFrame = document.createElement("div");
+ this.buttonFrame.className = "codemirror-ui-clearfix codemirror-ui-button-frame";
+ this.home.appendChild(this.buttonFrame);
+ for (var i = 0; i < this.options.buttons.length; i++) {
+ var buttonId = this.options.buttons[i];
+ var buttonDef = this.buttonDefs[buttonId];
+ this.addButton(buttonDef[0], buttonDef[1], buttonDef[2], buttonDef[3], this.buttonFrame);
+ }
+
+ //this.makeButton("Search", "search");
+ //this.makeButton("Replace", "replace");
+ //this.makeButton("Current line", "line");
+ //this.makeButton("Jump to line", "jump");
+ //this.makeButton("Insert constructor", "macro");
+ //this.makeButton("Indent all", "reindent");
+ },
+ /*
+ * This is left over from the MirrorFrame demo.
+ * Get rid of it quick.
+ */
+ /*
+ makeButton : function(name, action){
+ var button = document.createElement("input");
+ button.type = "button";
+ button.value = name;
+ this.home.appendChild(button);
+ button.onclick = function(){
+ self[action].call(self);
+ };
+ },
+ */
+ createFindBar: function() {
+ var findBar = document.createElement("div");
+ findBar.className = "codemirror-ui-find-bar";
+
+ this.findString = document.createElement("input");
+ this.findString.type = "text";
+ this.findString.size = 8;
+
+ this.findButton = document.createElement("input");
+ this.findButton.type = "button";
+ this.findButton.className = "button mainaction";
+ this.findButton.value = "Find";
+ this.findButton.onclick = function(){this.find()}.cmuiBind(this);
+
+ this.connect(this.findString, "keyup", function(e){
+ var code = e.keyCode;
+ if (code == 13){
+ this.find(this.mirror.getCursor(false))
+ }else{
+ if(!this.findString.value == ""){
+ this.find(this.mirror.getCursor(true))
+ }
+ }
+ this.findString.focus();
+
+ }.cmuiBind(this) );
+
+ var regLabel = document.createElement("label");
+ regLabel.title = "Regular Expressions"
+ this.regex = document.createElement("input");
+ this.regex.type = "checkbox"
+ this.regex.className = "codemirror-ui-checkbox"
+ regLabel.appendChild(this.regex);
+ regLabel.appendChild(document.createTextNode("RegEx"));
+
+ var caseLabel = document.createElement("label");
+ caseLabel.title = "Case Sensitive"
+ this.caseSensitive = document.createElement("input");
+ this.caseSensitive.type = "checkbox"
+ this.caseSensitive.className = "codemirror-ui-checkbox"
+ caseLabel.appendChild(this.caseSensitive);
+ caseLabel.appendChild(document.createTextNode("A/a"));
+
+ this.replaceString = document.createElement("input");
+ this.replaceString.type = "text";
+ this.replaceString.size = 8;
+
+ this.connect(this.replaceString, "keyup", function(e){
+ var code = e.keyCode;
+ if (code == 13){
+ this.replace()
+ }
+ }.cmuiBind(this) );
+
+ this.replaceButton = document.createElement("input");
+ this.replaceButton.type = "button";
+ this.replaceButton.className = "button";
+ this.replaceButton.value = "Replace";
+ this.replaceButton.onclick = this.replace.cmuiBind(this);
+
+ var replaceAllLabel = document.createElement("label");
+ replaceAllLabel.title = "Replace All"
+ this.replaceAll = document.createElement("input");
+ this.replaceAll.type = "checkbox"
+ this.replaceAll.className = "codemirror-ui-checkbox"
+ replaceAllLabel.appendChild(this.replaceAll);
+ replaceAllLabel.appendChild(document.createTextNode("All"));
+
+ findBar.appendChild(this.findString);
+ findBar.appendChild(this.findButton);
+ findBar.appendChild(caseLabel);
+ findBar.appendChild(regLabel);
+
+ findBar.appendChild(this.replaceString);
+ findBar.appendChild(this.replaceButton);
+ findBar.appendChild(replaceAllLabel);
+ return findBar;
+ },
+ initPopupFindControl: function() {
+ var findBar = this.createFindBar();
+
+ this.popupFindWrap = document.createElement("div");
+ this.popupFindWrap.className = "codemirror-ui-popup-find-wrap";
+
+ this.popupFindWrap.appendChild(findBar);
+
+ var buttonDef = this.buttonDefs['searchClose'];
+ this.addButton(buttonDef[0], buttonDef[1], buttonDef[2], buttonDef[3], this.popupFindWrap);
+
+ this.buttonFrame.appendChild(this.popupFindWrap);
+
+ },
+ initFindControl: function() {
+ var findBar = this.createFindBar();
+ this.buttonFrame.appendChild(findBar);
+ },
+ find: function( start ) {
+ var isCaseSensitive = this.caseSensitive.checked;
+ if(start == null){
+ start = this.mirror.getCursor();
+ }
+ var findString = this.findString.value;
+ if (findString == null || findString == '') {
+ alert('You must enter something to search for.');
+ return;
+ }
+ if (this.regex.checked) {
+ findString = new RegExp(findString, !isCaseSensitive ? "i" : "");
+ }
+
+ this.cursor = this.mirror.getSearchCursor(findString, start, !isCaseSensitive );
+ var found = this.cursor.findNext();
+ if (found) {
+ this.mirror.setSelection(this.cursor.from(),this.cursor.to())
+ //this.cursor.select();
+ } else {
+ if (confirm("No more matches. Should we start from the top?")) {
+ this.cursor = this.mirror.getSearchCursor(findString, 0, !isCaseSensitive);
+ found = this.cursor.findNext();
+ if (found) {
+ this.mirror.setSelection(this.cursor.from(),this.cursor.to())
+ //this.cursor.select();
+ } else {
+ alert("No matches found.");
+ }
+ }
+ }
+ },
+ replace: function() {
+ var findString = this.findString.value,
+ replaceString = this.replaceString.value,
+ isCaseSensitive = this.caseSensitive.checked,
+ isRegex = this.regex.checked,
+ regFindString = isRegex ? new RegExp(findString, !isCaseSensitive ? "i" : "") : "";
+
+ if (this.replaceAll.checked) {
+ var cursor = this.mirror.getSearchCursor(isRegex ? regFindString : findString, 0, !isCaseSensitive);
+ while (cursor.findNext())
+ this.mirror.replaceRange(
+ isRegex ? cursor.pos.match[0].replace(regFindString, replaceString) : replaceString
+ ,cursor.from(),cursor.to());
+ //cursor.replace(this.replaceString.value);
+ } else {
+ this.mirror.replaceRange(
+ isRegex ? this.cursor.pos.match[0].replace(regFindString, replaceString) : replaceString
+ ,this.cursor.from(),this.cursor.to())
+ //this.cursor.replace(this.replaceString.value);
+ this.find();
+ }
+ },
+ initWordWrapControl: function() {
+ var wrapDiv = document.createElement("div");
+ wrapDiv.className = "codemirror-ui-wrap"
+
+ var label = document.createElement("label");
+
+ this.wordWrap = document.createElement("input");
+ this.wordWrap.type = "checkbox"
+ this.wordWrap.checked = true;
+ label.appendChild(this.wordWrap);
+ label.appendChild(document.createTextNode("Word Wrap"));
+ this.wordWrap.onchange = this.toggleWordWrap.cmuiBind(this);
+ wrapDiv.appendChild(label);
+ this.buttonFrame.appendChild(wrapDiv);
+ },
+ toggleWordWrap: function() {
+ if (this.wordWrap.checked) {
+ this.mirror.setTextWrapping("nowrap");
+ } else {
+ this.mirror.setTextWrapping("");
+ }
+ },
+ addButton: function(name, action, image, func, frame) {
+ var button = document.createElement("a");
+ //button.href = "#";
+ button.className = "codemirror-ui-button " + action;
+ button.title = name;
+ button.func = func.cmuiBind(this);
+ button.onclick = function(event) {
+ //alert(event.target);
+ event.target.func();
+ return false;
+ //this.self[action].call(this);
+ //eval("this."+action)();
+ }
+ .cmuiBind(this, func);
+ var img = document.createElement("img");
+ img.src = image;
+ img.border = 0;
+ img.func = func.cmuiBind(this);
+ button.appendChild(img);
+ frame.appendChild(button);
+ if (action == 'save') {
+ this.saveButton = button;
+ }
+ if (action == 'undo') {
+ this.undoButton = button;
+ }
+ if (action == 'redo') {
+ this.redoButton = button;
+ }
+ },
+ classNameRegex: function(className) {
+ var regex = new RegExp("(.*) *" + className + " *(.*)");
+ return regex;
+ },
+ addClass: function(element, className) {
+ if (!element.className.match(this.classNameRegex(className))) {
+ element.className += " " + className;
+ }
+ },
+ removeClass: function(element, className) {
+ var m = element.className.match(this.classNameRegex(className))
+ if (m) {
+ element.className = m[1] + " " + m[2];
+ }
+ },
+ editorChanged: function() {
+ if(!this.mirror) {
+ return
+ }
+ var his = this.mirror.historySize();
+ if (his['undo'] > 0) {
+ this.removeClass(this.saveButton, 'inactive');
+ this.removeClass(this.undoButton, 'inactive');
+ } else {
+ this.addClass(this.saveButton, 'inactive');
+ this.addClass(this.undoButton, 'inactive');
+ }
+ if (his['redo'] > 0) {
+ this.removeClass(this.redoButton, 'inactive');
+ } else {
+ this.addClass(this.redoButton, 'inactive');
+ }
+ //alert("undo size = " + his['undo'] + " and redo size = " + his['redo']);
+ },
+ save: function() {
+ this.options.saveCallback();
+ this.addClass(this.saveButton, 'inactive');
+ },
+ undo: function() {
+ this.mirror.undo();
+ },
+ redo: function() {
+ this.mirror.redo();
+ },
+ replaceSelection: function(newVal) {
+ this.mirror.replaceSelection(newVal);
+ this.searchWindow.focus();
+ },
+ raise_search_window: function() {
+ //alert('raising window!');
+ this.searchWindow.focus();
+ },
+ find_replace_window: function() {
+ if (this.searchWindow == null) {
+ this.searchWindow = window.open(this.options.path + "find_replace.html", "mywindow", "scrollbars=1,width=400,height=350,modal=yes");
+ this.searchWindow.codeMirrorUI = this;
+ }
+ this.searchWindow.focus();
+ },
+ find_replace_popup: function() {
+ //alert('Hello!');
+ this.popupFindWrap.className = "codemirror-ui-popup-find-wrap active";
+ this.findString.focus();
+ },
+ find_replace_popup_close: function() {
+ //alert('Hello!');
+ this.popupFindWrap.className = "codemirror-ui-popup-find-wrap";
+ },
+ /*
+ find_replace: function(){
+ this.find_replace = document.createElement("div");
+ this.find_replace.className = "codemirror-search-replace";
+ this.find_replace.innerHTML = "Just a test!";
+ this.home.appendChild(this.find_replace);
+ },
+
+ search: function(){
+ var text = prompt("Enter search term:", "");
+ if (!text)
+ return;
+
+ var first = true;
+ do {
+ var cursor = this.mirror.getSearchCursor(text, first);
+ first = false;
+ while (cursor.findNext()) {
+ cursor.select();
+ if (!confirm("Search again?"))
+ return;
+ }
+ }
+ while (confirm("End of document reached. Start over?"));
+ },
+
+ replace: function(){
+ // This is a replace-all, but it is possible to implement a
+ // prompting replace.
+ var from = prompt("Enter search string:", ""), to;
+ if (from)
+ to = prompt("What should it be replaced with?", "");
+ if (to == null)
+ return;
+
+ var cursor = this.mirror.getSearchCursor(from, false);
+ while (cursor.findNext())
+ cursor.replace(to);
+ },
+ */
+ jump: function() {
+ var line = prompt("Jump to line:", "");
+ if (line && !isNaN(Number(line))) {
+ this.mirror.setCursor(Number(line),0);
+ this.mirror.setSelection({line:Number(line),ch:0},{line:Number(line)+1,ch:0});
+ this.mirror.focus();
+ }
+ },
+ /*
+ line: function(){
+ alert("The cursor is currently at line " + this.mirror.currentLine());
+ this.mirror.focus();
+ },
+
+ macro: function(){
+ var name = prompt("Name your constructor:", "");
+ if (name)
+ this.mirror.replaceSelection("function " + name + "() {\n \n}\n\n" + name + ".prototype = {\n \n};\n");
+ },
+ */
+ reindent: function() {
+ var lineCount = this.mirror.lineCount();
+ for(var line = 0; line < lineCount; line++) {
+ this.mirror.indentLine(line);
+ }
+ },
+ about : function() {
+ string = "CodeMirror-UI was written by Jeremy Green (http://www.octolabs.com/) as a light interface around CodeMirror by Marijn Haverbeke (http://codemirror.net)."
+ string += "\n\n"
+ string += "Documentation and the code can be found at https://github.com/jagthedrummer/codemirror-ui/."
+ alert(string);
+ },
+ reindentSelection: function() {
+ var cur = this.mirror.getCursor()
+ //console.log(cur)
+ var start = this.mirror.getCursor(true)["line"]
+ var end = this.mirror.getCursor(false)["line"]
+ for(var line = start; line <= end; line++) {
+ this.mirror.indentLine(line);
+ }
+ //this.mirror.reindentSelection();
+
+ },
+ // Event handler registration. If disconnect is true, it'll return a
+ // function that unregisters the handler.
+ // Borrowed from CodeMirror + modified
+ connect: function (node, type, handler, disconnect) {
+ /*function wrapHandler(event) {
+ handler(new Event(event || window.event));
+ }*/
+
+ if (typeof node.addEventListener == "function") {
+ node.addEventListener(type, handler, false);
+ if (disconnect)
+ return function() {
+ node.removeEventListener(type, handler, false);
+ };
+ } else {
+ node.attachEvent("on" + type, handler);
+ if (disconnect)
+ return function() {
+ node.detachEvent("on" + type, handler);
+ };
+ }
+ }
+};
+
+/*
+ * This makes coding callbacks much more sane
+ */
+Function.prototype.cmuiBind = function(scope) {
+ var _function = this;
+
+ return function() {
+ return _function.apply(scope, arguments);
+ }
+}
diff --git a/codemirror_ui/js/find_replace.html b/codemirror_ui/js/find_replace.html
new file mode 100644
index 0000000..3e551f4
--- /dev/null
+++ b/codemirror_ui/js/find_replace.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>CodeMirror UI Find/Replace</title>
+ <link rel="stylesheet" href="../css/codemirror-ui-find.css" type="text/css" media="screen" />
+ <script src="codemirror-ui-find.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <h3>Find/Replace</h3>
+ <form name="findReplaceForm">
+ <table>
+ <tr>
+ <td>Find</td>
+ <td><input id="find" type="text" value=""/></td>
+ </tr>
+ <tr>
+ <td>Replace</td>
+ <td><input id="replace" type="text" value=""/></td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <label>
+ <input type="radio" name="direction" value="forward" checked="checked"/>Forward
+ </label>
+ <label>
+ <input type="radio" name="direction" value="backward"/>Backward
+ </label>
+ <br/>
+ <label>
+ <input type="checkbox" id="wrap" value="true"/>Wrap Search
+ </label>
+ <br/>
+ <label>
+ <input type="checkbox" id="regex" value="true"/>Regex
+ </label>
+ </td>
+ </tr>
+ </table>
+ </form>
+ <table id="buttons">
+ <tr>
+ <td>
+ <a href="#" id="findButton">Find</a>
+ </td>
+ <td>
+ <a href="#" id="replaceFindButton">Replace/Find</a>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <a href="#" id="replaceButton">Replace</a>
+ </td>
+ <td>
+ <a href="#" id="replaceAllButton">Replace All</a>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <a href="#" id="closeButton">Close</a>
+ </td>
+ </tr>
+ </table>
+ <script type="text/javascript">
+ setupFindReplace();
+ </script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/README.md b/codemirror_ui/lib/CodeMirror-2.3/README.md
new file mode 100644
index 0000000..48a893f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/README.md
@@ -0,0 +1,8 @@
+# CodeMirror 2
+
+CodeMirror is a JavaScript component that provides a code editor in
+the browser. When a mode is available for the language you are coding
+in, it will color your code, and optionally help with indentation.
+
+The project page is http://codemirror.net
+The manual is at http://codemirror.net/doc/manual.html
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/activeline.html b/codemirror_ui/lib/CodeMirror-2.3/demo/activeline.html
new file mode 100644
index 0000000..a5b3c2c
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/activeline.html
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Active Line Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../mode/xml/xml.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+ .activeline {background: #e8f2ff !important;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Active Line Demo</h1>
+
+ <form><textarea id="code" name="code">
+<?xml version="1.0" encoding="UTF-8"?>
+<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"
+ xmlns:georss="http://www.georss.org/georss"
+ xmlns:twitter="http://api.twitter.com">
+ <channel>
+ <title>Twitter / codemirror</title>
+ <link>http://twitter.com/codemirror</link>
+ <atom:link type="application/rss+xml"
+ href="http://twitter.com/statuses/user_timeline/242283288.rss" rel="self"/>
+ <description>Twitter updates from CodeMirror / codemirror.</description>
+ <language>en-us</language>
+ <ttl>40</ttl>
+ <item>
+ <title>codemirror: http://cloud-ide.com &#8212; they're springing up like mushrooms. This one
+ uses CodeMirror as its editor.</title>
+ <description>codemirror: http://cloud-ide.com &#8212; they're springing up like mushrooms. This
+ one uses CodeMirror as its editor.</description>
+ <pubDate>Thu, 17 Mar 2011 23:34:47 +0000</pubDate>
+ <guid>http://twitter.com/codemirror/statuses/48527733722058752</guid>
+ <link>http://twitter.com/codemirror/statuses/48527733722058752</link>
+ <twitter:source>web</twitter:source>
+ <twitter:place/>
+ </item>
+ <item>
+ <title>codemirror: Posted a description of the CodeMirror 2 internals at
+ http://codemirror.net/2/internals.html</title>
+ <description>codemirror: Posted a description of the CodeMirror 2 internals at
+ http://codemirror.net/2/internals.html</description>
+ <pubDate>Wed, 02 Mar 2011 12:15:09 +0000</pubDate>
+ <guid>http://twitter.com/codemirror/statuses/42920879788789760</guid>
+ <link>http://twitter.com/codemirror/statuses/42920879788789760</link>
+ <twitter:source>web</twitter:source>
+ <twitter:place/>
+ </item>
+ </channel>
+</rss></textarea></form>
+
+ <script>
+var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: "application/xml",
+ lineNumbers: true,
+ lineWrapping: true,
+ onCursorActivity: function() {
+ editor.setLineClass(hlLine, null, null);
+ hlLine = editor.setLineClass(editor.getCursor().line, null, "activeline");
+ }
+});
+var hlLine = editor.setLineClass(0, "activeline");
+</script>
+
+ <p>Styling the current cursor line.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/changemode.html b/codemirror_ui/lib/CodeMirror-2.3/demo/changemode.html
new file mode 100644
index 0000000..f5e0661
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/changemode.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Mode-Changing Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../mode/javascript/javascript.js"></script>
+ <script src="../mode/scheme/scheme.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border: 1px solid black;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Mode-Changing demo</h1>
+
+ <form><textarea id="code" name="code">
+;; If there is Scheme code in here, the editor will be in Scheme mode.
+;; If you put in JS instead, it'll switch to JS mode.
+
+(define (double x)
+ (* x x))
+</textarea></form>
+
+<p>On changes to the content of the above editor, a (crude) script
+tries to auto-detect the language used, and switches the editor to
+either JavaScript or Scheme mode based on that.</p>
+
+<script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: "scheme",
+ lineNumbers: true,
+ matchBrackets: true,
+ tabMode: "indent",
+ onChange: function() {
+ clearTimeout(pending);
+ setTimeout(update, 400);
+ }
+ });
+ var pending;
+ function looksLikeScheme(code) {
+ return !/^\s*\(\s*function\b/.test(code) && /^\s*[;\(]/.test(code);
+ }
+ function update() {
+ editor.setOption("mode", looksLikeScheme(editor.getValue()) ? "scheme" : "javascript");
+ }
+</script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/closetag.html b/codemirror_ui/lib/CodeMirror-2.3/demo/closetag.html
new file mode 100644
index 0000000..57cd4be
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/closetag.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Close-Tag Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../lib/util/closetag.js"></script>
+ <script src="../mode/xml/xml.js"></script>
+ <script src="../mode/javascript/javascript.js"></script>
+ <script src="../mode/css/css.js"></script>
+ <script src="../mode/htmlmixed/htmlmixed.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid #eee; border-bottom: 1px solid #eee;}
+ </style>
+ </head>
+ <body>
+
+ <h1>Close-Tag Demo</h1>
+ <ul>
+ <li>Type an html tag. When you type '>' or '/', the tag will auto-close/complete. Block-level tags will indent.</li>
+ <li>There are options for disabling tag closing or customizing the list of tags to indent.</li>
+ <li>Works with "text/html" (based on htmlmixed.js or xml.js) mode.</li>
+ <li>View source for key binding details.</li>
+ </p>
+
+ <form><textarea id="code" name="code"></textarea></form>
+
+ <script type="text/javascript">
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: 'text/html',
+
+ //closeTagEnabled: false, // Set this option to disable tag closing behavior without having to remove the key bindings.
+ //closeTagIndent: false, // Pass false or an array of tag names to override the default indentation behavior.
+
+ extraKeys: {
+ "'>'": function(cm) { cm.closeTag(cm, '>'); },
+ "'/'": function(cm) { cm.closeTag(cm, '/'); }
+ },
+
+ /*
+ // extraKeys is the easier way to go, but if you need native key event processing, this should work too.
+ onKeyEvent: function(cm, e) {
+ if (e.type == 'keydown') {
+ var c = e.keyCode || e.which;
+ if (c == 190 || c == 191) {
+ try {
+ cm.closeTag(cm, c == 190 ? '>' : '/');
+ e.stop();
+ return true;
+ } catch (e) {
+ if (e != CodeMirror.Pass) throw e;
+ }
+ }
+ }
+ return false;
+ },
+ */
+
+ wordWrap: true
+ });
+ </script>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/complete.html b/codemirror_ui/lib/CodeMirror-2.3/demo/complete.html
new file mode 100644
index 0000000..95ae397
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/complete.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Autocomplete Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../lib/util/simple-hint.js"></script>
+ <link rel="stylesheet" href="../lib/util/simple-hint.css">
+ <script src="../lib/util/javascript-hint.js"></script>
+ <script src="../mode/javascript/javascript.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+ <style type="text/css">.CodeMirror {border: 1px solid #eee;} .CodeMirror-scroll { height: 100% }</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Autocomplete demo</h1>
+
+ <form><textarea id="code" name="code">
+function getCompletions(token, context) {
+ var found = [], start = token.string;
+ function maybeAdd(str) {
+ if (str.indexOf(start) == 0) found.push(str);
+ }
+ function gatherCompletions(obj) {
+ if (typeof obj == "string") forEach(stringProps, maybeAdd);
+ else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
+ else if (obj instanceof Function) forEach(funcProps, maybeAdd);
+ for (var name in obj) maybeAdd(name);
+ }
+
+ if (context) {
+ // If this is a property, see if it belongs to some object we can
+ // find in the current environment.
+ var obj = context.pop(), base;
+ if (obj.className == "js-variable")
+ base = window[obj.string];
+ else if (obj.className == "js-string")
+ base = "";
+ else if (obj.className == "js-atom")
+ base = 1;
+ while (base != null && context.length)
+ base = base[context.pop().string];
+ if (base != null) gatherCompletions(base);
+ }
+ else {
+ // If not, just look in the window object and any local scope
+ // (reading into JS mode internals to get at the local variables)
+ for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
+ gatherCompletions(window);
+ forEach(keywords, maybeAdd);
+ }
+ return found;
+}
+</textarea></form>
+
+<p>Press <strong>ctrl-space</strong> to activate autocompletion. See
+the code (<a href="../lib/util/simple-hint.js">here</a>
+and <a href="../lib/util/javascript-hint.js">here</a>) to figure out
+how it works.</p>
+
+ <script>
+ CodeMirror.commands.autocomplete = function(cm) {
+ CodeMirror.simpleHint(cm, CodeMirror.javascriptHint);
+ }
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ extraKeys: {"Ctrl-Space": "autocomplete"}
+ });
+ </script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/emacs.html b/codemirror_ui/lib/CodeMirror-2.3/demo/emacs.html
new file mode 100644
index 0000000..87190c5
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/emacs.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Emacs bindings demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../mode/clike/clike.js"></script>
+ <script src="../keymap/emacs.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid #eee; border-bottom: 1px solid #eee;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Emacs bindings demo</h1>
+
+ <form><textarea id="code" name="code">
+#include "syscalls.h"
+/* getchar: simple buffered version */
+int getchar(void)
+{
+ static char buf[BUFSIZ];
+ static char *bufp = buf;
+ static int n = 0;
+ if (n == 0) { /* buffer is empty */
+ n = read(0, buf, sizeof buf);
+ bufp = buf;
+ }
+ return (--n >= 0) ? (unsigned char) *bufp++ : EOF;
+}
+</textarea></form>
+
+<p>The emacs keybindings are enabled by
+including <a href="../keymap/emacs.js">keymap/emacs.js</a> and setting
+the <code>keyMap</code> option to <code>"emacs"</code>. Because
+CodeMirror's internal API is quite different from Emacs, they are only
+a loose approximation of actual emacs bindings, though.</p>
+
+<p>Also note that a lot of browsers disallow certain keys from being
+captured. For example, Chrome blocks both Ctrl-W and Ctrl-N, with the
+result that idiomatic use of Emacs keys will constantly close your tab
+or open a new window.</p>
+
+ <script>
+ CodeMirror.commands.save = function() {
+ var elt = editor.getWrapperElement();
+ elt.style.background = "#def";
+ setTimeout(function() { elt.style.background = ""; }, 300);
+ };
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ mode: "text/x-csrc",
+ keyMap: "emacs"
+ });
+ </script>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/folding.html b/codemirror_ui/lib/CodeMirror-2.3/demo/folding.html
new file mode 100644
index 0000000..2e05e9b
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/folding.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Code Folding Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../lib/util/foldcode.js"></script>
+ <script src="../mode/javascript/javascript.js"></script>
+ <script src="../mode/xml/xml.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+ .CodeMirror-gutter {min-width: 2.6em; cursor: pointer;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Code Folding Demo</h1>
+
+ <p>Demonstration of code folding using the code
+ in <a href="../lib/util/foldcode.js"><code>foldcode.js</code></a>.
+ Press ctrl-q or click on the gutter to fold a block, again
+ to unfold.</p>
+ <form>
+ <div style="max-width: 50em; margin-bottom: 1em">JavaScript:<br><textarea id="code" name="code"></textarea></div>
+ <div style="max-width: 50em">HTML:<br><textarea id="code-html" name="code-html"></textarea></div>
+ </form>
+ <script id="script">
+window.onload = function() {
+ var te = document.getElementById("code");
+ var sc = document.getElementById("script");
+ te.value = (sc.textContent || sc.innerText || sc.innerHTML).replace(/^\s*/, "");
+ sc.innerHTML = "";
+ var te_html = document.getElementById("code-html");
+ te_html.value = "<html>\n " + document.documentElement.innerHTML + "\n</html>";
+
+ var foldFunc = CodeMirror.newFoldFunction(CodeMirror.braceRangeFinder);
+ window.editor = CodeMirror.fromTextArea(te, {
+ mode: "javascript",
+ lineNumbers: true,
+ lineWrapping: true,
+ onGutterClick: foldFunc,
+ extraKeys: {"Ctrl-Q": function(cm){foldFunc(cm, cm.getCursor().line);}}
+ });
+ foldFunc(editor, 9);
+ foldFunc(editor, 20);
+
+ var foldFunc_html = CodeMirror.newFoldFunction(CodeMirror.tagRangeFinder);
+ window.editor_html = CodeMirror.fromTextArea(te_html, {
+ mode: "text/html",
+ lineNumbers: true,
+ lineWrapping: true,
+ onGutterClick: foldFunc_html,
+ extraKeys: {"Ctrl-Q": function(cm){foldFunc_html(cm, cm.getCursor().line);}}
+ })
+ foldFunc_html(editor_html, 1);
+ foldFunc_html(editor_html, 15);
+};
+</script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/formatting.html b/codemirror_ui/lib/CodeMirror-2.3/demo/formatting.html
new file mode 100644
index 0000000..e4faf5f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/formatting.html
@@ -0,0 +1,80 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Formatting Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../lib/util/formatting.js"></script>
+ <script src="../mode/css/css.js"></script>
+ <script src="../mode/xml/xml.js"></script>
+ <script src="../mode/javascript/javascript.js"></script>
+ <script src="../mode/htmlmixed/htmlmixed.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {
+ border: 1px solid #eee;
+ }
+ td {
+ padding-right: 20px;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Formatting demo</h1>
+
+ <form><textarea id="code" name="code"><script> function (s,e){ for(var i=0; i < 1; i++) test("test();a=1");} </script>
+<script>
+function test(c){ for (var i = 0; i < 10; i++){ process("a.b();c = null;", 300);}
+}
+</script>
+<table><tr><td>test 1</td></tr><tr><td>test 2</td></tr></table>
+<script> function test() { return 1;} </script>
+<style> .test { font-size: medium; font-family: monospace; }
+</style></textarea></form>
+
+<p>Select a piece of code and click one of the links below to apply automatic formatting to the selected text or comment/uncomment the selected text. Note that the formatting behavior depends on the current block's mode.
+ <table>
+ <tr>
+ <td>
+ <a href="javascript:autoFormatSelection()">
+ Autoformat Selected
+ </a>
+ </td>
+ <td>
+ <a href="javascript:commentSelection(true)">
+ Comment Selected
+ </a>
+ </td>
+ <td>
+ <a href="javascript:commentSelection(false)">
+ Uncomment Selected
+ </a>
+ </td>
+ </tr>
+ </table>
+</p>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ mode: "htmlmixed"
+ });
+ CodeMirror.commands["selectAll"](editor);
+
+ function getSelectedRange() {
+ return { from: editor.getCursor(true), to: editor.getCursor(false) };
+ }
+
+ function autoFormatSelection() {
+ var range = getSelectedRange();
+ editor.autoFormatRange(range.from, range.to);
+ }
+
+ function commentSelection(isComment) {
+ var range = getSelectedRange();
+ editor.commentRange(isComment, range.from, range.to);
+ }
+ </script>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/fullscreen.html b/codemirror_ui/lib/CodeMirror-2.3/demo/fullscreen.html
new file mode 100644
index 0000000..0e2b5ec
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/fullscreen.html
@@ -0,0 +1,152 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Full Screen Editing</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <link rel="stylesheet" href="../theme/night.css">
+ <script src="../mode/xml/xml.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+ .CodeMirror-fullscreen {
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 9999;
+ margin: 0;
+ padding: 0;
+ border: 0px solid #BBBBBB;
+ opacity: 1;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Full Screen Editing</h1>
+
+ <form><textarea id="code" name="code" rows="5">
+ <dt id="option_indentWithTabs"><code>indentWithTabs (boolean)</code></dt>
+ <dd>Whether, when indenting, the first N*8 spaces should be
+ replaced by N tabs. Default is false.</dd>
+
+ <dt id="option_tabMode"><code>tabMode (string)</code></dt>
+ <dd>Determines what happens when the user presses the tab key.
+ Must be one of the following:
+ <dl>
+ <dt><code>"classic" (the default)</code></dt>
+ <dd>When nothing is selected, insert a tab. Otherwise,
+ behave like the <code>"shift"</code> mode. (When shift is
+ held, this behaves like the <code>"indent"</code> mode.)</dd>
+ <dt><code>"shift"</code></dt>
+ <dd>Indent all selected lines by
+ one <a href="#option_indentUnit"><code>indentUnit</code></a>.
+ If shift was held while pressing tab, un-indent all selected
+ lines one unit.</dd>
+ <dt><code>"indent"</code></dt>
+ <dd>Indent the line the 'correctly', based on its syntactic
+ context. Only works if the
+ mode <a href="#indent">supports</a> it.</dd>
+ <dt><code>"default"</code></dt>
+ <dd>Do not capture tab presses, let the browser apply its
+ default behaviour (which usually means it skips to the next
+ control).</dd>
+ </dl></dd>
+
+ <dt id="option_enterMode"><code>enterMode (string)</code></dt>
+ <dd>Determines whether and how new lines are indented when the
+ enter key is pressed. The following modes are supported:
+ <dl>
+ <dt><code>"indent" (the default)</code></dt>
+ <dd>Use the mode's indentation rules to give the new line
+ the correct indentation.</dd>
+ <dt><code>"keep"</code></dt>
+ <dd>Indent the line the same as the previous line.</dd>
+ <dt><code>"flat"</code></dt>
+ <dd>Do not indent the new line.</dd>
+ </dl></dd>
+
+ <dt id="option_enterMode"><code>enterMode (string)</code></dt>
+ <dd>Determines whether and how new lines are indented when the
+ enter key is pressed. The following modes are supported:
+ <dl>
+ <dt><code>"indent" (the default)</code></dt>
+ <dd>Use the mode's indentation rules to give the new line
+ the correct indentation.</dd>
+ <dt><code>"keep"</code></dt>
+ <dd>Indent the line the same as the previous line.</dd>
+ <dt><code>"flat"</code></dt>
+ <dd>Do not indent the new line.</dd>
+ </dl></dd>
+
+ <dt id="option_enterMode"><code>enterMode (string)</code></dt>
+ <dd>Determines whether and how new lines are indented when the
+ enter key is pressed. The following modes are supported:
+ <dl>
+ <dt><code>"indent" (the default)</code></dt>
+ <dd>Use the mode's indentation rules to give the new line
+ the correct indentation.</dd>
+ <dt><code>"keep"</code></dt>
+ <dd>Indent the line the same as the previous line.</dd>
+ <dt><code>"flat"</code></dt>
+ <dd>Do not indent the new line.</dd>
+ </dl></dd>
+
+ <dt id="option_enterMode"><code>enterMode (string)</code></dt>
+ <dd>Determines whether and how new lines are indented when the
+ enter key is pressed. The following modes are supported:
+ <dl>
+ <dt><code>"indent" (the default)</code></dt>
+ <dd>Use the mode's indentation rules to give the new line
+ the correct indentation.</dd>
+ <dt><code>"keep"</code></dt>
+ <dd>Indent the line the same as the previous line.</dd>
+ <dt><code>"flat"</code></dt>
+ <dd>Do not indent the new line.</dd>
+ </dl></dd>
+
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ theme: "night",
+ extraKeys: {
+ "F11": function() {
+ var scroller = editor.getScrollerElement();
+ if (scroller.className.search(/\bCodeMirror-fullscreen\b/) === -1) {
+ scroller.className += " CodeMirror-fullscreen";
+ scroller.style.height = "100%";
+ scroller.style.width = "100%";
+ editor.refresh();
+ } else {
+ scroller.className = scroller.className.replace(" CodeMirror-fullscreen", "");
+ scroller.style.height = '';
+ scroller.style.width = '';
+ editor.refresh();
+ }
+ },
+ "Esc": function() {
+ var scroller = editor.getScrollerElement();
+ if (scroller.className.search(/\bCodeMirror-fullscreen\b/) !== -1) {
+ scroller.className = scroller.className.replace(" CodeMirror-fullscreen", "");
+ scroller.style.height = '';
+ scroller.style.width = '';
+ editor.refresh();
+ }
+ }
+ }
+ });
+
+</script>
+
+ <p>Press <strong>F11</strong> when cursor is in the editor to toggle full screen editing. <strong>Esc</strong> can also be used to <i>exit</i> full screen editing.</p>
+
+ <p><strong>Note:</strong> Does not currently work correctly in IE
+ 6 and 7, where setting the height of something
+ to <code>100%</code> doesn't make it full screen.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/loadmode.html b/codemirror_ui/lib/CodeMirror-2.3/demo/loadmode.html
new file mode 100644
index 0000000..3d7015e
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/loadmode.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Lazy Mode Loading Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../lib/util/loadmode.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Lazy Mode Loading</h1>
+
+ <form><textarea id="code" name="code">This is the editor.
+// It starts out in plain text mode,
+# use the control below to load and apply a mode
+ "you'll see the highlighting of" this text /*change*/.
+</textarea></form>
+<p><input type=text value=javascript id=mode> <button type=button onclick="change()">change mode</button></p>
+
+ <script>
+CodeMirror.modeURL = "../mode/%N/%N.js";
+var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true
+});
+var modeInput = document.getElementById("mode");
+CodeMirror.connect(modeInput, "keypress", function(e) {
+ if (e.keyCode == 13) change();
+});
+function change() {
+ editor.setOption("mode", modeInput.value);
+ CodeMirror.autoLoadMode(editor, modeInput.value);
+}
+</script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/marker.html b/codemirror_ui/lib/CodeMirror-2.3/demo/marker.html
new file mode 100644
index 0000000..00a89ce
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/marker.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Breakpoint Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../mode/javascript/javascript.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror-gutter {
+ width: 3em;
+ background: white;
+ }
+ .CodeMirror {
+ border: 1px solid #aaa;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Breakpoint demo</h1>
+
+ <form><textarea id="code" name="code">
+CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ onGutterClick: function(cm, n) {
+ var info = cm.lineInfo(n);
+ if (info.markerText)
+ cm.clearMarker(n);
+ else
+ cm.setMarker(n, "<span style=\"color: #900\">●</span> %N%");
+ }
+});
+</textarea></form>
+
+<p>Click the line-number gutter to add or remove 'breakpoints'.</p>
+
+ <script>
+ CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ onGutterClick: function(cm, n) {
+ var info = cm.lineInfo(n);
+ if (info.markerText)
+ cm.clearMarker(n);
+ else
+ cm.setMarker(n, "<span style=\"color: #900\">●</span> %N%");
+ }
+ });
+ </script>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/matchhighlighter.html b/codemirror_ui/lib/CodeMirror-2.3/demo/matchhighlighter.html
new file mode 100644
index 0000000..768c51e
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/matchhighlighter.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Match Highlighter Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../lib/util/searchcursor.js"></script>
+ <script src="../lib/util/match-highlighter.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+
+ span.CodeMirror-matchhighlight { background: #e9e9e9 }
+ .CodeMirror-focused span.CodeMirror-matchhighlight { background: #e7e4ff; !important }
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Match Highlighter Demo</h1>
+
+ <form><textarea id="code" name="code">Select this text: hardToSpotVar
+ And everywhere else in your code where hardToSpotVar appears will automatically illuminate.
+Give it a try! No more hardToSpotVars.</textarea></form>
+
+ <script>
+var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers : true,
+ onCursorActivity: function() {
+ editor.matchHighlight("CodeMirror-matchhighlight");
+ }
+});
+</script>
+
+ <p>Highlight matches of selected text on select</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/multiplex.html b/codemirror_ui/lib/CodeMirror-2.3/demo/multiplex.html
new file mode 100644
index 0000000..9348545
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/multiplex.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Multiplexing Parser Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../lib/util/multiplex.js"></script>
+ <script src="../mode/xml/xml.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border: 1px solid black;}
+ .cm-delimit {color: #fa4;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Multiplexing Parser Demo</h1>
+
+ <form><textarea id="code" name="code">
+<html>
+ <body>
+ <h1><< this is not <html >></h1>
+ <<
+ multiline
+ not html
+ at all : &amp;amp; <link/>
+ >>
+ <p>this is html again</p>
+ </body>
+</html>
+</textarea></form>
+
+ <script>
+CodeMirror.defineMode("demo", function(config) {
+ return CodeMirror.multiplexingMode(
+ CodeMirror.getMode(config, "text/html"),
+ {open: "<<", close: ">>",
+ mode: CodeMirror.getMode(config, "text/plain"),
+ delimStyle: "delimit"}
+ // .. more multiplexed styles can follow here
+ );
+});
+var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: "demo",
+ lineNumbers: true,
+ lineWrapping: true
+});
+</script>
+
+ <p>Demonstration of a multiplexing mode, which, at certain
+ boundary strings, switches to one or more inner modes. The out
+ (HTML) mode does not get fed the content of the <code>&lt;&lt;
+ >></code> blocks. See
+ the <a href="../doc/manual.html#util_multiplex">manual</a> and
+ the <a href="../lib/util/multiplex.js">source</a> for more
+ information.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/mustache.html b/codemirror_ui/lib/CodeMirror-2.3/demo/mustache.html
new file mode 100644
index 0000000..e96fda8
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/mustache.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Overlay Parser Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../lib/util/overlay.js"></script>
+ <script src="../mode/xml/xml.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border: 1px solid black;}
+ .cm-mustache {color: #0ca;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Overlay Parser Demo</h1>
+
+ <form><textarea id="code" name="code">
+<html>
+ <body>
+ <h1>{{title}}</h1>
+ <p>These are links to {{things}}:</p>
+ <ul>{{#links}}
+ <li><a href="{{url}}">{{text}}</a></li>
+ {{/links}}</ul>
+ </body>
+</html>
+</textarea></form>
+
+ <script>
+CodeMirror.defineMode("mustache", function(config, parserConfig) {
+ var mustacheOverlay = {
+ token: function(stream, state) {
+ var ch;
+ if (stream.match("{{")) {
+ while ((ch = stream.next()) != null)
+ if (ch == "}" && stream.next() == "}") break;
+ return "mustache";
+ }
+ while (stream.next() != null && !stream.match("{{", false)) {}
+ return null;
+ }
+ };
+ return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), mustacheOverlay);
+});
+var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "mustache"});
+</script>
+
+ <p>Demonstration of a mode that parses HTML, highlighting
+ the <a href="http://mustache.github.com/">Mustache</a> templating
+ directives inside of it by using the code
+ in <a href="../lib/util/overlay.js"><code>overlay.js</code></a>. View
+ source to see the 15 lines of code needed to accomplish this.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/preview.html b/codemirror_ui/lib/CodeMirror-2.3/demo/preview.html
new file mode 100644
index 0000000..607a621
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/preview.html
@@ -0,0 +1,76 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: HTML5 preview</title>
+ <meta charset=utf-8>
+ <script src=../lib/codemirror.js></script>
+ <script src=../mode/xml/xml.js></script>
+ <script src=../mode/javascript/javascript.js></script>
+ <script src=../mode/css/css.js></script>
+ <script src=../mode/htmlmixed/htmlmixed.js></script>
+ <link rel=stylesheet href=../lib/codemirror.css>
+ <link rel=stylesheet href=../doc/docs.css>
+ <style type=text/css>
+ .CodeMirror {
+ float: left;
+ width: 50%;
+ border: 1px solid black;
+ }
+ iframe {
+ width: 49%;
+ float: left;
+ height: 300px;
+ border: 1px solid black;
+ border-left: 0px;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: HTML5 preview</h1>
+ <textarea id=code name=code>
+<!doctype html>
+<html>
+ <head>
+ <meta charset=utf-8>
+ <title>HTML5 canvas demo</title>
+ <style>p {font-family: monospace;}</style>
+ </head>
+ <body>
+ <p>Canvas pane goes here:</p>
+ <canvas id=pane width=300 height=200></canvas>
+ <script>
+ var canvas = document.getElementById('pane');
+ var context = canvas.getContext('2d');
+
+ context.fillStyle = 'rgb(250,0,0)';
+ context.fillRect(10, 10, 55, 50);
+
+ context.fillStyle = 'rgba(0, 0, 250, 0.5)';
+ context.fillRect(30, 30, 55, 50);
+ </script>
+ </body>
+</html></textarea>
+ <iframe id=preview></iframe>
+ <script>
+ var delay;
+ // Initialize CodeMirror editor with a nice html5 canvas demo.
+ var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
+ mode: 'text/html',
+ tabMode: 'indent',
+ onChange: function() {
+ clearTimeout(delay);
+ delay = setTimeout(updatePreview, 300);
+ }
+ });
+
+ function updatePreview() {
+ var previewFrame = document.getElementById('preview');
+ var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
+ preview.open();
+ preview.write(editor.getValue());
+ preview.close();
+ }
+ setTimeout(updatePreview, 300);
+ </script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/resize.html b/codemirror_ui/lib/CodeMirror-2.3/demo/resize.html
new file mode 100644
index 0000000..e20c3fb
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/resize.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Autoresize Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../mode/css/css.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {
+ border: 1px solid #eee;
+ }
+ .CodeMirror-scroll {
+ height: auto;
+ overflow-y: hidden;
+ overflow-x: auto;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Autoresize demo</h1>
+
+ <form><textarea id="code" name="code">
+.CodeMirror-scroll {
+ height: auto;
+ overflow-y: hidden;
+ overflow-x: auto;
+}</textarea></form>
+
+<p>By setting a few CSS properties, CodeMirror can be made to
+automatically resize to fit its content.</p>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true
+ });
+ </script>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/runmode.html b/codemirror_ui/lib/CodeMirror-2.3/demo/runmode.html
new file mode 100644
index 0000000..d6ee17e
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/runmode.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Mode Runner Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../lib/util/runmode.js"></script>
+ <script src="../mode/xml/xml.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Mode Runner Demo</h1>
+
+ <textarea id="code" style="width: 90%; height: 7em; border: 1px solid black; padding: .2em .4em;">
+<foobar>
+ <blah>Enter your xml here and press the button below to display
+ it as highlighted by the CodeMirror XML mode</blah>
+ <tag2 foo="2" bar="&amp;quot;bar&amp;quot;"/>
+</foobar></textarea><br>
+ <button onclick="doHighlight();">Highlight!</button>
+ <pre id="output" class="cm-s-default"></pre>
+
+ <script>
+function doHighlight() {
+ CodeMirror.runMode(document.getElementById("code").value, "application/xml",
+ document.getElementById("output"));
+}
+</script>
+
+ <p>Running a CodeMirror mode outside of the editor.
+ The <code>CodeMirror.runMode</code> function, defined
+ in <code><a href="../lib/util/runmode.js">lib/runmode.js</a></code> takes the following arguments:</p>
+
+ <dl>
+ <dt><code>text (string)</code></dt>
+ <dd>The document to run through the highlighter.</dd>
+ <dt><code>mode (<a href="../doc/manual.html#option_mode">mode spec</a>)</code></dt>
+ <dd>The mode to use (must be loaded as normal).</dd>
+ <dt><code>output (function or DOM node)</code></dt>
+ <dd>If this is a function, it will be called for each token with
+ two arguments, the token's text and the token's style class (may
+ be <code>null</code> for unstyled tokens). If it is a DOM node,
+ the tokens will be converted to <code>span</code> elements as in
+ an editor, and inserted into the node
+ (through <code>innerHTML</code>).</dd>
+ </dl>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/search.html b/codemirror_ui/lib/CodeMirror-2.3/demo/search.html
new file mode 100644
index 0000000..c385e6b
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/search.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Search/Replace Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../mode/xml/xml.js"></script>
+ <script src="../lib/util/dialog.js"></script>
+ <link rel="stylesheet" href="../lib/util/dialog.css">
+ <script src="../lib/util/searchcursor.js"></script>
+ <script src="../lib/util/search.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+ dt {font-family: monospace; color: #666;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Search/Replace Demo</h1>
+
+ <form><textarea id="code" name="code">
+ <dt id="option_indentWithTabs"><code>indentWithTabs (boolean)</code></dt>
+ <dd>Whether, when indenting, the first N*8 spaces should be
+ replaced by N tabs. Default is false.</dd>
+
+ <dt id="option_tabMode"><code>tabMode (string)</code></dt>
+ <dd>Determines what happens when the user presses the tab key.
+ Must be one of the following:
+ <dl>
+ <dt><code>"classic" (the default)</code></dt>
+ <dd>When nothing is selected, insert a tab. Otherwise,
+ behave like the <code>"shift"</code> mode. (When shift is
+ held, this behaves like the <code>"indent"</code> mode.)</dd>
+ <dt><code>"shift"</code></dt>
+ <dd>Indent all selected lines by
+ one <a href="#option_indentUnit"><code>indentUnit</code></a>.
+ If shift was held while pressing tab, un-indent all selected
+ lines one unit.</dd>
+ <dt><code>"indent"</code></dt>
+ <dd>Indent the line the 'correctly', based on its syntactic
+ context. Only works if the
+ mode <a href="#indent">supports</a> it.</dd>
+ <dt><code>"default"</code></dt>
+ <dd>Do not capture tab presses, let the browser apply its
+ default behaviour (which usually means it skips to the next
+ control).</dd>
+ </dl></dd>
+
+ <dt id="option_enterMode"><code>enterMode (string)</code></dt>
+ <dd>Determines whether and how new lines are indented when the
+ enter key is pressed. The following modes are supported:
+ <dl>
+ <dt><code>"indent" (the default)</code></dt>
+ <dd>Use the mode's indentation rules to give the new line
+ the correct indentation.</dd>
+ <dt><code>"keep"</code></dt>
+ <dd>Indent the line the same as the previous line.</dd>
+ <dt><code>"flat"</code></dt>
+ <dd>Do not indent the new line.</dd>
+ </dl></dd>
+</textarea></form>
+
+ <script>
+var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", lineNumbers: true});
+</script>
+
+ <p>Demonstration of primitive search/replace functionality. The
+ keybindings (which can be overridden by custom keymaps) are:</p>
+ <dl>
+ <dt>Ctrl-F / Cmd-F</dt><dd>Start searching</dd>
+ <dt>Ctrl-G / Cmd-G</dt><dd>Find next</dd>
+ <dt>Shift-Ctrl-G / Shift-Cmd-G</dt><dd>Find previous</dd>
+ <dt>Shift-Ctrl-F / Cmd-Option-F</dt><dd>Replace</dd>
+ <dt>Shift-Ctrl-R / Shift-Cmd-Option-F</dt><dd>Replace all</dd>
+ </dl>
+ <p>Searching is enabled by
+ including <a href="../lib/util/search.js">lib/util/search.js</a>.
+ For good-looking input dialogs, you also want to include
+ <a href="../lib/util/dialog.js">lib/util/dialog.js</a>
+ and <a href="../lib/util/dialog.css">lib/util/dialog.css</a>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/theme.html b/codemirror_ui/lib/CodeMirror-2.3/demo/theme.html
new file mode 100644
index 0000000..ac47d91
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/theme.html
@@ -0,0 +1,78 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Theme Demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <link rel="stylesheet" href="../theme/neat.css">
+ <link rel="stylesheet" href="../theme/elegant.css">
+ <link rel="stylesheet" href="../theme/erlang-dark.css">
+ <link rel="stylesheet" href="../theme/night.css">
+ <link rel="stylesheet" href="../theme/monokai.css">
+ <link rel="stylesheet" href="../theme/cobalt.css">
+ <link rel="stylesheet" href="../theme/eclipse.css">
+ <link rel="stylesheet" href="../theme/rubyblue.css">
+ <link rel="stylesheet" href="../theme/lesser-dark.css">
+ <link rel="stylesheet" href="../theme/xq-dark.css">
+ <link rel="stylesheet" href="../theme/ambiance.css">
+ <link rel="stylesheet" href="../theme/blackboard.css">
+ <link rel="stylesheet" href="../theme/vibrant-ink.css">
+ <script src="../mode/javascript/javascript.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border: 1px solid black; font-size:13px}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Theme demo</h1>
+
+ <form><textarea id="code" name="code">
+function findSequence(goal) {
+ function find(start, history) {
+ if (start == goal)
+ return history;
+ else if (start > goal)
+ return null;
+ else
+ return find(start + 5, "(" + history + " + 5)") ||
+ find(start * 3, "(" + history + " * 3)");
+ }
+ return find(1, "1");
+}</textarea></form>
+
+<p>Select a theme: <select onchange="selectTheme()" id=select>
+ <option selected>default</option>
+ <option>ambiance</option>
+ <option>blackboard</option>
+ <option>cobalt</option>
+ <option>eclipse</option>
+ <option>elegant</option>
+ <option>erlang-dark</option>
+ <option>lesser-dark</option>
+ <option>monokai</option>
+ <option>neat</option>
+ <option>night</option>
+ <option>rubyblue</option>
+ <option>vibrant-ink</option>
+ <option>xq-dark</option>
+</select>
+</p>
+
+<script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true
+ });
+ var input = document.getElementById("select");
+ function selectTheme() {
+ var theme = input.options[input.selectedIndex].innerHTML;
+ editor.setOption("theme", theme);
+ }
+ var choice = document.location.search && document.location.search.slice(1);
+ if (choice) {
+ input.value = choice;
+ editor.setOption("theme", choice);
+ }
+</script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/vim.html b/codemirror_ui/lib/CodeMirror-2.3/demo/vim.html
new file mode 100644
index 0000000..76ad6da
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/vim.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Vim bindings demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../mode/clike/clike.js"></script>
+ <script src="../keymap/vim.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid #eee; border-bottom: 1px solid #eee;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Vim bindings demo</h1>
+
+ <form><textarea id="code" name="code">
+#include "syscalls.h"
+/* getchar: simple buffered version */
+int getchar(void)
+{
+ static char buf[BUFSIZ];
+ static char *bufp = buf;
+ static int n = 0;
+ if (n == 0) { /* buffer is empty */
+ n = read(0, buf, sizeof buf);
+ bufp = buf;
+ }
+ return (--n >= 0) ? (unsigned char) *bufp++ : EOF;
+}
+</textarea></form>
+
+<p>The vim keybindings are enabled by
+including <a href="../keymap/vim.js">keymap/vim.js</a> and setting
+the <code>keyMap</code> option to <code>"vim"</code>. Because
+CodeMirror's internal API is quite different from Vim, they are only
+a loose approximation of actual vim bindings, though.</p>
+
+ <script>
+ CodeMirror.commands.save = function(){ alert("Saving"); };
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ mode: "text/x-csrc",
+ keyMap: "vim"
+ });
+ </script>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/demo/visibletabs.html b/codemirror_ui/lib/CodeMirror-2.3/demo/visibletabs.html
new file mode 100644
index 0000000..96d1ea5
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/demo/visibletabs.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Visible tabs demo</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../mode/clike/clike.js"></script>
+ <link rel="stylesheet" href="../doc/docs.css">
+
+ <style type="text/css">
+ .CodeMirror {border-top: 1px solid #eee; border-bottom: 1px solid #eee;}
+ .cm-tab:after {
+ content: "\21e5";
+ display: -moz-inline-block;
+ display: -webkit-inline-block;
+ display: inline-block;
+ width: 0px;
+ position: relative;
+ overflow: visible;
+ left: -1.4em;
+ color: #aaa;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Visible tabs demo</h1>
+
+ <form><textarea id="code" name="code">
+#include "syscalls.h"
+/* getchar: simple buffered version */
+int getchar(void)
+{
+ static char buf[BUFSIZ];
+ static char *bufp = buf;
+ static int n = 0;
+ if (n == 0) { /* buffer is empty */
+ n = read(0, buf, sizeof buf);
+ bufp = buf;
+ }
+ return (--n >= 0) ? (unsigned char) *bufp++ : EOF;
+}
+</textarea></form>
+
+<p>Tabs inside the editor are spans with the
+class <code>cm-tab</code>, and can be styled. This demo uses
+an <code>:after</code> pseudo-class CSS hack that will not work on old
+browsers. You can use a more conservative technique like a background
+image as an alternative.</p>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ tabSize: 4,
+ indentUnit: 4,
+ indentWithTabs: true,
+ mode: "text/x-csrc"
+ });
+ </script>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/doc/baboon.png b/codemirror_ui/lib/CodeMirror-2.3/doc/baboon.png
new file mode 100644
index 0000000..55d97f7
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/doc/baboon.png
Binary files differ
diff --git a/codemirror_ui/lib/CodeMirror-2.3/doc/baboon_vector.svg b/codemirror_ui/lib/CodeMirror-2.3/doc/baboon_vector.svg
new file mode 100644
index 0000000..dc1667a
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/doc/baboon_vector.svg
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg3181"
+ version="1.1"
+ inkscape:version="0.48.0 r9654"
+ width="1750"
+ height="960"
+ xml:space="preserve"
+ sodipodi:docname="baboon_vector.svg"><metadata
+ id="metadata3187"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs3185"><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3195"><path
+ d="M 0,768 1400,768 1400,0 0,0 0,768 z"
+ id="path3197" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3215"><path
+ d="M 0,768 1400,768 1400,0 0,0 0,768 z"
+ id="path3217" /></clipPath></defs><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1440"
+ inkscape:window-height="851"
+ id="namedview3183"
+ showgrid="false"
+ inkscape:zoom="0.20550291"
+ inkscape:cx="1534.1667"
+ inkscape:cy="795.78156"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="g3189" /><g
+ id="g3189"
+ inkscape:groupmode="layer"
+ inkscape:label="baboon_vector"
+ transform="matrix(1.25,0,0,-1.25,0,960)"><g
+ id="g3191"><g
+ id="g3193"
+ clip-path="url(#clipPath3195)"><g
+ id="g3199"
+ transform="translate(458.9561,569.9678)"><path
+ d="m 0,0 59.835,69.355 87.034,26.518 133.949,-7.479 c 0,0 74.116,-32.639 74.795,-34.678 0.68,-2.04 84.314,-59.155 84.314,-59.155 l 12.238,-74.795 5.439,-97.912 -13.598,-25.159 -4.76,-40.797 -18.358,-23.118 24.39,-5.561 0.501,-5.192 -14.012,-60.641 16.477,-93.368 7.223,-49.972 -208.295,-51.754 -18.552,4.005 -37.468,8.325 -10.036,4.036 -66.885,10.101 c 0,0 -14.959,74.793 -16.999,73.433 -2.039,-1.359 -42.836,56.437 -42.836,56.437 l -19.719,65.274 12.48,74.571 -7.961,9.643 -26.479,16.187 -12.716,38.309 4.08,48.277 8.769,38.985 L 6.608,-74.308 0,0 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3201" /></g><g
+ id="g3203"
+ transform="translate(78.8657,682.1582)"><path
+ d="M 0,0 142.789,40.797 259.74,52.355 313.457,-232.543 204.665,-291.698 78.194,-293.738 0,0 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3205" /></g><g
+ id="g3207"
+ transform="translate(269.5122,345.2344)"><path
+ d="M 0,0 18.801,-74.425 40.728,-85.408 59.539,-59.541 40.259,13.503 36.821,15.669 0,0 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3209" /></g></g></g><g
+ id="g3223"
+ transform="translate(741.918,109.0332)"><path
+ d="m 0,0 -17.236,-9.401 -16.452,-22.721 -0.783,12.537 6.268,17.234 13.317,6.268 L 0,7.833 14.884,3.917 0,0 z m 172.622,-21.824 c -0.031,0.271 -0.081,0.535 -0.117,0.804 -20.85,7.653 -49.59,7.327 -66.874,10.927 -13.849,2.886 -23.047,9.119 -27.032,12.298 -9.863,-8.494 -12.025,-14.377 -12.025,-14.377 0,0 -9.816,15.309 -30.17,25.76 -7.05,3.621 -17.767,5.691 -29.341,5.691 -24.297,0 -52.384,-9.155 -58.339,-32.223 -10.458,-40.511 9.697,-76.594 49.814,-77.623 1.325,-0.034 2.623,-0.12 3.894,-0.12 36.131,0 48.855,8.572 58.323,15.478 0.027,0.021 0.104,0 0.104,0 0,0 25.126,-11.506 53.529,-11.506 4.419,0 9.156,0.415 14.249,1.063 31.641,4.018 47.989,28.124 43.985,63.828"
+ style="fill:#df0019;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3225"
+ inkscape:connector-curvature="0" /></g><g
+ id="g3227"
+ transform="translate(300.8481,270.0254)"><path
+ d="m 0,0 c -3.063,-0.691 -12.535,0.784 -12.535,0.784 l 6.267,-25.853 43.481,13.319 -9.01,27.418 C 28.203,15.668 7.867,1.777 0,0"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3229"
+ inkscape:connector-curvature="0" /></g><g
+ id="g3231"
+ transform="translate(211.66052,615.85984)"><path
+ d="m 0,0 -16.243,-2.871 -15.462,-9.4 4.323,-10.938 14.568,9.89 L 2.75,-8.771 0,0 z"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3233"
+ inkscape:connector-curvature="0" /></g><g
+ id="g3235"
+ transform="translate(274.15732,626.4084)"><path
+ d="m 0,0 -15.64,0.407 -14.279,-3.608 2.008,-9.747 14.756,4.208 L 1.111,-8.215 0,0 z"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3237"
+ inkscape:connector-curvature="0" /></g><path
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="M 436.65625 22.28125 C 436.65625 22.28125 338.18375 25.385 251 42.8125 C 163.24875 60.35375 70.40625 99.65625 70.40625 99.65625 L 175.1875 495.28125 L 327.96875 492.34375 L 337.75 527.59375 C 337.75 527.59375 365.095 523.25875 373 518.78125 C 376.31375 516.90375 383.78125 508 383.78125 508 L 377.75 484.65625 L 504.21875 407.15625 L 436.65625 22.28125 z M 410.53125 55.1875 L 465.6875 393.3125 L 346.59375 456.625 L 202.75 466.46875 L 112 114.40625 L 263 79.1875 L 410.53125 55.1875 z "
+ transform="matrix(0.8,0,0,-0.8,0,768)"
+ id="path3253" /><g
+ id="g3247"
+ transform="matrix(1.199238,-0.02879331,0.02673084,1.0520756,172.41935,498.37339)"><path
+ d="m 0,0 c 0,0 -1.861,1.481 -9.143,-1.457 9.712,18.867 9.439,39.989 9.439,39.989 0,0 -3.106,-2.465 -11.311,-8.47 9.241,23.044 5.338,72.525 5.338,72.525 0,0 -17.493,40.746 -13.657,45.799 8.841,11.65 23.834,23.968 44.295,25.594 17.935,1.424 44.606,-4.953 55.865,-15.284 4.536,-4.161 23.367,-47.493 23.367,-47.493 0,0 6.104,-35.271 11.619,-54.108 5.513,-18.839 11.054,-26.674 21.284,-34.825 17.831,-14.207 27.076,-29.938 27.076,-29.938 L 143.399,3.945 c 3.655,-17.356 14.875,-34.28 27.39,-47.672 -12.863,1.507 -19.61,8.783 -19.61,8.783 0,0 2.151,-12.664 9.109,-26.554 l 28.712,15.264 -1.762,10.805 c -5.128,9.304 -9.336,15.534 -9.336,15.534 0,0 2.089,0.956 7.385,-3.572 l -2.005,12.296 c -4.814,9.391 -11.773,16.752 -25.115,31.113 5.944,-6.087 15.438,-5.379 20.751,-4.356 l -0.572,3.512 c -2.231,1.278 -5.494,3.171 -10.241,5.957 -12.43,7.299 -22.326,21.049 -22.326,21.049 0,0 12.85,1.815 20.513,11.022 -7.316,-2.641 -18.585,0.799 -18.585,0.799 -17.086,6.772 -15.022,30.217 -17.687,50.587 -2.667,20.37 -9.299,34.125 -9.299,34.125 0,0 -0.243,2.149 11.91,-5.906 -7.744,33.215 -35.545,44.94 -35.545,44.94 0,0 2.223,2.79 22.843,0.044 -16.469,15.817 -32.303,16.896 -32.303,16.896 0,0 10.077,2.25 23.611,0.24 0,0 -3.327,3.508 -7.549,6.453 L 35.985,194.291 -77.543,167.815 -8.211,-101.17 17.481,-99.413 C 8.602,-85.114 -0.371,-63.837 -2.15,-40.857 -4.911,-5.208 0,0 0,0"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3249"
+ inkscape:connector-curvature="0" /></g><g
+ id="g3255"
+ transform="translate(204.22134,580.88353)"><path
+ d="m 0,0 c 0,-1.418 0.43,-2.736 1.168,-3.83 1.523,0.677 3.551,1.094 5.786,1.094 2.164,0 4.133,-0.39 5.639,-1.029 0.711,1.081 1.129,2.374 1.129,3.765 0,3.79 -3.072,6.861 -6.861,6.861 C 3.071,6.861 0,3.79 0,0"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3257"
+ inkscape:connector-curvature="0" /></g><g
+ id="g3259"
+ transform="translate(256.3311,595.31646)"><path
+ d="m 0,0 c 0,-1.418 0.43,-2.736 1.168,-3.83 1.524,0.677 3.552,1.094 5.787,1.094 2.163,0 4.132,-0.39 5.638,-1.029 0.712,1.081 1.129,2.373 1.129,3.765 0,3.79 -3.072,6.861 -6.861,6.861 C 3.071,6.861 0,3.79 0,0"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3261"
+ inkscape:connector-curvature="0" /></g><g
+ id="g4174"
+ transform="matrix(0.99694509,0.07810563,-0.07810563,0.99694509,47.348748,-15.348299)"><g
+ transform="translate(222.5098,610.1558)"
+ id="g3219"><path
+ inkscape:connector-curvature="0"
+ id="path3221"
+ style="fill:#df0019;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 4.45,2.752 5.34,3.785 7.05,-8.226 7.093,-33.359 17.801,-51.259 13.86,-30.215 26.261,-1.55 -6.685,-35.653 c 0,0 -49.98,-21.871 -49.545,-21.911 -42.657,4.001 -12.553,43.066 -8.631,47.301 L 3.666,-47.869 0,0 z" /></g><g
+ transform="translate(247.626,467.3545)"
+ id="g3239"><path
+ inkscape:connector-curvature="0"
+ id="path3241"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="M 0,0 C -3.044,-0.345 -5.232,-3.092 -4.888,-6.136 -4.543,-9.18 1.576,-2.254 13.308,-4.961 13.971,-1.97 3.044,0.344 0,0" /></g><g
+ transform="translate(279.4419,476.5762)"
+ id="g3243"><path
+ inkscape:connector-curvature="0"
+ id="path3245"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="M 0,0 C 3.271,1.08 6.798,-0.697 7.88,-3.969 8.96,-7.24 -0.55,-3.044 -11.258,-11.329 -13.345,-8.586 -3.272,-1.081 0,0" /></g><g
+ transform="translate(284.1929,525.9082)"
+ id="g3263"><path
+ inkscape:connector-curvature="0"
+ id="path3265"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="M 0,0 C 0,0 -6.972,28.671 -6.972,29.355 L 1.585,2.864 9.999,-10.564 13.634,-32.697 7.922,-11.098 0,0 z M -0.633,-15.036 -9.19,-4.86 -16.478,25.776 c -0.202,0.684 9.106,-28.811 9.106,-28.811 l 8.64,-11.642 2.469,-17.336 -4.37,16.977 z m -6.339,-6.085 -10.457,16.826 -5.444,28.646 6.614,-27.842 11.311,-18.026 1.413,-9.583 -3.437,9.979 z m -53.462,-13.246 -1.437,24.944 -2.682,28.754 5.106,-29.895 1.212,-21.677 4.139,-18.236 -6.338,16.11 z m -4.265,-19.55 -6.665,15.516 0.404,29.205 -0.882,28.169 3.104,-28.396 0.808,-26.697 4.242,-15.972 2.423,-6.617 -3.434,4.792 z m -9.695,-2.967 -7.117,16.885 1.318,32.01 0,25.223 2.115,-25.061 -0.581,-31.259 5.869,-16.429 5.056,-8.671 -6.66,7.302 z m 103.144,-7.97 -6.676,20.38 2.141,11.54 L 16.499,-9.376 4.557,13.104 -5.879,53.97 c 0,0 -8.325,-7.41 -16.781,-8.08 -8.455,-0.671 -15.09,4.018 -15.09,4.018 0,0 3.592,-17.761 8.659,-37.597 5.069,-19.836 17.528,-44.866 17.528,-44.866 0,0 21.578,-8.197 24.302,-16.587 2.724,-8.391 -3.508,-22.911 -14.102,-26.551 -10.593,-3.64 -32.284,-8.262 -32.284,-8.262 0,0 -19,1.512 -20.438,14.26 0,0 4.131,16.406 10.418,19.225 6.285,2.819 21.362,11.174 21.362,11.174 l -8.254,1.332 -7.664,-1.332 c 0,0 -4.784,11.295 -10.973,35.086 -6.19,23.79 -8.967,42.485 -8.967,42.485 0,0 -3.912,-4.391 -14.199,-4.885 -10.286,-0.494 -16.031,7.988 -16.031,7.988 l 1.027,-30.185 -1.049,-25.83 -0.15,-29.22 5.102,-15.99 19.818,-30.448 c 0,0 14.102,-9.293 31.728,-9.293 16.453,1.328 51.131,18.047 51.131,18.047 l 9.536,16.687 z" /></g></g><g
+ id="g3267"
+ transform="translate(847.2637,321.5059)"><path
+ d="m 0,0 c 2.252,3.516 6.693,15.3 6.693,15.3 0,0 3.778,-13.306 1.912,-17.213 -3.056,-6.404 -23.905,-15.3 -23.905,-15.3 0,0 12.196,12.364 15.3,17.213 m -33.514,23.16 -0.757,56.352 c 0,0 11.136,-14.028 11.843,-19.739 1.176,-9.491 -11.086,-36.613 -11.086,-36.613 m -17.575,236.921 c 0,0 12.453,-15.338 14.854,-21.39 1.424,-3.591 2.286,-15.287 2.286,-15.287 l -17.14,36.677 z M -98.574,-86.136 c -9.757,-0.906 -29.836,1.016 -38.912,4.708 -7.499,3.05 -25.734,19.656 -25.734,19.656 l 24.187,-10.86 -4.701,17.627 15.272,-22.009 41.813,-5.356 c 0,0 -8.812,-3.477 -11.925,-3.766 m -74.428,157.941 c -4.518,10.057 -1.763,44.065 -1.763,44.065 0,0 7.544,-31.093 12.338,-40.541 6.978,-13.754 37.015,-49.352 37.015,-49.352 0,0 -40.824,30.759 -47.59,45.828 m -17.833,-149.47 -40.407,24.724 1.636,-17.575 0.026,-0.035 -5.178,-29.811 -2.056,-10.701 0.383,-33.34 -4.982,36.406 6.41,41.45 -11.063,8.338 -17.532,43.159 23.502,-38.779 2.351,14.101 40.634,-25.695 11.924,-5.651 13.809,-28.871 -19.457,22.28 z m -85.522,138.863 17.212,-34.424 c 0,0 -12.972,11.185 -15.299,16.257 -1.905,4.152 -1.913,18.167 -1.913,18.167 m -2.367,66.042 c 0,0 -6.206,15.581 -6.323,21.082 -0.168,7.817 4.568,23.148 7.695,30.315 0.755,1.73 4.103,6.341 4.103,6.341 0,0 -4.654,-24.542 -5.347,-32.829 -0.518,-6.205 -0.128,-24.909 -0.128,-24.909 m -7.195,-114.809 c -0.334,3.363 1.912,13.387 1.912,13.387 l 3.825,-29.643 c 0,0 -5.313,11.967 -5.737,16.256 m -20.082,53.549 c -1.394,3.571 -0.956,15.301 -0.956,15.301 l 13.388,-30.6 c 0,0 -10.639,10.71 -12.432,15.299 m -6.03,106.795 c 0,0 -0.315,35.831 4.637,46.379 4.531,9.647 29.936,30.356 29.936,30.356 0,0 -17.824,-22.47 -21.503,-31.2 -5.089,-12.077 -10.119,-51.437 -10.119,-51.437 l -2.951,5.902 z M 50.121,205.01 c 3.335,-9.155 1.168,-38.956 1.168,-38.956 0,0 -5.451,29.987 -9.221,39.366 -4.214,10.487 -23.014,38.907 -23.014,38.907 0,0 26.78,-27.546 31.067,-39.317 M 54.506,95.624 c 0,0 6.884,-18.586 5.738,-24.861 -0.773,-4.241 -9.562,-14.345 -9.562,-14.345 0,0 2.414,12.874 2.868,17.212 0.573,5.474 0.956,21.994 0.956,21.994 M 19.125,-13.389 c 0,0 9.656,22.183 11.062,30.068 1.235,6.941 0,28.203 0,28.203 0,0 8.477,-22.819 7.106,-30.538 C 35.845,6.183 19.125,-13.389 19.125,-13.389 m 441.487,-40.965 c -3.249,8.935 -6.587,17.23 -10.01,24.928 l -1.862,28.873 -8.857,-4.876 -25.862,49.457 -4.828,-10.34 c -32.69,31.48 -70.457,34.284 -111.982,31.646 -65.568,-4.163 -91.587,-41.63 -79.098,-57.241 12.49,-15.613 18.733,-5.205 40.589,5.203 21.858,10.407 74.937,26.017 110.323,-2.082 35.386,-28.1 86.383,-109.281 50.997,-169.646 -35.386,-60.365 -105.626,-105.385 -182.135,-88.465 -86.422,19.112 -126.078,60.082 -177.675,74.811 -8.311,1.334 -18.347,2.789 -24.791,3.191 -12.671,0.792 -21.6,14.727 -21.6,14.727 l 17.181,-9.327 25.763,-2.36 c 2.331,14 9.395,49.054 9.395,49.054 l -8.688,87.29 -18.668,-27.06 -7.246,10.184 -21.349,-22.915 -15.473,-1.959 14.67,6.596 21.38,29.409 6.7,-13.754 19.485,24.691 0.004,-0.011 16.47,9.525 -3.123,68.69 10.407,-10.407 -4.163,40.59 22.173,71.502 -34.662,91.899 16.652,-4.162 -19.773,35.386 -40.591,38.509 9.368,17.693 -93.671,9.368 -20.229,-7.165 -18.437,38.292 13.22,8.813 -69.039,14.69 2.938,19.095 -80.791,-23.303 -26.147,-19.191 -116.339,0 8.814,-10.188 -42.501,-40.641 -8.911,-78.491 7.344,-1.494 8.814,-45.548 23.502,-24.978 19.096,45.533 -14.689,-4.409 41.13,48.474 30.848,26.44 -14.69,-1.469 19.096,16.158 105.763,2.938 72.917,15.799 -41.623,-14.742 -30.181,-7.285 -104.079,-1.043 1.04,-11.449 -64.526,-61.403 14.571,2.081 -27.844,-63.28 c -15.017,-13.719 -28.06,-55.016 -36.687,-75.145 -9.367,-21.856 -20.816,-39.55 -20.816,-39.55 0,0 -30.182,-6.244 -61.405,-18.734 -31.224,-12.489 -43.713,4.163 -43.713,4.163 l -3.122,-8.326 c 0,0 -18.28,-9.057 -39.303,-11.825 -16.43,-2.162 -9.967,-20.946 -9.613,-26.684 0.405,-6.57 4.294,-19.774 8.325,-24.978 3.227,-4.165 12.525,-10.425 17.694,-11.448 12.039,-2.385 28.101,5.204 45.794,17.693 74.936,-6.245 103.241,-10.321 126.974,8.326 14.572,11.448 29.142,22.897 41.631,40.59 l -15.611,42.671 -8.327,-14.569 -5.807,44.931 1.841,17.863 5.547,-51.234 7.789,9.257 35.387,-70.772 11.448,4.164 c 0,0 13.515,-18.583 23.057,-32.881 l -26.02,25.006 -10.224,-5.964 -11.076,22.152 c 0,0 -13.383,-2.353 -24.727,-18.027 -15.862,-21.915 -23.503,-24.678 -17.627,-78.735 5.876,-54.055 16.452,-54.055 64.632,-121.039 11.752,-16.452 14.601,-18.465 14.601,-18.465 l -51.03,-27.365 -22.327,-5.876 -21.384,-11.28 c 0,0 4.744,-8.174 7.495,-9.369 4.739,-2.062 20.613,1.56 20.613,1.56 0,0 15.603,-6.763 36.756,-6.763 21.152,0 32.903,8.225 47.005,8.225 14.101,0 38.78,-8.225 57.582,-5.876 18.802,2.351 22.328,12.927 22.328,12.927 l -51.706,54.057 -4.675,47.096 -56.605,75.769 -3.038,9.437 65.791,-82.24 5.107,-46.75 55.161,-61.405 37.468,-8.325 c 0,0 -0.257,1.226 -0.625,3.114 -6.146,15.664 -6.986,34.894 -1.999,54.214 6.975,27.012 38.85,36.596 64.029,36.596 12.506,0 24.179,-2.312 32.025,-6.341 12.912,-6.63 21.851,-15.076 27.029,-20.917 3.673,4.516 7.133,7.194 11.833,11.11 0,0 12.143,-11.751 45.047,-14.101 27.14,-1.939 45.048,-8.226 70.901,-19.585 53.676,-23.584 102.5,-61.785 207.618,-45.132 105.119,16.651 206.073,113.444 164.442,227.929"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3269"
+ inkscape:connector-curvature="0" /></g><path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 329.26398,723.3082 -118.025,-19.2 -120.800003,-28.175 72.600003,-281.65 115.075,7.875 95.275,50.65 -44.125,270.5 z m -6.55,-10.575 40.675,-252.4 -87.85,-47.275 -106.125,-7.325 -66.95,262.8 111.4,26.275 108.85,17.925 z"
+ id="path3253-3" /></g></svg> \ No newline at end of file
diff --git a/codemirror_ui/lib/CodeMirror-2.3/doc/compress.html b/codemirror_ui/lib/CodeMirror-2.3/doc/compress.html
new file mode 100644
index 0000000..34c3434
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/doc/compress.html
@@ -0,0 +1,148 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Compression Helper</title>
+ <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold"/>
+ <link rel="stylesheet" type="text/css" href="docs.css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ </head>
+ <body>
+
+<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
+
+<pre class="grey">
+<img src="baboon.png" class="logo" alt="logo"/>/* Script compression
+ helper */
+</pre>
+
+ <p>To optimize loading CodeMirror, especially when including a
+ bunch of different modes, it is recommended that you combine and
+ minify (and preferably also gzip) the scripts. This page makes
+ those first two steps very easy. Simply select the version and
+ scripts you need in the form below, and
+ click <strong>Compress</strong> to download the minified script
+ file.</p>
+
+ <form id="form" action="http://marijnhaverbeke.nl/uglifyjs" method="post">
+ <input type="hidden" id="download" name="download" value="codemirror-compressed.js"/>
+ <p>Version: <select id="version" onchange="setVersion(this);" style="padding: 1px">
+ <option value="http://codemirror.net/">HEAD</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.3;f=">2.3</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.25;f=">2.25</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.24;f=">2.24</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.23;f=">2.23</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.22;f=">2.22</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.21;f=">2.21</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.2;f=">2.2</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.18;f=">2.18</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.16;f=">2.16</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.15;f=">2.15</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.13;f=">2.13</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.12;f=">2.12</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.11;f=">2.11</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.1;f=">2.1</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.02;f=">2.02</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.01;f=">2.01</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.0;f=">2.0</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=beta2;f=">beta2</option>
+ <option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=beta1;f=">beta1</option>
+ </select></p>
+
+ <select multiple="multiple" size="20" name="code_url" style="width: 40em;" class="field" id="files">
+ <optgroup label="CodeMirror Library">
+ <option value="http://codemirror.net/lib/codemirror.js" selected>codemirror.js</option>
+ </optgroup>
+ <optgroup label="Modes">
+ <option value="http://codemirror.net/mode/clike/clike.js">clike.js</option>
+ <option value="http://codemirror.net/mode/clojure/clojure.js">clojure.js</option>
+ <option value="http://codemirror.net/mode/coffeescript/coffeescript.js">coffeescript.js</option>
+ <option value="http://codemirror.net/mode/css/css.js">css.js</option>
+ <option value="http://codemirror.net/mode/diff/diff.js">diff.js</option>
+ <option value="http://codemirror.net/mode/ecl/ecl.js">ecl.js</option>
+ <option value="http://codemirror.net/mode/erlang/erlang.js">erlang.js</option>
+ <option value="http://codemirror.net/mode/gfm/gfm.js">gfm.js</option>
+ <option value="http://codemirror.net/mode/go/go.js">go.js</option>
+ <option value="http://codemirror.net/mode/groovy/groovy.js">groovy.js</option>
+ <option value="http://codemirror.net/mode/haskell/haskell.js">haskell.js</option>
+ <option value="http://codemirror.net/mode/htmlembedded/htmlembedded.js">htmlembedded.js</option>
+ <option value="http://codemirror.net/mode/htmlmixed/htmlmixed.js">htmlmixed.js</option>
+ <option value="http://codemirror.net/mode/javascript/javascript.js">javascript.js</option>
+ <option value="http://codemirror.net/mode/jinja2/jinja2.js">jinja2.js</option>
+ <option value="http://codemirror.net/mode/less/less.js">less.js</option>
+ <option value="http://codemirror.net/mode/lua/lua.js">lua.js</option>
+ <option value="http://codemirror.net/mode/markdown/markdown.js">markdown.js</option>
+ <option value="http://codemirror.net/mode/mysql/mysql.js">mysql.js</option>
+ <option value="http://codemirror.net/mode/ntriples/ntriples.js">ntriples.js</option>
+ <option value="http://codemirror.net/mode/pascal/pascal.js">pascal.js</option>
+ <option value="http://codemirror.net/mode/perl/perl.js">perl.js</option>
+ <option value="http://codemirror.net/mode/php/php.js">php.js</option>
+ <option value="http://codemirror.net/mode/pig/pig.js">pig.js</option>
+ <option value="http://codemirror.net/mode/plsql/plsql.js">plsql.js</option>
+ <option value="http://codemirror.net/mode/properties/properties.js">properties.js</option>
+ <option value="http://codemirror.net/mode/python/python.js">python.js</option>
+ <option value="http://codemirror.net/mode/r/r.js">r.js</option>
+ <option value="http://codemirror.net/mode/rpm/changes/changes.js">rpm/changes.js</option>
+ <option value="http://codemirror.net/mode/rpm/spec/spec.js">rpm/spec.js</option>
+ <option value="http://codemirror.net/mode/rst/rst.js">rst.js</option>
+ <option value="http://codemirror.net/mode/ruby/ruby.js">ruby.js</option>
+ <option value="http://codemirror.net/mode/rust/rust.js">rust.js</option>
+ <option value="http://codemirror.net/mode/scheme/scheme.js">scheme.js</option>
+ <option value="http://codemirror.net/mode/shell/shell.js">shell.js</option>
+ <option value="http://codemirror.net/mode/smalltalk/smalltalk.js">smalltalk.js</option>
+ <option value="http://codemirror.net/mode/smarty/smarty.js">smarty.js</option>
+ <option value="http://codemirror.net/mode/sparql/sparql.js">sparql.js</option>
+ <option value="http://codemirror.net/mode/stex/stex.js">stex.js</option>
+ <option value="http://codemirror.net/mode/tiddlywiki/tiddlywiki.js">tiddlywiki.js</option>
+ <option value="http://codemirror.net/mode/tiki/tiki.js">tiki.js</option>
+ <option value="http://codemirror.net/mode/vbscript/vbscript.js">vbscript.js</option>
+ <option value="http://codemirror.net/mode/velocity/velocity.js">velocity.js</option>
+ <option value="http://codemirror.net/mode/verilog/verilog.js">verilog.js</option>
+ <option value="http://codemirror.net/mode/xml/xml.js">xml.js</option>
+ <option value="http://codemirror.net/mode/xquery/xquery.js">xquery.js</option>
+ <option value="http://codemirror.net/mode/yaml/yaml.js">yaml.js</option>
+ </optgroup>
+ <optgroup label="Utilities and add-ons">
+ <option value="http://codemirror.net/lib/util/overlay.js">overlay.js</option>
+ <option value="http://codemirror.net/lib/util/runmode.js">runmode.js</option>
+ <option value="http://codemirror.net/lib/util/simple-hint.js">simple-hint.js</option>
+ <option value="http://codemirror.net/lib/util/javascript-hint.js">javascript-hint.js</option>
+ <option value="http://codemirror.net/lib/util/foldcode.js">foldcode.js</option>
+ <option value="http://codemirror.net/lib/util/dialog.js">dialog.js</option>
+ <option value="http://codemirror.net/lib/util/search.js">search.js</option>
+ <option value="http://codemirror.net/lib/util/searchcursor.js">searchcursor.js</option>
+ <option value="http://codemirror.net/lib/util/formatting.js">formatting.js</option>
+ <option value="http://codemirror.net/lib/util/match-highlighter.js">match-highlighter.js</option>
+ <option value="http://codemirror.net/lib/util/closetag.js">closetag.js</option>
+ <option value="http://codemirror.net/lib/util/loadmode.js">loadmode.js</option>
+ </optgroup>
+ <optgroup label="Keymaps">
+ <option value="http://codemirror.net/keymap/emacs.js">emacs.js</option>
+ <option value="http://codemirror.net/keymap/vim.js">vim.js</option>
+ </optgroup>
+ </select></p>
+
+ <p>
+ <button type="submit">Compress</button> with <a href="http://github.com/mishoo/UglifyJS/">UglifyJS</a>
+ </p>
+
+ <p>Custom code to add to the compressed file:<textarea name="js_code" style="width: 100%; height: 15em;" class="field"></textarea></p>
+ </form>
+
+ <script type="text/javascript">
+ function setVersion(ver) {
+ var urlprefix = ver.options[ver.selectedIndex].value;
+ var select = document.getElementById("files"), m;
+ for (var optgr = select.firstChild; optgr; optgr = optgr.nextSibling)
+ for (var opt = optgr.firstChild; opt; opt = opt.nextSibling) {
+ if (opt.nodeName != "OPTION")
+ continue;
+ else if (m = opt.value.match(/^http:\/\/codemirror.net\/(.*)$/))
+ opt.value = urlprefix + m[1];
+ else if (m = opt.value.match(/http:\/\/marijnhaverbeke.nl\/git\/codemirror2\?a=blob_plain;hb=[^;]+;f=(.*)$/))
+ opt.value = urlprefix + m[1];
+ }
+ }
+ </script>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/doc/docs.css b/codemirror_ui/lib/CodeMirror-2.3/doc/docs.css
new file mode 100644
index 0000000..9ea1866
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/doc/docs.css
@@ -0,0 +1,154 @@
+body {
+ font-family: Droid Sans, Arial, sans-serif;
+ line-height: 1.5;
+ max-width: 64.3em;
+ margin: 3em auto;
+ padding: 0 1em;
+}
+
+h1 {
+ letter-spacing: -3px;
+ font-size: 3.23em;
+ font-weight: bold;
+ margin: 0;
+}
+
+h2 {
+ font-size: 1.23em;
+ font-weight: bold;
+ margin: .5em 0;
+ letter-spacing: -1px;
+}
+
+h3 {
+ font-size: 1em;
+ font-weight: bold;
+ margin: .4em 0;
+}
+
+pre {
+ background-color: #eee;
+ -moz-border-radius: 6px;
+ -webkit-border-radius: 6px;
+ border-radius: 6px;
+ padding: 1em;
+}
+
+pre.code {
+ margin: 0 1em;
+}
+
+.grey {
+ font-size: 2.2em;
+ padding: .5em 1em;
+ line-height: 1.2em;
+ margin-top: .5em;
+ position: relative;
+}
+
+img.logo {
+ position: absolute;
+ right: -25px;
+ bottom: 4px;
+}
+
+a:link, a:visited, .quasilink {
+ color: #df0019;
+ cursor: pointer;
+ text-decoration: none;
+}
+
+a:hover, .quasilink:hover {
+ color: #800004;
+}
+
+h1 a:link, h1 a:visited, h1 a:hover {
+ color: black;
+}
+
+ul {
+ margin: 0;
+ padding-left: 1.2em;
+}
+
+a.download {
+ color: white;
+ background-color: #df0019;
+ width: 100%;
+ display: block;
+ text-align: center;
+ font-size: 1.23em;
+ font-weight: bold;
+ text-decoration: none;
+ -moz-border-radius: 6px;
+ -webkit-border-radius: 6px;
+ border-radius: 6px;
+ padding: .5em 0;
+ margin-bottom: 1em;
+}
+
+a.download:hover {
+ background-color: #bb0010;
+}
+
+.rel {
+ margin-bottom: 0;
+}
+
+.rel-note {
+ color: #777;
+ font-size: .9em;
+ margin-top: .1em;
+}
+
+.logo-braces {
+ color: #df0019;
+ position: relative;
+ top: -4px;
+}
+
+.blk {
+ float: left;
+}
+
+.left {
+ width: 37em;
+ padding-right: 6.53em;
+ padding-bottom: 1em;
+}
+
+.left1 {
+ width: 15.24em;
+ padding-right: 6.45em;
+}
+
+.left2 {
+ width: 15.24em;
+}
+
+.right {
+ width: 20.68em;
+}
+
+.leftbig {
+ width: 42.44em;
+ padding-right: 6.53em;
+}
+
+.rightsmall {
+ width: 15.24em;
+}
+
+.clear:after {
+ visibility: hidden;
+ display: block;
+ font-size: 0;
+ content: " ";
+ clear: both;
+ height: 0;
+}
+.clear { display: inline-block; }
+/* start commented backslash hack \*/
+* html .clear { height: 1%; }
+.clear { display: block; }
+/* close commented backslash hack */
diff --git a/codemirror_ui/lib/CodeMirror-2.3/doc/internals.html b/codemirror_ui/lib/CodeMirror-2.3/doc/internals.html
new file mode 100644
index 0000000..338c9bb
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/doc/internals.html
@@ -0,0 +1,494 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Internals</title>
+ <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold"/>
+ <link rel="stylesheet" type="text/css" href="docs.css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <style>dl dl {margin: 0;} .update {color: #d40 !important}</style>
+ </head>
+ <body>
+
+<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
+
+<pre class="grey">
+<img src="baboon.png" class="logo" alt="logo"/>/* (Re-) Implementing A Syntax-
+ Highlighting Editor in JavaScript */
+</pre>
+
+<div class="clear"><div class="leftbig blk">
+
+<p style="font-size: 85%" id="intro">
+ <strong>Topic:</strong> JavaScript, code editor implementation<br>
+ <strong>Author:</strong> Marijn Haverbeke<br>
+ <strong>Date:</strong> March 2nd 2011 (updated November 13th 2011)
+</p>
+
+<p>This is a followup to
+my <a href="http://codemirror.net/story.html">Brutal Odyssey to the
+Dark Side of the DOM Tree</a> story. That one describes the
+mind-bending process of implementing (what would become) CodeMirror 1.
+This one describes the internals of CodeMirror 2, a complete rewrite
+and rethink of the old code base. I wanted to give this piece another
+Hunter Thompson copycat subtitle, but somehow that would be out of
+place—the process this time around was one of straightforward
+engineering, requiring no serious mind-bending whatsoever.</p>
+
+<p>So, what is wrong with CodeMirror 1? I'd estimate, by mailing list
+activity and general search-engine presence, that it has been
+integrated into about a thousand systems by now. The most prominent
+one, since a few weeks,
+being <a href="http://googlecode.blogspot.com/2011/01/make-quick-fixes-quicker-on-google.html">Google
+code's project hosting</a>. It works, and it's being used widely.</a>
+
+<p>Still, I did not start replacing it because I was bored. CodeMirror
+1 was heavily reliant on <code>designMode</code>
+or <code>contentEditable</code> (depending on the browser). Neither of
+these are well specified (HTML5 tries
+to <a href="http://www.w3.org/TR/html5/editing.html#contenteditable">specify</a>
+their basics), and, more importantly, they tend to be one of the more
+obscure and buggy areas of browser functionality—CodeMirror, by using
+this functionality in a non-typical way, was constantly running up
+against browser bugs. WebKit wouldn't show an empty line at the end of
+the document, and in some releases would suddenly get unbearably slow.
+Firefox would show the cursor in the wrong place. Internet Explorer
+would insist on linkifying everything that looked like a URL or email
+address, a behaviour that can't be turned off. Some bugs I managed to
+work around (which was often a frustrating, painful process), others,
+such as the Firefox cursor placement, I gave up on, and had to tell
+user after user that they were known problems, but not something I
+could help.</p>
+
+<p>Also, there is the fact that <code>designMode</code> (which seemed
+to be less buggy than <code>contentEditable</code> in Webkit and
+Firefox, and was thus used by CodeMirror 1 in those browsers) requires
+a frame. Frames are another tricky area. It takes some effort to
+prevent getting tripped up by domain restrictions, they don't
+initialize synchronously, behave strangely in response to the back
+button, and, on several browsers, can't be moved around the DOM
+without having them re-initialize. They did provide a very nice way to
+namespace the library, though—CodeMirror 1 could freely pollute the
+namespace inside the frame.</p>
+
+<p>Finally, working with an editable document means working with
+selection in arbitrary DOM structures. Internet Explorer (8 and
+before) has an utterly different (and awkward) selection API than all
+of the other browsers, and even among the different implementations of
+<code>document.selection</code>, details about how exactly a selection
+is represented vary quite a bit. Add to that the fact that Opera's
+selection support tended to be very buggy until recently, and you can
+imagine why CodeMirror 1 contains 700 lines of selection-handling
+code.</p>
+
+<p>And that brings us to the main issue with the CodeMirror 1
+code base: The proportion of browser-bug-workarounds to real
+application code was getting dangerously high. By building on top of a
+few dodgy features, I put the system in a vulnerable position—any
+incompatibility and bugginess in these features, I had to paper over
+with my own code. Not only did I have to do some serious stunt-work to
+get it to work on older browsers (as detailed in the
+previous <a href="http://codemirror.net/story.html">story</a>), things
+also kept breaking in newly released versions, requiring me to come up
+with <em>new</em> scary hacks in order to keep up. This was starting
+to lose its appeal.</p>
+
+<h2 id="approach">General Approach</h2>
+
+<p>What CodeMirror 2 does is try to sidestep most of the hairy hacks
+that came up in version 1. I owe a lot to the
+<a href="http://ace.ajax.org">ACE</a> editor for inspiration on how to
+approach this.</p>
+
+<p>I absolutely did not want to be completely reliant on key events to
+generate my input. Every JavaScript programmer knows that key event
+information is horrible and incomplete. Some people (most awesomely
+Mihai Bazon with <a href="http://ymacs.org">Ymacs</a>) have been able
+to build more or less functioning editors by directly reading key
+events, but it takes a lot of work (the kind of never-ending, fragile
+work I described earlier), and will never be able to properly support
+things like multi-keystoke international character
+input. <a href="#keymap" class="update">[see below for caveat]</a></p>
+
+<p>So what I do is focus a hidden textarea, and let the browser
+believe that the user is typing into that. What we show to the user is
+a DOM structure we built to represent his document. If this is updated
+quickly enough, and shows some kind of believable cursor, it feels
+like a real text-input control.</p>
+
+<p>Another big win is that this DOM representation does not have to
+span the whole document. Some CodeMirror 1 users insisted that they
+needed to put a 30 thousand line XML document into CodeMirror. Putting
+all that into the DOM takes a while, especially since, for some
+reason, an editable DOM tree is slower than a normal one on most
+browsers. If we have full control over what we show, we must only
+ensure that the visible part of the document has been added, and can
+do the rest only when needed. (Fortunately, the <code>onscroll</code>
+event works almost the same on all browsers, and lends itself well to
+displaying things only as they are scrolled into view.)</p>
+
+<h2 id="input">Input</h2>
+
+<p>ACE uses its hidden textarea only as a text input shim, and does
+all cursor movement and things like text deletion itself by directly
+handling key events. CodeMirror's way is to let the browser do its
+thing as much as possible, and not, for example, define its own set of
+key bindings. One way to do this would have been to have the whole
+document inside the hidden textarea, and after each key event update
+the display DOM to reflect what's in that textarea.</p>
+
+<p>That'd be simple, but it is not realistic. For even medium-sized
+document the editor would be constantly munging huge strings, and get
+terribly slow. What CodeMirror 2 does is put the current selection,
+along with an extra line on the top and on the bottom, into the
+textarea.</p>
+
+<p>This means that the arrow keys (and their ctrl-variations), home,
+end, etcetera, do not have to be handled specially. We just read the
+cursor position in the textarea, and update our cursor to match it.
+Also, copy and paste work pretty much for free, and people get their
+native key bindings, without any special work on my part. For example,
+I have emacs key bindings configured for Chrome and Firefox. There is
+no way for a script to detect this. <a class="update"
+href="#keymap">[no longer the case]</a></p>
+
+<p>Of course, since only a small part of the document sits in the
+textarea, keys like page up and ctrl-end won't do the right thing.
+CodeMirror is catching those events and handling them itself.</p>
+
+<h2 id="selection">Selection</h2>
+
+<p>Getting and setting the selection range of a textarea in modern
+browsers is trivial—you just use the <code>selectionStart</code>
+and <code>selectionEnd</code> properties. On IE you have to do some
+insane stuff with temporary ranges and compensating for the fact that
+moving the selection by a 'character' will treat \r\n as a single
+character, but even there it is possible to build functions that
+reliably set and get the selection range.</p>
+
+<p>But consider this typical case: When I'm somewhere in my document,
+press shift, and press the up arrow, something gets selected. Then, if
+I, still holding shift, press the up arrow again, the top of my
+selection is adjusted. The selection remembers where its <em>head</em>
+and its <em>anchor</em> are, and moves the head when we shift-move.
+This is a generally accepted property of selections, and done right by
+every editing component built in the past twenty years.</p>
+
+<p>But not something that the browser selection APIs expose.</p>
+
+<p>Great. So when someone creates an 'upside-down' selection, the next
+time CodeMirror has to update the textarea, it'll re-create the
+selection as an 'upside-up' selection, with the anchor at the top, and
+the next cursor motion will behave in an unexpected way—our second
+up-arrow press in the example above will not do anything, since it is
+interpreted in exactly the same way as the first.</p>
+
+<p>No problem. We'll just, ehm, detect that the selection is
+upside-down (you can tell by the way it was created), and then, when
+an upside-down selection is present, and a cursor-moving key is
+pressed in combination with shift, we quickly collapse the selection
+in the textarea to its start, allow the key to take effect, and then
+combine its new head with its old anchor to get the <em>real</em>
+selection.</p>
+
+<p>In short, scary hacks could not be avoided entirely in CodeMirror
+2.</p>
+
+<p>And, the observant reader might ask, how do you even know that a
+key combo is a cursor-moving combo, if you claim you support any
+native key bindings? Well, we don't, but we can learn. The editor
+keeps a set known cursor-movement combos (initialized to the
+predictable defaults), and updates this set when it observes that
+pressing a certain key had (only) the effect of moving the cursor.
+This, of course, doesn't work if the first time the key is used was
+for extending an inverted selection, but it works most of the
+time.</p>
+
+<h2 id="update">Intelligent Updating</h2>
+
+<p>One thing that always comes up when you have a complicated internal
+state that's reflected in some user-visible external representation
+(in this case, the displayed code and the textarea's content) is
+keeping the two in sync. The naive way is to just update the display
+every time you change your state, but this is not only error prone
+(you'll forget), it also easily leads to duplicate work on big,
+composite operations. Then you start passing around flags indicating
+whether the display should be updated in an attempt to be efficient
+again and, well, at that point you might as well give up completely.</p>
+
+<p>I did go down that road, but then switched to a much simpler model:
+simply keep track of all the things that have been changed during an
+action, and then, only at the end, use this information to update the
+user-visible display.</p>
+
+<p>CodeMirror uses a concept of <em>operations</em>, which start by
+calling a specific set-up function that clears the state and end by
+calling another function that reads this state and does the required
+updating. Most event handlers, and all the user-visible methods that
+change state are wrapped like this. There's a method
+called <code>operation</code> that accepts a function, and returns
+another function that wraps the given function as an operation.</p>
+
+<p>It's trivial to extend this (as CodeMirror does) to detect nesting,
+and, when an operation is started inside an operation, simply
+increment the nesting count, and only do the updating when this count
+reaches zero again.</p>
+
+<p>If we have a set of changed ranges and know the currently shown
+range, we can (with some awkward code to deal with the fact that
+changes can add and remove lines, so we're dealing with a changing
+coordinate system) construct a map of the ranges that were left
+intact. We can then compare this map with the part of the document
+that's currently visible (based on scroll offset and editor height) to
+determine whether something needs to be updated.</p>
+
+<p>CodeMirror uses two update algorithms—a full refresh, where it just
+discards the whole part of the DOM that contains the edited text and
+rebuilds it, and a patch algorithm, where it uses the information
+about changed and intact ranges to update only the out-of-date parts
+of the DOM. When more than 30 percent (which is the current heuristic,
+might change) of the lines need to be updated, the full refresh is
+chosen (since it's faster to do than painstakingly finding and
+updating all the changed lines), in the other case it does the
+patching (so that, if you scroll a line or select another character,
+the whole screen doesn't have to be
+re-rendered). <span class="update">[the full-refresh
+algorithm was dropped, it wasn't really faster than the patching
+one]</span></p>
+
+<p>All updating uses <code>innerHTML</code> rather than direct DOM
+manipulation, since that still seems to be by far the fastest way to
+build documents. There's a per-line function that combines the
+highlighting, <a href="manual.html#markText">marking</a>, and
+selection info for that line into a snippet of HTML. The patch updater
+uses this to reset individual lines, the refresh updater builds an
+HTML chunk for the whole visible document at once, and then uses a
+single <code>innerHTML</code> update to do the refresh.</p>
+
+<h2 id="parse">Parsers can be Simple</h2>
+
+<p>When I wrote CodeMirror 1, I
+thought <a href="http://codemirror.net/story.html#parser">interruptable
+parsers</a> were a hugely scary and complicated thing, and I used a
+bunch of heavyweight abstractions to keep this supposed complexity
+under control: parsers
+were <a href="http://bob.pythonmac.org/archives/2005/07/06/iteration-in-javascript/">iterators</a>
+that consumed input from another iterator, and used funny
+closure-resetting tricks to copy and resume themselves.</p>
+
+<p>This made for a rather nice system, in that parsers formed strictly
+separate modules, and could be composed in predictable ways.
+Unfortunately, it was quite slow (stacking three or four iterators on
+top of each other), and extremely intimidating to people not used to a
+functional programming style.</p>
+
+<p>With a few small changes, however, we can keep all those
+advantages, but simplify the API and make the whole thing less
+indirect and inefficient. CodeMirror
+2's <a href="manual.html#modeapi">mode API</a> uses explicit state
+objects, and makes the parser/tokenizer a function that simply takes a
+state and a character stream abstraction, advances the stream one
+token, and returns the way the token should be styled. This state may
+be copied, optionally in a mode-defined way, in order to be able to
+continue a parse at a given point. Even someone who's never touched a
+lambda in his life can understand this approach. Additionally, far
+fewer objects are allocated in the course of parsing now.</p>
+
+<p>The biggest speedup comes from the fact that the parsing no longer
+has to touch the DOM though. In CodeMirror 1, on an older browser, you
+could <em>see</em> the parser work its way through the document,
+managing some twenty lines in each 50-millisecond time slice it got. It
+was reading its input from the DOM, and updating the DOM as it went
+along, which any experienced JavaScript programmer will immediately
+spot as a recipe for slowness. In CodeMirror 2, the parser usually
+finishes the whole document in a single 100-millisecond time slice—it
+manages some 1500 lines during that time on Chrome. All it has to do
+is munge strings, so there is no real reason for it to be slow
+anymore.</p>
+
+<h2 id="summary">What Gives?</h2>
+
+<p>Given all this, what can you expect from CodeMirror 2?</p>
+
+<ul>
+
+<li><strong>Small.</strong> the base library is
+some <span class="update">45k</span> when minified
+now, <span class="update">17k</span> when gzipped. It's smaller than
+its own logo.</li>
+
+<li><strong>Lightweight.</strong> CodeMirror 2 initializes very
+quickly, and does almost no work when it is not focused. This means
+you can treat it almost like a textarea, have multiple instances on a
+page without trouble.</li>
+
+<li><strong>Huge document support.</strong> Since highlighting is
+really fast, and no DOM structure is being built for non-visible
+content, you don't have to worry about locking up your browser when a
+user enters a megabyte-sized document.</li>
+
+<li><strong>Extended API.</strong> Some things kept coming up in the
+mailing list, such as marking pieces of text or lines, which were
+extremely hard to do with CodeMirror 1. The new version has proper
+support for these built in.</li>
+
+<li><strong>Tab support.</strong> Tabs inside editable documents were,
+for some reason, a no-go. At least six different people announced they
+were going to add tab support to CodeMirror 1, none survived (I mean,
+none delivered a working version). CodeMirror 2 no longer removes tabs
+from your document.</li>
+
+<li><strong>Sane styling.</strong> <code>iframe</code> nodes aren't
+really known for respecting document flow. Now that an editor instance
+is a plain <code>div</code> element, it is much easier to size it to
+fit the surrounding elements. You don't even have to make it scroll if
+you do not <a href="../demo/resize.html">want to</a>.</li>
+
+</ul>
+
+<p>On the downside, a CodeMirror 2 instance is <em>not</em> a native
+editable component. Though it does its best to emulate such a
+component as much as possible, there is functionality that browsers
+just do not allow us to hook into. Doing select-all from the context
+menu, for example, is not currently detected by CodeMirror.</p>
+
+<p id="changes" style="margin-top: 2em;"><span style="font-weight:
+bold">[Updates from November 13th 2011]</span> Recently, I've made
+some changes to the codebase that cause some of the text above to no
+longer be current. I've left the text intact, but added markers at the
+passages that are now inaccurate. The new situation is described
+below.</p>
+
+<h2 id="btree">Content Representation</h2>
+
+<p>The original implementation of CodeMirror 2 represented the
+document as a flat array of line objects. This worked well—splicing
+arrays will require the part of the array after the splice to be
+moved, but this is basically just a simple <code>memmove</code> of a
+bunch of pointers, so it is cheap even for huge documents.</p>
+
+<p>However, I recently added line wrapping and code folding (line
+collapsing, basically). Once lines start taking up a non-constant
+amount of vertical space, looking up a line by vertical position
+(which is needed when someone clicks the document, and to determine
+the visible part of the document during scrolling) can only be done
+with a linear scan through the whole array, summing up line heights as
+you go. Seeing how I've been going out of my way to make big documents
+fast, this is not acceptable.</p>
+
+<p>The new representation is based on a B-tree. The leaves of the tree
+contain arrays of line objects, with a fixed minimum and maximum size,
+and the non-leaf nodes simply hold arrays of child nodes. Each node
+stores both the amount of lines that live below them and the vertical
+space taken up by these lines. This allows the tree to be indexed both
+by line number and by vertical position, and all access has
+logarithmic complexity in relation to the document size.</p>
+
+<p>I gave line objects and tree nodes parent pointers, to the node
+above them. When a line has to update its height, it can simply walk
+these pointers to the top of the tree, adding or subtracting the
+difference in height from each node it encounters. The parent pointers
+also make it cheaper (in complexity terms, the difference is probably
+tiny in normal-sized documents) to find the current line number when
+given a line object. In the old approach, the whole document array had
+to be searched. Now, we can just walk up the tree and count the sizes
+of the nodes coming before us at each level.</p>
+
+<p>I chose B-trees, not regular binary trees, mostly because they
+allow for very fast bulk insertions and deletions. When there is a big
+change to a document, it typically involves adding, deleting, or
+replacing a chunk of subsequent lines. In a regular balanced tree, all
+these inserts or deletes would have to be done separately, which could
+be really expensive. In a B-tree, to insert a chunk, you just walk
+down the tree once to find where it should go, insert them all in one
+shot, and then break up the node if needed. This breaking up might
+involve breaking up nodes further up, but only requires a single pass
+back up the tree. For deletion, I'm somewhat lax in keeping things
+balanced—I just collapse nodes into a leaf when their child count goes
+below a given number. This means that there are some weird editing
+patterns that may result in a seriously unbalanced tree, but even such
+an unbalanced tree will perform well, unless you spend a day making
+strangely repeating edits to a really big document.</p>
+
+<h2 id="keymap">Keymaps</h2>
+
+<p><a href="#approach">Above</a>, I claimed that directly catching key
+events for things like cursor movement is impractical because it
+requires some browser-specific kludges. I then proceeded to explain
+some awful <a href="#selection">hacks</a> that were needed to make it
+possible for the selection changes to be detected through the
+textarea. In fact, the second hack is about as bad as the first.</p>
+
+<p>On top of that, in the presence of user-configurable tab sizes and
+collapsed and wrapped lines, lining up cursor movement in the textarea
+with what's visible on the screen becomes a nightmare. Thus, I've
+decided to move to a model where the textarea's selection is no longer
+depended on.</p>
+
+<p>So I moved to a model where all cursor movement is handled by my
+own code. This adds support for a goal column, proper interaction of
+cursor movement with collapsed lines, and makes it possible for
+vertical movement to move through wrapped lines properly, instead of
+just treating them like non-wrapped lines.</p>
+
+<p>The key event handlers now translate the key event into a string,
+something like <code>Ctrl-Home</code> or <code>Shift-Cmd-R</code>, and
+use that string to look up an action to perform. To make keybinding
+customizable, this lookup goes through
+a <a href="manual.html#option_keyMap">table</a>, using a scheme that
+allows such tables to be chained together (for example, the default
+Mac bindings fall through to a table named 'emacsy', which defines
+basic Emacs-style bindings like <code>Ctrl-F</code>, and which is also
+used by the custom Emacs bindings).</p>
+
+<p>A new
+option <a href="manual.html#option_extraKeys"><code>extraKeys</code></a>
+allows ad-hoc keybindings to be defined in a much nicer way than what
+was possible with the
+old <a href="manual.html#option_onKeyEvent"><code>onKeyEvent</code></a>
+callback. You simply provide an object mapping key identifiers to
+functions, instead of painstakingly looking at raw key events.</p>
+
+<p>Built-in commands map to strings, rather than functions, for
+example <code>"goLineUp"</code> is the default action bound to the up
+arrow key. This allows new keymaps to refer to them without
+duplicating any code. New commands can be defined by assigning to
+the <code>CodeMirror.commands</code> object, which maps such commands
+to functions.</p>
+
+<p>The hidden textarea now only holds the current selection, with no
+extra characters around it. This has a nice advantage: polling for
+input becomes much, much faster. If there's a big selection, this text
+does not have to be read from the textarea every time—when we poll,
+just noticing that something is still selected is enough to tell us
+that no new text was typed.</p>
+
+<p>The reason that cheap polling is important is that many browsers do
+not fire useful events on IME (input method engine) input, which is
+the thing where people inputting a language like Japanese or Chinese
+use multiple keystrokes to create a character or sequence of
+characters. Most modern browsers fire <code>input</code> when the
+composing is finished, but many don't fire anything when the character
+is updated <em>during</em> composition. So we poll, whenever the
+editor is focused, to provide immediate updates of the display.</p>
+
+</div><div class="rightsmall blk">
+
+ <h2>Contents</h2>
+
+ <ul>
+ <li><a href="#intro">Introduction</a></li>
+ <li><a href="#approach">General Approach</a></li>
+ <li><a href="#input">Input</a></li>
+ <li><a href="#selection">Selection</a></li>
+ <li><a href="#update">Intelligent Updating</a></li>
+ <li><a href="#parse">Parsing</a></li>
+ <li><a href="#summary">What Gives?</a></li>
+ <li><a href="#btree">Content Representation</a></li>
+ <li><a href="#keymap">Key Maps</a></li>
+ </ul>
+
+</div></div>
+
+<div style="height: 2em">&nbsp;</div>
+
+</body></html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/doc/manual.html b/codemirror_ui/lib/CodeMirror-2.3/doc/manual.html
new file mode 100644
index 0000000..88b2746
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/doc/manual.html
@@ -0,0 +1,1128 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: User Manual</title>
+ <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold"/>
+ <link rel="stylesheet" type="text/css" href="docs.css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <style>dl dl {margin: 0;}</style>
+ </head>
+ <body>
+
+<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
+
+<pre class="grey">
+<img src="baboon.png" class="logo" alt="logo"/>/* User manual and
+ reference guide */
+</pre>
+
+<div class="clear"><div class="leftbig blk">
+
+ <h2 id="overview">Overview</h2>
+
+ <p>CodeMirror is a code-editor component that can be embedded in
+ Web pages. The code library provides <em>only</em> the editor
+ component, no accompanying buttons, auto-completion, or other IDE
+ functionality. It does provide a rich API on top of which such
+ functionality can be straightforwardly implemented. See
+ the <a href="#addons">add-ons</a> included in the distribution,
+ and
+ the <a href="https://github.com/jagthedrummer/codemirror-ui">CodeMirror
+ UI</a> project, for reusable implementations of extra features.</p>
+
+ <p>CodeMirror works with language-specific modes. Modes are
+ JavaScript programs that help color (and optionally indent) text
+ written in a given language. The distribution comes with a number
+ of modes (see the <code>mode/</code> directory), and it isn't hard
+ to <a href="#modeapi">write new ones</a> for other languages.</p>
+
+ <h2 id="usage">Basic Usage</h2>
+
+ <p>The easiest way to use CodeMirror is to simply load the script
+ and style sheet found under <code>lib/</code> in the distribution,
+ plus a mode script from one of the <code>mode/</code> directories
+ and a theme stylesheet from <code>theme/</code>. (See
+ also <a href="compress.html">the compression helper</a>.) For
+ example:</p>
+
+ <pre>&lt;script src="lib/codemirror.js">&lt;/script>
+&lt;link rel="stylesheet" href="../lib/codemirror.css">
+&lt;script src="mode/javascript/javascript.js">&lt;/script></pre>
+
+ <p>Having done this, an editor instance can be created like
+ this:</p>
+
+ <pre>var myCodeMirror = CodeMirror(document.body);</pre>
+
+ <p>The editor will be appended to the document body, will start
+ empty, and will use the mode that we loaded. To have more control
+ over the new editor, a configuration object can be passed
+ to <code>CodeMirror</code> as a second argument:</p>
+
+ <pre>var myCodeMirror = CodeMirror(document.body, {
+ value: "function myScript(){return 100;}\n",
+ mode: "javascript"
+});</pre>
+
+ <p>This will initialize the editor with a piece of code already in
+ it, and explicitly tell it to use the JavaScript mode (which is
+ useful when multiple modes are loaded).
+ See <a href="#config">below</a> for a full discussion of the
+ configuration options that CodeMirror accepts.</p>
+
+ <p>In cases where you don't want to append the editor to an
+ element, and need more control over the way it is inserted, the
+ first argument to the <code>CodeMirror</code> function can also
+ be a function that, when given a DOM element, inserts it into the
+ document somewhere. This could be used to, for example, replace a
+ textarea with a real editor:</p>
+
+ <pre>var myCodeMirror = CodeMirror(function(elt) {
+ myTextArea.parentNode.replaceChild(elt, myTextArea);
+}, {value: myTextArea.value});</pre>
+
+ <p>However, for this use case, which is a common way to use
+ CodeMirror, the library provides a much more powerful
+ shortcut:</p>
+
+ <pre>var myCodeMirror = CodeMirror.fromTextArea(myTextArea);</pre>
+
+ <p>This will, among other things, ensure that the textarea's value
+ is updated when the form (if it is part of a form) is submitted.
+ See the <a href="#fromTextArea">API reference</a> for a full
+ description of this method.</p>
+
+ <h2 id="config">Configuration</h2>
+
+ <p>Both the <code>CodeMirror</code> function and
+ its <code>fromTextArea</code> method take as second (optional)
+ argument an object containing configuration options. Any option
+ not supplied like this will be taken
+ from <code>CodeMirror.defaults</code>, an object containing the
+ default options. You can update this object to change the defaults
+ on your page.</p>
+
+ <p>Options are not checked in any way, so setting bogus option
+ values is bound to lead to odd errors.</p>
+
+ <p>These are the supported options:</p>
+
+ <dl>
+ <dt id="option_value"><code>value (string)</code></dt>
+ <dd>The starting value of the editor.</dd>
+
+ <dt id="option_mode"><code>mode (string or object)</code></dt>
+ <dd>The mode to use. When not given, this will default to the
+ first mode that was loaded. It may be a string, which either
+ simply names the mode or is
+ a <a href="http://en.wikipedia.org/wiki/MIME">MIME</a> type
+ associated with the mode. Alternatively, it may be an object
+ containing configuration options for the mode, with
+ a <code>name</code> property that names the mode (for
+ example <code>{name: "javascript", json: true}</code>). The demo
+ pages for each mode contain information about what configuration
+ parameters the mode supports. You can ask CodeMirror which modes
+ and MIME types are loaded with
+ the <code>CodeMirror.listModes</code>
+ and <code>CodeMirror.listMIMEs</code> functions.</dd>
+
+ <dt id="option_theme"><code>theme (string)</code></dt>
+ <dd>The theme to style the editor with. You must make sure the
+ CSS file defining the corresponding <code>.cm-s-[name]</code>
+ styles is loaded (see
+ the <a href="../theme/"><code>theme</code></a> directory in the
+ distribution). The default is <code>"default"</code>, for which
+ colors are included in <code>codemirror.css</code>. It is
+ possible to use multiple theming classes at once—for
+ example <code>"foo bar"</code> will assign both
+ the <code>cm-s-foo</code> and the <code>cm-s-bar</code> classes
+ to the editor.</dd>
+
+ <dt id="option_indentUnit"><code>indentUnit (integer)</code></dt>
+ <dd>How many spaces a block (whatever that means in the edited
+ language) should be indented. The default is 2.</dd>
+
+ <dt id="option_smartIndent"><code>smartIndent (boolean)</code></dt>
+ <dd>Whether to use the context-sensitive indentation that the
+ mode provides (or just indent the same as the line before).
+ Defaults to true.</dd>
+
+ <dt id="option_tabSize"><code>tabSize (integer)</code></dt>
+ <dd>The width of a tab character. Defaults to 4.</dd>
+
+ <dt id="option_indentWithTabs"><code>indentWithTabs (boolean)</code></dt>
+ <dd>Whether, when indenting, the first N*<code>tabSize</code>
+ spaces should be replaced by N tabs. Default is false.</dd>
+
+ <dt id="option_electricChars"><code>electricChars (boolean)</code></dt>
+ <dd>Configures whether the editor should re-indent the current
+ line when a character is typed that might change its proper
+ indentation (only works if the mode supports indentation).
+ Default is true.</dd>
+
+ <dt id="option_autoClearEmptyLines"><code>autoClearEmptyLines (boolean)</code></dt>
+ <dd>When turned on (default is off), this will clear
+ automatically clear lines consisting only of whitespace when the
+ cursor leaves them. This is mostly useful to prevent auto
+ indentation from introducing trailing whitespace in a file.</dd>
+
+ <dt id="option_keyMap"><code>keyMap (string)</code></dt>
+ <dd>Configures the keymap to use. The default
+ is <code>"default"</code>, which is the only keymap defined
+ in <code>codemirror.js</code> itself. Extra keymaps are found in
+ the <a href="../keymap/"><code>keymap</code></a> directory. See
+ the <a href="#keymaps">section on keymaps</a> for more
+ information.</dd>
+
+ <dt id="option_extraKeys"><code>extraKeys (object)</code></dt>
+ <dd>Can be used to specify extra keybindings for the editor,
+ alongside the ones defined
+ by <a href="#option_keyMap"><code>keyMap</code></a>. Should be
+ either null, or a valid <a href="#keymaps">keymap</a> value.</dd>
+
+ <dt id="option_lineWrapping"><code>lineWrapping (boolean)</code></dt>
+ <dd>Whether CodeMirror should scroll or wrap for long lines.
+ Defaults to <code>false</code> (scroll).</dd>
+
+ <dt id="option_lineNumbers"><code>lineNumbers (boolean)</code></dt>
+ <dd>Whether to show line numbers to the left of the editor.</dd>
+
+ <dt id="option_firstLineNumber"><code>firstLineNumber (integer)</code></dt>
+ <dd>At which number to start counting lines. Default is 1.</dd>
+
+ <dt id="option_gutter"><code>gutter (boolean)</code></dt>
+ <dd>Can be used to force a 'gutter' (empty space on the left of
+ the editor) to be shown even when no line numbers are active.
+ This is useful for setting <a href="#setMarker">markers</a>.</dd>
+
+ <dt id="option_fixedGutter"><code>fixedGutter (boolean)</code></dt>
+ <dd>When enabled (off by default), this will make the gutter
+ stay visible when the document is scrolled horizontally.</dd>
+
+ <dt id="option_readOnly"><code>readOnly (boolean)</code></dt>
+ <dd>This disables editing of the editor content by the user. If
+ the special value <code>"nocursor"</code> is given (instead of
+ simply <code>true</code>), focusing of the editor is also
+ disallowed.</dd>
+
+ <dt id="option_onChange"><code>onChange (function)</code></dt>
+ <dd>When given, this function will be called every time the
+ content of the editor is changed. It will be given the editor
+ instance as first argument, and an <code>{from, to, text, next}</code>
+ object containing information about the changes
+ that occurred as second argument. <code>from</code>
+ and <code>to</code> are the positions (in the pre-change
+ coordinate system) where the change started and
+ ended (for example, it might be <code>{ch:0, line:18}</code> if the
+ position is at the beginning of line #19). <code>text</code>
+ is an array of strings representing the text that replaced the changed
+ range (split by line). If multiple changes happened during a single
+ operation, the object will have a <code>next</code> property pointing to
+ another change object (which may point to another, etc).</dd>
+
+ <dt id="option_onCursorActivity"><code>onCursorActivity (function)</code></dt>
+ <dd>Will be called when the cursor or selection moves, or any
+ change is made to the editor content.</dd>
+
+ <dt id="option_onGutterClick"><code>onGutterClick (function)</code></dt>
+ <dd>When given, will be called whenever the editor gutter (the
+ line-number area) is clicked. Will be given the editor instance
+ as first argument, the (zero-based) number of the line that was
+ clicked as second argument, and the raw <code>mousedown</code>
+ event object as third argument.</dd>
+
+ <dt id="option_onFocus"><code>onFocus, onBlur (function)</code></dt>
+ <dd>The given functions will be called whenever the editor is
+ focused or unfocused.</dd>
+
+ <dt id="option_onScroll"><code>onScroll (function)</code></dt>
+ <dd>When given, will be called whenever the editor is
+ scrolled.</dd>
+
+ <dt id="option_onHighlightComplete"><code>onHighlightComplete (function)</code></dt>
+ <dd>Whenever the editor's content has been fully highlighted,
+ this function (if given) will be called. It'll be given a single
+ argument, the editor instance.</dd>
+
+ <dt id="option_onUpdate"><code>onUpdate (function)</code></dt>
+ <dd>Will be called whenever CodeMirror updates its DOM display.</dd>
+
+ <dt id="option_matchBrackets"><code>matchBrackets (boolean)</code></dt>
+ <dd>Determines whether brackets are matched whenever the cursor
+ is moved next to a bracket.</dd>
+
+ <dt id="option_workTime"><code>workTime, workDelay (number)</code></dt>
+ <dd>Highlighting is done by a pseudo background-thread that will
+ work for <code>workTime</code> milliseconds, and then use
+ timeout to sleep for <code>workDelay</code> milliseconds. The
+ defaults are 200 and 300, you can change these options to make
+ the highlighting more or less aggressive.</dd>
+
+ <dt id="option_pollInterval"><code>pollInterval (number)</code></dt>
+ <dd>Indicates how quickly CodeMirror should poll its input
+ textarea for changes. Most input is captured by events, but some
+ things, like IME input on some browsers, doesn't generate events
+ that allow CodeMirror to properly detect it. Thus, it polls.
+ Default is 100 milliseconds.</dd>
+
+ <dt id="option_undoDepth"><code>undoDepth (integer)</code></dt>
+ <dd>The maximum number of undo levels that the editor stores.
+ Defaults to 40.</dd>
+
+ <dt id="option_tabindex"><code>tabindex (integer)</code></dt>
+ <dd>The <a href="http://www.w3.org/TR/html401/interact/forms.html#adef-tabindex">tab
+ index</a> to assign to the editor. If not given, no tab index
+ will be assigned.</dd>
+
+ <dt id="option_autofocus"><code>autofocus (boolean)</code></dt>
+ <dd>Can be used to make CodeMirror focus itself on
+ initialization. Defaults to off.
+ When <a href="#fromTextArea"><code>fromTextArea</code></a> is
+ used, and no explicit value is given for this option, it will
+ inherit the setting from the textarea's <code>autofocus</code>
+ attribute.</dd>
+
+ <dt id="option_dragDrop"><code>dragDrop (boolean)</code></dt>
+ <dd>Controls whether drag-and-drop is enabled. On by default.</dd>
+
+ <dt id="option_onDragEvent"><code>onDragEvent (function)</code></dt>
+ <dd>When given, this will be called when the editor is handling
+ a <code>dragenter</code>, <code>dragover</code>,
+ or <code>drop</code> event. It will be passed the editor instance
+ and the event object as arguments. The callback can choose to
+ handle the event itself, in which case it should
+ return <code>true</code> to indicate that CodeMirror should not
+ do anything further.</dd>
+
+ <dt id="option_onKeyEvent"><code>onKeyEvent (function)</code></dt>
+ <dd>This provides a rather low-level hook into CodeMirror's key
+ handling. If provided, this function will be called on
+ every <code>keydown</code>, <code>keyup</code>,
+ and <code>keypress</code> event that CodeMirror captures. It
+ will be passed two arguments, the editor instance and the key
+ event. This key event is pretty much the raw key event, except
+ that a <code>stop()</code> method is always added to it. You
+ could feed it to, for example, <code>jQuery.Event</code> to
+ further normalize it.<br>This function can inspect the key
+ event, and handle it if it wants to. It may return true to tell
+ CodeMirror to ignore the event. Be wary that, on some browsers,
+ stopping a <code>keydown</code> does not stop
+ the <code>keypress</code> from firing, whereas on others it
+ does. If you respond to an event, you should probably inspect
+ its <code>type</code> property and only do something when it
+ is <code>keydown</code> (or <code>keypress</code> for actions
+ that need character data).</dd>
+ </dl>
+
+ <h2 id="keymaps">Keymaps</h2>
+
+ <p>Keymaps are ways to associate keys with functionality. A keymap
+ is an object mapping strings that identify the keys to functions
+ that implement their functionality.</p>
+
+ <p>Keys are identified either by name or by character.
+ The <code>CodeMirror.keyNames</code> object defines names for
+ common keys and associates them with their key codes. Examples of
+ names defined here are <code>Enter</code>, <code>F5</code>,
+ and <code>Q</code>. These can be prefixed
+ with <code>Shift-</code>, <code>Cmd-</code>, <code>Ctrl-</code>,
+ and <code>Alt-</code> (in that order!) to specify a modifier. So
+ for example, <code>Shift-Ctrl-Space</code> would be a valid key
+ identifier.</p>
+
+ <p>Alternatively, a character can be specified directly by
+ surrounding it in single quotes, for example <code>'$'</code>
+ or <code>'q'</code>. Due to limitations in the way browsers fire
+ key events, these may not be prefixed with modifiers.</p>
+
+ <p>The <code>CodeMirror.keyMap</code> object associates keymaps
+ with names. User code and keymap definitions can assign extra
+ properties to this object. Anywhere where a keymap is expected, a
+ string can be given, which will be looked up in this object. It
+ also contains the <code>"default"</code> keymap holding the
+ default bindings.</p>
+
+ <p>The values of properties in keymaps can be either functions of
+ a single argument (the CodeMirror instance), or strings. Such
+ strings refer to properties of the
+ <code>CodeMirror.commands</code> object, which defines a number of
+ common commands that are used by the default keybindings, and maps
+ them to functions. A key handler function may throw
+ <code>CodeMirror.Pass</code> to indicate that it has decided not
+ to handle the key, and other handlers (or the default behavior)
+ should be given a turn.</p>
+
+ <p>Keys mapped to command names that start with the
+ characters <code>"go"</code> (which should be used for
+ cursor-movement actions) will be fired even when an
+ extra <code>Shift</code> modifier is present (i.e. <code>"Up":
+ "goLineUp"</code> matches both up and shift-up). This is used to
+ easily implement shift-selection.</p>
+
+ <p>Keymaps can defer to each other by defining
+ a <code>fallthrough</code> property. This indicates that when a
+ key is not found in the map itself, one or more other maps should
+ be searched. It can hold either a single keymap or an array of
+ keymaps.</p>
+
+ <p>When a keymap contains a <code>nofallthrough</code> property
+ set to <code>true</code>, keys matched against that map will be
+ ignored if they don't match any of the bindings in the map (no
+ further child maps will be tried, and the default effect of
+ inserting a character will not occur).</p>
+
+ <h2 id="styling">Customized Styling</h2>
+
+ <p>Up to a certain extent, CodeMirror's look can be changed by
+ modifying style sheet files. The style sheets supplied by modes
+ simply provide the colors for that mode, and can be adapted in a
+ very straightforward way. To style the editor itself, it is
+ possible to alter or override the styles defined
+ in <a href="../lib/codemirror.css"><code>codemirror.css</code></a>.</p>
+
+ <p>Some care must be taken there, since a lot of the rules in this
+ file are necessary to have CodeMirror function properly. Adjusting
+ colors should be safe, of course, and with some care a lot of
+ other things can be changed as well. The CSS classes defined in
+ this file serve the following roles:</p>
+
+ <dl>
+ <dt id="class_CodeMirror"><code>CodeMirror</code></dt>
+ <dd>The outer element of the editor. This should be used for
+ borders and positioning. Can also be used to set styles that
+ should hold for everything inside the editor (such as font
+ and font size), or to set a background.</dd>
+
+ <dt id="class_CodeMirror_scroll"><code>CodeMirror-scroll</code></dt>
+ <dd>This determines whether the editor scrolls (<code>overflow:
+ auto</code> + fixed height). By default, it does. Giving
+ this <code>height: auto; overflow: visible;</code> will cause
+ the editor to resize to fit its content.</dd>
+
+ <dt id="class_CodeMirror_focused"><code>CodeMirror-focused</code></dt>
+ <dd>Whenever the editor is focused, the top element gets this
+ class. This is used to hide the cursor and give the selection a
+ different color when the editor is not focused.</dd>
+
+ <dt id="class_CodeMirror_gutter"><code>CodeMirror-gutter</code></dt>
+ <dd>Use this for giving a background or a border to the editor
+ gutter. Don't set any padding here,
+ use <code>CodeMirror-gutter-text</code> for that. By default,
+ the gutter is 'fluid', meaning it will adjust its width to the
+ maximum line number or line marker width. You can also set a
+ fixed width if you want.</dd>
+
+ <dt id="class_CodeMirror_gutter_text"><code>CodeMirror-gutter-text</code></dt>
+ <dd>Used to style the actual line numbers. For the numbers to
+ line up, you must make sure that the font in the gutter is the
+ same as the one in the rest of the editor, so you should
+ probably only set font style and size in
+ the <code>CodeMirror</code> class.</dd>
+
+ <dt id="class_CodeMirror_lines"><code>CodeMirror-lines</code></dt>
+ <dd>The visible lines. If this has vertical
+ padding, <code>CodeMirror-gutter</code> should have the same
+ padding.</dd>
+
+ <dt id="class_CodeMirror_cursor"><code>CodeMirror-cursor</code></dt>
+ <dd>The cursor is a block element that is absolutely positioned.
+ You can make it look whichever way you want.</dd>
+
+ <dt id="class_CodeMirror_selected"><code>CodeMirror-selected</code></dt>
+ <dd>The selection is represented by <code>span</code> elements
+ with this class.</dd>
+
+ <dt id="class_CodeMirror_matchingbracket"><code>CodeMirror-matchingbracket</code>,
+ <code>CodeMirror-nonmatchingbracket</code></dt>
+ <dd>These are used to style matched (or unmatched) brackets.</dd>
+ </dl>
+
+ <p>The actual lines, as well as the cursor, are represented
+ by <code>pre</code> elements. By default no text styling (such as
+ bold) that might change line height is applied. If you do want
+ such effects, you'll have to give <code>CodeMirror pre</code> a
+ fixed height.</p>
+
+ <p>If your page's style sheets do funky things to
+ all <code>div</code> or <code>pre</code> elements (you probably
+ shouldn't do that), you'll have to define rules to cancel these
+ effects out again for elements under the <code>CodeMirror</code>
+ class.</p>
+
+ <p>Themes are also simply CSS files, which define colors for
+ various syntactic elements. See the files in
+ the <a href="../theme/"><code>theme</code></a> directory.</p>
+
+ <h2 id="api">Programming API</h2>
+
+ <p>A lot of CodeMirror features are only available through its API.
+ This has the disadvantage that you need to do work to enable them,
+ and the advantage that CodeMirror will fit seamlessly into your
+ application.</p>
+
+ <p>Whenever points in the document are represented, the API uses
+ objects with <code>line</code> and <code>ch</code> properties.
+ Both are zero-based. CodeMirror makes sure to 'clip' any positions
+ passed by client code so that they fit inside the document, so you
+ shouldn't worry too much about sanitizing your coordinates. If you
+ give <code>ch</code> a value of <code>null</code>, or don't
+ specify it, it will be replaced with the length of the specified
+ line.</p>
+
+ <dl>
+ <dt id="getValue"><code>getValue() → string</code></dt>
+ <dd>Get the current editor content.</dd>
+ <dt id="setValue"><code>setValue(string)</code></dt>
+ <dd>Set the editor content.</dd>
+
+ <dt id="getSelection"><code>getSelection() → string</code></dt>
+ <dd>Get the currently selected code.</dd>
+ <dt id="replaceSelection"><code>replaceSelection(string)</code></dt>
+ <dd>Replace the selection with the given string.</dd>
+
+ <dt id="focus"><code>focus()</code></dt>
+ <dd>Give the editor focus.</dd>
+ <dt id="scrollTo"><code>scrollTo(x, y)</code></dt>
+ <dd>Scroll the editor to a given (pixel) position. Both
+ arguments may be left as <code>null</code>
+ or <code>undefined</code> to have no effect.</dd>
+ <dt id="getScrollInfo"><code>getScrollInfo()</code></dt>
+ <dd>Get an <code>{x, y, width, height}</code> object that
+ represents the current scroll position and scrollable area size
+ of the editor.</dd>
+
+ <dt id="setOption"><code>setOption(option, value)</code></dt>
+ <dd>Change the configuration of the editor. <code>option</code>
+ should the name of an <a href="#config">option</a>,
+ and <code>value</code> should be a valid value for that
+ option.</dd>
+ <dt id="getOption"><code>getOption(option) → value</code></dt>
+ <dd>Retrieves the current value of the given option for this
+ editor instance.</dd>
+
+ <dt id="cursorCoords"><code>cursorCoords(start, mode) → object</code></dt>
+ <dd>Returns an <code>{x, y, yBot}</code> object containing the
+ coordinates of the cursor. If <code>mode</code>
+ is <code>"local"</code>, they will be relative to the top-left
+ corner of the editable document. If it is <code>"page"</code> or
+ not given, they are relative to the top-left corner of the
+ page. <code>yBot</code> is the coordinate of the bottom of the
+ cursor. <code>start</code> is a boolean indicating whether you
+ want the start or the end of the selection.</dd>
+ <dt id="charCoords"><code>charCoords(pos, mode) → object</code></dt>
+ <dd>Like <code>cursorCoords</code>, but returns the position of
+ an arbitrary characters. <code>pos</code> should be
+ a <code>{line, ch}</code> object.</dd>
+ <dt id="coordsChar"><code>coordsChar(object) → pos</code></dt>
+ <dd>Given an <code>{x, y}</code> object (in page coordinates),
+ returns the <code>{line, ch}</code> position that corresponds to
+ it.</dd>
+
+ <dt id="undo"><code>undo()</code></dt>
+ <dd>Undo one edit (if any undo events are stored).</dd>
+ <dt id="redo"><code>redo()</code></dt>
+ <dd>Redo one undone edit.</dd>
+ <dt id="historySize"><code>historySize() → object</code></dt>
+ <dd>Returns an object with <code>{undo, redo}</code> properties,
+ both of which hold integers, indicating the amount of stored
+ undo and redo operations.</dd>
+ <dt id="clearHistory"><code>clearHistory()</code></dt>
+ <dd>Clears the editor's undo history.</dd>
+
+ <dt id="indentLine"><code>indentLine(line, dir)</code></dt>
+ <dd>Reset the given line's indentation to the indentation
+ prescribed by the mode. If the second argument is given,
+ indentation will be increased (if <code>dir</code> is true) or
+ decreased (if false) by an <a href="#option_indentUnit">indent
+ unit</a> instead.</dd>
+
+ <dt id="getTokenAt"><code>getTokenAt(pos) → object</code></dt>
+ <dd>Retrieves information about the token the current mode found
+ before the given position (a <code>{line, ch}</code> object). The
+ returned object has the following properties:
+ <dl>
+ <dt><code>start</code></dt><dd>The character (on the given line) at which the token starts.</dd>
+ <dt><code>end</code></dt><dd>The character at which the token ends.</dd>
+ <dt><code>string</code></dt><dd>The token's string.</dd>
+ <dt><code>className</code></dt><dd>The class the mode assigned
+ to the token. (Can be null when no class was assigned.)</dd>
+ <dt><code>state</code></dt><dd>The mode's state at the end of this token.</dd>
+ </dl></dd>
+
+ <dt id="markText"><code>markText(from, to, className) → object</code></dt>
+ <dd>Can be used to mark a range of text with a specific CSS
+ class name. <code>from</code> and <code>to</code> should
+ be <code>{line, ch}</code> objects. The method will return an
+ object with two methods, <code>clear()</code>, which removes the
+ mark, and <code>find()</code>, which returns a <code>{from,
+ to}</code> (both document positions), indicating the current
+ position of the marked range.</dd>
+
+ <dt id="setBookmark"><code>setBookmark(pos) → object</code></dt>
+ <dd>Inserts a bookmark, a handle that follows the text around it
+ as it is being edited, at the given position. A bookmark has two
+ methods <code>find()</code> and <code>clear()</code>. The first
+ returns the current position of the bookmark, if it is still in
+ the document, and the second explicitly removes the
+ bookmark.</dd>
+
+ <dt id="findMarksAt"><code>findMarksAt(pos) → array</code></dt>
+ <dd>Returns an array of all the bookmarks and marked ranges
+ present at the given position.</dd>
+
+ <dt id="setMarker"><code>setMarker(line, text, className) → lineHandle</code></dt>
+ <dd>Add a gutter marker for the given line. Gutter markers are
+ shown in the line-number area (instead of the number for this
+ line). Both <code>text</code> and <code>className</code> are
+ optional. Setting <code>text</code> to a Unicode character like
+ ● tends to give a nice effect. To put a picture in the gutter,
+ set <code>text</code> to a space and <code>className</code> to
+ something that sets a background image. If you
+ specify <code>text</code>, the given text (which may contain
+ HTML) will, by default, replace the line number for that line.
+ If this is not what you want, you can include the
+ string <code>%N%</code> in the text, which will be replaced by
+ the line number.</dd>
+ <dt id="clearMarker"><code>clearMarker(line)</code></dt>
+ <dd>Clears a marker created
+ with <code>setMarker</code>. <code>line</code> can be either a
+ number or a handle returned by <code>setMarker</code> (since a
+ number may now refer to a different line if something was added
+ or deleted).</dd>
+ <dt id="setLineClass"><code>setLineClass(line, className, backgroundClassName) → lineHandle</code></dt>
+ <dd>Set a CSS class name for the given line. <code>line</code>
+ can be a number or a line handle (as returned
+ by <code>setMarker</code> or this
+ function). <code>className</code> will be used to style the text
+ for the line, and <code>backgroundClassName</code> to style its
+ background (which lies behind the selection).
+ Pass <code>null</code> to clear the classes for a line.</dd>
+ <dt id="hideLine"><code>hideLine(line) → lineHandle</code></dt>
+ <dd>Hide the given line (either by number or by handle). Hidden
+ lines don't show up in the editor, and their numbers are skipped
+ when <a href="#option_lineNumbers">line numbers</a> are enabled.
+ Deleting a region around them does delete them, and coping a
+ region around will include them in the copied text.</dd>
+ <dt id="showLine"><code>showLine(line) → lineHandle</code></dt>
+ <dd>The inverse of <code>hideLine</code>—re-shows a previously
+ hidden line, by number or by handle.</dd>
+
+ <dt id="onDeleteLine"><code>onDeleteLine(line, func)</code></dt>
+ <dd>Register a function that should be called when the line is
+ deleted from the document.</dd>
+
+ <dt id="lineInfo"><code>lineInfo(line) → object</code></dt>
+ <dd>Returns the line number, text content, and marker status of
+ the given line, which can be either a number or a handle
+ returned by <code>setMarker</code>. The returned object has the
+ structure <code>{line, handle, text, markerText, markerClass,
+ lineClass, bgClass}</code>.</dd>
+
+ <dt id="getLineHandle"><code>getLineHandle(num) → lineHandle</code></dt>
+ <dd>Fetches the line handle for the given line number.</dd>
+
+ <dt id="addWidget"><code>addWidget(pos, node, scrollIntoView)</code></dt>
+ <dd>Puts <code>node</code>, which should be an absolutely
+ positioned DOM node, into the editor, positioned right below the
+ given <code>{line, ch}</code> position.
+ When <code>scrollIntoView</code> is true, the editor will ensure
+ that the entire node is visible (if possible). To remove the
+ widget again, simply use DOM methods (move it somewhere else, or
+ call <code>removeChild</code> on its parent).</dd>
+
+ <dt id="matchBrackets"><code>matchBrackets()</code></dt>
+ <dd>Force matching-bracket-highlighting to happen.</dd>
+
+ <dt id="lineCount"><code>lineCount() → number</code></dt>
+ <dd>Get the number of lines in the editor.</dd>
+
+ <dt id="getCursor"><code>getCursor(start) → object</code></dt>
+ <dd><code>start</code> is a boolean indicating whether the start
+ or the end of the selection must be retrieved. If it is not
+ given, the current cursor pos, i.e. the side of the selection
+ that would move if you pressed an arrow key, is chosen.
+ A <code>{line, ch}</code> object will be returned.</dd>
+ <dt id="somethingSelected"><code>somethingSelected() → boolean</code></dt>
+ <dd>Return true if any text is selected.</dd>
+ <dt id="setCursor"><code>setCursor(pos)</code></dt>
+ <dd>Set the cursor position. You can either pass a
+ single <code>{line, ch}</code> object, or the line and the
+ character as two separate parameters.</dd>
+ <dt id="setSelection"><code>setSelection(start, end)</code></dt>
+ <dd>Set the selection range. <code>start</code>
+ and <code>end</code> should be <code>{line, ch}</code> objects.</dd>
+
+ <dt id="getLine"><code>getLine(n) → string</code></dt>
+ <dd>Get the content of line <code>n</code>.</dd>
+ <dt id="setLine"><code>setLine(n, text)</code></dt>
+ <dd>Set the content of line <code>n</code>.</dd>
+ <dt id="removeLine"><code>removeLine(n)</code></dt>
+ <dd>Remove the given line from the document.</dd>
+
+ <dt id="getRange"><code>getRange(from, to) → string</code></td>
+ <dd>Get the text between the given points in the editor, which
+ should be <code>{line, ch}</code> objects.</dd>
+ <dt id="replaceRange"><code>replaceRange(string, from, to)</code></dt>
+ <dd>Replace the part of the document between <code>from</code>
+ and <code>to</code> with the given string. <code>from</code>
+ and <code>to</code> must be <code>{line, ch}</code>
+ objects. <code>to</code> can be left off to simply insert the
+ string at position <code>from</code>.</dd>
+
+ <dt id="posFromIndex"><code>posFromIndex(index) → object</code></dt>
+ <dd>Calculates and returns a <code>{line, ch}</code> object for a
+ zero-based <code>index</code> who's value is relative to the start of the
+ editor's text. If the <code>index</code> is out of range of the text then
+ the returned object is clipped to start or end of the text
+ respectively.</dd>
+ <dt id="indexFromPos"><code>indexFromPos(object) → number</code></dt>
+ <dd>The reverse of <a href="#posFromIndex"><code>posFromIndex</code></a>.</dd>
+ </dl>
+
+ <p>The following are more low-level methods:</p>
+
+ <dl>
+ <dt id="operation"><code>operation(func) → result</code></dt>
+ <dd>CodeMirror internally buffers changes and only updates its
+ DOM structure after it has finished performing some operation.
+ If you need to perform a lot of operations on a CodeMirror
+ instance, you can call this method with a function argument. It
+ will call the function, buffering up all changes, and only doing
+ the expensive update after the function returns. This can be a
+ lot faster. The return value from this method will be the return
+ value of your function.</dd>
+
+ <dt id="compoundChange"><code>compoundChange(func) → result</code></dt>
+ <dd>Will call the given function (and return its result),
+ combining all changes made while that function executes into a
+ single undo event.</dd>
+
+ <dt id="refresh"><code>refresh()</code></dt>
+ <dd>If your code does something to change the size of the editor
+ element (window resizes are already listened for), or unhides
+ it, you should probably follow up by calling this method to
+ ensure CodeMirror is still looking as intended.</dd>
+
+ <dt id="getInputField"><code>getInputField() → textarea</code></dt>
+ <dd>Returns the hidden textarea used to read input.</dd>
+ <dt id="getWrapperElement"><code>getWrapperElement() → node</code></dt>
+ <dd>Returns the DOM node that represents the editor. Remove this
+ from your tree to delete an editor instance.</dd>
+ <dt id="getScrollerElement"><code>getScrollerElement() → node</code></dt>
+ <dd>Returns the DOM node that is responsible for the sizing and
+ the scrolling of the editor. You can change
+ the <code>height</code> and <code>width</code> styles of this
+ element to resize an editor. (You might have to call
+ the <a href="#refresh"><code>refresh</code></a> method
+ afterwards.)</dd>
+ <dt id="getGutterElement"><code>getGutterElement() → node</code></dt>
+ <dd>Fetches the DOM node that represents the editor gutter.</dd>
+
+ <dt id="getStateAfter"><code>getStateAfter(line) → state</code></dt>
+ <dd>Returns the mode's parser state, if any, at the end of the
+ given line number. If no line number is given, the state at the
+ end of the document is returned. This can be useful for storing
+ parsing errors in the state, or getting other kinds of
+ contextual information for a line.</dd>
+ </dl>
+
+ <p id="fromTextArea">Finally, the <code>CodeMirror</code> object
+ itself has a method <code>fromTextArea</code>. This takes a
+ textarea DOM node as first argument and an optional configuration
+ object as second. It will replace the textarea with a CodeMirror
+ instance, and wire up the form of that textarea (if any) to make
+ sure the editor contents are put into the textarea when the form
+ is submitted. A CodeMirror instance created this way has two
+ additional methods:</p>
+
+ <dl>
+ <dt id="save"><code>save()</code></dt>
+ <dd>Copy the content of the editor into the textarea.</dd>
+
+ <dt id="toTextArea"><code>toTextArea()</code></dt>
+ <dd>Remove the editor, and restore the original textarea (with
+ the editor's current content).</dd>
+
+ <dt id="getTextArea"><code>getTextArea() → textarea</code></dt>
+ <dd>Returns the textarea that the instance was based on.</dd>
+ </dl>
+
+ <p id="defineExtension">If you want to define extra methods in terms
+ of the CodeMirror API, it is possible to
+ use <code>CodeMirror.defineExtension(name, value)</code>. This
+ will cause the given value (usually a method) to be added to all
+ CodeMirror instances created from then on.</p>
+
+ <h2 id="addons">Add-ons</h2>
+
+ <p>The <code>lib/util</code> directory in the distribution
+ contains a number of reusable components that implement extra
+ editor functionality. In brief, they are:</p>
+
+ <dl>
+ <dt id="util_dialog"><a href="../lib/util/dialog.js"><code>dialog.js</code></a></dt>
+ <dd>Provides a very simple way to query users for text input.
+ Adds an <code>openDialog</code> method to CodeMirror instances,
+ which can be called with an HTML fragment that provides the
+ prompt (should include an <code>input</code> tag), and a
+ callback function that is called when text has been entered.
+ Depends on <code>lib/util/dialog.css</code>.</dd>
+ <dt id="util_searchcursor"><a href="../lib/util/searchcursor.js"><code>searchcursor.js</code></a></dt>
+ <dd>Adds the <code>getSearchCursor(query, start, caseFold) →
+ cursor</code> method to CodeMirror instances, which can be used
+ to implement search/replace functionality. <code>query</code>
+ can be a regular expression or a string (only strings will match
+ across lines—if they contain newlines). <code>start</code>
+ provides the starting position of the search. It can be
+ a <code>{line, ch}</code> object, or can be left off to default
+ to the start of the document. <code>caseFold</code> is only
+ relevant when matching a string. It will cause the search to be
+ case-insensitive. A search cursor has the following methods:
+ <dl>
+ <dt><code>findNext(), findPrevious() → boolean</code></dt>
+ <dd>Search forward or backward from the current position.
+ The return value indicates whether a match was found. If
+ matching a regular expression, the return value will be the
+ array returned by the <code>match</code> method, in case you
+ want to extract matched groups.</dd>
+ <dt><code>from(), to() → object</code></dt>
+ <dd>These are only valid when the last call
+ to <code>findNext</code> or <code>findPrevious</code> did
+ not return false. They will return <code>{line, ch}</code>
+ objects pointing at the start and end of the match.</dd>
+ <dt><code>replace(text)</code></dt>
+ <dd>Replaces the currently found match with the given text
+ and adjusts the cursor position to reflect the
+ replacement.</dd>
+ </dl></dd>
+
+ <dt id="util_search"><a href="../lib/util/search.js"><code>search.js</code></a></dt>
+ <dd>Implements the search commands. CodeMirror has keys bound to
+ these by default, but will not do anything with them unless an
+ implementation is provided. Depends
+ on <code>searchcursor.js</code>, and will make use
+ of <a href="#util_dialog"><code>openDialog</code></a> when
+ available to make prompting for search queries less ugly.</dd>
+ <dt id="util_foldcode"><a href="../lib/util/foldcode.js"><code>foldcode.js</code></a></dt>
+ <dd>Helps with code folding.
+ See <a href="../demo/folding.html">the demo</a> for an example.
+ Call <code>CodeMirror.newFoldFunction</code> with a range-finder
+ helper function to create a function that will, when applied to
+ a CodeMirror instance and a line number, attempt to fold or
+ unfold the block starting at the given line. A range-finder is a
+ language-specific function that also takes an instance and a
+ line number, and returns an end line for the block, or null if
+ no block is started on that line. This file
+ provides <code>CodeMirror.braceRangeFinder</code>, which finds
+ blocks in brace languages (JavaScript, C, Java,
+ etc), <code>CodeMirror.indentRangeFinder</code>, for languages
+ where indentation determines block structure (Python, Haskell),
+ and <code>CodeMirror.tagRangeFinder</code>, for XML-style
+ languages.</dd>
+ <dt id="util_runmode"><a href="../lib/util/runmode.js"><code>runmode.js</code></a></dt>
+ <dd>Can be used to run a CodeMirror mode over text without
+ actually opening an editor instance.
+ See <a href="../demo/runmode.html">the demo</a> for an
+ example.</dd>
+ <dt id="util_overlay"><a href="../lib/util/overlay.js"><code>overlay.js</code></a></dt>
+ <dd>Mode combinator that can be used to extend a mode with an
+ 'overlay' — a secondary mode is run over the stream, along with
+ the base mode, and can color specific pieces of text without
+ interfering with the base mode.
+ Defines <code>CodeMirror.overlayMode</code>, which is used to
+ create such a mode. See <a href="../demo/mustache.html">this
+ demo</a> for a detailed example.</dd>
+ <dt id="util_multiplex"><a href="../lib/util/multiplex.js"><code>multiplex.js</code></a></dt>
+ <dd>Mode combinator that can be used to easily 'multiplex'
+ between several modes.
+ Defines <code>CodeMirror.multiplexingMode</code> which, when
+ given as first argument a mode object, and as other arguments
+ any number of <code>{open, close, mode [, delimStyle]}</code>
+ objects, will return a mode object that starts parsing using the
+ mode passed as first argument, but will switch to another mode
+ as soon as it encounters a string that occurs in one of
+ the <code>open</code> fields of the passed objects. When in a
+ sub-mode, it will go back to the top mode again when
+ the <code>close</code> string is encountered.
+ When <code>delimStyle</code> is specified, it will be the token
+ style returned for the delimiter tokens. The outer mode will not
+ see the content between the delimiters.
+ See <a href="../demo/multiplex.html">this demo</a> for an
+ example.</dd>
+ <dt id="util_simple-hint"><a href="../lib/util/simple-hint.js"><code>simple-hint.js</code></a></dt>
+ <dd>Provides a framework for showing autocompletion hints.
+ Defines <code>CodeMirror.simpleHint</code>, which takes a
+ CodeMirror instance and a hinting function, and pops up a widget
+ that allows the user to select a completion. Hinting functions
+ are function that take an editor instance, and return
+ a <code>{list, from, to}</code> object, where <code>list</code>
+ is an array of strings (the completions), and <code>from</code>
+ and <code>to</code> give the start and end of the token that is
+ being completed. Depends
+ on <code>lib/util/simple-hint.css</code>.</dd>
+ <dt id="util_javascript-hint"><a href="../lib/util/javascript-hint.js"><code>javascript-hint.js</code></a></dt>
+ <dd>Defines <code>CodeMirror.javascriptHint</code>
+ and <code>CodeMirror.coffeescriptHint</code>, which are simple
+ hinting functions for the JavaScript and CoffeeScript
+ modes.</dd>
+ <dt id="util_match-highlighter"><a href="../lib/util/match-highlighter.js"><code>match-highlighter.js</code></a></dt>
+ <dd>Adds a <code>matchHighlight</code> method to CodeMirror
+ instances that can be called (typically from
+ a <a href="#option_onCursorActivity"><code>onCursorActivity</code></a>
+ handler) to highlight all instances of a currently selected word
+ with the a classname given as a first argument to the method.
+ Depends on
+ the <a href="#util_searchcursor"><code>searchcursor</code></a>
+ add-on. Demo <a href="../demo/matchhighlighter.html">here</a>.</dd>
+ <dt id="util_closetag"><a href="../lib/util/closetag.js"><code>closetag.js</code></a></dt>
+ <dd>Provides utility functions for adding automatic tag closing
+ to XML modes. See
+ the <a href="../demo/closetag.html">demo</a>.</dd>
+ <dt id="util_loadmode"><a href="../lib/util/loadmode.js"><code>loadmode.js</code></a></dt>
+ <dd>Defines a <code>CodeMirror.requireMode(modename,
+ callback)</code> function that will try to load a given mode and
+ call the callback when it succeeded. You'll have to
+ set <code>CodeMirror.modeURL</code> to a string that mode paths
+ can be constructed from, for
+ example <code>"mode/%N/%N.js"</code>—the <code>%N</code>'s will
+ be replaced with the mode name. Also
+ defines <code>CodeMirror.autoLoadMode(instance, mode)</code>,
+ which will ensure the given mode is loaded and cause the given
+ editor instance to refresh its mode when the loading
+ succeeded. See the <a href="../demo/loadmode.html">demo</a>.</dd>
+ </dl>
+
+ <h2 id="modeapi">Writing CodeMirror Modes</h2>
+
+ <p>Modes typically consist of a single JavaScript file. This file
+ defines, in the simplest case, a lexer (tokenizer) for your
+ language—a function that takes a character stream as input,
+ advances it past a token, and returns a style for that token. More
+ advanced modes can also handle indentation for the language.</p>
+
+ <p id="defineMode">The mode script should
+ call <code>CodeMirror.defineMode</code> to register itself with
+ CodeMirror. This function takes two arguments. The first should be
+ the name of the mode, for which you should use a lowercase string,
+ preferably one that is also the name of the files that define the
+ mode (i.e. <code>"xml"</code> is defined <code>xml.js</code>). The
+ second argument should be a function that, given a CodeMirror
+ configuration object (the thing passed to
+ the <code>CodeMirror</code> function) and an optional mode
+ configuration object (as in
+ the <a href="#option_mode"><code>mode</code></a> option), returns
+ a mode object.</p>
+
+ <p>Typically, you should use this second argument
+ to <code>defineMode</code> as your module scope function (modes
+ should not leak anything into the global scope!), i.e. write your
+ whole mode inside this function.</p>
+
+ <p>The main responsibility of a mode script is <em>parsing</em>
+ the content of the editor. Depending on the language and the
+ amount of functionality desired, this can be done in really easy
+ or extremely complicated ways. Some parsers can be stateless,
+ meaning that they look at one element (<em>token</em>) of the code
+ at a time, with no memory of what came before. Most, however, will
+ need to remember something. This is done by using a <em>state
+ object</em>, which is an object that is always passed when
+ reading a token, and which can be mutated by the tokenizer.</p>
+
+ <p id="startState">Modes that use a state must define
+ a <code>startState</code> method on their mode object. This is a
+ function of no arguments that produces a state object to be used
+ at the start of a document.</p>
+
+ <p id="token">The most important part of a mode object is
+ its <code>token(stream, state)</code> method. All modes must
+ define this method. It should read one token from the stream it is
+ given as an argument, optionally update its state, and return a
+ style string, or <code>null</code> for tokens that do not have to
+ be styled. For your styles, you can either use the 'standard' ones
+ defined in the themes (without the <code>cm-</code> prefix), or
+ define your own and have people include a custom CSS file for your
+ mode.<p>
+
+ <p id="StringStream">The stream object encapsulates a line of code
+ (tokens may never span lines) and our current position in that
+ line. It has the following API:</p>
+
+ <dl>
+ <dt><code>eol() → boolean</code></dt>
+ <dd>Returns true only if the stream is at the end of the
+ line.</dd>
+ <dt><code>sol() → boolean</code></dt>
+ <dd>Returns true only if the stream is at the start of the
+ line.</dd>
+
+ <dt><code>peek() → character</code></dt>
+ <dd>Returns the next character in the stream without advancing
+ it. Will return <code>undefined</code> at the end of the
+ line.</dd>
+ <dt><code>next() → character</code></dt>
+ <dd>Returns the next character in the stream and advances it.
+ Also returns <code>undefined</code> when no more characters are
+ available.</dd>
+
+ <dt><code>eat(match) → character</code></dt>
+ <dd><code>match</code> can be a character, a regular expression,
+ or a function that takes a character and returns a boolean. If
+ the next character in the stream 'matches' the given argument,
+ it is consumed and returned. Otherwise, <code>undefined</code>
+ is returned.</dd>
+ <dt><code>eatWhile(match) → boolean</code></dt>
+ <dd>Repeatedly calls <code>eat</code> with the given argument,
+ until it fails. Returns true if any characters were eaten.</dd>
+ <dt><code>eatSpace() → boolean</code></dt>
+ <dd>Shortcut for <code>eatWhile</code> when matching
+ white-space.</dd>
+ <dt><code>skipToEnd()</code></dt>
+ <dd>Moves the position to the end of the line.</dd>
+ <dt><code>skipTo(ch) → boolean</code></dt>
+ <dd>Skips to the next occurrence of the given character, if
+ found on the current line (doesn't advance the stream if the
+ character does not occur on the line). Returns true if the
+ character was found.</dd>
+ <dt><code>match(pattern, consume, caseFold) → boolean</code></dt>
+ <dd>Act like a
+ multi-character <code>eat</code>—if <code>consume</code> is true
+ or not given—or a look-ahead that doesn't update the stream
+ position—if it is false. <code>pattern</code> can be either a
+ string or a regular expression starting with <code>^</code>.
+ When it is a string, <code>caseFold</code> can be set to true to
+ make the match case-insensitive. When successfully matching a
+ regular expression, the returned value will be the array
+ returned by <code>match</code>, in case you need to extract
+ matched groups.</dd>
+
+ <dt><code>backUp(n)</code></dt>
+ <dd>Backs up the stream <code>n</code> characters. Backing it up
+ further than the start of the current token will cause things to
+ break, so be careful.</dd>
+ <dt><code>column() → integer</code></dt>
+ <dd>Returns the column (taking into account tabs) at which the
+ current token starts. Can be used to find out whether a token
+ starts a new line.</dd>
+ <dt><code>indentation() → integer</code></dt>
+ <dd>Tells you how far the current line has been indented, in
+ spaces. Corrects for tab characters.</dd>
+
+ <dt><code>current() → string</code></dt>
+ <dd>Get the string between the start of the current token and
+ the current stream position.</dd>
+ </dl>
+
+ <p id="blankLine">By default, blank lines are simply skipped when
+ tokenizing a document. For languages that have significant blank
+ lines, you can define a <code>blankLine(state)</code> method on
+ your mode that will get called whenever a blank line is passed
+ over, so that it can update the parser state.</p>
+
+ <p id="copyState">Because state object are mutated, and CodeMirror
+ needs to keep valid versions of a state around so that it can
+ restart a parse at any line, copies must be made of state objects.
+ The default algorithm used is that a new state object is created,
+ which gets all the properties of the old object. Any properties
+ which hold arrays get a copy of these arrays (since arrays tend to
+ be used as mutable stacks). When this is not correct, for example
+ because a mode mutates non-array properties of its state object, a
+ mode object should define a <code>copyState</code> method,
+ which is given a state and should return a safe copy of that
+ state.</p>
+
+ <p id="compareStates">By default, CodeMirror will stop re-parsing
+ a document as soon as it encounters a few lines that were
+ highlighted the same in the old parse as in the new one. It is
+ possible to provide an explicit way to test whether a state is
+ equivalent to another one, which CodeMirror will use (instead of
+ the unchanged-lines heuristic) to decide when to stop
+ highlighting. You do this by providing
+ a <code>compareStates</code> method on your mode object, which
+ takes two state arguments and returns a boolean indicating whether
+ they are equivalent. See the XML mode, which uses this to provide
+ reliable highlighting of bad closing tags, as an example.</p>
+
+ <p id="indent">If you want your mode to provide smart indentation
+ (though the <a href="#indentLine"><code>indentLine</code></a>
+ method and the <code>indentAuto</code>
+ and <code>newlineAndIndent</code> commands, which keys can be
+ <a href="#option_extraKeys">bound</a> to), you must define
+ an <code>indent(state, textAfter)</code> method on your mode
+ object.</p>
+
+ <p>The indentation method should inspect the given state object,
+ and optionally the <code>textAfter</code> string, which contains
+ the text on the line that is being indented, and return an
+ integer, the amount of spaces to indent. It should usually take
+ the <a href="#option_indentUnit"><code>indentUnit</code></a>
+ option into account.</p>
+
+ <p id="electricChars">Finally, a mode may define
+ an <code>electricChars</code> property, which should hold a string
+ containing all the characters that should trigger the behaviour
+ described for
+ the <a href="#option_electricChars"><code>electricChars</code></a>
+ option.</p>
+
+ <p>So, to summarize, a mode <em>must</em> provide
+ a <code>token</code> method, and it <em>may</em>
+ provide <code>startState</code>, <code>copyState</code>,
+ <code>compareStates</code>, and <code>indent</code> methods. For
+ an example of a trivial mode, see
+ the <a href="../mode/diff/diff.js">diff mode</a>, for a more involved
+ example, see the <a href="../mode/clike/clike.js">C-like
+ mode</a>.</p>
+
+ <p>Sometimes, it is useful for modes to <em>nest</em>—to have one
+ mode delegate work to another mode. An example of this kind of
+ mode is the <a href="../mode/htmlmixed/htmlmixed.js">mixed-mode HTML
+ mode</a>. To implement such nesting, it is usually necessary to
+ create mode objects and copy states yourself. To create a mode
+ object, there are <code>CodeMirror.getMode(options,
+ parserConfig)</code>, where the first argument is a configuration
+ object as passed to the mode constructor function, and the second
+ argument is a mode specification as in
+ the <a href="#option_mode"><code>mode</code></a> option. To copy a
+ state object, call <code>CodeMirror.copyState(mode, state)</code>,
+ where <code>mode</code> is the mode that created the given
+ state.</p>
+
+ <p>To make indentation work properly in a nested parser, it is
+ advisable to give the <code>startState</code> method of modes that
+ are intended to be nested an optional argument that provides the
+ base indentation for the block of code. The JavaScript and CSS
+ parser do this, for example, to allow JavaScript and CSS code
+ inside the mixed-mode HTML mode to be properly indented.</p>
+
+ <p>Finally, it is possible to associate your mode, or a certain
+ configuration of your mode, with
+ a <a href="http://en.wikipedia.org/wiki/MIME">MIME</a> type. For
+ example, the JavaScript mode associates itself
+ with <code>text/javascript</code>, and its JSON variant
+ with <code>application/json</code>. To do this,
+ call <code>CodeMirror.defineMIME(mime, modeSpec)</code>,
+ where <code>modeSpec</code> can be a string or object specifying a
+ mode, as in the <a href="#option_mode"><code>mode</code></a>
+ option.</p>
+
+</div><div class="rightsmall blk">
+
+ <h2>Contents</h2>
+
+ <ul>
+ <li><a href="#overview">Overview</a></li>
+ <li><a href="#usage">Basic Usage</a></li>
+ <li><a href="#config">Configuration</a></li>
+ <li><a href="#keymaps">Keymaps</a></li>
+ <li><a href="#styling">Customized Styling</a></li>
+ <li><a href="#api">Programming API</a></li>
+ <li><a href="#addons">Add-ons</a></li>
+ <li><a href="#modeapi">Writing CodeMirror Modes</a></li>
+ </ul>
+
+</div></div>
+
+<div style="height: 2em">&nbsp;</div>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/doc/oldrelease.html b/codemirror_ui/lib/CodeMirror-2.3/doc/oldrelease.html
new file mode 100644
index 0000000..a659f40
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/doc/oldrelease.html
@@ -0,0 +1,267 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror</title>
+ <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold"/>
+ <link rel="stylesheet" type="text/css" href="docs.css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <link rel="alternate" href="http://twitter.com/statuses/user_timeline/242283288.rss" type="application/rss+xml"/>
+ </head>
+ <body>
+
+<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
+
+<pre class="grey">
+<img src="baboon.png" class="logo" alt="logo"/>/* Old release history */
+
+</pre>
+
+ <p class="rel">26-09-2011: <a href="http://codemirror.net/codemirror-2.15.zip">Version 2.15</a>:</p>
+ <p class="rel-note">Fix bug that snuck into 2.14: Clicking the
+ character that currently has the cursor didn't re-focus the
+ editor.</p>
+
+ <p class="rel">26-09-2011: <a href="http://codemirror.net/codemirror-2.14.zip">Version 2.14</a>:</p>
+ <ul class="rel-note">
+ <li>Add <a href="../mode/clojure/index.html">Clojure</a>, <a href="../mode/pascal/index.html">Pascal</a>, <a href="../mode/ntriples/index.html">NTriples</a>, <a href="../mode/jinja2/index.html">Jinja2</a>, and <a href="../mode/markdown/index.html">Markdown</a> modes.</li>
+ <li>Add <a href="../theme/cobalt.css">Cobalt</a> and <a href="../theme/eclipse.css">Eclipse</a> themes.</li>
+ <li>Add a <a href="manual.html#option_fixedGutter"><code>fixedGutter</code></a> option.</li>
+ <li>Fix bug with <code>setValue</code> breaking cursor movement.</li>
+ <li>Make gutter updates much more efficient.</li>
+ <li>Allow dragging of text out of the editor (on modern browsers).</li>
+ </ul>
+
+
+ <p class="rel">23-08-2011: <a href="http://codemirror.net/codemirror-2.13.zip">Version 2.13</a>:</p>
+ <ul class="rel-note">
+ <li>Add <a href="../mode/ruby/index.html">Ruby</a>, <a href="../mode/r/index.html">R</a>, <a href="../mode/coffeescript/index.html">CoffeeScript</a>, and <a href="../mode/velocity/index.html">Velocity</a> modes.</li>
+ <li>Add <a href="manual.html#getGutterElement"><code>getGutterElement</code></a> to API.</li>
+ <li>Several fixes to scrolling and positioning.</li>
+ <li>Add <a href="manual.html#option_smartHome"><code>smartHome</code></a> option.</li>
+ <li>Add an experimental <a href="../mode/xmlpure/index.html">pure XML</a> mode.</li>
+ </ul>
+
+ <p class="rel">25-07-2011: <a href="http://codemirror.net/codemirror-2.12.zip">Version 2.12</a>:</p>
+ <ul class="rel-note">
+ <li>Add a <a href="../mode/sparql/index.html">SPARQL</a> mode.</li>
+ <li>Fix bug with cursor jumping around in an unfocused editor in IE.</li>
+ <li>Allow key and mouse events to bubble out of the editor. Ignore widget clicks.</li>
+ <li>Solve cursor flakiness after undo/redo.</li>
+ <li>Fix block-reindent ignoring the last few lines.</li>
+ <li>Fix parsing of multi-line attrs in XML mode.</li>
+ <li>Use <code>innerHTML</code> for HTML-escaping.</li>
+ <li>Some fixes to indentation in C-like mode.</li>
+ <li>Shrink horiz scrollbars when long lines removed.</li>
+ <li>Fix width feedback loop bug that caused the width of an inner DIV to shrink.</li>
+ </ul>
+
+ <p class="rel">04-07-2011: <a href="http://codemirror.net/codemirror-2.11.zip">Version 2.11</a>:</p>
+ <ul class="rel-note">
+ <li>Add a <a href="../mode/scheme/index.html">Scheme mode</a>.</li>
+ <li>Add a <code>replace</code> method to search cursors, for cursor-preserving replacements.</li>
+ <li>Make the <a href="../mode/clike/index.html">C-like mode</a> mode more customizable.</li>
+ <li>Update XML mode to spot mismatched tags.</li>
+ <li>Add <code>getStateAfter</code> API and <code>compareState</code> mode API methods for finer-grained mode magic.</li>
+ <li>Add a <code>getScrollerElement</code> API method to manipulate the scrolling DIV.</li>
+ <li>Fix drag-and-drop for Firefox.</li>
+ <li>Add a C# configuration for the <a href="../mode/clike/index.html">C-like mode</a>.</li>
+ <li>Add <a href="../demo/fullscreen.html">full-screen editing</a> and <a href="../demo/changemode.html">mode-changing</a> demos.</li>
+ </ul>
+
+ <p class="rel">07-06-2011: <a href="http://codemirror.net/codemirror-2.1.zip">Version 2.1</a>:</p>
+ <p class="rel-note">Add
+ a <a href="manual.html#option_theme">theme</a> system
+ (<a href="../demo/theme.html">demo</a>). Note that this is not
+ backwards-compatible—you'll have to update your styles and
+ modes!</p>
+
+ <p class="rel">07-06-2011: <a href="http://codemirror.net/codemirror-2.02.zip">Version 2.02</a>:</p>
+ <ul class="rel-note">
+ <li>Add a <a href="../mode/lua/index.html">Lua mode</a>.</li>
+ <li>Fix reverse-searching for a regexp.</li>
+ <li>Empty lines can no longer break highlighting.</li>
+ <li>Rework scrolling model (the outer wrapper no longer does the scrolling).</li>
+ <li>Solve horizontal jittering on long lines.</li>
+ <li>Add <a href="../demo/runmode.html">runmode.js</a>.</li>
+ <li>Immediately re-highlight text when typing.</li>
+ <li>Fix problem with 'sticking' horizontal scrollbar.</li>
+ </ul>
+
+ <p class="rel">26-05-2011: <a href="http://codemirror.net/codemirror-2.01.zip">Version 2.01</a>:</p>
+ <ul class="rel-note">
+ <li>Add a <a href="../mode/smalltalk/index.html">Smalltalk mode</a>.</li>
+ <li>Add a <a href="../mode/rst/index.html">reStructuredText mode</a>.</li>
+ <li>Add a <a href="../mode/python/index.html">Python mode</a>.</li>
+ <li>Add a <a href="../mode/plsql/index.html">PL/SQL mode</a>.</li>
+ <li><code>coordsChar</code> now works</li>
+ <li>Fix a problem where <code>onCursorActivity</code> interfered with <code>onChange</code>.</li>
+ <li>Fix a number of scrolling and mouse-click-position glitches.</li>
+ <li>Pass information about the changed lines to <code>onChange</code>.</li>
+ <li>Support cmd-up/down on OS X.</li>
+ <li>Add triple-click line selection.</li>
+ <li>Don't handle shift when changing the selection through the API.</li>
+ <li>Support <code>"nocursor"</code> mode for <code>readOnly</code> option.</li>
+ <li>Add an <code>onHighlightComplete</code> option.</li>
+ <li>Fix the context menu for Firefox.</li>
+ </ul>
+
+ <p class="rel">28-03-2011: <a href="http://codemirror.net/codemirror-2.0.zip">Version 2.0</a>:</p>
+ <p class="rel-note">CodeMirror 2 is a complete rewrite that's
+ faster, smaller, simpler to use, and less dependent on browser
+ quirks. See <a href="internals.html">this</a>
+ and <a href="http://groups.google.com/group/codemirror/browse_thread/thread/5a8e894024a9f580">this</a>
+ for more information.</a>
+
+ <p class="rel">28-03-2011: <a href="http://codemirror.net/codemirror-1.0.zip">Version 1.0</a>:</p>
+ <ul class="rel-note">
+ <li>Fix error when debug history overflows.</li>
+ <li>Refine handling of C# verbatim strings.</li>
+ <li>Fix some issues with JavaScript indentation.</li>
+ </ul>
+
+ <p class="rel">22-02-2011: <a href="https://github.com/marijnh/codemirror2/tree/beta2">Version 2.0 beta 2</a>:</p>
+ <p class="rel-note">Somewhat more mature API, lots of bugs shaken out.</a>
+
+ <p class="rel">17-02-2011: <a href="http://codemirror.net/codemirror-0.94.zip">Version 0.94</a>:</p>
+ <ul class="rel-note">
+ <li><code>tabMode: "spaces"</code> was modified slightly (now indents when something is selected).</li>
+ <li>Fixes a bug that would cause the selection code to break on some IE versions.</li>
+ <li>Disabling spell-check on WebKit browsers now works.</li>
+ </ul>
+
+ <p class="rel">08-02-2011: <a href="http://codemirror.net/">Version 2.0 beta 1</a>:</p>
+ <p class="rel-note">CodeMirror 2 is a complete rewrite of
+ CodeMirror, no longer depending on an editable frame.</p>
+
+ <p class="rel">19-01-2011: <a href="http://codemirror.net/codemirror-0.93.zip">Version 0.93</a>:</p>
+ <ul class="rel-note">
+ <li>Added a <a href="contrib/regex/index.html">Regular Expression</a> parser.</li>
+ <li>Fixes to the PHP parser.</li>
+ <li>Support for regular expression in search/replace.</li>
+ <li>Add <code>save</code> method to instances created with <code>fromTextArea</code>.</li>
+ <li>Add support for MS T-SQL in the SQL parser.</li>
+ <li>Support use of CSS classes for highlighting brackets.</li>
+ <li>Fix yet another hang with line-numbering in hidden editors.</li>
+ </ul>
+
+ <p class="rel">17-12-2010: <a href="http://codemirror.net/codemirror-0.92.zip">Version 0.92</a>:</p>
+ <ul class="rel-note">
+ <li>Make CodeMirror work in XHTML documents.</li>
+ <li>Fix bug in handling of backslashes in Python strings.</li>
+ <li>The <code>styleNumbers</code> option is now officially
+ supported and documented.</li>
+ <li><code>onLineNumberClick</code> option added.</li>
+ <li>More consistent names <code>onLoad</code> and
+ <code>onCursorActivity</code> callbacks. Old names still work, but
+ are deprecated.</li>
+ <li>Add a <a href="contrib/freemarker/index.html">Freemarker</a> mode.</li>
+ </ul>
+
+ <p class="rel">11-11-2010: <a
+ href="http://codemirror.net/codemirror-0.91.zip">Version 0.91</a>:</p>
+ <ul class="rel-note">
+ <li>Adds support for <a href="contrib/java">Java</a>.</li>
+ <li>Small additions to the <a href="contrib/php">PHP</a> and <a href="contrib/sql">SQL</a> parsers.</li>
+ <li>Work around various <a href="https://bugs.webkit.org/show_bug.cgi?id=47806">Webkit</a> <a href="https://bugs.webkit.org/show_bug.cgi?id=23474">issues</a>.</li>
+ <li>Fix <code>toTextArea</code> to update the code in the textarea.</li>
+ <li>Add a <code>noScriptCaching</code> option (hack to ease development).</li>
+ <li>Make sub-modes of <a href="mixedtest.html">HTML mixed</a> mode configurable.</li>
+ </ul>
+
+ <p class="rel">02-10-2010: <a
+ href="http://codemirror.net/codemirror-0.9.zip">Version 0.9</a>:</p>
+ <ul class="rel-note">
+ <li>Add support for searching backwards.</li>
+ <li>There are now parsers for <a href="contrib/scheme/index.html">Scheme</a>, <a href="contrib/xquery/index.html">XQuery</a>, and <a href="contrib/ometa/index.html">OmetaJS</a>.</li>
+ <li>Makes <code>height: "dynamic"</code> more robust.</li>
+ <li>Fixes bug where paste did not work on OS X.</li>
+ <li>Add a <code>enterMode</code> and <code>electricChars</code> options to make indentation even more customizable.</li>
+ <li>Add <code>firstLineNumber</code> option.</li>
+ <li>Fix bad handling of <code>@media</code> rules by the CSS parser.</li>
+ <li>Take a new, more robust approach to working around the invisible-last-line bug in WebKit.</li>
+ </ul>
+
+ <p class="rel">22-07-2010: <a
+ href="http://codemirror.net/codemirror-0.8.zip">Version 0.8</a>:</p>
+ <ul class="rel-note">
+ <li>Add a <code>cursorCoords</code> method to find the screen
+ coordinates of the cursor.</li>
+ <li>A number of fixes and support for more syntax in the PHP parser.</li>
+ <li>Fix indentation problem with JSON-mode JS parser in Webkit.</li>
+ <li>Add a <a href="compress.html">minification</a> UI.</li>
+ <li>Support a <code>height: dynamic</code> mode, where the editor's
+ height will adjust to the size of its content.</li>
+ <li>Better support for IME input mode.</li>
+ <li>Fix JavaScript parser getting confused when seeing a no-argument
+ function call.</li>
+ <li>Have CSS parser see the difference between selectors and other
+ identifiers.</li>
+ <li>Fix scrolling bug when pasting in a horizontally-scrolled
+ editor.</li>
+ <li>Support <code>toTextArea</code> method in instances created with
+ <code>fromTextArea</code>.</li>
+ <li>Work around new Opera cursor bug that causes the cursor to jump
+ when pressing backspace at the end of a line.</li>
+ </ul>
+
+ <p class="rel">27-04-2010: <a
+ href="http://codemirror.net/codemirror-0.67.zip">Version
+ 0.67</a>:</p>
+ <p class="rel-note">More consistent page-up/page-down behaviour
+ across browsers. Fix some issues with hidden editors looping forever
+ when line-numbers were enabled. Make PHP parser parse
+ <code>"\\"</code> correctly. Have <code>jumpToLine</code> work on
+ line handles, and add <code>cursorLine</code> function to fetch the
+ line handle where the cursor currently is. Add new
+ <code>setStylesheet</code> function to switch style-sheets in a
+ running editor.</p>
+
+ <p class="rel">01-03-2010: <a
+ href="http://codemirror.net/codemirror-0.66.zip">Version
+ 0.66</a>:</p>
+ <p class="rel-note">Adds <code>removeLine</code> method to API.
+ Introduces the <a href="contrib/plsql/index.html">PLSQL parser</a>.
+ Marks XML errors by adding (rather than replacing) a CSS class, so
+ that they can be disabled by modifying their style. Fixes several
+ selection bugs, and a number of small glitches.</p>
+
+ <p class="rel">12-11-2009: <a
+ href="http://codemirror.net/codemirror-0.65.zip">Version
+ 0.65</a>:</p>
+ <p class="rel-note">Add support for having both line-wrapping and
+ line-numbers turned on, make paren-highlighting style customisable
+ (<code>markParen</code> and <code>unmarkParen</code> config
+ options), work around a selection bug that Opera
+ <em>re</em>introduced in version 10.</p>
+
+ <p class="rel">23-10-2009: <a
+ href="http://codemirror.net/codemirror-0.64.zip">Version
+ 0.64</a>:</p>
+ <p class="rel-note">Solves some issues introduced by the
+ paste-handling changes from the previous release. Adds
+ <code>setSpellcheck</code>, <code>setTextWrapping</code>,
+ <code>setIndentUnit</code>, <code>setUndoDepth</code>,
+ <code>setTabMode</code>, and <code>setLineNumbers</code> to
+ customise a running editor. Introduces an <a
+ href="contrib/sql/index.html">SQL</a> parser. Fixes a few small
+ problems in the <a href="contrib/python/index.html">Python</a>
+ parser. And, as usual, add workarounds for various newly discovered
+ browser incompatibilities.</p>
+
+<p class="rel"><em>31-08-2009</em>: <a
+href="http://codemirror.net/codemirror-0.63.zip">Version
+0.63</a>:</p>
+<p class="rel-note"> Overhaul of paste-handling (less fragile), fixes for several
+serious IE8 issues (cursor jumping, end-of-document bugs) and a number
+of small problems.</p>
+
+<p class="rel"><em>30-05-2009</em>: <a
+href="http://codemirror.net/codemirror-0.62.zip">Version
+0.62</a>:</p>
+<p class="rel-note">Introduces <a href="contrib/python/index.html">Python</a>
+and <a href="contrib/lua/index.html">Lua</a> parsers. Add
+<code>setParser</code> (on-the-fly mode changing) and
+<code>clearHistory</code> methods. Make parsing passes time-based
+instead of lines-based (see the <code>passTime</code> option).</p>
+
+</body></html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/doc/reporting.html b/codemirror_ui/lib/CodeMirror-2.3/doc/reporting.html
new file mode 100644
index 0000000..915fa52
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/doc/reporting.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Reporting Bugs</title>
+ <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold"/>
+ <link rel="stylesheet" type="text/css" href="docs.css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <style>li { margin-top: 1em; }</style>
+ </head>
+ <body>
+
+<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
+
+<pre class="grey">
+<img src="baboon.png" class="logo" alt="logo"/>/* Reporting bugs
+ effectively */
+</pre>
+
+<div class="left">
+
+<p>So you found a problem in CodeMirror. By all means, report it! Bug
+reports from users are the main drive behind improvements to
+CodeMirror. But first, please read over these points:</p>
+
+<ol>
+ <li>CodeMirror is maintained by volunteers. They don't owe you
+ anything, so be polite. Reports with an indignant or belligerent
+ tone tend to be moved to the bottom of the pile.</li>
+
+ <li>Include information about <strong>the browser in which the
+ problem occurred</strong>. Even if you tested several browsers, and
+ the problem occurred in all of them, mention this fact in the bug
+ report. Also include browser version numbers and the operating
+ system that you're on.</li>
+
+ <li>Mention which release of CodeMirror you're using. Preferably,
+ try also with the current development snapshot, to ensure the
+ problem has not already been fixed.</li>
+
+ <li>Mention very precisely what went wrong. "X is broken" is not a
+ good bug report. What did you expect to happen? What happened
+ instead? Describe the exact steps a maintainer has to take to make
+ the problem occur. We can not fix something that we can not
+ observe.</li>
+
+ <li>If the problem can not be reproduced in any of the demos
+ included in the CodeMirror distribution, please provide an HTML
+ document that demonstrates the problem. The best way to do this is
+ to go to <a href="http://jsbin.com/ihunin/edit">jsbin.com</a>, enter
+ it there, press save, and include the resulting link in your bug
+ report.</li>
+</ol>
+
+</div>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/doc/upgrade_v2.2.html b/codemirror_ui/lib/CodeMirror-2.3/doc/upgrade_v2.2.html
new file mode 100644
index 0000000..a6d0236
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/doc/upgrade_v2.2.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Upgrading to v2.2</title>
+ <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold"/>
+ <link rel="stylesheet" type="text/css" href="docs.css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ </head>
+ <body>
+
+<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
+
+<pre class="grey">
+<img src="baboon.png" class="logo" alt="logo"/>/* Upgrading to v2.2
+ */
+</pre>
+
+<div class="left">
+
+<p>There are a few things in the 2.2 release that require some care
+when upgrading.</p>
+
+<h2>No more default.css</h2>
+
+<p>The default theme is now included
+in <a href="../lib/codemirror.css"><code>codemirror.css</code></a>, so
+you do not have to included it separately anymore. (It was tiny, so
+even if you're not using it, the extra data overhead is negligible.)
+
+<h2>Different key customization</h2>
+
+<p>CodeMirror has moved to a system
+where <a href="manual.html#option_keyMap">keymaps</a> are used to
+bind behavior to keys. This means <a href="../demo/emacs.html">custom
+bindings</a> are now possible.</p>
+
+<p>Three options that influenced key
+behavior, <code>tabMode</code>, <code>enterMode</code>,
+and <code>smartHome</code>, are no longer supported. Instead, you can
+provide custom bindings to influence the way these keys act. This is
+done through the
+new <a href="manual.html#option_extraKeys"><code>extraKeys</code></a>
+option, which can hold an object mapping key names to functionality. A
+simple example would be:</p>
+
+<pre> extraKeys: {
+ "Ctrl-S": function(instance) { saveText(instance.getValue()); },
+ "Ctrl-/": "undo"
+ }</pre>
+
+<p>Keys can be mapped either to functions, which will be given the
+editor instance as argument, or to strings, which are mapped through
+functions through the <code>CodeMirror.commands</code> table, which
+contains all the built-in editing commands, and can be inspected and
+extended by external code.</p>
+
+<p>By default, the <code>Home</code> key is bound to
+the <code>"goLineStartSmart"</code> command, which moves the cursor to
+the first non-whitespace character on the line. You can set do this to
+make it always go to the very start instead:</p>
+
+<pre> extraKeys: {"Home": "goLineStart"}</pre>
+
+<p>Similarly, <code>Enter</code> is bound
+to <code>"newlineAndIndent"</code> by default. You can bind it to
+something else to get different behavior. To disable special handling
+completely and only get a newline character inserted, you can bind it
+to <code>false</code>:</p>
+
+<pre> extraKeys: {"Enter": false}</pre>
+
+<p>The same works for <code>Tab</code>. If you don't want CodeMirror
+to handle it, bind it to <code>false</code>. The default behaviour is
+to indent the current line more (<code>"indentMore"</code> command),
+and indent it less when shift is held (<code>"indentLess"</code>).
+There are also <code>"indentAuto"</code> (smart indent)
+and <code>"insertTab"</code> commands provided for alternate
+behaviors. Or you can write your own handler function to do something
+different altogether.</p>
+
+<h2>Tabs</h2>
+
+<p>Handling of tabs changed completely. The display width of tabs can
+now be set with the <code>tabSize</code> option, and tabs can
+be <a href="../demo/visibletabs.html">styled</a> by setting CSS rules
+for the <code>cm-tab</code> class.</p>
+
+<p>The default width for tabs is now 4, as opposed to the 8 that is
+hard-wired into browsers. If you are relying on 8-space tabs, make
+sure you explicitly set <code>tabSize: 8</code> in your options.</p>
+
+</div>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/index.html b/codemirror_ui/lib/CodeMirror-2.3/index.html
new file mode 100644
index 0000000..3d53518
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/index.html
@@ -0,0 +1,417 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror</title>
+ <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold"/>
+ <link rel="stylesheet" type="text/css" href="doc/docs.css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <link rel="alternate" href="http://twitter.com/statuses/user_timeline/242283288.rss" type="application/rss+xml"/>
+ </head>
+ <body>
+
+<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
+
+<pre class="grey">
+<img src="doc/baboon.png" class="logo" alt="logo"/>/* In-browser code editing
+ made bearable */
+</pre>
+
+<div class="clear"><div class="left blk">
+
+ <p style="margin-top: 0">CodeMirror is a JavaScript component that
+ provides a code editor in the browser. When a mode is available for
+ the language you are coding in, it will color your code, and
+ optionally help with indentation.</p>
+
+ <p>A <a href="doc/manual.html">rich programming API</a> and a CSS
+ theming system are available for customizing CodeMirror to fit your
+ application, and extending it with new functionality.</p>
+
+ <div class="clear"><div class="left1 blk">
+
+ <h2 style="margin-top: 0">Supported modes:</h2>
+
+ <ul>
+ <li><a href="mode/clike/index.html">C, C++, C#</a></li>
+ <li><a href="mode/clojure/index.html">Clojure</a></li>
+ <li><a href="mode/coffeescript/index.html">CoffeeScript</a></li>
+ <li><a href="mode/css/index.html">CSS</a></li>
+ <li><a href="mode/diff/index.html">diff</a></li>
+ <li><a href="mode/ecl/index.html">ECL</a></li>
+ <li><a href="mode/erlang/index.html">Erlang</a></li>
+ <li><a href="mode/go/index.html">Go</a></li>
+ <li><a href="mode/groovy/index.html">Groovy</a></li>
+ <li><a href="mode/haskell/index.html">Haskell</a></li>
+ <li><a href="mode/htmlembedded/index.html">HTML embedded scripts</a></li>
+ <li><a href="mode/htmlmixed/index.html">HTML mixed-mode</a></li>
+ <li><a href="mode/clike/index.html">Java</a></li>
+ <li><a href="mode/javascript/index.html">JavaScript</a></li>
+ <li><a href="mode/jinja2/index.html">Jinja2</a></li>
+ <li><a href="mode/less/index.html">LESS</a></li>
+ <li><a href="mode/lua/index.html">Lua</a></li>
+ <li><a href="mode/markdown/index.html">Markdown</a> (<a href="mode/gfm/index.html">Github-flavour</a>)</li>
+ <li><a href="mode/mysql/index.html">MySQL</a></li>
+ <li><a href="mode/ntriples/index.html">NTriples</a></li>
+ <li><a href="mode/pascal/index.html">Pascal</a></li>
+ <li><a href="mode/perl/index.html">Perl</a></li>
+ <li><a href="mode/php/index.html">PHP</a></li>
+ <li><a href="mode/pig/index.html">Pig Latin</a></li>
+ <li><a href="mode/plsql/index.html">PL/SQL</a></li>
+ <li><a href="mode/properties/index.html">Properties files</a></li>
+ <li><a href="mode/python/index.html">Python</a></li>
+ <li><a href="mode/r/index.html">R</a></li>
+ <li>RPM <a href="mode/rpm/spec/index.html">spec</a> and <a href="mode/rpm/changes/index.html">changelog</a></li>
+ <li><a href="mode/rst/index.html">reStructuredText</a></li>
+ <li><a href="mode/ruby/index.html">Ruby</a></li>
+ <li><a href="mode/rust/index.html">Rust</a></li>
+ <li><a href="mode/clike/scala.html">Scala</a></li>
+ <li><a href="mode/scheme/index.html">Scheme</a></li>
+ <li><a href="mode/shell/index.html">Shell</a></li>
+ <li><a href="mode/smalltalk/index.html">Smalltalk</a></li>
+ <li><a href="mode/smarty/index.html">Smarty</a></li>
+ <li><a href="mode/sparql/index.html">SPARQL</a></li>
+ <li><a href="mode/stex/index.html">sTeX, LaTeX</a></li>
+ <li><a href="mode/tiddlywiki/index.html">Tiddlywiki</a></li>
+ <li><a href="mode/tiki/index.html">Tiki wiki</a></li>
+ <li><a href="mode/vbscript/index.html">VBScript</a></li>
+ <li><a href="mode/velocity/index.html">Velocity</a></li>
+ <li><a href="mode/verilog/index.html">Verilog</a></li>
+ <li><a href="mode/xml/index.html">XML/HTML</a></li>
+ <li><a href="mode/xquery/index.html">XQuery</a></li>
+ <li><a href="mode/yaml/index.html">YAML</a></li>
+ </ul>
+
+ </div><div class="left2 blk">
+
+ <h2 style="margin-top: 0">Usage demos:</h2>
+
+ <ul>
+ <li><a href="demo/complete.html">Autocompletion</a></li>
+ <li><a href="demo/mustache.html">Mode overlays</a></li>
+ <li><a href="demo/search.html">Search/replace</a></li>
+ <li><a href="demo/folding.html">Code folding</a></li>
+ <li><a href="demo/preview.html">HTML editor with preview</a></li>
+ <li><a href="demo/resize.html">Auto-resizing editor</a></li>
+ <li><a href="demo/marker.html">Setting breakpoints</a></li>
+ <li><a href="demo/activeline.html">Highlighting the current line</a></li>
+ <li><a href="demo/matchhighlighter.html">Highlighting selection matches</a></li>
+ <li><a href="demo/theme.html">Theming</a></li>
+ <li><a href="demo/runmode.html">Stand-alone highlighting</a></li>
+ <li><a href="demo/fullscreen.html">Full-screen editing</a></li>
+ <li><a href="demo/changemode.html">Mode auto-changing</a></li>
+ <li><a href="demo/visibletabs.html">Visible tabs</a></li>
+ <li><a href="demo/formatting.html">Autoformatting of code</a></li>
+ <li><a href="demo/emacs.html">Emacs keybindings</a></li>
+ <li><a href="demo/vim.html">Vim keybindings</a></li>
+ <li><a href="demo/closetag.html">Automatic xml tag closing</a></li>
+ <li><a href="demo/loadmode.html">Lazy mode loading</a></li>
+ </ul>
+
+ <h2>Real-world uses:</h2>
+
+ <ul>
+ <li><a href="http://jsbin.com">jsbin.com</a> (JS playground)</li>
+ <li><a href="http://buzzard.ups.edu/">Sage demo</a> (math system)</li>
+ <li><a href="http://www.sourcelair.com/">sourceLair</a> (online IDE)</li>
+ <li><a href="http://eloquentjavascript.net/chapter1.html">Eloquent JavaScript</a> (book)</a></li>
+ <li><a href="http://www.mergely.com/">Mergely</a> (interactive diffing)</li>
+ <li><a href="http://paperjs.org/">Paper.js</a> (graphics scripting)</li>
+ <li><a href="http://www.wescheme.org/">WeScheme</a> (learning tool)</li>
+ <li><a href="http://webglplayground.net/">WebGL playground</a></li>
+ <li><a href="http://ql.io/">ql.io</a> (http API query helper)</li>
+ <li><a href="http://elm-lang.org/Examples.elm">Elm language examples</a></li>
+ <li><a href="http://bluegriffon.org/">BlueGriffon</a> (HTML editor)</li>
+ <li><a href="http://www.jshint.com/">JSHint</a> (JS linter)</li>
+ <li><a href="http://kl1p.com/cmtest/1">kl1p</a> (paste service)</li>
+ <li><a href="http://sqlfiddle.com">SQLFiddle</a> (SQL playground)</li>
+ <li><a href="http://tour.golang.org">Go language tour</a></li>
+ <li><a href="http://cssdeck.com/">CSSDeck</a> (CSS showcase)</li>
+ <li><a href="http://www.ckwnc.com/">CKWNC</a> (UML editor)</li>
+ <li><a href="http://www.sketchpatch.net/labs/livecodelabIntro.html">sketchPatch Livecodelab</a></li>
+ <li><a href="https://thefiletree.com">The File Tree</a> (collab editor)</li>
+ <li><a href="http://enjalot.com/tributary/2636296/sinwaves.js">Tributary</a> (augmented editing)</li>
+ </ul>
+
+ </div></div>
+
+ <h2 id="code">Getting the code</h2>
+
+ <p>All of CodeMirror is released under a <a
+ href="LICENSE">MIT-style</a> license. To get it, you can download
+ the <a href="http://codemirror.net/codemirror.zip">latest
+ release</a> or the current <a
+ href="http://codemirror.net/codemirror2-latest.zip">development
+ snapshot</a> as zip files. To create a custom minified script file,
+ you can use the <a href="doc/compress.html">compression API</a>.</p>
+
+ <p>We use <a href="http://git-scm.com/">git</a> for version control.
+ The main repository can be fetched in this way:</p>
+
+ <pre class="code">git clone http://marijnhaverbeke.nl/git/codemirror2</pre>
+
+ <p>CodeMirror can also be found on GitHub at <a
+ href="http://github.com/marijnh/CodeMirror2">marijnh/CodeMirror2</a>.
+ If you plan to hack on the code and contribute patches, the best way
+ to do it is to create a GitHub fork, and send pull requests.</p>
+
+ <h2 id="documention">Documentation</h2>
+
+ <p>The <a href="doc/manual.html">manual</a> is your first stop for
+ learning how to use this library. It starts with a quick explanation
+ of how to use the editor, and then describes the API in detail.</p>
+
+ <p>For those who want to learn more about the code, there is
+ an <a href="doc/internals.html">overview of the internals</a> available.
+ The <a href="http://github.com/marijnh/CodeMirror2">source code</a>
+ itself is, for the most part, also well commented.</p>
+
+ <h2 id="support">Support and bug reports</h2>
+
+ <p>There is
+ a <a href="http://groups.google.com/group/codemirror">Google
+ group</a> (a sort of mailing list/newsgroup thing) for discussion
+ and news related to CodeMirror. When reporting a bug,
+ <a href="doc/reporting.html">read this first</a>. If you have
+ a <a href="http://github.com">github</a> account,
+ simply <a href="http://github.com/marijnh/CodeMirror2/issues">open
+ an issue there</a>. Otherwise, post something to
+ the <a href="http://groups.google.com/group/codemirror">group</a>,
+ or e-mail me directly: <a href="mailto:marijnh@gmail.com">Marijn
+ Haverbeke</a>.</p>
+
+ <h2 id="supported">Supported browsers</h2>
+
+ <p>The following browsers are able to run CodeMirror:</p>
+
+ <ul>
+ <li>Firefox 2 or higher</li>
+ <li>Chrome, any version</li>
+ <li>Safari 3 or higher</li>
+ <li>Internet Explorer 7 or higher in standards (<strong>non-quirks</strong>) mode</li>
+ <li>Opera 9 or higher (with some key-handling problems on OS X)</li>
+ </ul>
+
+ <p>I am not actively testing against every new browser release, and
+ vendors have a habit of introducing bugs all the time, so I am
+ relying on the community to tell me when something breaks.
+ See <a href="#support">here</a> for information on how to contact
+ me.</p>
+
+ <h2 id="commercial">Commercial support</h2>
+
+ <p>CodeMirror is developed and maintained by me, Marijn Haverbeke,
+ in my own time. If your company is getting value out of CodeMirror,
+ please consider purchasing a support contract.</p>
+
+ <ul>
+ <li>You'll be funding further work on CodeMirror.</li>
+ <li>You ensure that you get a quick response when you have a
+ problem, even when I am otherwise busy.</li>
+ </ul>
+
+ <p>CodeMirror support contracts exist in two
+ forms—<strong>basic</strong> at €100 per month,
+ and <strong>premium</strong> at €500 per
+ month. <a href="mailto:marijnh@gmail.com">Contact me</a> for further
+ information.</p>
+
+</div>
+
+<div class="right blk">
+
+ <a href="http://codemirror.net/codemirror.zip" class="download">Download the latest release</a>
+
+ <h2>Support CodeMirror</h2>
+
+ <ul>
+ <li>Donate
+ (<span onclick="document.getElementById('paypal').submit();"
+ class="quasilink">Paypal</span>
+ or <span onclick="document.getElementById('bankinfo').style.display = 'block';"
+ class="quasilink">bank</span>)</li>
+ <li>Purchase <a href="#commercial">commercial support</a></li>
+ </ul>
+
+ <p id="bankinfo" style="display: none;">
+ Bank: <i>Rabobank</i><br/>
+ Country: <i>Netherlands</i><br/>
+ SWIFT: <i>RABONL2U</i><br/>
+ Account: <i>147850770</i><br/>
+ Name: <i>Marijn Haverbeke</i><br/>
+ IBAN: <i>NL26 RABO 0147 8507 70</i>
+ </p>
+
+ <h2>Reading material</h2>
+
+ <ul>
+ <li><a href="doc/manual.html">User manual</a></li>
+ <li><a href="http://github.com/marijnh/CodeMirror2">Browse the code</a></li>
+ </ul>
+
+ <h2>Releases</h2>
+
+ <p class="rel">22-06-2012: <a href="http://codemirror.net/codemirror-2.3.zip">Version 2.3</a>:</p>
+
+ <ul class="rel-note">
+ <li><strong>New scrollbar implementation</strong>. Should flicker less. Changes DOM structure of the editor.</li>
+ <li>New theme: <a href="demo/theme.html?vibrant-ink">vibrant-ink</a>.</li>
+ <li>Many extensions to the VIM keymap (including text objects).</li>
+ <li>Add <a href="demo/multiplex.html">mode-multiplexing</a> utility script.</li>
+ <li>Fix bug where right-click paste works in read-only mode.</li>
+ <li>Add a <a href="doc/manual.html#getScrollInfo"><code>getScrollInfo</code></a> method.</li>
+ <li>Lots of other <a href="https://github.com/marijnh/CodeMirror2/compare/v2.25...v2.3">fixes</a>.</li>
+ </ul>
+
+ <p class="rel">23-05-2012: <a href="http://codemirror.net/codemirror-2.25.zip">Version 2.25</a>:</p>
+
+ <ul class="rel-note">
+ <li>New mode: <a href="mode/erlang/index.html">Erlang</a>.</li>
+ <li><strong>Remove xmlpure mode</strong> (use <a href="mode/xml/index.html">xml.js</a>).</li>
+ <li>Fix line-wrapping in Opera.</li>
+ <li>Fix X Windows middle-click paste in Chrome.</li>
+ <li>Fix bug that broke pasting of huge documents.</li>
+ <li>Fix backspace and tab key repeat in Opera.</li>
+ </ul>
+
+ <p class="rel">23-04-2012: <a href="http://codemirror.net/codemirror-2.24.zip">Version 2.24</a>:</p>
+
+ <ul class="rel-note">
+ <li><strong>Drop support for Internet Explorer 6</strong>.</li>
+ <li>New
+ modes: <a href="mode/shell/index.html">Shell</a>, <a href="mode/tiki/index.html">Tiki
+ wiki</a>, <a href="mode/pig/index.html">Pig Latin</a>.</li>
+ <li>New themes: <a href="demo/theme.html?ambiance">Ambiance</a>, <a href="demo/theme.html?blackboard">Blackboard</a>.</li>
+ <li>More control over drag/drop
+ with <a href="doc/manual.html#option_dragDrop"><code>dragDrop</code></a>
+ and <a href="doc/manual.html#option_onDragEvent"><code>onDragEvent</code></a>
+ options.</li>
+ <li>Make HTML mode a bit less pedantic.</li>
+ <li>Add <a href="doc/manual.html#compoundChange"><code>compoundChange</code></a> API method.</li>
+ <li>Several fixes in undo history and line hiding.</li>
+ <li>Remove (broken) support for <code>catchall</code> in key maps,
+ add <code>nofallthrough</code> boolean field instead.</li>
+ </ul>
+
+ <p class="rel">26-03-2012: <a href="http://codemirror.net/codemirror-2.23.zip">Version 2.23</a>:</p>
+
+ <ul class="rel-note">
+ <li>Change <strong>default binding for tab</strong> <a href="javascript:void(document.getElementById('tabbinding').style.display='')">[more]</a>
+ <div style="display: none" id=tabbinding>
+ Starting in 2.23, these bindings are default:
+ <ul><li>Tab: Insert tab character</li>
+ <li>Shift-tab: Reset line indentation to default</li>
+ <li>Ctrl/Cmd-[: Reduce line indentation (old tab behaviour)</li>
+ <li>Ctrl/Cmd-]: Increase line indentation (old shift-tab behaviour)</li>
+ </ul>
+ </div>
+ </li>
+ <li>New modes: <a href="mode/xquery/index.html">XQuery</a> and <a href="mode/vbscript/index.html">VBScript</a>.</li>
+ <li>Two new themes: <a href="mode/less/index.html">lesser-dark</a> and <a href="mode/xquery/index.html">xq-dark</a>.</li>
+ <li>Differentiate between background and text styles in <a href="doc/manual.html#setLineClass"><code>setLineClass</code></a>.</li>
+ <li>Fix drag-and-drop in IE9+.</li>
+ <li>Extend <a href="doc/manual.html#charCoords"><code>charCoords</code></a>
+ and <a href="doc/manual.html#cursorCoords"><code>cursorCoords</code></a> with a <code>mode</code> argument.</li>
+ <li>Add <a href="doc/manual.html#option_autofocus"><code>autofocus</code></a> option.</li>
+ <li>Add <a href="doc/manual.html#findMarksAt"><code>findMarksAt</code></a> method.</li>
+ </ul>
+
+ <p class="rel">27-02-2012: <a href="http://codemirror.net/codemirror-2.22.zip">Version 2.22</a>:</p>
+
+ <ul class="rel-note">
+ <li>Allow <a href="doc/manual.html#keymaps">key handlers</a> to pass up events, allow binding characters.</li>
+ <li>Add <a href="doc/manual.html#option_autoClearEmptyLines"><code>autoClearEmptyLines</code></a> option.</li>
+ <li>Properly use tab stops when rendering tabs.</li>
+ <li>Make PHP mode more robust.</li>
+ <li>Support indentation blocks in <a href="doc/manual.html#util_foldcode">code folder</a>.</li>
+ <li>Add a script for <a href="doc/manual.html#util_match-highlighter">highlighting instances of the selection</a>.</li>
+ <li>New <a href="mode/properties/index.html">.properties</a> mode.</li>
+ <li>Fix many bugs.</li>
+ </ul>
+
+ <p class="rel">27-01-2012: <a href="http://codemirror.net/codemirror-2.21.zip">Version 2.21</a>:</p>
+
+ <ul class="rel-note">
+ <li>Added <a href="mode/less/index.html">LESS</a>, <a href="mode/mysql/index.html">MySQL</a>,
+ <a href="mode/go/index.html">Go</a>, and <a href="mode/verilog/index.html">Verilog</a> modes.</li>
+ <li>Add <a href="doc/manual.html#option_smartIndent"><code>smartIndent</code></a>
+ option.</li>
+ <li>Support a cursor in <a href="doc/manual.html#option_readOnly"><code>readOnly</code></a>-mode.</li>
+ <li>Support assigning multiple styles to a token.</li>
+ <li>Use a new approach to drawing the selection.</li>
+ <li>Add <a href="doc/manual.html#scrollTo"><code>scrollTo</code></a> method.</li>
+ <li>Allow undo/redo events to span non-adjacent lines.</li>
+ <li>Lots and lots of bugfixes.</li>
+ </ul>
+
+ <p class="rel">20-12-2011: <a href="http://codemirror.net/codemirror-2.2.zip">Version 2.2</a>:</p>
+
+ <ul class="rel-note">
+ <li>Slightly incompatible API changes. Read <a href="doc/upgrade_v2.2.html">this</a>.</li>
+ <li>New approach
+ to <a href="doc/manual.html#option_extraKeys">binding</a> keys,
+ support for <a href="doc/manual.html#option_keyMap">custom
+ bindings</a>.</li>
+ <li>Support for overwrite (insert).</li>
+ <li><a href="doc/manual.html#option_tabSize">Custom-width</a>
+ and <a href="demo/visibletabs.html">stylable</a> tabs.</li>
+ <li>Moved more code into <a href="doc/manual.html#addons">add-on scripts</a>.</li>
+ <li>Support for sane vertical cursor movement in wrapped lines.</li>
+ <li>More reliable handling of
+ editing <a href="doc/manual.html#markText">marked text</a>.</li>
+ <li>Add minimal <a href="demo/emacs.html">emacs</a>
+ and <a href="demo/vim.html">vim</a> bindings.</li>
+ <li>Rename <code>coordsFromIndex</code>
+ to <a href="doc/manual.html#posFromIndex"><code>posFromIndex</code></a>,
+ add <a href="doc/manual.html#indexFromPos"><code>indexFromPos</code></a>
+ method.</li>
+ </ul>
+
+ <p class="rel">21-11-2011: <a href="http://codemirror.net/codemirror-2.18.zip">Version 2.18</a>:</p>
+ <p class="rel-note">Fixes <code>TextMarker.clear</code>, which is broken in 2.17.</p>
+
+ <p class="rel">21-11-2011: <a href="http://codemirror.net/codemirror-2.17.zip">Version 2.17</a>:</p>
+ <ul class="rel-note">
+ <li>Add support for <a href="doc/manual.html#option_lineWrapping">line
+ wrapping</a> and <a href="doc/manual.html#hideLine">code
+ folding</a>.</li>
+ <li>Add <a href="mode/gfm/index.html">Github-style Markdown</a> mode.</li>
+ <li>Add <a href="theme/monokai.css">Monokai</a>
+ and <a href="theme/rubyblue.css">Rubyblue</a> themes.</li>
+ <li>Add <a href="doc/manual.html#setBookmark"><code>setBookmark</code></a> method.</li>
+ <li>Move some of the demo code into reusable components
+ under <a href="lib/util/"><code>lib/util</code></a>.</li>
+ <li>Make screen-coord-finding code faster and more reliable.</li>
+ <li>Fix drag-and-drop in Firefox.</li>
+ <li>Improve support for IME.</li>
+ <li>Speed up content rendering.</li>
+ <li>Fix browser's built-in search in Webkit.</li>
+ <li>Make double- and triple-click work in IE.</li>
+ <li>Various fixes to modes.</li>
+ </ul>
+
+ <p class="rel">27-10-2011: <a href="http://codemirror.net/codemirror-2.16.zip">Version 2.16</a>:</p>
+ <ul class="rel-note">
+ <li>Add <a href="mode/perl/index.html">Perl</a>, <a href="mode/rust/index.html">Rust</a>, <a href="mode/tiddlywiki/index.html">TiddlyWiki</a>, and <a href="mode/groovy/index.html">Groovy</a> modes.</li>
+ <li>Dragging text inside the editor now moves, rather than copies.</li>
+ <li>Add a <a href="doc/manual.html#coordsFromIndex"><code>coordsFromIndex</code></a> method.</li>
+ <li><strong>API change</strong>: <code>setValue</code> now no longer clears history. Use <a href="doc/manual.html#clearHistory"><code>clearHistory</code></a> for that.</li>
+ <li><strong>API change</strong>: <a href="doc/manual.html#markText"><code>markText</code></a> now
+ returns an object with <code>clear</code> and <code>find</code>
+ methods. Marked text is now more robust when edited.</li>
+ <li>Fix editing code with tabs in Internet Explorer.</li>
+ </ul>
+
+ <p><a href="doc/oldrelease.html">Older releases...</a></p>
+
+</div></div>
+
+<div style="height: 2em">&nbsp;</div>
+
+ <form action="https://www.paypal.com/cgi-bin/webscr" method="post" id="paypal">
+ <input type="hidden" name="cmd" value="_s-xclick"/>
+ <input type="hidden" name="hosted_button_id" value="3FVHS5FGUY7CC"/>
+ </form>
+
+ </body>
+</html>
+
diff --git a/codemirror_ui/lib/CodeMirror-2.3/keymap/emacs.js b/codemirror_ui/lib/CodeMirror-2.3/keymap/emacs.js
new file mode 100644
index 0000000..2a57e2f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/keymap/emacs.js
@@ -0,0 +1,29 @@
+// TODO number prefixes
+(function() {
+ // Really primitive kill-ring implementation.
+ var killRing = [];
+ function addToRing(str) {
+ killRing.push(str);
+ if (killRing.length > 50) killRing.shift();
+ }
+ function getFromRing() { return killRing[killRing.length - 1] || ""; }
+ function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); }
+
+ CodeMirror.keyMap.emacs = {
+ "Ctrl-X": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-X");},
+ "Ctrl-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
+ "Ctrl-Alt-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
+ "Alt-W": function(cm) {addToRing(cm.getSelection());},
+ "Ctrl-Y": function(cm) {cm.replaceSelection(getFromRing());},
+ "Alt-Y": function(cm) {cm.replaceSelection(popFromRing());},
+ "Ctrl-/": "undo", "Shift-Ctrl--": "undo", "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
+ "Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": "clearSearch", "Shift-Alt-5": "replace",
+ "Ctrl-Z": "undo", "Cmd-Z": "undo", "Alt-/": "autocomplete",
+ fallthrough: ["basic", "emacsy"]
+ };
+
+ CodeMirror.keyMap["emacs-Ctrl-X"] = {
+ "Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": "undo", "K": "close",
+ auto: "emacs", nofallthrough: true
+ };
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/keymap/vim.js b/codemirror_ui/lib/CodeMirror-2.3/keymap/vim.js
new file mode 100644
index 0000000..2aa6e0f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/keymap/vim.js
@@ -0,0 +1,766 @@
+// Supported keybindings:
+//
+// Cursor movement:
+// h, j, k, l
+// e, E, w, W, b, B
+// Ctrl-f, Ctrl-b
+// Ctrl-n, Ctrl-p
+// $, ^, 0
+// G
+// ge, gE
+// gg
+// f<char>, F<char>, t<char>, T<char>
+// Ctrl-o, Ctrl-i TODO (FIXME - Ctrl-O wont work in Chrome)
+// /, ?, n, N TODO (does not work)
+// #, * TODO
+//
+// Entering insert mode:
+// i, I, a, A, o, O
+// s
+// ce, cb (without support for number of actions like c3e - TODO)
+// cc
+// S, C TODO
+// cf<char>, cF<char>, ct<char>, cT<char>
+//
+// Deleting text:
+// x, X
+// J
+// dd, D
+// de, db (without support for number of actions like d3e - TODO)
+// df<char>, dF<char>, dt<char>, dT<char>
+//
+// Yanking and pasting:
+// yy, Y
+// p, P
+// p'<char> TODO - test
+// y'<char> TODO - test
+// m<char> TODO - test
+//
+// Changing text in place:
+// ~
+// r<char>
+//
+// Visual mode:
+// v, V TODO
+//
+// Misc:
+// . TODO
+//
+
+(function() {
+ var count = "";
+ var sdir = "f";
+ var buf = "";
+ var yank = 0;
+ var mark = [];
+ var reptTimes = 0;
+ function emptyBuffer() { buf = ""; }
+ function pushInBuffer(str) { buf += str; }
+ function pushCountDigit(digit) { return function(cm) {count += digit;}; }
+ function popCount() { var i = parseInt(count, 10); count = ""; return i || 1; }
+ function iterTimes(func) {
+ for (var i = 0, c = popCount(); i < c; ++i) func(i, i == c - 1);
+ }
+ function countTimes(func) {
+ if (typeof func == "string") func = CodeMirror.commands[func];
+ return function(cm) { iterTimes(function () { func(cm); }); };
+ }
+
+ function iterObj(o, f) {
+ for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]);
+ }
+ function iterList(l, f) {
+ for (var i in l) f(l[i]);
+ }
+ function toLetter(ch) {
+ // T -> t, Shift-T -> T, '*' -> *, "Space" -> " "
+ if (ch.slice(0, 6) == "Shift-") {
+ return ch.slice(0, 1);
+ } else {
+ if (ch == "Space") return " ";
+ if (ch.length == 3 && ch[0] == "'" && ch[2] == "'") return ch[1];
+ return ch.toLowerCase();
+ }
+ }
+ var SPECIAL_SYMBOLS = "~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;\"\'1234567890";
+ function toCombo(ch) {
+ // t -> T, T -> Shift-T, * -> '*', " " -> "Space"
+ if (ch == " ") return "Space";
+ var specialIdx = SPECIAL_SYMBOLS.indexOf(ch);
+ if (specialIdx != -1) return "'" + ch + "'";
+ if (ch.toLowerCase() == ch) return ch.toUpperCase();
+ return "Shift-" + ch.toUpperCase();
+ }
+
+ var word = [/\w/, /[^\w\s]/], bigWord = [/\S/];
+ function findWord(line, pos, dir, regexps) {
+ var stop = 0, next = -1;
+ if (dir > 0) { stop = line.length; next = 0; }
+ var start = stop, end = stop;
+ // Find bounds of next one.
+ outer: for (; pos != stop; pos += dir) {
+ for (var i = 0; i < regexps.length; ++i) {
+ if (regexps[i].test(line.charAt(pos + next))) {
+ start = pos;
+ for (; pos != stop; pos += dir) {
+ if (!regexps[i].test(line.charAt(pos + next))) break;
+ }
+ end = pos;
+ break outer;
+ }
+ }
+ }
+ return {from: Math.min(start, end), to: Math.max(start, end)};
+ }
+ function moveToWord(cm, regexps, dir, times, where) {
+ var cur = cm.getCursor();
+
+ for (var i = 0; i < times; i++) {
+ var line = cm.getLine(cur.line), startCh = cur.ch, word;
+ while (true) {
+ // If we're at start/end of line, start on prev/next respectivly
+ if (cur.ch == line.length && dir > 0) {
+ cur.line++;
+ cur.ch = 0;
+ line = cm.getLine(cur.line);
+ } else if (cur.ch == 0 && dir < 0) {
+ cur.line--;
+ cur.ch = line.length;
+ line = cm.getLine(cur.line);
+ }
+ if (!line) break;
+
+ // On to the actual searching
+ word = findWord(line, cur.ch, dir, regexps);
+ cur.ch = word[where == "end" ? "to" : "from"];
+ if (startCh == cur.ch && word.from != word.to) cur.ch = word[dir < 0 ? "from" : "to"];
+ else break;
+ }
+ }
+ return cur;
+ }
+ function joinLineNext(cm) {
+ var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line);
+ CodeMirror.commands.goLineEnd(cm);
+ if (cur.line != cm.lineCount()) {
+ CodeMirror.commands.goLineEnd(cm);
+ cm.replaceSelection(" ", "end");
+ CodeMirror.commands.delCharRight(cm);
+ }
+ }
+ function delTillMark(cm, cHar) {
+ var i = mark[cHar];
+ if (i === undefined) {
+ // console.log("Mark not set"); // TODO - show in status bar
+ return;
+ }
+ var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
+ cm.setCursor(start);
+ for (var c = start; c <= end; c++) {
+ pushInBuffer("\n"+cm.getLine(start));
+ cm.removeLine(start);
+ }
+ }
+ function yankTillMark(cm, cHar) {
+ var i = mark[cHar];
+ if (i === undefined) {
+ // console.log("Mark not set"); // TODO - show in status bar
+ return;
+ }
+ var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
+ for (var c = start; c <= end; c++) {
+ pushInBuffer("\n"+cm.getLine(c));
+ }
+ cm.setCursor(start);
+ }
+ function goLineStartText(cm) {
+ // Go to the start of the line where the text begins, or the end for whitespace-only lines
+ var cur = cm.getCursor(), firstNonWS = cm.getLine(cur.line).search(/\S/);
+ cm.setCursor(cur.line, firstNonWS == -1 ? line.length : firstNonWS, true);
+ }
+
+ function charIdxInLine(cm, cHar, motion_options) {
+ // Search for cHar in line.
+ // motion_options: {forward, inclusive}
+ // If inclusive = true, include it too.
+ // If forward = true, search forward, else search backwards.
+ // If char is not found on this line, do nothing
+ var cur = cm.getCursor(), line = cm.getLine(cur.line), idx;
+ var ch = toLetter(cHar), mo = motion_options;
+ if (mo.forward) {
+ idx = line.indexOf(ch, cur.ch + 1);
+ if (idx != -1 && mo.inclusive) idx += 1;
+ } else {
+ idx = line.lastIndexOf(ch, cur.ch);
+ if (idx != -1 && !mo.inclusive) idx += 1;
+ }
+ return idx;
+ }
+
+ function moveTillChar(cm, cHar, motion_options) {
+ // Move to cHar in line, as found by charIdxInLine.
+ var idx = charIdxInLine(cm, cHar, motion_options), cur = cm.getCursor();
+ if (idx != -1) cm.setCursor({line: cur.line, ch: idx});
+ }
+
+ function delTillChar(cm, cHar, motion_options) {
+ // delete text in this line, untill cHar is met,
+ // as found by charIdxInLine.
+ // If char is not found on this line, do nothing
+ var idx = charIdxInLine(cm, cHar, motion_options);
+ var cur = cm.getCursor();
+ if (idx !== -1) {
+ if (motion_options.forward) {
+ cm.replaceRange("", {line: cur.line, ch: cur.ch}, {line: cur.line, ch: idx});
+ } else {
+ cm.replaceRange("", {line: cur.line, ch: idx}, {line: cur.line, ch: cur.ch});
+ }
+ }
+ }
+
+ function enterInsertMode(cm) {
+ // enter insert mode: switch mode and cursor
+ popCount();
+ cm.setOption("keyMap", "vim-insert");
+ }
+
+ // main keymap
+ var map = CodeMirror.keyMap.vim = {
+ // Pipe (|); TODO: should be *screen* chars, so need a util function to turn tabs into spaces?
+ "'|'": function(cm) {
+ cm.setCursor(cm.getCursor().line, popCount() - 1, true);
+ },
+ "A": function(cm) {
+ cm.setCursor(cm.getCursor().line, cm.getCursor().ch+1, true);
+ enterInsertMode(cm);
+ },
+ "Shift-A": function(cm) { CodeMirror.commands.goLineEnd(cm); enterInsertMode(cm);},
+ "I": function(cm) { enterInsertMode(cm);},
+ "Shift-I": function(cm) { goLineStartText(cm); enterInsertMode(cm);},
+ "O": function(cm) {
+ CodeMirror.commands.goLineEnd(cm);
+ CodeMirror.commands.newlineAndIndent(cm);
+ enterInsertMode(cm);
+ },
+ "Shift-O": function(cm) {
+ CodeMirror.commands.goLineStart(cm);
+ cm.replaceSelection("\n", "start");
+ cm.indentLine(cm.getCursor().line);
+ enterInsertMode(cm);
+ },
+ "G": function(cm) { cm.setOption("keyMap", "vim-prefix-g");},
+ "Shift-D": function(cm) {
+ // commented out verions works, but I left original, cause maybe
+ // I don't know vim enouth to see what it does
+ /* var cur = cm.getCursor();
+ var f = {line: cur.line, ch: cur.ch}, t = {line: cur.line};
+ pushInBuffer(cm.getRange(f, t));
+ */
+ emptyBuffer();
+ mark["Shift-D"] = cm.getCursor(false).line;
+ cm.setCursor(cm.getCursor(true).line);
+ delTillMark(cm,"Shift-D"); mark = [];
+ },
+
+ "S": function (cm) {
+ countTimes(function (_cm) {
+ CodeMirror.commands.delCharRight(_cm);
+ })(cm);
+ enterInsertMode(cm);
+ },
+ "M": function(cm) {cm.setOption("keyMap", "vim-prefix-m"); mark = [];},
+ "Y": function(cm) {cm.setOption("keyMap", "vim-prefix-y"); emptyBuffer(); yank = 0;},
+ "Shift-Y": function(cm) {
+ emptyBuffer();
+ mark["Shift-D"] = cm.getCursor(false).line;
+ cm.setCursor(cm.getCursor(true).line);
+ yankTillMark(cm,"Shift-D"); mark = [];
+ },
+ "/": function(cm) {var f = CodeMirror.commands.find; f && f(cm); sdir = "f";},
+ "'?'": function(cm) {
+ var f = CodeMirror.commands.find;
+ if (f) { f(cm); CodeMirror.commands.findPrev(cm); sdir = "r"; }
+ },
+ "N": function(cm) {
+ var fn = CodeMirror.commands.findNext;
+ if (fn) sdir != "r" ? fn(cm) : CodeMirror.commands.findPrev(cm);
+ },
+ "Shift-N": function(cm) {
+ var fn = CodeMirror.commands.findNext;
+ if (fn) sdir != "r" ? CodeMirror.commands.findPrev(cm) : fn.findNext(cm);
+ },
+ "Shift-G": function(cm) {
+ count == "" ? cm.setCursor(cm.lineCount()) : cm.setCursor(parseInt(count, 10)-1);
+ popCount();
+ CodeMirror.commands.goLineStart(cm);
+ },
+ nofallthrough: true, style: "fat-cursor"
+ };
+
+ // standard mode switching
+ iterList(["d", "t", "T", "f", "F", "c", "r"],
+ function (ch) {
+ CodeMirror.keyMap.vim[toCombo(ch)] = function (cm) {
+ cm.setOption("keyMap", "vim-prefix-" + ch);
+ emptyBuffer();
+ };
+ });
+
+ function addCountBindings(keyMap) {
+ // Add bindings for number keys
+ keyMap["0"] = function(cm) {
+ count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);
+ };
+ for (var i = 1; i < 10; ++i) keyMap[i] = pushCountDigit(i);
+ }
+ addCountBindings(CodeMirror.keyMap.vim);
+
+ // main num keymap
+ // Add bindings that are influenced by number keys
+ iterObj({
+ "Left": "goColumnLeft", "Right": "goColumnRight",
+ "Down": "goLineDown", "Up": "goLineUp", "Backspace": "goCharLeft",
+ "Space": "goCharRight",
+ "X": function(cm) {CodeMirror.commands.delCharRight(cm);},
+ "P": function(cm) {
+ var cur = cm.getCursor().line;
+ if (buf!= "") {
+ if (buf[0] == "\n") CodeMirror.commands.goLineEnd(cm);
+ cm.replaceRange(buf, cm.getCursor());
+ }
+ },
+ "Shift-X": function(cm) {CodeMirror.commands.delCharLeft(cm);},
+ "Shift-J": function(cm) {joinLineNext(cm);},
+ "Shift-P": function(cm) {
+ var cur = cm.getCursor().line;
+ if (buf!= "") {
+ CodeMirror.commands.goLineUp(cm);
+ CodeMirror.commands.goLineEnd(cm);
+ cm.replaceSelection(buf, "end");
+ }
+ cm.setCursor(cur+1);
+ },
+ "'~'": function(cm) {
+ var cur = cm.getCursor(), cHar = cm.getRange({line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
+ cHar = cHar != cHar.toLowerCase() ? cHar.toLowerCase() : cHar.toUpperCase();
+ cm.replaceRange(cHar, {line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
+ cm.setCursor(cur.line, cur.ch+1);
+ },
+ "Ctrl-B": function(cm) {CodeMirror.commands.goPageUp(cm);},
+ "Ctrl-F": function(cm) {CodeMirror.commands.goPageDown(cm);},
+ "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
+ "U": "undo", "Ctrl-R": "redo"
+ }, function(key, cmd) { map[key] = countTimes(cmd); });
+
+ // empty key maps
+ iterList([
+ "vim-prefix-d'",
+ "vim-prefix-y'",
+ "vim-prefix-df",
+ "vim-prefix-dF",
+ "vim-prefix-dt",
+ "vim-prefix-dT",
+ "vim-prefix-c",
+ "vim-prefix-cf",
+ "vim-prefix-cF",
+ "vim-prefix-ct",
+ "vim-prefix-cT",
+ "vim-prefix-",
+ "vim-prefix-f",
+ "vim-prefix-F",
+ "vim-prefix-t",
+ "vim-prefix-T",
+ "vim-prefix-r",
+ "vim-prefix-m"
+ ],
+ function (prefix) {
+ CodeMirror.keyMap[prefix] = {
+ auto: "vim",
+ nofallthrough: true,
+ style: "fat-cursor"
+ };
+ });
+
+ CodeMirror.keyMap["vim-prefix-g"] = {
+ "E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, word, -1, 1, "start"));}),
+ "Shift-E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, bigWord, -1, 1, "start"));}),
+ "G": function (cm) { cm.setCursor({line: 0, ch: cm.getCursor().ch});},
+ auto: "vim", nofallthrough: true, style: "fat-cursor"
+ };
+
+ CodeMirror.keyMap["vim-prefix-d"] = {
+ "D": countTimes(function(cm) {
+ pushInBuffer("\n"+cm.getLine(cm.getCursor().line));
+ cm.removeLine(cm.getCursor().line);
+ cm.setOption("keyMap", "vim");
+ }),
+ "'": function(cm) {
+ cm.setOption("keyMap", "vim-prefix-d'");
+ emptyBuffer();
+ },
+ "B": function(cm) {
+ var cur = cm.getCursor();
+ var line = cm.getLine(cur.line);
+ var index = line.lastIndexOf(" ", cur.ch);
+
+ pushInBuffer(line.substring(index, cur.ch));
+ cm.replaceRange("", {line: cur.line, ch: index}, cur);
+ cm.setOption("keyMap", "vim");
+ },
+ nofallthrough: true, style: "fat-cursor"
+ };
+ // FIXME - does not work for bindings like "d3e"
+ addCountBindings(CodeMirror.keyMap["vim-prefix-d"]);
+
+ CodeMirror.keyMap["vim-prefix-c"] = {
+ "B": function (cm) {
+ countTimes("delWordLeft")(cm);
+ enterInsertMode(cm);
+ },
+ "C": function (cm) {
+ iterTimes(function (i, last) {
+ CodeMirror.commands.deleteLine(cm);
+ if (i) {
+ CodeMirror.commands.delCharRight(cm);
+ if (last) CodeMirror.commands.deleteLine(cm);
+ }
+ });
+ enterInsertMode(cm);
+ },
+ nofallthrough: true, style: "fat-cursor"
+ };
+
+ iterList(["vim-prefix-d", "vim-prefix-c", "vim-prefix-"], function (prefix) {
+ iterList(["f", "F", "T", "t"],
+ function (ch) {
+ CodeMirror.keyMap[prefix][toCombo(ch)] = function (cm) {
+ cm.setOption("keyMap", prefix + ch);
+ emptyBuffer();
+ };
+ });
+ });
+
+ var MOTION_OPTIONS = {
+ "t": {inclusive: false, forward: true},
+ "f": {inclusive: true, forward: true},
+ "T": {inclusive: false, forward: false},
+ "F": {inclusive: true, forward: false}
+ };
+
+ function setupPrefixBindingForKey(m) {
+ CodeMirror.keyMap["vim-prefix-m"][m] = function(cm) {
+ mark[m] = cm.getCursor().line;
+ };
+ CodeMirror.keyMap["vim-prefix-d'"][m] = function(cm) {
+ delTillMark(cm,m);
+ };
+ CodeMirror.keyMap["vim-prefix-y'"][m] = function(cm) {
+ yankTillMark(cm,m);
+ };
+ CodeMirror.keyMap["vim-prefix-r"][m] = function (cm) {
+ var cur = cm.getCursor();
+ cm.replaceRange(toLetter(m),
+ {line: cur.line, ch: cur.ch},
+ {line: cur.line, ch: cur.ch + 1});
+ CodeMirror.commands.goColumnLeft(cm);
+ };
+ // all commands, related to motions till char in line
+ iterObj(MOTION_OPTIONS, function (ch, options) {
+ CodeMirror.keyMap["vim-prefix-" + ch][m] = function(cm) {
+ moveTillChar(cm, m, options);
+ };
+ CodeMirror.keyMap["vim-prefix-d" + ch][m] = function(cm) {
+ delTillChar(cm, m, options);
+ };
+ CodeMirror.keyMap["vim-prefix-c" + ch][m] = function(cm) {
+ delTillChar(cm, m, options);
+ enterInsertMode(cm);
+ };
+ });
+ }
+ for (var i = 65; i < 65 + 26; i++) { // uppercase alphabet char codes
+ var ch = String.fromCharCode(i);
+ setupPrefixBindingForKey(toCombo(ch));
+ setupPrefixBindingForKey(toCombo(ch.toLowerCase()));
+ }
+ iterList(SPECIAL_SYMBOLS, function (ch) {
+ setupPrefixBindingForKey(toCombo(ch));
+ });
+ setupPrefixBindingForKey("Space");
+
+ CodeMirror.keyMap["vim-prefix-y"] = {
+ "Y": countTimes(function(cm) { pushInBuffer("\n"+cm.getLine(cm.getCursor().line+yank)); yank++; }),
+ "'": function(cm) {cm.setOption("keyMap", "vim-prefix-y'"); emptyBuffer();},
+ nofallthrough: true, style: "fat-cursor"
+ };
+
+ CodeMirror.keyMap["vim-insert"] = {
+ // TODO: override navigation keys so that Esc will cancel automatic indentation from o, O, i_<CR>
+ "Esc": function(cm) {
+ cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
+ cm.setOption("keyMap", "vim");
+ },
+ "Ctrl-N": "autocomplete",
+ "Ctrl-P": "autocomplete",
+ fallthrough: ["default"]
+ };
+
+ function findMatchedSymbol(cm, cur, symb) {
+ var line = cur.line;
+ var symb = symb ? symb : cm.getLine(line)[cur.ch];
+
+ // Are we at the opening or closing char
+ var forwards = ['(', '[', '{'].indexOf(symb) != -1;
+
+ var reverseSymb = (function(sym) {
+ switch (sym) {
+ case '(' : return ')';
+ case '[' : return ']';
+ case '{' : return '}';
+ case ')' : return '(';
+ case ']' : return '[';
+ case '}' : return '{';
+ default : return null;
+ }
+ })(symb);
+
+ // Couldn't find a matching symbol, abort
+ if (reverseSymb == null) return cur;
+
+ // Tracking our imbalance in open/closing symbols. An opening symbol wii be
+ // the first thing we pick up if moving forward, this isn't true moving backwards
+ var disBal = forwards ? 0 : 1;
+
+ while (true) {
+ if (line == cur.line) {
+ // First pass, do some special stuff
+ var currLine = forwards ? cm.getLine(line).substr(cur.ch).split('') : cm.getLine(line).substr(0,cur.ch).split('').reverse();
+ } else {
+ var currLine = forwards ? cm.getLine(line).split('') : cm.getLine(line).split('').reverse();
+ }
+
+ for (var index = 0; index < currLine.length; index++) {
+ if (currLine[index] == symb) disBal++;
+ else if (currLine[index] == reverseSymb) disBal--;
+
+ if (disBal == 0) {
+ if (forwards && cur.line == line) return {line: line, ch: index + cur.ch};
+ else if (forwards) return {line: line, ch: index};
+ else return {line: line, ch: currLine.length - index - 1 };
+ }
+ }
+
+ if (forwards) line++;
+ else line--;
+ }
+ }
+
+ function selectCompanionObject(cm, revSymb, inclusive) {
+ var cur = cm.getCursor();
+
+ var end = findMatchedSymbol(cm, cur, revSymb);
+ var start = findMatchedSymbol(cm, end);
+ start.ch += inclusive ? 1 : 0;
+ end.ch += inclusive ? 0 : 1;
+
+ return {start: start, end: end};
+ }
+
+ // These are our motion commands to be used for navigation and selection with
+ // certian other commands. All should return a cursor object.
+ var motionList = ['B', 'E', 'J', 'K', 'H', 'L', 'W', 'Shift-W', "'^'", "'$'", "'%'", 'Esc'];
+
+ motions = {
+ 'B': function(cm, times) { return moveToWord(cm, word, -1, times); },
+ 'Shift-B': function(cm, times) { return moveToWord(cm, bigWord, -1, times); },
+ 'E': function(cm, times) { return moveToWord(cm, word, 1, times, 'end'); },
+ 'Shift-E': function(cm, times) { return moveToWord(cm, bigWord, 1, times, 'end'); },
+ 'J': function(cm, times) {
+ var cur = cm.getCursor();
+ return {line: cur.line+times, ch : cur.ch};
+ },
+
+ 'K': function(cm, times) {
+ var cur = cm.getCursor();
+ return {line: cur.line-times, ch: cur.ch};
+ },
+
+ 'H': function(cm, times) {
+ var cur = cm.getCursor();
+ return {line: cur.line, ch: cur.ch-times};
+ },
+
+ 'L': function(cm, times) {
+ var cur = cm.getCursor();
+ return {line: cur.line, ch: cur.ch+times};
+ },
+ 'W': function(cm, times) { return moveToWord(cm, word, 1, times); },
+ 'Shift-W': function(cm, times) { return moveToWord(cm, bigWord, 1, times); },
+ "'^'": function(cm, times) {
+ var cur = cm.getCursor();
+ var line = cm.getLine(cur.line).split('');
+
+ // Empty line :o
+ if (line.length == 0) return cur;
+
+ for (var index = 0; index < line.length; index++) {
+ if (line[index].match(/[^\s]/)) return {line: cur.line, ch: index};
+ }
+ },
+ "'$'": function(cm) {
+ var cur = cm.getCursor();
+ var line = cm.getLine(cur.line);
+ return {line: cur.line, ch: line.length};
+ },
+ "'%'": function(cm) { return findMatchedSymbol(cm, cm.getCursor()); },
+ "Esc" : function(cm) {
+ cm.setOption('vim');
+ reptTimes = 0;
+
+ return cm.getCursor();
+ }
+ };
+
+ // Map our movement actions each operator and non-operational movement
+ motionList.forEach(function(key, index, array) {
+ CodeMirror.keyMap['vim-prefix-d'][key] = function(cm) {
+ // Get our selected range
+ var start = cm.getCursor();
+ var end = motions[key](cm, reptTimes ? reptTimes : 1);
+
+ // Set swap var if range is of negative length
+ if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
+
+ // Take action, switching start and end if swap var is set
+ pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
+ cm.replaceRange("", swap ? end : start, swap ? start : end);
+
+ // And clean up
+ reptTimes = 0;
+ cm.setOption("keyMap", "vim");
+ };
+
+ CodeMirror.keyMap['vim-prefix-c'][key] = function(cm) {
+ var start = cm.getCursor();
+ var end = motions[key](cm, reptTimes ? reptTimes : 1);
+
+ if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
+ pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
+ cm.replaceRange("", swap ? end : start, swap ? start : end);
+
+ reptTimes = 0;
+ cm.setOption('keyMap', 'vim-insert');
+ };
+
+ CodeMirror.keyMap['vim-prefix-y'][key] = function(cm) {
+ var start = cm.getCursor();
+ var end = motions[key](cm, reptTimes ? reptTimes : 1);
+
+ if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
+ pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
+
+ reptTimes = 0;
+ cm.setOption("keyMap", "vim");
+ };
+
+ CodeMirror.keyMap['vim'][key] = function(cm) {
+ var cur = motions[key](cm, reptTimes ? reptTimes : 1);
+ cm.setCursor(cur.line, cur.ch);
+
+ reptTimes = 0;
+ };
+ });
+
+ var nums = [1,2,3,4,5,6,7,8,9];
+ nums.forEach(function(key, index, array) {
+ CodeMirror.keyMap['vim'][key] = function (cm) {
+ reptTimes = (reptTimes * 10) + key;
+ };
+ CodeMirror.keyMap['vim-prefix-d'][key] = function (cm) {
+ reptTimes = (reptTimes * 10) + key;
+ };
+ CodeMirror.keyMap['vim-prefix-y'][key] = function (cm) {
+ reptTimes = (reptTimes * 10) + key;
+ };
+ CodeMirror.keyMap['vim-prefix-c'][key] = function (cm) {
+ reptTimes = (reptTimes * 10) + key;
+ };
+ });
+
+ // Create our keymaps for each operator and make xa and xi where x is an operator
+ // change to the corrosponding keymap
+ var operators = ['d', 'y', 'c'];
+ operators.forEach(function(key, index, array) {
+ CodeMirror.keyMap['vim-prefix-'+key+'a'] = {
+ auto: 'vim', nofallthrough: true, style: "fat-cursor"
+ };
+ CodeMirror.keyMap['vim-prefix-'+key+'i'] = {
+ auto: 'vim', nofallthrough: true, style: "fat-cursor"
+ };
+
+ CodeMirror.keyMap['vim-prefix-'+key]['A'] = function(cm) {
+ reptTimes = 0;
+ cm.setOption('keyMap', 'vim-prefix-' + key + 'a');
+ };
+
+ CodeMirror.keyMap['vim-prefix-'+key]['I'] = function(cm) {
+ reptTimes = 0;
+ cm.setOption('keyMap', 'vim-prefix-' + key + 'i');
+ };
+ });
+
+ function regexLastIndexOf(string, pattern, startIndex) {
+ for (var i = startIndex == null ? string.length : startIndex; i >= 0; --i)
+ if (pattern.test(string.charAt(i))) return i;
+ return -1;
+ }
+
+ // Create our text object functions. They work similar to motions but they
+ // return a start cursor as well
+ var textObjectList = ['W', 'Shift-[', 'Shift-9', '['];
+ var textObjects = {
+ 'W': function(cm, inclusive) {
+ var cur = cm.getCursor();
+ var line = cm.getLine(cur.line);
+
+ var line_to_char = new String(line.substring(0, cur.ch));
+ var start = regexLastIndexOf(line_to_char, /[^a-zA-Z0-9]/) + 1;
+ var end = motions["E"](cm, 1) ;
+
+ end.ch += inclusive ? 1 : 0 ;
+ return {start: {line: cur.line, ch: start}, end: end };
+ },
+ 'Shift-[': function(cm, inclusive) { return selectCompanionObject(cm, '}', inclusive); },
+ 'Shift-9': function(cm, inclusive) { return selectCompanionObject(cm, ')', inclusive); },
+ '[': function(cm, inclusive) { return selectCompanionObject(cm, ']', inclusive); }
+ };
+
+ // One function to handle all operation upon text objects. Kinda funky but it works
+ // better than rewriting this code six times
+ function textObjectManipulation(cm, object, remove, insert, inclusive) {
+ // Object is the text object, delete object if remove is true, enter insert
+ // mode if insert is true, inclusive is the difference between a and i
+ var tmp = textObjects[object](cm, inclusive);
+ var start = tmp.start;
+ var end = tmp.end;
+
+ if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true ;
+
+ pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
+ if (remove) cm.replaceRange("", swap ? end : start, swap ? start : end);
+ if (insert) cm.setOption('keyMap', 'vim-insert');
+ }
+
+ // And finally build the keymaps up from the text objects
+ for (var i = 0; i < textObjectList.length; ++i) {
+ var object = textObjectList[i];
+ (function(object) {
+ CodeMirror.keyMap['vim-prefix-di'][object] = function(cm) { textObjectManipulation(cm, object, true, false, false); };
+ CodeMirror.keyMap['vim-prefix-da'][object] = function(cm) { textObjectManipulation(cm, object, true, false, true); };
+ CodeMirror.keyMap['vim-prefix-yi'][object] = function(cm) { textObjectManipulation(cm, object, false, false, false); };
+ CodeMirror.keyMap['vim-prefix-ya'][object] = function(cm) { textObjectManipulation(cm, object, false, false, true); };
+ CodeMirror.keyMap['vim-prefix-ci'][object] = function(cm) { textObjectManipulation(cm, object, true, true, false); };
+ CodeMirror.keyMap['vim-prefix-ca'][object] = function(cm) { textObjectManipulation(cm, object, true, true, true); };
+ })(object)
+ }
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.css b/codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.css
new file mode 100644
index 0000000..191ac25
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.css
@@ -0,0 +1,168 @@
+.CodeMirror {
+ line-height: 1em;
+ font-family: monospace;
+
+ /* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
+ position: relative;
+ /* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
+ overflow: hidden;
+}
+
+.CodeMirror-scroll {
+ overflow-x: auto;
+ overflow-y: hidden;
+ height: 300px;
+ /* This is needed to prevent an IE[67] bug where the scrolled content
+ is visible outside of the scrolling box. */
+ position: relative;
+ outline: none;
+}
+
+/* Vertical scrollbar */
+.CodeMirror-scrollbar {
+ float: right;
+ overflow-x: hidden;
+ overflow-y: scroll;
+
+ /* This corrects for the 1px gap introduced to the left of the scrollbar
+ by the rule for .CodeMirror-scrollbar-inner. */
+ margin-left: -1px;
+}
+.CodeMirror-scrollbar-inner {
+ /* This needs to have a nonzero width in order for the scrollbar to appear
+ in Firefox and IE9. */
+ width: 1px;
+}
+.CodeMirror-scrollbar.cm-sb-overlap {
+ /* Ensure that the scrollbar appears in Lion, and that it overlaps the content
+ rather than sitting to the right of it. */
+ position: absolute;
+ z-index: 1;
+ float: none;
+ right: 0;
+ min-width: 12px;
+}
+.CodeMirror-scrollbar.cm-sb-nonoverlap {
+ min-width: 12px;
+}
+.CodeMirror-scrollbar.cm-sb-ie7 {
+ min-width: 18px;
+}
+
+.CodeMirror-gutter {
+ position: absolute; left: 0; top: 0;
+ z-index: 10;
+ background-color: #f7f7f7;
+ border-right: 1px solid #eee;
+ min-width: 2em;
+ height: 100%;
+}
+.CodeMirror-gutter-text {
+ color: #aaa;
+ text-align: right;
+ padding: .4em .2em .4em .4em;
+ white-space: pre !important;
+}
+.CodeMirror-lines {
+ padding: .4em;
+ white-space: pre;
+ cursor: text;
+}
+.CodeMirror-lines * {
+ /* Necessary for throw-scrolling to decelerate properly on Safari. */
+ pointer-events: none;
+}
+
+.CodeMirror pre {
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0;
+ border-width: 0; margin: 0; padding: 0; background: transparent;
+ font-family: inherit;
+ font-size: inherit;
+ padding: 0; margin: 0;
+ white-space: pre;
+ word-wrap: normal;
+ line-height: inherit;
+ color: inherit;
+}
+
+.CodeMirror-wrap pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: normal;
+}
+.CodeMirror-wrap .CodeMirror-scroll {
+ overflow-x: hidden;
+}
+
+.CodeMirror textarea {
+ outline: none !important;
+}
+
+.CodeMirror pre.CodeMirror-cursor {
+ z-index: 10;
+ position: absolute;
+ visibility: hidden;
+ border-left: 1px solid black;
+ border-right: none;
+ width: 0;
+}
+.cm-keymap-fat-cursor pre.CodeMirror-cursor {
+ width: auto;
+ border: 0;
+ background: transparent;
+ background: rgba(0, 200, 0, .4);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
+}
+/* Kludge to turn off filter in ie9+, which also accepts rgba */
+.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
+.CodeMirror-focused pre.CodeMirror-cursor {
+ visibility: visible;
+}
+
+div.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; }
+
+.CodeMirror-searching {
+ background: #ffa;
+ background: rgba(255, 255, 0, .4);
+}
+
+/* Default theme */
+
+.cm-s-default span.cm-keyword {color: #708;}
+.cm-s-default span.cm-atom {color: #219;}
+.cm-s-default span.cm-number {color: #164;}
+.cm-s-default span.cm-def {color: #00f;}
+.cm-s-default span.cm-variable {color: black;}
+.cm-s-default span.cm-variable-2 {color: #05a;}
+.cm-s-default span.cm-variable-3 {color: #085;}
+.cm-s-default span.cm-property {color: black;}
+.cm-s-default span.cm-operator {color: black;}
+.cm-s-default span.cm-comment {color: #a50;}
+.cm-s-default span.cm-string {color: #a11;}
+.cm-s-default span.cm-string-2 {color: #f50;}
+.cm-s-default span.cm-meta {color: #555;}
+.cm-s-default span.cm-error {color: #f00;}
+.cm-s-default span.cm-qualifier {color: #555;}
+.cm-s-default span.cm-builtin {color: #30a;}
+.cm-s-default span.cm-bracket {color: #cc7;}
+.cm-s-default span.cm-tag {color: #170;}
+.cm-s-default span.cm-attribute {color: #00c;}
+.cm-s-default span.cm-header {color: blue;}
+.cm-s-default span.cm-quote {color: #090;}
+.cm-s-default span.cm-hr {color: #999;}
+.cm-s-default span.cm-link {color: #00c;}
+
+span.cm-header, span.cm-strong {font-weight: bold;}
+span.cm-em {font-style: italic;}
+span.cm-emstrong {font-style: italic; font-weight: bold;}
+span.cm-link {text-decoration: underline;}
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.js b/codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.js
new file mode 100644
index 0000000..250d5b1
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.js
@@ -0,0 +1,3181 @@
+// CodeMirror version 2.3
+//
+// All functions that need access to the editor's state live inside
+// the CodeMirror function. Below that, at the bottom of the file,
+// some utilities are defined.
+
+// CodeMirror is the only global var we claim
+var CodeMirror = (function() {
+ // This is the function that produces an editor instance. Its
+ // closure is used to store the editor state.
+ function CodeMirror(place, givenOptions) {
+ // Determine effective options based on given values and defaults.
+ var options = {}, defaults = CodeMirror.defaults;
+ for (var opt in defaults)
+ if (defaults.hasOwnProperty(opt))
+ options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
+
+ // The element in which the editor lives.
+ var wrapper = document.createElement("div");
+ wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : "");
+ // This mess creates the base DOM structure for the editor.
+ wrapper.innerHTML =
+ '<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea
+ '<textarea style="position: absolute; padding: 0; width: 1px; height: 1em" wrap="off" ' +
+ 'autocorrect="off" autocapitalize="off"></textarea></div>' +
+ '<div class="CodeMirror-scrollbar">' + // The vertical scrollbar. Horizontal scrolling is handled by the scroller itself.
+ '<div class="CodeMirror-scrollbar-inner">' + // The empty scrollbar content, used solely for managing the scrollbar thumb.
+ '</div></div>' + // This must be before the scroll area because it's float-right.
+ '<div class="CodeMirror-scroll" tabindex="-1">' +
+ '<div style="position: relative">' + // Set to the height of the text, causes scrolling
+ '<div style="position: relative">' + // Moved around its parent to cover visible view
+ '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
+ // Provides positioning relative to (visible) text origin
+ '<div class="CodeMirror-lines"><div style="position: relative; z-index: 0">' +
+ // Used to measure text size
+ '<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden;"></div>' +
+ '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
+ '<pre class="CodeMirror-cursor" style="visibility: hidden">&#160;</pre>' + // Used to force a width
+ '<div style="position: relative; z-index: -1"></div><div></div>' + // DIVs containing the selection and the actual code
+ '</div></div></div></div></div>';
+ if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
+ // I've never seen more elegant code in my life.
+ var inputDiv = wrapper.firstChild, input = inputDiv.firstChild,
+ scroller = wrapper.lastChild, code = scroller.firstChild,
+ mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
+ lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
+ cursor = measure.nextSibling, widthForcer = cursor.nextSibling,
+ selectionDiv = widthForcer.nextSibling, lineDiv = selectionDiv.nextSibling,
+ scrollbar = inputDiv.nextSibling, scrollbarInner = scrollbar.firstChild;
+ themeChanged(); keyMapChanged();
+ // Needed to hide big blue blinking cursor on Mobile Safari
+ if (ios) input.style.width = "0px";
+ if (!webkit) scroller.draggable = true;
+ lineSpace.style.outline = "none";
+ if (options.tabindex != null) input.tabIndex = options.tabindex;
+ if (options.autofocus) focusInput();
+ if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
+ // Needed to handle Tab key in KHTML
+ if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute";
+
+ // Check for OS X >= 10.7. If so, we need to force a width on the scrollbar, and
+ // make it overlap the content. (But we only do this if the scrollbar doesn't already
+ // have a natural width. If the mouse is plugged in or the user sets the system pref
+ // to always show scrollbars, the scrollbar shouldn't overlap.)
+ if (mac_geLion) {
+ scrollbar.className += (overlapScrollbars() ? " cm-sb-overlap" : " cm-sb-nonoverlap");
+ } else if (ie_lt8) {
+ // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
+ scrollbar.className += " cm-sb-ie7";
+ }
+
+ // Check for problem with IE innerHTML not working when we have a
+ // P (or similar) parent node.
+ try { stringWidth("x"); }
+ catch (e) {
+ if (e.message.match(/runtime/i))
+ e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)");
+ throw e;
+ }
+
+ // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
+ var poll = new Delayed(), highlight = new Delayed(), blinker;
+
+ // mode holds a mode API object. doc is the tree of Line objects,
+ // work an array of lines that should be parsed, and history the
+ // undo history (instance of History constructor).
+ var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), work, focused;
+ loadMode();
+ // The selection. These are always maintained to point at valid
+ // positions. Inverted is used to remember that the user is
+ // selecting bottom-to-top.
+ var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
+ // Selection-related flags. shiftSelecting obviously tracks
+ // whether the user is holding shift.
+ var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, lastScrollLeft = 0, draggingText,
+ overwrite = false, suppressEdits = false;
+ // Variables used by startOperation/endOperation to track what
+ // happened during the operation.
+ var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone,
+ gutterDirty, callbacks;
+ // Current visible range (may be bigger than the view window).
+ var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
+ // bracketHighlighted is used to remember that a bracket has been
+ // marked.
+ var bracketHighlighted;
+ // Tracks the maximum line length so that the horizontal scrollbar
+ // can be kept static when scrolling.
+ var maxLine = "", updateMaxLine = false, maxLineChanged = true;
+ var tabCache = {};
+
+ // Initialize the content.
+ operation(function(){setValue(options.value || ""); updateInput = false;})();
+ var history = new History();
+
+ // Register our event handlers.
+ connect(scroller, "mousedown", operation(onMouseDown));
+ connect(scroller, "dblclick", operation(onDoubleClick));
+ connect(lineSpace, "selectstart", e_preventDefault);
+ // Gecko browsers fire contextmenu *after* opening the menu, at
+ // which point we can't mess with it anymore. Context menu is
+ // handled in onMouseDown for Gecko.
+ if (!gecko) connect(scroller, "contextmenu", onContextMenu);
+ connect(scroller, "scroll", onScroll);
+ connect(scrollbar, "scroll", onScroll);
+ connect(scrollbar, "mousedown", function() {setTimeout(focusInput, 0);});
+ connect(scroller, "mousewheel", onMouseWheel);
+ connect(scroller, "DOMMouseScroll", onMouseWheel);
+ connect(window, "resize", function() {updateDisplay(true);});
+ connect(input, "keyup", operation(onKeyUp));
+ connect(input, "input", fastPoll);
+ connect(input, "keydown", operation(onKeyDown));
+ connect(input, "keypress", operation(onKeyPress));
+ connect(input, "focus", onFocus);
+ connect(input, "blur", onBlur);
+
+ if (options.dragDrop) {
+ connect(scroller, "dragstart", onDragStart);
+ function drag_(e) {
+ if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
+ e_stop(e);
+ }
+ connect(scroller, "dragenter", drag_);
+ connect(scroller, "dragover", drag_);
+ connect(scroller, "drop", operation(onDrop));
+ }
+ connect(scroller, "paste", function(){focusInput(); fastPoll();});
+ connect(input, "paste", fastPoll);
+ connect(input, "cut", operation(function(){
+ if (!options.readOnly) replaceSelection("");
+ }));
+
+ // Needed to handle Tab key in KHTML
+ if (khtml) connect(code, "mouseup", function() {
+ if (document.activeElement == input) input.blur();
+ focusInput();
+ });
+
+ // IE throws unspecified error in certain cases, when
+ // trying to access activeElement before onload
+ var hasFocus; try { hasFocus = (document.activeElement == input); } catch(e) { }
+ if (hasFocus || options.autofocus) setTimeout(onFocus, 20);
+ else onBlur();
+
+ function isLine(l) {return l >= 0 && l < doc.size;}
+ // The instance object that we'll return. Mostly calls out to
+ // local functions in the CodeMirror function. Some do some extra
+ // range checking and/or clipping. operation is used to wrap the
+ // call so that changes it makes are tracked, and the display is
+ // updated afterwards.
+ var instance = wrapper.CodeMirror = {
+ getValue: getValue,
+ setValue: operation(setValue),
+ getSelection: getSelection,
+ replaceSelection: operation(replaceSelection),
+ focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();},
+ setOption: function(option, value) {
+ var oldVal = options[option];
+ options[option] = value;
+ if (option == "mode" || option == "indentUnit") loadMode();
+ else if (option == "readOnly" && value == "nocursor") {onBlur(); input.blur();}
+ else if (option == "readOnly" && !value) {resetInput(true);}
+ else if (option == "theme") themeChanged();
+ else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
+ else if (option == "tabSize") updateDisplay(true);
+ else if (option == "keyMap") keyMapChanged();
+ if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
+ gutterChanged();
+ updateDisplay(true);
+ }
+ },
+ getOption: function(option) {return options[option];},
+ undo: operation(undo),
+ redo: operation(redo),
+ indentLine: operation(function(n, dir) {
+ if (typeof dir != "string") {
+ if (dir == null) dir = options.smartIndent ? "smart" : "prev";
+ else dir = dir ? "add" : "subtract";
+ }
+ if (isLine(n)) indentLine(n, dir);
+ }),
+ indentSelection: operation(indentSelected),
+ historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
+ clearHistory: function() {history = new History();},
+ matchBrackets: operation(function(){matchBrackets(true);}),
+ getTokenAt: operation(function(pos) {
+ pos = clipPos(pos);
+ return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), pos.ch);
+ }),
+ getStateAfter: function(line) {
+ line = clipLine(line == null ? doc.size - 1: line);
+ return getStateBefore(line + 1);
+ },
+ cursorCoords: function(start, mode) {
+ if (start == null) start = sel.inverted;
+ return this.charCoords(start ? sel.from : sel.to, mode);
+ },
+ charCoords: function(pos, mode) {
+ pos = clipPos(pos);
+ if (mode == "local") return localCoords(pos, false);
+ if (mode == "div") return localCoords(pos, true);
+ return pageCoords(pos);
+ },
+ coordsChar: function(coords) {
+ var off = eltOffset(lineSpace);
+ return coordsChar(coords.x - off.left, coords.y - off.top);
+ },
+ markText: operation(markText),
+ setBookmark: setBookmark,
+ findMarksAt: findMarksAt,
+ setMarker: operation(addGutterMarker),
+ clearMarker: operation(removeGutterMarker),
+ setLineClass: operation(setLineClass),
+ hideLine: operation(function(h) {return setLineHidden(h, true);}),
+ showLine: operation(function(h) {return setLineHidden(h, false);}),
+ onDeleteLine: function(line, f) {
+ if (typeof line == "number") {
+ if (!isLine(line)) return null;
+ line = getLine(line);
+ }
+ (line.handlers || (line.handlers = [])).push(f);
+ return line;
+ },
+ lineInfo: lineInfo,
+ addWidget: function(pos, node, scroll, vert, horiz) {
+ pos = localCoords(clipPos(pos));
+ var top = pos.yBot, left = pos.x;
+ node.style.position = "absolute";
+ code.appendChild(node);
+ if (vert == "over") top = pos.y;
+ else if (vert == "near") {
+ var vspace = Math.max(scroller.offsetHeight, doc.height * textHeight()),
+ hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft();
+ if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
+ top = pos.y - node.offsetHeight;
+ if (left + node.offsetWidth > hspace)
+ left = hspace - node.offsetWidth;
+ }
+ node.style.top = (top + paddingTop()) + "px";
+ node.style.left = node.style.right = "";
+ if (horiz == "right") {
+ left = code.clientWidth - node.offsetWidth;
+ node.style.right = "0px";
+ } else {
+ if (horiz == "left") left = 0;
+ else if (horiz == "middle") left = (code.clientWidth - node.offsetWidth) / 2;
+ node.style.left = (left + paddingLeft()) + "px";
+ }
+ if (scroll)
+ scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight);
+ },
+
+ lineCount: function() {return doc.size;},
+ clipPos: clipPos,
+ getCursor: function(start) {
+ if (start == null) start = sel.inverted;
+ return copyPos(start ? sel.from : sel.to);
+ },
+ somethingSelected: function() {return !posEq(sel.from, sel.to);},
+ setCursor: operation(function(line, ch, user) {
+ if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch, user);
+ else setCursor(line, ch, user);
+ }),
+ setSelection: operation(function(from, to, user) {
+ (user ? setSelectionUser : setSelection)(clipPos(from), clipPos(to || from));
+ }),
+ getLine: function(line) {if (isLine(line)) return getLine(line).text;},
+ getLineHandle: function(line) {if (isLine(line)) return getLine(line);},
+ setLine: operation(function(line, text) {
+ if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: getLine(line).text.length});
+ }),
+ removeLine: operation(function(line) {
+ if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
+ }),
+ replaceRange: operation(replaceRange),
+ getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
+
+ triggerOnKeyDown: operation(onKeyDown),
+ execCommand: function(cmd) {return commands[cmd](instance);},
+ // Stuff used by commands, probably not much use to outside code.
+ moveH: operation(moveH),
+ deleteH: operation(deleteH),
+ moveV: operation(moveV),
+ toggleOverwrite: function() {
+ if(overwrite){
+ overwrite = false;
+ cursor.className = cursor.className.replace(" CodeMirror-overwrite", "");
+ } else {
+ overwrite = true;
+ cursor.className += " CodeMirror-overwrite";
+ }
+ },
+
+ posFromIndex: function(off) {
+ var lineNo = 0, ch;
+ doc.iter(0, doc.size, function(line) {
+ var sz = line.text.length + 1;
+ if (sz > off) { ch = off; return true; }
+ off -= sz;
+ ++lineNo;
+ });
+ return clipPos({line: lineNo, ch: ch});
+ },
+ indexFromPos: function (coords) {
+ if (coords.line < 0 || coords.ch < 0) return 0;
+ var index = coords.ch;
+ doc.iter(0, coords.line, function (line) {
+ index += line.text.length + 1;
+ });
+ return index;
+ },
+ scrollTo: function(x, y) {
+ if (x != null) scroller.scrollLeft = x;
+ if (y != null) scrollbar.scrollTop = y;
+ updateDisplay([]);
+ },
+ getScrollInfo: function() {
+ return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
+ height: scrollbar.scrollHeight, width: scroller.scrollWidth};
+ },
+
+ operation: function(f){return operation(f)();},
+ compoundChange: function(f){return compoundChange(f);},
+ refresh: function(){
+ updateDisplay(true);
+ if (scrollbar.scrollHeight > lastScrollTop)
+ scrollbar.scrollTop = lastScrollTop;
+ },
+ getInputField: function(){return input;},
+ getWrapperElement: function(){return wrapper;},
+ getScrollerElement: function(){return scroller;},
+ getGutterElement: function(){return gutter;}
+ };
+
+ function getLine(n) { return getLineAt(doc, n); }
+ function updateLineHeight(line, height) {
+ gutterDirty = true;
+ var diff = height - line.height;
+ for (var n = line; n; n = n.parent) n.height += diff;
+ }
+
+ function setValue(code) {
+ var top = {line: 0, ch: 0};
+ updateLines(top, {line: doc.size - 1, ch: getLine(doc.size-1).text.length},
+ splitLines(code), top, top);
+ updateInput = true;
+ }
+ function getValue() {
+ var text = [];
+ doc.iter(0, doc.size, function(line) { text.push(line.text); });
+ return text.join("\n");
+ }
+
+ function onScroll(e) {
+ if (lastScrollTop != scrollbar.scrollTop || lastScrollLeft != scroller.scrollLeft) {
+ lastScrollTop = scrollbar.scrollTop;
+ lastScrollLeft = scroller.scrollLeft;
+ updateDisplay([]);
+ if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
+ if (options.onScroll) options.onScroll(instance);
+ }
+ }
+
+ function onMouseDown(e) {
+ setShift(e_prop(e, "shiftKey"));
+ // Check whether this is a click in a widget
+ for (var n = e_target(e); n != wrapper; n = n.parentNode)
+ if (n.parentNode == code && n != mover) return;
+
+ // See if this is a click in the gutter
+ for (var n = e_target(e); n != wrapper; n = n.parentNode)
+ if (n.parentNode == gutterText) {
+ if (options.onGutterClick)
+ options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom, e);
+ return e_preventDefault(e);
+ }
+
+ var start = posFromMouse(e);
+
+ switch (e_button(e)) {
+ case 3:
+ if (gecko && !mac) onContextMenu(e);
+ return;
+ case 2:
+ if (start) setCursor(start.line, start.ch, true);
+ setTimeout(focusInput, 20);
+ e_preventDefault(e);
+ return;
+ }
+ // For button 1, if it was clicked inside the editor
+ // (posFromMouse returning non-null), we have to adjust the
+ // selection.
+ if (!start) {if (e_target(e) == scroller) e_preventDefault(e); return;}
+
+ if (!focused) onFocus();
+
+ var now = +new Date;
+ if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
+ e_preventDefault(e);
+ setTimeout(focusInput, 20);
+ return selectLine(start.line);
+ } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
+ lastDoubleClick = {time: now, pos: start};
+ e_preventDefault(e);
+ return selectWordAt(start);
+ } else { lastClick = {time: now, pos: start}; }
+
+ var last = start, going;
+ if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
+ !posLess(start, sel.from) && !posLess(sel.to, start)) {
+ // Let the drag handler handle this.
+ if (webkit) scroller.draggable = true;
+ function dragEnd(e2) {
+ if (webkit) scroller.draggable = false;
+ draggingText = false;
+ up(); drop();
+ if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
+ e_preventDefault(e2);
+ setCursor(start.line, start.ch, true);
+ focusInput();
+ }
+ }
+ var up = connect(document, "mouseup", operation(dragEnd), true);
+ var drop = connect(scroller, "drop", operation(dragEnd), true);
+ draggingText = true;
+ // IE's approach to draggable
+ if (scroller.dragDrop) scroller.dragDrop();
+ return;
+ }
+ e_preventDefault(e);
+ setCursor(start.line, start.ch, true);
+
+ function extend(e) {
+ var cur = posFromMouse(e, true);
+ if (cur && !posEq(cur, last)) {
+ if (!focused) onFocus();
+ last = cur;
+ setSelectionUser(start, cur);
+ updateInput = false;
+ var visible = visibleLines();
+ if (cur.line >= visible.to || cur.line < visible.from)
+ going = setTimeout(operation(function(){extend(e);}), 150);
+ }
+ }
+
+ function done(e) {
+ clearTimeout(going);
+ var cur = posFromMouse(e);
+ if (cur) setSelectionUser(start, cur);
+ e_preventDefault(e);
+ focusInput();
+ updateInput = true;
+ move(); up();
+ }
+ var move = connect(document, "mousemove", operation(function(e) {
+ clearTimeout(going);
+ e_preventDefault(e);
+ if (!ie && !e_button(e)) done(e);
+ else extend(e);
+ }), true);
+ var up = connect(document, "mouseup", operation(done), true);
+ }
+ function onDoubleClick(e) {
+ for (var n = e_target(e); n != wrapper; n = n.parentNode)
+ if (n.parentNode == gutterText) return e_preventDefault(e);
+ var start = posFromMouse(e);
+ if (!start) return;
+ lastDoubleClick = {time: +new Date, pos: start};
+ e_preventDefault(e);
+ selectWordAt(start);
+ }
+ function onDrop(e) {
+ if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
+ e.preventDefault();
+ var pos = posFromMouse(e, true), files = e.dataTransfer.files;
+ if (!pos || options.readOnly) return;
+ if (files && files.length && window.FileReader && window.File) {
+ function loadFile(file, i) {
+ var reader = new FileReader;
+ reader.onload = function() {
+ text[i] = reader.result;
+ if (++read == n) {
+ pos = clipPos(pos);
+ operation(function() {
+ var end = replaceRange(text.join(""), pos, pos);
+ setSelectionUser(pos, end);
+ })();
+ }
+ };
+ reader.readAsText(file);
+ }
+ var n = files.length, text = Array(n), read = 0;
+ for (var i = 0; i < n; ++i) loadFile(files[i], i);
+ } else {
+ // Don't do a replace if the drop happened inside of the selected text.
+ if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return;
+ try {
+ var text = e.dataTransfer.getData("Text");
+ if (text) {
+ compoundChange(function() {
+ var curFrom = sel.from, curTo = sel.to;
+ setSelectionUser(pos, pos);
+ if (draggingText) replaceRange("", curFrom, curTo);
+ replaceSelection(text);
+ focusInput();
+ });
+ }
+ }
+ catch(e){}
+ }
+ }
+ function onDragStart(e) {
+ var txt = getSelection();
+ e.dataTransfer.setData("Text", txt);
+
+ // Use dummy image instead of default browsers image.
+ if (gecko || chrome || opera) {
+ var img = document.createElement('img');
+ img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image
+ e.dataTransfer.setDragImage(img, 0, 0);
+ }
+ }
+
+ function doHandleBinding(bound, dropShift) {
+ if (typeof bound == "string") {
+ bound = commands[bound];
+ if (!bound) return false;
+ }
+ var prevShift = shiftSelecting;
+ try {
+ if (options.readOnly) suppressEdits = true;
+ if (dropShift) shiftSelecting = null;
+ bound(instance);
+ } catch(e) {
+ if (e != Pass) throw e;
+ return false;
+ } finally {
+ shiftSelecting = prevShift;
+ suppressEdits = false;
+ }
+ return true;
+ }
+ function handleKeyBinding(e) {
+ // Handle auto keymap transitions
+ var startMap = getKeyMap(options.keyMap), next = startMap.auto;
+ clearTimeout(maybeTransition);
+ if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
+ if (getKeyMap(options.keyMap) == startMap) {
+ options.keyMap = (next.call ? next.call(null, instance) : next);
+ }
+ }, 50);
+
+ var name = keyNames[e_prop(e, "keyCode")], handled = false;
+ if (name == null || e.altGraphKey) return false;
+ if (e_prop(e, "altKey")) name = "Alt-" + name;
+ if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
+ if (e_prop(e, "metaKey")) name = "Cmd-" + name;
+
+ var stopped = false;
+ function stop() { stopped = true; }
+
+ if (e_prop(e, "shiftKey")) {
+ handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap,
+ function(b) {return doHandleBinding(b, true);}, stop)
+ || lookupKey(name, options.extraKeys, options.keyMap, function(b) {
+ if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(b);
+ }, stop);
+ } else {
+ handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding, stop);
+ }
+ if (stopped) handled = false;
+ if (handled) {
+ e_preventDefault(e);
+ restartBlink();
+ if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
+ }
+ return handled;
+ }
+ function handleCharBinding(e, ch) {
+ var handled = lookupKey("'" + ch + "'", options.extraKeys,
+ options.keyMap, function(b) { return doHandleBinding(b, true); });
+ if (handled) {
+ e_preventDefault(e);
+ restartBlink();
+ }
+ return handled;
+ }
+
+ var lastStoppedKey = null, maybeTransition;
+ function onKeyDown(e) {
+ if (!focused) onFocus();
+ if (ie && e.keyCode == 27) { e.returnValue = false; }
+ if (pollingFast) { if (readInput()) pollingFast = false; }
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
+ var code = e_prop(e, "keyCode");
+ // IE does strange things with escape.
+ setShift(code == 16 || e_prop(e, "shiftKey"));
+ // First give onKeyEvent option a chance to handle this.
+ var handled = handleKeyBinding(e);
+ if (opera) {
+ lastStoppedKey = handled ? code : null;
+ // Opera has no cut event... we try to at least catch the key combo
+ if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey"))
+ replaceSelection("");
+ }
+ }
+ function onKeyPress(e) {
+ if (pollingFast) readInput();
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
+ var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
+ if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
+ if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(e)) return;
+ var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
+ if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
+ if (mode.electricChars.indexOf(ch) > -1)
+ setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
+ }
+ if (handleCharBinding(e, ch)) return;
+ fastPoll();
+ }
+ function onKeyUp(e) {
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
+ if (e_prop(e, "keyCode") == 16) shiftSelecting = null;
+ }
+
+ function onFocus() {
+ if (options.readOnly == "nocursor") return;
+ if (!focused) {
+ if (options.onFocus) options.onFocus(instance);
+ focused = true;
+ if (scroller.className.search(/\bCodeMirror-focused\b/) == -1)
+ scroller.className += " CodeMirror-focused";
+ if (!leaveInputAlone) resetInput(true);
+ }
+ slowPoll();
+ restartBlink();
+ }
+ function onBlur() {
+ if (focused) {
+ if (options.onBlur) options.onBlur(instance);
+ focused = false;
+ if (bracketHighlighted)
+ operation(function(){
+ if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; }
+ })();
+ scroller.className = scroller.className.replace(" CodeMirror-focused", "");
+ }
+ clearInterval(blinker);
+ setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
+ }
+
+ function chopDelta(delta) {
+ // Make sure we always scroll a little bit for any nonzero delta.
+ if (delta > 0.0 && delta < 1.0) return 1;
+ else if (delta > -1.0 && delta < 0.0) return -1;
+ else return Math.round(delta);
+ }
+
+ function onMouseWheel(e) {
+ var deltaX = 0, deltaY = 0;
+ if (e.type == "DOMMouseScroll") { // Firefox
+ var delta = -e.detail * 8.0;
+ if (e.axis == e.HORIZONTAL_AXIS) deltaX = delta;
+ else if (e.axis == e.VERTICAL_AXIS) deltaY = delta;
+ } else if (e.wheelDeltaX !== undefined && e.wheelDeltaY !== undefined) { // WebKit
+ deltaX = e.wheelDeltaX / 3.0;
+ deltaY = e.wheelDeltaY / 3.0;
+ } else if (e.wheelDelta !== undefined) { // IE or Opera
+ deltaY = e.wheelDelta / 3.0;
+ }
+
+ var scrolled = false;
+ deltaX = chopDelta(deltaX);
+ deltaY = chopDelta(deltaY);
+ if ((deltaX > 0 && scroller.scrollLeft > 0) ||
+ (deltaX < 0 && scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth)) {
+ scroller.scrollLeft -= deltaX;
+ scrolled = true;
+ }
+ if ((deltaY > 0 && scrollbar.scrollTop > 0) ||
+ (deltaY < 0 && scrollbar.scrollTop + scrollbar.clientHeight < scrollbar.scrollHeight)) {
+ scrollbar.scrollTop -= deltaY;
+ scrolled = true;
+ }
+ if (scrolled) e_stop(e);
+ }
+
+ // Replace the range from from to to by the strings in newText.
+ // Afterwards, set the selection to selFrom, selTo.
+ function updateLines(from, to, newText, selFrom, selTo) {
+ if (suppressEdits) return;
+ if (history) {
+ var old = [];
+ doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); });
+ history.addChange(from.line, newText.length, old);
+ while (history.done.length > options.undoDepth) history.done.shift();
+ }
+ updateLinesNoUndo(from, to, newText, selFrom, selTo);
+ }
+ function unredoHelper(from, to) {
+ if (!from.length) return;
+ var set = from.pop(), out = [];
+ for (var i = set.length - 1; i >= 0; i -= 1) {
+ var change = set[i];
+ var replaced = [], end = change.start + change.added;
+ doc.iter(change.start, end, function(line) { replaced.push(line.text); });
+ out.push({start: change.start, added: change.old.length, old: replaced});
+ var pos = {line: change.start + change.old.length - 1,
+ ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])};
+ updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
+ }
+ updateInput = true;
+ to.push(out);
+ }
+ function undo() {unredoHelper(history.done, history.undone);}
+ function redo() {unredoHelper(history.undone, history.done);}
+
+ function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
+ if (suppressEdits) return;
+ var recomputeMaxLength = false, maxLineLength = maxLine.length;
+ if (!options.lineWrapping)
+ doc.iter(from.line, to.line + 1, function(line) {
+ if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
+ });
+ if (from.line != to.line || newText.length > 1) gutterDirty = true;
+
+ var nlines = to.line - from.line, firstLine = getLine(from.line), lastLine = getLine(to.line);
+ // First adjust the line structure, taking some care to leave highlighting intact.
+ if (from.ch == 0 && to.ch == 0 && newText[newText.length - 1] == "") {
+ // This is a whole-line replace. Treated specially to make
+ // sure line objects move the way they are supposed to.
+ var added = [], prevLine = null;
+ if (from.line) {
+ prevLine = getLine(from.line - 1);
+ prevLine.fixMarkEnds(lastLine);
+ } else lastLine.fixMarkStarts();
+ for (var i = 0, e = newText.length - 1; i < e; ++i)
+ added.push(Line.inheritMarks(newText[i], prevLine));
+ if (nlines) doc.remove(from.line, nlines, callbacks);
+ if (added.length) doc.insert(from.line, added);
+ } else if (firstLine == lastLine) {
+ if (newText.length == 1)
+ firstLine.replace(from.ch, to.ch, newText[0]);
+ else {
+ lastLine = firstLine.split(to.ch, newText[newText.length-1]);
+ firstLine.replace(from.ch, null, newText[0]);
+ firstLine.fixMarkEnds(lastLine);
+ var added = [];
+ for (var i = 1, e = newText.length - 1; i < e; ++i)
+ added.push(Line.inheritMarks(newText[i], firstLine));
+ added.push(lastLine);
+ doc.insert(from.line + 1, added);
+ }
+ } else if (newText.length == 1) {
+ firstLine.replace(from.ch, null, newText[0]);
+ lastLine.replace(null, to.ch, "");
+ firstLine.append(lastLine);
+ doc.remove(from.line + 1, nlines, callbacks);
+ } else {
+ var added = [];
+ firstLine.replace(from.ch, null, newText[0]);
+ lastLine.replace(null, to.ch, newText[newText.length-1]);
+ firstLine.fixMarkEnds(lastLine);
+ for (var i = 1, e = newText.length - 1; i < e; ++i)
+ added.push(Line.inheritMarks(newText[i], firstLine));
+ if (nlines > 1) doc.remove(from.line + 1, nlines - 1, callbacks);
+ doc.insert(from.line + 1, added);
+ }
+ if (options.lineWrapping) {
+ var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3);
+ doc.iter(from.line, from.line + newText.length, function(line) {
+ if (line.hidden) return;
+ var guess = Math.ceil(line.text.length / perLine) || 1;
+ if (guess != line.height) updateLineHeight(line, guess);
+ });
+ } else {
+ doc.iter(from.line, from.line + newText.length, function(line) {
+ var l = line.text;
+ if (!line.hidden && l.length > maxLineLength) {
+ maxLine = l; maxLineLength = l.length; maxLineChanged = true;
+ recomputeMaxLength = false;
+ }
+ });
+ if (recomputeMaxLength) updateMaxLine = true;
+ }
+
+ // Add these lines to the work array, so that they will be
+ // highlighted. Adjust work lines if lines were added/removed.
+ var newWork = [], lendiff = newText.length - nlines - 1;
+ for (var i = 0, l = work.length; i < l; ++i) {
+ var task = work[i];
+ if (task < from.line) newWork.push(task);
+ else if (task > to.line) newWork.push(task + lendiff);
+ }
+ var hlEnd = from.line + Math.min(newText.length, 500);
+ highlightLines(from.line, hlEnd);
+ newWork.push(hlEnd);
+ work = newWork;
+ startWorker(100);
+ // Remember that these lines changed, for updating the display
+ changes.push({from: from.line, to: to.line + 1, diff: lendiff});
+ var changeObj = {from: from, to: to, text: newText};
+ if (textChanged) {
+ for (var cur = textChanged; cur.next; cur = cur.next) {}
+ cur.next = changeObj;
+ } else textChanged = changeObj;
+
+ // Update the selection
+ function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
+ setSelection(clipPos(selFrom), clipPos(selTo),
+ updateLine(sel.from.line), updateLine(sel.to.line));
+ }
+
+ function updateVerticalScroll(scrollTop) {
+ var th = textHeight(), virtualHeight = Math.floor(doc.height * th + 2 * paddingTop()), scrollbarHeight = scroller.clientHeight;
+ scrollbar.style.height = scrollbarHeight + "px";
+ if (scroller.clientHeight)
+ scrollbarInner.style.height = virtualHeight + "px";
+ // Position the mover div to align with the current virtual scroll position
+ if (scrollTop != null) scrollbar.scrollTop = scrollTop;
+ mover.style.top = (displayOffset * th - scrollbar.scrollTop) + "px";
+ scrollbar.style.display = (virtualHeight > scrollbarHeight) ? "block" : "none";
+ }
+
+ // On Mac OS X Lion and up, detect whether the mouse is plugged in by measuring
+ // the width of a div with a scrollbar in it. If the width is <= 1, then
+ // the mouse isn't plugged in and scrollbars should overlap the content.
+ function overlapScrollbars() {
+ var tmpSb = document.createElement('div'),
+ tmpSbInner = document.createElement('div');
+ tmpSb.className = "CodeMirror-scrollbar";
+ tmpSb.style.cssText = "position: absolute; left: -9999px; height: 100px;";
+ tmpSbInner.className = "CodeMirror-scrollbar-inner";
+ tmpSbInner.style.height = "200px";
+ tmpSb.appendChild(tmpSbInner);
+
+ document.body.appendChild(tmpSb);
+ var result = (tmpSb.offsetWidth <= 1);
+ document.body.removeChild(tmpSb);
+ return result;
+ }
+
+ function computeMaxLength() {
+ var maxLineLength = 0;
+ maxLine = ""; maxLineChanged = true;
+ doc.iter(0, doc.size, function(line) {
+ var l = line.text;
+ if (!line.hidden && l.length > maxLineLength) {
+ maxLineLength = l.length; maxLine = l;
+ }
+ });
+ updateMaxLine = false;
+ }
+
+ function replaceRange(code, from, to) {
+ from = clipPos(from);
+ if (!to) to = from; else to = clipPos(to);
+ code = splitLines(code);
+ function adjustPos(pos) {
+ if (posLess(pos, from)) return pos;
+ if (!posLess(to, pos)) return end;
+ var line = pos.line + code.length - (to.line - from.line) - 1;
+ var ch = pos.ch;
+ if (pos.line == to.line)
+ ch += code[code.length-1].length - (to.ch - (to.line == from.line ? from.ch : 0));
+ return {line: line, ch: ch};
+ }
+ var end;
+ replaceRange1(code, from, to, function(end1) {
+ end = end1;
+ return {from: adjustPos(sel.from), to: adjustPos(sel.to)};
+ });
+ return end;
+ }
+ function replaceSelection(code, collapse) {
+ replaceRange1(splitLines(code), sel.from, sel.to, function(end) {
+ if (collapse == "end") return {from: end, to: end};
+ else if (collapse == "start") return {from: sel.from, to: sel.from};
+ else return {from: sel.from, to: end};
+ });
+ }
+ function replaceRange1(code, from, to, computeSel) {
+ var endch = code.length == 1 ? code[0].length + from.ch : code[code.length-1].length;
+ var newSel = computeSel({line: from.line + code.length - 1, ch: endch});
+ updateLines(from, to, code, newSel.from, newSel.to);
+ }
+
+ function getRange(from, to) {
+ var l1 = from.line, l2 = to.line;
+ if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch);
+ var code = [getLine(l1).text.slice(from.ch)];
+ doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
+ code.push(getLine(l2).text.slice(0, to.ch));
+ return code.join("\n");
+ }
+ function getSelection() {
+ return getRange(sel.from, sel.to);
+ }
+
+ var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
+ function slowPoll() {
+ if (pollingFast) return;
+ poll.set(options.pollInterval, function() {
+ startOperation();
+ readInput();
+ if (focused) slowPoll();
+ endOperation();
+ });
+ }
+ function fastPoll() {
+ var missed = false;
+ pollingFast = true;
+ function p() {
+ startOperation();
+ var changed = readInput();
+ if (!changed && !missed) {missed = true; poll.set(60, p);}
+ else {pollingFast = false; slowPoll();}
+ endOperation();
+ }
+ poll.set(20, p);
+ }
+
+ // Previnput is a hack to work with IME. If we reset the textarea
+ // on every change, that breaks IME. So we look for changes
+ // compared to the previous content instead. (Modern browsers have
+ // events that indicate IME taking place, but these are not widely
+ // supported or compatible enough yet to rely on.)
+ var prevInput = "";
+ function readInput() {
+ if (leaveInputAlone || !focused || hasSelection(input) || options.readOnly) return false;
+ var text = input.value;
+ if (text == prevInput) return false;
+ shiftSelecting = null;
+ var same = 0, l = Math.min(prevInput.length, text.length);
+ while (same < l && prevInput[same] == text[same]) ++same;
+ if (same < prevInput.length)
+ sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)};
+ else if (overwrite && posEq(sel.from, sel.to))
+ sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
+ replaceSelection(text.slice(same), "end");
+ if (text.length > 1000) { input.value = prevInput = ""; }
+ else prevInput = text;
+ return true;
+ }
+ function resetInput(user) {
+ if (!posEq(sel.from, sel.to)) {
+ prevInput = "";
+ input.value = getSelection();
+ selectInput(input);
+ } else if (user) prevInput = input.value = "";
+ }
+
+ function focusInput() {
+ if (options.readOnly != "nocursor") input.focus();
+ }
+
+ function scrollEditorIntoView() {
+ if (!cursor.getBoundingClientRect) return;
+ var rect = cursor.getBoundingClientRect();
+ // IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
+ if (ie && rect.top == rect.bottom) return;
+ var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
+ if (rect.top < 0 || rect.bottom > winH) scrollCursorIntoView();
+ }
+ function scrollCursorIntoView() {
+ var coords = calculateCursorCoords();
+ return scrollIntoView(coords.x, coords.y, coords.x, coords.yBot);
+ }
+ function calculateCursorCoords() {
+ var cursor = localCoords(sel.inverted ? sel.from : sel.to);
+ var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
+ return {x: x, y: cursor.y, yBot: cursor.yBot};
+ }
+ function scrollIntoView(x1, y1, x2, y2) {
+ var scrollPos = calculateScrollPos(x1, y1, x2, y2), scrolled = false;
+ if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft; scrolled = true;}
+ if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scrollPos.scrollTop; scrolled = true;}
+ if (scrolled && options.onScroll) options.onScroll(instance);
+ }
+ function calculateScrollPos(x1, y1, x2, y2) {
+ var pl = paddingLeft(), pt = paddingTop();
+ y1 += pt; y2 += pt; x1 += pl; x2 += pl;
+ var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {};
+ var atTop = y1 < paddingTop() + 10;
+ if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
+ else if (y2 > screentop + screen) result.scrollTop = y2 - screen;
+
+ var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
+ var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
+ var atLeft = x1 < gutterw + pl + 10;
+ if (x1 < screenleft + gutterw || atLeft) {
+ if (atLeft) x1 = 0;
+ result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
+ } else if (x2 > screenw + screenleft - 3) {
+ result.scrollLeft = x2 + 10 - screenw;
+ }
+ return result;
+ }
+
+ function visibleLines(scrollTop) {
+ var lh = textHeight(), top = (scrollTop != null ? scrollTop : scrollbar.scrollTop) - paddingTop();
+ var fromHeight = Math.max(0, Math.floor(top / lh));
+ var toHeight = Math.ceil((top + scroller.clientHeight) / lh);
+ return {from: lineAtHeight(doc, fromHeight),
+ to: lineAtHeight(doc, toHeight)};
+ }
+ // Uses a set of changes plus the current scroll position to
+ // determine which DOM updates have to be made, and makes the
+ // updates.
+ function updateDisplay(changes, suppressCallback, scrollTop) {
+ if (!scroller.clientWidth) {
+ showingFrom = showingTo = displayOffset = 0;
+ return;
+ }
+ // Compute the new visible window
+ // If scrollTop is specified, use that to determine which lines
+ // to render instead of the current scrollbar position.
+ var visible = visibleLines(scrollTop);
+ // Bail out if the visible area is already rendered and nothing changed.
+ if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) {
+ updateVerticalScroll(scrollTop);
+ return;
+ }
+ var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
+ if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
+ if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
+
+ // Create a range of theoretically intact lines, and punch holes
+ // in that using the change info.
+ var intact = changes === true ? [] :
+ computeIntact([{from: showingFrom, to: showingTo, domStart: 0}], changes);
+ // Clip off the parts that won't be visible
+ var intactLines = 0;
+ for (var i = 0; i < intact.length; ++i) {
+ var range = intact[i];
+ if (range.from < from) {range.domStart += (from - range.from); range.from = from;}
+ if (range.to > to) range.to = to;
+ if (range.from >= range.to) intact.splice(i--, 1);
+ else intactLines += range.to - range.from;
+ }
+ if (intactLines == to - from && from == showingFrom && to == showingTo) {
+ updateVerticalScroll(scrollTop);
+ return;
+ }
+ intact.sort(function(a, b) {return a.domStart - b.domStart;});
+
+ var th = textHeight(), gutterDisplay = gutter.style.display;
+ lineDiv.style.display = "none";
+ patchDisplay(from, to, intact);
+ lineDiv.style.display = gutter.style.display = "";
+
+ var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
+ // This is just a bogus formula that detects when the editor is
+ // resized or the font size changes.
+ if (different) lastSizeC = scroller.clientHeight + th;
+ showingFrom = from; showingTo = to;
+ displayOffset = heightAtLine(doc, from);
+
+ // Since this is all rather error prone, it is honoured with the
+ // only assertion in the whole file.
+ if (lineDiv.childNodes.length != showingTo - showingFrom)
+ throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) +
+ " nodes=" + lineDiv.childNodes.length);
+
+ function checkHeights() {
+ var curNode = lineDiv.firstChild, heightChanged = false;
+ doc.iter(showingFrom, showingTo, function(line) {
+ if (!line.hidden) {
+ var height = Math.round(curNode.offsetHeight / th) || 1;
+ if (line.height != height) {
+ updateLineHeight(line, height);
+ gutterDirty = heightChanged = true;
+ }
+ }
+ curNode = curNode.nextSibling;
+ });
+ return heightChanged;
+ }
+
+ if (options.lineWrapping) {
+ // Guess whether we're going to need the scrollbar, so that we don't end up changing the linewrapping
+ // after the scrollbar appears (during updateVerticalScroll()). Only do this if the scrollbar is
+ // appearing (if it's disappearing, we don't have to worry about the scroll position, and there are
+ // issues on IE7 if we turn it off too early).
+ var virtualHeight = Math.floor(doc.height * th + 2 * paddingTop()), scrollbarHeight = scroller.clientHeight;
+ if (virtualHeight > scrollbarHeight) scrollbar.style.display = "block";
+ checkHeights();
+ }
+
+ gutter.style.display = gutterDisplay;
+ if (different || gutterDirty) {
+ // If the gutter grew in size, re-check heights. If those changed, re-draw gutter.
+ updateGutter() && options.lineWrapping && checkHeights() && updateGutter();
+ }
+ updateSelection();
+ updateVerticalScroll(scrollTop);
+ if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
+ return true;
+ }
+
+ function computeIntact(intact, changes) {
+ for (var i = 0, l = changes.length || 0; i < l; ++i) {
+ var change = changes[i], intact2 = [], diff = change.diff || 0;
+ for (var j = 0, l2 = intact.length; j < l2; ++j) {
+ var range = intact[j];
+ if (change.to <= range.from && change.diff)
+ intact2.push({from: range.from + diff, to: range.to + diff,
+ domStart: range.domStart});
+ else if (change.to <= range.from || change.from >= range.to)
+ intact2.push(range);
+ else {
+ if (change.from > range.from)
+ intact2.push({from: range.from, to: change.from, domStart: range.domStart});
+ if (change.to < range.to)
+ intact2.push({from: change.to + diff, to: range.to + diff,
+ domStart: range.domStart + (change.to - range.from)});
+ }
+ }
+ intact = intact2;
+ }
+ return intact;
+ }
+
+ function patchDisplay(from, to, intact) {
+ // The first pass removes the DOM nodes that aren't intact.
+ if (!intact.length) lineDiv.innerHTML = "";
+ else {
+ function killNode(node) {
+ var tmp = node.nextSibling;
+ node.parentNode.removeChild(node);
+ return tmp;
+ }
+ var domPos = 0, curNode = lineDiv.firstChild, n;
+ for (var i = 0; i < intact.length; ++i) {
+ var cur = intact[i];
+ while (cur.domStart > domPos) {curNode = killNode(curNode); domPos++;}
+ for (var j = 0, e = cur.to - cur.from; j < e; ++j) {curNode = curNode.nextSibling; domPos++;}
+ }
+ while (curNode) curNode = killNode(curNode);
+ }
+ // This pass fills in the lines that actually changed.
+ var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from;
+ var scratch = document.createElement("div");
+ doc.iter(from, to, function(line) {
+ if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
+ if (!nextIntact || nextIntact.from > j) {
+ if (line.hidden) var html = scratch.innerHTML = "<pre></pre>";
+ else {
+ var html = '<pre' + (line.className ? ' class="' + line.className + '"' : '') + '>'
+ + line.getHTML(makeTab) + '</pre>';
+ // Kludge to make sure the styled element lies behind the selection (by z-index)
+ if (line.bgClassName)
+ html = '<div style="position: relative"><pre class="' + line.bgClassName +
+ '" style="position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2">&#160;</pre>' + html + "</div>";
+ }
+ scratch.innerHTML = html;
+ lineDiv.insertBefore(scratch.firstChild, curNode);
+ } else {
+ curNode = curNode.nextSibling;
+ }
+ ++j;
+ });
+ }
+
+ function updateGutter() {
+ if (!options.gutter && !options.lineNumbers) return;
+ var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
+ gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
+ var html = [], i = showingFrom, normalNode;
+ doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) {
+ if (line.hidden) {
+ html.push("<pre></pre>");
+ } else {
+ var marker = line.gutterMarker;
+ var text = options.lineNumbers ? i + options.firstLineNumber : null;
+ if (marker && marker.text)
+ text = marker.text.replace("%N%", text != null ? text : "");
+ else if (text == null)
+ text = "\u00a0";
+ html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text);
+ for (var j = 1; j < line.height; ++j) html.push("<br/>&#160;");
+ html.push("</pre>");
+ if (!marker) normalNode = i;
+ }
+ ++i;
+ });
+ gutter.style.display = "none";
+ gutterText.innerHTML = html.join("");
+ // Make sure scrolling doesn't cause number gutter size to pop
+ if (normalNode != null && options.lineNumbers) {
+ var node = gutterText.childNodes[normalNode - showingFrom];
+ var minwidth = String(doc.size).length, val = eltText(node.firstChild), pad = "";
+ while (val.length + pad.length < minwidth) pad += "\u00a0";
+ if (pad) node.insertBefore(document.createTextNode(pad), node.firstChild);
+ }
+ gutter.style.display = "";
+ var resized = Math.abs((parseInt(lineSpace.style.marginLeft) || 0) - gutter.offsetWidth) > 2;
+ lineSpace.style.marginLeft = gutter.offsetWidth + "px";
+ gutterDirty = false;
+ return resized;
+ }
+ function updateSelection() {
+ var collapsed = posEq(sel.from, sel.to);
+ var fromPos = localCoords(sel.from, true);
+ var toPos = collapsed ? fromPos : localCoords(sel.to, true);
+ var headPos = sel.inverted ? fromPos : toPos, th = textHeight();
+ var wrapOff = eltOffset(wrapper), lineOff = eltOffset(lineDiv);
+ inputDiv.style.top = Math.max(0, Math.min(scroller.offsetHeight, headPos.y + lineOff.top - wrapOff.top)) + "px";
+ inputDiv.style.left = Math.max(0, Math.min(scroller.offsetWidth, headPos.x + lineOff.left - wrapOff.left)) + "px";
+ if (collapsed) {
+ cursor.style.top = headPos.y + "px";
+ cursor.style.left = (options.lineWrapping ? Math.min(headPos.x, lineSpace.offsetWidth) : headPos.x) + "px";
+ cursor.style.display = "";
+ selectionDiv.style.display = "none";
+ } else {
+ var sameLine = fromPos.y == toPos.y, html = "";
+ var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth;
+ var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight;
+ function add(left, top, right, height) {
+ var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px"
+ : "right: " + right + "px";
+ html += '<div class="CodeMirror-selected" style="position: absolute; left: ' + left +
+ 'px; top: ' + top + 'px; ' + rstyle + '; height: ' + height + 'px"></div>';
+ }
+ if (sel.from.ch && fromPos.y >= 0) {
+ var right = sameLine ? clientWidth - toPos.x : 0;
+ add(fromPos.x, fromPos.y, right, th);
+ }
+ var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0));
+ var middleHeight = Math.min(toPos.y, clientHeight) - middleStart;
+ if (middleHeight > 0.2 * th)
+ add(0, middleStart, 0, middleHeight);
+ if ((!sameLine || !sel.from.ch) && toPos.y < clientHeight - .5 * th)
+ add(0, toPos.y, clientWidth - toPos.x, th);
+ selectionDiv.innerHTML = html;
+ cursor.style.display = "none";
+ selectionDiv.style.display = "";
+ }
+ }
+
+ function setShift(val) {
+ if (val) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
+ else shiftSelecting = null;
+ }
+ function setSelectionUser(from, to) {
+ var sh = shiftSelecting && clipPos(shiftSelecting);
+ if (sh) {
+ if (posLess(sh, from)) from = sh;
+ else if (posLess(to, sh)) to = sh;
+ }
+ setSelection(from, to);
+ userSelChange = true;
+ }
+ // Update the selection. Last two args are only used by
+ // updateLines, since they have to be expressed in the line
+ // numbers before the update.
+ function setSelection(from, to, oldFrom, oldTo) {
+ goalColumn = null;
+ if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
+ if (posEq(sel.from, from) && posEq(sel.to, to)) return;
+ if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
+
+ // Skip over hidden lines.
+ if (from.line != oldFrom) {
+ var from1 = skipHidden(from, oldFrom, sel.from.ch);
+ // If there is no non-hidden line left, force visibility on current line
+ if (!from1) setLineHidden(from.line, false);
+ else from = from1;
+ }
+ if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
+
+ if (posEq(from, to)) sel.inverted = false;
+ else if (posEq(from, sel.to)) sel.inverted = false;
+ else if (posEq(to, sel.from)) sel.inverted = true;
+
+ if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) {
+ var head = sel.inverted ? from : to;
+ if (head.line != sel.from.line && sel.from.line < doc.size) {
+ var oldLine = getLine(sel.from.line);
+ if (/^\s+$/.test(oldLine.text))
+ setTimeout(operation(function() {
+ if (oldLine.parent && /^\s+$/.test(oldLine.text)) {
+ var no = lineNo(oldLine);
+ replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length});
+ }
+ }, 10));
+ }
+ }
+
+ sel.from = from; sel.to = to;
+ selectionChanged = true;
+ }
+ function skipHidden(pos, oldLine, oldCh) {
+ function getNonHidden(dir) {
+ var lNo = pos.line + dir, end = dir == 1 ? doc.size : -1;
+ while (lNo != end) {
+ var line = getLine(lNo);
+ if (!line.hidden) {
+ var ch = pos.ch;
+ if (toEnd || ch > oldCh || ch > line.text.length) ch = line.text.length;
+ return {line: lNo, ch: ch};
+ }
+ lNo += dir;
+ }
+ }
+ var line = getLine(pos.line);
+ var toEnd = pos.ch == line.text.length && pos.ch != oldCh;
+ if (!line.hidden) return pos;
+ if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
+ else return getNonHidden(-1) || getNonHidden(1);
+ }
+ function setCursor(line, ch, user) {
+ var pos = clipPos({line: line, ch: ch || 0});
+ (user ? setSelectionUser : setSelection)(pos, pos);
+ }
+
+ function clipLine(n) {return Math.max(0, Math.min(n, doc.size-1));}
+ function clipPos(pos) {
+ if (pos.line < 0) return {line: 0, ch: 0};
+ if (pos.line >= doc.size) return {line: doc.size-1, ch: getLine(doc.size-1).text.length};
+ var ch = pos.ch, linelen = getLine(pos.line).text.length;
+ if (ch == null || ch > linelen) return {line: pos.line, ch: linelen};
+ else if (ch < 0) return {line: pos.line, ch: 0};
+ else return pos;
+ }
+
+ function findPosH(dir, unit) {
+ var end = sel.inverted ? sel.from : sel.to, line = end.line, ch = end.ch;
+ var lineObj = getLine(line);
+ function findNextLine() {
+ for (var l = line + dir, e = dir < 0 ? -1 : doc.size; l != e; l += dir) {
+ var lo = getLine(l);
+ if (!lo.hidden) { line = l; lineObj = lo; return true; }
+ }
+ }
+ function moveOnce(boundToLine) {
+ if (ch == (dir < 0 ? 0 : lineObj.text.length)) {
+ if (!boundToLine && findNextLine()) ch = dir < 0 ? lineObj.text.length : 0;
+ else return false;
+ } else ch += dir;
+ return true;
+ }
+ if (unit == "char") moveOnce();
+ else if (unit == "column") moveOnce(true);
+ else if (unit == "word") {
+ var sawWord = false;
+ for (;;) {
+ if (dir < 0) if (!moveOnce()) break;
+ if (isWordChar(lineObj.text.charAt(ch))) sawWord = true;
+ else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;}
+ if (dir > 0) if (!moveOnce()) break;
+ }
+ }
+ return {line: line, ch: ch};
+ }
+ function moveH(dir, unit) {
+ var pos = dir < 0 ? sel.from : sel.to;
+ if (shiftSelecting || posEq(sel.from, sel.to)) pos = findPosH(dir, unit);
+ setCursor(pos.line, pos.ch, true);
+ }
+ function deleteH(dir, unit) {
+ if (!posEq(sel.from, sel.to)) replaceRange("", sel.from, sel.to);
+ else if (dir < 0) replaceRange("", findPosH(dir, unit), sel.to);
+ else replaceRange("", sel.from, findPosH(dir, unit));
+ userSelChange = true;
+ }
+ var goalColumn = null;
+ function moveV(dir, unit) {
+ var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true);
+ if (goalColumn != null) pos.x = goalColumn;
+ if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight);
+ else if (unit == "line") dist = textHeight();
+ var target = coordsChar(pos.x, pos.y + dist * dir + 2);
+ if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y;
+ setCursor(target.line, target.ch, true);
+ goalColumn = pos.x;
+ }
+
+ function selectWordAt(pos) {
+ var line = getLine(pos.line).text;
+ var start = pos.ch, end = pos.ch;
+ while (start > 0 && isWordChar(line.charAt(start - 1))) --start;
+ while (end < line.length && isWordChar(line.charAt(end))) ++end;
+ setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end});
+ }
+ function selectLine(line) {
+ setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0}));
+ }
+ function indentSelected(mode) {
+ if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
+ var e = sel.to.line - (sel.to.ch ? 0 : 1);
+ for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
+ }
+
+ function indentLine(n, how) {
+ if (!how) how = "add";
+ if (how == "smart") {
+ if (!mode.indent) how = "prev";
+ else var state = getStateBefore(n);
+ }
+
+ var line = getLine(n), curSpace = line.indentation(options.tabSize),
+ curSpaceString = line.text.match(/^\s*/)[0], indentation;
+ if (how == "smart") {
+ indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
+ if (indentation == Pass) how = "prev";
+ }
+ if (how == "prev") {
+ if (n) indentation = getLine(n-1).indentation(options.tabSize);
+ else indentation = 0;
+ }
+ else if (how == "add") indentation = curSpace + options.indentUnit;
+ else if (how == "subtract") indentation = curSpace - options.indentUnit;
+ indentation = Math.max(0, indentation);
+ var diff = indentation - curSpace;
+
+ if (!diff) {
+ if (sel.from.line != n && sel.to.line != n) return;
+ var indentString = curSpaceString;
+ } else {
+ var indentString = "", pos = 0;
+ if (options.indentWithTabs)
+ for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
+ while (pos < indentation) {++pos; indentString += " ";}
+ }
+
+ replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
+ }
+
+ function loadMode() {
+ mode = CodeMirror.getMode(options, options.mode);
+ doc.iter(0, doc.size, function(line) { line.stateAfter = null; });
+ work = [0];
+ startWorker();
+ }
+ function gutterChanged() {
+ var visible = options.gutter || options.lineNumbers;
+ gutter.style.display = visible ? "" : "none";
+ if (visible) gutterDirty = true;
+ else lineDiv.parentNode.style.marginLeft = 0;
+ }
+ function wrappingChanged(from, to) {
+ if (options.lineWrapping) {
+ wrapper.className += " CodeMirror-wrap";
+ var perLine = scroller.clientWidth / charWidth() - 3;
+ doc.iter(0, doc.size, function(line) {
+ if (line.hidden) return;
+ var guess = Math.ceil(line.text.length / perLine) || 1;
+ if (guess != 1) updateLineHeight(line, guess);
+ });
+ lineSpace.style.width = code.style.width = "";
+ widthForcer.style.left = "";
+ } else {
+ wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
+ maxLine = ""; maxLineChanged = true;
+ doc.iter(0, doc.size, function(line) {
+ if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
+ if (line.text.length > maxLine.length) maxLine = line.text;
+ });
+ }
+ changes.push({from: 0, to: doc.size});
+ }
+ function makeTab(col) {
+ var w = options.tabSize - col % options.tabSize, cached = tabCache[w];
+ if (cached) return cached;
+ for (var str = '<span class="cm-tab">', i = 0; i < w; ++i) str += " ";
+ return (tabCache[w] = {html: str + "</span>", width: w});
+ }
+ function themeChanged() {
+ scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
+ options.theme.replace(/(^|\s)\s*/g, " cm-s-");
+ }
+ function keyMapChanged() {
+ var style = keyMap[options.keyMap].style;
+ wrapper.className = wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
+ (style ? " cm-keymap-" + style : "");
+ }
+
+ function TextMarker() { this.set = []; }
+ TextMarker.prototype.clear = operation(function() {
+ var min = Infinity, max = -Infinity;
+ for (var i = 0, e = this.set.length; i < e; ++i) {
+ var line = this.set[i], mk = line.marked;
+ if (!mk || !line.parent) continue;
+ var lineN = lineNo(line);
+ min = Math.min(min, lineN); max = Math.max(max, lineN);
+ for (var j = 0; j < mk.length; ++j)
+ if (mk[j].marker == this) mk.splice(j--, 1);
+ }
+ if (min != Infinity)
+ changes.push({from: min, to: max + 1});
+ });
+ TextMarker.prototype.find = function() {
+ var from, to;
+ for (var i = 0, e = this.set.length; i < e; ++i) {
+ var line = this.set[i], mk = line.marked;
+ for (var j = 0; j < mk.length; ++j) {
+ var mark = mk[j];
+ if (mark.marker == this) {
+ if (mark.from != null || mark.to != null) {
+ var found = lineNo(line);
+ if (found != null) {
+ if (mark.from != null) from = {line: found, ch: mark.from};
+ if (mark.to != null) to = {line: found, ch: mark.to};
+ }
+ }
+ }
+ }
+ }
+ return {from: from, to: to};
+ };
+
+ function markText(from, to, className) {
+ from = clipPos(from); to = clipPos(to);
+ var tm = new TextMarker();
+ if (!posLess(from, to)) return tm;
+ function add(line, from, to, className) {
+ getLine(line).addMark(new MarkedText(from, to, className, tm));
+ }
+ if (from.line == to.line) add(from.line, from.ch, to.ch, className);
+ else {
+ add(from.line, from.ch, null, className);
+ for (var i = from.line + 1, e = to.line; i < e; ++i)
+ add(i, null, null, className);
+ add(to.line, null, to.ch, className);
+ }
+ changes.push({from: from.line, to: to.line + 1});
+ return tm;
+ }
+
+ function setBookmark(pos) {
+ pos = clipPos(pos);
+ var bm = new Bookmark(pos.ch);
+ getLine(pos.line).addMark(bm);
+ return bm;
+ }
+
+ function findMarksAt(pos) {
+ pos = clipPos(pos);
+ var markers = [], marked = getLine(pos.line).marked;
+ if (!marked) return markers;
+ for (var i = 0, e = marked.length; i < e; ++i) {
+ var m = marked[i];
+ if ((m.from == null || m.from <= pos.ch) &&
+ (m.to == null || m.to >= pos.ch))
+ markers.push(m.marker || m);
+ }
+ return markers;
+ }
+
+ function addGutterMarker(line, text, className) {
+ if (typeof line == "number") line = getLine(clipLine(line));
+ line.gutterMarker = {text: text, style: className};
+ gutterDirty = true;
+ return line;
+ }
+ function removeGutterMarker(line) {
+ if (typeof line == "number") line = getLine(clipLine(line));
+ line.gutterMarker = null;
+ gutterDirty = true;
+ }
+
+ function changeLine(handle, op) {
+ var no = handle, line = handle;
+ if (typeof handle == "number") line = getLine(clipLine(handle));
+ else no = lineNo(handle);
+ if (no == null) return null;
+ if (op(line, no)) changes.push({from: no, to: no + 1});
+ else return null;
+ return line;
+ }
+ function setLineClass(handle, className, bgClassName) {
+ return changeLine(handle, function(line) {
+ if (line.className != className || line.bgClassName != bgClassName) {
+ line.className = className;
+ line.bgClassName = bgClassName;
+ return true;
+ }
+ });
+ }
+ function setLineHidden(handle, hidden) {
+ return changeLine(handle, function(line, no) {
+ if (line.hidden != hidden) {
+ line.hidden = hidden;
+ if (!options.lineWrapping) {
+ var l = line.text;
+ if (hidden && l.length == maxLine.length) {
+ updateMaxLine = true;
+ } else if (!hidden && l.length > maxLine.length) {
+ maxLine = l; maxWidth = null; updateMaxLine = false;
+ }
+ }
+ updateLineHeight(line, hidden ? 0 : 1);
+ var fline = sel.from.line, tline = sel.to.line;
+ if (hidden && (fline == no || tline == no)) {
+ var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from;
+ var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to;
+ // Can't hide the last visible line, we'd have no place to put the cursor
+ if (!to) return;
+ setSelection(from, to);
+ }
+ return (gutterDirty = true);
+ }
+ });
+ }
+
+ function lineInfo(line) {
+ if (typeof line == "number") {
+ if (!isLine(line)) return null;
+ var n = line;
+ line = getLine(line);
+ if (!line) return null;
+ } else {
+ var n = lineNo(line);
+ if (n == null) return null;
+ }
+ var marker = line.gutterMarker;
+ return {line: n, handle: line, text: line.text, markerText: marker && marker.text,
+ markerClass: marker && marker.style, lineClass: line.className, bgClass: line.bgClassName};
+ }
+
+ function stringWidth(str) {
+ measure.innerHTML = "<pre><span>x</span></pre>";
+ measure.firstChild.firstChild.firstChild.nodeValue = str;
+ return measure.firstChild.firstChild.offsetWidth || 10;
+ }
+ // These are used to go from pixel positions to character
+ // positions, taking varying character widths into account.
+ function charFromX(line, x) {
+ if (x <= 0) return 0;
+ var lineObj = getLine(line), text = lineObj.text;
+ function getX(len) {
+ return measureLine(lineObj, len).left;
+ }
+ var from = 0, fromX = 0, to = text.length, toX;
+ // Guess a suitable upper bound for our search.
+ var estimated = Math.min(to, Math.ceil(x / charWidth()));
+ for (;;) {
+ var estX = getX(estimated);
+ if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
+ else {toX = estX; to = estimated; break;}
+ }
+ if (x > toX) return to;
+ // Try to guess a suitable lower bound as well.
+ estimated = Math.floor(to * 0.8); estX = getX(estimated);
+ if (estX < x) {from = estimated; fromX = estX;}
+ // Do a binary search between these bounds.
+ for (;;) {
+ if (to - from <= 1) return (toX - x > x - fromX) ? from : to;
+ var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
+ if (middleX > x) {to = middle; toX = middleX;}
+ else {from = middle; fromX = middleX;}
+ }
+ }
+
+ var tempId = "CodeMirror-temp-" + Math.floor(Math.random() * 0xffffff).toString(16);
+ function measureLine(line, ch) {
+ if (ch == 0) return {top: 0, left: 0};
+ var wbr = options.lineWrapping && ch < line.text.length &&
+ spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
+ measure.innerHTML = "<pre>" + line.getHTML(makeTab, ch, tempId, wbr) + "</pre>";
+ var elt = document.getElementById(tempId);
+ var top = elt.offsetTop, left = elt.offsetLeft;
+ // Older IEs report zero offsets for spans directly after a wrap
+ if (ie && top == 0 && left == 0) {
+ var backup = document.createElement("span");
+ backup.innerHTML = "x";
+ elt.parentNode.insertBefore(backup, elt.nextSibling);
+ top = backup.offsetTop;
+ }
+ return {top: top, left: left};
+ }
+ function localCoords(pos, inLineWrap) {
+ var x, lh = textHeight(), y = lh * (heightAtLine(doc, pos.line) - (inLineWrap ? displayOffset : 0));
+ if (pos.ch == 0) x = 0;
+ else {
+ var sp = measureLine(getLine(pos.line), pos.ch);
+ x = sp.left;
+ if (options.lineWrapping) y += Math.max(0, sp.top);
+ }
+ return {x: x, y: y, yBot: y + lh};
+ }
+ // Coords must be lineSpace-local
+ function coordsChar(x, y) {
+ if (y < 0) y = 0;
+ var th = textHeight(), cw = charWidth(), heightPos = displayOffset + Math.floor(y / th);
+ var lineNo = lineAtHeight(doc, heightPos);
+ if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc.size - 1).text.length};
+ var lineObj = getLine(lineNo), text = lineObj.text;
+ var tw = options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0;
+ if (x <= 0 && innerOff == 0) return {line: lineNo, ch: 0};
+ function getX(len) {
+ var sp = measureLine(lineObj, len);
+ if (tw) {
+ var off = Math.round(sp.top / th);
+ return Math.max(0, sp.left + (off - innerOff) * scroller.clientWidth);
+ }
+ return sp.left;
+ }
+ var from = 0, fromX = 0, to = text.length, toX;
+ // Guess a suitable upper bound for our search.
+ var estimated = Math.min(to, Math.ceil((x + innerOff * scroller.clientWidth * .9) / cw));
+ for (;;) {
+ var estX = getX(estimated);
+ if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
+ else {toX = estX; to = estimated; break;}
+ }
+ if (x > toX) return {line: lineNo, ch: to};
+ // Try to guess a suitable lower bound as well.
+ estimated = Math.floor(to * 0.8); estX = getX(estimated);
+ if (estX < x) {from = estimated; fromX = estX;}
+ // Do a binary search between these bounds.
+ for (;;) {
+ if (to - from <= 1) return {line: lineNo, ch: (toX - x > x - fromX) ? from : to};
+ var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
+ if (middleX > x) {to = middle; toX = middleX;}
+ else {from = middle; fromX = middleX;}
+ }
+ }
+ function pageCoords(pos) {
+ var local = localCoords(pos, true), off = eltOffset(lineSpace);
+ return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
+ }
+
+ var cachedHeight, cachedHeightFor, measureText;
+ function textHeight() {
+ if (measureText == null) {
+ measureText = "<pre>";
+ for (var i = 0; i < 49; ++i) measureText += "x<br/>";
+ measureText += "x</pre>";
+ }
+ var offsetHeight = lineDiv.clientHeight;
+ if (offsetHeight == cachedHeightFor) return cachedHeight;
+ cachedHeightFor = offsetHeight;
+ measure.innerHTML = measureText;
+ cachedHeight = measure.firstChild.offsetHeight / 50 || 1;
+ measure.innerHTML = "";
+ return cachedHeight;
+ }
+ var cachedWidth, cachedWidthFor = 0;
+ function charWidth() {
+ if (scroller.clientWidth == cachedWidthFor) return cachedWidth;
+ cachedWidthFor = scroller.clientWidth;
+ return (cachedWidth = stringWidth("x"));
+ }
+ function paddingTop() {return lineSpace.offsetTop;}
+ function paddingLeft() {return lineSpace.offsetLeft;}
+
+ function posFromMouse(e, liberal) {
+ var offW = eltOffset(scroller, true), x, y;
+ // Fails unpredictably on IE[67] when mouse is dragged around quickly.
+ try { x = e.clientX; y = e.clientY; } catch (e) { return null; }
+ // This is a mess of a heuristic to try and determine whether a
+ // scroll-bar was clicked or not, and to return null if one was
+ // (and !liberal).
+ if (!liberal && (x - offW.left > scroller.clientWidth || y - offW.top > scroller.clientHeight))
+ return null;
+ var offL = eltOffset(lineSpace, true);
+ return coordsChar(x - offL.left, y - offL.top);
+ }
+ function onContextMenu(e) {
+ var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop;
+ if (!pos || opera) return; // Opera is difficult.
+ if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
+ operation(setCursor)(pos.line, pos.ch);
+
+ var oldCSS = input.style.cssText;
+ inputDiv.style.position = "absolute";
+ input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
+ "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " +
+ "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
+ leaveInputAlone = true;
+ var val = input.value = getSelection();
+ focusInput();
+ selectInput(input);
+ function rehide() {
+ var newVal = splitLines(input.value).join("\n");
+ if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end");
+ inputDiv.style.position = "relative";
+ input.style.cssText = oldCSS;
+ if (ie_lt9) scrollbar.scrollTop = scrollPos;
+ leaveInputAlone = false;
+ resetInput(true);
+ slowPoll();
+ }
+
+ if (gecko) {
+ e_stop(e);
+ var mouseup = connect(window, "mouseup", function() {
+ mouseup();
+ setTimeout(rehide, 20);
+ }, true);
+ } else {
+ setTimeout(rehide, 50);
+ }
+ }
+
+ // Cursor-blinking
+ function restartBlink() {
+ clearInterval(blinker);
+ var on = true;
+ cursor.style.visibility = "";
+ blinker = setInterval(function() {
+ cursor.style.visibility = (on = !on) ? "" : "hidden";
+ }, 650);
+ }
+
+ var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
+ function matchBrackets(autoclear) {
+ var head = sel.inverted ? sel.from : sel.to, line = getLine(head.line), pos = head.ch - 1;
+ var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
+ if (!match) return;
+ var ch = match.charAt(0), forward = match.charAt(1) == ">", d = forward ? 1 : -1, st = line.styles;
+ for (var off = pos + 1, i = 0, e = st.length; i < e; i+=2)
+ if ((off -= st[i].length) <= 0) {var style = st[i+1]; break;}
+
+ var stack = [line.text.charAt(pos)], re = /[(){}[\]]/;
+ function scan(line, from, to) {
+ if (!line.text) return;
+ var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
+ for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
+ var text = st[i];
+ if (st[i+1] != style) {pos += d * text.length; continue;}
+ for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
+ if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
+ var match = matching[cur];
+ if (match.charAt(1) == ">" == forward) stack.push(cur);
+ else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false};
+ else if (!stack.length) return {pos: pos, match: true};
+ }
+ }
+ }
+ }
+ for (var i = head.line, e = forward ? Math.min(i + 100, doc.size) : Math.max(-1, i - 100); i != e; i+=d) {
+ var line = getLine(i), first = i == head.line;
+ var found = scan(line, first && forward ? pos + 1 : 0, first && !forward ? pos : line.text.length);
+ if (found) break;
+ }
+ if (!found) found = {pos: null, match: false};
+ var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
+ var one = markText({line: head.line, ch: pos}, {line: head.line, ch: pos+1}, style),
+ two = found.pos != null && markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style);
+ var clear = operation(function(){one.clear(); two && two.clear();});
+ if (autoclear) setTimeout(clear, 800);
+ else bracketHighlighted = clear;
+ }
+
+ // Finds the line to start with when starting a parse. Tries to
+ // find a line with a stateAfter, so that it can start with a
+ // valid state. If that fails, it returns the line with the
+ // smallest indentation, which tends to need the least context to
+ // parse correctly.
+ function findStartLine(n) {
+ var minindent, minline;
+ for (var search = n, lim = n - 40; search > lim; --search) {
+ if (search == 0) return 0;
+ var line = getLine(search-1);
+ if (line.stateAfter) return search;
+ var indented = line.indentation(options.tabSize);
+ if (minline == null || minindent > indented) {
+ minline = search - 1;
+ minindent = indented;
+ }
+ }
+ return minline;
+ }
+ function getStateBefore(n) {
+ var start = findStartLine(n), state = start && getLine(start-1).stateAfter;
+ if (!state) state = startState(mode);
+ else state = copyState(mode, state);
+ doc.iter(start, n, function(line) {
+ line.highlight(mode, state, options.tabSize);
+ line.stateAfter = copyState(mode, state);
+ });
+ if (start < n) changes.push({from: start, to: n});
+ if (n < doc.size && !getLine(n).stateAfter) work.push(n);
+ return state;
+ }
+ function highlightLines(start, end) {
+ var state = getStateBefore(start);
+ doc.iter(start, end, function(line) {
+ line.highlight(mode, state, options.tabSize);
+ line.stateAfter = copyState(mode, state);
+ });
+ }
+ function highlightWorker() {
+ var end = +new Date + options.workTime;
+ var foundWork = work.length;
+ while (work.length) {
+ if (!getLine(showingFrom).stateAfter) var task = showingFrom;
+ else var task = work.pop();
+ if (task >= doc.size) continue;
+ var start = findStartLine(task), state = start && getLine(start-1).stateAfter;
+ if (state) state = copyState(mode, state);
+ else state = startState(mode);
+
+ var unchanged = 0, compare = mode.compareStates, realChange = false,
+ i = start, bail = false;
+ doc.iter(i, doc.size, function(line) {
+ var hadState = line.stateAfter;
+ if (+new Date > end) {
+ work.push(i);
+ startWorker(options.workDelay);
+ if (realChange) changes.push({from: task, to: i + 1});
+ return (bail = true);
+ }
+ var changed = line.highlight(mode, state, options.tabSize);
+ if (changed) realChange = true;
+ line.stateAfter = copyState(mode, state);
+ var done = null;
+ if (compare) {
+ var same = hadState && compare(hadState, state);
+ if (same != Pass) done = !!same;
+ }
+ if (done == null) {
+ if (changed !== false || !hadState) unchanged = 0;
+ else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
+ done = true;
+ }
+ if (done) return true;
+ ++i;
+ });
+ if (bail) return;
+ if (realChange) changes.push({from: task, to: i + 1});
+ }
+ if (foundWork && options.onHighlightComplete)
+ options.onHighlightComplete(instance);
+ }
+ function startWorker(time) {
+ if (!work.length) return;
+ highlight.set(time, operation(highlightWorker));
+ }
+
+ // Operations are used to wrap changes in such a way that each
+ // change won't have to update the cursor and display (which would
+ // be awkward, slow, and error-prone), but instead updates are
+ // batched and then all combined and executed at once.
+ function startOperation() {
+ updateInput = userSelChange = textChanged = null;
+ changes = []; selectionChanged = false; callbacks = [];
+ }
+ function endOperation() {
+ if (updateMaxLine) computeMaxLength();
+ if (maxLineChanged && !options.lineWrapping) {
+ widthForcer.style.left = stringWidth(maxLine) + "px";
+ maxLineChanged = false;
+ }
+ var newScrollPos, updated;
+ if (selectionChanged) {
+ var coords = calculateCursorCoords();
+ newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot);
+ }
+ if (changes.length) updated = updateDisplay(changes, true, (newScrollPos ? newScrollPos.scrollTop : null));
+ else {
+ if (selectionChanged) updateSelection();
+ if (gutterDirty) updateGutter();
+ }
+ if (newScrollPos) scrollCursorIntoView();
+ if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
+
+ if (focused && !leaveInputAlone &&
+ (updateInput === true || (updateInput !== false && selectionChanged)))
+ resetInput(userSelChange);
+
+ if (selectionChanged && options.matchBrackets)
+ setTimeout(operation(function() {
+ if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
+ if (posEq(sel.from, sel.to)) matchBrackets(false);
+ }), 20);
+ var sc = selectionChanged, cbs = callbacks; // these can be reset by callbacks
+ if (textChanged && options.onChange && instance)
+ options.onChange(instance, textChanged);
+ if (sc && options.onCursorActivity)
+ options.onCursorActivity(instance);
+ for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
+ if (updated && options.onUpdate) options.onUpdate(instance);
+ }
+ var nestedOperation = 0;
+ function operation(f) {
+ return function() {
+ if (!nestedOperation++) startOperation();
+ try {var result = f.apply(this, arguments);}
+ finally {if (!--nestedOperation) endOperation();}
+ return result;
+ };
+ }
+
+ function compoundChange(f) {
+ history.startCompound();
+ try { return f(); } finally { history.endCompound(); }
+ }
+
+ for (var ext in extensions)
+ if (extensions.propertyIsEnumerable(ext) &&
+ !instance.propertyIsEnumerable(ext))
+ instance[ext] = extensions[ext];
+ return instance;
+ } // (end of function CodeMirror)
+
+ // The default configuration options.
+ CodeMirror.defaults = {
+ value: "",
+ mode: null,
+ theme: "default",
+ indentUnit: 2,
+ indentWithTabs: false,
+ smartIndent: true,
+ tabSize: 4,
+ keyMap: "default",
+ extraKeys: null,
+ electricChars: true,
+ autoClearEmptyLines: false,
+ onKeyEvent: null,
+ onDragEvent: null,
+ lineWrapping: false,
+ lineNumbers: false,
+ gutter: false,
+ fixedGutter: false,
+ firstLineNumber: 1,
+ readOnly: false,
+ dragDrop: true,
+ onChange: null,
+ onCursorActivity: null,
+ onGutterClick: null,
+ onHighlightComplete: null,
+ onUpdate: null,
+ onFocus: null, onBlur: null, onScroll: null,
+ matchBrackets: false,
+ workTime: 100,
+ workDelay: 200,
+ pollInterval: 100,
+ undoDepth: 40,
+ tabindex: null,
+ autofocus: null
+ };
+
+ var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
+ var mac = ios || /Mac/.test(navigator.platform);
+ var win = /Win/.test(navigator.platform);
+
+ // Known modes, by name and by MIME
+ var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
+ CodeMirror.defineMode = function(name, mode) {
+ if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
+ if (arguments.length > 2) {
+ mode.dependencies = [];
+ for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
+ }
+ modes[name] = mode;
+ };
+ CodeMirror.defineMIME = function(mime, spec) {
+ mimeModes[mime] = spec;
+ };
+ CodeMirror.resolveMode = function(spec) {
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
+ spec = mimeModes[spec];
+ else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
+ return CodeMirror.resolveMode("application/xml");
+ if (typeof spec == "string") return {name: spec};
+ else return spec || {name: "null"};
+ };
+ CodeMirror.getMode = function(options, spec) {
+ var spec = CodeMirror.resolveMode(spec);
+ var mfactory = modes[spec.name];
+ if (!mfactory) return CodeMirror.getMode(options, "text/plain");
+ return mfactory(options, spec);
+ };
+ CodeMirror.listModes = function() {
+ var list = [];
+ for (var m in modes)
+ if (modes.propertyIsEnumerable(m)) list.push(m);
+ return list;
+ };
+ CodeMirror.listMIMEs = function() {
+ var list = [];
+ for (var m in mimeModes)
+ if (mimeModes.propertyIsEnumerable(m)) list.push({mime: m, mode: mimeModes[m]});
+ return list;
+ };
+
+ var extensions = CodeMirror.extensions = {};
+ CodeMirror.defineExtension = function(name, func) {
+ extensions[name] = func;
+ };
+
+ var commands = CodeMirror.commands = {
+ selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});},
+ killLine: function(cm) {
+ var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
+ if (!sel && cm.getLine(from.line).length == from.ch) cm.replaceRange("", from, {line: from.line + 1, ch: 0});
+ else cm.replaceRange("", from, sel ? to : {line: from.line});
+ },
+ deleteLine: function(cm) {var l = cm.getCursor().line; cm.replaceRange("", {line: l, ch: 0}, {line: l});},
+ undo: function(cm) {cm.undo();},
+ redo: function(cm) {cm.redo();},
+ goDocStart: function(cm) {cm.setCursor(0, 0, true);},
+ goDocEnd: function(cm) {cm.setSelection({line: cm.lineCount() - 1}, null, true);},
+ goLineStart: function(cm) {cm.setCursor(cm.getCursor().line, 0, true);},
+ goLineStartSmart: function(cm) {
+ var cur = cm.getCursor();
+ var text = cm.getLine(cur.line), firstNonWS = Math.max(0, text.search(/\S/));
+ cm.setCursor(cur.line, cur.ch <= firstNonWS && cur.ch ? 0 : firstNonWS, true);
+ },
+ goLineEnd: function(cm) {cm.setSelection({line: cm.getCursor().line}, null, true);},
+ goLineUp: function(cm) {cm.moveV(-1, "line");},
+ goLineDown: function(cm) {cm.moveV(1, "line");},
+ goPageUp: function(cm) {cm.moveV(-1, "page");},
+ goPageDown: function(cm) {cm.moveV(1, "page");},
+ goCharLeft: function(cm) {cm.moveH(-1, "char");},
+ goCharRight: function(cm) {cm.moveH(1, "char");},
+ goColumnLeft: function(cm) {cm.moveH(-1, "column");},
+ goColumnRight: function(cm) {cm.moveH(1, "column");},
+ goWordLeft: function(cm) {cm.moveH(-1, "word");},
+ goWordRight: function(cm) {cm.moveH(1, "word");},
+ delCharLeft: function(cm) {cm.deleteH(-1, "char");},
+ delCharRight: function(cm) {cm.deleteH(1, "char");},
+ delWordLeft: function(cm) {cm.deleteH(-1, "word");},
+ delWordRight: function(cm) {cm.deleteH(1, "word");},
+ indentAuto: function(cm) {cm.indentSelection("smart");},
+ indentMore: function(cm) {cm.indentSelection("add");},
+ indentLess: function(cm) {cm.indentSelection("subtract");},
+ insertTab: function(cm) {cm.replaceSelection("\t", "end");},
+ defaultTab: function(cm) {
+ if (cm.somethingSelected()) cm.indentSelection("add");
+ else cm.replaceSelection("\t", "end");
+ },
+ transposeChars: function(cm) {
+ var cur = cm.getCursor(), line = cm.getLine(cur.line);
+ if (cur.ch > 0 && cur.ch < line.length - 1)
+ cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
+ {line: cur.line, ch: cur.ch - 1}, {line: cur.line, ch: cur.ch + 1});
+ },
+ newlineAndIndent: function(cm) {
+ cm.replaceSelection("\n", "end");
+ cm.indentLine(cm.getCursor().line);
+ },
+ toggleOverwrite: function(cm) {cm.toggleOverwrite();}
+ };
+
+ var keyMap = CodeMirror.keyMap = {};
+ keyMap.basic = {
+ "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
+ "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
+ "Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
+ "Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
+ };
+ // Note that the save and find-related commands aren't defined by
+ // default. Unknown commands are simply ignored.
+ keyMap.pcDefault = {
+ "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
+ "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
+ "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
+ "Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
+ "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
+ "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
+ fallthrough: "basic"
+ };
+ keyMap.macDefault = {
+ "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
+ "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft",
+ "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
+ "Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
+ "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
+ "Cmd-[": "indentLess", "Cmd-]": "indentMore",
+ fallthrough: ["basic", "emacsy"]
+ };
+ keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
+ keyMap.emacsy = {
+ "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
+ "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
+ "Ctrl-V": "goPageUp", "Shift-Ctrl-V": "goPageDown", "Ctrl-D": "delCharRight", "Ctrl-H": "delCharLeft",
+ "Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
+ };
+
+ function getKeyMap(val) {
+ if (typeof val == "string") return keyMap[val];
+ else return val;
+ }
+ function lookupKey(name, extraMap, map, handle, stop) {
+ function lookup(map) {
+ map = getKeyMap(map);
+ var found = map[name];
+ if (found != null && handle(found)) return true;
+ if (map.nofallthrough) {
+ if (stop) stop();
+ return true;
+ }
+ var fallthrough = map.fallthrough;
+ if (fallthrough == null) return false;
+ if (Object.prototype.toString.call(fallthrough) != "[object Array]")
+ return lookup(fallthrough);
+ for (var i = 0, e = fallthrough.length; i < e; ++i) {
+ if (lookup(fallthrough[i])) return true;
+ }
+ return false;
+ }
+ if (extraMap && lookup(extraMap)) return true;
+ return lookup(map);
+ }
+ function isModifierKey(event) {
+ var name = keyNames[e_prop(event, "keyCode")];
+ return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
+ }
+
+ CodeMirror.fromTextArea = function(textarea, options) {
+ if (!options) options = {};
+ options.value = textarea.value;
+ if (!options.tabindex && textarea.tabindex)
+ options.tabindex = textarea.tabindex;
+ if (options.autofocus == null && textarea.getAttribute("autofocus") != null)
+ options.autofocus = true;
+
+ function save() {textarea.value = instance.getValue();}
+ if (textarea.form) {
+ // Deplorable hack to make the submit method do the right thing.
+ var rmSubmit = connect(textarea.form, "submit", save, true);
+ if (typeof textarea.form.submit == "function") {
+ var realSubmit = textarea.form.submit;
+ function wrappedSubmit() {
+ save();
+ textarea.form.submit = realSubmit;
+ textarea.form.submit();
+ textarea.form.submit = wrappedSubmit;
+ }
+ textarea.form.submit = wrappedSubmit;
+ }
+ }
+
+ textarea.style.display = "none";
+ var instance = CodeMirror(function(node) {
+ textarea.parentNode.insertBefore(node, textarea.nextSibling);
+ }, options);
+ instance.save = save;
+ instance.getTextArea = function() { return textarea; };
+ instance.toTextArea = function() {
+ save();
+ textarea.parentNode.removeChild(instance.getWrapperElement());
+ textarea.style.display = "";
+ if (textarea.form) {
+ rmSubmit();
+ if (typeof textarea.form.submit == "function")
+ textarea.form.submit = realSubmit;
+ }
+ };
+ return instance;
+ };
+
+ // Utility functions for working with state. Exported because modes
+ // sometimes need to do this.
+ function copyState(mode, state) {
+ if (state === true) return state;
+ if (mode.copyState) return mode.copyState(state);
+ var nstate = {};
+ for (var n in state) {
+ var val = state[n];
+ if (val instanceof Array) val = val.concat([]);
+ nstate[n] = val;
+ }
+ return nstate;
+ }
+ CodeMirror.copyState = copyState;
+ function startState(mode, a1, a2) {
+ return mode.startState ? mode.startState(a1, a2) : true;
+ }
+ CodeMirror.startState = startState;
+
+ // The character stream used by a mode's parser.
+ function StringStream(string, tabSize) {
+ this.pos = this.start = 0;
+ this.string = string;
+ this.tabSize = tabSize || 8;
+ }
+ StringStream.prototype = {
+ eol: function() {return this.pos >= this.string.length;},
+ sol: function() {return this.pos == 0;},
+ peek: function() {return this.string.charAt(this.pos);},
+ next: function() {
+ if (this.pos < this.string.length)
+ return this.string.charAt(this.pos++);
+ },
+ eat: function(match) {
+ var ch = this.string.charAt(this.pos);
+ if (typeof match == "string") var ok = ch == match;
+ else var ok = ch && (match.test ? match.test(ch) : match(ch));
+ if (ok) {++this.pos; return ch;}
+ },
+ eatWhile: function(match) {
+ var start = this.pos;
+ while (this.eat(match)){}
+ return this.pos > start;
+ },
+ eatSpace: function() {
+ var start = this.pos;
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
+ return this.pos > start;
+ },
+ skipToEnd: function() {this.pos = this.string.length;},
+ skipTo: function(ch) {
+ var found = this.string.indexOf(ch, this.pos);
+ if (found > -1) {this.pos = found; return true;}
+ },
+ backUp: function(n) {this.pos -= n;},
+ column: function() {return countColumn(this.string, this.start, this.tabSize);},
+ indentation: function() {return countColumn(this.string, null, this.tabSize);},
+ match: function(pattern, consume, caseInsensitive) {
+ if (typeof pattern == "string") {
+ function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
+ if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
+ if (consume !== false) this.pos += pattern.length;
+ return true;
+ }
+ } else {
+ var match = this.string.slice(this.pos).match(pattern);
+ if (match && consume !== false) this.pos += match[0].length;
+ return match;
+ }
+ },
+ current: function(){return this.string.slice(this.start, this.pos);}
+ };
+ CodeMirror.StringStream = StringStream;
+
+ function MarkedText(from, to, className, marker) {
+ this.from = from; this.to = to; this.style = className; this.marker = marker;
+ }
+ MarkedText.prototype = {
+ attach: function(line) { this.marker.set.push(line); },
+ detach: function(line) {
+ var ix = indexOf(this.marker.set, line);
+ if (ix > -1) this.marker.set.splice(ix, 1);
+ },
+ split: function(pos, lenBefore) {
+ if (this.to <= pos && this.to != null) return null;
+ var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
+ var to = this.to == null ? null : this.to - pos + lenBefore;
+ return new MarkedText(from, to, this.style, this.marker);
+ },
+ dup: function() { return new MarkedText(null, null, this.style, this.marker); },
+ clipTo: function(fromOpen, from, toOpen, to, diff) {
+ if (fromOpen && to > this.from && (to < this.to || this.to == null))
+ this.from = null;
+ else if (this.from != null && this.from >= from)
+ this.from = Math.max(to, this.from) + diff;
+ if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null))
+ this.to = null;
+ else if (this.to != null && this.to > from)
+ this.to = to < this.to ? this.to + diff : from;
+ },
+ isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
+ sameSet: function(x) { return this.marker == x.marker; }
+ };
+
+ function Bookmark(pos) {
+ this.from = pos; this.to = pos; this.line = null;
+ }
+ Bookmark.prototype = {
+ attach: function(line) { this.line = line; },
+ detach: function(line) { if (this.line == line) this.line = null; },
+ split: function(pos, lenBefore) {
+ if (pos < this.from) {
+ this.from = this.to = (this.from - pos) + lenBefore;
+ return this;
+ }
+ },
+ isDead: function() { return this.from > this.to; },
+ clipTo: function(fromOpen, from, toOpen, to, diff) {
+ if ((fromOpen || from < this.from) && (toOpen || to > this.to)) {
+ this.from = 0; this.to = -1;
+ } else if (this.from > from) {
+ this.from = this.to = Math.max(to, this.from) + diff;
+ }
+ },
+ sameSet: function(x) { return false; },
+ find: function() {
+ if (!this.line || !this.line.parent) return null;
+ return {line: lineNo(this.line), ch: this.from};
+ },
+ clear: function() {
+ if (this.line) {
+ var found = indexOf(this.line.marked, this);
+ if (found != -1) this.line.marked.splice(found, 1);
+ this.line = null;
+ }
+ }
+ };
+
+ // Line objects. These hold state related to a line, including
+ // highlighting info (the styles array).
+ function Line(text, styles) {
+ this.styles = styles || [text, null];
+ this.text = text;
+ this.height = 1;
+ this.marked = this.gutterMarker = this.className = this.bgClassName = this.handlers = null;
+ this.stateAfter = this.parent = this.hidden = null;
+ }
+ Line.inheritMarks = function(text, orig) {
+ var ln = new Line(text), mk = orig && orig.marked;
+ if (mk) {
+ for (var i = 0; i < mk.length; ++i) {
+ if (mk[i].to == null && mk[i].style) {
+ var newmk = ln.marked || (ln.marked = []), mark = mk[i];
+ var nmark = mark.dup(); newmk.push(nmark); nmark.attach(ln);
+ }
+ }
+ }
+ return ln;
+ }
+ Line.prototype = {
+ // Replace a piece of a line, keeping the styles around it intact.
+ replace: function(from, to_, text) {
+ var st = [], mk = this.marked, to = to_ == null ? this.text.length : to_;
+ copyStyles(0, from, this.styles, st);
+ if (text) st.push(text, null);
+ copyStyles(to, this.text.length, this.styles, st);
+ this.styles = st;
+ this.text = this.text.slice(0, from) + text + this.text.slice(to);
+ this.stateAfter = null;
+ if (mk) {
+ var diff = text.length - (to - from);
+ for (var i = 0; i < mk.length; ++i) {
+ var mark = mk[i];
+ mark.clipTo(from == null, from || 0, to_ == null, to, diff);
+ if (mark.isDead()) {mark.detach(this); mk.splice(i--, 1);}
+ }
+ }
+ },
+ // Split a part off a line, keeping styles and markers intact.
+ split: function(pos, textBefore) {
+ var st = [textBefore, null], mk = this.marked;
+ copyStyles(pos, this.text.length, this.styles, st);
+ var taken = new Line(textBefore + this.text.slice(pos), st);
+ if (mk) {
+ for (var i = 0; i < mk.length; ++i) {
+ var mark = mk[i];
+ var newmark = mark.split(pos, textBefore.length);
+ if (newmark) {
+ if (!taken.marked) taken.marked = [];
+ taken.marked.push(newmark); newmark.attach(taken);
+ if (newmark == mark) mk.splice(i--, 1);
+ }
+ }
+ }
+ return taken;
+ },
+ append: function(line) {
+ var mylen = this.text.length, mk = line.marked, mymk = this.marked;
+ this.text += line.text;
+ copyStyles(0, line.text.length, line.styles, this.styles);
+ if (mymk) {
+ for (var i = 0; i < mymk.length; ++i)
+ if (mymk[i].to == null) mymk[i].to = mylen;
+ }
+ if (mk && mk.length) {
+ if (!mymk) this.marked = mymk = [];
+ outer: for (var i = 0; i < mk.length; ++i) {
+ var mark = mk[i];
+ if (!mark.from) {
+ for (var j = 0; j < mymk.length; ++j) {
+ var mymark = mymk[j];
+ if (mymark.to == mylen && mymark.sameSet(mark)) {
+ mymark.to = mark.to == null ? null : mark.to + mylen;
+ if (mymark.isDead()) {
+ mymark.detach(this);
+ mk.splice(i--, 1);
+ }
+ continue outer;
+ }
+ }
+ }
+ mymk.push(mark);
+ mark.attach(this);
+ mark.from += mylen;
+ if (mark.to != null) mark.to += mylen;
+ }
+ }
+ },
+ fixMarkEnds: function(other) {
+ var mk = this.marked, omk = other.marked;
+ if (!mk) return;
+ for (var i = 0; i < mk.length; ++i) {
+ var mark = mk[i], close = mark.to == null;
+ if (close && omk) {
+ for (var j = 0; j < omk.length; ++j)
+ if (omk[j].sameSet(mark)) {close = false; break;}
+ }
+ if (close) mark.to = this.text.length;
+ }
+ },
+ fixMarkStarts: function() {
+ var mk = this.marked;
+ if (!mk) return;
+ for (var i = 0; i < mk.length; ++i)
+ if (mk[i].from == null) mk[i].from = 0;
+ },
+ addMark: function(mark) {
+ mark.attach(this);
+ if (this.marked == null) this.marked = [];
+ this.marked.push(mark);
+ this.marked.sort(function(a, b){return (a.from || 0) - (b.from || 0);});
+ },
+ // Run the given mode's parser over a line, update the styles
+ // array, which contains alternating fragments of text and CSS
+ // classes.
+ highlight: function(mode, state, tabSize) {
+ var stream = new StringStream(this.text, tabSize), st = this.styles, pos = 0;
+ var changed = false, curWord = st[0], prevWord;
+ if (this.text == "" && mode.blankLine) mode.blankLine(state);
+ while (!stream.eol()) {
+ var style = mode.token(stream, state);
+ var substr = this.text.slice(stream.start, stream.pos);
+ stream.start = stream.pos;
+ if (pos && st[pos-1] == style)
+ st[pos-2] += substr;
+ else if (substr) {
+ if (!changed && (st[pos+1] != style || (pos && st[pos-2] != prevWord))) changed = true;
+ st[pos++] = substr; st[pos++] = style;
+ prevWord = curWord; curWord = st[pos];
+ }
+ // Give up when line is ridiculously long
+ if (stream.pos > 5000) {
+ st[pos++] = this.text.slice(stream.pos); st[pos++] = null;
+ break;
+ }
+ }
+ if (st.length != pos) {st.length = pos; changed = true;}
+ if (pos && st[pos-2] != prevWord) changed = true;
+ // Short lines with simple highlights return null, and are
+ // counted as changed by the driver because they are likely to
+ // highlight the same way in various contexts.
+ return changed || (st.length < 5 && this.text.length < 10 ? null : false);
+ },
+ // Fetch the parser token for a given character. Useful for hacks
+ // that want to inspect the mode state (say, for completion).
+ getTokenAt: function(mode, state, ch) {
+ var txt = this.text, stream = new StringStream(txt);
+ while (stream.pos < ch && !stream.eol()) {
+ stream.start = stream.pos;
+ var style = mode.token(stream, state);
+ }
+ return {start: stream.start,
+ end: stream.pos,
+ string: stream.current(),
+ className: style || null,
+ state: state};
+ },
+ indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
+ // Produces an HTML fragment for the line, taking selection,
+ // marking, and highlighting into account.
+ getHTML: function(makeTab, wrapAt, wrapId, wrapWBR) {
+ var html = [], first = true, col = 0;
+ function span_(text, style) {
+ if (!text) return;
+ // Work around a bug where, in some compat modes, IE ignores leading spaces
+ if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
+ first = false;
+ if (text.indexOf("\t") == -1) {
+ col += text.length;
+ var escaped = htmlEscape(text);
+ } else {
+ var escaped = "";
+ for (var pos = 0;;) {
+ var idx = text.indexOf("\t", pos);
+ if (idx == -1) {
+ escaped += htmlEscape(text.slice(pos));
+ col += text.length - pos;
+ break;
+ } else {
+ col += idx - pos;
+ var tab = makeTab(col);
+ escaped += htmlEscape(text.slice(pos, idx)) + tab.html;
+ col += tab.width;
+ pos = idx + 1;
+ }
+ }
+ }
+ if (style) html.push('<span class="', style, '">', escaped, "</span>");
+ else html.push(escaped);
+ }
+ var span = span_;
+ if (wrapAt != null) {
+ var outPos = 0, open = "<span id=\"" + wrapId + "\">";
+ span = function(text, style) {
+ var l = text.length;
+ if (wrapAt >= outPos && wrapAt < outPos + l) {
+ if (wrapAt > outPos) {
+ span_(text.slice(0, wrapAt - outPos), style);
+ // See comment at the definition of spanAffectsWrapping
+ if (wrapWBR) html.push("<wbr>");
+ }
+ html.push(open);
+ var cut = wrapAt - outPos;
+ span_(opera ? text.slice(cut, cut + 1) : text.slice(cut), style);
+ html.push("</span>");
+ if (opera) span_(text.slice(cut + 1), style);
+ wrapAt--;
+ outPos += l;
+ } else {
+ outPos += l;
+ span_(text, style);
+ // Output empty wrapper when at end of line
+ if (outPos == wrapAt && outPos == len) html.push(open + " </span>");
+ // Stop outputting HTML when gone sufficiently far beyond measure
+ else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){};
+ }
+ }
+ }
+
+ var st = this.styles, allText = this.text, marked = this.marked;
+ var len = allText.length;
+ function styleToClass(style) {
+ if (!style) return null;
+ return "cm-" + style.replace(/ +/g, " cm-");
+ }
+
+ if (!allText && wrapAt == null) {
+ span(" ");
+ } else if (!marked || !marked.length) {
+ for (var i = 0, ch = 0; ch < len; i+=2) {
+ var str = st[i], style = st[i+1], l = str.length;
+ if (ch + l > len) str = str.slice(0, len - ch);
+ ch += l;
+ span(str, styleToClass(style));
+ }
+ } else {
+ var pos = 0, i = 0, text = "", style, sg = 0;
+ var nextChange = marked[0].from || 0, marks = [], markpos = 0;
+ function advanceMarks() {
+ var m;
+ while (markpos < marked.length &&
+ ((m = marked[markpos]).from == pos || m.from == null)) {
+ if (m.style != null) marks.push(m);
+ ++markpos;
+ }
+ nextChange = markpos < marked.length ? marked[markpos].from : Infinity;
+ for (var i = 0; i < marks.length; ++i) {
+ var to = marks[i].to || Infinity;
+ if (to == pos) marks.splice(i--, 1);
+ else nextChange = Math.min(to, nextChange);
+ }
+ }
+ var m = 0;
+ while (pos < len) {
+ if (nextChange == pos) advanceMarks();
+ var upto = Math.min(len, nextChange);
+ while (true) {
+ if (text) {
+ var end = pos + text.length;
+ var appliedStyle = style;
+ for (var j = 0; j < marks.length; ++j)
+ appliedStyle = (appliedStyle ? appliedStyle + " " : "") + marks[j].style;
+ span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
+ if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
+ pos = end;
+ }
+ text = st[i++]; style = styleToClass(st[i++]);
+ }
+ }
+ }
+ return html.join("");
+ },
+ cleanUp: function() {
+ this.parent = null;
+ if (this.marked)
+ for (var i = 0, e = this.marked.length; i < e; ++i) this.marked[i].detach(this);
+ }
+ };
+ // Utility used by replace and split above
+ function copyStyles(from, to, source, dest) {
+ for (var i = 0, pos = 0, state = 0; pos < to; i+=2) {
+ var part = source[i], end = pos + part.length;
+ if (state == 0) {
+ if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
+ if (end >= from) state = 1;
+ } else if (state == 1) {
+ if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
+ else dest.push(part, source[i+1]);
+ }
+ pos = end;
+ }
+ }
+
+ // Data structure that holds the sequence of lines.
+ function LeafChunk(lines) {
+ this.lines = lines;
+ this.parent = null;
+ for (var i = 0, e = lines.length, height = 0; i < e; ++i) {
+ lines[i].parent = this;
+ height += lines[i].height;
+ }
+ this.height = height;
+ }
+ LeafChunk.prototype = {
+ chunkSize: function() { return this.lines.length; },
+ remove: function(at, n, callbacks) {
+ for (var i = at, e = at + n; i < e; ++i) {
+ var line = this.lines[i];
+ this.height -= line.height;
+ line.cleanUp();
+ if (line.handlers)
+ for (var j = 0; j < line.handlers.length; ++j) callbacks.push(line.handlers[j]);
+ }
+ this.lines.splice(at, n);
+ },
+ collapse: function(lines) {
+ lines.splice.apply(lines, [lines.length, 0].concat(this.lines));
+ },
+ insertHeight: function(at, lines, height) {
+ this.height += height;
+ this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
+ for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
+ },
+ iterN: function(at, n, op) {
+ for (var e = at + n; at < e; ++at)
+ if (op(this.lines[at])) return true;
+ }
+ };
+ function BranchChunk(children) {
+ this.children = children;
+ var size = 0, height = 0;
+ for (var i = 0, e = children.length; i < e; ++i) {
+ var ch = children[i];
+ size += ch.chunkSize(); height += ch.height;
+ ch.parent = this;
+ }
+ this.size = size;
+ this.height = height;
+ this.parent = null;
+ }
+ BranchChunk.prototype = {
+ chunkSize: function() { return this.size; },
+ remove: function(at, n, callbacks) {
+ this.size -= n;
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at < sz) {
+ var rm = Math.min(n, sz - at), oldHeight = child.height;
+ child.remove(at, rm, callbacks);
+ this.height -= oldHeight - child.height;
+ if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
+ if ((n -= rm) == 0) break;
+ at = 0;
+ } else at -= sz;
+ }
+ if (this.size - n < 25) {
+ var lines = [];
+ this.collapse(lines);
+ this.children = [new LeafChunk(lines)];
+ this.children[0].parent = this;
+ }
+ },
+ collapse: function(lines) {
+ for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines);
+ },
+ insert: function(at, lines) {
+ var height = 0;
+ for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height;
+ this.insertHeight(at, lines, height);
+ },
+ insertHeight: function(at, lines, height) {
+ this.size += lines.length;
+ this.height += height;
+ for (var i = 0, e = this.children.length; i < e; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at <= sz) {
+ child.insertHeight(at, lines, height);
+ if (child.lines && child.lines.length > 50) {
+ while (child.lines.length > 50) {
+ var spilled = child.lines.splice(child.lines.length - 25, 25);
+ var newleaf = new LeafChunk(spilled);
+ child.height -= newleaf.height;
+ this.children.splice(i + 1, 0, newleaf);
+ newleaf.parent = this;
+ }
+ this.maybeSpill();
+ }
+ break;
+ }
+ at -= sz;
+ }
+ },
+ maybeSpill: function() {
+ if (this.children.length <= 10) return;
+ var me = this;
+ do {
+ var spilled = me.children.splice(me.children.length - 5, 5);
+ var sibling = new BranchChunk(spilled);
+ if (!me.parent) { // Become the parent node
+ var copy = new BranchChunk(me.children);
+ copy.parent = me;
+ me.children = [copy, sibling];
+ me = copy;
+ } else {
+ me.size -= sibling.size;
+ me.height -= sibling.height;
+ var myIndex = indexOf(me.parent.children, me);
+ me.parent.children.splice(myIndex + 1, 0, sibling);
+ }
+ sibling.parent = me.parent;
+ } while (me.children.length > 10);
+ me.parent.maybeSpill();
+ },
+ iter: function(from, to, op) { this.iterN(from, to - from, op); },
+ iterN: function(at, n, op) {
+ for (var i = 0, e = this.children.length; i < e; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at < sz) {
+ var used = Math.min(n, sz - at);
+ if (child.iterN(at, used, op)) return true;
+ if ((n -= used) == 0) break;
+ at = 0;
+ } else at -= sz;
+ }
+ }
+ };
+
+ function getLineAt(chunk, n) {
+ while (!chunk.lines) {
+ for (var i = 0;; ++i) {
+ var child = chunk.children[i], sz = child.chunkSize();
+ if (n < sz) { chunk = child; break; }
+ n -= sz;
+ }
+ }
+ return chunk.lines[n];
+ }
+ function lineNo(line) {
+ if (line.parent == null) return null;
+ var cur = line.parent, no = indexOf(cur.lines, line);
+ for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
+ for (var i = 0, e = chunk.children.length; ; ++i) {
+ if (chunk.children[i] == cur) break;
+ no += chunk.children[i].chunkSize();
+ }
+ }
+ return no;
+ }
+ function lineAtHeight(chunk, h) {
+ var n = 0;
+ outer: do {
+ for (var i = 0, e = chunk.children.length; i < e; ++i) {
+ var child = chunk.children[i], ch = child.height;
+ if (h < ch) { chunk = child; continue outer; }
+ h -= ch;
+ n += child.chunkSize();
+ }
+ return n;
+ } while (!chunk.lines);
+ for (var i = 0, e = chunk.lines.length; i < e; ++i) {
+ var line = chunk.lines[i], lh = line.height;
+ if (h < lh) break;
+ h -= lh;
+ }
+ return n + i;
+ }
+ function heightAtLine(chunk, n) {
+ var h = 0;
+ outer: do {
+ for (var i = 0, e = chunk.children.length; i < e; ++i) {
+ var child = chunk.children[i], sz = child.chunkSize();
+ if (n < sz) { chunk = child; continue outer; }
+ n -= sz;
+ h += child.height;
+ }
+ return h;
+ } while (!chunk.lines);
+ for (var i = 0; i < n; ++i) h += chunk.lines[i].height;
+ return h;
+ }
+
+ // The history object 'chunks' changes that are made close together
+ // and at almost the same time into bigger undoable units.
+ function History() {
+ this.time = 0;
+ this.done = []; this.undone = [];
+ this.compound = 0;
+ this.closed = false;
+ }
+ History.prototype = {
+ addChange: function(start, added, old) {
+ this.undone.length = 0;
+ var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
+ var dtime = time - this.time;
+
+ if (this.compound && cur && !this.closed) {
+ cur.push({start: start, added: added, old: old});
+ } else if (dtime > 400 || !last || this.closed ||
+ last.start > start + old.length || last.start + last.added < start) {
+ this.done.push([{start: start, added: added, old: old}]);
+ this.closed = false;
+ } else {
+ var startBefore = Math.max(0, last.start - start),
+ endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
+ for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
+ for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
+ if (startBefore) last.start = start;
+ last.added += added - (old.length - startBefore - endAfter);
+ }
+ this.time = time;
+ },
+ startCompound: function() {
+ if (!this.compound++) this.closed = true;
+ },
+ endCompound: function() {
+ if (!--this.compound) this.closed = true;
+ }
+ };
+
+ function stopMethod() {e_stop(this);}
+ // Ensure an event has a stop method.
+ function addStop(event) {
+ if (!event.stop) event.stop = stopMethod;
+ return event;
+ }
+
+ function e_preventDefault(e) {
+ if (e.preventDefault) e.preventDefault();
+ else e.returnValue = false;
+ }
+ function e_stopPropagation(e) {
+ if (e.stopPropagation) e.stopPropagation();
+ else e.cancelBubble = true;
+ }
+ function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
+ CodeMirror.e_stop = e_stop;
+ CodeMirror.e_preventDefault = e_preventDefault;
+ CodeMirror.e_stopPropagation = e_stopPropagation;
+
+ function e_target(e) {return e.target || e.srcElement;}
+ function e_button(e) {
+ if (e.which) return e.which;
+ else if (e.button & 1) return 1;
+ else if (e.button & 2) return 3;
+ else if (e.button & 4) return 2;
+ }
+
+ // Allow 3rd-party code to override event properties by adding an override
+ // object to an event object.
+ function e_prop(e, prop) {
+ var overridden = e.override && e.override.hasOwnProperty(prop);
+ return overridden ? e.override[prop] : e[prop];
+ }
+
+ // Event handler registration. If disconnect is true, it'll return a
+ // function that unregisters the handler.
+ function connect(node, type, handler, disconnect) {
+ if (typeof node.addEventListener == "function") {
+ node.addEventListener(type, handler, false);
+ if (disconnect) return function() {node.removeEventListener(type, handler, false);};
+ } else {
+ var wrapHandler = function(event) {handler(event || window.event);};
+ node.attachEvent("on" + type, wrapHandler);
+ if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
+ }
+ }
+ CodeMirror.connect = connect;
+
+ function Delayed() {this.id = null;}
+ Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
+
+ var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
+
+ var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
+ var ie = /MSIE \d/.test(navigator.userAgent);
+ var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
+ var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
+ var quirksMode = ie && document.documentMode == 5;
+ var webkit = /WebKit\//.test(navigator.userAgent);
+ var chrome = /Chrome\//.test(navigator.userAgent);
+ var opera = /Opera\//.test(navigator.userAgent);
+ var safari = /Apple Computer/.test(navigator.vendor);
+ var khtml = /KHTML\//.test(navigator.userAgent);
+ var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent);
+
+ // Detect drag-and-drop
+ var dragAndDrop = function() {
+ // There is *some* kind of drag-and-drop support in IE6-8, but I
+ // couldn't get it to work yet.
+ if (ie_lt9) return false;
+ var div = document.createElement('div');
+ return "draggable" in div || "dragDrop" in div;
+ }();
+
+ // Feature-detect whether newlines in textareas are converted to \r\n
+ var lineSep = function () {
+ var te = document.createElement("textarea");
+ te.value = "foo\nbar";
+ if (te.value.indexOf("\r") > -1) return "\r\n";
+ return "\n";
+ }();
+
+ // For a reason I have yet to figure out, some browsers disallow
+ // word wrapping between certain characters *only* if a new inline
+ // element is started between them. This makes it hard to reliably
+ // measure the position of things, since that requires inserting an
+ // extra span. This terribly fragile set of regexps matches the
+ // character combinations that suffer from this phenomenon on the
+ // various browsers.
+ var spanAffectsWrapping = /^$/; // Won't match any two-character string
+ if (gecko) spanAffectsWrapping = /$'/;
+ else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
+ else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
+
+ // Counts the column offset in a string, taking tabs into account.
+ // Used mostly to find indentation.
+ function countColumn(string, end, tabSize) {
+ if (end == null) {
+ end = string.search(/[^\s\u00a0]/);
+ if (end == -1) end = string.length;
+ }
+ for (var i = 0, n = 0; i < end; ++i) {
+ if (string.charAt(i) == "\t") n += tabSize - (n % tabSize);
+ else ++n;
+ }
+ return n;
+ }
+
+ function computedStyle(elt) {
+ if (elt.currentStyle) return elt.currentStyle;
+ return window.getComputedStyle(elt, null);
+ }
+
+ // Find the position of an element by following the offsetParent chain.
+ // If screen==true, it returns screen (rather than page) coordinates.
+ function eltOffset(node, screen) {
+ var bod = node.ownerDocument.body;
+ var x = 0, y = 0, skipBody = false;
+ for (var n = node; n; n = n.offsetParent) {
+ var ol = n.offsetLeft, ot = n.offsetTop;
+ // Firefox reports weird inverted offsets when the body has a border.
+ if (n == bod) { x += Math.abs(ol); y += Math.abs(ot); }
+ else { x += ol, y += ot; }
+ if (screen && computedStyle(n).position == "fixed")
+ skipBody = true;
+ }
+ var e = screen && !skipBody ? null : bod;
+ for (var n = node.parentNode; n != e; n = n.parentNode)
+ if (n.scrollLeft != null) { x -= n.scrollLeft; y -= n.scrollTop;}
+ return {left: x, top: y};
+ }
+ // Use the faster and saner getBoundingClientRect method when possible.
+ if (document.documentElement.getBoundingClientRect != null) eltOffset = function(node, screen) {
+ // Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
+ // since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
+ try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; }
+ catch(e) { box = {top: 0, left: 0}; }
+ if (!screen) {
+ // Get the toplevel scroll, working around browser differences.
+ if (window.pageYOffset == null) {
+ var t = document.documentElement || document.body.parentNode;
+ if (t.scrollTop == null) t = document.body;
+ box.top += t.scrollTop; box.left += t.scrollLeft;
+ } else {
+ box.top += window.pageYOffset; box.left += window.pageXOffset;
+ }
+ }
+ return box;
+ };
+
+ // Get a node's text content.
+ function eltText(node) {
+ return node.textContent || node.innerText || node.nodeValue || "";
+ }
+ function selectInput(node) {
+ if (ios) { // Mobile Safari apparently has a bug where select() is broken.
+ node.selectionStart = 0;
+ node.selectionEnd = node.value.length;
+ } else node.select();
+ }
+
+ // Operations on {line, ch} objects.
+ function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
+ function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
+ function copyPos(x) {return {line: x.line, ch: x.ch};}
+
+ var escapeElement = document.createElement("pre");
+ function htmlEscape(str) {
+ escapeElement.textContent = str;
+ return escapeElement.innerHTML;
+ }
+ // Recent (late 2011) Opera betas insert bogus newlines at the start
+ // of the textContent, so we strip those.
+ if (htmlEscape("a") == "\na") {
+ htmlEscape = function(str) {
+ escapeElement.textContent = str;
+ return escapeElement.innerHTML.slice(1);
+ };
+ // Some IEs don't preserve tabs through innerHTML
+ } else if (htmlEscape("\t") != "\t") {
+ htmlEscape = function(str) {
+ escapeElement.innerHTML = "";
+ escapeElement.appendChild(document.createTextNode(str));
+ return escapeElement.innerHTML;
+ };
+ }
+ CodeMirror.htmlEscape = htmlEscape;
+
+ // Used to position the cursor after an undo/redo by finding the
+ // last edited character.
+ function editEnd(from, to) {
+ if (!to) return 0;
+ if (!from) return to.length;
+ for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j)
+ if (from.charAt(i) != to.charAt(j)) break;
+ return j + 1;
+ }
+
+ function indexOf(collection, elt) {
+ if (collection.indexOf) return collection.indexOf(elt);
+ for (var i = 0, e = collection.length; i < e; ++i)
+ if (collection[i] == elt) return i;
+ return -1;
+ }
+ function isWordChar(ch) {
+ return /\w/.test(ch) || ch.toUpperCase() != ch.toLowerCase();
+ }
+
+ // See if "".split is the broken IE version, if so, provide an
+ // alternative way to split lines.
+ var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
+ var pos = 0, nl, result = [];
+ while ((nl = string.indexOf("\n", pos)) > -1) {
+ result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl));
+ pos = nl + 1;
+ }
+ result.push(string.slice(pos));
+ return result;
+ } : function(string){return string.split(/\r?\n/);};
+ CodeMirror.splitLines = splitLines;
+
+ var hasSelection = window.getSelection ? function(te) {
+ try { return te.selectionStart != te.selectionEnd; }
+ catch(e) { return false; }
+ } : function(te) {
+ try {var range = te.ownerDocument.selection.createRange();}
+ catch(e) {}
+ if (!range || range.parentElement() != te) return false;
+ return range.compareEndPoints("StartToEnd", range) != 0;
+ };
+
+ CodeMirror.defineMode("null", function() {
+ return {token: function(stream) {stream.skipToEnd();}};
+ });
+ CodeMirror.defineMIME("text/plain", "null");
+
+ var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
+ 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
+ 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
+ 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
+ 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
+ 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
+ 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
+ CodeMirror.keyNames = keyNames;
+ (function() {
+ // Number keys
+ for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
+ // Alphabetic keys
+ for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
+ // Function keys
+ for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
+ })();
+
+ return CodeMirror;
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/closetag.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/closetag.js
new file mode 100644
index 0000000..20a43b9
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/closetag.js
@@ -0,0 +1,146 @@
+/**
+ * Tag-closer extension for CodeMirror.
+ *
+ * This extension adds a "closeTag" utility function that can be used with key bindings to
+ * insert a matching end tag after the ">" character of a start tag has been typed. It can
+ * also complete "</" if a matching start tag is found. It will correctly ignore signal
+ * characters for empty tags, comments, CDATA, etc.
+ *
+ * The function depends on internal parser state to identify tags. It is compatible with the
+ * following CodeMirror modes and will ignore all others:
+ * - htmlmixed
+ * - xml
+ *
+ * See demos/closetag.html for a usage example.
+ *
+ * @author Nathan Williams <nathan@nlwillia.net>
+ * Contributed under the same license terms as CodeMirror.
+ */
+(function() {
+ /** Option that allows tag closing behavior to be toggled. Default is true. */
+ CodeMirror.defaults['closeTagEnabled'] = true;
+
+ /** Array of tag names to add indentation after the start tag for. Default is the list of block-level html tags. */
+ CodeMirror.defaults['closeTagIndent'] = ['applet', 'blockquote', 'body', 'button', 'div', 'dl', 'fieldset', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', 'iframe', 'layer', 'legend', 'object', 'ol', 'p', 'select', 'table', 'ul'];
+
+ /**
+ * Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass.
+ * - cm: The editor instance.
+ * - ch: The character being processed.
+ * - indent: Optional. Omit or pass true to use the default indentation tag list defined in the 'closeTagIndent' option.
+ * Pass false to disable indentation. Pass an array to override the default list of tag names.
+ */
+ CodeMirror.defineExtension("closeTag", function(cm, ch, indent) {
+ if (!cm.getOption('closeTagEnabled')) {
+ throw CodeMirror.Pass;
+ }
+
+ var mode = cm.getOption('mode');
+
+ if (mode == 'text/html') {
+
+ /*
+ * Relevant structure of token:
+ *
+ * htmlmixed
+ * className
+ * state
+ * htmlState
+ * type
+ * context
+ * tagName
+ * mode
+ *
+ * xml
+ * className
+ * state
+ * tagName
+ * type
+ */
+
+ var pos = cm.getCursor();
+ var tok = cm.getTokenAt(pos);
+ var state = tok.state;
+
+ if (state.mode && state.mode != 'html') {
+ throw CodeMirror.Pass; // With htmlmixed, we only care about the html sub-mode.
+ }
+
+ if (ch == '>') {
+ var type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
+
+ if (tok.className == 'tag' && type == 'closeTag') {
+ throw CodeMirror.Pass; // Don't process the '>' at the end of an end-tag.
+ }
+
+ cm.replaceSelection('>'); // Mode state won't update until we finish the tag.
+ pos = {line: pos.line, ch: pos.ch + 1};
+ cm.setCursor(pos);
+
+ tok = cm.getTokenAt(cm.getCursor());
+ state = tok.state;
+ type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
+
+ if (tok.className == 'tag' && type != 'selfcloseTag') {
+ var tagName = state.htmlState ? state.htmlState.context.tagName : state.tagName; // htmlmixed : xml
+ if (tagName.length > 0) {
+ insertEndTag(cm, indent, pos, tagName);
+ }
+ return;
+ }
+
+ // Undo the '>' insert and allow cm to handle the key instead.
+ cm.setSelection({line: pos.line, ch: pos.ch - 1}, pos);
+ cm.replaceSelection("");
+
+ } else if (ch == '/') {
+ if (tok.className == 'tag' && tok.string == '<') {
+ var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : state.context.tagName; // htmlmixed : xml # extra htmlmized check is for '</' edge case
+ if (tagName.length > 0) {
+ completeEndTag(cm, pos, tagName);
+ return;
+ }
+ }
+ }
+
+ }
+
+ throw CodeMirror.Pass; // Bubble if not handled
+ });
+
+ function insertEndTag(cm, indent, pos, tagName) {
+ if (shouldIndent(cm, indent, tagName)) {
+ cm.replaceSelection('\n\n</' + tagName + '>', 'end');
+ cm.indentLine(pos.line + 1);
+ cm.indentLine(pos.line + 2);
+ cm.setCursor({line: pos.line + 1, ch: cm.getLine(pos.line + 1).length});
+ } else {
+ cm.replaceSelection('</' + tagName + '>');
+ cm.setCursor(pos);
+ }
+ }
+
+ function shouldIndent(cm, indent, tagName) {
+ if (typeof indent == 'undefined' || indent == null || indent == true) {
+ indent = cm.getOption('closeTagIndent');
+ }
+ if (!indent) {
+ indent = [];
+ }
+ return indexOf(indent, tagName.toLowerCase()) != -1;
+ }
+
+ // C&P from codemirror.js...would be nice if this were visible to utilities.
+ function indexOf(collection, elt) {
+ if (collection.indexOf) return collection.indexOf(elt);
+ for (var i = 0, e = collection.length; i < e; ++i)
+ if (collection[i] == elt) return i;
+ return -1;
+ }
+
+ function completeEndTag(cm, pos, tagName) {
+ cm.replaceSelection('/' + tagName + '>');
+ cm.setCursor({line: pos.line, ch: pos.ch + tagName.length + 2 });
+ }
+
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/dialog.css b/codemirror_ui/lib/CodeMirror-2.3/lib/util/dialog.css
new file mode 100644
index 0000000..4cb467e
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/dialog.css
@@ -0,0 +1,23 @@
+.CodeMirror-dialog {
+ position: relative;
+}
+
+.CodeMirror-dialog > div {
+ position: absolute;
+ top: 0; left: 0; right: 0;
+ background: white;
+ border-bottom: 1px solid #eee;
+ z-index: 15;
+ padding: .1em .8em;
+ overflow: hidden;
+ color: #333;
+}
+
+.CodeMirror-dialog input {
+ border: none;
+ outline: none;
+ background: transparent;
+ width: 20em;
+ color: inherit;
+ font-family: monospace;
+}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/dialog.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/dialog.js
new file mode 100644
index 0000000..8950bf0
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/dialog.js
@@ -0,0 +1,63 @@
+// Open simple dialogs on top of an editor. Relies on dialog.css.
+
+(function() {
+ function dialogDiv(cm, template) {
+ var wrap = cm.getWrapperElement();
+ var dialog = wrap.insertBefore(document.createElement("div"), wrap.firstChild);
+ dialog.className = "CodeMirror-dialog";
+ dialog.innerHTML = '<div>' + template + '</div>';
+ return dialog;
+ }
+
+ CodeMirror.defineExtension("openDialog", function(template, callback) {
+ var dialog = dialogDiv(this, template);
+ var closed = false, me = this;
+ function close() {
+ if (closed) return;
+ closed = true;
+ dialog.parentNode.removeChild(dialog);
+ }
+ var inp = dialog.getElementsByTagName("input")[0];
+ if (inp) {
+ CodeMirror.connect(inp, "keydown", function(e) {
+ if (e.keyCode == 13 || e.keyCode == 27) {
+ CodeMirror.e_stop(e);
+ close();
+ me.focus();
+ if (e.keyCode == 13) callback(inp.value);
+ }
+ });
+ inp.focus();
+ CodeMirror.connect(inp, "blur", close);
+ }
+ return close;
+ });
+
+ CodeMirror.defineExtension("openConfirm", function(template, callbacks) {
+ var dialog = dialogDiv(this, template);
+ var buttons = dialog.getElementsByTagName("button");
+ var closed = false, me = this, blurring = 1;
+ function close() {
+ if (closed) return;
+ closed = true;
+ dialog.parentNode.removeChild(dialog);
+ me.focus();
+ }
+ buttons[0].focus();
+ for (var i = 0; i < buttons.length; ++i) {
+ var b = buttons[i];
+ (function(callback) {
+ CodeMirror.connect(b, "click", function(e) {
+ CodeMirror.e_preventDefault(e);
+ close();
+ if (callback) callback(me);
+ });
+ })(callbacks[i]);
+ CodeMirror.connect(b, "blur", function() {
+ --blurring;
+ setTimeout(function() { if (blurring <= 0) close(); }, 200);
+ });
+ CodeMirror.connect(b, "focus", function() { ++blurring; });
+ }
+ });
+})(); \ No newline at end of file
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/foldcode.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/foldcode.js
new file mode 100644
index 0000000..02cfb50
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/foldcode.js
@@ -0,0 +1,196 @@
+// the tagRangeFinder function is
+// Copyright (C) 2011 by Daniel Glazman <daniel@glazman.org>
+// released under the MIT license (../../LICENSE) like the rest of CodeMirror
+CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
+ var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
+ var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
+ var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");
+
+ var lineText = cm.getLine(line);
+ var found = false;
+ var tag = null;
+ var pos = 0;
+ while (!found) {
+ pos = lineText.indexOf("<", pos);
+ if (-1 == pos) // no tag on line
+ return;
+ if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag
+ pos++;
+ continue;
+ }
+ // ok we weem to have a start tag
+ if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name...
+ pos++;
+ continue;
+ }
+ var gtPos = lineText.indexOf(">", pos + 1);
+ if (-1 == gtPos) { // end of start tag not in line
+ var l = line + 1;
+ var foundGt = false;
+ var lastLine = cm.lineCount();
+ while (l < lastLine && !foundGt) {
+ var lt = cm.getLine(l);
+ var gt = lt.indexOf(">");
+ if (-1 != gt) { // found a >
+ foundGt = true;
+ var slash = lt.lastIndexOf("/", gt);
+ if (-1 != slash && slash < gt) {
+ var str = lineText.substr(slash, gt - slash + 1);
+ if (!str.match( /\/\s*\>/ )) { // yep, that's the end of empty tag
+ if (hideEnd === true) l++;
+ return l;
+ }
+ }
+ }
+ l++;
+ }
+ found = true;
+ }
+ else {
+ var slashPos = lineText.lastIndexOf("/", gtPos);
+ if (-1 == slashPos) { // cannot be empty tag
+ found = true;
+ // don't continue
+ }
+ else { // empty tag?
+ // check if really empty tag
+ var str = lineText.substr(slashPos, gtPos - slashPos + 1);
+ if (!str.match( /\/\s*\>/ )) { // finally not empty
+ found = true;
+ // don't continue
+ }
+ }
+ }
+ if (found) {
+ var subLine = lineText.substr(pos + 1);
+ tag = subLine.match(xmlNAMERegExp);
+ if (tag) {
+ // we have an element name, wooohooo !
+ tag = tag[0];
+ // do we have the close tag on same line ???
+ if (-1 != lineText.indexOf("</" + tag + ">", pos)) // yep
+ {
+ found = false;
+ }
+ // we don't, so we have a candidate...
+ }
+ else
+ found = false;
+ }
+ if (!found)
+ pos++;
+ }
+
+ if (found) {
+ var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)";
+ var startTagRegExp = new RegExp(startTag, "g");
+ var endTag = "</" + tag + ">";
+ var depth = 1;
+ var l = line + 1;
+ var lastLine = cm.lineCount();
+ while (l < lastLine) {
+ lineText = cm.getLine(l);
+ var match = lineText.match(startTagRegExp);
+ if (match) {
+ for (var i = 0; i < match.length; i++) {
+ if (match[i] == endTag)
+ depth--;
+ else
+ depth++;
+ if (!depth) {
+ if (hideEnd === true) l++;
+ return l;
+ }
+ }
+ }
+ l++;
+ }
+ return;
+ }
+};
+
+CodeMirror.braceRangeFinder = function(cm, line, hideEnd) {
+ var lineText = cm.getLine(line), at = lineText.length, startChar, tokenType;
+ for (;;) {
+ var found = lineText.lastIndexOf("{", at);
+ if (found < 0) break;
+ tokenType = cm.getTokenAt({line: line, ch: found}).className;
+ if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
+ at = found - 1;
+ }
+ if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
+ var count = 1, lastLine = cm.lineCount(), end;
+ outer: for (var i = line + 1; i < lastLine; ++i) {
+ var text = cm.getLine(i), pos = 0;
+ for (;;) {
+ var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
+ if (nextOpen < 0) nextOpen = text.length;
+ if (nextClose < 0) nextClose = text.length;
+ pos = Math.min(nextOpen, nextClose);
+ if (pos == text.length) break;
+ if (cm.getTokenAt({line: i, ch: pos + 1}).className == tokenType) {
+ if (pos == nextOpen) ++count;
+ else if (!--count) { end = i; break outer; }
+ }
+ ++pos;
+ }
+ }
+ if (end == null || end == line + 1) return;
+ if (hideEnd === true) end++;
+ return end;
+};
+
+CodeMirror.indentRangeFinder = function(cm, line) {
+ var tabSize = cm.getOption("tabSize");
+ var myIndent = cm.getLineHandle(line).indentation(tabSize), last;
+ for (var i = line + 1, end = cm.lineCount(); i < end; ++i) {
+ var handle = cm.getLineHandle(i);
+ if (!/^\s*$/.test(handle.text)) {
+ if (handle.indentation(tabSize) <= myIndent) break;
+ last = i;
+ }
+ }
+ if (!last) return null;
+ return last + 1;
+};
+
+CodeMirror.newFoldFunction = function(rangeFinder, markText, hideEnd) {
+ var folded = [];
+ if (markText == null) markText = '<div style="position: absolute; left: 2px; color:#600">&#x25bc;</div>%N%';
+
+ function isFolded(cm, n) {
+ for (var i = 0; i < folded.length; ++i) {
+ var start = cm.lineInfo(folded[i].start);
+ if (!start) folded.splice(i--, 1);
+ else if (start.line == n) return {pos: i, region: folded[i]};
+ }
+ }
+
+ function expand(cm, region) {
+ cm.clearMarker(region.start);
+ for (var i = 0; i < region.hidden.length; ++i)
+ cm.showLine(region.hidden[i]);
+ }
+
+ return function(cm, line) {
+ cm.operation(function() {
+ var known = isFolded(cm, line);
+ if (known) {
+ folded.splice(known.pos, 1);
+ expand(cm, known.region);
+ } else {
+ var end = rangeFinder(cm, line, hideEnd);
+ if (end == null) return;
+ var hidden = [];
+ for (var i = line + 1; i < end; ++i) {
+ var handle = cm.hideLine(i);
+ if (handle) hidden.push(handle);
+ }
+ var first = cm.setMarker(line, markText);
+ var region = {start: first, hidden: hidden};
+ cm.onDeleteLine(first, function() { expand(cm, region); });
+ folded.push(region);
+ }
+ });
+ };
+};
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/formatting.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/formatting.js
new file mode 100644
index 0000000..3a1a987
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/formatting.js
@@ -0,0 +1,297 @@
+// ============== Formatting extensions ============================
+// A common storage for all mode-specific formatting features
+if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {};
+
+// Returns the extension of the editor's current mode
+CodeMirror.defineExtension("getModeExt", function () {
+ var mname = CodeMirror.resolveMode(this.getOption("mode")).name;
+ var ext = CodeMirror.modeExtensions[mname];
+ if (!ext) throw new Error("No extensions found for mode " + mname);
+ return ext;
+});
+
+// If the current mode is 'htmlmixed', returns the extension of a mode located at
+// the specified position (can be htmlmixed, css or javascript). Otherwise, simply
+// returns the extension of the editor's current mode.
+CodeMirror.defineExtension("getModeExtAtPos", function (pos) {
+ var token = this.getTokenAt(pos);
+ if (token && token.state && token.state.mode)
+ return CodeMirror.modeExtensions[token.state.mode == "html" ? "htmlmixed" : token.state.mode];
+ else
+ return this.getModeExt();
+});
+
+// Comment/uncomment the specified range
+CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
+ var curMode = this.getModeExtAtPos(this.getCursor());
+ if (isComment) { // Comment range
+ var commentedText = this.getRange(from, to);
+ this.replaceRange(curMode.commentStart + this.getRange(from, to) + curMode.commentEnd
+ , from, to);
+ if (from.line == to.line && from.ch == to.ch) { // An empty comment inserted - put cursor inside
+ this.setCursor(from.line, from.ch + curMode.commentStart.length);
+ }
+ }
+ else { // Uncomment range
+ var selText = this.getRange(from, to);
+ var startIndex = selText.indexOf(curMode.commentStart);
+ var endIndex = selText.lastIndexOf(curMode.commentEnd);
+ if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
+ // Take string till comment start
+ selText = selText.substr(0, startIndex)
+ // From comment start till comment end
+ + selText.substring(startIndex + curMode.commentStart.length, endIndex)
+ // From comment end till string end
+ + selText.substr(endIndex + curMode.commentEnd.length);
+ }
+ this.replaceRange(selText, from, to);
+ }
+});
+
+// Applies automatic mode-aware indentation to the specified range
+CodeMirror.defineExtension("autoIndentRange", function (from, to) {
+ var cmInstance = this;
+ this.operation(function () {
+ for (var i = from.line; i <= to.line; i++) {
+ cmInstance.indentLine(i, "smart");
+ }
+ });
+});
+
+// Applies automatic formatting to the specified range
+CodeMirror.defineExtension("autoFormatRange", function (from, to) {
+ var absStart = this.indexFromPos(from);
+ var absEnd = this.indexFromPos(to);
+ // Insert additional line breaks where necessary according to the
+ // mode's syntax
+ var res = this.getModeExt().autoFormatLineBreaks(this.getValue(), absStart, absEnd);
+ var cmInstance = this;
+
+ // Replace and auto-indent the range
+ this.operation(function () {
+ cmInstance.replaceRange(res, from, to);
+ var startLine = cmInstance.posFromIndex(absStart).line;
+ var endLine = cmInstance.posFromIndex(absStart + res.length).line;
+ for (var i = startLine; i <= endLine; i++) {
+ cmInstance.indentLine(i, "smart");
+ }
+ });
+});
+
+// Define extensions for a few modes
+
+CodeMirror.modeExtensions["css"] = {
+ commentStart: "/*",
+ commentEnd: "*/",
+ wordWrapChars: [";", "\\{", "\\}"],
+ autoFormatLineBreaks: function (text, startPos, endPos) {
+ text = text.substring(startPos, endPos);
+ return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
+ }
+};
+
+CodeMirror.modeExtensions["javascript"] = {
+ commentStart: "/*",
+ commentEnd: "*/",
+ wordWrapChars: [";", "\\{", "\\}"],
+
+ getNonBreakableBlocks: function (text) {
+ var nonBreakableRegexes = [
+ new RegExp("for\\s*?\\(([\\s\\S]*?)\\)"),
+ new RegExp("'([\\s\\S]*?)('|$)"),
+ new RegExp("\"([\\s\\S]*?)(\"|$)"),
+ new RegExp("//.*([\r\n]|$)")
+ ];
+ var nonBreakableBlocks = new Array();
+ for (var i = 0; i < nonBreakableRegexes.length; i++) {
+ var curPos = 0;
+ while (curPos < text.length) {
+ var m = text.substr(curPos).match(nonBreakableRegexes[i]);
+ if (m != null) {
+ nonBreakableBlocks.push({
+ start: curPos + m.index,
+ end: curPos + m.index + m[0].length
+ });
+ curPos += m.index + Math.max(1, m[0].length);
+ }
+ else { // No more matches
+ break;
+ }
+ }
+ }
+ nonBreakableBlocks.sort(function (a, b) {
+ return a.start - b.start;
+ });
+
+ return nonBreakableBlocks;
+ },
+
+ autoFormatLineBreaks: function (text, startPos, endPos) {
+ text = text.substring(startPos, endPos);
+ var curPos = 0;
+ var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n])", "g");
+ var nonBreakableBlocks = this.getNonBreakableBlocks(text);
+ if (nonBreakableBlocks != null) {
+ var res = "";
+ for (var i = 0; i < nonBreakableBlocks.length; i++) {
+ if (nonBreakableBlocks[i].start > curPos) { // Break lines till the block
+ res += text.substring(curPos, nonBreakableBlocks[i].start).replace(reLinesSplitter, "$1\n$2");
+ curPos = nonBreakableBlocks[i].start;
+ }
+ if (nonBreakableBlocks[i].start <= curPos
+ && nonBreakableBlocks[i].end >= curPos) { // Skip non-breakable block
+ res += text.substring(curPos, nonBreakableBlocks[i].end);
+ curPos = nonBreakableBlocks[i].end;
+ }
+ }
+ if (curPos < text.length - 1) {
+ res += text.substr(curPos).replace(reLinesSplitter, "$1\n$2");
+ }
+ return res;
+ }
+ else {
+ return text.replace(reLinesSplitter, "$1\n$2");
+ }
+ }
+};
+
+CodeMirror.modeExtensions["xml"] = {
+ commentStart: "<!--",
+ commentEnd: "-->",
+ wordWrapChars: [">"],
+
+ autoFormatLineBreaks: function (text, startPos, endPos) {
+ text = text.substring(startPos, endPos);
+ var lines = text.split("\n");
+ var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
+ var reOpenBrackets = new RegExp("<", "g");
+ var reCloseBrackets = new RegExp("(>)([^\r\n])", "g");
+ for (var i = 0; i < lines.length; i++) {
+ var mToProcess = lines[i].match(reProcessedPortion);
+ if (mToProcess != null && mToProcess.length > 3) { // The line starts with whitespaces and ends with whitespaces
+ lines[i] = mToProcess[1]
+ + mToProcess[2].replace(reOpenBrackets, "\n$&").replace(reCloseBrackets, "$1\n$2")
+ + mToProcess[3];
+ continue;
+ }
+ }
+
+ return lines.join("\n");
+ }
+};
+
+CodeMirror.modeExtensions["htmlmixed"] = {
+ commentStart: "<!--",
+ commentEnd: "-->",
+ wordWrapChars: [">", ";", "\\{", "\\}"],
+
+ getModeInfos: function (text, absPos) {
+ var modeInfos = new Array();
+ modeInfos[0] =
+ {
+ pos: 0,
+ modeExt: CodeMirror.modeExtensions["xml"],
+ modeName: "xml"
+ };
+
+ var modeMatchers = new Array();
+ modeMatchers[0] =
+ {
+ regex: new RegExp("<style[^>]*>([\\s\\S]*?)(</style[^>]*>|$)", "i"),
+ modeExt: CodeMirror.modeExtensions["css"],
+ modeName: "css"
+ };
+ modeMatchers[1] =
+ {
+ regex: new RegExp("<script[^>]*>([\\s\\S]*?)(</script[^>]*>|$)", "i"),
+ modeExt: CodeMirror.modeExtensions["javascript"],
+ modeName: "javascript"
+ };
+
+ var lastCharPos = (typeof (absPos) !== "undefined" ? absPos : text.length - 1);
+ // Detect modes for the entire text
+ for (var i = 0; i < modeMatchers.length; i++) {
+ var curPos = 0;
+ while (curPos <= lastCharPos) {
+ var m = text.substr(curPos).match(modeMatchers[i].regex);
+ if (m != null) {
+ if (m.length > 1 && m[1].length > 0) {
+ // Push block begin pos
+ var blockBegin = curPos + m.index + m[0].indexOf(m[1]);
+ modeInfos.push(
+ {
+ pos: blockBegin,
+ modeExt: modeMatchers[i].modeExt,
+ modeName: modeMatchers[i].modeName
+ });
+ // Push block end pos
+ modeInfos.push(
+ {
+ pos: blockBegin + m[1].length,
+ modeExt: modeInfos[0].modeExt,
+ modeName: modeInfos[0].modeName
+ });
+ curPos += m.index + m[0].length;
+ continue;
+ }
+ else {
+ curPos += m.index + Math.max(m[0].length, 1);
+ }
+ }
+ else { // No more matches
+ break;
+ }
+ }
+ }
+ // Sort mode infos
+ modeInfos.sort(function sortModeInfo(a, b) {
+ return a.pos - b.pos;
+ });
+
+ return modeInfos;
+ },
+
+ autoFormatLineBreaks: function (text, startPos, endPos) {
+ var modeInfos = this.getModeInfos(text);
+ var reBlockStartsWithNewline = new RegExp("^\\s*?\n");
+ var reBlockEndsWithNewline = new RegExp("\n\\s*?$");
+ var res = "";
+ // Use modes info to break lines correspondingly
+ if (modeInfos.length > 1) { // Deal with multi-mode text
+ for (var i = 1; i <= modeInfos.length; i++) {
+ var selStart = modeInfos[i - 1].pos;
+ var selEnd = (i < modeInfos.length ? modeInfos[i].pos : endPos);
+
+ if (selStart >= endPos) { // The block starts later than the needed fragment
+ break;
+ }
+ if (selStart < startPos) {
+ if (selEnd <= startPos) { // The block starts earlier than the needed fragment
+ continue;
+ }
+ selStart = startPos;
+ }
+ if (selEnd > endPos) {
+ selEnd = endPos;
+ }
+ var textPortion = text.substring(selStart, selEnd);
+ if (modeInfos[i - 1].modeName != "xml") { // Starting a CSS or JavaScript block
+ if (!reBlockStartsWithNewline.test(textPortion)
+ && selStart > 0) { // The block does not start with a line break
+ textPortion = "\n" + textPortion;
+ }
+ if (!reBlockEndsWithNewline.test(textPortion)
+ && selEnd < text.length - 1) { // The block does not end with a line break
+ textPortion += "\n";
+ }
+ }
+ res += modeInfos[i - 1].modeExt.autoFormatLineBreaks(textPortion);
+ }
+ }
+ else { // Single-mode text
+ res = modeInfos[0].modeExt.autoFormatLineBreaks(text.substring(startPos, endPos));
+ }
+
+ return res;
+ }
+};
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/javascript-hint.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/javascript-hint.js
new file mode 100644
index 0000000..2117e5a
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/javascript-hint.js
@@ -0,0 +1,134 @@
+(function () {
+ function forEach(arr, f) {
+ for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
+ }
+
+ function arrayContains(arr, item) {
+ if (!Array.prototype.indexOf) {
+ var i = arr.length;
+ while (i--) {
+ if (arr[i] === item) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return arr.indexOf(item) != -1;
+ }
+
+ function scriptHint(editor, keywords, getToken) {
+ // Find the token at the cursor
+ var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
+ // If it's not a 'word-style' token, ignore the token.
+ if (!/^[\w$_]*$/.test(token.string)) {
+ token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
+ className: token.string == "." ? "property" : null};
+ }
+ // If it is a property, find out what it is a property of.
+ while (tprop.className == "property") {
+ tprop = getToken(editor, {line: cur.line, ch: tprop.start});
+ if (tprop.string != ".") return;
+ tprop = getToken(editor, {line: cur.line, ch: tprop.start});
+ if (tprop.string == ')') {
+ var level = 1;
+ do {
+ tprop = getToken(editor, {line: cur.line, ch: tprop.start});
+ switch (tprop.string) {
+ case ')': level++; break;
+ case '(': level--; break;
+ default: break;
+ }
+ } while (level > 0)
+ tprop = getToken(editor, {line: cur.line, ch: tprop.start});
+ if (tprop.className == 'variable')
+ tprop.className = 'function';
+ else return; // no clue
+ }
+ if (!context) var context = [];
+ context.push(tprop);
+ }
+ return {list: getCompletions(token, context, keywords),
+ from: {line: cur.line, ch: token.start},
+ to: {line: cur.line, ch: token.end}};
+ }
+
+ CodeMirror.javascriptHint = function(editor) {
+ return scriptHint(editor, javascriptKeywords,
+ function (e, cur) {return e.getTokenAt(cur);});
+ }
+
+ function getCoffeeScriptToken(editor, cur) {
+ // This getToken, it is for coffeescript, imitates the behavior of
+ // getTokenAt method in javascript.js, that is, returning "property"
+ // type and treat "." as indepenent token.
+ var token = editor.getTokenAt(cur);
+ if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
+ token.end = token.start;
+ token.string = '.';
+ token.className = "property";
+ }
+ else if (/^\.[\w$_]*$/.test(token.string)) {
+ token.className = "property";
+ token.start++;
+ token.string = token.string.replace(/\./, '');
+ }
+ return token;
+ }
+
+ CodeMirror.coffeescriptHint = function(editor) {
+ return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken);
+ }
+
+ var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
+ "toUpperCase toLowerCase split concat match replace search").split(" ");
+ var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
+ "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
+ var funcProps = "prototype apply call bind".split(" ");
+ var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
+ "if in instanceof new null return switch throw true try typeof var void while with").split(" ");
+ var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
+ "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
+
+ function getCompletions(token, context, keywords) {
+ var found = [], start = token.string;
+ function maybeAdd(str) {
+ if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
+ }
+ function gatherCompletions(obj) {
+ if (typeof obj == "string") forEach(stringProps, maybeAdd);
+ else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
+ else if (obj instanceof Function) forEach(funcProps, maybeAdd);
+ for (var name in obj) maybeAdd(name);
+ }
+
+ if (context) {
+ // If this is a property, see if it belongs to some object we can
+ // find in the current environment.
+ var obj = context.pop(), base;
+ if (obj.className == "variable")
+ base = window[obj.string];
+ else if (obj.className == "string")
+ base = "";
+ else if (obj.className == "atom")
+ base = 1;
+ else if (obj.className == "function") {
+ if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
+ (typeof window.jQuery == 'function'))
+ base = window.jQuery();
+ else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function'))
+ base = window._();
+ }
+ while (base != null && context.length)
+ base = base[context.pop().string];
+ if (base != null) gatherCompletions(base);
+ }
+ else {
+ // If not, just look in the window object and any local scope
+ // (reading into JS mode internals to get at the local variables)
+ for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
+ gatherCompletions(window);
+ forEach(keywords, maybeAdd);
+ }
+ return found;
+ }
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/loadmode.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/loadmode.js
new file mode 100644
index 0000000..48d5a7a
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/loadmode.js
@@ -0,0 +1,51 @@
+(function() {
+ if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
+
+ var loading = {};
+ function splitCallback(cont, n) {
+ var countDown = n;
+ return function() { if (--countDown == 0) cont(); }
+ }
+ function ensureDeps(mode, cont) {
+ var deps = CodeMirror.modes[mode].dependencies;
+ if (!deps) return cont();
+ var missing = [];
+ for (var i = 0; i < deps.length; ++i) {
+ if (!CodeMirror.modes.hasOwnProperty(deps[i]))
+ missing.push(deps[i]);
+ }
+ if (!missing.length) return cont();
+ var split = splitCallback(cont, missing.length);
+ for (var i = 0; i < missing.length; ++i)
+ CodeMirror.requireMode(missing[i], split);
+ }
+
+ CodeMirror.requireMode = function(mode, cont) {
+ if (typeof mode != "string") mode = mode.name;
+ if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
+ if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
+
+ var script = document.createElement("script");
+ script.src = CodeMirror.modeURL.replace(/%N/g, mode);
+ var others = document.getElementsByTagName("script")[0];
+ others.parentNode.insertBefore(script, others);
+ var list = loading[mode] = [cont];
+ var count = 0, poll = setInterval(function() {
+ if (++count > 100) return clearInterval(poll);
+ if (CodeMirror.modes.hasOwnProperty(mode)) {
+ clearInterval(poll);
+ loading[mode] = null;
+ ensureDeps(mode, function() {
+ for (var i = 0; i < list.length; ++i) list[i]();
+ });
+ }
+ }, 200);
+ };
+
+ CodeMirror.autoLoadMode = function(instance, mode) {
+ if (!CodeMirror.modes.hasOwnProperty(mode))
+ CodeMirror.requireMode(mode, function() {
+ instance.setOption("mode", instance.getOption("mode"));
+ });
+ };
+}());
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/match-highlighter.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/match-highlighter.js
new file mode 100644
index 0000000..59098ff
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/match-highlighter.js
@@ -0,0 +1,44 @@
+// Define match-highlighter commands. Depends on searchcursor.js
+// Use by attaching the following function call to the onCursorActivity event:
+ //myCodeMirror.matchHighlight(minChars);
+// And including a special span.CodeMirror-matchhighlight css class (also optionally a separate one for .CodeMirror-focused -- see demo matchhighlighter.html)
+
+(function() {
+ var DEFAULT_MIN_CHARS = 2;
+
+ function MatchHighlightState() {
+ this.marked = [];
+ }
+ function getMatchHighlightState(cm) {
+ return cm._matchHighlightState || (cm._matchHighlightState = new MatchHighlightState());
+ }
+
+ function clearMarks(cm) {
+ var state = getMatchHighlightState(cm);
+ for (var i = 0; i < state.marked.length; ++i)
+ state.marked[i].clear();
+ state.marked = [];
+ }
+
+ function markDocument(cm, className, minChars) {
+ clearMarks(cm);
+ minChars = (typeof minChars !== 'undefined' ? minChars : DEFAULT_MIN_CHARS);
+ if (cm.somethingSelected() && cm.getSelection().replace(/^\s+|\s+$/g, "").length >= minChars) {
+ var state = getMatchHighlightState(cm);
+ var query = cm.getSelection();
+ cm.operation(function() {
+ if (cm.lineCount() < 2000) { // This is too expensive on big documents.
+ for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
+ //Only apply matchhighlight to the matches other than the one actually selected
+ if (!(cursor.from().line === cm.getCursor(true).line && cursor.from().ch === cm.getCursor(true).ch))
+ state.marked.push(cm.markText(cursor.from(), cursor.to(), className));
+ }
+ }
+ });
+ }
+ }
+
+ CodeMirror.defineExtension("matchHighlight", function(className, minChars) {
+ markDocument(this, className, minChars);
+ });
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/multiplex.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/multiplex.js
new file mode 100644
index 0000000..822ee62
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/multiplex.js
@@ -0,0 +1,72 @@
+CodeMirror.multiplexingMode = function(outer /*, others */) {
+ // Others should be {open, close, mode [, delimStyle]} objects
+ var others = Array.prototype.slice.call(arguments, 1);
+ var n_others = others.length;
+
+ return {
+ startState: function() {
+ return {
+ outer: CodeMirror.startState(outer),
+ innerActive: null,
+ inner: null
+ };
+ },
+
+ copyState: function(state) {
+ return {
+ outer: CodeMirror.copyState(outer, state.outer),
+ innerActive: state.innerActive,
+ inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
+ };
+ },
+
+ token: function(stream, state) {
+ if (!state.innerActive) {
+ for (var i = 0; i < n_others; ++i) {
+ var other = others[i];
+ if (stream.match(other.open)) {
+ state.innerActive = other;
+ state.inner = CodeMirror.startState(other.mode);
+ return other.delimStyle;
+ }
+ }
+ var outerToken = outer.token(stream, state.outer);
+ var cur = stream.current();
+ for (var i = 0; i < n_others; ++i) {
+ var other = others[i], found = cur.indexOf(other.open);
+ if (found > -1) {
+ stream.backUp(cur.length - found);
+ cur = cur.slice(0, found);
+ }
+ }
+ return outerToken;
+ } else {
+ var curInner = state.innerActive;
+ if (stream.match(curInner.close)) {
+ state.innerActive = state.inner = null;
+ return curInner.delimStyle;
+ }
+ var innerToken = curInner.mode.token(stream, state.inner);
+ var cur = stream.current(), found = cur.indexOf(curInner.close);
+ if (found > -1) stream.backUp(cur.length - found);
+ return innerToken;
+ }
+ },
+
+ indent: function(state, textAfter) {
+ var mode = state.innerActive || outer;
+ if (!mode.indent) return CodeMirror.Pass;
+ return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
+ },
+
+ compareStates: function(a, b) {
+ if (a.innerActive != b.innerActive) return false;
+ var mode = a.innerActive || outer;
+ if (!mode.compareStates) return CodeMirror.Pass;
+ return mode.compareStates(a.innerActive ? a.inner : a.outer,
+ b.innerActive ? b.inner : b.outer);
+ },
+
+ electricChars: outer.electricChars
+ };
+};
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/overlay.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/overlay.js
new file mode 100644
index 0000000..1d5df6c
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/overlay.js
@@ -0,0 +1,52 @@
+// Utility function that allows modes to be combined. The mode given
+// as the base argument takes care of most of the normal mode
+// functionality, but a second (typically simple) mode is used, which
+// can override the style of text. Both modes get to parse all of the
+// text, but when both assign a non-null style to a piece of code, the
+// overlay wins, unless the combine argument was true, in which case
+// the styles are combined.
+
+// overlayParser is the old, deprecated name
+CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, combine) {
+ return {
+ startState: function() {
+ return {
+ base: CodeMirror.startState(base),
+ overlay: CodeMirror.startState(overlay),
+ basePos: 0, baseCur: null,
+ overlayPos: 0, overlayCur: null
+ };
+ },
+ copyState: function(state) {
+ return {
+ base: CodeMirror.copyState(base, state.base),
+ overlay: CodeMirror.copyState(overlay, state.overlay),
+ basePos: state.basePos, baseCur: null,
+ overlayPos: state.overlayPos, overlayCur: null
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.start == state.basePos) {
+ state.baseCur = base.token(stream, state.base);
+ state.basePos = stream.pos;
+ }
+ if (stream.start == state.overlayPos) {
+ stream.pos = stream.start;
+ state.overlayCur = overlay.token(stream, state.overlay);
+ state.overlayPos = stream.pos;
+ }
+ stream.pos = Math.min(state.basePos, state.overlayPos);
+ if (stream.eol()) state.basePos = state.overlayPos = 0;
+
+ if (state.overlayCur == null) return state.baseCur;
+ if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
+ else return state.overlayCur;
+ },
+
+ indent: base.indent && function(state, textAfter) {
+ return base.indent(state.base, textAfter);
+ },
+ electricChars: base.electricChars
+ };
+};
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/pig-hint.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/pig-hint.js
new file mode 100644
index 0000000..233b72b
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/pig-hint.js
@@ -0,0 +1,123 @@
+(function () {
+ function forEach(arr, f) {
+ for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
+ }
+
+ function arrayContains(arr, item) {
+ if (!Array.prototype.indexOf) {
+ var i = arr.length;
+ while (i--) {
+ if (arr[i] === item) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return arr.indexOf(item) != -1;
+ }
+
+ function scriptHint(editor, keywords, getToken) {
+ // Find the token at the cursor
+ var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
+ // If it's not a 'word-style' token, ignore the token.
+
+ if (!/^[\w$_]*$/.test(token.string)) {
+ token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
+ className: token.string == ":" ? "pig-type" : null};
+ }
+
+ if (!context) var context = [];
+ context.push(tprop);
+
+ completionList = getCompletions(token, context);
+ completionList = completionList.sort();
+ //prevent autocomplete for last word, instead show dropdown with one word
+ if(completionList.length == 1) {
+ completionList.push(" ");
+ }
+
+ return {list: completionList,
+ from: {line: cur.line, ch: token.start},
+ to: {line: cur.line, ch: token.end}};
+ }
+
+ CodeMirror.pigHint = function(editor) {
+ return scriptHint(editor, pigKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
+ }
+
+ function toTitleCase(str) {
+ return str.replace(/(?:^|\s)\w/g, function(match) {
+ return match.toUpperCase();
+ });
+ }
+
+ var pigKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
+ + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
+ + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
+ + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
+ + "NEQ MATCHES TRUE FALSE";
+ var pigKeywordsU = pigKeywords.split(" ");
+ var pigKeywordsL = pigKeywords.toLowerCase().split(" ");
+
+ var pigTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP";
+ var pigTypesU = pigTypes.split(" ");
+ var pigTypesL = pigTypes.toLowerCase().split(" ");
+
+ var pigBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
+ + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
+ + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
+ + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
+ + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER "
+ + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS "
+ + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
+ + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
+ + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
+ + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER";
+ var pigBuiltinsU = pigBuiltins.split(" ").join("() ").split(" ");
+ var pigBuiltinsL = pigBuiltins.toLowerCase().split(" ").join("() ").split(" ");
+ var pigBuiltinsC = ("BagSize BinStorage Bloom BuildBloom ConstantSize CubeDimensions DoubleAbs "
+ + "DoubleAvg DoubleBase DoubleMax DoubleMin DoubleRound DoubleSum FloatAbs FloatAvg FloatMax "
+ + "FloatMin FloatRound FloatSum GenericInvoker IntAbs IntAvg IntMax IntMin IntSum "
+ + "InvokeForDouble InvokeForFloat InvokeForInt InvokeForLong InvokeForString Invoker "
+ + "IsEmpty JsonLoader JsonMetadata JsonStorage LongAbs LongAvg LongMax LongMin LongSum MapSize "
+ + "MonitoredUDF Nondeterministic OutputSchema PigStorage PigStreaming StringConcat StringMax "
+ + "StringMin StringSize TextLoader TupleSize Utf8StorageConverter").split(" ").join("() ").split(" ");
+
+ function getCompletions(token, context) {
+ var found = [], start = token.string;
+ function maybeAdd(str) {
+ if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
+ }
+
+ function gatherCompletions(obj) {
+ if(obj == ":") {
+ forEach(pigTypesL, maybeAdd);
+ }
+ else {
+ forEach(pigBuiltinsU, maybeAdd);
+ forEach(pigBuiltinsL, maybeAdd);
+ forEach(pigBuiltinsC, maybeAdd);
+ forEach(pigTypesU, maybeAdd);
+ forEach(pigTypesL, maybeAdd);
+ forEach(pigKeywordsU, maybeAdd);
+ forEach(pigKeywordsL, maybeAdd);
+ }
+ }
+
+ if (context) {
+ // If this is a property, see if it belongs to some object we can
+ // find in the current environment.
+ var obj = context.pop(), base;
+
+ if (obj.className == "pig-word")
+ base = obj.string;
+ else if(obj.className == "pig-type")
+ base = ":" + obj.string;
+
+ while (base != null && context.length)
+ base = base[context.pop().string];
+ if (base != null) gatherCompletions(base);
+ }
+ return found;
+ }
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/runmode.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/runmode.js
new file mode 100644
index 0000000..fc58d85
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/runmode.js
@@ -0,0 +1,49 @@
+CodeMirror.runMode = function(string, modespec, callback, options) {
+ var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
+ var isNode = callback.nodeType == 1;
+ var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
+ if (isNode) {
+ var node = callback, accum = [], col = 0;
+ callback = function(text, style) {
+ if (text == "\n") {
+ accum.push("<br>");
+ col = 0;
+ return;
+ }
+ var escaped = "";
+ // HTML-escape and replace tabs
+ for (var pos = 0;;) {
+ var idx = text.indexOf("\t", pos);
+ if (idx == -1) {
+ escaped += CodeMirror.htmlEscape(text.slice(pos));
+ col += text.length - pos;
+ break;
+ } else {
+ col += idx - pos;
+ escaped += CodeMirror.htmlEscape(text.slice(pos, idx));
+ var size = tabSize - col % tabSize;
+ col += size;
+ for (var i = 0; i < size; ++i) escaped += " ";
+ pos = idx + 1;
+ }
+ }
+
+ if (style)
+ accum.push("<span class=\"cm-" + CodeMirror.htmlEscape(style) + "\">" + escaped + "</span>");
+ else
+ accum.push(escaped);
+ }
+ }
+ var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
+ for (var i = 0, e = lines.length; i < e; ++i) {
+ if (i) callback("\n");
+ var stream = new CodeMirror.StringStream(lines[i]);
+ while (!stream.eol()) {
+ var style = mode.token(stream, state);
+ callback(stream.current(), style, i, stream.start);
+ stream.start = stream.pos;
+ }
+ }
+ if (isNode)
+ node.innerHTML = accum.join("");
+};
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/search.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/search.js
new file mode 100644
index 0000000..c5a2bcc
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/search.js
@@ -0,0 +1,118 @@
+// Define search commands. Depends on dialog.js or another
+// implementation of the openDialog method.
+
+// Replace works a little oddly -- it will do the replace on the next
+// Ctrl-G (or whatever is bound to findNext) press. You prevent a
+// replace by making sure the match is no longer selected when hitting
+// Ctrl-G.
+
+(function() {
+ function SearchState() {
+ this.posFrom = this.posTo = this.query = null;
+ this.marked = [];
+ }
+ function getSearchState(cm) {
+ return cm._searchState || (cm._searchState = new SearchState());
+ }
+ function getSearchCursor(cm, query, pos) {
+ // Heuristic: if the query string is all lowercase, do a case insensitive search.
+ return cm.getSearchCursor(query, pos, typeof query == "string" && query == query.toLowerCase());
+ }
+ function dialog(cm, text, shortText, f) {
+ if (cm.openDialog) cm.openDialog(text, f);
+ else f(prompt(shortText, ""));
+ }
+ function confirmDialog(cm, text, shortText, fs) {
+ if (cm.openConfirm) cm.openConfirm(text, fs);
+ else if (confirm(shortText)) fs[0]();
+ }
+ function parseQuery(query) {
+ var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
+ return isRE ? new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i") : query;
+ }
+ var queryDialog =
+ 'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
+ function doSearch(cm, rev) {
+ var state = getSearchState(cm);
+ if (state.query) return findNext(cm, rev);
+ dialog(cm, queryDialog, "Search for:", function(query) {
+ cm.operation(function() {
+ if (!query || state.query) return;
+ state.query = parseQuery(query);
+ if (cm.lineCount() < 2000) { // This is too expensive on big documents.
+ for (var cursor = getSearchCursor(cm, query); cursor.findNext();)
+ state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
+ }
+ state.posFrom = state.posTo = cm.getCursor();
+ findNext(cm, rev);
+ });
+ });
+ }
+ function findNext(cm, rev) {cm.operation(function() {
+ var state = getSearchState(cm);
+ var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
+ if (!cursor.find(rev)) {
+ cursor = getSearchCursor(cm, state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
+ if (!cursor.find(rev)) return;
+ }
+ cm.setSelection(cursor.from(), cursor.to());
+ state.posFrom = cursor.from(); state.posTo = cursor.to();
+ })}
+ function clearSearch(cm) {cm.operation(function() {
+ var state = getSearchState(cm);
+ if (!state.query) return;
+ state.query = null;
+ for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear();
+ state.marked.length = 0;
+ })}
+
+ var replaceQueryDialog =
+ 'Replace: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
+ var replacementQueryDialog = 'With: <input type="text" style="width: 10em"/>';
+ var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
+ function replace(cm, all) {
+ dialog(cm, replaceQueryDialog, "Replace:", function(query) {
+ if (!query) return;
+ query = parseQuery(query);
+ dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
+ if (all) {
+ cm.compoundChange(function() { cm.operation(function() {
+ for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
+ if (typeof query != "string") {
+ var match = cm.getRange(cursor.from(), cursor.to()).match(query);
+ cursor.replace(text.replace(/\$(\d)/, function(w, i) {return match[i];}));
+ } else cursor.replace(text);
+ }
+ })});
+ } else {
+ clearSearch(cm);
+ var cursor = getSearchCursor(cm, query, cm.getCursor());
+ function advance() {
+ var start = cursor.from(), match;
+ if (!(match = cursor.findNext())) {
+ cursor = getSearchCursor(cm, query);
+ if (!(match = cursor.findNext()) ||
+ (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
+ }
+ cm.setSelection(cursor.from(), cursor.to());
+ confirmDialog(cm, doReplaceConfirm, "Replace?",
+ [function() {doReplace(match);}, advance]);
+ }
+ function doReplace(match) {
+ cursor.replace(typeof query == "string" ? text :
+ text.replace(/\$(\d)/, function(w, i) {return match[i];}));
+ advance();
+ }
+ advance();
+ }
+ });
+ });
+ }
+
+ CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
+ CodeMirror.commands.findNext = doSearch;
+ CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
+ CodeMirror.commands.clearSearch = clearSearch;
+ CodeMirror.commands.replace = replace;
+ CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/searchcursor.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/searchcursor.js
new file mode 100644
index 0000000..ec3f73c
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/searchcursor.js
@@ -0,0 +1,117 @@
+(function(){
+ function SearchCursor(cm, query, pos, caseFold) {
+ this.atOccurrence = false; this.cm = cm;
+ if (caseFold == null && typeof query == "string") caseFold = false;
+
+ pos = pos ? cm.clipPos(pos) : {line: 0, ch: 0};
+ this.pos = {from: pos, to: pos};
+
+ // The matches method is filled in based on the type of query.
+ // It takes a position and a direction, and returns an object
+ // describing the next occurrence of the query, or null if no
+ // more matches were found.
+ if (typeof query != "string") // Regexp match
+ this.matches = function(reverse, pos) {
+ if (reverse) {
+ var line = cm.getLine(pos.line).slice(0, pos.ch), match = line.match(query), start = 0;
+ while (match) {
+ var ind = line.indexOf(match[0]);
+ start += ind;
+ line = line.slice(ind + 1);
+ var newmatch = line.match(query);
+ if (newmatch) match = newmatch;
+ else break;
+ start++;
+ }
+ }
+ else {
+ var line = cm.getLine(pos.line).slice(pos.ch), match = line.match(query),
+ start = match && pos.ch + line.indexOf(match[0]);
+ }
+ if (match)
+ return {from: {line: pos.line, ch: start},
+ to: {line: pos.line, ch: start + match[0].length},
+ match: match};
+ };
+ else { // String query
+ if (caseFold) query = query.toLowerCase();
+ var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
+ var target = query.split("\n");
+ // Different methods for single-line and multi-line queries
+ if (target.length == 1)
+ this.matches = function(reverse, pos) {
+ var line = fold(cm.getLine(pos.line)), len = query.length, match;
+ if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
+ : (match = line.indexOf(query, pos.ch)) != -1)
+ return {from: {line: pos.line, ch: match},
+ to: {line: pos.line, ch: match + len}};
+ };
+ else
+ this.matches = function(reverse, pos) {
+ var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln));
+ var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
+ if (reverse ? offsetA >= pos.ch || offsetA != match.length
+ : offsetA <= pos.ch || offsetA != line.length - match.length)
+ return;
+ for (;;) {
+ if (reverse ? !ln : ln == cm.lineCount() - 1) return;
+ line = fold(cm.getLine(ln += reverse ? -1 : 1));
+ match = target[reverse ? --idx : ++idx];
+ if (idx > 0 && idx < target.length - 1) {
+ if (line != match) return;
+ else continue;
+ }
+ var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
+ if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
+ return;
+ var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
+ return {from: reverse ? end : start, to: reverse ? start : end};
+ }
+ };
+ }
+ }
+
+ SearchCursor.prototype = {
+ findNext: function() {return this.find(false);},
+ findPrevious: function() {return this.find(true);},
+
+ find: function(reverse) {
+ var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to);
+ function savePosAndFail(line) {
+ var pos = {line: line, ch: 0};
+ self.pos = {from: pos, to: pos};
+ self.atOccurrence = false;
+ return false;
+ }
+
+ for (;;) {
+ if (this.pos = this.matches(reverse, pos)) {
+ this.atOccurrence = true;
+ return this.pos.match || true;
+ }
+ if (reverse) {
+ if (!pos.line) return savePosAndFail(0);
+ pos = {line: pos.line-1, ch: this.cm.getLine(pos.line-1).length};
+ }
+ else {
+ var maxLine = this.cm.lineCount();
+ if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
+ pos = {line: pos.line+1, ch: 0};
+ }
+ }
+ },
+
+ from: function() {if (this.atOccurrence) return this.pos.from;},
+ to: function() {if (this.atOccurrence) return this.pos.to;},
+
+ replace: function(newText) {
+ var self = this;
+ if (this.atOccurrence)
+ self.pos.to = this.cm.replaceRange(newText, self.pos.from, self.pos.to);
+ }
+ };
+
+ CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
+ return new SearchCursor(this, query, pos, caseFold);
+ });
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/simple-hint.css b/codemirror_ui/lib/CodeMirror-2.3/lib/util/simple-hint.css
new file mode 100644
index 0000000..4387cb9
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/simple-hint.css
@@ -0,0 +1,16 @@
+.CodeMirror-completions {
+ position: absolute;
+ z-index: 10;
+ overflow: hidden;
+ -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+ -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+ box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+}
+.CodeMirror-completions select {
+ background: #fafafa;
+ outline: none;
+ border: none;
+ padding: 0;
+ margin: 0;
+ font-family: monospace;
+}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/lib/util/simple-hint.js b/codemirror_ui/lib/CodeMirror-2.3/lib/util/simple-hint.js
new file mode 100644
index 0000000..7decd58
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/lib/util/simple-hint.js
@@ -0,0 +1,72 @@
+(function() {
+ CodeMirror.simpleHint = function(editor, getHints) {
+ // We want a single cursor position.
+ if (editor.somethingSelected()) return;
+ var result = getHints(editor);
+ if (!result || !result.list.length) return;
+ var completions = result.list;
+ function insert(str) {
+ editor.replaceRange(str, result.from, result.to);
+ }
+ // When there is only one completion, use it directly.
+ if (completions.length == 1) {insert(completions[0]); return true;}
+
+ // Build the select widget
+ var complete = document.createElement("div");
+ complete.className = "CodeMirror-completions";
+ var sel = complete.appendChild(document.createElement("select"));
+ // Opera doesn't move the selection when pressing up/down in a
+ // multi-select, but it does properly support the size property on
+ // single-selects, so no multi-select is necessary.
+ if (!window.opera) sel.multiple = true;
+ for (var i = 0; i < completions.length; ++i) {
+ var opt = sel.appendChild(document.createElement("option"));
+ opt.appendChild(document.createTextNode(completions[i]));
+ }
+ sel.firstChild.selected = true;
+ sel.size = Math.min(10, completions.length);
+ var pos = editor.cursorCoords();
+ complete.style.left = pos.x + "px";
+ complete.style.top = pos.yBot + "px";
+ document.body.appendChild(complete);
+ // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
+ var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
+ if(winW - pos.x < sel.clientWidth)
+ complete.style.left = (pos.x - sel.clientWidth) + "px";
+ // Hack to hide the scrollbar.
+ if (completions.length <= 10)
+ complete.style.width = (sel.clientWidth - 1) + "px";
+
+ var done = false;
+ function close() {
+ if (done) return;
+ done = true;
+ complete.parentNode.removeChild(complete);
+ }
+ function pick() {
+ insert(completions[sel.selectedIndex]);
+ close();
+ setTimeout(function(){editor.focus();}, 50);
+ }
+ CodeMirror.connect(sel, "blur", close);
+ CodeMirror.connect(sel, "keydown", function(event) {
+ var code = event.keyCode;
+ // Enter
+ if (code == 13) {CodeMirror.e_stop(event); pick();}
+ // Escape
+ else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();}
+ else if (code != 38 && code != 40) {
+ close(); editor.focus();
+ // Pass the event to the CodeMirror instance so that it can handle things like backspace properly.
+ editor.triggerOnKeyDown(event);
+ setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50);
+ }
+ });
+ CodeMirror.connect(sel, "dblclick", pick);
+
+ sel.focus();
+ // Opera sometimes ignores focusing a freshly created node
+ if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100);
+ return true;
+ };
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/clike/clike.js b/codemirror_ui/lib/CodeMirror-2.3/mode/clike/clike.js
new file mode 100644
index 0000000..0e7f48b
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/clike/clike.js
@@ -0,0 +1,271 @@
+CodeMirror.defineMode("clike", function(config, parserConfig) {
+ var indentUnit = config.indentUnit,
+ keywords = parserConfig.keywords || {},
+ blockKeywords = parserConfig.blockKeywords || {},
+ atoms = parserConfig.atoms || {},
+ hooks = parserConfig.hooks || {},
+ multiLineStrings = parserConfig.multiLineStrings;
+ var isOperatorChar = /[+\-*&%=<>!?|\/]/;
+
+ var curPunc;
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ if (hooks[ch]) {
+ var result = hooks[ch](stream, state);
+ if (result !== false) return result;
+ }
+ if (ch == '"' || ch == "'") {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ }
+ if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+ curPunc = ch;
+ return null;
+ }
+ if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return "number";
+ }
+ if (ch == "/") {
+ if (stream.eat("*")) {
+ state.tokenize = tokenComment;
+ return tokenComment(stream, state);
+ }
+ if (stream.eat("/")) {
+ stream.skipToEnd();
+ return "comment";
+ }
+ }
+ if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return "operator";
+ }
+ stream.eatWhile(/[\w\$_]/);
+ var cur = stream.current();
+ if (keywords.propertyIsEnumerable(cur)) {
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+ return "keyword";
+ }
+ if (atoms.propertyIsEnumerable(cur)) return "atom";
+ return "word";
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {end = true; break;}
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = null;
+ return "string";
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = null;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return "comment";
+ }
+
+ function Context(indented, column, type, align, prev) {
+ this.indented = indented;
+ this.column = column;
+ this.type = type;
+ this.align = align;
+ this.prev = prev;
+ }
+ function pushContext(state, col, type) {
+ return state.context = new Context(state.indented, col, type, null, state.context);
+ }
+ function popContext(state) {
+ var t = state.context.type;
+ if (t == ")" || t == "]" || t == "}")
+ state.indented = state.context.indented;
+ return state.context = state.context.prev;
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: null,
+ context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
+ indented: 0,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ var ctx = state.context;
+ if (stream.sol()) {
+ if (ctx.align == null) ctx.align = false;
+ state.indented = stream.indentation();
+ state.startOfLine = true;
+ }
+ if (stream.eatSpace()) return null;
+ curPunc = null;
+ var style = (state.tokenize || tokenBase)(stream, state);
+ if (style == "comment" || style == "meta") return style;
+ if (ctx.align == null) ctx.align = true;
+
+ if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
+ else if (curPunc == "{") pushContext(state, stream.column(), "}");
+ else if (curPunc == "[") pushContext(state, stream.column(), "]");
+ else if (curPunc == "(") pushContext(state, stream.column(), ")");
+ else if (curPunc == "}") {
+ while (ctx.type == "statement") ctx = popContext(state);
+ if (ctx.type == "}") ctx = popContext(state);
+ while (ctx.type == "statement") ctx = popContext(state);
+ }
+ else if (curPunc == ctx.type) popContext(state);
+ else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
+ pushContext(state, stream.column(), "statement");
+ state.startOfLine = false;
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != tokenBase && state.tokenize != null) return 0;
+ var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
+ if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
+ var closing = firstChar == ctx.type;
+ if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
+ else if (ctx.align) return ctx.column + (closing ? 0 : 1);
+ else return ctx.indented + (closing ? 0 : indentUnit);
+ },
+
+ electricChars: "{}"
+ };
+});
+
+(function() {
+ function words(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+ var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
+ "double static else struct entry switch extern typedef float union for unsigned " +
+ "goto while enum void const signed volatile";
+
+ function cppHook(stream, state) {
+ if (!state.startOfLine) return false;
+ stream.skipToEnd();
+ return "meta";
+ }
+
+ // C#-style strings where "" escapes a quote.
+ function tokenAtString(stream, state) {
+ var next;
+ while ((next = stream.next()) != null) {
+ if (next == '"' && !stream.eat('"')) {
+ state.tokenize = null;
+ break;
+ }
+ }
+ return "string";
+ }
+
+ CodeMirror.defineMIME("text/x-csrc", {
+ name: "clike",
+ keywords: words(cKeywords),
+ blockKeywords: words("case do else for if switch while struct"),
+ atoms: words("null"),
+ hooks: {"#": cppHook}
+ });
+ CodeMirror.defineMIME("text/x-c++src", {
+ name: "clike",
+ keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
+ "static_cast typeid catch operator template typename class friend private " +
+ "this using const_cast inline public throw virtual delete mutable protected " +
+ "wchar_t"),
+ blockKeywords: words("catch class do else finally for if struct switch try while"),
+ atoms: words("true false null"),
+ hooks: {"#": cppHook}
+ });
+ CodeMirror.defineMIME("text/x-java", {
+ name: "clike",
+ keywords: words("abstract assert boolean break byte case catch char class const continue default " +
+ "do double else enum extends final finally float for goto if implements import " +
+ "instanceof int interface long native new package private protected public " +
+ "return short static strictfp super switch synchronized this throw throws transient " +
+ "try void volatile while"),
+ blockKeywords: words("catch class do else finally for if switch try while"),
+ atoms: words("true false null"),
+ hooks: {
+ "@": function(stream, state) {
+ stream.eatWhile(/[\w\$_]/);
+ return "meta";
+ }
+ }
+ });
+ CodeMirror.defineMIME("text/x-csharp", {
+ name: "clike",
+ keywords: words("abstract as base bool break byte case catch char checked class const continue decimal" +
+ " default delegate do double else enum event explicit extern finally fixed float for" +
+ " foreach goto if implicit in int interface internal is lock long namespace new object" +
+ " operator out override params private protected public readonly ref return sbyte sealed short" +
+ " sizeof stackalloc static string struct switch this throw try typeof uint ulong unchecked" +
+ " unsafe ushort using virtual void volatile while add alias ascending descending dynamic from get" +
+ " global group into join let orderby partial remove select set value var yield"),
+ blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
+ atoms: words("true false null"),
+ hooks: {
+ "@": function(stream, state) {
+ if (stream.eat('"')) {
+ state.tokenize = tokenAtString;
+ return tokenAtString(stream, state);
+ }
+ stream.eatWhile(/[\w\$_]/);
+ return "meta";
+ }
+ }
+ });
+ CodeMirror.defineMIME("text/x-scala", {
+ name: "clike",
+ keywords: words(
+
+ /* scala */
+ "abstract case catch class def do else extends false final finally for forSome if " +
+ "implicit import lazy match new null object override package private protected return " +
+ "sealed super this throw trait try trye type val var while with yield _ : = => <- <: " +
+ "<% >: # @ " +
+
+ /* package scala */
+ "assert assume require print println printf readLine readBoolean readByte readShort " +
+ "readChar readInt readLong readFloat readDouble " +
+
+ "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
+ "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
+ "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
+ "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
+ "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " +
+
+ /* package java.lang */
+ "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
+ "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
+ "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
+ "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
+
+
+ ),
+ blockKeywords: words("catch class do else finally for forSome if match switch try while"),
+ atoms: words("true false null"),
+ hooks: {
+ "@": function(stream, state) {
+ stream.eatWhile(/[\w\$_]/);
+ return "meta";
+ }
+ }
+ });
+}());
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/clike/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/clike/index.html
new file mode 100644
index 0000000..64d02f1
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/clike/index.html
@@ -0,0 +1,101 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: C-like mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="clike.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>.CodeMirror {border: 2px inset #dee;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: C-like mode</h1>
+
+<form><textarea id="code" name="code">
+/* C demo code */
+
+#include <zmq.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <malloc.h>
+
+typedef struct {
+ void* arg_socket;
+ zmq_msg_t* arg_msg;
+ char* arg_string;
+ unsigned long arg_len;
+ int arg_int, arg_command;
+
+ int signal_fd;
+ int pad;
+ void* context;
+ sem_t sem;
+} acl_zmq_context;
+
+#define p(X) (context->arg_##X)
+
+void* zmq_thread(void* context_pointer) {
+ acl_zmq_context* context = (acl_zmq_context*)context_pointer;
+ char ok = 'K', err = 'X';
+ int res;
+
+ while (1) {
+ while ((res = sem_wait(&amp;context->sem)) == EINTR);
+ if (res) {write(context->signal_fd, &amp;err, 1); goto cleanup;}
+ switch(p(command)) {
+ case 0: goto cleanup;
+ case 1: p(socket) = zmq_socket(context->context, p(int)); break;
+ case 2: p(int) = zmq_close(p(socket)); break;
+ case 3: p(int) = zmq_bind(p(socket), p(string)); break;
+ case 4: p(int) = zmq_connect(p(socket), p(string)); break;
+ case 5: p(int) = zmq_getsockopt(p(socket), p(int), (void*)p(string), &amp;p(len)); break;
+ case 6: p(int) = zmq_setsockopt(p(socket), p(int), (void*)p(string), p(len)); break;
+ case 7: p(int) = zmq_send(p(socket), p(msg), p(int)); break;
+ case 8: p(int) = zmq_recv(p(socket), p(msg), p(int)); break;
+ case 9: p(int) = zmq_poll(p(socket), p(int), p(len)); break;
+ }
+ p(command) = errno;
+ write(context->signal_fd, &amp;ok, 1);
+ }
+ cleanup:
+ close(context->signal_fd);
+ free(context_pointer);
+ return 0;
+}
+
+void* zmq_thread_init(void* zmq_context, int signal_fd) {
+ acl_zmq_context* context = malloc(sizeof(acl_zmq_context));
+ pthread_t thread;
+
+ context->context = zmq_context;
+ context->signal_fd = signal_fd;
+ sem_init(&amp;context->sem, 1, 0);
+ pthread_create(&amp;thread, 0, &amp;zmq_thread, context);
+ pthread_detach(thread);
+ return context;
+}
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ mode: "text/x-csrc"
+ });
+ </script>
+
+ <p>Simple mode that tries to handle C-like languages as well as it
+ can. Takes two configuration parameters: <code>keywords</code>, an
+ object whose property names are the keywords in the language,
+ and <code>useCPP</code>, which determines whether C preprocessor
+ directives are recognized.</p>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-csrc</code>
+ (C code), <code>text/x-c++src</code> (C++
+ code), <code>text/x-java</code> (Java
+ code), <code>text/x-csharp</code> (C#).</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/clike/scala.html b/codemirror_ui/lib/CodeMirror-2.3/mode/clike/scala.html
new file mode 100644
index 0000000..5fdd84e
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/clike/scala.html
@@ -0,0 +1,765 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: C-like mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <link rel="stylesheet" href="../../theme/ambiance.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="clike.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>
+ body
+ {
+ margin: 0;
+ padding: 0;
+ max-width:inherit;
+ height: 100%;
+ }
+ html, form, .CodeMirror, .CodeMirror-scroll
+ {
+ height: 100%;
+ }
+ </style>
+ </head>
+ <body>
+<form>
+<textarea id="code" name="code">
+
+ /* __ *\
+ ** ________ ___ / / ___ Scala API **
+ ** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
+ ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+ ** /____/\___/_/ |_/____/_/ | | **
+ ** |/ **
+ \* */
+
+ package scala.collection
+
+ import generic._
+ import mutable.{ Builder, ListBuffer }
+ import annotation.{tailrec, migration, bridge}
+ import annotation.unchecked.{ uncheckedVariance => uV }
+ import parallel.ParIterable
+
+ /** A template trait for traversable collections of type `Traversable[A]`.
+ *
+ * $traversableInfo
+ * @define mutability
+ * @define traversableInfo
+ * This is a base trait of all kinds of $mutability Scala collections. It
+ * implements the behavior common to all collections, in terms of a method
+ * `foreach` with signature:
+ * {{{
+ * def foreach[U](f: Elem => U): Unit
+ * }}}
+ * Collection classes mixing in this trait provide a concrete
+ * `foreach` method which traverses all the
+ * elements contained in the collection, applying a given function to each.
+ * They also need to provide a method `newBuilder`
+ * which creates a builder for collections of the same kind.
+ *
+ * A traversable class might or might not have two properties: strictness
+ * and orderedness. Neither is represented as a type.
+ *
+ * The instances of a strict collection class have all their elements
+ * computed before they can be used as values. By contrast, instances of
+ * a non-strict collection class may defer computation of some of their
+ * elements until after the instance is available as a value.
+ * A typical example of a non-strict collection class is a
+ * <a href="../immutable/Stream.html" target="ContentFrame">
+ * `scala.collection.immutable.Stream`</a>.
+ * A more general class of examples are `TraversableViews`.
+ *
+ * If a collection is an instance of an ordered collection class, traversing
+ * its elements with `foreach` will always visit elements in the
+ * same order, even for different runs of the program. If the class is not
+ * ordered, `foreach` can visit elements in different orders for
+ * different runs (but it will keep the same order in the same run).'
+ *
+ * A typical example of a collection class which is not ordered is a
+ * `HashMap` of objects. The traversal order for hash maps will
+ * depend on the hash codes of its elements, and these hash codes might
+ * differ from one run to the next. By contrast, a `LinkedHashMap`
+ * is ordered because it's `foreach` method visits elements in the
+ * order they were inserted into the `HashMap`.
+ *
+ * @author Martin Odersky
+ * @version 2.8
+ * @since 2.8
+ * @tparam A the element type of the collection
+ * @tparam Repr the type of the actual collection containing the elements.
+ *
+ * @define Coll Traversable
+ * @define coll traversable collection
+ */
+ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr]
+ with FilterMonadic[A, Repr]
+ with TraversableOnce[A]
+ with GenTraversableLike[A, Repr]
+ with Parallelizable[A, ParIterable[A]]
+ {
+ self =>
+
+ import Traversable.breaks._
+
+ /** The type implementing this traversable */
+ protected type Self = Repr
+
+ /** The collection of type $coll underlying this `TraversableLike` object.
+ * By default this is implemented as the `TraversableLike` object itself,
+ * but this can be overridden.
+ */
+ def repr: Repr = this.asInstanceOf[Repr]
+
+ /** The underlying collection seen as an instance of `$Coll`.
+ * By default this is implemented as the current collection object itself,
+ * but this can be overridden.
+ */
+ protected[this] def thisCollection: Traversable[A] = this.asInstanceOf[Traversable[A]]
+
+ /** A conversion from collections of type `Repr` to `$Coll` objects.
+ * By default this is implemented as just a cast, but this can be overridden.
+ */
+ protected[this] def toCollection(repr: Repr): Traversable[A] = repr.asInstanceOf[Traversable[A]]
+
+ /** Creates a new builder for this collection type.
+ */
+ protected[this] def newBuilder: Builder[A, Repr]
+
+ protected[this] def parCombiner = ParIterable.newCombiner[A]
+
+ /** Applies a function `f` to all elements of this $coll.
+ *
+ * Note: this method underlies the implementation of most other bulk operations.
+ * It's important to implement this method in an efficient way.
+ *
+ *
+ * @param f the function that is applied for its side-effect to every element.
+ * The result of function `f` is discarded.
+ *
+ * @tparam U the type parameter describing the result of function `f`.
+ * This result will always be ignored. Typically `U` is `Unit`,
+ * but this is not necessary.
+ *
+ * @usecase def foreach(f: A => Unit): Unit
+ */
+ def foreach[U](f: A => U): Unit
+
+ /** Tests whether this $coll is empty.
+ *
+ * @return `true` if the $coll contain no elements, `false` otherwise.
+ */
+ def isEmpty: Boolean = {
+ var result = true
+ breakable {
+ for (x <- this) {
+ result = false
+ break
+ }
+ }
+ result
+ }
+
+ /** Tests whether this $coll is known to have a finite size.
+ * All strict collections are known to have finite size. For a non-strict collection
+ * such as `Stream`, the predicate returns `true` if all elements have been computed.
+ * It returns `false` if the stream is not yet evaluated to the end.
+ *
+ * Note: many collection methods will not work on collections of infinite sizes.
+ *
+ * @return `true` if this collection is known to have finite size, `false` otherwise.
+ */
+ def hasDefiniteSize = true
+
+ def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ if (that.isInstanceOf[IndexedSeqLike[_, _]]) b.sizeHint(this, that.seq.size)
+ b ++= thisCollection
+ b ++= that.seq
+ b.result
+ }
+
+ @bridge
+ def ++[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That =
+ ++(that: GenTraversableOnce[B])(bf)
+
+ /** Concatenates this $coll with the elements of a traversable collection.
+ * It differs from ++ in that the right operand determines the type of the
+ * resulting collection rather than the left one.
+ *
+ * @param that the traversable to append.
+ * @tparam B the element type of the returned collection.
+ * @tparam That $thatinfo
+ * @param bf $bfinfo
+ * @return a new collection of type `That` which contains all elements
+ * of this $coll followed by all elements of `that`.
+ *
+ * @usecase def ++:[B](that: TraversableOnce[B]): $Coll[B]
+ *
+ * @return a new $coll which contains all elements of this $coll
+ * followed by all elements of `that`.
+ */
+ def ++:[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ if (that.isInstanceOf[IndexedSeqLike[_, _]]) b.sizeHint(this, that.size)
+ b ++= that
+ b ++= thisCollection
+ b.result
+ }
+
+ /** This overload exists because: for the implementation of ++: we should reuse
+ * that of ++ because many collections override it with more efficient versions.
+ * Since TraversableOnce has no '++' method, we have to implement that directly,
+ * but Traversable and down can use the overload.
+ */
+ def ++:[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[Repr, B, That]): That =
+ (that ++ seq)(breakOut)
+
+ def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ b.sizeHint(this)
+ for (x <- this) b += f(x)
+ b.result
+ }
+
+ def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ for (x <- this) b ++= f(x).seq
+ b.result
+ }
+
+ /** Selects all elements of this $coll which satisfy a predicate.
+ *
+ * @param p the predicate used to test elements.
+ * @return a new $coll consisting of all elements of this $coll that satisfy the given
+ * predicate `p`. The order of the elements is preserved.
+ */
+ def filter(p: A => Boolean): Repr = {
+ val b = newBuilder
+ for (x <- this)
+ if (p(x)) b += x
+ b.result
+ }
+
+ /** Selects all elements of this $coll which do not satisfy a predicate.
+ *
+ * @param p the predicate used to test elements.
+ * @return a new $coll consisting of all elements of this $coll that do not satisfy the given
+ * predicate `p`. The order of the elements is preserved.
+ */
+ def filterNot(p: A => Boolean): Repr = filter(!p(_))
+
+ def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ for (x <- this) if (pf.isDefinedAt(x)) b += pf(x)
+ b.result
+ }
+
+ /** Builds a new collection by applying an option-valued function to all
+ * elements of this $coll on which the function is defined.
+ *
+ * @param f the option-valued function which filters and maps the $coll.
+ * @tparam B the element type of the returned collection.
+ * @tparam That $thatinfo
+ * @param bf $bfinfo
+ * @return a new collection of type `That` resulting from applying the option-valued function
+ * `f` to each element and collecting all defined results.
+ * The order of the elements is preserved.
+ *
+ * @usecase def filterMap[B](f: A => Option[B]): $Coll[B]
+ *
+ * @param pf the partial function which filters and maps the $coll.
+ * @return a new $coll resulting from applying the given option-valued function
+ * `f` to each element and collecting all defined results.
+ * The order of the elements is preserved.
+ def filterMap[B, That](f: A => Option[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ for (x <- this)
+ f(x) match {
+ case Some(y) => b += y
+ case _ =>
+ }
+ b.result
+ }
+ */
+
+ /** Partitions this $coll in two ${coll}s according to a predicate.
+ *
+ * @param p the predicate on which to partition.
+ * @return a pair of ${coll}s: the first $coll consists of all elements that
+ * satisfy the predicate `p` and the second $coll consists of all elements
+ * that don't. The relative order of the elements in the resulting ${coll}s
+ * is the same as in the original $coll.
+ */
+ def partition(p: A => Boolean): (Repr, Repr) = {
+ val l, r = newBuilder
+ for (x <- this) (if (p(x)) l else r) += x
+ (l.result, r.result)
+ }
+
+ def groupBy[K](f: A => K): immutable.Map[K, Repr] = {
+ val m = mutable.Map.empty[K, Builder[A, Repr]]
+ for (elem <- this) {
+ val key = f(elem)
+ val bldr = m.getOrElseUpdate(key, newBuilder)
+ bldr += elem
+ }
+ val b = immutable.Map.newBuilder[K, Repr]
+ for ((k, v) <- m)
+ b += ((k, v.result))
+
+ b.result
+ }
+
+ /** Tests whether a predicate holds for all elements of this $coll.
+ *
+ * $mayNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return `true` if the given predicate `p` holds for all elements
+ * of this $coll, otherwise `false`.
+ */
+ def forall(p: A => Boolean): Boolean = {
+ var result = true
+ breakable {
+ for (x <- this)
+ if (!p(x)) { result = false; break }
+ }
+ result
+ }
+
+ /** Tests whether a predicate holds for some of the elements of this $coll.
+ *
+ * $mayNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return `true` if the given predicate `p` holds for some of the
+ * elements of this $coll, otherwise `false`.
+ */
+ def exists(p: A => Boolean): Boolean = {
+ var result = false
+ breakable {
+ for (x <- this)
+ if (p(x)) { result = true; break }
+ }
+ result
+ }
+
+ /** Finds the first element of the $coll satisfying a predicate, if any.
+ *
+ * $mayNotTerminateInf
+ * $orderDependent
+ *
+ * @param p the predicate used to test elements.
+ * @return an option value containing the first element in the $coll
+ * that satisfies `p`, or `None` if none exists.
+ */
+ def find(p: A => Boolean): Option[A] = {
+ var result: Option[A] = None
+ breakable {
+ for (x <- this)
+ if (p(x)) { result = Some(x); break }
+ }
+ result
+ }
+
+ def scan[B >: A, That](z: B)(op: (B, B) => B)(implicit cbf: CanBuildFrom[Repr, B, That]): That = scanLeft(z)(op)
+
+ def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ b.sizeHint(this, 1)
+ var acc = z
+ b += acc
+ for (x <- this) { acc = op(acc, x); b += acc }
+ b.result
+ }
+
+ @migration(2, 9,
+ "This scanRight definition has changed in 2.9.\n" +
+ "The previous behavior can be reproduced with scanRight.reverse."
+ )
+ def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ var scanned = List(z)
+ var acc = z
+ for (x <- reversed) {
+ acc = op(x, acc)
+ scanned ::= acc
+ }
+ val b = bf(repr)
+ for (elem <- scanned) b += elem
+ b.result
+ }
+
+ /** Selects the first element of this $coll.
+ * $orderDependent
+ * @return the first element of this $coll.
+ * @throws `NoSuchElementException` if the $coll is empty.
+ */
+ def head: A = {
+ var result: () => A = () => throw new NoSuchElementException
+ breakable {
+ for (x <- this) {
+ result = () => x
+ break
+ }
+ }
+ result()
+ }
+
+ /** Optionally selects the first element.
+ * $orderDependent
+ * @return the first element of this $coll if it is nonempty, `None` if it is empty.
+ */
+ def headOption: Option[A] = if (isEmpty) None else Some(head)
+
+ /** Selects all elements except the first.
+ * $orderDependent
+ * @return a $coll consisting of all elements of this $coll
+ * except the first one.
+ * @throws `UnsupportedOperationException` if the $coll is empty.
+ */
+ override def tail: Repr = {
+ if (isEmpty) throw new UnsupportedOperationException("empty.tail")
+ drop(1)
+ }
+
+ /** Selects the last element.
+ * $orderDependent
+ * @return The last element of this $coll.
+ * @throws NoSuchElementException If the $coll is empty.
+ */
+ def last: A = {
+ var lst = head
+ for (x <- this)
+ lst = x
+ lst
+ }
+
+ /** Optionally selects the last element.
+ * $orderDependent
+ * @return the last element of this $coll$ if it is nonempty, `None` if it is empty.
+ */
+ def lastOption: Option[A] = if (isEmpty) None else Some(last)
+
+ /** Selects all elements except the last.
+ * $orderDependent
+ * @return a $coll consisting of all elements of this $coll
+ * except the last one.
+ * @throws `UnsupportedOperationException` if the $coll is empty.
+ */
+ def init: Repr = {
+ if (isEmpty) throw new UnsupportedOperationException("empty.init")
+ var lst = head
+ var follow = false
+ val b = newBuilder
+ b.sizeHint(this, -1)
+ for (x <- this.seq) {
+ if (follow) b += lst
+ else follow = true
+ lst = x
+ }
+ b.result
+ }
+
+ def take(n: Int): Repr = slice(0, n)
+
+ def drop(n: Int): Repr =
+ if (n <= 0) {
+ val b = newBuilder
+ b.sizeHint(this)
+ b ++= thisCollection result
+ }
+ else sliceWithKnownDelta(n, Int.MaxValue, -n)
+
+ def slice(from: Int, until: Int): Repr = sliceWithKnownBound(math.max(from, 0), until)
+
+ // Precondition: from >= 0, until > 0, builder already configured for building.
+ private[this] def sliceInternal(from: Int, until: Int, b: Builder[A, Repr]): Repr = {
+ var i = 0
+ breakable {
+ for (x <- this.seq) {
+ if (i >= from) b += x
+ i += 1
+ if (i >= until) break
+ }
+ }
+ b.result
+ }
+ // Precondition: from >= 0
+ private[scala] def sliceWithKnownDelta(from: Int, until: Int, delta: Int): Repr = {
+ val b = newBuilder
+ if (until <= from) b.result
+ else {
+ b.sizeHint(this, delta)
+ sliceInternal(from, until, b)
+ }
+ }
+ // Precondition: from >= 0
+ private[scala] def sliceWithKnownBound(from: Int, until: Int): Repr = {
+ val b = newBuilder
+ if (until <= from) b.result
+ else {
+ b.sizeHintBounded(until - from, this)
+ sliceInternal(from, until, b)
+ }
+ }
+
+ def takeWhile(p: A => Boolean): Repr = {
+ val b = newBuilder
+ breakable {
+ for (x <- this) {
+ if (!p(x)) break
+ b += x
+ }
+ }
+ b.result
+ }
+
+ def dropWhile(p: A => Boolean): Repr = {
+ val b = newBuilder
+ var go = false
+ for (x <- this) {
+ if (!p(x)) go = true
+ if (go) b += x
+ }
+ b.result
+ }
+
+ def span(p: A => Boolean): (Repr, Repr) = {
+ val l, r = newBuilder
+ var toLeft = true
+ for (x <- this) {
+ toLeft = toLeft && p(x)
+ (if (toLeft) l else r) += x
+ }
+ (l.result, r.result)
+ }
+
+ def splitAt(n: Int): (Repr, Repr) = {
+ val l, r = newBuilder
+ l.sizeHintBounded(n, this)
+ if (n >= 0) r.sizeHint(this, -n)
+ var i = 0
+ for (x <- this) {
+ (if (i < n) l else r) += x
+ i += 1
+ }
+ (l.result, r.result)
+ }
+
+ /** Iterates over the tails of this $coll. The first value will be this
+ * $coll and the final one will be an empty $coll, with the intervening
+ * values the results of successive applications of `tail`.
+ *
+ * @return an iterator over all the tails of this $coll
+ * @example `List(1,2,3).tails = Iterator(List(1,2,3), List(2,3), List(3), Nil)`
+ */
+ def tails: Iterator[Repr] = iterateUntilEmpty(_.tail)
+
+ /** Iterates over the inits of this $coll. The first value will be this
+ * $coll and the final one will be an empty $coll, with the intervening
+ * values the results of successive applications of `init`.
+ *
+ * @return an iterator over all the inits of this $coll
+ * @example `List(1,2,3).inits = Iterator(List(1,2,3), List(1,2), List(1), Nil)`
+ */
+ def inits: Iterator[Repr] = iterateUntilEmpty(_.init)
+
+ /** Copies elements of this $coll to an array.
+ * Fills the given array `xs` with at most `len` elements of
+ * this $coll, starting at position `start`.
+ * Copying will stop once either the end of the current $coll is reached,
+ * or the end of the array is reached, or `len` elements have been copied.
+ *
+ * $willNotTerminateInf
+ *
+ * @param xs the array to fill.
+ * @param start the starting index.
+ * @param len the maximal number of elements to copy.
+ * @tparam B the type of the elements of the array.
+ *
+ *
+ * @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit
+ */
+ def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) {
+ var i = start
+ val end = (start + len) min xs.length
+ breakable {
+ for (x <- this) {
+ if (i >= end) break
+ xs(i) = x
+ i += 1
+ }
+ }
+ }
+
+ def toTraversable: Traversable[A] = thisCollection
+ def toIterator: Iterator[A] = toStream.iterator
+ def toStream: Stream[A] = toBuffer.toStream
+
+ /** Converts this $coll to a string.
+ *
+ * @return a string representation of this collection. By default this
+ * string consists of the `stringPrefix` of this $coll,
+ * followed by all elements separated by commas and enclosed in parentheses.
+ */
+ override def toString = mkString(stringPrefix + "(", ", ", ")")
+
+ /** Defines the prefix of this object's `toString` representation.
+ *
+ * @return a string representation which starts the result of `toString`
+ * applied to this $coll. By default the string prefix is the
+ * simple name of the collection class $coll.
+ */
+ def stringPrefix : String = {
+ var string = repr.asInstanceOf[AnyRef].getClass.getName
+ val idx1 = string.lastIndexOf('.' : Int)
+ if (idx1 != -1) string = string.substring(idx1 + 1)
+ val idx2 = string.indexOf('$')
+ if (idx2 != -1) string = string.substring(0, idx2)
+ string
+ }
+
+ /** Creates a non-strict view of this $coll.
+ *
+ * @return a non-strict view of this $coll.
+ */
+ def view = new TraversableView[A, Repr] {
+ protected lazy val underlying = self.repr
+ override def foreach[U](f: A => U) = self foreach f
+ }
+
+ /** Creates a non-strict view of a slice of this $coll.
+ *
+ * Note: the difference between `view` and `slice` is that `view` produces
+ * a view of the current $coll, whereas `slice` produces a new $coll.
+ *
+ * Note: `view(from, to)` is equivalent to `view.slice(from, to)`
+ * $orderDependent
+ *
+ * @param from the index of the first element of the view
+ * @param until the index of the element following the view
+ * @return a non-strict view of a slice of this $coll, starting at index `from`
+ * and extending up to (but not including) index `until`.
+ */
+ def view(from: Int, until: Int): TraversableView[A, Repr] = view.slice(from, until)
+
+ /** Creates a non-strict filter of this $coll.
+ *
+ * Note: the difference between `c filter p` and `c withFilter p` is that
+ * the former creates a new collection, whereas the latter only
+ * restricts the domain of subsequent `map`, `flatMap`, `foreach`,
+ * and `withFilter` operations.
+ * $orderDependent
+ *
+ * @param p the predicate used to test elements.
+ * @return an object of class `WithFilter`, which supports
+ * `map`, `flatMap`, `foreach`, and `withFilter` operations.
+ * All these operations apply to those elements of this $coll which
+ * satisfy the predicate `p`.
+ */
+ def withFilter(p: A => Boolean): FilterMonadic[A, Repr] = new WithFilter(p)
+
+ /** A class supporting filtered operations. Instances of this class are
+ * returned by method `withFilter`.
+ */
+ class WithFilter(p: A => Boolean) extends FilterMonadic[A, Repr] {
+
+ /** Builds a new collection by applying a function to all elements of the
+ * outer $coll containing this `WithFilter` instance that satisfy predicate `p`.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned collection.
+ * @tparam That $thatinfo
+ * @param bf $bfinfo
+ * @return a new collection of type `That` resulting from applying
+ * the given function `f` to each element of the outer $coll
+ * that satisfies predicate `p` and collecting the results.
+ *
+ * @usecase def map[B](f: A => B): $Coll[B]
+ *
+ * @return a new $coll resulting from applying the given function
+ * `f` to each element of the outer $coll that satisfies
+ * predicate `p` and collecting the results.
+ */
+ def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ for (x <- self)
+ if (p(x)) b += f(x)
+ b.result
+ }
+
+ /** Builds a new collection by applying a function to all elements of the
+ * outer $coll containing this `WithFilter` instance that satisfy
+ * predicate `p` and concatenating the results.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned collection.
+ * @tparam That $thatinfo
+ * @param bf $bfinfo
+ * @return a new collection of type `That` resulting from applying
+ * the given collection-valued function `f` to each element
+ * of the outer $coll that satisfies predicate `p` and
+ * concatenating the results.
+ *
+ * @usecase def flatMap[B](f: A => TraversableOnce[B]): $Coll[B]
+ *
+ * @return a new $coll resulting from applying the given collection-valued function
+ * `f` to each element of the outer $coll that satisfies predicate `p` and concatenating the results.
+ */
+ def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ for (x <- self)
+ if (p(x)) b ++= f(x).seq
+ b.result
+ }
+
+ /** Applies a function `f` to all elements of the outer $coll containing
+ * this `WithFilter` instance that satisfy predicate `p`.
+ *
+ * @param f the function that is applied for its side-effect to every element.
+ * The result of function `f` is discarded.
+ *
+ * @tparam U the type parameter describing the result of function `f`.
+ * This result will always be ignored. Typically `U` is `Unit`,
+ * but this is not necessary.
+ *
+ * @usecase def foreach(f: A => Unit): Unit
+ */
+ def foreach[U](f: A => U): Unit =
+ for (x <- self)
+ if (p(x)) f(x)
+
+ /** Further refines the filter for this $coll.
+ *
+ * @param q the predicate used to test elements.
+ * @return an object of class `WithFilter`, which supports
+ * `map`, `flatMap`, `foreach`, and `withFilter` operations.
+ * All these operations apply to those elements of this $coll which
+ * satisfy the predicate `q` in addition to the predicate `p`.
+ */
+ def withFilter(q: A => Boolean): WithFilter =
+ new WithFilter(x => p(x) && q(x))
+ }
+
+ // A helper for tails and inits.
+ private def iterateUntilEmpty(f: Traversable[A @uV] => Traversable[A @uV]): Iterator[Repr] = {
+ val it = Iterator.iterate(thisCollection)(f) takeWhile (x => !x.isEmpty)
+ it ++ Iterator(Nil) map (newBuilder ++= _ result)
+ }
+ }
+
+
+</textarea>
+</form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ theme: "ambiance",
+ mode: "text/x-scala"
+ });
+ </script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/clojure/clojure.js b/codemirror_ui/lib/CodeMirror-2.3/mode/clojure/clojure.js
new file mode 100644
index 0000000..c683641
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/clojure/clojure.js
@@ -0,0 +1,207 @@
+/**
+ * Author: Hans Engel
+ * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun)
+ */
+CodeMirror.defineMode("clojure", function (config, mode) {
+ var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", TAG = "tag",
+ ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword";
+ var INDENT_WORD_SKIP = 2, KEYWORDS_SKIP = 1;
+
+ function makeKeywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+
+ var atoms = makeKeywords("true false nil");
+
+ var keywords = makeKeywords(
+ "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle");
+
+ var builtins = makeKeywords(
+ "* *1 *2 *3 *agent* *allow-unresolved-vars* *assert *clojure-version* *command-line-args* *compile-files* *compile-path* *e *err* *file* *flush-on-newline* *in* *macro-meta* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *use-context-classloader* *warn-on-reflection* + - / < <= = == > >= accessor aclone agent agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec decimal? declare definline defmacro defmethod defmulti defn defn- defonce defstruct delay delay? deliver deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall doc dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq eval even? every? extend extend-protocol extend-type extends? extenders false? ffirst file-seq filter find find-doc find-ns find-var first float float-array float? floats flush fn fn? fnext for force format future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator hash hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map? mapcat max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod name namespace neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext num number? odd? or parents partial partition pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-doc print-dup print-method print-namespace-doc print-simple print-special-doc print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string reify reduce ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure release-pending-sends rem remove remove-method remove-ns repeat repeatedly replace replicate require reset! reset-meta! resolve rest resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-validator! set? short short-array shorts shutdown-agents slurp some sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-form-anchor special-symbol? split-at split-with str stream? string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync syntax-symbol-anchor take take-last take-nth take-while test the-ns time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-dec unchecked-divide unchecked-inc unchecked-multiply unchecked-negate unchecked-remainder unchecked-subtract underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision xml-seq");
+
+ var indentKeys = makeKeywords(
+ // Built-ins
+ "ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type try catch " +
+
+ // Binding forms
+ "let letfn binding loop for doseq dotimes when-let if-let " +
+
+ // Data structures
+ "defstruct struct-map assoc " +
+
+ // clojure.test
+ "testing deftest " +
+
+ // contrib
+ "handler-case handle dotrace deftrace");
+
+ var tests = {
+ digit: /\d/,
+ digit_or_colon: /[\d:]/,
+ hex: /[0-9a-fA-F]/,
+ sign: /[+-]/,
+ exponent: /[eE]/,
+ keyword_char: /[^\s\(\[\;\)\]]/,
+ basic: /[\w\$_\-]/,
+ lang_keyword: /[\w*+!\-_?:\/]/
+ };
+
+ function stateStack(indent, type, prev) { // represents a state stack object
+ this.indent = indent;
+ this.type = type;
+ this.prev = prev;
+ }
+
+ function pushStack(state, indent, type) {
+ state.indentStack = new stateStack(indent, type, state.indentStack);
+ }
+
+ function popStack(state) {
+ state.indentStack = state.indentStack.prev;
+ }
+
+ function isNumber(ch, stream){
+ // hex
+ if ( ch === '0' && 'x' == stream.peek().toLowerCase() ) {
+ stream.eat('x');
+ stream.eatWhile(tests.hex);
+ return true;
+ }
+
+ // leading sign
+ if ( ch == '+' || ch == '-' ) {
+ stream.eat(tests.sign);
+ ch = stream.next();
+ }
+
+ if ( tests.digit.test(ch) ) {
+ stream.eat(ch);
+ stream.eatWhile(tests.digit);
+
+ if ( '.' == stream.peek() ) {
+ stream.eat('.');
+ stream.eatWhile(tests.digit);
+ }
+
+ if ( 'e' == stream.peek().toLowerCase() ) {
+ stream.eat(tests.exponent);
+ stream.eat(tests.sign);
+ stream.eatWhile(tests.digit);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ return {
+ startState: function () {
+ return {
+ indentStack: null,
+ indentation: 0,
+ mode: false
+ };
+ },
+
+ token: function (stream, state) {
+ if (state.indentStack == null && stream.sol()) {
+ // update indentation, but only if indentStack is empty
+ state.indentation = stream.indentation();
+ }
+
+ // skip spaces
+ if (stream.eatSpace()) {
+ return null;
+ }
+ var returnType = null;
+
+ switch(state.mode){
+ case "string": // multi-line string parsing mode
+ var next, escaped = false;
+ while ((next = stream.next()) != null) {
+ if (next == "\"" && !escaped) {
+
+ state.mode = false;
+ break;
+ }
+ escaped = !escaped && next == "\\";
+ }
+ returnType = STRING; // continue on in string mode
+ break;
+ default: // default parsing mode
+ var ch = stream.next();
+
+ if (ch == "\"") {
+ state.mode = "string";
+ returnType = STRING;
+ } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) {
+ returnType = ATOM;
+ } else if (ch == ";") { // comment
+ stream.skipToEnd(); // rest of the line is a comment
+ returnType = COMMENT;
+ } else if (isNumber(ch,stream)){
+ returnType = NUMBER;
+ } else if (ch == "(" || ch == "[") {
+ var keyWord = ''; var indentTemp = stream.column();
+ /**
+ Either
+ (indent-word ..
+ (non-indent-word ..
+ (;something else, bracket, etc.
+ */
+
+ if (ch == "(") while ((letter = stream.eat(tests.keyword_char)) != null) {
+ keyWord += letter;
+ }
+
+ if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word
+ pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
+ } else { // non-indent word
+ // we continue eating the spaces
+ stream.eatSpace();
+ if (stream.eol() || stream.peek() == ";") {
+ // nothing significant after
+ // we restart indentation 1 space after
+ pushStack(state, indentTemp + 1, ch);
+ } else {
+ pushStack(state, indentTemp + stream.current().length, ch); // else we match
+ }
+ }
+ stream.backUp(stream.current().length - 1); // undo all the eating
+
+ returnType = BRACKET;
+ } else if (ch == ")" || ch == "]") {
+ returnType = BRACKET;
+ if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) {
+ popStack(state);
+ }
+ } else if ( ch == ":" ) {
+ stream.eatWhile(tests.lang_keyword);
+ return ATOM;
+ } else {
+ stream.eatWhile(tests.basic);
+
+ if (keywords && keywords.propertyIsEnumerable(stream.current())) {
+ returnType = KEYWORD;
+ } else if (builtins && builtins.propertyIsEnumerable(stream.current())) {
+ returnType = BUILTIN;
+ } else if (atoms && atoms.propertyIsEnumerable(stream.current())) {
+ returnType = ATOM;
+ } else returnType = null;
+ }
+ }
+
+ return returnType;
+ },
+
+ indent: function (state, textAfter) {
+ if (state.indentStack == null) return state.indentation;
+ return state.indentStack.indent;
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-clojure", "clojure");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/clojure/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/clojure/index.html
new file mode 100644
index 0000000..9762d58
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/clojure/index.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Clojure mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="clojure.js"></script>
+ <style>.CodeMirror {background: #f8f8f8;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Clojure mode</h1>
+ <form><textarea id="code" name="code">
+; Conway's Game of Life, based on the work of:
+;; Laurent Petit https://gist.github.com/1200343
+;; Christophe Grand http://clj-me.cgrand.net/2011/08/19/conways-game-of-life
+
+(ns ^{:doc "Conway's Game of Life."}
+ game-of-life)
+
+;; Core game of life's algorithm functions
+
+(defn neighbours
+ "Given a cell's coordinates, returns the coordinates of its neighbours."
+ [[x y]]
+ (for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])]
+ [(+ dx x) (+ dy y)]))
+
+(defn step
+ "Given a set of living cells, computes the new set of living cells."
+ [cells]
+ (set (for [[cell n] (frequencies (mapcat neighbours cells))
+ :when (or (= n 3) (and (= n 2) (cells cell)))]
+ cell)))
+
+;; Utility methods for displaying game on a text terminal
+
+(defn print-board
+ "Prints a board on *out*, representing a step in the game."
+ [board w h]
+ (doseq [x (range (inc w)) y (range (inc h))]
+ (if (= y 0) (print "\n"))
+ (print (if (board [x y]) "[X]" " . "))))
+
+(defn display-grids
+ "Prints a squence of boards on *out*, representing several steps."
+ [grids w h]
+ (doseq [board grids]
+ (print-board board w h)
+ (print "\n")))
+
+;; Launches an example board
+
+(def
+ ^{:doc "board represents the initial set of living cells"}
+ board #{[2 1] [2 2] [2 3]})
+
+(display-grids (take 3 (iterate step board)) 5 5) </textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-clojure</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/coffeescript/coffeescript.js b/codemirror_ui/lib/CodeMirror-2.3/mode/coffeescript/coffeescript.js
new file mode 100644
index 0000000..dece5f8
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/coffeescript/coffeescript.js
@@ -0,0 +1,347 @@
+/**
+ * Link to the project's GitHub page:
+ * https://github.com/pickhardt/coffeescript-codemirror-mode
+ */
+CodeMirror.defineMode('coffeescript', function(conf) {
+ var ERRORCLASS = 'error';
+
+ function wordRegexp(words) {
+ return new RegExp("^((" + words.join(")|(") + "))\\b");
+ }
+
+ var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\?]");
+ var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
+ var doubleOperators = new RegExp("^((\->)|(\=>)|(\\+\\+)|(\\+\\=)|(\\-\\-)|(\\-\\=)|(\\*\\*)|(\\*\\=)|(\\/\\/)|(\\/\\=)|(==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//))");
+ var doubleDelimiters = new RegExp("^((\\.\\.)|(\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
+ var tripleDelimiters = new RegExp("^((\\.\\.\\.)|(//=)|(>>=)|(<<=)|(\\*\\*=))");
+ var identifiers = new RegExp("^[_A-Za-z$][_A-Za-z$0-9]*");
+
+ var wordOperators = wordRegexp(['and', 'or', 'not',
+ 'is', 'isnt', 'in',
+ 'instanceof', 'typeof']);
+ var indentKeywords = ['for', 'while', 'loop', 'if', 'unless', 'else',
+ 'switch', 'try', 'catch', 'finally', 'class'];
+ var commonKeywords = ['break', 'by', 'continue', 'debugger', 'delete',
+ 'do', 'in', 'of', 'new', 'return', 'then',
+ 'this', 'throw', 'when', 'until'];
+
+ var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
+
+ indentKeywords = wordRegexp(indentKeywords);
+
+
+ var stringPrefixes = new RegExp("^('{3}|\"{3}|['\"])");
+ var regexPrefixes = new RegExp("^(/{3}|/)");
+ var commonConstants = ['Infinity', 'NaN', 'undefined', 'null', 'true', 'false', 'on', 'off', 'yes', 'no'];
+ var constants = wordRegexp(commonConstants);
+
+ // Tokenizers
+ function tokenBase(stream, state) {
+ // Handle scope changes
+ if (stream.sol()) {
+ var scopeOffset = state.scopes[0].offset;
+ if (stream.eatSpace()) {
+ var lineOffset = stream.indentation();
+ if (lineOffset > scopeOffset) {
+ return 'indent';
+ } else if (lineOffset < scopeOffset) {
+ return 'dedent';
+ }
+ return null;
+ } else {
+ if (scopeOffset > 0) {
+ dedent(stream, state);
+ }
+ }
+ }
+ if (stream.eatSpace()) {
+ return null;
+ }
+
+ var ch = stream.peek();
+
+ // Handle docco title comment (single line)
+ if (stream.match("####")) {
+ stream.skipToEnd();
+ return 'comment';
+ }
+
+ // Handle multi line comments
+ if (stream.match("###")) {
+ state.tokenize = longComment;
+ return state.tokenize(stream, state);
+ }
+
+ // Single line comment
+ if (ch === '#') {
+ stream.skipToEnd();
+ return 'comment';
+ }
+
+ // Handle number literals
+ if (stream.match(/^-?[0-9\.]/, false)) {
+ var floatLiteral = false;
+ // Floats
+ if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {
+ floatLiteral = true;
+ }
+ if (stream.match(/^-?\d+\.\d*/)) {
+ floatLiteral = true;
+ }
+ if (stream.match(/^-?\.\d+/)) {
+ floatLiteral = true;
+ }
+
+ if (floatLiteral) {
+ // prevent from getting extra . on 1..
+ if (stream.peek() == "."){
+ stream.backUp(1);
+ }
+ return 'number';
+ }
+ // Integers
+ var intLiteral = false;
+ // Hex
+ if (stream.match(/^-?0x[0-9a-f]+/i)) {
+ intLiteral = true;
+ }
+ // Decimal
+ if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
+ intLiteral = true;
+ }
+ // Zero by itself with no other piece of number.
+ if (stream.match(/^-?0(?![\dx])/i)) {
+ intLiteral = true;
+ }
+ if (intLiteral) {
+ return 'number';
+ }
+ }
+
+ // Handle strings
+ if (stream.match(stringPrefixes)) {
+ state.tokenize = tokenFactory(stream.current(), 'string');
+ return state.tokenize(stream, state);
+ }
+ // Handle regex literals
+ if (stream.match(regexPrefixes)) {
+ if (stream.current() != '/' || stream.match(/^.*\//, false)) { // prevent highlight of division
+ state.tokenize = tokenFactory(stream.current(), 'string-2');
+ return state.tokenize(stream, state);
+ } else {
+ stream.backUp(1);
+ }
+ }
+
+ // Handle operators and delimiters
+ if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
+ return 'punctuation';
+ }
+ if (stream.match(doubleOperators)
+ || stream.match(singleOperators)
+ || stream.match(wordOperators)) {
+ return 'operator';
+ }
+ if (stream.match(singleDelimiters)) {
+ return 'punctuation';
+ }
+
+ if (stream.match(constants)) {
+ return 'atom';
+ }
+
+ if (stream.match(keywords)) {
+ return 'keyword';
+ }
+
+ if (stream.match(identifiers)) {
+ return 'variable';
+ }
+
+ // Handle non-detected items
+ stream.next();
+ return ERRORCLASS;
+ }
+
+ function tokenFactory(delimiter, outclass) {
+ var singleline = delimiter.length == 1;
+ return function tokenString(stream, state) {
+ while (!stream.eol()) {
+ stream.eatWhile(/[^'"\/\\]/);
+ if (stream.eat('\\')) {
+ stream.next();
+ if (singleline && stream.eol()) {
+ return outclass;
+ }
+ } else if (stream.match(delimiter)) {
+ state.tokenize = tokenBase;
+ return outclass;
+ } else {
+ stream.eat(/['"\/]/);
+ }
+ }
+ if (singleline) {
+ if (conf.mode.singleLineStringErrors) {
+ outclass = ERRORCLASS
+ } else {
+ state.tokenize = tokenBase;
+ }
+ }
+ return outclass;
+ };
+ }
+
+ function longComment(stream, state) {
+ while (!stream.eol()) {
+ stream.eatWhile(/[^#]/);
+ if (stream.match("###")) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ stream.eatWhile("#");
+ }
+ return "comment"
+ }
+
+ function indent(stream, state, type) {
+ type = type || 'coffee';
+ var indentUnit = 0;
+ if (type === 'coffee') {
+ for (var i = 0; i < state.scopes.length; i++) {
+ if (state.scopes[i].type === 'coffee') {
+ indentUnit = state.scopes[i].offset + conf.indentUnit;
+ break;
+ }
+ }
+ } else {
+ indentUnit = stream.column() + stream.current().length;
+ }
+ state.scopes.unshift({
+ offset: indentUnit,
+ type: type
+ });
+ }
+
+ function dedent(stream, state) {
+ if (state.scopes.length == 1) return;
+ if (state.scopes[0].type === 'coffee') {
+ var _indent = stream.indentation();
+ var _indent_index = -1;
+ for (var i = 0; i < state.scopes.length; ++i) {
+ if (_indent === state.scopes[i].offset) {
+ _indent_index = i;
+ break;
+ }
+ }
+ if (_indent_index === -1) {
+ return true;
+ }
+ while (state.scopes[0].offset !== _indent) {
+ state.scopes.shift();
+ }
+ return false
+ } else {
+ state.scopes.shift();
+ return false;
+ }
+ }
+
+ function tokenLexer(stream, state) {
+ var style = state.tokenize(stream, state);
+ var current = stream.current();
+
+ // Handle '.' connected identifiers
+ if (current === '.') {
+ style = state.tokenize(stream, state);
+ current = stream.current();
+ if (style === 'variable') {
+ return 'variable';
+ } else {
+ return ERRORCLASS;
+ }
+ }
+
+ // Handle properties
+ if (current === '@') {
+ stream.eat('@');
+ return 'keyword';
+ }
+
+ // Handle scope changes.
+ if (current === 'return') {
+ state.dedent += 1;
+ }
+ if (((current === '->' || current === '=>') &&
+ !state.lambda &&
+ state.scopes[0].type == 'coffee' &&
+ stream.peek() === '')
+ || style === 'indent') {
+ indent(stream, state);
+ }
+ var delimiter_index = '[({'.indexOf(current);
+ if (delimiter_index !== -1) {
+ indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
+ }
+ if (indentKeywords.exec(current)){
+ indent(stream, state);
+ }
+ if (current == 'then'){
+ dedent(stream, state);
+ }
+
+
+ if (style === 'dedent') {
+ if (dedent(stream, state)) {
+ return ERRORCLASS;
+ }
+ }
+ delimiter_index = '])}'.indexOf(current);
+ if (delimiter_index !== -1) {
+ if (dedent(stream, state)) {
+ return ERRORCLASS;
+ }
+ }
+ if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'coffee') {
+ if (state.scopes.length > 1) state.scopes.shift();
+ state.dedent -= 1;
+ }
+
+ return style;
+ }
+
+ var external = {
+ startState: function(basecolumn) {
+ return {
+ tokenize: tokenBase,
+ scopes: [{offset:basecolumn || 0, type:'coffee'}],
+ lastToken: null,
+ lambda: false,
+ dedent: 0
+ };
+ },
+
+ token: function(stream, state) {
+ var style = tokenLexer(stream, state);
+
+ state.lastToken = {style:style, content: stream.current()};
+
+ if (stream.eol() && stream.lambda) {
+ state.lambda = false;
+ }
+
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != tokenBase) {
+ return 0;
+ }
+
+ return state.scopes[0].offset;
+ }
+
+ };
+ return external;
+});
+
+CodeMirror.defineMIME('text/x-coffeescript', 'coffeescript');
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/coffeescript/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/coffeescript/index.html
new file mode 100644
index 0000000..98bd497
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/coffeescript/index.html
@@ -0,0 +1,727 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: CoffeeScript mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="coffeescript.js"></script>
+ <style>.CodeMirror {border-top: 1px solid silver; border-bottom: 1px solid silver;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: CoffeeScript mode</h1>
+ <form><textarea id="code" name="code">
+# CoffeeScript mode for CodeMirror
+# Copyright (c) 2011 Jeff Pickhardt, released under
+# the MIT License.
+#
+# Modified from the Python CodeMirror mode, which also is
+# under the MIT License Copyright (c) 2010 Timothy Farrell.
+#
+# The following script, Underscore.coffee, is used to
+# demonstrate CoffeeScript mode for CodeMirror.
+#
+# To download CoffeeScript mode for CodeMirror, go to:
+# https://github.com/pickhardt/coffeescript-codemirror-mode
+
+# **Underscore.coffee
+# (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.**
+# Underscore is freely distributable under the terms of the
+# [MIT license](http://en.wikipedia.org/wiki/MIT_License).
+# Portions of Underscore are inspired by or borrowed from
+# [Prototype.js](http://prototypejs.org/api), Oliver Steele's
+# [Functional](http://osteele.com), and John Resig's
+# [Micro-Templating](http://ejohn.org).
+# For all details and documentation:
+# http://documentcloud.github.com/underscore/
+
+
+# Baseline setup
+# --------------
+
+# Establish the root object, `window` in the browser, or `global` on the server.
+root = this
+
+
+# Save the previous value of the `_` variable.
+previousUnderscore = root._
+
+### Multiline
+ comment
+###
+
+# Establish the object that gets thrown to break out of a loop iteration.
+# `StopIteration` is SOP on Mozilla.
+breaker = if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration
+
+
+#### Docco style single line comment (title)
+
+
+# Helper function to escape **RegExp** contents, because JS doesn't have one.
+escapeRegExp = (string) -> string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1')
+
+
+# Save bytes in the minified (but not gzipped) version:
+ArrayProto = Array.prototype
+ObjProto = Object.prototype
+
+
+# Create quick reference variables for speed access to core prototypes.
+slice = ArrayProto.slice
+unshift = ArrayProto.unshift
+toString = ObjProto.toString
+hasOwnProperty = ObjProto.hasOwnProperty
+propertyIsEnumerable = ObjProto.propertyIsEnumerable
+
+
+# All **ECMA5** native implementations we hope to use are declared here.
+nativeForEach = ArrayProto.forEach
+nativeMap = ArrayProto.map
+nativeReduce = ArrayProto.reduce
+nativeReduceRight = ArrayProto.reduceRight
+nativeFilter = ArrayProto.filter
+nativeEvery = ArrayProto.every
+nativeSome = ArrayProto.some
+nativeIndexOf = ArrayProto.indexOf
+nativeLastIndexOf = ArrayProto.lastIndexOf
+nativeIsArray = Array.isArray
+nativeKeys = Object.keys
+
+
+# Create a safe reference to the Underscore object for use below.
+_ = (obj) -> new wrapper(obj)
+
+
+# Export the Underscore object for **CommonJS**.
+if typeof(exports) != 'undefined' then exports._ = _
+
+
+# Export Underscore to global scope.
+root._ = _
+
+
+# Current version.
+_.VERSION = '1.1.0'
+
+
+# Collection Functions
+# --------------------
+
+# The cornerstone, an **each** implementation.
+# Handles objects implementing **forEach**, arrays, and raw objects.
+_.each = (obj, iterator, context) ->
+ try
+ if nativeForEach and obj.forEach is nativeForEach
+ obj.forEach iterator, context
+ else if _.isNumber obj.length
+ iterator.call context, obj[i], i, obj for i in [0...obj.length]
+ else
+ iterator.call context, val, key, obj for own key, val of obj
+ catch e
+ throw e if e isnt breaker
+ obj
+
+
+# Return the results of applying the iterator to each element. Use JavaScript
+# 1.6's version of **map**, if possible.
+_.map = (obj, iterator, context) ->
+ return obj.map(iterator, context) if nativeMap and obj.map is nativeMap
+ results = []
+ _.each obj, (value, index, list) ->
+ results.push iterator.call context, value, index, list
+ results
+
+
+# **Reduce** builds up a single result from a list of values. Also known as
+# **inject**, or **foldl**. Uses JavaScript 1.8's version of **reduce**, if possible.
+_.reduce = (obj, iterator, memo, context) ->
+ if nativeReduce and obj.reduce is nativeReduce
+ iterator = _.bind iterator, context if context
+ return obj.reduce iterator, memo
+ _.each obj, (value, index, list) ->
+ memo = iterator.call context, memo, value, index, list
+ memo
+
+
+# The right-associative version of **reduce**, also known as **foldr**. Uses
+# JavaScript 1.8's version of **reduceRight**, if available.
+_.reduceRight = (obj, iterator, memo, context) ->
+ if nativeReduceRight and obj.reduceRight is nativeReduceRight
+ iterator = _.bind iterator, context if context
+ return obj.reduceRight iterator, memo
+ reversed = _.clone(_.toArray(obj)).reverse()
+ _.reduce reversed, iterator, memo, context
+
+
+# Return the first value which passes a truth test.
+_.detect = (obj, iterator, context) ->
+ result = null
+ _.each obj, (value, index, list) ->
+ if iterator.call context, value, index, list
+ result = value
+ _.breakLoop()
+ result
+
+
+# Return all the elements that pass a truth test. Use JavaScript 1.6's
+# **filter**, if it exists.
+_.filter = (obj, iterator, context) ->
+ return obj.filter iterator, context if nativeFilter and obj.filter is nativeFilter
+ results = []
+ _.each obj, (value, index, list) ->
+ results.push value if iterator.call context, value, index, list
+ results
+
+
+# Return all the elements for which a truth test fails.
+_.reject = (obj, iterator, context) ->
+ results = []
+ _.each obj, (value, index, list) ->
+ results.push value if not iterator.call context, value, index, list
+ results
+
+
+# Determine whether all of the elements match a truth test. Delegate to
+# JavaScript 1.6's **every**, if it is present.
+_.every = (obj, iterator, context) ->
+ iterator ||= _.identity
+ return obj.every iterator, context if nativeEvery and obj.every is nativeEvery
+ result = true
+ _.each obj, (value, index, list) ->
+ _.breakLoop() unless (result = result and iterator.call(context, value, index, list))
+ result
+
+
+# Determine if at least one element in the object matches a truth test. Use
+# JavaScript 1.6's **some**, if it exists.
+_.some = (obj, iterator, context) ->
+ iterator ||= _.identity
+ return obj.some iterator, context if nativeSome and obj.some is nativeSome
+ result = false
+ _.each obj, (value, index, list) ->
+ _.breakLoop() if (result = iterator.call(context, value, index, list))
+ result
+
+
+# Determine if a given value is included in the array or object,
+# based on `===`.
+_.include = (obj, target) ->
+ return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf
+ return true for own key, val of obj when val is target
+ false
+
+
+# Invoke a method with arguments on every item in a collection.
+_.invoke = (obj, method) ->
+ args = _.rest arguments, 2
+ (if method then val[method] else val).apply(val, args) for val in obj
+
+
+# Convenience version of a common use case of **map**: fetching a property.
+_.pluck = (obj, key) ->
+ _.map(obj, (val) -> val[key])
+
+
+# Return the maximum item or (item-based computation).
+_.max = (obj, iterator, context) ->
+ return Math.max.apply(Math, obj) if not iterator and _.isArray(obj)
+ result = computed: -Infinity
+ _.each obj, (value, index, list) ->
+ computed = if iterator then iterator.call(context, value, index, list) else value
+ computed >= result.computed and (result = {value: value, computed: computed})
+ result.value
+
+
+# Return the minimum element (or element-based computation).
+_.min = (obj, iterator, context) ->
+ return Math.min.apply(Math, obj) if not iterator and _.isArray(obj)
+ result = computed: Infinity
+ _.each obj, (value, index, list) ->
+ computed = if iterator then iterator.call(context, value, index, list) else value
+ computed < result.computed and (result = {value: value, computed: computed})
+ result.value
+
+
+# Sort the object's values by a criterion produced by an iterator.
+_.sortBy = (obj, iterator, context) ->
+ _.pluck(((_.map obj, (value, index, list) ->
+ {value: value, criteria: iterator.call(context, value, index, list)}
+ ).sort((left, right) ->
+ a = left.criteria; b = right.criteria
+ if a < b then -1 else if a > b then 1 else 0
+ )), 'value')
+
+
+# Use a comparator function to figure out at what index an object should
+# be inserted so as to maintain order. Uses binary search.
+_.sortedIndex = (array, obj, iterator) ->
+ iterator ||= _.identity
+ low = 0
+ high = array.length
+ while low < high
+ mid = (low + high) >> 1
+ if iterator(array[mid]) < iterator(obj) then low = mid + 1 else high = mid
+ low
+
+
+# Convert anything iterable into a real, live array.
+_.toArray = (iterable) ->
+ return [] if (!iterable)
+ return iterable.toArray() if (iterable.toArray)
+ return iterable if (_.isArray(iterable))
+ return slice.call(iterable) if (_.isArguments(iterable))
+ _.values(iterable)
+
+
+# Return the number of elements in an object.
+_.size = (obj) -> _.toArray(obj).length
+
+
+# Array Functions
+# ---------------
+
+# Get the first element of an array. Passing `n` will return the first N
+# values in the array. Aliased as **head**. The `guard` check allows it to work
+# with **map**.
+_.first = (array, n, guard) ->
+ if n and not guard then slice.call(array, 0, n) else array[0]
+
+
+# Returns everything but the first entry of the array. Aliased as **tail**.
+# Especially useful on the arguments object. Passing an `index` will return
+# the rest of the values in the array from that index onward. The `guard`
+# check allows it to work with **map**.
+_.rest = (array, index, guard) ->
+ slice.call(array, if _.isUndefined(index) or guard then 1 else index)
+
+
+# Get the last element of an array.
+_.last = (array) -> array[array.length - 1]
+
+
+# Trim out all falsy values from an array.
+_.compact = (array) -> item for item in array when item
+
+
+# Return a completely flattened version of an array.
+_.flatten = (array) ->
+ _.reduce array, (memo, value) ->
+ return memo.concat(_.flatten(value)) if _.isArray value
+ memo.push value
+ memo
+ , []
+
+
+# Return a version of the array that does not contain the specified value(s).
+_.without = (array) ->
+ values = _.rest arguments
+ val for val in _.toArray(array) when not _.include values, val
+
+
+# Produce a duplicate-free version of the array. If the array has already
+# been sorted, you have the option of using a faster algorithm.
+_.uniq = (array, isSorted) ->
+ memo = []
+ for el, i in _.toArray array
+ memo.push el if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))
+ memo
+
+
+# Produce an array that contains every item shared between all the
+# passed-in arrays.
+_.intersect = (array) ->
+ rest = _.rest arguments
+ _.select _.uniq(array), (item) ->
+ _.all rest, (other) ->
+ _.indexOf(other, item) >= 0
+
+
+# Zip together multiple lists into a single array -- elements that share
+# an index go together.
+_.zip = ->
+ length = _.max _.pluck arguments, 'length'
+ results = new Array length
+ for i in [0...length]
+ results[i] = _.pluck arguments, String i
+ results
+
+
+# If the browser doesn't supply us with **indexOf** (I'm looking at you, MSIE),
+# we need this function. Return the position of the first occurrence of an
+# item in an array, or -1 if the item is not included in the array.
+_.indexOf = (array, item) ->
+ return array.indexOf item if nativeIndexOf and array.indexOf is nativeIndexOf
+ i = 0; l = array.length
+ while l - i
+ if array[i] is item then return i else i++
+ -1
+
+
+# Provide JavaScript 1.6's **lastIndexOf**, delegating to the native function,
+# if possible.
+_.lastIndexOf = (array, item) ->
+ return array.lastIndexOf(item) if nativeLastIndexOf and array.lastIndexOf is nativeLastIndexOf
+ i = array.length
+ while i
+ if array[i] is item then return i else i--
+ -1
+
+
+# Generate an integer Array containing an arithmetic progression. A port of
+# [the native Python **range** function](http://docs.python.org/library/functions.html#range).
+_.range = (start, stop, step) ->
+ a = arguments
+ solo = a.length <= 1
+ i = start = if solo then 0 else a[0]
+ stop = if solo then a[0] else a[1]
+ step = a[2] or 1
+ len = Math.ceil((stop - start) / step)
+ return [] if len <= 0
+ range = new Array len
+ idx = 0
+ loop
+ return range if (if step > 0 then i - stop else stop - i) >= 0
+ range[idx] = i
+ idx++
+ i+= step
+
+
+# Function Functions
+# ------------------
+
+# Create a function bound to a given object (assigning `this`, and arguments,
+# optionally). Binding with arguments is also known as **curry**.
+_.bind = (func, obj) ->
+ args = _.rest arguments, 2
+ -> func.apply obj or root, args.concat arguments
+
+
+# Bind all of an object's methods to that object. Useful for ensuring that
+# all callbacks defined on an object belong to it.
+_.bindAll = (obj) ->
+ funcs = if arguments.length > 1 then _.rest(arguments) else _.functions(obj)
+ _.each funcs, (f) -> obj[f] = _.bind obj[f], obj
+ obj
+
+
+# Delays a function for the given number of milliseconds, and then calls
+# it with the arguments supplied.
+_.delay = (func, wait) ->
+ args = _.rest arguments, 2
+ setTimeout((-> func.apply(func, args)), wait)
+
+
+# Memoize an expensive function by storing its results.
+_.memoize = (func, hasher) ->
+ memo = {}
+ hasher or= _.identity
+ ->
+ key = hasher.apply this, arguments
+ return memo[key] if key of memo
+ memo[key] = func.apply this, arguments
+
+
+# Defers a function, scheduling it to run after the current call stack has
+# cleared.
+_.defer = (func) ->
+ _.delay.apply _, [func, 1].concat _.rest arguments
+
+
+# Returns the first function passed as an argument to the second,
+# allowing you to adjust arguments, run code before and after, and
+# conditionally execute the original function.
+_.wrap = (func, wrapper) ->
+ -> wrapper.apply wrapper, [func].concat arguments
+
+
+# Returns a function that is the composition of a list of functions, each
+# consuming the return value of the function that follows.
+_.compose = ->
+ funcs = arguments
+ ->
+ args = arguments
+ for i in [funcs.length - 1..0] by -1
+ args = [funcs[i].apply(this, args)]
+ args[0]
+
+
+# Object Functions
+# ----------------
+
+# Retrieve the names of an object's properties.
+_.keys = nativeKeys or (obj) ->
+ return _.range 0, obj.length if _.isArray(obj)
+ key for key, val of obj
+
+
+# Retrieve the values of an object's properties.
+_.values = (obj) ->
+ _.map obj, _.identity
+
+
+# Return a sorted list of the function names available in Underscore.
+_.functions = (obj) ->
+ _.filter(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()
+
+
+# Extend a given object with all of the properties in a source object.
+_.extend = (obj) ->
+ for source in _.rest(arguments)
+ obj[key] = val for key, val of source
+ obj
+
+
+# Create a (shallow-cloned) duplicate of an object.
+_.clone = (obj) ->
+ return obj.slice 0 if _.isArray obj
+ _.extend {}, obj
+
+
+# Invokes interceptor with the obj, and then returns obj.
+# The primary purpose of this method is to "tap into" a method chain,
+# in order to perform operations on intermediate results within
+ the chain.
+_.tap = (obj, interceptor) ->
+ interceptor obj
+ obj
+
+
+# Perform a deep comparison to check if two objects are equal.
+_.isEqual = (a, b) ->
+ # Check object identity.
+ return true if a is b
+ # Different types?
+ atype = typeof(a); btype = typeof(b)
+ return false if atype isnt btype
+ # Basic equality test (watch out for coercions).
+ return true if `a == b`
+ # One is falsy and the other truthy.
+ return false if (!a and b) or (a and !b)
+ # One of them implements an `isEqual()`?
+ return a.isEqual(b) if a.isEqual
+ # Check dates' integer values.
+ return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b)
+ # Both are NaN?
+ return false if _.isNaN(a) and _.isNaN(b)
+ # Compare regular expressions.
+ if _.isRegExp(a) and _.isRegExp(b)
+ return a.source is b.source and
+ a.global is b.global and
+ a.ignoreCase is b.ignoreCase and
+ a.multiline is b.multiline
+ # If a is not an object by this point, we can't handle it.
+ return false if atype isnt 'object'
+ # Check for different array lengths before comparing contents.
+ return false if a.length and (a.length isnt b.length)
+ # Nothing else worked, deep compare the contents.
+ aKeys = _.keys(a); bKeys = _.keys(b)
+ # Different object sizes?
+ return false if aKeys.length isnt bKeys.length
+ # Recursive comparison of contents.
+ return false for key, val of a when !(key of b) or !_.isEqual(val, b[key])
+ true
+
+
+# Is a given array or object empty?
+_.isEmpty = (obj) ->
+ return obj.length is 0 if _.isArray(obj) or _.isString(obj)
+ return false for own key of obj
+ true
+
+
+# Is a given value a DOM element?
+_.isElement = (obj) -> obj and obj.nodeType is 1
+
+
+# Is a given value an array?
+_.isArray = nativeIsArray or (obj) -> !!(obj and obj.concat and obj.unshift and not obj.callee)
+
+
+# Is a given variable an arguments object?
+_.isArguments = (obj) -> obj and obj.callee
+
+
+# Is the given value a function?
+_.isFunction = (obj) -> !!(obj and obj.constructor and obj.call and obj.apply)
+
+
+# Is the given value a string?
+_.isString = (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr))
+
+
+# Is a given value a number?
+_.isNumber = (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]'
+
+
+# Is a given value a boolean?
+_.isBoolean = (obj) -> obj is true or obj is false
+
+
+# Is a given value a Date?
+_.isDate = (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)
+
+
+# Is the given value a regular expression?
+_.isRegExp = (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))
+
+
+# Is the given value NaN -- this one is interesting. `NaN != NaN`, and
+# `isNaN(undefined) == true`, so we make sure it's a number first.
+_.isNaN = (obj) -> _.isNumber(obj) and window.isNaN(obj)
+
+
+# Is a given value equal to null?
+_.isNull = (obj) -> obj is null
+
+
+# Is a given variable undefined?
+_.isUndefined = (obj) -> typeof obj is 'undefined'
+
+
+# Utility Functions
+# -----------------
+
+# Run Underscore.js in noConflict mode, returning the `_` variable to its
+# previous owner. Returns a reference to the Underscore object.
+_.noConflict = ->
+ root._ = previousUnderscore
+ this
+
+
+# Keep the identity function around for default iterators.
+_.identity = (value) -> value
+
+
+# Run a function `n` times.
+_.times = (n, iterator, context) ->
+ iterator.call context, i for i in [0...n]
+
+
+# Break out of the middle of an iteration.
+_.breakLoop = -> throw breaker
+
+
+# Add your own custom functions to the Underscore object, ensuring that
+# they're correctly added to the OOP wrapper as well.
+_.mixin = (obj) ->
+ for name in _.functions(obj)
+ addToWrapper name, _[name] = obj[name]
+
+
+# Generate a unique integer id (unique within the entire client session).
+# Useful for temporary DOM ids.
+idCounter = 0
+_.uniqueId = (prefix) ->
+ (prefix or '') + idCounter++
+
+
+# By default, Underscore uses **ERB**-style template delimiters, change the
+# following template settings to use alternative delimiters.
+_.templateSettings = {
+ start: '<%'
+ end: '%>'
+ interpolate: /<%=(.+?)%>/g
+}
+
+
+# JavaScript templating a-la **ERB**, pilfered from John Resig's
+# *Secrets of the JavaScript Ninja*, page 83.
+# Single-quote fix from Rick Strahl.
+# With alterations for arbitrary delimiters, and to preserve whitespace.
+_.template = (str, data) ->
+ c = _.templateSettings
+ endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g")
+ fn = new Function 'obj',
+ 'var p=[],print=function(){p.push.apply(p,arguments);};' +
+ 'with(obj||{}){p.push(\'' +
+ str.replace(/\r/g, '\\r')
+ .replace(/\n/g, '\\n')
+ .replace(/\t/g, '\\t')
+ .replace(endMatch,"���")
+ .split("'").join("\\'")
+ .split("���").join("'")
+ .replace(c.interpolate, "',$1,'")
+ .split(c.start).join("');")
+ .split(c.end).join("p.push('") +
+ "');}return p.join('');"
+ if data then fn(data) else fn
+
+
+# Aliases
+# -------
+
+_.forEach = _.each
+_.foldl = _.inject = _.reduce
+_.foldr = _.reduceRight
+_.select = _.filter
+_.all = _.every
+_.any = _.some
+_.contains = _.include
+_.head = _.first
+_.tail = _.rest
+_.methods = _.functions
+
+
+# Setup the OOP Wrapper
+# ---------------------
+
+# If Underscore is called as a function, it returns a wrapped object that
+# can be used OO-style. This wrapper holds altered versions of all the
+# underscore functions. Wrapped objects may be chained.
+wrapper = (obj) ->
+ this._wrapped = obj
+ this
+
+
+# Helper function to continue chaining intermediate results.
+result = (obj, chain) ->
+ if chain then _(obj).chain() else obj
+
+
+# A method to easily add functions to the OOP wrapper.
+addToWrapper = (name, func) ->
+ wrapper.prototype[name] = ->
+ args = _.toArray arguments
+ unshift.call args, this._wrapped
+ result func.apply(_, args), this._chain
+
+
+# Add all ofthe Underscore functions to the wrapper object.
+_.mixin _
+
+
+# Add all mutator Array functions to the wrapper.
+_.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) ->
+ method = Array.prototype[name]
+ wrapper.prototype[name] = ->
+ method.apply(this._wrapped, arguments)
+ result(this._wrapped, this._chain)
+
+
+# Add all accessor Array functions to the wrapper.
+_.each ['concat', 'join', 'slice'], (name) ->
+ method = Array.prototype[name]
+ wrapper.prototype[name] = ->
+ result(method.apply(this._wrapped, arguments), this._chain)
+
+
+# Start chaining a wrapped Underscore object.
+wrapper::chain = ->
+ this._chain = true
+ this
+
+
+# Extracts the result from a wrapped and chained object.
+wrapper::value = -> this._wrapped
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-coffeescript</code>.</p>
+
+ <p>The CoffeeScript mode was written by Jeff Pickhardt (<a href="LICENSE">license</a>).</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/css/css.js b/codemirror_ui/lib/CodeMirror-2.3/mode/css/css.js
new file mode 100644
index 0000000..050e112
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/css/css.js
@@ -0,0 +1,124 @@
+CodeMirror.defineMode("css", function(config) {
+ var indentUnit = config.indentUnit, type;
+ function ret(style, tp) {type = tp; return style;}
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());}
+ else if (ch == "/" && stream.eat("*")) {
+ state.tokenize = tokenCComment;
+ return tokenCComment(stream, state);
+ }
+ else if (ch == "<" && stream.eat("!")) {
+ state.tokenize = tokenSGMLComment;
+ return tokenSGMLComment(stream, state);
+ }
+ else if (ch == "=") ret(null, "compare");
+ else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
+ else if (ch == "\"" || ch == "'") {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ }
+ else if (ch == "#") {
+ stream.eatWhile(/[\w\\\-]/);
+ return ret("atom", "hash");
+ }
+ else if (ch == "!") {
+ stream.match(/^\s*\w*/);
+ return ret("keyword", "important");
+ }
+ else if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w.%]/);
+ return ret("number", "unit");
+ }
+ else if (/[,.+>*\/]/.test(ch)) {
+ return ret(null, "select-op");
+ }
+ else if (/[;{}:\[\]]/.test(ch)) {
+ return ret(null, ch);
+ }
+ else {
+ stream.eatWhile(/[\w\\\-]/);
+ return ret("variable", "variable");
+ }
+ }
+
+ function tokenCComment(stream, state) {
+ var maybeEnd = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (maybeEnd && ch == "/") {
+ state.tokenize = tokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return ret("comment", "comment");
+ }
+
+ function tokenSGMLComment(stream, state) {
+ var dashes = 0, ch;
+ while ((ch = stream.next()) != null) {
+ if (dashes >= 2 && ch == ">") {
+ state.tokenize = tokenBase;
+ break;
+ }
+ dashes = (ch == "-") ? dashes + 1 : 0;
+ }
+ return ret("comment", "comment");
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == quote && !escaped)
+ break;
+ escaped = !escaped && ch == "\\";
+ }
+ if (!escaped) state.tokenize = tokenBase;
+ return ret("string", "string");
+ };
+ }
+
+ return {
+ startState: function(base) {
+ return {tokenize: tokenBase,
+ baseIndent: base || 0,
+ stack: []};
+ },
+
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+
+ var context = state.stack[state.stack.length-1];
+ if (type == "hash" && context != "rule") style = "string-2";
+ else if (style == "variable") {
+ if (context == "rule") style = "number";
+ else if (!context || context == "@media{") style = "tag";
+ }
+
+ if (context == "rule" && /^[\{\};]$/.test(type))
+ state.stack.pop();
+ if (type == "{") {
+ if (context == "@media") state.stack[state.stack.length-1] = "@media{";
+ else state.stack.push("{");
+ }
+ else if (type == "}") state.stack.pop();
+ else if (type == "@media") state.stack.push("@media");
+ else if (context == "{" && type != "comment") state.stack.push("rule");
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ var n = state.stack.length;
+ if (/^\}/.test(textAfter))
+ n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
+ return state.baseIndent + n * indentUnit;
+ },
+
+ electricChars: "}"
+ };
+});
+
+CodeMirror.defineMIME("text/css", "css");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/css/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/css/index.html
new file mode 100644
index 0000000..4993434
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/css/index.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: CSS mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="css.js"></script>
+ <style>.CodeMirror {background: #f8f8f8;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: CSS mode</h1>
+ <form><textarea id="code" name="code">
+/* Some example CSS */
+
+@import url("something.css");
+
+body {
+ margin: 0;
+ padding: 3em 6em;
+ font-family: tahoma, arial, sans-serif;
+ color: #000;
+}
+
+#navigation a {
+ font-weight: bold;
+ text-decoration: none !important;
+}
+
+h1 {
+ font-size: 2.5em;
+}
+
+h2 {
+ font-size: 1.7em;
+}
+
+h1:before, h2:before {
+ content: "::";
+}
+
+code {
+ font-family: courier, monospace;
+ font-size: 80%;
+ color: #418A8A;
+}
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/css</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/diff/diff.js b/codemirror_ui/lib/CodeMirror-2.3/mode/diff/diff.js
new file mode 100644
index 0000000..3402f3b
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/diff/diff.js
@@ -0,0 +1,32 @@
+CodeMirror.defineMode("diff", function() {
+
+ var TOKEN_NAMES = {
+ '+': 'tag',
+ '-': 'string',
+ '@': 'meta'
+ };
+
+ return {
+ token: function(stream) {
+ var tw_pos = stream.string.search(/[\t ]+?$/);
+
+ if (!stream.sol() || tw_pos === 0) {
+ stream.skipToEnd();
+ return ("error " + (
+ TOKEN_NAMES[stream.string.charAt(0)] || '')).replace(/ $/, '');
+ }
+
+ var token_name = TOKEN_NAMES[stream.peek()] || stream.skipToEnd();
+
+ if (tw_pos === -1) {
+ stream.skipToEnd();
+ } else {
+ stream.pos = tw_pos;
+ }
+
+ return token_name;
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-diff", "diff");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/diff/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/diff/index.html
new file mode 100644
index 0000000..b102c09
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/diff/index.html
@@ -0,0 +1,104 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Diff mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="diff.js"></script>
+ <style>
+ .CodeMirror {border-top: 1px solid #ddd; border-bottom: 1px solid #ddd;}
+ span.cm-meta {color: #a0b !important;}
+ span.cm-error { background-color: black; opacity: 0.4;}
+ span.cm-error.cm-string { background-color: red; }
+ span.cm-error.cm-tag { background-color: #2b2; }
+ </style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Diff mode</h1>
+ <form><textarea id="code" name="code">
+diff --git a/index.html b/index.html
+index c1d9156..7764744 100644
+--- a/index.html
++++ b/index.html
+@@ -95,7 +95,8 @@ StringStream.prototype = {
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+- autoMatchBrackets: true
++ autoMatchBrackets: true,
++ onGutterClick: function(x){console.log(x);}
+ });
+ </script>
+ </body>
+diff --git a/lib/codemirror.js b/lib/codemirror.js
+index 04646a9..9a39cc7 100644
+--- a/lib/codemirror.js
++++ b/lib/codemirror.js
+@@ -399,10 +399,16 @@ var CodeMirror = (function() {
+ }
+
+ function onMouseDown(e) {
+- var start = posFromMouse(e), last = start;
++ var start = posFromMouse(e), last = start, target = e.target();
+ if (!start) return;
+ setCursor(start.line, start.ch, false);
+ if (e.button() != 1) return;
++ if (target.parentNode == gutter) {
++ if (options.onGutterClick)
++ options.onGutterClick(indexOf(gutter.childNodes, target) + showingFrom);
++ return;
++ }
++
+ if (!focused) onFocus();
+
+ e.stop();
+@@ -808,7 +814,7 @@ var CodeMirror = (function() {
+ for (var i = showingFrom; i < showingTo; ++i) {
+ var marker = lines[i].gutterMarker;
+ if (marker) html.push('<div class="' + marker.style + '">' + htmlEscape(marker.text) + '</div>');
+- else html.push("<div>" + (options.lineNumbers ? i + 1 : "\u00a0") + "</div>");
++ else html.push("<div>" + (options.lineNumbers ? i + options.firstLineNumber : "\u00a0") + "</div>");
+ }
+ gutter.style.display = "none"; // TODO test whether this actually helps
+ gutter.innerHTML = html.join("");
+@@ -1371,10 +1377,8 @@ var CodeMirror = (function() {
+ if (option == "parser") setParser(value);
+ else if (option === "lineNumbers") setLineNumbers(value);
+ else if (option === "gutter") setGutter(value);
+- else if (option === "readOnly") options.readOnly = value;
+- else if (option === "indentUnit") {options.indentUnit = indentUnit = value; setParser(options.parser);}
+- else if (/^(?:enterMode|tabMode|indentWithTabs|readOnly|autoMatchBrackets|undoDepth)$/.test(option)) options[option] = value;
+- else throw new Error("Can't set option " + option);
++ else if (option === "indentUnit") {options.indentUnit = value; setParser(options.parser);}
++ else options[option] = value;
+ },
+ cursorCoords: cursorCoords,
+ undo: operation(undo),
+@@ -1402,7 +1406,8 @@ var CodeMirror = (function() {
+ replaceRange: operation(replaceRange),
+
+ operation: function(f){return operation(f)();},
+- refresh: function(){updateDisplay([{from: 0, to: lines.length}]);}
++ refresh: function(){updateDisplay([{from: 0, to: lines.length}]);},
++ getInputField: function(){return input;}
+ };
+ return instance;
+ }
+@@ -1420,6 +1425,7 @@ var CodeMirror = (function() {
+ readOnly: false,
+ onChange: null,
+ onCursorActivity: null,
++ onGutterClick: null,
+ autoMatchBrackets: false,
+ workTime: 200,
+ workDelay: 300,
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-diff</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/ecl/ecl.js b/codemirror_ui/lib/CodeMirror-2.3/mode/ecl/ecl.js
new file mode 100644
index 0000000..57c8554
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/ecl/ecl.js
@@ -0,0 +1,203 @@
+CodeMirror.defineMode("ecl", function(config) {
+
+ function words(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+
+ function metaHook(stream, state) {
+ if (!state.startOfLine) return false;
+ stream.skipToEnd();
+ return "meta";
+ }
+
+ function tokenAtString(stream, state) {
+ var next;
+ while ((next = stream.next()) != null) {
+ if (next == '"' && !stream.eat('"')) {
+ state.tokenize = null;
+ break;
+ }
+ }
+ return "string";
+ }
+
+ var indentUnit = config.indentUnit;
+ var keyword = words("abs acos allnodes ascii asin asstring atan atan2 ave case choose choosen choosesets clustersize combine correlation cos cosh count covariance cron dataset dedup define denormalize distribute distributed distribution ebcdic enth error evaluate event eventextra eventname exists exp failcode failmessage fetch fromunicode getisvalid global graph group hash hash32 hash64 hashcrc hashmd5 having if index intformat isvalid iterate join keyunicode length library limit ln local log loop map matched matchlength matchposition matchtext matchunicode max merge mergejoin min nolocal nonempty normalize parse pipe power preload process project pull random range rank ranked realformat recordof regexfind regexreplace regroup rejected rollup round roundup row rowdiff sample set sin sinh sizeof soapcall sort sorted sqrt stepped stored sum table tan tanh thisnode topn tounicode transfer trim truncate typeof ungroup unicodeorder variance which workunit xmldecode xmlencode xmltext xmlunicode");
+ var variable = words("apply assert build buildindex evaluate fail keydiff keypatch loadxml nothor notify output parallel sequential soapcall wait");
+ var variable_2 = words("__compressed__ all and any as atmost before beginc++ best between case const counter csv descend encrypt end endc++ endmacro except exclusive expire export extend false few first flat from full function group header heading hole ifblock import in interface joined keep keyed last left limit load local locale lookup macro many maxcount maxlength min skew module named nocase noroot noscan nosort not of only opt or outer overwrite packed partition penalty physicallength pipe quote record relationship repeat return right scan self separator service shared skew skip sql store terminator thor threshold token transform trim true type unicodeorder unsorted validate virtual whole wild within xml xpath");
+ var variable_3 = words("ascii big_endian boolean data decimal ebcdic integer pattern qstring real record rule set of string token udecimal unicode unsigned varstring varunicode");
+ var builtin = words("checkpoint deprecated failcode failmessage failure global independent onwarning persist priority recovery stored success wait when");
+ var blockKeywords = words("catch class do else finally for if switch try while");
+ var atoms = words("true false null");
+ var hooks = {"#": metaHook};
+ var multiLineStrings;
+ var isOperatorChar = /[+\-*&%=<>!?|\/]/;
+
+ var curPunc;
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ if (hooks[ch]) {
+ var result = hooks[ch](stream, state);
+ if (result !== false) return result;
+ }
+ if (ch == '"' || ch == "'") {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ }
+ if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+ curPunc = ch;
+ return null
+ }
+ if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return "number";
+ }
+ if (ch == "/") {
+ if (stream.eat("*")) {
+ state.tokenize = tokenComment;
+ return tokenComment(stream, state);
+ }
+ if (stream.eat("/")) {
+ stream.skipToEnd();
+ return "comment";
+ }
+ }
+ if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return "operator";
+ }
+ stream.eatWhile(/[\w\$_]/);
+ var cur = stream.current().toLowerCase();
+ if (keyword.propertyIsEnumerable(cur)) {
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+ return "keyword";
+ } else if (variable.propertyIsEnumerable(cur)) {
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+ return "variable";
+ } else if (variable_2.propertyIsEnumerable(cur)) {
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+ return "variable-2";
+ } else if (variable_3.propertyIsEnumerable(cur)) {
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+ return "variable-3";
+ } else if (builtin.propertyIsEnumerable(cur)) {
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+ return "builtin";
+ } else { //Data types are of from KEYWORD##
+ var i = cur.length - 1;
+ while(i >= 0 && (!isNaN(cur[i]) || cur[i] == '_'))
+ --i;
+
+ if (i > 0) {
+ var cur2 = cur.substr(0, i + 1);
+ if (variable_3.propertyIsEnumerable(cur2)) {
+ if (blockKeywords.propertyIsEnumerable(cur2)) curPunc = "newstatement";
+ return "variable-3";
+ }
+ }
+ }
+ if (atoms.propertyIsEnumerable(cur)) return "atom";
+ return "word";
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {end = true; break;}
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = tokenBase;
+ return "string";
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return "comment";
+ }
+
+ function Context(indented, column, type, align, prev) {
+ this.indented = indented;
+ this.column = column;
+ this.type = type;
+ this.align = align;
+ this.prev = prev;
+ }
+ function pushContext(state, col, type) {
+ return state.context = new Context(state.indented, col, type, null, state.context);
+ }
+ function popContext(state) {
+ var t = state.context.type;
+ if (t == ")" || t == "]" || t == "}")
+ state.indented = state.context.indented;
+ return state.context = state.context.prev;
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: null,
+ context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
+ indented: 0,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ var ctx = state.context;
+ if (stream.sol()) {
+ if (ctx.align == null) ctx.align = false;
+ state.indented = stream.indentation();
+ state.startOfLine = true;
+ }
+ if (stream.eatSpace()) return null;
+ curPunc = null;
+ var style = (state.tokenize || tokenBase)(stream, state);
+ if (style == "comment" || style == "meta") return style;
+ if (ctx.align == null) ctx.align = true;
+
+ if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
+ else if (curPunc == "{") pushContext(state, stream.column(), "}");
+ else if (curPunc == "[") pushContext(state, stream.column(), "]");
+ else if (curPunc == "(") pushContext(state, stream.column(), ")");
+ else if (curPunc == "}") {
+ while (ctx.type == "statement") ctx = popContext(state);
+ if (ctx.type == "}") ctx = popContext(state);
+ while (ctx.type == "statement") ctx = popContext(state);
+ }
+ else if (curPunc == ctx.type) popContext(state);
+ else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
+ pushContext(state, stream.column(), "statement");
+ state.startOfLine = false;
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != tokenBase && state.tokenize != null) return 0;
+ var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
+ if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
+ var closing = firstChar == ctx.type;
+ if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
+ else if (ctx.align) return ctx.column + (closing ? 0 : 1);
+ else return ctx.indented + (closing ? 0 : indentUnit);
+ },
+
+ electricChars: "{}"
+ };
+});
+
+CodeMirror.defineMIME("text/x-ecl", "ecl");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/ecl/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/ecl/index.html
new file mode 100644
index 0000000..d6b41f4
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/ecl/index.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: ECL mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="ecl.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>.CodeMirror {border: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: ECL mode</h1>
+ <form><textarea id="code" name="code">
+/*
+sample useless code to demonstrate ecl syntax highlighting
+this is a multiline comment!
+*/
+
+// this is a singleline comment!
+
+import ut;
+r :=
+ record
+ string22 s1 := '123';
+ integer4 i1 := 123;
+ end;
+#option('tmp', true);
+d := dataset('tmp::qb', r, thor);
+output(d);
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ tabMode: "indent",
+ matchBrackets: true,
+ });
+ </script>
+
+ <p>Based on CodeMirror's clike mode. For more information see <a href="http://hpccsystems.com">HPCC Systems</a> web site.</p>
+ <p><strong>MIME types defined:</strong> <code>text/x-ecl</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/erlang/erlang.js b/codemirror_ui/lib/CodeMirror-2.3/mode/erlang/erlang.js
new file mode 100644
index 0000000..5c094f8
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/erlang/erlang.js
@@ -0,0 +1,251 @@
+// erlang -> CodeMirror tag
+//
+// atom -> atom
+// attribute -> attribute
+// builtin -> builtin
+// comment -> comment
+// error -> error
+// fun -> meta
+// function -> tag
+// guard -> property
+// keyword -> keyword
+// macro -> variable-2
+// number -> number
+// operator -> operator
+// record -> bracket
+// string -> string
+// type -> def
+// variable -> variable
+
+CodeMirror.defineMIME("text/x-erlang", "erlang");
+
+CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
+
+ var typeWords = [
+ "-type", "-spec", "-export_type", "-opaque"];
+
+ var keywordWords = [
+ "after","begin","catch","case","cond","end","fun","if",
+ "let","of","query","receive","try","when"];
+
+ var operatorWords = [
+ "and","andalso","band","bnot","bor","bsl","bsr","bxor",
+ "div","not","or","orelse","rem","xor"];
+
+ var operatorSymbols = [
+ "+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-"];
+
+ var guardWords = [
+ "is_atom","is_binary","is_bitstring","is_boolean","is_float",
+ "is_function","is_integer","is_list","is_number","is_pid",
+ "is_port","is_record","is_reference","is_tuple",
+ "atom","binary","bitstring","boolean","function","integer","list",
+ "number","pid","port","record","reference","tuple"];
+
+ var bifWords = [
+ "abs","adler32","adler32_combine","alive","apply","atom_to_binary",
+ "atom_to_list","binary_to_atom","binary_to_existing_atom",
+ "binary_to_list","binary_to_term","bit_size","bitstring_to_list",
+ "byte_size","check_process_code","contact_binary","crc32",
+ "crc32_combine","date","decode_packet","delete_module",
+ "disconnect_node","element","erase","exit","float","float_to_list",
+ "garbage_collect","get","get_keys","group_leader","halt","hd",
+ "integer_to_list","internal_bif","iolist_size","iolist_to_binary",
+ "is_alive","is_atom","is_binary","is_bitstring","is_boolean",
+ "is_float","is_function","is_integer","is_list","is_number","is_pid",
+ "is_port","is_process_alive","is_record","is_reference","is_tuple",
+ "length","link","list_to_atom","list_to_binary","list_to_bitstring",
+ "list_to_existing_atom","list_to_float","list_to_integer",
+ "list_to_pid","list_to_tuple","load_module","make_ref","module_loaded",
+ "monitor_node","node","node_link","node_unlink","nodes","notalive",
+ "now","open_port","pid_to_list","port_close","port_command",
+ "port_connect","port_control","pre_loaded","process_flag",
+ "process_info","processes","purge_module","put","register",
+ "registered","round","self","setelement","size","spawn","spawn_link",
+ "spawn_monitor","spawn_opt","split_binary","statistics",
+ "term_to_binary","time","throw","tl","trunc","tuple_size",
+ "tuple_to_list","unlink","unregister","whereis"];
+
+ function isMember(element,list) {
+ return (-1 < list.indexOf(element));
+ }
+
+ function isPrev(stream,string) {
+ var start = stream.start;
+ var len = string.length;
+ if (len <= start) {
+ var word = stream.string.slice(start-len,start);
+ return word == string;
+ }else{
+ return false;
+ }
+ }
+
+ var smallRE = /[a-z_]/;
+ var largeRE = /[A-Z_]/;
+ var digitRE = /[0-9]/;
+ var octitRE = /[0-7]/;
+ var idRE = /[a-z_A-Z0-9]/;
+
+ function tokenize(stream, state) {
+ if (stream.eatSpace()) {
+ return null;
+ }
+
+ // attributes and type specs
+ if (stream.sol() && stream.peek() == '-') {
+ stream.next();
+ if (stream.eat(smallRE) && stream.eatWhile(idRE)) {
+ if (stream.peek() == "(") {
+ return "attribute";
+ }else if (isMember(stream.current(),typeWords)) {
+ return "def";
+ }else{
+ return null;
+ }
+ }
+ stream.backUp(1);
+ }
+
+ var ch = stream.next();
+
+ // comment
+ if (ch == '%') {
+ stream.skipToEnd();
+ return "comment";
+ }
+
+ // macro
+ if (ch == '?') {
+ stream.eatWhile(idRE);
+ return "variable-2";
+ }
+
+ // record
+ if ( ch == "#") {
+ stream.eatWhile(idRE);
+ return "bracket";
+ }
+
+ // char
+ if ( ch == "$") {
+ if (stream.next() == "\\") {
+ if (!stream.eatWhile(octitRE)) {
+ stream.next();
+ }
+ }
+ return "string";
+ }
+
+ // quoted atom
+ if (ch == '\'') {
+ return singleQuote(stream);
+ }
+
+ // string
+ if (ch == '"') {
+ return doubleQuote(stream);
+ }
+
+ // variable
+ if (largeRE.test(ch)) {
+ stream.eatWhile(idRE);
+ return "variable";
+ }
+
+ // atom/keyword/BIF/function
+ if (smallRE.test(ch)) {
+ stream.eatWhile(idRE);
+
+ if (stream.peek() == "/") {
+ stream.next();
+ if (stream.eatWhile(digitRE)) {
+ return "meta"; // f/0 style fun
+ }else{
+ stream.backUp(1);
+ return "atom";
+ }
+ }
+
+ var w = stream.current();
+
+ if (isMember(w,keywordWords)) {
+ return "keyword"; // keyword
+ }
+ if (stream.peek() == "(") {
+ if (isMember(w,bifWords) &&
+ (!isPrev(stream,":") || isPrev(stream,"erlang:"))) {
+ return "builtin"; // BIF
+ }else{
+ return "tag"; // function
+ }
+ }
+ if (isMember(w,guardWords)) {
+ return "property"; // guard
+ }
+ if (isMember(w,operatorWords)) {
+ return "operator"; // operator
+ }
+
+
+ if (stream.peek() == ":") {
+ if (w == "erlang") { // f:now() is highlighted incorrectly
+ return "builtin";
+ } else {
+ return "tag"; // function application
+ }
+ }
+
+ return "atom";
+ }
+
+ // number
+ if (digitRE.test(ch)) {
+ stream.eatWhile(digitRE);
+ if (stream.eat('#')) {
+ stream.eatWhile(digitRE); // 16#10 style integer
+ } else {
+ if (stream.eat('.')) { // float
+ stream.eatWhile(digitRE);
+ }
+ if (stream.eat(/[eE]/)) {
+ stream.eat(/[-+]/); // float with exponent
+ stream.eatWhile(digitRE);
+ }
+ }
+ return "number"; // normal integer
+ }
+
+ return null;
+ }
+
+ function doubleQuote(stream) {
+ return Quote(stream, '"', '\\', "string");
+ }
+
+ function singleQuote(stream) {
+ return Quote(stream,'\'','\\',"atom");
+ }
+
+ function Quote(stream,quoteChar,escapeChar,tag) {
+ while (!stream.eol()) {
+ var ch = stream.next();
+ if (ch == quoteChar) {
+ return tag;
+ }else if (ch == escapeChar) {
+ stream.next();
+ }
+ }
+ return "error";
+ }
+
+ return {
+ startState: function() {
+ return {};
+ },
+
+ token: function(stream, state) {
+ return tokenize(stream, state);
+ }
+ };
+});
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/erlang/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/erlang/index.html
new file mode 100644
index 0000000..625491f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/erlang/index.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Erlang mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="erlang.js"></script>
+ <link rel="stylesheet" href="../../theme/erlang-dark.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Erlang mode</h1>
+
+<form><textarea id="code" name="code">
+%% -*- mode: erlang; erlang-indent-level: 2 -*-
+%%% Created : 7 May 2012 by mats cronqvist <masse@klarna.com>
+
+%% @doc
+%% Demonstrates how to print a record.
+%% @end
+
+-module('ex').
+-author('mats cronqvist').
+-export([demo/0,
+ rec_info/1]).
+
+-record(demo,{a="One",b="Two",c="Three",d="Four"}).
+
+rec_info(demo) -> record_info(fields,demo).
+
+demo() -> expand_recs(?MODULE,#demo{a="A",b="BB"}).
+
+expand_recs(M,List) when is_list(List) ->
+ [expand_recs(M,L)||L<-List];
+expand_recs(M,Tup) when is_tuple(Tup) ->
+ case tuple_size(Tup) of
+ L when L < 1 -> Tup;
+ L ->
+ try Fields = M:rec_info(element(1,Tup)),
+ L = length(Fields)+1,
+ lists:zip(Fields,expand_recs(M,tl(tuple_to_list(Tup))))
+ catch _:_ ->
+ list_to_tuple(expand_recs(M,tuple_to_list(Tup)))
+ end
+ end;
+expand_recs(_,Term) ->
+ Term.
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ theme: "erlang-dark"
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-erlang</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/gfm/gfm.js b/codemirror_ui/lib/CodeMirror-2.3/mode/gfm/gfm.js
new file mode 100644
index 0000000..8f457c5
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/gfm/gfm.js
@@ -0,0 +1,144 @@
+CodeMirror.defineMode("gfm", function(config, parserConfig) {
+ var mdMode = CodeMirror.getMode(config, "markdown");
+ var aliases = {
+ html: "htmlmixed",
+ js: "javascript",
+ json: "application/json",
+ c: "text/x-csrc",
+ "c++": "text/x-c++src",
+ java: "text/x-java",
+ csharp: "text/x-csharp",
+ "c#": "text/x-csharp"
+ };
+
+ // make this lazy so that we don't need to load GFM last
+ var getMode = (function () {
+ var i, modes = {}, mimes = {}, mime;
+
+ var list = CodeMirror.listModes();
+ for (i = 0; i < list.length; i++) {
+ modes[list[i]] = list[i];
+ }
+ var mimesList = CodeMirror.listMIMEs();
+ for (i = 0; i < mimesList.length; i++) {
+ mime = mimesList[i].mime;
+ mimes[mime] = mimesList[i].mime;
+ }
+
+ for (var a in aliases) {
+ if (aliases[a] in modes || aliases[a] in mimes)
+ modes[a] = aliases[a];
+ }
+
+ return function (lang) {
+ return modes[lang] ? CodeMirror.getMode(config, modes[lang]) : null;
+ }
+ }());
+
+ function markdown(stream, state) {
+ // intercept fenced code blocks
+ if (stream.sol() && stream.match(/^```([\w+#]*)/)) {
+ // try switching mode
+ state.localMode = getMode(RegExp.$1)
+ if (state.localMode)
+ state.localState = state.localMode.startState();
+
+ state.token = local;
+ return 'code';
+ }
+
+ return mdMode.token(stream, state.mdState);
+ }
+
+ function local(stream, state) {
+ if (stream.sol() && stream.match(/^```/)) {
+ state.localMode = state.localState = null;
+ state.token = markdown;
+ return 'code';
+ }
+ else if (state.localMode) {
+ return state.localMode.token(stream, state.localState);
+ } else {
+ stream.skipToEnd();
+ return 'code';
+ }
+ }
+
+ // custom handleText to prevent emphasis in the middle of a word
+ // and add autolinking
+ function handleText(stream, mdState) {
+ var match;
+ if (stream.match(/^\w+:\/\/\S+/)) {
+ return 'link';
+ }
+ if (stream.match(/^[^\[*\\<>` _][^\[*\\<>` ]*[^\[*\\<>` _]/)) {
+ return mdMode.getType(mdState);
+ }
+ if (match = stream.match(/^[^\[*\\<>` ]+/)) {
+ var word = match[0];
+ if (word[0] === '_' && word[word.length-1] === '_') {
+ stream.backUp(word.length);
+ return undefined;
+ }
+ return mdMode.getType(mdState);
+ }
+ if (stream.eatSpace()) {
+ return null;
+ }
+ }
+
+ return {
+ startState: function() {
+ var mdState = mdMode.startState();
+ mdState.text = handleText;
+ return {token: markdown, mode: "markdown", mdState: mdState,
+ localMode: null, localState: null};
+ },
+
+ copyState: function(state) {
+ return {token: state.token, mode: state.mode, mdState: CodeMirror.copyState(mdMode, state.mdState),
+ localMode: state.localMode,
+ localState: state.localMode ? CodeMirror.copyState(state.localMode, state.localState) : null};
+ },
+
+ token: function(stream, state) {
+ /* Parse GFM double bracket links */
+ if ((ch = stream.peek()) != undefined && ch == '[') {
+ stream.next(); // Advance the stream
+
+ /* Only handle double bracket links */
+ if ((ch = stream.peek()) == undefined || ch != '[') {
+ stream.backUp(1);
+ return state.token(stream, state);
+ }
+
+ while ((ch = stream.next()) != undefined && ch != ']') {}
+
+ if (ch == ']' && (ch = stream.next()) != undefined && ch == ']')
+ return 'link';
+
+ /* If we did not find the second ']' */
+ stream.backUp(1);
+ }
+
+ /* Match GFM latex formulas, as well as latex formulas within '$' */
+ if (stream.match(/^\$[^\$]+\$/)) {
+ return "string";
+ }
+
+ if (stream.match(/^\\\((.*?)\\\)/)) {
+ return "string";
+ }
+
+ if (stream.match(/^\$\$[^\$]+\$\$/)) {
+ return "string";
+ }
+
+ if (stream.match(/^\\\[(.*?)\\\]/)) {
+ return "string";
+ }
+
+ return state.token(stream, state);
+ }
+ }
+}, "markdown");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/gfm/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/gfm/index.html
new file mode 100644
index 0000000..b27d49a
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/gfm/index.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: GFM mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="../xml/xml.js"></script>
+ <script src="../markdown/markdown.js"></script>
+ <script src="gfm.js"></script>
+ <script src="../javascript/javascript.js"></script>
+ <link rel="stylesheet" href="../markdown/markdown.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: GFM mode</h1>
+
+<!-- source: http://daringfireball.net/projects/markdown/basics.text -->
+<form><textarea id="code" name="code">
+Github Flavored Markdown
+========================
+
+Everything from markdown plus GFM features:
+
+## Fenced code blocks
+
+```javascript
+for (var i = 0; i &lt; items.length; i++) {
+ console.log(items[i], i); // log them
+}
+```
+
+See http://github.github.com/github-flavored-markdown/
+
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: 'gfm',
+ lineNumbers: true,
+ matchBrackets: true,
+ theme: "default"
+ });
+ </script>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/go/go.js b/codemirror_ui/lib/CodeMirror-2.3/mode/go/go.js
new file mode 100644
index 0000000..00e5d6c
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/go/go.js
@@ -0,0 +1,170 @@
+CodeMirror.defineMode("go", function(config, parserConfig) {
+ var indentUnit = config.indentUnit;
+
+ var keywords = {
+ "break":true, "case":true, "chan":true, "const":true, "continue":true,
+ "default":true, "defer":true, "else":true, "fallthrough":true, "for":true,
+ "func":true, "go":true, "goto":true, "if":true, "import":true,
+ "interface":true, "map":true, "package":true, "range":true, "return":true,
+ "select":true, "struct":true, "switch":true, "type":true, "var":true,
+ "bool":true, "byte":true, "complex64":true, "complex128":true,
+ "float32":true, "float64":true, "int8":true, "int16":true, "int32":true,
+ "int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true,
+ "uint64":true, "int":true, "uint":true, "uintptr":true
+ };
+
+ var atoms = {
+ "true":true, "false":true, "iota":true, "nil":true, "append":true,
+ "cap":true, "close":true, "complex":true, "copy":true, "imag":true,
+ "len":true, "make":true, "new":true, "panic":true, "print":true,
+ "println":true, "real":true, "recover":true
+ };
+
+ var blockKeywords = {
+ "else":true, "for":true, "func":true, "if":true, "interface":true,
+ "select":true, "struct":true, "switch":true
+ };
+
+ var isOperatorChar = /[+\-*&^%:=<>!|\/]/;
+
+ var curPunc;
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ if (ch == '"' || ch == "'" || ch == "`") {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ }
+ if (/[\d\.]/.test(ch)) {
+ if (ch == ".") {
+ stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
+ } else if (ch == "0") {
+ stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
+ } else {
+ stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
+ }
+ return "number";
+ }
+ if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+ curPunc = ch;
+ return null
+ }
+ if (ch == "/") {
+ if (stream.eat("*")) {
+ state.tokenize = tokenComment;
+ return tokenComment(stream, state);
+ }
+ if (stream.eat("/")) {
+ stream.skipToEnd();
+ return "comment";
+ }
+ }
+ if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return "operator";
+ }
+ stream.eatWhile(/[\w\$_]/);
+ var cur = stream.current();
+ if (keywords.propertyIsEnumerable(cur)) {
+ if (cur == "case" || cur == "default") curPunc = "case";
+ return "keyword";
+ }
+ if (atoms.propertyIsEnumerable(cur)) return "atom";
+ return "word";
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {end = true; break;}
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || quote == "`"))
+ state.tokenize = tokenBase;
+ return "string";
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return "comment";
+ }
+
+ function Context(indented, column, type, align, prev) {
+ this.indented = indented;
+ this.column = column;
+ this.type = type;
+ this.align = align;
+ this.prev = prev;
+ }
+ function pushContext(state, col, type) {
+ return state.context = new Context(state.indented, col, type, null, state.context);
+ }
+ function popContext(state) {
+ var t = state.context.type;
+ if (t == ")" || t == "]" || t == "}")
+ state.indented = state.context.indented;
+ return state.context = state.context.prev;
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: null,
+ context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
+ indented: 0,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ var ctx = state.context;
+ if (stream.sol()) {
+ if (ctx.align == null) ctx.align = false;
+ state.indented = stream.indentation();
+ state.startOfLine = true;
+ if (ctx.type == "case") ctx.type = "}";
+ }
+ if (stream.eatSpace()) return null;
+ curPunc = null;
+ var style = (state.tokenize || tokenBase)(stream, state);
+ if (style == "comment") return style;
+ if (ctx.align == null) ctx.align = true;
+
+ if (curPunc == "{") pushContext(state, stream.column(), "}");
+ else if (curPunc == "[") pushContext(state, stream.column(), "]");
+ else if (curPunc == "(") pushContext(state, stream.column(), ")");
+ else if (curPunc == "case") ctx.type = "case"
+ else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state);
+ else if (curPunc == ctx.type) popContext(state);
+ state.startOfLine = false;
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != tokenBase && state.tokenize != null) return 0;
+ var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
+ if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) {
+ state.context.type = "}";
+ return ctx.indented;
+ }
+ var closing = firstChar == ctx.type;
+ if (ctx.align) return ctx.column + (closing ? 0 : 1);
+ else return ctx.indented + (closing ? 0 : indentUnit);
+ },
+
+ electricChars: "{}:"
+ };
+});
+
+CodeMirror.defineMIME("text/x-go", "go");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/go/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/go/index.html
new file mode 100644
index 0000000..9cdad1a
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/go/index.html
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Go mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <link rel="stylesheet" href="../../theme/elegant.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="go.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>.CodeMirror {border:1px solid #999; background:#ffc}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Go mode</h1>
+
+<form><textarea id="code" name="code">
+// Prime Sieve in Go.
+// Taken from the Go specification.
+// Copyright © The Go Authors.
+
+package main
+
+import "fmt"
+
+// Send the sequence 2, 3, 4, ... to channel 'ch'.
+func generate(ch chan&lt;- int) {
+ for i := 2; ; i++ {
+ ch &lt;- i // Send 'i' to channel 'ch'
+ }
+}
+
+// Copy the values from channel 'src' to channel 'dst',
+// removing those divisible by 'prime'.
+func filter(src &lt;-chan int, dst chan&lt;- int, prime int) {
+ for i := range src { // Loop over values received from 'src'.
+ if i%prime != 0 {
+ dst &lt;- i // Send 'i' to channel 'dst'.
+ }
+ }
+}
+
+// The prime sieve: Daisy-chain filter processes together.
+func sieve() {
+ ch := make(chan int) // Create a new channel.
+ go generate(ch) // Start generate() as a subprocess.
+ for {
+ prime := &lt;-ch
+ fmt.Print(prime, "\n")
+ ch1 := make(chan int)
+ go filter(ch, ch1, prime)
+ ch = ch1
+ }
+}
+
+func main() {
+ sieve()
+}
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ theme: "elegant",
+ matchBrackets: true,
+ indentUnit: 8,
+ tabSize: 8,
+ indentWithTabs: true,
+ mode: "text/x-go"
+ });
+ </script>
+
+ <p><strong>MIME type:</strong> <code>text/x-go</code></p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/groovy/groovy.js b/codemirror_ui/lib/CodeMirror-2.3/mode/groovy/groovy.js
new file mode 100644
index 0000000..029e0c9
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/groovy/groovy.js
@@ -0,0 +1,210 @@
+CodeMirror.defineMode("groovy", function(config, parserConfig) {
+ function words(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+ var keywords = words(
+ "abstract as assert boolean break byte case catch char class const continue def default " +
+ "do double else enum extends final finally float for goto if implements import in " +
+ "instanceof int interface long native new package private protected public return " +
+ "short static strictfp super switch synchronized threadsafe throw throws transient " +
+ "try void volatile while");
+ var blockKeywords = words("catch class do else finally for if switch try while enum interface def");
+ var atoms = words("null true false this");
+
+ var curPunc;
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ if (ch == '"' || ch == "'") {
+ return startString(ch, stream, state);
+ }
+ if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+ curPunc = ch;
+ return null
+ }
+ if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ if (stream.eat(/eE/)) { stream.eat(/\+\-/); stream.eatWhile(/\d/); }
+ return "number";
+ }
+ if (ch == "/") {
+ if (stream.eat("*")) {
+ state.tokenize.push(tokenComment);
+ return tokenComment(stream, state);
+ }
+ if (stream.eat("/")) {
+ stream.skipToEnd();
+ return "comment";
+ }
+ if (expectExpression(state.lastToken)) {
+ return startString(ch, stream, state);
+ }
+ }
+ if (ch == "-" && stream.eat(">")) {
+ curPunc = "->";
+ return null;
+ }
+ if (/[+\-*&%=<>!?|\/~]/.test(ch)) {
+ stream.eatWhile(/[+\-*&%=<>|~]/);
+ return "operator";
+ }
+ stream.eatWhile(/[\w\$_]/);
+ if (ch == "@") { stream.eatWhile(/[\w\$_\.]/); return "meta"; }
+ if (state.lastToken == ".") return "property";
+ if (stream.eat(":")) { curPunc = "proplabel"; return "property"; }
+ var cur = stream.current();
+ if (atoms.propertyIsEnumerable(cur)) { return "atom"; }
+ if (keywords.propertyIsEnumerable(cur)) {
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+ return "keyword";
+ }
+ return "word";
+ }
+ tokenBase.isBase = true;
+
+ function startString(quote, stream, state) {
+ var tripleQuoted = false;
+ if (quote != "/" && stream.eat(quote)) {
+ if (stream.eat(quote)) tripleQuoted = true;
+ else return "string";
+ }
+ function t(stream, state) {
+ var escaped = false, next, end = !tripleQuoted;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {
+ if (!tripleQuoted) { break; }
+ if (stream.match(quote + quote)) { end = true; break; }
+ }
+ if (quote == '"' && next == "$" && !escaped && stream.eat("{")) {
+ state.tokenize.push(tokenBaseUntilBrace());
+ return "string";
+ }
+ escaped = !escaped && next == "\\";
+ }
+ if (end) state.tokenize.pop();
+ return "string";
+ }
+ state.tokenize.push(t);
+ return t(stream, state);
+ }
+
+ function tokenBaseUntilBrace() {
+ var depth = 1;
+ function t(stream, state) {
+ if (stream.peek() == "}") {
+ depth--;
+ if (depth == 0) {
+ state.tokenize.pop();
+ return state.tokenize[state.tokenize.length-1](stream, state);
+ }
+ } else if (stream.peek() == "{") {
+ depth++;
+ }
+ return tokenBase(stream, state);
+ }
+ t.isBase = true;
+ return t;
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize.pop();
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return "comment";
+ }
+
+ function expectExpression(last) {
+ return !last || last == "operator" || last == "->" || /[\.\[\{\(,;:]/.test(last) ||
+ last == "newstatement" || last == "keyword" || last == "proplabel";
+ }
+
+ function Context(indented, column, type, align, prev) {
+ this.indented = indented;
+ this.column = column;
+ this.type = type;
+ this.align = align;
+ this.prev = prev;
+ }
+ function pushContext(state, col, type) {
+ return state.context = new Context(state.indented, col, type, null, state.context);
+ }
+ function popContext(state) {
+ var t = state.context.type;
+ if (t == ")" || t == "]" || t == "}")
+ state.indented = state.context.indented;
+ return state.context = state.context.prev;
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: [tokenBase],
+ context: new Context((basecolumn || 0) - config.indentUnit, 0, "top", false),
+ indented: 0,
+ startOfLine: true,
+ lastToken: null
+ };
+ },
+
+ token: function(stream, state) {
+ var ctx = state.context;
+ if (stream.sol()) {
+ if (ctx.align == null) ctx.align = false;
+ state.indented = stream.indentation();
+ state.startOfLine = true;
+ // Automatic semicolon insertion
+ if (ctx.type == "statement" && !expectExpression(state.lastToken)) {
+ popContext(state); ctx = state.context;
+ }
+ }
+ if (stream.eatSpace()) return null;
+ curPunc = null;
+ var style = state.tokenize[state.tokenize.length-1](stream, state);
+ if (style == "comment") return style;
+ if (ctx.align == null) ctx.align = true;
+
+ if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
+ // Handle indentation for {x -> \n ... }
+ else if (curPunc == "->" && ctx.type == "statement" && ctx.prev.type == "}") {
+ popContext(state);
+ state.context.align = false;
+ }
+ else if (curPunc == "{") pushContext(state, stream.column(), "}");
+ else if (curPunc == "[") pushContext(state, stream.column(), "]");
+ else if (curPunc == "(") pushContext(state, stream.column(), ")");
+ else if (curPunc == "}") {
+ while (ctx.type == "statement") ctx = popContext(state);
+ if (ctx.type == "}") ctx = popContext(state);
+ while (ctx.type == "statement") ctx = popContext(state);
+ }
+ else if (curPunc == ctx.type) popContext(state);
+ else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
+ pushContext(state, stream.column(), "statement");
+ state.startOfLine = false;
+ state.lastToken = curPunc || style;
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (!state.tokenize[state.tokenize.length-1].isBase) return 0;
+ var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;
+ if (ctx.type == "statement" && !expectExpression(state.lastToken)) ctx = ctx.prev;
+ var closing = firstChar == ctx.type;
+ if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : config.indentUnit);
+ else if (ctx.align) return ctx.column + (closing ? 0 : 1);
+ else return ctx.indented + (closing ? 0 : config.indentUnit);
+ },
+
+ electricChars: "{}"
+ };
+});
+
+CodeMirror.defineMIME("text/x-groovy", "groovy");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/groovy/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/groovy/index.html
new file mode 100644
index 0000000..226475c
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/groovy/index.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Groovy mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="groovy.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>.CodeMirror {border-top: 1px solid #500; border-bottom: 1px solid #500;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Groovy mode</h1>
+
+<form><textarea id="code" name="code">
+//Pattern for groovy script
+def p = ~/.*\.groovy/
+new File( 'd:\\scripts' ).eachFileMatch(p) {f ->
+ // imports list
+ def imports = []
+ f.eachLine {
+ // condition to detect an import instruction
+ ln -> if ( ln =~ '^import .*' ) {
+ imports << "${ln - 'import '}"
+ }
+ }
+ // print thmen
+ if ( ! imports.empty ) {
+ println f
+ imports.each{ println " $it" }
+ }
+}
+
+/* Coin changer demo code from http://groovy.codehaus.org */
+
+enum UsCoin {
+ quarter(25), dime(10), nickel(5), penny(1)
+ UsCoin(v) { value = v }
+ final value
+}
+
+enum OzzieCoin {
+ fifty(50), twenty(20), ten(10), five(5)
+ OzzieCoin(v) { value = v }
+ final value
+}
+
+def plural(word, count) {
+ if (count == 1) return word
+ word[-1] == 'y' ? word[0..-2] + "ies" : word + "s"
+}
+
+def change(currency, amount) {
+ currency.values().inject([]){ list, coin ->
+ int count = amount / coin.value
+ amount = amount % coin.value
+ list += "$count ${plural(coin.toString(), count)}"
+ }
+}
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ mode: "text/x-groovy"
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-groovy</code></p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/haskell/haskell.js b/codemirror_ui/lib/CodeMirror-2.3/mode/haskell/haskell.js
new file mode 100644
index 0000000..aac5041
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/haskell/haskell.js
@@ -0,0 +1,242 @@
+CodeMirror.defineMode("haskell", function(cmCfg, modeCfg) {
+
+ function switchState(source, setState, f) {
+ setState(f);
+ return f(source, setState);
+ }
+
+ // These should all be Unicode extended, as per the Haskell 2010 report
+ var smallRE = /[a-z_]/;
+ var largeRE = /[A-Z]/;
+ var digitRE = /[0-9]/;
+ var hexitRE = /[0-9A-Fa-f]/;
+ var octitRE = /[0-7]/;
+ var idRE = /[a-z_A-Z0-9']/;
+ var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
+ var specialRE = /[(),;[\]`{}]/;
+ var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer
+
+ function normal(source, setState) {
+ if (source.eatWhile(whiteCharRE)) {
+ return null;
+ }
+
+ var ch = source.next();
+ if (specialRE.test(ch)) {
+ if (ch == '{' && source.eat('-')) {
+ var t = "comment";
+ if (source.eat('#')) {
+ t = "meta";
+ }
+ return switchState(source, setState, ncomment(t, 1));
+ }
+ return null;
+ }
+
+ if (ch == '\'') {
+ if (source.eat('\\')) {
+ source.next(); // should handle other escapes here
+ }
+ else {
+ source.next();
+ }
+ if (source.eat('\'')) {
+ return "string";
+ }
+ return "error";
+ }
+
+ if (ch == '"') {
+ return switchState(source, setState, stringLiteral);
+ }
+
+ if (largeRE.test(ch)) {
+ source.eatWhile(idRE);
+ if (source.eat('.')) {
+ return "qualifier";
+ }
+ return "variable-2";
+ }
+
+ if (smallRE.test(ch)) {
+ source.eatWhile(idRE);
+ return "variable";
+ }
+
+ if (digitRE.test(ch)) {
+ if (ch == '0') {
+ if (source.eat(/[xX]/)) {
+ source.eatWhile(hexitRE); // should require at least 1
+ return "integer";
+ }
+ if (source.eat(/[oO]/)) {
+ source.eatWhile(octitRE); // should require at least 1
+ return "number";
+ }
+ }
+ source.eatWhile(digitRE);
+ var t = "number";
+ if (source.eat('.')) {
+ t = "number";
+ source.eatWhile(digitRE); // should require at least 1
+ }
+ if (source.eat(/[eE]/)) {
+ t = "number";
+ source.eat(/[-+]/);
+ source.eatWhile(digitRE); // should require at least 1
+ }
+ return t;
+ }
+
+ if (symbolRE.test(ch)) {
+ if (ch == '-' && source.eat(/-/)) {
+ source.eatWhile(/-/);
+ if (!source.eat(symbolRE)) {
+ source.skipToEnd();
+ return "comment";
+ }
+ }
+ var t = "variable";
+ if (ch == ':') {
+ t = "variable-2";
+ }
+ source.eatWhile(symbolRE);
+ return t;
+ }
+
+ return "error";
+ }
+
+ function ncomment(type, nest) {
+ if (nest == 0) {
+ return normal;
+ }
+ return function(source, setState) {
+ var currNest = nest;
+ while (!source.eol()) {
+ var ch = source.next();
+ if (ch == '{' && source.eat('-')) {
+ ++currNest;
+ }
+ else if (ch == '-' && source.eat('}')) {
+ --currNest;
+ if (currNest == 0) {
+ setState(normal);
+ return type;
+ }
+ }
+ }
+ setState(ncomment(type, currNest));
+ return type;
+ }
+ }
+
+ function stringLiteral(source, setState) {
+ while (!source.eol()) {
+ var ch = source.next();
+ if (ch == '"') {
+ setState(normal);
+ return "string";
+ }
+ if (ch == '\\') {
+ if (source.eol() || source.eat(whiteCharRE)) {
+ setState(stringGap);
+ return "string";
+ }
+ if (source.eat('&')) {
+ }
+ else {
+ source.next(); // should handle other escapes here
+ }
+ }
+ }
+ setState(normal);
+ return "error";
+ }
+
+ function stringGap(source, setState) {
+ if (source.eat('\\')) {
+ return switchState(source, setState, stringLiteral);
+ }
+ source.next();
+ setState(normal);
+ return "error";
+ }
+
+
+ var wellKnownWords = (function() {
+ var wkw = {};
+ function setType(t) {
+ return function () {
+ for (var i = 0; i < arguments.length; i++)
+ wkw[arguments[i]] = t;
+ }
+ }
+
+ setType("keyword")(
+ "case", "class", "data", "default", "deriving", "do", "else", "foreign",
+ "if", "import", "in", "infix", "infixl", "infixr", "instance", "let",
+ "module", "newtype", "of", "then", "type", "where", "_");
+
+ setType("keyword")(
+ "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
+
+ setType("builtin")(
+ "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
+ "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
+
+ setType("builtin")(
+ "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq",
+ "False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT",
+ "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
+ "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
+ "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
+ "String", "True");
+
+ setType("builtin")(
+ "abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
+ "asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
+ "compare", "concat", "concatMap", "const", "cos", "cosh", "curry",
+ "cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either",
+ "elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo",
+ "enumFromTo", "error", "even", "exp", "exponent", "fail", "filter",
+ "flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap",
+ "foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger",
+ "fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents",
+ "getLine", "head", "id", "init", "interact", "ioError", "isDenormalized",
+ "isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last",
+ "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
+ "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
+ "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
+ "otherwise", "pi", "pred", "print", "product", "properFraction",
+ "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
+ "readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
+ "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
+ "round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq",
+ "sequence", "sequence_", "show", "showChar", "showList", "showParen",
+ "showString", "shows", "showsPrec", "significand", "signum", "sin",
+ "sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum",
+ "tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger",
+ "toRational", "truncate", "uncurry", "undefined", "unlines", "until",
+ "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
+ "zip3", "zipWith", "zipWith3");
+
+ return wkw;
+ })();
+
+
+
+ return {
+ startState: function () { return { f: normal }; },
+ copyState: function (s) { return { f: s.f }; },
+
+ token: function(stream, state) {
+ var t = state.f(stream, function(s) { state.f = s; });
+ var w = stream.current();
+ return (w in wellKnownWords) ? wellKnownWords[w] : t;
+ }
+ };
+
+});
+
+CodeMirror.defineMIME("text/x-haskell", "haskell");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/haskell/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/haskell/index.html
new file mode 100644
index 0000000..15706e7
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/haskell/index.html
@@ -0,0 +1,60 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Haskell mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="haskell.js"></script>
+ <link rel="stylesheet" href="../../theme/elegant.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Haskell mode</h1>
+
+<form><textarea id="code" name="code">
+module UniquePerms (
+ uniquePerms
+ )
+where
+
+-- | Find all unique permutations of a list where there might be duplicates.
+uniquePerms :: (Eq a) => [a] -> [[a]]
+uniquePerms = permBag . makeBag
+
+-- | An unordered collection where duplicate values are allowed,
+-- but represented with a single value and a count.
+type Bag a = [(a, Int)]
+
+makeBag :: (Eq a) => [a] -> Bag a
+makeBag [] = []
+makeBag (a:as) = mix a $ makeBag as
+ where
+ mix a [] = [(a,1)]
+ mix a (bn@(b,n):bs) | a == b = (b,n+1):bs
+ | otherwise = bn : mix a bs
+
+permBag :: Bag a -> [[a]]
+permBag [] = [[]]
+permBag bs = concatMap (\(f,cs) -> map (f:) $ permBag cs) . oneOfEach $ bs
+ where
+ oneOfEach [] = []
+ oneOfEach (an@(a,n):bs) =
+ let bs' = if n == 1 then bs else (a,n-1):bs
+ in (a,bs') : mapSnd (an:) (oneOfEach bs)
+
+ apSnd f (a,b) = (a, f b)
+ mapSnd = map . apSnd
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ theme: "elegant"
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-haskell</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/htmlembedded/htmlembedded.js b/codemirror_ui/lib/CodeMirror-2.3/mode/htmlembedded/htmlembedded.js
new file mode 100644
index 0000000..1773aeb
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/htmlembedded/htmlembedded.js
@@ -0,0 +1,68 @@
+CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
+
+ //config settings
+ var scriptStartRegex = parserConfig.scriptStartRegex || /^<%/i,
+ scriptEndRegex = parserConfig.scriptEndRegex || /^%>/i;
+
+ //inner modes
+ var scriptingMode, htmlMixedMode;
+
+ //tokenizer when in html mode
+ function htmlDispatch(stream, state) {
+ if (stream.match(scriptStartRegex, false)) {
+ state.token=scriptingDispatch;
+ return scriptingMode.token(stream, state.scriptState);
+ }
+ else
+ return htmlMixedMode.token(stream, state.htmlState);
+ }
+
+ //tokenizer when in scripting mode
+ function scriptingDispatch(stream, state) {
+ if (stream.match(scriptEndRegex, false)) {
+ state.token=htmlDispatch;
+ return htmlMixedMode.token(stream, state.htmlState);
+ }
+ else
+ return scriptingMode.token(stream, state.scriptState);
+ }
+
+
+ return {
+ startState: function() {
+ scriptingMode = scriptingMode || CodeMirror.getMode(config, parserConfig.scriptingModeSpec);
+ htmlMixedMode = htmlMixedMode || CodeMirror.getMode(config, "htmlmixed");
+ return {
+ token : parserConfig.startOpen ? scriptingDispatch : htmlDispatch,
+ htmlState : htmlMixedMode.startState(),
+ scriptState : scriptingMode.startState()
+ }
+ },
+
+ token: function(stream, state) {
+ return state.token(stream, state);
+ },
+
+ indent: function(state, textAfter) {
+ if (state.token == htmlDispatch)
+ return htmlMixedMode.indent(state.htmlState, textAfter);
+ else
+ return scriptingMode.indent(state.scriptState, textAfter);
+ },
+
+ copyState: function(state) {
+ return {
+ token : state.token,
+ htmlState : CodeMirror.copyState(htmlMixedMode, state.htmlState),
+ scriptState : CodeMirror.copyState(scriptingMode, state.scriptState)
+ }
+ },
+
+
+ electricChars: "/{}:"
+ }
+}, "htmlmixed");
+
+CodeMirror.defineMIME("application/x-ejs", { name: "htmlembedded", scriptingModeSpec:"javascript"});
+CodeMirror.defineMIME("application/x-aspx", { name: "htmlembedded", scriptingModeSpec:"text/x-csharp"});
+CodeMirror.defineMIME("application/x-jsp", { name: "htmlembedded", scriptingModeSpec:"text/x-java"});
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/htmlembedded/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/htmlembedded/index.html
new file mode 100644
index 0000000..c1374e5
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/htmlembedded/index.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Html Embedded Scripts mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="../xml/xml.js"></script>
+ <script src="../javascript/javascript.js"></script>
+ <script src="../css/css.js"></script>
+ <script src="../htmlmixed/htmlmixed.js"></script>
+ <script src="htmlembedded.js"></script>
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Html Embedded Scripts mode</h1>
+
+<form><textarea id="code" name="code">
+<%
+function hello(who) {
+ return "Hello " + who;
+}
+%>
+This is an example of EJS (embedded javascript)
+<p>The program says <%= hello("world") %>.</p>
+<script>
+ alert("And here is some normal JS code"); // also colored
+</script>
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ mode: "application/x-ejs",
+ indentUnit: 4,
+ indentWithTabs: true,
+ enterMode: "keep",
+ tabMode: "shift"
+ });
+ </script>
+
+ <p>Mode for html embedded scripts like JSP and ASP.NET. Depends on HtmlMixed which in turn depends on
+ JavaScript, CSS and XML.<br />Other dependancies include those of the scriping language chosen.</p>
+
+ <p><strong>MIME types defined:</strong> <code>application/x-aspx</code> (ASP.NET),
+ <code>application/x-ejs</code> (Embedded Javascript), <code>application/x-jsp</code> (JavaServer Pages)</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/htmlmixed/htmlmixed.js b/codemirror_ui/lib/CodeMirror-2.3/mode/htmlmixed/htmlmixed.js
new file mode 100644
index 0000000..a6c62c9
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/htmlmixed/htmlmixed.js
@@ -0,0 +1,85 @@
+CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
+ var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
+ var jsMode = CodeMirror.getMode(config, "javascript");
+ var cssMode = CodeMirror.getMode(config, "css");
+
+ function html(stream, state) {
+ var style = htmlMode.token(stream, state.htmlState);
+ if (style == "tag" && stream.current() == ">" && state.htmlState.context) {
+ if (/^script$/i.test(state.htmlState.context.tagName)) {
+ state.token = javascript;
+ state.localState = jsMode.startState(htmlMode.indent(state.htmlState, ""));
+ state.mode = "javascript";
+ }
+ else if (/^style$/i.test(state.htmlState.context.tagName)) {
+ state.token = css;
+ state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
+ state.mode = "css";
+ }
+ }
+ return style;
+ }
+ function maybeBackup(stream, pat, style) {
+ var cur = stream.current();
+ var close = cur.search(pat);
+ if (close > -1) stream.backUp(cur.length - close);
+ return style;
+ }
+ function javascript(stream, state) {
+ if (stream.match(/^<\/\s*script\s*>/i, false)) {
+ state.token = html;
+ state.localState = null;
+ state.mode = "html";
+ return html(stream, state);
+ }
+ return maybeBackup(stream, /<\/\s*script\s*>/,
+ jsMode.token(stream, state.localState));
+ }
+ function css(stream, state) {
+ if (stream.match(/^<\/\s*style\s*>/i, false)) {
+ state.token = html;
+ state.localState = null;
+ state.mode = "html";
+ return html(stream, state);
+ }
+ return maybeBackup(stream, /<\/\s*style\s*>/,
+ cssMode.token(stream, state.localState));
+ }
+
+ return {
+ startState: function() {
+ var state = htmlMode.startState();
+ return {token: html, localState: null, mode: "html", htmlState: state};
+ },
+
+ copyState: function(state) {
+ if (state.localState)
+ var local = CodeMirror.copyState(state.token == css ? cssMode : jsMode, state.localState);
+ return {token: state.token, localState: local, mode: state.mode,
+ htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
+ },
+
+ token: function(stream, state) {
+ return state.token(stream, state);
+ },
+
+ indent: function(state, textAfter) {
+ if (state.token == html || /^\s*<\//.test(textAfter))
+ return htmlMode.indent(state.htmlState, textAfter);
+ else if (state.token == javascript)
+ return jsMode.indent(state.localState, textAfter);
+ else
+ return cssMode.indent(state.localState, textAfter);
+ },
+
+ compareStates: function(a, b) {
+ if (a.mode != b.mode) return false;
+ if (a.localState) return CodeMirror.Pass;
+ return htmlMode.compareStates(a.htmlState, b.htmlState);
+ },
+
+ electricChars: "/{}:"
+ }
+}, "xml", "javascript", "css");
+
+CodeMirror.defineMIME("text/html", "htmlmixed");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/htmlmixed/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/htmlmixed/index.html
new file mode 100644
index 0000000..63fc412
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/htmlmixed/index.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: HTML mixed mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="../xml/xml.js"></script>
+ <script src="../javascript/javascript.js"></script>
+ <script src="../css/css.js"></script>
+ <script src="htmlmixed.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: HTML mixed mode</h1>
+ <form><textarea id="code" name="code">
+<html style="color: green">
+ <!-- this is a comment -->
+ <head>
+ <title>Mixed HTML Example</title>
+ <style type="text/css">
+ h1 {font-family: comic sans; color: #f0f;}
+ div {background: yellow !important;}
+ body {
+ max-width: 50em;
+ margin: 1em 2em 1em 5em;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>Mixed HTML Example</h1>
+ <script>
+ function jsFunc(arg1, arg2) {
+ if (arg1 && arg2) document.body.innerHTML = "achoo";
+ }
+ </script>
+ </body>
+</html>
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", tabMode: "indent"});
+ </script>
+
+ <p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p>
+
+ <p><strong>MIME types defined:</strong> <code>text/html</code>
+ (redefined, only takes effect if you load this parser after the
+ XML parser).</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/javascript/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/javascript/index.html
new file mode 100644
index 0000000..c3ab91d
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/javascript/index.html
@@ -0,0 +1,77 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: JavaScript mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="javascript.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: JavaScript mode</h1>
+
+<div><textarea id="code" name="code">
+// Demo code (the actual new parser character stream implementation)
+
+function StringStream(string) {
+ this.pos = 0;
+ this.string = string;
+}
+
+StringStream.prototype = {
+ done: function() {return this.pos >= this.string.length;},
+ peek: function() {return this.string.charAt(this.pos);},
+ next: function() {
+ if (this.pos &lt; this.string.length)
+ return this.string.charAt(this.pos++);
+ },
+ eat: function(match) {
+ var ch = this.string.charAt(this.pos);
+ if (typeof match == "string") var ok = ch == match;
+ else var ok = ch &amp;&amp; match.test ? match.test(ch) : match(ch);
+ if (ok) {this.pos++; return ch;}
+ },
+ eatWhile: function(match) {
+ var start = this.pos;
+ while (this.eat(match));
+ if (this.pos > start) return this.string.slice(start, this.pos);
+ },
+ backUp: function(n) {this.pos -= n;},
+ column: function() {return this.pos;},
+ eatSpace: function() {
+ var start = this.pos;
+ while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
+ return this.pos - start;
+ },
+ match: function(pattern, consume, caseInsensitive) {
+ if (typeof pattern == "string") {
+ function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
+ if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
+ if (consume !== false) this.pos += str.length;
+ return true;
+ }
+ }
+ else {
+ var match = this.string.slice(this.pos).match(pattern);
+ if (match &amp;&amp; consume !== false) this.pos += match[0].length;
+ return match;
+ }
+ }
+};
+</textarea></div>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true
+ });
+ </script>
+
+ <p>JavaScript mode supports a single configuration
+ option, <code>json</code>, which will set the mode to expect JSON
+ data rather than a JavaScript program.</p>
+
+ <p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/javascript/javascript.js b/codemirror_ui/lib/CodeMirror-2.3/mode/javascript/javascript.js
new file mode 100644
index 0000000..65f11c5
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/javascript/javascript.js
@@ -0,0 +1,361 @@
+CodeMirror.defineMode("javascript", function(config, parserConfig) {
+ var indentUnit = config.indentUnit;
+ var jsonMode = parserConfig.json;
+
+ // Tokenizer
+
+ var keywords = function(){
+ function kw(type) {return {type: type, style: "keyword"};}
+ var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
+ var operator = kw("operator"), atom = {type: "atom", style: "atom"};
+ return {
+ "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
+ "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
+ "var": kw("var"), "const": kw("var"), "let": kw("var"),
+ "function": kw("function"), "catch": kw("catch"),
+ "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
+ "in": operator, "typeof": operator, "instanceof": operator,
+ "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
+ };
+ }();
+
+ var isOperatorChar = /[+\-*&%=<>!?|]/;
+
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ function nextUntilUnescaped(stream, end) {
+ var escaped = false, next;
+ while ((next = stream.next()) != null) {
+ if (next == end && !escaped)
+ return false;
+ escaped = !escaped && next == "\\";
+ }
+ return escaped;
+ }
+
+ // Used as scratch variables to communicate multiple values without
+ // consing up tons of objects.
+ var type, content;
+ function ret(tp, style, cont) {
+ type = tp; content = cont;
+ return style;
+ }
+
+ function jsTokenBase(stream, state) {
+ var ch = stream.next();
+ if (ch == '"' || ch == "'")
+ return chain(stream, state, jsTokenString(ch));
+ else if (/[\[\]{}\(\),;\:\.]/.test(ch))
+ return ret(ch);
+ else if (ch == "0" && stream.eat(/x/i)) {
+ stream.eatWhile(/[\da-f]/i);
+ return ret("number", "number");
+ }
+ else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
+ stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
+ return ret("number", "number");
+ }
+ else if (ch == "/") {
+ if (stream.eat("*")) {
+ return chain(stream, state, jsTokenComment);
+ }
+ else if (stream.eat("/")) {
+ stream.skipToEnd();
+ return ret("comment", "comment");
+ }
+ else if (state.reAllowed) {
+ nextUntilUnescaped(stream, "/");
+ stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
+ return ret("regexp", "string-2");
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", null, stream.current());
+ }
+ }
+ else if (ch == "#") {
+ stream.skipToEnd();
+ return ret("error", "error");
+ }
+ else if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", null, stream.current());
+ }
+ else {
+ stream.eatWhile(/[\w\$_]/);
+ var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
+ return (known && state.kwAllowed) ? ret(known.type, known.style, word) :
+ ret("variable", "variable", word);
+ }
+ }
+
+ function jsTokenString(quote) {
+ return function(stream, state) {
+ if (!nextUntilUnescaped(stream, quote))
+ state.tokenize = jsTokenBase;
+ return ret("string", "string");
+ };
+ }
+
+ function jsTokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return ret("comment", "comment");
+ }
+
+ // Parser
+
+ var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
+
+ function JSLexical(indented, column, type, align, prev, info) {
+ this.indented = indented;
+ this.column = column;
+ this.type = type;
+ this.prev = prev;
+ this.info = info;
+ if (align != null) this.align = align;
+ }
+
+ function inScope(state, varname) {
+ for (var v = state.localVars; v; v = v.next)
+ if (v.name == varname) return true;
+ }
+
+ function parseJS(state, style, type, content, stream) {
+ var cc = state.cc;
+ // Communicate our context to the combinators.
+ // (Less wasteful than consing up a hundred closures on every call.)
+ cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
+
+ if (!state.lexical.hasOwnProperty("align"))
+ state.lexical.align = true;
+
+ while(true) {
+ var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
+ if (combinator(type, content)) {
+ while(cc.length && cc[cc.length - 1].lex)
+ cc.pop()();
+ if (cx.marked) return cx.marked;
+ if (type == "variable" && inScope(state, content)) return "variable-2";
+ return style;
+ }
+ }
+ }
+
+ // Combinator utils
+
+ var cx = {state: null, column: null, marked: null, cc: null};
+ function pass() {
+ for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
+ }
+ function cont() {
+ pass.apply(null, arguments);
+ return true;
+ }
+ function register(varname) {
+ var state = cx.state;
+ if (state.context) {
+ cx.marked = "def";
+ for (var v = state.localVars; v; v = v.next)
+ if (v.name == varname) return;
+ state.localVars = {name: varname, next: state.localVars};
+ }
+ }
+
+ // Combinators
+
+ var defaultVars = {name: "this", next: {name: "arguments"}};
+ function pushcontext() {
+ if (!cx.state.context) cx.state.localVars = defaultVars;
+ cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
+ }
+ function popcontext() {
+ cx.state.localVars = cx.state.context.vars;
+ cx.state.context = cx.state.context.prev;
+ }
+ function pushlex(type, info) {
+ var result = function() {
+ var state = cx.state;
+ state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
+ };
+ result.lex = true;
+ return result;
+ }
+ function poplex() {
+ var state = cx.state;
+ if (state.lexical.prev) {
+ if (state.lexical.type == ")")
+ state.indented = state.lexical.indented;
+ state.lexical = state.lexical.prev;
+ }
+ }
+ poplex.lex = true;
+
+ function expect(wanted) {
+ return function expecting(type) {
+ if (type == wanted) return cont();
+ else if (wanted == ";") return pass();
+ else return cont(arguments.callee);
+ };
+ }
+
+ function statement(type) {
+ if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
+ if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
+ if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
+ if (type == "{") return cont(pushlex("}"), block, poplex);
+ if (type == ";") return cont();
+ if (type == "function") return cont(functiondef);
+ if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
+ poplex, statement, poplex);
+ if (type == "variable") return cont(pushlex("stat"), maybelabel);
+ if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
+ block, poplex, poplex);
+ if (type == "case") return cont(expression, expect(":"));
+ if (type == "default") return cont(expect(":"));
+ if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
+ statement, poplex, popcontext);
+ return pass(pushlex("stat"), expression, expect(";"), poplex);
+ }
+ function expression(type) {
+ if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
+ if (type == "function") return cont(functiondef);
+ if (type == "keyword c") return cont(maybeexpression);
+ if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
+ if (type == "operator") return cont(expression);
+ if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
+ if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
+ return cont();
+ }
+ function maybeexpression(type) {
+ if (type.match(/[;\}\)\],]/)) return pass();
+ return pass(expression);
+ }
+
+ function maybeoperator(type, value) {
+ if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
+ if (type == "operator" || type == ":") return cont(expression);
+ if (type == ";") return;
+ if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
+ if (type == ".") return cont(property, maybeoperator);
+ if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
+ }
+ function maybelabel(type) {
+ if (type == ":") return cont(poplex, statement);
+ return pass(maybeoperator, expect(";"), poplex);
+ }
+ function property(type) {
+ if (type == "variable") {cx.marked = "property"; return cont();}
+ }
+ function objprop(type) {
+ if (type == "variable") cx.marked = "property";
+ if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
+ }
+ function commasep(what, end) {
+ function proceed(type) {
+ if (type == ",") return cont(what, proceed);
+ if (type == end) return cont();
+ return cont(expect(end));
+ }
+ return function commaSeparated(type) {
+ if (type == end) return cont();
+ else return pass(what, proceed);
+ };
+ }
+ function block(type) {
+ if (type == "}") return cont();
+ return pass(statement, block);
+ }
+ function vardef1(type, value) {
+ if (type == "variable"){register(value); return cont(vardef2);}
+ return cont();
+ }
+ function vardef2(type, value) {
+ if (value == "=") return cont(expression, vardef2);
+ if (type == ",") return cont(vardef1);
+ }
+ function forspec1(type) {
+ if (type == "var") return cont(vardef1, forspec2);
+ if (type == ";") return pass(forspec2);
+ if (type == "variable") return cont(formaybein);
+ return pass(forspec2);
+ }
+ function formaybein(type, value) {
+ if (value == "in") return cont(expression);
+ return cont(maybeoperator, forspec2);
+ }
+ function forspec2(type, value) {
+ if (type == ";") return cont(forspec3);
+ if (value == "in") return cont(expression);
+ return cont(expression, expect(";"), forspec3);
+ }
+ function forspec3(type) {
+ if (type != ")") cont(expression);
+ }
+ function functiondef(type, value) {
+ if (type == "variable") {register(value); return cont(functiondef);}
+ if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
+ }
+ function funarg(type, value) {
+ if (type == "variable") {register(value); return cont();}
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: jsTokenBase,
+ reAllowed: true,
+ kwAllowed: true,
+ cc: [],
+ lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
+ localVars: parserConfig.localVars,
+ context: parserConfig.localVars && {vars: parserConfig.localVars},
+ indented: 0
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.sol()) {
+ if (!state.lexical.hasOwnProperty("align"))
+ state.lexical.align = false;
+ state.indented = stream.indentation();
+ }
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ if (type == "comment") return style;
+ state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/));
+ state.kwAllowed = type != '.';
+ return parseJS(state, style, type, content, stream);
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != jsTokenBase) return 0;
+ var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
+ if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
+ var type = lexical.type, closing = firstChar == type;
+ if (type == "vardef") return lexical.indented + 4;
+ else if (type == "form" && firstChar == "{") return lexical.indented;
+ else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
+ else if (lexical.info == "switch" && !closing)
+ return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
+ else if (lexical.align) return lexical.column + (closing ? 0 : 1);
+ else return lexical.indented + (closing ? 0 : indentUnit);
+ },
+
+ electricChars: ":{}"
+ };
+});
+
+CodeMirror.defineMIME("text/javascript", "javascript");
+CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/jinja2/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/jinja2/index.html
new file mode 100644
index 0000000..021a282
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/jinja2/index.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Jinja2 mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="jinja2.js"></script>
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Jinja2 mode</h1>
+ <form><textarea id="code" name="code">
+&lt;html style="color: green"&gt;
+ &lt;!-- this is a comment --&gt;
+ &lt;head&gt;
+ &lt;title&gt;Jinja2 Example&lt;/title&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;ul&gt;
+ {# this is a comment #}
+ {%- for item in li -%}
+ &lt;li&gt;
+ {{ item.label }}
+ &lt;/li&gt;
+ {% endfor -%}
+ &lt;/ul&gt;
+ &lt;/body&gt;
+&lt;/html&gt;
+</textarea></form>
+ <script>
+ var editor =
+ CodeMirror.fromTextArea(document.getElementById("code"), {mode:
+ {name: "jinja2", htmlMode: true}});
+ </script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/jinja2/jinja2.js b/codemirror_ui/lib/CodeMirror-2.3/mode/jinja2/jinja2.js
new file mode 100644
index 0000000..75419d8
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/jinja2/jinja2.js
@@ -0,0 +1,42 @@
+CodeMirror.defineMode("jinja2", function(config, parserConf) {
+ var keywords = ["block", "endblock", "for", "endfor", "in", "true", "false",
+ "loop", "none", "self", "super", "if", "as", "not", "and",
+ "else", "import", "with", "without", "context"];
+ keywords = new RegExp("^((" + keywords.join(")|(") + "))\\b");
+
+ function tokenBase (stream, state) {
+ var ch = stream.next();
+ if (ch == "{") {
+ if (ch = stream.eat(/\{|%|#/)) {
+ stream.eat("-");
+ state.tokenize = inTag(ch);
+ return "tag";
+ }
+ }
+ }
+ function inTag (close) {
+ if (close == "{") {
+ close = "}";
+ }
+ return function (stream, state) {
+ var ch = stream.next();
+ if ((ch == close || (ch == "-" && stream.eat(close)))
+ && stream.eat("}")) {
+ state.tokenize = tokenBase;
+ return "tag";
+ }
+ if (stream.match(keywords)) {
+ return "keyword";
+ }
+ return close == "#" ? "comment" : "string";
+ };
+ }
+ return {
+ startState: function () {
+ return {tokenize: tokenBase};
+ },
+ token: function (stream, state) {
+ return state.tokenize(stream, state);
+ }
+ };
+});
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/less/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/less/index.html
new file mode 100644
index 0000000..cad8e4b
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/less/index.html
@@ -0,0 +1,618 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: LESS mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="less.js"></script>
+ <style>.CodeMirror {background: #f8f8f8; border: 1px solid #ddd; font-size:12px} .CodeMirror-scroll {height: 400px}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <link rel="stylesheet" href="../../theme/lesser-dark.css">
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ </head>
+ <body>
+ <h1>CodeMirror: LESS mode</h1>
+ <form><textarea id="code" name="code">/* Some LESS code */
+
+button {
+ width: 32px;
+ height: 32px;
+ border: 0;
+ margin: 4px;
+ cursor: pointer;
+}
+button.icon-plus { background: url(http://dahlström.net/tmp/sharp-icons/svg-icon-target.svg#plus) no-repeat; }
+button.icon-chart { background: url(http://dahlström.net/tmp/sharp-icons/svg-icon-target.svg#chart) no-repeat; }
+
+button:hover { background-color: #999; }
+button:active { background-color: #666; }
+
+@test_a: #eeeQQQ;//this is not a valid hex value and thus parsed as an element id
+@test_b: #eeeFFF //this is a valid hex value but the declaration doesn't end with a semicolon and thus parsed as an element id
+
+#eee aaa .box
+{
+ #test bbb {
+ width: 500px;
+ height: 250px;
+ background-image: url(dir/output/sheep.png), url( betweengrassandsky.png );
+ background-position: center bottom, left top;
+ background-repeat: no-repeat;
+ }
+}
+
+@base: #f938ab;
+
+.box-shadow(@style, @c) when (iscolor(@c)) {
+ box-shadow: @style @c;
+ -webkit-box-shadow: @style @c;
+ -moz-box-shadow: @style @c;
+}
+.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
+ .box-shadow(@style, rgba(0, 0, 0, @alpha));
+}
+
+@color: #4D926F;
+
+#header {
+ color: @color;
+ color: #000000;
+}
+h2 {
+ color: @color;
+}
+
+.rounded-corners (@radius: 5px) {
+ border-radius: @radius;
+ -webkit-border-radius: @radius;
+ -moz-border-radius: @radius;
+}
+
+#header {
+ .rounded-corners;
+}
+#footer {
+ .rounded-corners(10px);
+}
+
+.box-shadow (@x: 0, @y: 0, @blur: 1px, @alpha) {
+ @val: @x @y @blur rgba(0, 0, 0, @alpha);
+
+ box-shadow: @val;
+ -webkit-box-shadow: @val;
+ -moz-box-shadow: @val;
+}
+.box { @base: #f938ab;
+ color: saturate(@base, 5%);
+ border-color: lighten(@base, 30%);
+ div { .box-shadow(0, 0, 5px, 0.4) }
+}
+
+@import url("something.css");
+
+@light-blue: hsl(190, 50%, 65%);
+@light-yellow: desaturate(#fefec8, 10%);
+@dark-yellow: desaturate(darken(@light-yellow, 10%), 40%);
+@darkest: hsl(20, 0%, 15%);
+@dark: hsl(190, 20%, 30%);
+@medium: hsl(10, 60%, 30%);
+@light: hsl(90, 40%, 20%);
+@lightest: hsl(90, 20%, 90%);
+@highlight: hsl(80, 50%, 90%);
+@blue: hsl(210, 60%, 20%);
+@alpha-blue: hsla(210, 60%, 40%, 0.5);
+
+.box-shadow (@x, @y, @blur, @alpha) {
+ @value: @x @y @blur rgba(0, 0, 0, @alpha);
+ box-shadow: @value;
+ -moz-box-shadow: @value;
+ -webkit-box-shadow: @value;
+}
+.border-radius (@radius) {
+ border-radius: @radius;
+ -moz-border-radius: @radius;
+ -webkit-border-radius: @radius;
+}
+
+.border-radius (@radius, bottom) {
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+ -moz-border-top-right-radius: 0;
+ -moz-border-top-left-radius: 0;
+ -webkit-border-top-left-radius: 0;
+ -webkit-border-top-right-radius: 0;
+}
+.border-radius (@radius, right) {
+ border-bottom-left-radius: 0;
+ border-top-left-radius: 0;
+ -moz-border-bottom-left-radius: 0;
+ -moz-border-top-left-radius: 0;
+ -webkit-border-bottom-left-radius: 0;
+ -webkit-border-top-left-radius: 0;
+}
+.box-shadow-inset (@x, @y, @blur, @color) {
+ box-shadow: @x @y @blur @color inset;
+ -moz-box-shadow: @x @y @blur @color inset;
+ -webkit-box-shadow: @x @y @blur @color inset;
+}
+.code () {
+ font-family: 'Bitstream Vera Sans Mono',
+ 'DejaVu Sans Mono',
+ 'Monaco',
+ Courier,
+ monospace !important;
+}
+.wrap () {
+ text-wrap: wrap;
+ white-space: pre-wrap; /* css-3 */
+ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+html { margin: 0 }
+body {
+ background-color: @darkest;
+ margin: 0 auto;
+ font-family: Arial, sans-serif;
+ font-size: 100%;
+ overflow-x: hidden;
+}
+nav, header, footer, section, article {
+ display: block;
+}
+a {
+ color: #b83000;
+}
+h1 a {
+ color: black;
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+h1, h2, h3, h4 {
+ margin: 0;
+ font-weight: normal;
+}
+ul, li {
+ list-style-type: none;
+}
+code { .code; }
+code {
+ .string, .regexp { color: @dark }
+ .keyword { font-weight: bold }
+ .comment { color: rgba(0, 0, 0, 0.5) }
+ .number { color: @blue }
+ .class, .special { color: rgba(0, 50, 100, 0.8) }
+}
+pre {
+ padding: 0 30px;
+ .wrap;
+}
+blockquote {
+ font-style: italic;
+}
+body > footer {
+ text-align: left;
+ margin-left: 10px;
+ font-style: italic;
+ font-size: 18px;
+ color: #888;
+}
+
+#logo {
+ margin-top: 30px;
+ margin-bottom: 30px;
+ display: block;
+ width: 199px;
+ height: 81px;
+ background: url(/images/logo.png) no-repeat;
+}
+nav {
+ margin-left: 15px;
+}
+nav a, #dropdown li {
+ display: inline-block;
+ color: white;
+ line-height: 42px;
+ margin: 0;
+ padding: 0px 15px;
+ text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.5);
+ text-decoration: none;
+ border: 2px solid transparent;
+ border-width: 0 2px;
+ &:hover {
+ .dark-red;
+ text-decoration: none;
+ }
+}
+.dark-red {
+ @red: @medium;
+ border: 2px solid darken(@red, 25%);
+ border-left-color: darken(@red, 15%);
+ border-right-color: darken(@red, 15%);
+ border-bottom: 0;
+ border-top: 0;
+ background-color: darken(@red, 10%);
+}
+
+.content {
+ margin: 0 auto;
+ width: 980px;
+}
+
+#menu {
+ position: absolute;
+ width: 100%;
+ z-index: 3;
+ clear: both;
+ display: block;
+ background-color: @blue;
+ height: 42px;
+ border-top: 2px solid lighten(@alpha-blue, 20%);
+ border-bottom: 2px solid darken(@alpha-blue, 25%);
+ .box-shadow(0, 1px, 8px, 0.6);
+ -moz-box-shadow: 0 0 0 #000; // Because firefox sucks.
+
+ &.docked {
+ background-color: hsla(210, 60%, 40%, 0.4);
+ }
+ &:hover {
+ background-color: @blue;
+ }
+
+ #dropdown {
+ margin: 0 0 0 117px;
+ padding: 0;
+ padding-top: 5px;
+ display: none;
+ width: 190px;
+ border-top: 2px solid @medium;
+ color: @highlight;
+ border: 2px solid darken(@medium, 25%);
+ border-left-color: darken(@medium, 15%);
+ border-right-color: darken(@medium, 15%);
+ border-top-width: 0;
+ background-color: darken(@medium, 10%);
+ ul {
+ padding: 0px;
+ }
+ li {
+ font-size: 14px;
+ display: block;
+ text-align: left;
+ padding: 0;
+ border: 0;
+ a {
+ display: block;
+ padding: 0px 15px;
+ text-decoration: none;
+ color: white;
+ &:hover {
+ background-color: darken(@medium, 15%);
+ text-decoration: none;
+ }
+ }
+ }
+ .border-radius(5px, bottom);
+ .box-shadow(0, 6px, 8px, 0.5);
+ }
+}
+
+#main {
+ margin: 0 auto;
+ width: 100%;
+ background-color: @light-blue;
+ border-top: 8px solid darken(@light-blue, 5%);
+
+ #intro {
+ background-color: lighten(@light-blue, 25%);
+ float: left;
+ margin-top: -8px;
+ margin-right: 5px;
+
+ height: 380px;
+ position: relative;
+ z-index: 2;
+ font-family: 'Droid Serif', 'Georgia';
+ width: 395px;
+ padding: 45px 20px 23px 30px;
+ border: 2px dashed darken(@light-blue, 10%);
+ .box-shadow(1px, 0px, 6px, 0.5);
+ border-bottom: 0;
+ border-top: 0;
+ #download { color: transparent; border: 0; float: left; display: inline-block; margin: 15px 0 15px -5px; }
+ #download img { display: inline-block}
+ #download-info {
+ code {
+ font-size: 13px;
+ }
+ color: @blue + #333; display: inline; float: left; margin: 36px 0 0 15px }
+ }
+ h2 {
+ span {
+ color: @medium;
+ }
+ color: @blue;
+ margin: 20px 0;
+ font-size: 24px;
+ line-height: 1.2em;
+ }
+ h3 {
+ color: @blue;
+ line-height: 1.4em;
+ margin: 30px 0 15px 0;
+ font-size: 1em;
+ text-shadow: 0px 0px 0px @lightest;
+ span { color: @medium }
+ }
+ #example {
+ p {
+ font-size: 18px;
+ color: @blue;
+ font-weight: bold;
+ text-shadow: 0px 1px 1px @lightest;
+ }
+ pre {
+ margin: 0;
+ text-shadow: 0 -1px 1px @darkest;
+ margin-top: 20px;
+ background-color: desaturate(@darkest, 8%);
+ border: 0;
+ width: 450px;
+ color: lighten(@lightest, 2%);
+ background-repeat: repeat;
+ padding: 15px;
+ border: 1px dashed @lightest;
+ line-height: 15px;
+ .box-shadow(0, 0px, 15px, 0.5);
+ .code;
+ .border-radius(2px);
+ code .attribute { color: hsl(40, 50%, 70%) }
+ code .variable { color: hsl(120, 10%, 50%) }
+ code .element { color: hsl(170, 20%, 50%) }
+
+ code .string, .regexp { color: hsl(75, 50%, 65%) }
+ code .class { color: hsl(40, 40%, 60%); font-weight: normal }
+ code .id { color: hsl(50, 40%, 60%); font-weight: normal }
+ code .comment { color: rgba(255, 255, 255, 0.2) }
+ code .number, .color { color: hsl(10, 40%, 50%) }
+ code .class, code .mixin, .special { color: hsl(190, 20%, 50%) }
+ #time { color: #aaa }
+ }
+ float: right;
+ font-size: 12px;
+ margin: 0;
+ margin-top: 15px;
+ padding: 0;
+ width: 500px;
+ }
+}
+
+
+.page {
+ .content {
+ width: 870px;
+ padding: 45px;
+ }
+ margin: 0 auto;
+ font-family: 'Georgia', serif;
+ font-size: 18px;
+ line-height: 26px;
+ padding: 0 60px;
+ code {
+ font-size: 16px;
+ }
+ pre {
+ border-width: 1px;
+ border-style: dashed;
+ padding: 15px;
+ margin: 15px 0;
+ }
+ h1 {
+ text-align: left;
+ font-size: 40px;
+ margin-top: 15px;
+ margin-bottom: 35px;
+ }
+ p + h1 { margin-top: 60px }
+ h2, h3 {
+ margin: 30px 0 15px 0;
+ }
+ p + h2, pre + h2, code + h2 {
+ border-top: 6px solid rgba(255, 255, 255, 0.1);
+ padding-top: 30px;
+ }
+ h3 {
+ margin: 15px 0;
+ }
+}
+
+
+#docs {
+ @bg: lighten(@light-blue, 5%);
+ border-top: 2px solid lighten(@bg, 5%);
+ color: @blue;
+ background-color: @light-blue;
+ .box-shadow(0, -2px, 5px, 0.2);
+
+ h1 {
+ font-family: 'Droid Serif', 'Georgia', serif;
+ padding-top: 30px;
+ padding-left: 45px;
+ font-size: 44px;
+ text-align: left;
+ margin: 30px 0 !important;
+ text-shadow: 0px 1px 1px @lightest;
+ font-weight: bold;
+ }
+ .content {
+ clear: both;
+ border-color: transparent;
+ background-color: lighten(@light-blue, 25%);
+ .box-shadow(0, 5px, 5px, 0.4);
+ }
+ pre {
+ @background: lighten(@bg, 30%);
+ color: lighten(@blue, 10%);
+ background-color: @background;
+ border-color: lighten(@light-blue, 25%);
+ border-width: 2px;
+ code .attribute { color: hsl(40, 50%, 30%) }
+ code .variable { color: hsl(120, 10%, 30%) }
+ code .element { color: hsl(170, 20%, 30%) }
+
+ code .string, .regexp { color: hsl(75, 50%, 35%) }
+ code .class { color: hsl(40, 40%, 30%); font-weight: normal }
+ code .id { color: hsl(50, 40%, 30%); font-weight: normal }
+ code .comment { color: rgba(0, 0, 0, 0.4) }
+ code .number, .color { color: hsl(10, 40%, 30%) }
+ code .class, code .mixin, .special { color: hsl(190, 20%, 30%) }
+ }
+ pre code { font-size: 15px }
+ p + h2, pre + h2, code + h2 { border-top-color: rgba(0, 0, 0, 0.1) }
+}
+
+td {
+ padding-right: 30px;
+}
+#synopsis {
+ .box-shadow(0, 5px, 5px, 0.2);
+}
+#synopsis, #about {
+ h2 {
+ font-size: 30px;
+ padding: 10px 0;
+ }
+ h1 + h2 {
+ margin-top: 15px;
+ }
+ h3 { font-size: 22px }
+
+ .code-example {
+ border-spacing: 0;
+ border-width: 1px;
+ border-style: dashed;
+ padding: 0;
+ pre { border: 0; margin: 0 }
+ td {
+ border: 0;
+ margin: 0;
+ background-color: desaturate(darken(@darkest, 5%), 20%);
+ vertical-align: top;
+ padding: 0;
+ }
+ tr { padding: 0 }
+ }
+ .css-output {
+ td {
+ border-left: 0;
+ }
+ }
+ .less-example {
+ //border-right: 1px dotted rgba(255, 255, 255, 0.5) !important;
+ }
+ .css-output, .less-example {
+ width: 390px;
+ }
+ pre {
+ padding: 20px;
+ line-height: 20px;
+ font-size: 14px;
+ }
+}
+#about, #synopsis, #guide {
+ a {
+ text-decoration: none;
+ color: @light-yellow;
+ border-bottom: 1px dashed rgba(255, 255, 255, 0.2);
+ &:hover {
+ text-decoration: none;
+ border-bottom: 1px dashed @light-yellow;
+ }
+ }
+ @bg: desaturate(darken(@darkest, 5%), 20%);
+ text-shadow: 0 -1px 1px lighten(@bg, 5%);
+ color: @highlight;
+ background-color: @bg;
+ .content {
+ background-color: desaturate(@darkest, 20%);
+ clear: both;
+ .box-shadow(0, 5px, 5px, 0.4);
+ }
+ h1, h2, h3 {
+ color: @dark-yellow;
+ }
+ pre {
+ code .attribute { color: hsl(40, 50%, 70%) }
+ code .variable { color: hsl(120, 10%, 50%) }
+ code .element { color: hsl(170, 20%, 50%) }
+
+ code .string, .regexp { color: hsl(75, 50%, 65%) }
+ code .class { color: hsl(40, 40%, 60%); font-weight: normal }
+ code .id { color: hsl(50, 40%, 60%); font-weight: normal }
+ code .comment { color: rgba(255, 255, 255, 0.2) }
+ code .number, .color { color: hsl(10, 40%, 50%) }
+ code .class, code .mixin, .special { color: hsl(190, 20%, 50%) }
+ background-color: @bg;
+ border-color: darken(@light-yellow, 5%);
+ }
+ code {
+ color: darken(@dark-yellow, 5%);
+ .string, .regexp { color: desaturate(@light-blue, 15%) }
+ .keyword { color: hsl(40, 40%, 60%); font-weight: normal }
+ .comment { color: rgba(255, 255, 255, 0.2) }
+ .number { color: lighten(@blue, 10%) }
+ .class, .special { color: hsl(190, 20%, 50%) }
+ }
+}
+#guide {
+ background-color: @darkest;
+ .content {
+ background-color: transparent;
+ }
+
+}
+
+#about {
+ background-color: @darkest !important;
+ .content {
+ background-color: desaturate(lighten(@darkest, 3%), 5%);
+ }
+}
+#synopsis {
+ background-color: desaturate(lighten(@darkest, 3%), 5%) !important;
+ .content {
+ background-color: desaturate(lighten(@darkest, 3%), 5%);
+ }
+ pre {}
+}
+#synopsis, #guide {
+ .content {
+ .box-shadow(0, 0px, 0px, 0.0);
+ }
+}
+#about footer {
+ margin-top: 30px;
+ padding-top: 30px;
+ border-top: 6px solid rgba(0, 0, 0, 0.1);
+ text-align: center;
+ font-size: 16px;
+ color: rgba(255, 255, 255, 0.35);
+ #copy { font-size: 12px }
+ text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.02);
+}
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ theme: "lesser-dark",
+ lineNumbers : true,
+ matchBrackets : true
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-less</code>, <code>text/css</code> (if not previously defined).</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/less/less.js b/codemirror_ui/lib/CodeMirror-2.3/mode/less/less.js
new file mode 100644
index 0000000..5116389
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/less/less.js
@@ -0,0 +1,232 @@
+/*
+LESS mode - http://www.lesscss.org/
+Ported to CodeMirror by Peter Kroon
+*/
+
+CodeMirror.defineMode("less", function(config) {
+ var indentUnit = config.indentUnit, type;
+ function ret(style, tp) {type = tp; return style;}
+ //html5 tags
+ var tags = ["a","abbr","acronym","address","applet","area","article","aside","audio","b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","legend","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr"];
+
+ function inTagsArray(val){
+ for(var i=0; i<tags.length; i++){
+ if(val === tags[i]){
+ return true;
+ }
+ }
+ }
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+
+ if (ch == "@") {stream.eatWhile(/[\w\-]/); return ret("meta", stream.current());}
+ else if (ch == "/" && stream.eat("*")) {
+ state.tokenize = tokenCComment;
+ return tokenCComment(stream, state);
+ }
+ else if (ch == "<" && stream.eat("!")) {
+ state.tokenize = tokenSGMLComment;
+ return tokenSGMLComment(stream, state);
+ }
+ else if (ch == "=") ret(null, "compare");
+ else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
+ else if (ch == "\"" || ch == "'") {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ }
+ else if (ch == "/") { // lesscss e.g.: .png will not be parsed as a class
+ if(stream.eat("/")){
+ state.tokenize = tokenSComment
+ return tokenSComment(stream, state);
+ }else{
+ stream.eatWhile(/[\a-zA-Z0-9\-_.\s]/);
+ if(/\/|\)|#/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == ")")))return ret("string", "string");//let url(/images/logo.png) without quotes return as string
+ return ret("number", "unit");
+ }
+ }
+ else if (ch == "!") {
+ stream.match(/^\s*\w*/);
+ return ret("keyword", "important");
+ }
+ else if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w.%]/);
+ return ret("number", "unit");
+ }
+ else if (/[,+<>*\/]/.test(ch)) {//removed . dot character original was [,.+>*\/]
+ return ret(null, "select-op");
+ }
+ else if (/[;{}:\[\]()]/.test(ch)) { //added () char for lesscss original was [;{}:\[\]]
+ if(ch == ":"){
+ stream.eatWhile(/[active|hover|link|visited]/);
+ if( stream.current().match(/active|hover|link|visited/)){
+ return ret("tag", "tag");
+ }else{
+ return ret(null, ch);
+ }
+ }else{
+ return ret(null, ch);
+ }
+ }
+ else if (ch == ".") { // lesscss
+ stream.eatWhile(/[\a-zA-Z0-9\-_]/);
+ return ret("tag", "tag");
+ }
+ else if (ch == "#") { // lesscss
+ //we don't eat white-space, we want the hex color and or id only
+ stream.eatWhile(/[A-Za-z0-9]/);
+ //check if there is a proper hex color length e.g. #eee || #eeeEEE
+ if(stream.current().length ===4 || stream.current().length ===7){
+ if(stream.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,false) != null){//is there a valid hex color value present in the current stream
+ //when not a valid hex value, parse as id
+ if(stream.current().substring(1) != stream.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,false))return ret("atom", "tag");
+ //eat white-space
+ stream.eatSpace();
+ //when hex value declaration doesn't end with [;,] but is does with a slash/cc comment treat it as an id, just like the other hex values that don't end with[;,]
+ if( /[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/.test(stream.peek()) )return ret("atom", "tag");
+ //#time { color: #aaa }
+ else if(stream.peek() == "}" )return ret("number", "unit");
+ //we have a valid hex color value, parse as id whenever an element/class is defined after the hex(id) value e.g. #eee aaa || #eee .aaa
+ else if( /[a-zA-Z\\]/.test(stream.peek()) )return ret("atom", "tag");
+ //when a hex value is on the end of a line, parse as id
+ else if(stream.eol())return ret("atom", "tag");
+ //default
+ else return ret("number", "unit");
+ }else{//when not a valid hexvalue in the current stream e.g. #footer
+ stream.eatWhile(/[\w\\\-]/);
+ return ret("atom", "tag");
+ }
+ }else{
+ stream.eatWhile(/[\w\\\-]/);
+ return ret("atom", "tag");
+ }
+ }
+ else if (ch == "&") {
+ stream.eatWhile(/[\w\-]/);
+ return ret(null, ch);
+ }
+ else {
+ stream.eatWhile(/[\w\\\-_%.{]/);
+ if(stream.current().match(/http|https/) != null){
+ stream.eatWhile(/[\w\\\-_%.{:\/]/);
+ return ret("string", "string");
+ }else if(stream.peek() == "<" || stream.peek() == ">"){
+ return ret("tag", "tag");
+ }else if( stream.peek().match(/\(/) != null ){// lessc
+ return ret(null, ch);
+ }else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png)
+ return ret("string", "string");
+ }else if( stream.current().match(/\-\d|\-.\d/) ){ // lesscss match e.g.: -5px -0.4 etc... only colorize the minus sign
+ //stream.backUp(stream.current().length-1); //commment out these 2 comment if you want the minus sign to be parsed as null -500px
+ //return ret(null, ch);
+ return ret("number", "unit");
+ }else if( inTagsArray(stream.current()) ){ // lesscss match html tags
+ return ret("tag", "tag");
+ }else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){
+ if(stream.current().substring(stream.current().length-1,stream.current().length) == "{"){
+ stream.backUp(1);
+ return ret("tag", "tag");
+ }//end if
+ if( (stream.eatSpace() && stream.peek().match(/[{<>.a-zA-Z]/) != null) || stream.eol() )return ret("tag", "tag");//e.g. button.icon-plus
+ return ret("string", "string");//let url(/images/logo.png) without quotes return as string
+ }else if( stream.eol() ){
+ if(stream.current().substring(stream.current().length-1,stream.current().length) == "{")stream.backUp(1);
+ return ret("tag", "tag");
+ }else{
+ return ret("variable", "variable");
+ }
+ }
+
+ }
+
+ function tokenSComment(stream, state) {// SComment = Slash comment
+ stream.skipToEnd();
+ state.tokenize = tokenBase;
+ return ret("comment", "comment");
+ }
+
+ function tokenCComment(stream, state) {
+ var maybeEnd = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (maybeEnd && ch == "/") {
+ state.tokenize = tokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return ret("comment", "comment");
+ }
+
+ function tokenSGMLComment(stream, state) {
+ var dashes = 0, ch;
+ while ((ch = stream.next()) != null) {
+ if (dashes >= 2 && ch == ">") {
+ state.tokenize = tokenBase;
+ break;
+ }
+ dashes = (ch == "-") ? dashes + 1 : 0;
+ }
+ return ret("comment", "comment");
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == quote && !escaped)
+ break;
+ escaped = !escaped && ch == "\\";
+ }
+ if (!escaped) state.tokenize = tokenBase;
+ return ret("string", "string");
+ };
+ }
+
+ return {
+ startState: function(base) {
+ return {tokenize: tokenBase,
+ baseIndent: base || 0,
+ stack: []};
+ },
+
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+
+ var context = state.stack[state.stack.length-1];
+ if (type == "hash" && context == "rule") style = "atom";
+ else if (style == "variable") {
+ if (context == "rule") style = null; //"tag"
+ else if (!context || context == "@media{"){
+ style = stream.current() == "when" ? "variable" :
+ stream.string.match(/#/g) != undefined ? null :
+ /[\s,|\s\)]/.test(stream.peek()) ? "tag" : null;
+ }
+ }
+
+ if (context == "rule" && /^[\{\};]$/.test(type))
+ state.stack.pop();
+ if (type == "{") {
+ if (context == "@media") state.stack[state.stack.length-1] = "@media{";
+ else state.stack.push("{");
+ }
+ else if (type == "}") state.stack.pop();
+ else if (type == "@media") state.stack.push("@media");
+ else if (context == "{" && type != "comment") state.stack.push("rule");
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ var n = state.stack.length;
+ if (/^\}/.test(textAfter))
+ n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
+ return state.baseIndent + n * indentUnit;
+ },
+
+ electricChars: "}"
+ };
+});
+
+CodeMirror.defineMIME("text/x-less", "less");
+if (!CodeMirror.mimeModes.hasOwnProperty("text/css"))
+ CodeMirror.defineMIME("text/css", "less");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/lua/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/lua/index.html
new file mode 100644
index 0000000..600ddb0
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/lua/index.html
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Lua mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="lua.js"></script>
+ <link rel="stylesheet" href="../../theme/neat.css">
+ <style>.CodeMirror {border: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Lua mode</h1>
+ <form><textarea id="code" name="code">
+--[[
+example useless code to show lua syntax highlighting
+this is multiline comment
+]]
+
+function blahblahblah(x)
+
+ local table = {
+ "asd" = 123,
+ "x" = 0.34,
+ }
+ if x ~= 3 then
+ print( x )
+ elseif x == "string"
+ my_custom_function( 0x34 )
+ else
+ unknown_function( "some string" )
+ end
+
+ --single line comment
+
+end
+
+function blablabla3()
+
+ for k,v in ipairs( table ) do
+ --abcde..
+ y=[=[
+ x=[[
+ x is a multi line string
+ ]]
+ but its definition is iside a highest level string!
+ ]=]
+ print(" \"\" ")
+
+ s = math.sin( x )
+ end
+
+end
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ tabMode: "indent",
+ matchBrackets: true,
+ theme: "neat"
+ });
+ </script>
+
+ <p>Loosely based on Franciszek
+ Wawrzak's <a href="http://codemirror.net/1/contrib/lua">CodeMirror
+ 1 mode</a>. One configuration parameter is
+ supported, <code>specials</code>, to which you can provide an
+ array of strings to have those identifiers highlighted with
+ the <code>lua-special</code> style.</p>
+ <p><strong>MIME types defined:</strong> <code>text/x-lua</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/lua/lua.js b/codemirror_ui/lib/CodeMirror-2.3/mode/lua/lua.js
new file mode 100644
index 0000000..60e84a9
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/lua/lua.js
@@ -0,0 +1,140 @@
+// LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's
+// CodeMirror 1 mode.
+// highlights keywords, strings, comments (no leveling supported! ("[==[")), tokens, basic indenting
+
+CodeMirror.defineMode("lua", function(config, parserConfig) {
+ var indentUnit = config.indentUnit;
+
+ function prefixRE(words) {
+ return new RegExp("^(?:" + words.join("|") + ")", "i");
+ }
+ function wordRE(words) {
+ return new RegExp("^(?:" + words.join("|") + ")$", "i");
+ }
+ var specials = wordRE(parserConfig.specials || []);
+
+ // long list of standard functions from lua manual
+ var builtins = wordRE([
+ "_G","_VERSION","assert","collectgarbage","dofile","error","getfenv","getmetatable","ipairs","load",
+ "loadfile","loadstring","module","next","pairs","pcall","print","rawequal","rawget","rawset","require",
+ "select","setfenv","setmetatable","tonumber","tostring","type","unpack","xpcall",
+
+ "coroutine.create","coroutine.resume","coroutine.running","coroutine.status","coroutine.wrap","coroutine.yield",
+
+ "debug.debug","debug.getfenv","debug.gethook","debug.getinfo","debug.getlocal","debug.getmetatable",
+ "debug.getregistry","debug.getupvalue","debug.setfenv","debug.sethook","debug.setlocal","debug.setmetatable",
+ "debug.setupvalue","debug.traceback",
+
+ "close","flush","lines","read","seek","setvbuf","write",
+
+ "io.close","io.flush","io.input","io.lines","io.open","io.output","io.popen","io.read","io.stderr","io.stdin",
+ "io.stdout","io.tmpfile","io.type","io.write",
+
+ "math.abs","math.acos","math.asin","math.atan","math.atan2","math.ceil","math.cos","math.cosh","math.deg",
+ "math.exp","math.floor","math.fmod","math.frexp","math.huge","math.ldexp","math.log","math.log10","math.max",
+ "math.min","math.modf","math.pi","math.pow","math.rad","math.random","math.randomseed","math.sin","math.sinh",
+ "math.sqrt","math.tan","math.tanh",
+
+ "os.clock","os.date","os.difftime","os.execute","os.exit","os.getenv","os.remove","os.rename","os.setlocale",
+ "os.time","os.tmpname",
+
+ "package.cpath","package.loaded","package.loaders","package.loadlib","package.path","package.preload",
+ "package.seeall",
+
+ "string.byte","string.char","string.dump","string.find","string.format","string.gmatch","string.gsub",
+ "string.len","string.lower","string.match","string.rep","string.reverse","string.sub","string.upper",
+
+ "table.concat","table.insert","table.maxn","table.remove","table.sort"
+ ]);
+ var keywords = wordRE(["and","break","elseif","false","nil","not","or","return",
+ "true","function", "end", "if", "then", "else", "do",
+ "while", "repeat", "until", "for", "in", "local" ]);
+
+ var indentTokens = wordRE(["function", "if","repeat","do", "\\(", "{"]);
+ var dedentTokens = wordRE(["end", "until", "\\)", "}"]);
+ var dedentPartial = prefixRE(["end", "until", "\\)", "}", "else", "elseif"]);
+
+ function readBracket(stream) {
+ var level = 0;
+ while (stream.eat("=")) ++level;
+ stream.eat("[");
+ return level;
+ }
+
+ function normal(stream, state) {
+ var ch = stream.next();
+ if (ch == "-" && stream.eat("-")) {
+ if (stream.eat("["))
+ return (state.cur = bracketed(readBracket(stream), "comment"))(stream, state);
+ stream.skipToEnd();
+ return "comment";
+ }
+ if (ch == "\"" || ch == "'")
+ return (state.cur = string(ch))(stream, state);
+ if (ch == "[" && /[\[=]/.test(stream.peek()))
+ return (state.cur = bracketed(readBracket(stream), "string"))(stream, state);
+ if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w.%]/);
+ return "number";
+ }
+ if (/[\w_]/.test(ch)) {
+ stream.eatWhile(/[\w\\\-_.]/);
+ return "variable";
+ }
+ return null;
+ }
+
+ function bracketed(level, style) {
+ return function(stream, state) {
+ var curlev = null, ch;
+ while ((ch = stream.next()) != null) {
+ if (curlev == null) {if (ch == "]") curlev = 0;}
+ else if (ch == "=") ++curlev;
+ else if (ch == "]" && curlev == level) { state.cur = normal; break; }
+ else curlev = null;
+ }
+ return style;
+ };
+ }
+
+ function string(quote) {
+ return function(stream, state) {
+ var escaped = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == quote && !escaped) break;
+ escaped = !escaped && ch == "\\";
+ }
+ if (!escaped) state.cur = normal;
+ return "string";
+ };
+ }
+
+ return {
+ startState: function(basecol) {
+ return {basecol: basecol || 0, indentDepth: 0, cur: normal};
+ },
+
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = state.cur(stream, state);
+ var word = stream.current();
+ if (style == "variable") {
+ if (keywords.test(word)) style = "keyword";
+ else if (builtins.test(word)) style = "builtin";
+ else if (specials.test(word)) style = "variable-2";
+ }
+ if ((style != "comment") && (style != "string")){
+ if (indentTokens.test(word)) ++state.indentDepth;
+ else if (dedentTokens.test(word)) --state.indentDepth;
+ }
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ var closing = dedentPartial.test(textAfter);
+ return state.basecol + indentUnit * (state.indentDepth - (closing ? 1 : 0));
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-lua", "lua");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/markdown/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/markdown/index.html
new file mode 100644
index 0000000..cae8df4
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/markdown/index.html
@@ -0,0 +1,338 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Markdown mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="../xml/xml.js"></script>
+ <script src="markdown.js"></script>
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Markdown mode</h1>
+
+<!-- source: http://daringfireball.net/projects/markdown/basics.text -->
+<form><textarea id="code" name="code">
+Markdown: Basics
+================
+
+&lt;ul id="ProjectSubmenu"&gt;
+ &lt;li&gt;&lt;a href="/projects/markdown/" title="Markdown Project Page"&gt;Main&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a class="selected" title="Markdown Basics"&gt;Basics&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="/projects/markdown/syntax" title="Markdown Syntax Documentation"&gt;Syntax&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="/projects/markdown/license" title="Pricing and License Information"&gt;License&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="/projects/markdown/dingus" title="Online Markdown Web Form"&gt;Dingus&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+
+Getting the Gist of Markdown's Formatting Syntax
+------------------------------------------------
+
+This page offers a brief overview of what it's like to use Markdown.
+The [syntax page] [s] provides complete, detailed documentation for
+every feature, but Markdown should be very easy to pick up simply by
+looking at a few examples of it in action. The examples on this page
+are written in a before/after style, showing example syntax and the
+HTML output produced by Markdown.
+
+It's also helpful to simply try Markdown out; the [Dingus] [d] is a
+web application that allows you type your own Markdown-formatted text
+and translate it to XHTML.
+
+**Note:** This document is itself written using Markdown; you
+can [see the source for it by adding '.text' to the URL] [src].
+
+ [s]: /projects/markdown/syntax "Markdown Syntax"
+ [d]: /projects/markdown/dingus "Markdown Dingus"
+ [src]: /projects/markdown/basics.text
+
+
+## Paragraphs, Headers, Blockquotes ##
+
+A paragraph is simply one or more consecutive lines of text, separated
+by one or more blank lines. (A blank line is any line that looks like
+a blank line -- a line containing nothing but spaces or tabs is
+considered blank.) Normal paragraphs should not be indented with
+spaces or tabs.
+
+Markdown offers two styles of headers: *Setext* and *atx*.
+Setext-style headers for `&lt;h1&gt;` and `&lt;h2&gt;` are created by
+"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
+To create an atx-style header, you put 1-6 hash marks (`#`) at the
+beginning of the line -- the number of hashes equals the resulting
+HTML header level.
+
+Blockquotes are indicated using email-style '`&gt;`' angle brackets.
+
+Markdown:
+
+ A First Level Header
+ ====================
+
+ A Second Level Header
+ ---------------------
+
+ Now is the time for all good men to come to
+ the aid of their country. This is just a
+ regular paragraph.
+
+ The quick brown fox jumped over the lazy
+ dog's back.
+
+ ### Header 3
+
+ &gt; This is a blockquote.
+ &gt;
+ &gt; This is the second paragraph in the blockquote.
+ &gt;
+ &gt; ## This is an H2 in a blockquote
+
+
+Output:
+
+ &lt;h1&gt;A First Level Header&lt;/h1&gt;
+
+ &lt;h2&gt;A Second Level Header&lt;/h2&gt;
+
+ &lt;p&gt;Now is the time for all good men to come to
+ the aid of their country. This is just a
+ regular paragraph.&lt;/p&gt;
+
+ &lt;p&gt;The quick brown fox jumped over the lazy
+ dog's back.&lt;/p&gt;
+
+ &lt;h3&gt;Header 3&lt;/h3&gt;
+
+ &lt;blockquote&gt;
+ &lt;p&gt;This is a blockquote.&lt;/p&gt;
+
+ &lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;
+
+ &lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;
+ &lt;/blockquote&gt;
+
+
+
+### Phrase Emphasis ###
+
+Markdown uses asterisks and underscores to indicate spans of emphasis.
+
+Markdown:
+
+ Some of these words *are emphasized*.
+ Some of these words _are emphasized also_.
+
+ Use two asterisks for **strong emphasis**.
+ Or, if you prefer, __use two underscores instead__.
+
+Output:
+
+ &lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.
+ Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;
+
+ &lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.
+ Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;
+
+
+
+## Lists ##
+
+Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
+`+`, and `-`) as list markers. These three markers are
+interchangable; this:
+
+ * Candy.
+ * Gum.
+ * Booze.
+
+this:
+
+ + Candy.
+ + Gum.
+ + Booze.
+
+and this:
+
+ - Candy.
+ - Gum.
+ - Booze.
+
+all produce the same output:
+
+ &lt;ul&gt;
+ &lt;li&gt;Candy.&lt;/li&gt;
+ &lt;li&gt;Gum.&lt;/li&gt;
+ &lt;li&gt;Booze.&lt;/li&gt;
+ &lt;/ul&gt;
+
+Ordered (numbered) lists use regular numbers, followed by periods, as
+list markers:
+
+ 1. Red
+ 2. Green
+ 3. Blue
+
+Output:
+
+ &lt;ol&gt;
+ &lt;li&gt;Red&lt;/li&gt;
+ &lt;li&gt;Green&lt;/li&gt;
+ &lt;li&gt;Blue&lt;/li&gt;
+ &lt;/ol&gt;
+
+If you put blank lines between items, you'll get `&lt;p&gt;` tags for the
+list item text. You can create multi-paragraph list items by indenting
+the paragraphs by 4 spaces or 1 tab:
+
+ * A list item.
+
+ With multiple paragraphs.
+
+ * Another item in the list.
+
+Output:
+
+ &lt;ul&gt;
+ &lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;
+ &lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;
+ &lt;/ul&gt;
+
+
+
+### Links ###
+
+Markdown supports two styles for creating links: *inline* and
+*reference*. With both styles, you use square brackets to delimit the
+text you want to turn into a link.
+
+Inline-style links use parentheses immediately after the link text.
+For example:
+
+ This is an [example link](http://example.com/).
+
+Output:
+
+ &lt;p&gt;This is an &lt;a href="http://example.com/"&gt;
+ example link&lt;/a&gt;.&lt;/p&gt;
+
+Optionally, you may include a title attribute in the parentheses:
+
+ This is an [example link](http://example.com/ "With a Title").
+
+Output:
+
+ &lt;p&gt;This is an &lt;a href="http://example.com/" title="With a Title"&gt;
+ example link&lt;/a&gt;.&lt;/p&gt;
+
+Reference-style links allow you to refer to your links by names, which
+you define elsewhere in your document:
+
+ I get 10 times more traffic from [Google][1] than from
+ [Yahoo][2] or [MSN][3].
+
+ [1]: http://google.com/ "Google"
+ [2]: http://search.yahoo.com/ "Yahoo Search"
+ [3]: http://search.msn.com/ "MSN Search"
+
+Output:
+
+ &lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
+ title="Google"&gt;Google&lt;/a&gt; than from &lt;a href="http://search.yahoo.com/"
+ title="Yahoo Search"&gt;Yahoo&lt;/a&gt; or &lt;a href="http://search.msn.com/"
+ title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
+
+The title attribute is optional. Link names may contain letters,
+numbers and spaces, but are *not* case sensitive:
+
+ I start my morning with a cup of coffee and
+ [The New York Times][NY Times].
+
+ [ny times]: http://www.nytimes.com/
+
+Output:
+
+ &lt;p&gt;I start my morning with a cup of coffee and
+ &lt;a href="http://www.nytimes.com/"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;
+
+
+### Images ###
+
+Image syntax is very much like link syntax.
+
+Inline (titles are optional):
+
+ ![alt text](/path/to/img.jpg "Title")
+
+Reference-style:
+
+ ![alt text][id]
+
+ [id]: /path/to/img.jpg "Title"
+
+Both of the above examples produce the same output:
+
+ &lt;img src="/path/to/img.jpg" alt="alt text" title="Title" /&gt;
+
+
+
+### Code ###
+
+In a regular paragraph, you can create code span by wrapping text in
+backtick quotes. Any ampersands (`&amp;`) and angle brackets (`&lt;` or
+`&gt;`) will automatically be translated into HTML entities. This makes
+it easy to use Markdown to write about HTML example code:
+
+ I strongly recommend against using any `&lt;blink&gt;` tags.
+
+ I wish SmartyPants used named entities like `&amp;mdash;`
+ instead of decimal-encoded entites like `&amp;#8212;`.
+
+Output:
+
+ &lt;p&gt;I strongly recommend against using any
+ &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
+
+ &lt;p&gt;I wish SmartyPants used named entities like
+ &lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded
+ entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
+
+
+To specify an entire block of pre-formatted code, indent every line of
+the block by 4 spaces or 1 tab. Just like with code spans, `&amp;`, `&lt;`,
+and `&gt;` characters will be escaped automatically.
+
+Markdown:
+
+ If you want your page to validate under XHTML 1.0 Strict,
+ you've got to put paragraph tags in your blockquotes:
+
+ &lt;blockquote&gt;
+ &lt;p&gt;For example.&lt;/p&gt;
+ &lt;/blockquote&gt;
+
+Output:
+
+ &lt;p&gt;If you want your page to validate under XHTML 1.0 Strict,
+ you've got to put paragraph tags in your blockquotes:&lt;/p&gt;
+
+ &lt;pre&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;
+ &amp;lt;p&amp;gt;For example.&amp;lt;/p&amp;gt;
+ &amp;lt;/blockquote&amp;gt;
+ &lt;/code&gt;&lt;/pre&gt;
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: 'markdown',
+ lineNumbers: true,
+ matchBrackets: true,
+ theme: "default"
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/markdown/markdown.js b/codemirror_ui/lib/CodeMirror-2.3/mode/markdown/markdown.js
new file mode 100644
index 0000000..232ced7
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/markdown/markdown.js
@@ -0,0 +1,245 @@
+CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
+
+ var htmlMode = CodeMirror.getMode(cmCfg, { name: 'xml', htmlMode: true });
+
+ var header = 'header'
+ , code = 'comment'
+ , quote = 'quote'
+ , list = 'string'
+ , hr = 'hr'
+ , linktext = 'link'
+ , linkhref = 'string'
+ , em = 'em'
+ , strong = 'strong'
+ , emstrong = 'emstrong';
+
+ var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
+ , ulRE = /^[*\-+]\s+/
+ , olRE = /^[0-9]+\.\s+/
+ , headerRE = /^(?:\={3,}|-{3,})$/
+ , textRE = /^[^\[*_\\<>`]+/;
+
+ function switchInline(stream, state, f) {
+ state.f = state.inline = f;
+ return f(stream, state);
+ }
+
+ function switchBlock(stream, state, f) {
+ state.f = state.block = f;
+ return f(stream, state);
+ }
+
+
+ // Blocks
+
+ function blankLine(state) {
+ // Reset EM state
+ state.em = false;
+ // Reset STRONG state
+ state.strong = false;
+ return null;
+ }
+
+ function blockNormal(stream, state) {
+ var match;
+ if (state.indentationDiff >= 4) {
+ state.indentation -= state.indentationDiff;
+ stream.skipToEnd();
+ return code;
+ } else if (stream.eatSpace()) {
+ return null;
+ } else if (stream.peek() === '#' || stream.match(headerRE)) {
+ state.header = true;
+ } else if (stream.eat('>')) {
+ state.indentation++;
+ state.quote = true;
+ } else if (stream.peek() === '[') {
+ return switchInline(stream, state, footnoteLink);
+ } else if (stream.match(hrRE, true)) {
+ return hr;
+ } else if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
+ state.indentation += match[0].length;
+ return list;
+ }
+
+ return switchInline(stream, state, state.inline);
+ }
+
+ function htmlBlock(stream, state) {
+ var style = htmlMode.token(stream, state.htmlState);
+ if (style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
+ state.f = inlineNormal;
+ state.block = blockNormal;
+ }
+ return style;
+ }
+
+
+ // Inline
+ function getType(state) {
+ var styles = [];
+
+ if (state.strong) { styles.push(state.em ? emstrong : strong); }
+ else if (state.em) { styles.push(em); }
+
+ if (state.header) { styles.push(header); }
+ if (state.quote) { styles.push(quote); }
+
+ return styles.length ? styles.join(' ') : null;
+ }
+
+ function handleText(stream, state) {
+ if (stream.match(textRE, true)) {
+ return getType(state);
+ }
+ return undefined;
+ }
+
+ function inlineNormal(stream, state) {
+ var style = state.text(stream, state)
+ if (typeof style !== 'undefined')
+ return style;
+
+ var ch = stream.next();
+
+ if (ch === '\\') {
+ stream.next();
+ return getType(state);
+ }
+ if (ch === '`') {
+ return switchInline(stream, state, inlineElement(code, '`'));
+ }
+ if (ch === '[') {
+ return switchInline(stream, state, linkText);
+ }
+ if (ch === '<' && stream.match(/^\w/, false)) {
+ stream.backUp(1);
+ return switchBlock(stream, state, htmlBlock);
+ }
+
+ var t = getType(state);
+ if (ch === '*' || ch === '_') {
+ if (stream.eat(ch)) {
+ return (state.strong = !state.strong) ? getType(state) : t;
+ }
+ return (state.em = !state.em) ? getType(state) : t;
+ }
+
+ return getType(state);
+ }
+
+ function linkText(stream, state) {
+ while (!stream.eol()) {
+ var ch = stream.next();
+ if (ch === '\\') stream.next();
+ if (ch === ']') {
+ state.inline = state.f = linkHref;
+ return linktext;
+ }
+ }
+ return linktext;
+ }
+
+ function linkHref(stream, state) {
+ stream.eatSpace();
+ var ch = stream.next();
+ if (ch === '(' || ch === '[') {
+ return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
+ }
+ return 'error';
+ }
+
+ function footnoteLink(stream, state) {
+ if (stream.match(/^[^\]]*\]:/, true)) {
+ state.f = footnoteUrl;
+ return linktext;
+ }
+ return switchInline(stream, state, inlineNormal);
+ }
+
+ function footnoteUrl(stream, state) {
+ stream.eatSpace();
+ stream.match(/^[^\s]+/, true);
+ state.f = state.inline = inlineNormal;
+ return linkhref;
+ }
+
+ function inlineRE(endChar) {
+ if (!inlineRE[endChar]) {
+ // match any not-escaped-non-endChar and any escaped char
+ // then match endChar or eol
+ inlineRE[endChar] = new RegExp('^(?:[^\\\\\\' + endChar + ']|\\\\.)*(?:\\' + endChar + '|$)');
+ }
+ return inlineRE[endChar];
+ }
+
+ function inlineElement(type, endChar, next) {
+ next = next || inlineNormal;
+ return function(stream, state) {
+ stream.match(inlineRE(endChar));
+ state.inline = state.f = next;
+ return type;
+ };
+ }
+
+ return {
+ startState: function() {
+ return {
+ f: blockNormal,
+
+ block: blockNormal,
+ htmlState: htmlMode.startState(),
+ indentation: 0,
+
+ inline: inlineNormal,
+ text: handleText,
+ em: false,
+ strong: false,
+ header: false,
+ quote: false
+ };
+ },
+
+ copyState: function(s) {
+ return {
+ f: s.f,
+
+ block: s.block,
+ htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
+ indentation: s.indentation,
+
+ inline: s.inline,
+ text: s.text,
+ em: s.em,
+ strong: s.strong,
+ header: s.header,
+ quote: s.quote
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.sol()) {
+ if (stream.match(/^\s*$/, true)) { return blankLine(state); }
+
+ // Reset state.header
+ state.header = false;
+ // Reset state.quote
+ state.quote = false;
+
+ state.f = state.block;
+ var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
+ state.indentationDiff = indentation - state.indentation;
+ state.indentation = indentation;
+ if (indentation > 0) { return null; }
+ }
+ return state.f(stream, state);
+ },
+
+ blankLine: blankLine,
+
+ getType: getType
+ };
+
+}, "xml");
+
+CodeMirror.defineMIME("text/x-markdown", "markdown");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/mysql/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/mysql/index.html
new file mode 100644
index 0000000..006918c
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/mysql/index.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: MySQL mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="mysql.js"></script>
+ <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: MySQL mode</h1>
+ <form><textarea id="code" name="code">
+-- Comment for the code
+-- MySQL Mode for CodeMirror2 by MySQLTools http://github.com/partydroid/MySQL-Tools
+SELECT UNIQUE `var1` as `variable`,
+ MAX(`var5`) as `max`,
+ MIN(`var5`) as `min`,
+ STDEV(`var5`) as `dev`
+FROM `table`
+
+LEFT JOIN `table2` ON `var2` = `variable`
+
+ORDER BY `var3` DESC
+GROUP BY `groupvar`
+
+LIMIT 0,30;
+
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: "text/x-mysql",
+ tabMode: "indent",
+ matchBrackets: true
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-mysql</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/mysql/mysql.js b/codemirror_ui/lib/CodeMirror-2.3/mode/mysql/mysql.js
new file mode 100644
index 0000000..dca5b0f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/mysql/mysql.js
@@ -0,0 +1,188 @@
+/*
+ * MySQL Mode for CodeMirror 2 by MySQL-Tools
+ * @author James Thorne (partydroid)
+ * @link http://github.com/partydroid/MySQL-Tools
+ * @link http://mysqltools.org
+ * @version 02/Jan/2012
+*/
+CodeMirror.defineMode("mysql", function(config) {
+ var indentUnit = config.indentUnit;
+ var curPunc;
+
+ function wordRegexp(words) {
+ return new RegExp("^(?:" + words.join("|") + ")$", "i");
+ }
+ var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri",
+ "isblank", "isliteral", "union", "a"]);
+ var keywords = wordRegexp([
+ ('ACCESSIBLE'),('ALTER'),('AS'),('BEFORE'),('BINARY'),('BY'),('CASE'),('CHARACTER'),('COLUMN'),('CONTINUE'),('CROSS'),('CURRENT_TIMESTAMP'),('DATABASE'),('DAY_MICROSECOND'),('DEC'),('DEFAULT'),
+ ('DESC'),('DISTINCT'),('DOUBLE'),('EACH'),('ENCLOSED'),('EXIT'),('FETCH'),('FLOAT8'),('FOREIGN'),('GRANT'),('HIGH_PRIORITY'),('HOUR_SECOND'),('IN'),('INNER'),('INSERT'),('INT2'),('INT8'),
+ ('INTO'),('JOIN'),('KILL'),('LEFT'),('LINEAR'),('LOCALTIME'),('LONG'),('LOOP'),('MATCH'),('MEDIUMTEXT'),('MINUTE_SECOND'),('NATURAL'),('NULL'),('OPTIMIZE'),('OR'),('OUTER'),('PRIMARY'),
+ ('RANGE'),('READ_WRITE'),('REGEXP'),('REPEAT'),('RESTRICT'),('RIGHT'),('SCHEMAS'),('SENSITIVE'),('SHOW'),('SPECIFIC'),('SQLSTATE'),('SQL_CALC_FOUND_ROWS'),('STARTING'),('TERMINATED'),
+ ('TINYINT'),('TRAILING'),('UNDO'),('UNLOCK'),('USAGE'),('UTC_DATE'),('VALUES'),('VARCHARACTER'),('WHERE'),('WRITE'),('ZEROFILL'),('ALL'),('AND'),('ASENSITIVE'),('BIGINT'),('BOTH'),('CASCADE'),
+ ('CHAR'),('COLLATE'),('CONSTRAINT'),('CREATE'),('CURRENT_TIME'),('CURSOR'),('DAY_HOUR'),('DAY_SECOND'),('DECLARE'),('DELETE'),('DETERMINISTIC'),('DIV'),('DUAL'),('ELSEIF'),('EXISTS'),('FALSE'),
+ ('FLOAT4'),('FORCE'),('FULLTEXT'),('HAVING'),('HOUR_MINUTE'),('IGNORE'),('INFILE'),('INSENSITIVE'),('INT1'),('INT4'),('INTERVAL'),('ITERATE'),('KEYS'),('LEAVE'),('LIMIT'),('LOAD'),('LOCK'),
+ ('LONGTEXT'),('MASTER_SSL_VERIFY_SERVER_CERT'),('MEDIUMINT'),('MINUTE_MICROSECOND'),('MODIFIES'),('NO_WRITE_TO_BINLOG'),('ON'),('OPTIONALLY'),('OUT'),('PRECISION'),('PURGE'),('READS'),
+ ('REFERENCES'),('RENAME'),('REQUIRE'),('REVOKE'),('SCHEMA'),('SELECT'),('SET'),('SPATIAL'),('SQLEXCEPTION'),('SQL_BIG_RESULT'),('SSL'),('TABLE'),('TINYBLOB'),('TO'),('TRUE'),('UNIQUE'),
+ ('UPDATE'),('USING'),('UTC_TIMESTAMP'),('VARCHAR'),('WHEN'),('WITH'),('YEAR_MONTH'),('ADD'),('ANALYZE'),('ASC'),('BETWEEN'),('BLOB'),('CALL'),('CHANGE'),('CHECK'),('CONDITION'),('CONVERT'),
+ ('CURRENT_DATE'),('CURRENT_USER'),('DATABASES'),('DAY_MINUTE'),('DECIMAL'),('DELAYED'),('DESCRIBE'),('DISTINCTROW'),('DROP'),('ELSE'),('ESCAPED'),('EXPLAIN'),('FLOAT'),('FOR'),('FROM'),
+ ('GROUP'),('HOUR_MICROSECOND'),('IF'),('INDEX'),('INOUT'),('INT'),('INT3'),('INTEGER'),('IS'),('KEY'),('LEADING'),('LIKE'),('LINES'),('LOCALTIMESTAMP'),('LONGBLOB'),('LOW_PRIORITY'),
+ ('MEDIUMBLOB'),('MIDDLEINT'),('MOD'),('NOT'),('NUMERIC'),('OPTION'),('ORDER'),('OUTFILE'),('PROCEDURE'),('READ'),('REAL'),('RELEASE'),('REPLACE'),('RETURN'),('RLIKE'),('SECOND_MICROSECOND'),
+ ('SEPARATOR'),('SMALLINT'),('SQL'),('SQLWARNING'),('SQL_SMALL_RESULT'),('STRAIGHT_JOIN'),('THEN'),('TINYTEXT'),('TRIGGER'),('UNION'),('UNSIGNED'),('USE'),('UTC_TIME'),('VARBINARY'),('VARYING'),
+ ('WHILE'),('XOR'),('FULL'),('COLUMNS'),('MIN'),('MAX'),('STDEV'),('COUNT')
+ ]);
+ var operatorChars = /[*+\-<>=&|]/;
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ curPunc = null;
+ if (ch == "$" || ch == "?") {
+ stream.match(/^[\w\d]*/);
+ return "variable-2";
+ }
+ else if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) {
+ stream.match(/^[^\s\u00a0>]*>?/);
+ return "atom";
+ }
+ else if (ch == "\"" || ch == "'") {
+ state.tokenize = tokenLiteral(ch);
+ return state.tokenize(stream, state);
+ }
+ else if (ch == "`") {
+ state.tokenize = tokenOpLiteral(ch);
+ return state.tokenize(stream, state);
+ }
+ else if (/[{}\(\),\.;\[\]]/.test(ch)) {
+ curPunc = ch;
+ return null;
+ }
+ else if (ch == "-") {
+ ch2 = stream.next();
+ if(ch2=="-")
+ {
+ stream.skipToEnd();
+ return "comment";
+ }
+
+ }
+ else if (operatorChars.test(ch)) {
+ stream.eatWhile(operatorChars);
+ return null;
+ }
+ else if (ch == ":") {
+ stream.eatWhile(/[\w\d\._\-]/);
+ return "atom";
+ }
+ else {
+ stream.eatWhile(/[_\w\d]/);
+ if (stream.eat(":")) {
+ stream.eatWhile(/[\w\d_\-]/);
+ return "atom";
+ }
+ var word = stream.current(), type;
+ if (ops.test(word))
+ return null;
+ else if (keywords.test(word))
+ return "keyword";
+ else
+ return "variable";
+ }
+ }
+
+ function tokenLiteral(quote) {
+ return function(stream, state) {
+ var escaped = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == quote && !escaped) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ escaped = !escaped && ch == "\\";
+ }
+ return "string";
+ };
+ }
+
+ function tokenOpLiteral(quote) {
+ return function(stream, state) {
+ var escaped = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == quote && !escaped) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ escaped = !escaped && ch == "\\";
+ }
+ return "variable-2";
+ };
+ }
+
+
+ function pushContext(state, type, col) {
+ state.context = {prev: state.context, indent: state.indent, col: col, type: type};
+ }
+ function popContext(state) {
+ state.indent = state.context.indent;
+ state.context = state.context.prev;
+ }
+
+ return {
+ startState: function(base) {
+ return {tokenize: tokenBase,
+ context: null,
+ indent: 0,
+ col: 0};
+ },
+
+ token: function(stream, state) {
+ if (stream.sol()) {
+ if (state.context && state.context.align == null) state.context.align = false;
+ state.indent = stream.indentation();
+ }
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+
+ if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") {
+ state.context.align = true;
+ }
+
+ if (curPunc == "(") pushContext(state, ")", stream.column());
+ else if (curPunc == "[") pushContext(state, "]", stream.column());
+ else if (curPunc == "{") pushContext(state, "}", stream.column());
+ else if (/[\]\}\)]/.test(curPunc)) {
+ while (state.context && state.context.type == "pattern") popContext(state);
+ if (state.context && curPunc == state.context.type) popContext(state);
+ }
+ else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state);
+ else if (/atom|string|variable/.test(style) && state.context) {
+ if (/[\}\]]/.test(state.context.type))
+ pushContext(state, "pattern", stream.column());
+ else if (state.context.type == "pattern" && !state.context.align) {
+ state.context.align = true;
+ state.context.col = stream.column();
+ }
+ }
+
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ var firstChar = textAfter && textAfter.charAt(0);
+ var context = state.context;
+ if (/[\]\}]/.test(firstChar))
+ while (context && context.type == "pattern") context = context.prev;
+
+ var closing = context && firstChar == context.type;
+ if (!context)
+ return 0;
+ else if (context.type == "pattern")
+ return context.col;
+ else if (context.align)
+ return context.col + (closing ? 0 : 1);
+ else
+ return context.indent + (closing ? 0 : indentUnit);
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-mysql", "mysql");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/ntriples/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/ntriples/index.html
new file mode 100644
index 0000000..08d33ba
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/ntriples/index.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: NTriples mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="ntriples.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style type="text/css">
+ .CodeMirror {
+ border: 1px solid #eee;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: NTriples mode</h1>
+<form>
+<textarea id="ntriples" name="ntriples">
+<http://Sub1> <http://pred1> <http://obj> .
+<http://Sub2> <http://pred2#an2> "literal 1" .
+<http://Sub3#an3> <http://pred3> _:bnode3 .
+_:bnode4 <http://pred4> "literal 2"@lang .
+_:bnode5 <http://pred5> "literal 3"^^<http://type> .
+</textarea>
+</form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("ntriples"), {});
+ </script>
+ <p><strong>MIME types defined:</strong> <code>text/n-triples</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/ntriples/ntriples.js b/codemirror_ui/lib/CodeMirror-2.3/mode/ntriples/ntriples.js
new file mode 100644
index 0000000..3b6cb41
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/ntriples/ntriples.js
@@ -0,0 +1,172 @@
+/**********************************************************
+* This script provides syntax highlighting support for
+* the Ntriples format.
+* Ntriples format specification:
+* http://www.w3.org/TR/rdf-testcases/#ntriples
+***********************************************************/
+
+/*
+ The following expression defines the defined ASF grammar transitions.
+
+ pre_subject ->
+ {
+ ( writing_subject_uri | writing_bnode_uri )
+ -> pre_predicate
+ -> writing_predicate_uri
+ -> pre_object
+ -> writing_object_uri | writing_object_bnode |
+ (
+ writing_object_literal
+ -> writing_literal_lang | writing_literal_type
+ )
+ -> post_object
+ -> BEGIN
+ } otherwise {
+ -> ERROR
+ }
+*/
+CodeMirror.defineMode("ntriples", function() {
+
+ Location = {
+ PRE_SUBJECT : 0,
+ WRITING_SUB_URI : 1,
+ WRITING_BNODE_URI : 2,
+ PRE_PRED : 3,
+ WRITING_PRED_URI : 4,
+ PRE_OBJ : 5,
+ WRITING_OBJ_URI : 6,
+ WRITING_OBJ_BNODE : 7,
+ WRITING_OBJ_LITERAL : 8,
+ WRITING_LIT_LANG : 9,
+ WRITING_LIT_TYPE : 10,
+ POST_OBJ : 11,
+ ERROR : 12
+ };
+ function transitState(currState, c) {
+ var currLocation = currState.location;
+ var ret;
+
+ // Opening.
+ if (currLocation == Location.PRE_SUBJECT && c == '<') ret = Location.WRITING_SUB_URI;
+ else if(currLocation == Location.PRE_SUBJECT && c == '_') ret = Location.WRITING_BNODE_URI;
+ else if(currLocation == Location.PRE_PRED && c == '<') ret = Location.WRITING_PRED_URI;
+ else if(currLocation == Location.PRE_OBJ && c == '<') ret = Location.WRITING_OBJ_URI;
+ else if(currLocation == Location.PRE_OBJ && c == '_') ret = Location.WRITING_OBJ_BNODE;
+ else if(currLocation == Location.PRE_OBJ && c == '"') ret = Location.WRITING_OBJ_LITERAL;
+
+ // Closing.
+ else if(currLocation == Location.WRITING_SUB_URI && c == '>') ret = Location.PRE_PRED;
+ else if(currLocation == Location.WRITING_BNODE_URI && c == ' ') ret = Location.PRE_PRED;
+ else if(currLocation == Location.WRITING_PRED_URI && c == '>') ret = Location.PRE_OBJ;
+ else if(currLocation == Location.WRITING_OBJ_URI && c == '>') ret = Location.POST_OBJ;
+ else if(currLocation == Location.WRITING_OBJ_BNODE && c == ' ') ret = Location.POST_OBJ;
+ else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '"') ret = Location.POST_OBJ;
+ else if(currLocation == Location.WRITING_LIT_LANG && c == ' ') ret = Location.POST_OBJ;
+ else if(currLocation == Location.WRITING_LIT_TYPE && c == '>') ret = Location.POST_OBJ;
+
+ // Closing typed and language literal.
+ else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '@') ret = Location.WRITING_LIT_LANG;
+ else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '^') ret = Location.WRITING_LIT_TYPE;
+
+ // Spaces.
+ else if( c == ' ' &&
+ (
+ currLocation == Location.PRE_SUBJECT ||
+ currLocation == Location.PRE_PRED ||
+ currLocation == Location.PRE_OBJ ||
+ currLocation == Location.POST_OBJ
+ )
+ ) ret = currLocation;
+
+ // Reset.
+ else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT;
+
+ // Error
+ else ret = Location.ERROR;
+
+ currState.location=ret;
+ }
+
+ untilSpace = function(c) { return c != ' '; };
+ untilEndURI = function(c) { return c != '>'; };
+ return {
+ startState: function() {
+ return {
+ location : Location.PRE_SUBJECT,
+ uris : [],
+ anchors : [],
+ bnodes : [],
+ langs : [],
+ types : []
+ };
+ },
+ token: function(stream, state) {
+ var ch = stream.next();
+ if(ch == '<') {
+ transitState(state, ch);
+ var parsedURI = '';
+ stream.eatWhile( function(c) { if( c != '#' && c != '>' ) { parsedURI += c; return true; } return false;} );
+ state.uris.push(parsedURI);
+ if( stream.match('#', false) ) return 'variable';
+ stream.next();
+ transitState(state, '>');
+ return 'variable';
+ }
+ if(ch == '#') {
+ var parsedAnchor = '';
+ stream.eatWhile(function(c) { if(c != '>' && c != ' ') { parsedAnchor+= c; return true; } return false});
+ state.anchors.push(parsedAnchor);
+ return 'variable-2';
+ }
+ if(ch == '>') {
+ transitState(state, '>');
+ return 'variable';
+ }
+ if(ch == '_') {
+ transitState(state, ch);
+ var parsedBNode = '';
+ stream.eatWhile(function(c) { if( c != ' ' ) { parsedBNode += c; return true; } return false;});
+ state.bnodes.push(parsedBNode);
+ stream.next();
+ transitState(state, ' ');
+ return 'builtin';
+ }
+ if(ch == '"') {
+ transitState(state, ch);
+ stream.eatWhile( function(c) { return c != '"'; } );
+ stream.next();
+ if( stream.peek() != '@' && stream.peek() != '^' ) {
+ transitState(state, '"');
+ }
+ return 'string';
+ }
+ if( ch == '@' ) {
+ transitState(state, '@');
+ var parsedLang = '';
+ stream.eatWhile(function(c) { if( c != ' ' ) { parsedLang += c; return true; } return false;});
+ state.langs.push(parsedLang);
+ stream.next();
+ transitState(state, ' ');
+ return 'string-2';
+ }
+ if( ch == '^' ) {
+ stream.next();
+ transitState(state, '^');
+ var parsedType = '';
+ stream.eatWhile(function(c) { if( c != '>' ) { parsedType += c; return true; } return false;} );
+ state.types.push(parsedType);
+ stream.next();
+ transitState(state, '>');
+ return 'variable';
+ }
+ if( ch == ' ' ) {
+ transitState(state, ch);
+ }
+ if( ch == '.' ) {
+ transitState(state, ch);
+ }
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/n-triples", "ntriples");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/pascal/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/pascal/index.html
new file mode 100644
index 0000000..6af6b46
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/pascal/index.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Pascal mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="pascal.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Pascal mode</h1>
+
+<div><textarea id="code" name="code">
+(* Example Pascal code *)
+
+while a <> b do writeln('Waiting');
+
+if a > b then
+ writeln('Condition met')
+else
+ writeln('Condition not met');
+
+for i := 1 to 10 do
+ writeln('Iteration: ', i:1);
+
+repeat
+ a := a + 1
+until a = 10;
+
+case i of
+ 0: write('zero');
+ 1: write('one');
+ 2: write('two')
+end;
+</textarea></div>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ mode: "text/x-pascal"
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-pascal</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/pascal/pascal.js b/codemirror_ui/lib/CodeMirror-2.3/mode/pascal/pascal.js
new file mode 100644
index 0000000..9ac522f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/pascal/pascal.js
@@ -0,0 +1,94 @@
+CodeMirror.defineMode("pascal", function(config) {
+ function words(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+ var keywords = words("and array begin case const div do downto else end file for forward integer " +
+ "boolean char function goto if in label mod nil not of or packed procedure " +
+ "program record repeat set string then to type until var while with");
+ var atoms = {"null": true};
+
+ var isOperatorChar = /[+\-*&%=<>!?|\/]/;
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ if (ch == "#" && state.startOfLine) {
+ stream.skipToEnd();
+ return "meta";
+ }
+ if (ch == '"' || ch == "'") {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ }
+ if (ch == "(" && stream.eat("*")) {
+ state.tokenize = tokenComment;
+ return tokenComment(stream, state);
+ }
+ if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+ return null
+ }
+ if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return "number";
+ }
+ if (ch == "/") {
+ if (stream.eat("/")) {
+ stream.skipToEnd();
+ return "comment";
+ }
+ }
+ if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return "operator";
+ }
+ stream.eatWhile(/[\w\$_]/);
+ var cur = stream.current();
+ if (keywords.propertyIsEnumerable(cur)) return "keyword";
+ if (atoms.propertyIsEnumerable(cur)) return "atom";
+ return "word";
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {end = true; break;}
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !escaped) state.tokenize = null;
+ return "string";
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == ")" && maybeEnd) {
+ state.tokenize = null;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return "comment";
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {tokenize: null};
+ },
+
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = (state.tokenize || tokenBase)(stream, state);
+ if (style == "comment" || style == "meta") return style;
+ return style;
+ },
+
+ electricChars: "{}"
+ };
+});
+
+CodeMirror.defineMIME("text/x-pascal", "pascal");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/perl/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/perl/index.html
new file mode 100644
index 0000000..5ef55d3
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/perl/index.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Perl mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="perl.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Perl mode</h1>
+
+<div><textarea id="code" name="code">
+#!/usr/bin/perl
+
+use Something qw(func1 func2);
+
+# strings
+my $s1 = qq'single line';
+our $s2 = q(multi-
+ line);
+
+=item Something
+ Example.
+=cut
+
+my $html=<<'HTML'
+<html>
+<title>hi!</title>
+</html>
+HTML
+
+print "first,".join(',', 'second', qq~third~);
+
+if($s1 =~ m[(?<!\s)(l.ne)\z]o) {
+ $h->{$1}=$$.' predefined variables';
+ $s2 =~ s/\-line//ox;
+ $s1 =~ s[
+ line ]
+ [
+ block
+ ]ox;
+}
+
+1; # numbers and comments
+
+__END__
+something...
+
+</textarea></div>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-perl</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/perl/perl.js b/codemirror_ui/lib/CodeMirror-2.3/mode/perl/perl.js
new file mode 100644
index 0000000..7fa129e
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/perl/perl.js
@@ -0,0 +1,816 @@
+// CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)
+// This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)
+CodeMirror.defineMode("perl",function(config,parserConfig){
+ // http://perldoc.perl.org
+ var PERL={ // null - magic touch
+ // 1 - keyword
+ // 2 - def
+ // 3 - atom
+ // 4 - operator
+ // 5 - variable-2 (predefined)
+ // [x,y] - x=1,2,3; y=must be defined if x{...}
+ // PERL operators
+ '->' : 4,
+ '++' : 4,
+ '--' : 4,
+ '**' : 4,
+ // ! ~ \ and unary + and -
+ '=~' : 4,
+ '!~' : 4,
+ '*' : 4,
+ '/' : 4,
+ '%' : 4,
+ 'x' : 4,
+ '+' : 4,
+ '-' : 4,
+ '.' : 4,
+ '<<' : 4,
+ '>>' : 4,
+ // named unary operators
+ '<' : 4,
+ '>' : 4,
+ '<=' : 4,
+ '>=' : 4,
+ 'lt' : 4,
+ 'gt' : 4,
+ 'le' : 4,
+ 'ge' : 4,
+ '==' : 4,
+ '!=' : 4,
+ '<=>' : 4,
+ 'eq' : 4,
+ 'ne' : 4,
+ 'cmp' : 4,
+ '~~' : 4,
+ '&' : 4,
+ '|' : 4,
+ '^' : 4,
+ '&&' : 4,
+ '||' : 4,
+ '//' : 4,
+ '..' : 4,
+ '...' : 4,
+ '?' : 4,
+ ':' : 4,
+ '=' : 4,
+ '+=' : 4,
+ '-=' : 4,
+ '*=' : 4, // etc. ???
+ ',' : 4,
+ '=>' : 4,
+ '::' : 4,
+ // list operators (rightward)
+ 'not' : 4,
+ 'and' : 4,
+ 'or' : 4,
+ 'xor' : 4,
+ // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;)
+ 'BEGIN' : [5,1],
+ 'END' : [5,1],
+ 'PRINT' : [5,1],
+ 'PRINTF' : [5,1],
+ 'GETC' : [5,1],
+ 'READ' : [5,1],
+ 'READLINE' : [5,1],
+ 'DESTROY' : [5,1],
+ 'TIE' : [5,1],
+ 'TIEHANDLE' : [5,1],
+ 'UNTIE' : [5,1],
+ 'STDIN' : 5,
+ 'STDIN_TOP' : 5,
+ 'STDOUT' : 5,
+ 'STDOUT_TOP' : 5,
+ 'STDERR' : 5,
+ 'STDERR_TOP' : 5,
+ '$ARG' : 5,
+ '$_' : 5,
+ '@ARG' : 5,
+ '@_' : 5,
+ '$LIST_SEPARATOR' : 5,
+ '$"' : 5,
+ '$PROCESS_ID' : 5,
+ '$PID' : 5,
+ '$$' : 5,
+ '$REAL_GROUP_ID' : 5,
+ '$GID' : 5,
+ '$(' : 5,
+ '$EFFECTIVE_GROUP_ID' : 5,
+ '$EGID' : 5,
+ '$)' : 5,
+ '$PROGRAM_NAME' : 5,
+ '$0' : 5,
+ '$SUBSCRIPT_SEPARATOR' : 5,
+ '$SUBSEP' : 5,
+ '$;' : 5,
+ '$REAL_USER_ID' : 5,
+ '$UID' : 5,
+ '$<' : 5,
+ '$EFFECTIVE_USER_ID' : 5,
+ '$EUID' : 5,
+ '$>' : 5,
+ '$a' : 5,
+ '$b' : 5,
+ '$COMPILING' : 5,
+ '$^C' : 5,
+ '$DEBUGGING' : 5,
+ '$^D' : 5,
+ '${^ENCODING}' : 5,
+ '$ENV' : 5,
+ '%ENV' : 5,
+ '$SYSTEM_FD_MAX' : 5,
+ '$^F' : 5,
+ '@F' : 5,
+ '${^GLOBAL_PHASE}' : 5,
+ '$^H' : 5,
+ '%^H' : 5,
+ '@INC' : 5,
+ '%INC' : 5,
+ '$INPLACE_EDIT' : 5,
+ '$^I' : 5,
+ '$^M' : 5,
+ '$OSNAME' : 5,
+ '$^O' : 5,
+ '${^OPEN}' : 5,
+ '$PERLDB' : 5,
+ '$^P' : 5,
+ '$SIG' : 5,
+ '%SIG' : 5,
+ '$BASETIME' : 5,
+ '$^T' : 5,
+ '${^TAINT}' : 5,
+ '${^UNICODE}' : 5,
+ '${^UTF8CACHE}' : 5,
+ '${^UTF8LOCALE}' : 5,
+ '$PERL_VERSION' : 5,
+ '$^V' : 5,
+ '${^WIN32_SLOPPY_STAT}' : 5,
+ '$EXECUTABLE_NAME' : 5,
+ '$^X' : 5,
+ '$1' : 5, // - regexp $1, $2...
+ '$MATCH' : 5,
+ '$&' : 5,
+ '${^MATCH}' : 5,
+ '$PREMATCH' : 5,
+ '$`' : 5,
+ '${^PREMATCH}' : 5,
+ '$POSTMATCH' : 5,
+ "$'" : 5,
+ '${^POSTMATCH}' : 5,
+ '$LAST_PAREN_MATCH' : 5,
+ '$+' : 5,
+ '$LAST_SUBMATCH_RESULT' : 5,
+ '$^N' : 5,
+ '@LAST_MATCH_END' : 5,
+ '@+' : 5,
+ '%LAST_PAREN_MATCH' : 5,
+ '%+' : 5,
+ '@LAST_MATCH_START' : 5,
+ '@-' : 5,
+ '%LAST_MATCH_START' : 5,
+ '%-' : 5,
+ '$LAST_REGEXP_CODE_RESULT' : 5,
+ '$^R' : 5,
+ '${^RE_DEBUG_FLAGS}' : 5,
+ '${^RE_TRIE_MAXBUF}' : 5,
+ '$ARGV' : 5,
+ '@ARGV' : 5,
+ 'ARGV' : 5,
+ 'ARGVOUT' : 5,
+ '$OUTPUT_FIELD_SEPARATOR' : 5,
+ '$OFS' : 5,
+ '$,' : 5,
+ '$INPUT_LINE_NUMBER' : 5,
+ '$NR' : 5,
+ '$.' : 5,
+ '$INPUT_RECORD_SEPARATOR' : 5,
+ '$RS' : 5,
+ '$/' : 5,
+ '$OUTPUT_RECORD_SEPARATOR' : 5,
+ '$ORS' : 5,
+ '$\\' : 5,
+ '$OUTPUT_AUTOFLUSH' : 5,
+ '$|' : 5,
+ '$ACCUMULATOR' : 5,
+ '$^A' : 5,
+ '$FORMAT_FORMFEED' : 5,
+ '$^L' : 5,
+ '$FORMAT_PAGE_NUMBER' : 5,
+ '$%' : 5,
+ '$FORMAT_LINES_LEFT' : 5,
+ '$-' : 5,
+ '$FORMAT_LINE_BREAK_CHARACTERS' : 5,
+ '$:' : 5,
+ '$FORMAT_LINES_PER_PAGE' : 5,
+ '$=' : 5,
+ '$FORMAT_TOP_NAME' : 5,
+ '$^' : 5,
+ '$FORMAT_NAME' : 5,
+ '$~' : 5,
+ '${^CHILD_ERROR_NATIVE}' : 5,
+ '$EXTENDED_OS_ERROR' : 5,
+ '$^E' : 5,
+ '$EXCEPTIONS_BEING_CAUGHT' : 5,
+ '$^S' : 5,
+ '$WARNING' : 5,
+ '$^W' : 5,
+ '${^WARNING_BITS}' : 5,
+ '$OS_ERROR' : 5,
+ '$ERRNO' : 5,
+ '$!' : 5,
+ '%OS_ERROR' : 5,
+ '%ERRNO' : 5,
+ '%!' : 5,
+ '$CHILD_ERROR' : 5,
+ '$?' : 5,
+ '$EVAL_ERROR' : 5,
+ '$@' : 5,
+ '$OFMT' : 5,
+ '$#' : 5,
+ '$*' : 5,
+ '$ARRAY_BASE' : 5,
+ '$[' : 5,
+ '$OLD_PERL_VERSION' : 5,
+ '$]' : 5,
+ // PERL blocks
+ 'if' :[1,1],
+ elsif :[1,1],
+ 'else' :[1,1],
+ 'while' :[1,1],
+ unless :[1,1],
+ 'for' :[1,1],
+ foreach :[1,1],
+ // PERL functions
+ 'abs' :1, // - absolute value function
+ accept :1, // - accept an incoming socket connect
+ alarm :1, // - schedule a SIGALRM
+ 'atan2' :1, // - arctangent of Y/X in the range -PI to PI
+ bind :1, // - binds an address to a socket
+ binmode :1, // - prepare binary files for I/O
+ bless :1, // - create an object
+ bootstrap :1, //
+ 'break' :1, // - break out of a "given" block
+ caller :1, // - get context of the current subroutine call
+ chdir :1, // - change your current working directory
+ chmod :1, // - changes the permissions on a list of files
+ chomp :1, // - remove a trailing record separator from a string
+ chop :1, // - remove the last character from a string
+ chown :1, // - change the owership on a list of files
+ chr :1, // - get character this number represents
+ chroot :1, // - make directory new root for path lookups
+ close :1, // - close file (or pipe or socket) handle
+ closedir :1, // - close directory handle
+ connect :1, // - connect to a remote socket
+ 'continue' :[1,1], // - optional trailing block in a while or foreach
+ 'cos' :1, // - cosine function
+ crypt :1, // - one-way passwd-style encryption
+ dbmclose :1, // - breaks binding on a tied dbm file
+ dbmopen :1, // - create binding on a tied dbm file
+ 'default' :1, //
+ defined :1, // - test whether a value, variable, or function is defined
+ 'delete' :1, // - deletes a value from a hash
+ die :1, // - raise an exception or bail out
+ 'do' :1, // - turn a BLOCK into a TERM
+ dump :1, // - create an immediate core dump
+ each :1, // - retrieve the next key/value pair from a hash
+ endgrent :1, // - be done using group file
+ endhostent :1, // - be done using hosts file
+ endnetent :1, // - be done using networks file
+ endprotoent :1, // - be done using protocols file
+ endpwent :1, // - be done using passwd file
+ endservent :1, // - be done using services file
+ eof :1, // - test a filehandle for its end
+ 'eval' :1, // - catch exceptions or compile and run code
+ 'exec' :1, // - abandon this program to run another
+ exists :1, // - test whether a hash key is present
+ exit :1, // - terminate this program
+ 'exp' :1, // - raise I to a power
+ fcntl :1, // - file control system call
+ fileno :1, // - return file descriptor from filehandle
+ flock :1, // - lock an entire file with an advisory lock
+ fork :1, // - create a new process just like this one
+ format :1, // - declare a picture format with use by the write() function
+ formline :1, // - internal function used for formats
+ getc :1, // - get the next character from the filehandle
+ getgrent :1, // - get next group record
+ getgrgid :1, // - get group record given group user ID
+ getgrnam :1, // - get group record given group name
+ gethostbyaddr :1, // - get host record given its address
+ gethostbyname :1, // - get host record given name
+ gethostent :1, // - get next hosts record
+ getlogin :1, // - return who logged in at this tty
+ getnetbyaddr :1, // - get network record given its address
+ getnetbyname :1, // - get networks record given name
+ getnetent :1, // - get next networks record
+ getpeername :1, // - find the other end of a socket connection
+ getpgrp :1, // - get process group
+ getppid :1, // - get parent process ID
+ getpriority :1, // - get current nice value
+ getprotobyname :1, // - get protocol record given name
+ getprotobynumber :1, // - get protocol record numeric protocol
+ getprotoent :1, // - get next protocols record
+ getpwent :1, // - get next passwd record
+ getpwnam :1, // - get passwd record given user login name
+ getpwuid :1, // - get passwd record given user ID
+ getservbyname :1, // - get services record given its name
+ getservbyport :1, // - get services record given numeric port
+ getservent :1, // - get next services record
+ getsockname :1, // - retrieve the sockaddr for a given socket
+ getsockopt :1, // - get socket options on a given socket
+ given :1, //
+ glob :1, // - expand filenames using wildcards
+ gmtime :1, // - convert UNIX time into record or string using Greenwich time
+ 'goto' :1, // - create spaghetti code
+ grep :1, // - locate elements in a list test true against a given criterion
+ hex :1, // - convert a string to a hexadecimal number
+ 'import' :1, // - patch a module's namespace into your own
+ index :1, // - find a substring within a string
+ 'int' :1, // - get the integer portion of a number
+ ioctl :1, // - system-dependent device control system call
+ 'join' :1, // - join a list into a string using a separator
+ keys :1, // - retrieve list of indices from a hash
+ kill :1, // - send a signal to a process or process group
+ last :1, // - exit a block prematurely
+ lc :1, // - return lower-case version of a string
+ lcfirst :1, // - return a string with just the next letter in lower case
+ length :1, // - return the number of bytes in a string
+ 'link' :1, // - create a hard link in the filesytem
+ listen :1, // - register your socket as a server
+ local : 2, // - create a temporary value for a global variable (dynamic scoping)
+ localtime :1, // - convert UNIX time into record or string using local time
+ lock :1, // - get a thread lock on a variable, subroutine, or method
+ 'log' :1, // - retrieve the natural logarithm for a number
+ lstat :1, // - stat a symbolic link
+ m :null, // - match a string with a regular expression pattern
+ map :1, // - apply a change to a list to get back a new list with the changes
+ mkdir :1, // - create a directory
+ msgctl :1, // - SysV IPC message control operations
+ msgget :1, // - get SysV IPC message queue
+ msgrcv :1, // - receive a SysV IPC message from a message queue
+ msgsnd :1, // - send a SysV IPC message to a message queue
+ my : 2, // - declare and assign a local variable (lexical scoping)
+ 'new' :1, //
+ next :1, // - iterate a block prematurely
+ no :1, // - unimport some module symbols or semantics at compile time
+ oct :1, // - convert a string to an octal number
+ open :1, // - open a file, pipe, or descriptor
+ opendir :1, // - open a directory
+ ord :1, // - find a character's numeric representation
+ our : 2, // - declare and assign a package variable (lexical scoping)
+ pack :1, // - convert a list into a binary representation
+ 'package' :1, // - declare a separate global namespace
+ pipe :1, // - open a pair of connected filehandles
+ pop :1, // - remove the last element from an array and return it
+ pos :1, // - find or set the offset for the last/next m//g search
+ print :1, // - output a list to a filehandle
+ printf :1, // - output a formatted list to a filehandle
+ prototype :1, // - get the prototype (if any) of a subroutine
+ push :1, // - append one or more elements to an array
+ q :null, // - singly quote a string
+ qq :null, // - doubly quote a string
+ qr :null, // - Compile pattern
+ quotemeta :null, // - quote regular expression magic characters
+ qw :null, // - quote a list of words
+ qx :null, // - backquote quote a string
+ rand :1, // - retrieve the next pseudorandom number
+ read :1, // - fixed-length buffered input from a filehandle
+ readdir :1, // - get a directory from a directory handle
+ readline :1, // - fetch a record from a file
+ readlink :1, // - determine where a symbolic link is pointing
+ readpipe :1, // - execute a system command and collect standard output
+ recv :1, // - receive a message over a Socket
+ redo :1, // - start this loop iteration over again
+ ref :1, // - find out the type of thing being referenced
+ rename :1, // - change a filename
+ require :1, // - load in external functions from a library at runtime
+ reset :1, // - clear all variables of a given name
+ 'return' :1, // - get out of a function early
+ reverse :1, // - flip a string or a list
+ rewinddir :1, // - reset directory handle
+ rindex :1, // - right-to-left substring search
+ rmdir :1, // - remove a directory
+ s :null, // - replace a pattern with a string
+ say :1, // - print with newline
+ scalar :1, // - force a scalar context
+ seek :1, // - reposition file pointer for random-access I/O
+ seekdir :1, // - reposition directory pointer
+ select :1, // - reset default output or do I/O multiplexing
+ semctl :1, // - SysV semaphore control operations
+ semget :1, // - get set of SysV semaphores
+ semop :1, // - SysV semaphore operations
+ send :1, // - send a message over a socket
+ setgrent :1, // - prepare group file for use
+ sethostent :1, // - prepare hosts file for use
+ setnetent :1, // - prepare networks file for use
+ setpgrp :1, // - set the process group of a process
+ setpriority :1, // - set a process's nice value
+ setprotoent :1, // - prepare protocols file for use
+ setpwent :1, // - prepare passwd file for use
+ setservent :1, // - prepare services file for use
+ setsockopt :1, // - set some socket options
+ shift :1, // - remove the first element of an array, and return it
+ shmctl :1, // - SysV shared memory operations
+ shmget :1, // - get SysV shared memory segment identifier
+ shmread :1, // - read SysV shared memory
+ shmwrite :1, // - write SysV shared memory
+ shutdown :1, // - close down just half of a socket connection
+ 'sin' :1, // - return the sine of a number
+ sleep :1, // - block for some number of seconds
+ socket :1, // - create a socket
+ socketpair :1, // - create a pair of sockets
+ 'sort' :1, // - sort a list of values
+ splice :1, // - add or remove elements anywhere in an array
+ 'split' :1, // - split up a string using a regexp delimiter
+ sprintf :1, // - formatted print into a string
+ 'sqrt' :1, // - square root function
+ srand :1, // - seed the random number generator
+ stat :1, // - get a file's status information
+ state :1, // - declare and assign a state variable (persistent lexical scoping)
+ study :1, // - optimize input data for repeated searches
+ 'sub' :1, // - declare a subroutine, possibly anonymously
+ 'substr' :1, // - get or alter a portion of a stirng
+ symlink :1, // - create a symbolic link to a file
+ syscall :1, // - execute an arbitrary system call
+ sysopen :1, // - open a file, pipe, or descriptor
+ sysread :1, // - fixed-length unbuffered input from a filehandle
+ sysseek :1, // - position I/O pointer on handle used with sysread and syswrite
+ system :1, // - run a separate program
+ syswrite :1, // - fixed-length unbuffered output to a filehandle
+ tell :1, // - get current seekpointer on a filehandle
+ telldir :1, // - get current seekpointer on a directory handle
+ tie :1, // - bind a variable to an object class
+ tied :1, // - get a reference to the object underlying a tied variable
+ time :1, // - return number of seconds since 1970
+ times :1, // - return elapsed time for self and child processes
+ tr :null, // - transliterate a string
+ truncate :1, // - shorten a file
+ uc :1, // - return upper-case version of a string
+ ucfirst :1, // - return a string with just the next letter in upper case
+ umask :1, // - set file creation mode mask
+ undef :1, // - remove a variable or function definition
+ unlink :1, // - remove one link to a file
+ unpack :1, // - convert binary structure into normal perl variables
+ unshift :1, // - prepend more elements to the beginning of a list
+ untie :1, // - break a tie binding to a variable
+ use :1, // - load in a module at compile time
+ utime :1, // - set a file's last access and modify times
+ values :1, // - return a list of the values in a hash
+ vec :1, // - test or set particular bits in a string
+ wait :1, // - wait for any child process to die
+ waitpid :1, // - wait for a particular child process to die
+ wantarray :1, // - get void vs scalar vs list context of current subroutine call
+ warn :1, // - print debugging info
+ when :1, //
+ write :1, // - print a picture record
+ y :null}; // - transliterate a string
+
+ var RXstyle="string-2";
+ var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type
+
+ function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;)
+ state.chain=null; // 12 3tail
+ state.style=null;
+ state.tail=null;
+ state.tokenize=function(stream,state){
+ var e=false,c,i=0;
+ while(c=stream.next()){
+ if(c===chain[i]&&!e){
+ if(chain[++i]!==undefined){
+ state.chain=chain[i];
+ state.style=style;
+ state.tail=tail}
+ else if(tail)
+ stream.eatWhile(tail);
+ state.tokenize=tokenPerl;
+ return style}
+ e=!e&&c=="\\"}
+ return style};
+ return state.tokenize(stream,state)}
+
+ function tokenSOMETHING(stream,state,string){
+ state.tokenize=function(stream,state){
+ if(stream.string==string)
+ state.tokenize=tokenPerl;
+ stream.skipToEnd();
+ return "string"};
+ return state.tokenize(stream,state)}
+
+ function tokenPerl(stream,state){
+ if(stream.eatSpace())
+ return null;
+ if(state.chain)
+ return tokenChain(stream,state,state.chain,state.style,state.tail);
+ if(stream.match(/^\-?[\d\.]/,false))
+ if(stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))
+ return 'number';
+ if(stream.match(/^<<(?=\w)/)){ // NOTE: <<SOMETHING\n...\nSOMETHING\n
+ stream.eatWhile(/\w/);
+ return tokenSOMETHING(stream,state,stream.current().substr(2))}
+ if(stream.sol()&&stream.match(/^\=item(?!\w)/)){// NOTE: \n=item...\n=cut\n
+ return tokenSOMETHING(stream,state,'=cut')}
+ var ch=stream.next();
+ if(ch=='"'||ch=="'"){ // NOTE: ' or " or <<'SOMETHING'\n...\nSOMETHING\n or <<"SOMETHING"\n...\nSOMETHING\n
+ if(stream.prefix(3)=="<<"+ch){
+ var p=stream.pos;
+ stream.eatWhile(/\w/);
+ var n=stream.current().substr(1);
+ if(n&&stream.eat(ch))
+ return tokenSOMETHING(stream,state,n);
+ stream.pos=p}
+ return tokenChain(stream,state,[ch],"string")}
+ if(ch=="q"){
+ var c=stream.look(-2);
+ if(!(c&&/\w/.test(c))){
+ c=stream.look(0);
+ if(c=="x"){
+ c=stream.look(1);
+ if(c=="("){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[")"],RXstyle,RXmodifiers)}
+ if(c=="["){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["]"],RXstyle,RXmodifiers)}
+ if(c=="{"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["}"],RXstyle,RXmodifiers)}
+ if(c=="<"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[">"],RXstyle,RXmodifiers)}
+ if(/[\^'"!~\/]/.test(c)){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers)}}
+ else if(c=="q"){
+ c=stream.look(1);
+ if(c=="("){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[")"],"string")}
+ if(c=="["){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["]"],"string")}
+ if(c=="{"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["}"],"string")}
+ if(c=="<"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[">"],"string")}
+ if(/[\^'"!~\/]/.test(c)){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[stream.eat(c)],"string")}}
+ else if(c=="w"){
+ c=stream.look(1);
+ if(c=="("){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[")"],"bracket")}
+ if(c=="["){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["]"],"bracket")}
+ if(c=="{"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["}"],"bracket")}
+ if(c=="<"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[">"],"bracket")}
+ if(/[\^'"!~\/]/.test(c)){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[stream.eat(c)],"bracket")}}
+ else if(c=="r"){
+ c=stream.look(1);
+ if(c=="("){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[")"],RXstyle,RXmodifiers)}
+ if(c=="["){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["]"],RXstyle,RXmodifiers)}
+ if(c=="{"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["}"],RXstyle,RXmodifiers)}
+ if(c=="<"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[">"],RXstyle,RXmodifiers)}
+ if(/[\^'"!~\/]/.test(c)){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers)}}
+ else if(/[\^'"!~\/(\[{<]/.test(c)){
+ if(c=="("){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[")"],"string")}
+ if(c=="["){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,["]"],"string")}
+ if(c=="{"){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,["}"],"string")}
+ if(c=="<"){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[">"],"string")}
+ if(/[\^'"!~\/]/.test(c)){
+ return tokenChain(stream,state,[stream.eat(c)],"string")}}}}
+ if(ch=="m"){
+ var c=stream.look(-2);
+ if(!(c&&/\w/.test(c))){
+ c=stream.eat(/[(\[{<\^'"!~\/]/);
+ if(c){
+ if(/[\^'"!~\/]/.test(c)){
+ return tokenChain(stream,state,[c],RXstyle,RXmodifiers)}
+ if(c=="("){
+ return tokenChain(stream,state,[")"],RXstyle,RXmodifiers)}
+ if(c=="["){
+ return tokenChain(stream,state,["]"],RXstyle,RXmodifiers)}
+ if(c=="{"){
+ return tokenChain(stream,state,["}"],RXstyle,RXmodifiers)}
+ if(c=="<"){
+ return tokenChain(stream,state,[">"],RXstyle,RXmodifiers)}}}}
+ if(ch=="s"){
+ var c=/[\/>\]})\w]/.test(stream.look(-2));
+ if(!c){
+ c=stream.eat(/[(\[{<\^'"!~\/]/);
+ if(c){
+ if(c=="[")
+ return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
+ if(c=="{")
+ return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
+ if(c=="<")
+ return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
+ if(c=="(")
+ return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
+ return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers)}}}
+ if(ch=="y"){
+ var c=/[\/>\]})\w]/.test(stream.look(-2));
+ if(!c){
+ c=stream.eat(/[(\[{<\^'"!~\/]/);
+ if(c){
+ if(c=="[")
+ return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
+ if(c=="{")
+ return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
+ if(c=="<")
+ return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
+ if(c=="(")
+ return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
+ return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers)}}}
+ if(ch=="t"){
+ var c=/[\/>\]})\w]/.test(stream.look(-2));
+ if(!c){
+ c=stream.eat("r");if(c){
+ c=stream.eat(/[(\[{<\^'"!~\/]/);
+ if(c){
+ if(c=="[")
+ return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
+ if(c=="{")
+ return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
+ if(c=="<")
+ return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
+ if(c=="(")
+ return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
+ return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers)}}}}
+ if(ch=="`"){
+ return tokenChain(stream,state,[ch],"variable-2")}
+ if(ch=="/"){
+ if(!/~\s*$/.test(stream.prefix()))
+ return "operator";
+ else
+ return tokenChain(stream,state,[ch],RXstyle,RXmodifiers)}
+ if(ch=="$"){
+ var p=stream.pos;
+ if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}"))
+ return "variable-2";
+ else
+ stream.pos=p}
+ if(/[$@%]/.test(ch)){
+ var p=stream.pos;
+ if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(stream.look(-2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){
+ var c=stream.current();
+ if(PERL[c])
+ return "variable-2"}
+ stream.pos=p}
+ if(/[$@%&]/.test(ch)){
+ if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){
+ var c=stream.current();
+ if(PERL[c])
+ return "variable-2";
+ else
+ return "variable"}}
+ if(ch=="#"){
+ if(stream.look(-2)!="$"){
+ stream.skipToEnd();
+ return "comment"}}
+ if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){
+ var p=stream.pos;
+ stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/);
+ if(PERL[stream.current()])
+ return "operator";
+ else
+ stream.pos=p}
+ if(ch=="_"){
+ if(stream.pos==1){
+ if(stream.suffix(6)=="_END__"){
+ return tokenChain(stream,state,['\0'],"comment")}
+ else if(stream.suffix(7)=="_DATA__"){
+ return tokenChain(stream,state,['\0'],"variable-2")}
+ else if(stream.suffix(7)=="_C__"){
+ return tokenChain(stream,state,['\0'],"string")}}}
+ if(/\w/.test(ch)){
+ var p=stream.pos;
+ if(stream.look(-2)=="{"&&(stream.look(0)=="}"||stream.eatWhile(/\w/)&&stream.look(0)=="}"))
+ return "string";
+ else
+ stream.pos=p}
+ if(/[A-Z]/.test(ch)){
+ var l=stream.look(-2);
+ var p=stream.pos;
+ stream.eatWhile(/[A-Z_]/);
+ if(/[\da-z]/.test(stream.look(0))){
+ stream.pos=p}
+ else{
+ var c=PERL[stream.current()];
+ if(!c)
+ return "meta";
+ if(c[1])
+ c=c[0];
+ if(l!=":"){
+ if(c==1)
+ return "keyword";
+ else if(c==2)
+ return "def";
+ else if(c==3)
+ return "atom";
+ else if(c==4)
+ return "operator";
+ else if(c==5)
+ return "variable-2";
+ else
+ return "meta"}
+ else
+ return "meta"}}
+ if(/[a-zA-Z_]/.test(ch)){
+ var l=stream.look(-2);
+ stream.eatWhile(/\w/);
+ var c=PERL[stream.current()];
+ if(!c)
+ return "meta";
+ if(c[1])
+ c=c[0];
+ if(l!=":"){
+ if(c==1)
+ return "keyword";
+ else if(c==2)
+ return "def";
+ else if(c==3)
+ return "atom";
+ else if(c==4)
+ return "operator";
+ else if(c==5)
+ return "variable-2";
+ else
+ return "meta"}
+ else
+ return "meta"}
+ return null}
+
+ return{
+ startState:function(){
+ return{
+ tokenize:tokenPerl,
+ chain:null,
+ style:null,
+ tail:null}},
+ token:function(stream,state){
+ return (state.tokenize||tokenPerl)(stream,state)},
+ electricChars:"{}"}});
+
+CodeMirror.defineMIME("text/x-perl", "perl");
+
+// it's like "peek", but need for look-ahead or look-behind if index < 0
+CodeMirror.StringStream.prototype.look=function(c){
+ return this.string.charAt(this.pos+(c||0))};
+
+// return a part of prefix of current stream from current position
+CodeMirror.StringStream.prototype.prefix=function(c){
+ if(c){
+ var x=this.pos-c;
+ return this.string.substr((x>=0?x:0),c)}
+ else{
+ return this.string.substr(0,this.pos-1)}};
+
+// return a part of suffix of current stream from current position
+CodeMirror.StringStream.prototype.suffix=function(c){
+ var y=this.string.length;
+ var x=y-this.pos+1;
+ return this.string.substr(this.pos,(c&&c<y?c:x))};
+
+// return a part of suffix of current stream from current position and change current position
+CodeMirror.StringStream.prototype.nsuffix=function(c){
+ var p=this.pos;
+ var l=c||(this.string.length-this.pos+1);
+ this.pos+=l;
+ return this.string.substr(p,l)};
+
+// eating and vomiting a part of stream from current position
+CodeMirror.StringStream.prototype.eatSuffix=function(c){
+ var x=this.pos+c;
+ var y;
+ if(x<=0)
+ this.pos=0;
+ else if(x>=(y=this.string.length-1))
+ this.pos=y;
+ else
+ this.pos=x};
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/php/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/php/index.html
new file mode 100644
index 0000000..7949044
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/php/index.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: PHP mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="../xml/xml.js"></script>
+ <script src="../javascript/javascript.js"></script>
+ <script src="../css/css.js"></script>
+ <script src="../clike/clike.js"></script>
+ <script src="php.js"></script>
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: PHP mode</h1>
+
+<form><textarea id="code" name="code">
+<?php
+function hello($who) {
+ return "Hello " . $who;
+}
+?>
+<p>The program says <?= hello("World") ?>.</p>
+<script>
+ alert("And here is some JS code"); // also colored
+</script>
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ mode: "application/x-httpd-php",
+ indentUnit: 4,
+ indentWithTabs: true,
+ enterMode: "keep",
+ tabMode: "shift"
+ });
+ </script>
+
+ <p>Simple HTML/PHP mode based on
+ the <a href="../clike/">C-like</a> mode. Depends on XML,
+ JavaScript, CSS, and C-like modes.</p>
+
+ <p><strong>MIME types defined:</strong> <code>application/x-httpd-php</code> (HTML with PHP code), <code>text/x-php</code> (plain, non-wrapped PHP code).</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/php/php.js b/codemirror_ui/lib/CodeMirror-2.3/mode/php/php.js
new file mode 100644
index 0000000..e35922f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/php/php.js
@@ -0,0 +1,150 @@
+(function() {
+ function keywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+ function heredoc(delim) {
+ return function(stream, state) {
+ if (stream.match(delim)) state.tokenize = null;
+ else stream.skipToEnd();
+ return "string";
+ }
+ }
+ var phpConfig = {
+ name: "clike",
+ keywords: keywords("abstract and array as break case catch class clone const continue declare default " +
+ "do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " +
+ "for foreach function global goto if implements interface instanceof namespace " +
+ "new or private protected public static switch throw trait try use var while xor " +
+ "die echo empty exit eval include include_once isset list require require_once return " +
+ "print unset __halt_compiler self static parent"),
+ blockKeywords: keywords("catch do else elseif for foreach if switch try while"),
+ atoms: keywords("true false null TRUE FALSE NULL"),
+ multiLineStrings: true,
+ hooks: {
+ "$": function(stream, state) {
+ stream.eatWhile(/[\w\$_]/);
+ return "variable-2";
+ },
+ "<": function(stream, state) {
+ if (stream.match(/<</)) {
+ stream.eatWhile(/[\w\.]/);
+ state.tokenize = heredoc(stream.current().slice(3));
+ return state.tokenize(stream, state);
+ }
+ return false;
+ },
+ "#": function(stream, state) {
+ while (!stream.eol() && !stream.match("?>", false)) stream.next();
+ return "comment";
+ },
+ "/": function(stream, state) {
+ if (stream.eat("/")) {
+ while (!stream.eol() && !stream.match("?>", false)) stream.next();
+ return "comment";
+ }
+ return false;
+ }
+ }
+ };
+
+ CodeMirror.defineMode("php", function(config, parserConfig) {
+ var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
+ var jsMode = CodeMirror.getMode(config, "javascript");
+ var cssMode = CodeMirror.getMode(config, "css");
+ var phpMode = CodeMirror.getMode(config, phpConfig);
+
+ function dispatch(stream, state) { // TODO open PHP inside text/css
+ var isPHP = state.mode == "php";
+ if (stream.sol() && state.pending != '"') state.pending = null;
+ if (state.curMode == htmlMode) {
+ if (stream.match(/^<\?\w*/)) {
+ state.curMode = phpMode;
+ state.curState = state.php;
+ state.curClose = "?>";
+ state.mode = "php";
+ return "meta";
+ }
+ if (state.pending == '"') {
+ while (!stream.eol() && stream.next() != '"') {}
+ var style = "string";
+ } else if (state.pending && stream.pos < state.pending.end) {
+ stream.pos = state.pending.end;
+ var style = state.pending.style;
+ } else {
+ var style = htmlMode.token(stream, state.curState);
+ }
+ state.pending = null;
+ var cur = stream.current(), openPHP = cur.search(/<\?/);
+ if (openPHP != -1) {
+ if (style == "string" && /\"$/.test(cur) && !/\?>/.test(cur)) state.pending = '"';
+ else state.pending = {end: stream.pos, style: style};
+ stream.backUp(cur.length - openPHP);
+ } else if (style == "tag" && stream.current() == ">" && state.curState.context) {
+ if (/^script$/i.test(state.curState.context.tagName)) {
+ state.curMode = jsMode;
+ state.curState = jsMode.startState(htmlMode.indent(state.curState, ""));
+ state.curClose = /^<\/\s*script\s*>/i;
+ state.mode = "javascript";
+ }
+ else if (/^style$/i.test(state.curState.context.tagName)) {
+ state.curMode = cssMode;
+ state.curState = cssMode.startState(htmlMode.indent(state.curState, ""));
+ state.curClose = /^<\/\s*style\s*>/i;
+ state.mode = "css";
+ }
+ }
+ return style;
+ } else if ((!isPHP || state.php.tokenize == null) &&
+ stream.match(state.curClose, isPHP)) {
+ state.curMode = htmlMode;
+ state.curState = state.html;
+ state.curClose = null;
+ state.mode = "html";
+ if (isPHP) return "meta";
+ else return dispatch(stream, state);
+ } else {
+ return state.curMode.token(stream, state.curState);
+ }
+ }
+
+ return {
+ startState: function() {
+ var html = htmlMode.startState();
+ return {html: html,
+ php: phpMode.startState(),
+ curMode: parserConfig.startOpen ? phpMode : htmlMode,
+ curState: parserConfig.startOpen ? phpMode.startState() : html,
+ curClose: parserConfig.startOpen ? /^\?>/ : null,
+ mode: parserConfig.startOpen ? "php" : "html",
+ pending: null}
+ },
+
+ copyState: function(state) {
+ var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html),
+ php = state.php, phpNew = CodeMirror.copyState(phpMode, php), cur;
+ if (state.curState == html) cur = htmlNew;
+ else if (state.curState == php) cur = phpNew;
+ else cur = CodeMirror.copyState(state.curMode, state.curState);
+ return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur,
+ curClose: state.curClose, mode: state.mode,
+ pending: state.pending};
+ },
+
+ token: dispatch,
+
+ indent: function(state, textAfter) {
+ if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
+ (state.curMode == phpMode && /^\?>/.test(textAfter)))
+ return htmlMode.indent(state.html, textAfter);
+ return state.curMode.indent(state.curState, textAfter);
+ },
+
+ electricChars: "/{}:"
+ }
+ }, "xml", "clike", "javascript", "css");
+ CodeMirror.defineMIME("application/x-httpd-php", "php");
+ CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true});
+ CodeMirror.defineMIME("text/x-php", phpConfig);
+})();
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/pig/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/pig/index.html
new file mode 100644
index 0000000..9cd69c4
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/pig/index.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Pig Latin mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="pig.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>.CodeMirror {border: 2px inset #dee;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Pig Latin mode</h1>
+
+<form><textarea id="code" name="code">
+-- Apache Pig (Pig Latin Language) Demo
+/*
+This is a multiline comment.
+*/
+a = LOAD "\path\to\input" USING PigStorage('\t') AS (x:long, y:chararray, z:bytearray);
+b = GROUP a BY (x,y,3+4);
+c = FOREACH b GENERATE flatten(group) as (x,y), SUM(group.$2) as z;
+STORE c INTO "\path\to\output";
+
+--
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ indentUnit: 4,
+ mode: "text/x-pig"
+ });
+ </script>
+
+ <p>
+ Simple mode that handles Pig Latin language.
+ </p>
+
+ <p><strong>MIME type defined:</strong> <code>text/x-pig</code>
+ (PIG code)
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/pig/pig.js b/codemirror_ui/lib/CodeMirror-2.3/mode/pig/pig.js
new file mode 100644
index 0000000..b7399b4
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/pig/pig.js
@@ -0,0 +1,172 @@
+/*
+ * Pig Latin Mode for CodeMirror 2
+ * @author Prasanth Jayachandran
+ * @link https://github.com/prasanthj/pig-codemirror-2
+ * This implementation is adapted from PL/SQL mode in CodeMirror 2.
+*/
+CodeMirror.defineMode("pig", function(config, parserConfig) {
+ var indentUnit = config.indentUnit,
+ keywords = parserConfig.keywords,
+ builtins = parserConfig.builtins,
+ types = parserConfig.types,
+ multiLineStrings = parserConfig.multiLineStrings;
+
+ var isOperatorChar = /[*+\-%<>=&?:\/!|]/;
+
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ var type;
+ function ret(tp, style) {
+ type = tp;
+ return style;
+ }
+
+ function tokenComment(stream, state) {
+ var isEnd = false;
+ var ch;
+ while(ch = stream.next()) {
+ if(ch == "/" && isEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ isEnd = (ch == "*");
+ }
+ return ret("comment", "comment");
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while((next = stream.next()) != null) {
+ if (next == quote && !escaped) {
+ end = true; break;
+ }
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = tokenBase;
+ return ret("string", "error");
+ };
+ }
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+
+ // is a start of string?
+ if (ch == '"' || ch == "'")
+ return chain(stream, state, tokenString(ch));
+ // is it one of the special chars
+ else if(/[\[\]{}\(\),;\.]/.test(ch))
+ return ret(ch);
+ // is it a number?
+ else if(/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return ret("number", "number");
+ }
+ // multi line comment or operator
+ else if (ch == "/") {
+ if (stream.eat("*")) {
+ return chain(stream, state, tokenComment);
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // single line comment or operator
+ else if (ch=="-") {
+ if(stream.eat("-")){
+ stream.skipToEnd();
+ return ret("comment", "comment");
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // is it an operator
+ else if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ else {
+ // get the while word
+ stream.eatWhile(/[\w\$_]/);
+ // is it one of the listed keywords?
+ if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) {
+ if (stream.eat(")") || stream.eat(".")) {
+ //keywords can be used as variables like flatten(group), group.$0 etc..
+ }
+ else {
+ return ("keyword", "keyword");
+ }
+ }
+ // is it one of the builtin functions?
+ if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase()))
+ {
+ return ("keyword", "variable-2")
+ }
+ // is it one of the listed types?
+ if (types && types.propertyIsEnumerable(stream.current().toUpperCase()))
+ return ("keyword", "variable-3")
+ // default is a 'word'
+ return ret("word", "pig-word");
+ }
+ }
+
+ // Interface
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: tokenBase,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ if(stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ }
+ };
+});
+
+(function() {
+ function keywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+
+ // builtin funcs taken from trunk revision 1303237
+ var pBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
+ + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
+ + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
+ + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
+ + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER "
+ + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS "
+ + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
+ + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
+ + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
+ + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER ";
+
+ // taken from QueryLexer.g
+ var pKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
+ + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
+ + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
+ + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
+ + "NEQ MATCHES TRUE FALSE ";
+
+ // data types
+ var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP "
+
+ CodeMirror.defineMIME("text/x-pig", {
+ name: "pig",
+ builtins: keywords(pBuiltins),
+ keywords: keywords(pKeywords),
+ types: keywords(pTypes)
+ });
+}());
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/plsql/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/plsql/index.html
new file mode 100644
index 0000000..be603d9
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/plsql/index.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Oracle PL/SQL mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="plsql.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>.CodeMirror {border: 2px inset #dee;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Oracle PL/SQL mode</h1>
+
+<form><textarea id="code" name="code">
+-- Oracle PL/SQL Code Demo
+/*
+ based on c-like mode, adapted to PL/SQL by Peter Raganitsch ( http://www.oracle-and-apex.com/ )
+ April 2011
+*/
+DECLARE
+ vIdx NUMBER;
+ vString VARCHAR2(100);
+ cText CONSTANT VARCHAR2(100) := 'That''s it! Have fun with CodeMirror 2';
+BEGIN
+ vIdx := 0;
+ --
+ FOR rDATA IN
+ ( SELECT *
+ FROM EMP
+ ORDER BY EMPNO
+ )
+ LOOP
+ vIdx := vIdx + 1;
+ vString := rDATA.EMPNO || ' - ' || rDATA.ENAME;
+ --
+ UPDATE EMP
+ SET SAL = SAL * 101/100
+ WHERE EMPNO = rDATA.EMPNO
+ ;
+ END LOOP;
+ --
+ SYS.DBMS_OUTPUT.Put_Line (cText);
+END;
+--
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ indentUnit: 4,
+ mode: "text/x-plsql"
+ });
+ </script>
+
+ <p>
+ Simple mode that handles Oracle PL/SQL language (and Oracle SQL, of course).
+ </p>
+
+ <p><strong>MIME type defined:</strong> <code>text/x-plsql</code>
+ (PLSQL code)
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/plsql/plsql.js b/codemirror_ui/lib/CodeMirror-2.3/mode/plsql/plsql.js
new file mode 100644
index 0000000..a2ac2e8
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/plsql/plsql.js
@@ -0,0 +1,217 @@
+CodeMirror.defineMode("plsql", function(config, parserConfig) {
+ var indentUnit = config.indentUnit,
+ keywords = parserConfig.keywords,
+ functions = parserConfig.functions,
+ types = parserConfig.types,
+ sqlplus = parserConfig.sqlplus,
+ multiLineStrings = parserConfig.multiLineStrings;
+ var isOperatorChar = /[+\-*&%=<>!?:\/|]/;
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ var type;
+ function ret(tp, style) {
+ type = tp;
+ return style;
+ }
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ // start of string?
+ if (ch == '"' || ch == "'")
+ return chain(stream, state, tokenString(ch));
+ // is it one of the special signs []{}().,;? Seperator?
+ else if (/[\[\]{}\(\),;\.]/.test(ch))
+ return ret(ch);
+ // start of a number value?
+ else if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return ret("number", "number");
+ }
+ // multi line comment or simple operator?
+ else if (ch == "/") {
+ if (stream.eat("*")) {
+ return chain(stream, state, tokenComment);
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // single line comment or simple operator?
+ else if (ch == "-") {
+ if (stream.eat("-")) {
+ stream.skipToEnd();
+ return ret("comment", "comment");
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // pl/sql variable?
+ else if (ch == "@" || ch == "$") {
+ stream.eatWhile(/[\w\d\$_]/);
+ return ret("word", "variable");
+ }
+ // is it a operator?
+ else if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ else {
+ // get the whole word
+ stream.eatWhile(/[\w\$_]/);
+ // is it one of the listed keywords?
+ if (keywords && keywords.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "keyword");
+ // is it one of the listed functions?
+ if (functions && functions.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "builtin");
+ // is it one of the listed types?
+ if (types && types.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-2");
+ // is it one of the listed sqlplus keywords?
+ if (sqlplus && sqlplus.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-3");
+ // default: just a "word"
+ return ret("word", "plsql-word");
+ }
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {end = true; break;}
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = tokenBase;
+ return ret("string", "plsql-string");
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return ret("comment", "plsql-comment");
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: tokenBase,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ }
+ };
+});
+
+(function() {
+ function keywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+ var cKeywords = "abort accept access add all alter and any array arraylen as asc assert assign at attributes audit " +
+ "authorization avg " +
+ "base_table begin between binary_integer body boolean by " +
+ "case cast char char_base check close cluster clusters colauth column comment commit compress connect " +
+ "connected constant constraint crash create current currval cursor " +
+ "data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete " +
+ "desc digits dispose distinct do drop " +
+ "else elsif enable end entry escape exception exception_init exchange exclusive exists exit external " +
+ "fast fetch file for force form from function " +
+ "generic goto grant group " +
+ "having " +
+ "identified if immediate in increment index indexes indicator initial initrans insert interface intersect " +
+ "into is " +
+ "key " +
+ "level library like limited local lock log logging long loop " +
+ "master maxextents maxtrans member minextents minus mislabel mode modify multiset " +
+ "new next no noaudit nocompress nologging noparallel not nowait number_base " +
+ "object of off offline on online only open option or order out " +
+ "package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior " +
+ "private privileges procedure public " +
+ "raise range raw read rebuild record ref references refresh release rename replace resource restrict return " +
+ "returning reverse revoke rollback row rowid rowlabel rownum rows run " +
+ "savepoint schema segment select separate session set share snapshot some space split sql start statement " +
+ "storage subtype successful synonym " +
+ "tabauth table tables tablespace task terminate then to trigger truncate type " +
+ "union unique unlimited unrecoverable unusable update use using " +
+ "validate value values variable view views " +
+ "when whenever where while with work";
+
+ var cFunctions = "abs acos add_months ascii asin atan atan2 average " +
+ "bfilename " +
+ "ceil chartorowid chr concat convert cos cosh count " +
+ "decode deref dual dump dup_val_on_index " +
+ "empty error exp " +
+ "false floor found " +
+ "glb greatest " +
+ "hextoraw " +
+ "initcap instr instrb isopen " +
+ "last_day least lenght lenghtb ln lower lpad ltrim lub " +
+ "make_ref max min mod months_between " +
+ "new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower " +
+ "nls_sort nls_upper nlssort no_data_found notfound null nvl " +
+ "others " +
+ "power " +
+ "rawtohex reftohex round rowcount rowidtochar rpad rtrim " +
+ "sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate " +
+ "tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc " +
+ "uid upper user userenv " +
+ "variance vsize";
+
+ var cTypes = "bfile blob " +
+ "character clob " +
+ "dec " +
+ "float " +
+ "int integer " +
+ "mlslabel " +
+ "natural naturaln nchar nclob number numeric nvarchar2 " +
+ "real rowtype " +
+ "signtype smallint string " +
+ "varchar varchar2";
+
+ var cSqlplus = "appinfo arraysize autocommit autoprint autorecovery autotrace " +
+ "blockterminator break btitle " +
+ "cmdsep colsep compatibility compute concat copycommit copytypecheck " +
+ "define describe " +
+ "echo editfile embedded escape exec execute " +
+ "feedback flagger flush " +
+ "heading headsep " +
+ "instance " +
+ "linesize lno loboffset logsource long longchunksize " +
+ "markup " +
+ "native newpage numformat numwidth " +
+ "pagesize pause pno " +
+ "recsep recsepchar release repfooter repheader " +
+ "serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber " +
+ "sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix " +
+ "tab term termout time timing trimout trimspool ttitle " +
+ "underline " +
+ "verify version " +
+ "wrap";
+
+ CodeMirror.defineMIME("text/x-plsql", {
+ name: "plsql",
+ keywords: keywords(cKeywords),
+ functions: keywords(cFunctions),
+ types: keywords(cTypes),
+ sqlplus: keywords(cSqlplus)
+ });
+}());
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/properties/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/properties/index.html
new file mode 100644
index 0000000..4f0c269
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/properties/index.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Properties files mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="properties.js"></script>
+ <style>.CodeMirror {border-top: 1px solid #ddd; border-bottom: 1px solid #ddd;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Properties files mode</h1>
+ <form><textarea id="code" name="code">
+# This is a properties file
+a.key = A value
+another.key = http://example.com
+! Exclamation mark as comment
+but.not=Within ! A value # indeed
+ # Spaces at the beginning of a line
+ spaces.before.key=value
+backslash=Used for multi\
+ line entries,\
+ that's convenient.
+# Unicode sequences
+unicode.key=This is \u0020 Unicode
+no.multiline=here
+# Colons
+colons : can be used too
+# Spaces
+spaces\ in\ keys=Not very common...
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-properties</code>,
+ <code>text/x-ini</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/properties/properties.js b/codemirror_ui/lib/CodeMirror-2.3/mode/properties/properties.js
new file mode 100644
index 0000000..d3a13c7
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/properties/properties.js
@@ -0,0 +1,63 @@
+CodeMirror.defineMode("properties", function() {
+ return {
+ token: function(stream, state) {
+ var sol = stream.sol() || state.afterSection;
+ var eol = stream.eol();
+
+ state.afterSection = false;
+
+ if (sol) {
+ if (state.nextMultiline) {
+ state.inMultiline = true;
+ state.nextMultiline = false;
+ } else {
+ state.position = "def";
+ }
+ }
+
+ if (eol && ! state.nextMultiline) {
+ state.inMultiline = false;
+ state.position = "def";
+ }
+
+ if (sol) {
+ while(stream.eatSpace());
+ }
+
+ var ch = stream.next();
+
+ if (sol && (ch === "#" || ch === "!" || ch === ";")) {
+ state.position = "comment";
+ stream.skipToEnd();
+ return "comment";
+ } else if (sol && ch === "[") {
+ state.afterSection = true;
+ stream.skipTo("]"); stream.eat("]");
+ return "header";
+ } else if (ch === "=" || ch === ":") {
+ state.position = "quote";
+ return null;
+ } else if (ch === "\\" && state.position === "quote") {
+ if (stream.next() !== "u") { // u = Unicode sequence \u1234
+ // Multiline value
+ state.nextMultiline = true;
+ }
+ }
+
+ return state.position;
+ },
+
+ startState: function() {
+ return {
+ position : "def", // Current position, "def", "quote" or "comment"
+ nextMultiline : false, // Is the next line multiline value
+ inMultiline : false, // Is the current line a multiline value
+ afterSection : false // Did we just open a section
+ };
+ }
+
+ };
+});
+
+CodeMirror.defineMIME("text/x-properties", "properties");
+CodeMirror.defineMIME("text/x-ini", "properties");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/python/LICENSE.txt b/codemirror_ui/lib/CodeMirror-2.3/mode/python/LICENSE.txt
new file mode 100644
index 0000000..918866b
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/python/LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2010 Timothy Farrell
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. \ No newline at end of file
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/python/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/python/index.html
new file mode 100644
index 0000000..47e0e9d
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/python/index.html
@@ -0,0 +1,122 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Python mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="python.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Python mode</h1>
+
+ <div><textarea id="code" name="code">
+# Literals
+1234
+0.0e101
+.123
+0b01010011100
+0o01234567
+0x0987654321abcdef
+7
+2147483647
+3L
+79228162514264337593543950336L
+0x100000000L
+79228162514264337593543950336
+0xdeadbeef
+3.14j
+10.j
+10j
+.001j
+1e100j
+3.14e-10j
+
+
+# String Literals
+'For\''
+"God\""
+"""so loved
+the world"""
+'''that he gave
+his only begotten\' '''
+'that whosoever believeth \
+in him'
+''
+
+# Identifiers
+__a__
+a.b
+a.b.c
+
+# Operators
++ - * / % & | ^ ~ < >
+== != <= >= <> << >> // **
+and or not in is
+
+# Delimiters
+() [] {} , : ` = ; @ . # Note that @ and . require the proper context.
++= -= *= /= %= &= |= ^=
+//= >>= <<= **=
+
+# Keywords
+as assert break class continue def del elif else except
+finally for from global if import lambda pass raise
+return try while with yield
+
+# Python 2 Keywords (otherwise Identifiers)
+exec print
+
+# Python 3 Keywords (otherwise Identifiers)
+nonlocal
+
+# Types
+bool classmethod complex dict enumerate float frozenset int list object
+property reversed set slice staticmethod str super tuple type
+
+# Python 2 Types (otherwise Identifiers)
+basestring buffer file long unicode xrange
+
+# Python 3 Types (otherwise Identifiers)
+bytearray bytes filter map memoryview open range zip
+
+# Some Example code
+import os
+from package import ParentClass
+
+@nonsenseDecorator
+def doesNothing():
+ pass
+
+class ExampleClass(ParentClass):
+ @staticmethod
+ def example(inputStr):
+ a = list(inputStr)
+ a.reverse()
+ return ''.join(a)
+
+ def __init__(self, mixin = 'Hello'):
+ self.mixin = mixin
+
+</textarea></div>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: {name: "python",
+ version: 2,
+ singleLineStringErrors: false},
+ lineNumbers: true,
+ indentUnit: 4,
+ tabMode: "shift",
+ matchBrackets: true
+ });
+ </script>
+ <h2>Configuration Options:</h2>
+ <ul>
+ <li>version - 2/3 - The version of Python to recognize. Default is 2.</li>
+ <li>singleLineStringErrors - true/false - If you have a single-line string that is not terminated at the end of the line, this will show subsequent lines as errors if true, otherwise it will consider the newline as the end of the string. Default is false.</li>
+ </ul>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-python</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/python/python.js b/codemirror_ui/lib/CodeMirror-2.3/mode/python/python.js
new file mode 100644
index 0000000..d6888e8
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/python/python.js
@@ -0,0 +1,338 @@
+CodeMirror.defineMode("python", function(conf, parserConf) {
+ var ERRORCLASS = 'error';
+
+ function wordRegexp(words) {
+ return new RegExp("^((" + words.join(")|(") + "))\\b");
+ }
+
+ var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
+ var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
+ var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
+ var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
+ var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
+ var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
+
+ var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
+ var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
+ 'def', 'del', 'elif', 'else', 'except', 'finally',
+ 'for', 'from', 'global', 'if', 'import',
+ 'lambda', 'pass', 'raise', 'return',
+ 'try', 'while', 'with', 'yield'];
+ var commonBuiltins = ['abs', 'all', 'any', 'bin', 'bool', 'bytearray', 'callable', 'chr',
+ 'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
+ 'enumerate', 'eval', 'filter', 'float', 'format', 'frozenset',
+ 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id',
+ 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len',
+ 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next',
+ 'object', 'oct', 'open', 'ord', 'pow', 'property', 'range',
+ 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
+ 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple',
+ 'type', 'vars', 'zip', '__import__', 'NotImplemented',
+ 'Ellipsis', '__debug__'];
+ var py2 = {'builtins': ['apply', 'basestring', 'buffer', 'cmp', 'coerce', 'execfile',
+ 'file', 'intern', 'long', 'raw_input', 'reduce', 'reload',
+ 'unichr', 'unicode', 'xrange', 'False', 'True', 'None'],
+ 'keywords': ['exec', 'print']};
+ var py3 = {'builtins': ['ascii', 'bytes', 'exec', 'print'],
+ 'keywords': ['nonlocal', 'False', 'True', 'None']};
+
+ if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) {
+ commonkeywords = commonkeywords.concat(py3.keywords);
+ commonBuiltins = commonBuiltins.concat(py3.builtins);
+ var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
+ } else {
+ commonkeywords = commonkeywords.concat(py2.keywords);
+ commonBuiltins = commonBuiltins.concat(py2.builtins);
+ var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
+ }
+ var keywords = wordRegexp(commonkeywords);
+ var builtins = wordRegexp(commonBuiltins);
+
+ var indentInfo = null;
+
+ // tokenizers
+ function tokenBase(stream, state) {
+ // Handle scope changes
+ if (stream.sol()) {
+ var scopeOffset = state.scopes[0].offset;
+ if (stream.eatSpace()) {
+ var lineOffset = stream.indentation();
+ if (lineOffset > scopeOffset) {
+ indentInfo = 'indent';
+ } else if (lineOffset < scopeOffset) {
+ indentInfo = 'dedent';
+ }
+ return null;
+ } else {
+ if (scopeOffset > 0) {
+ dedent(stream, state);
+ }
+ }
+ }
+ if (stream.eatSpace()) {
+ return null;
+ }
+
+ var ch = stream.peek();
+
+ // Handle Comments
+ if (ch === '#') {
+ stream.skipToEnd();
+ return 'comment';
+ }
+
+ // Handle Number Literals
+ if (stream.match(/^[0-9\.]/, false)) {
+ var floatLiteral = false;
+ // Floats
+ if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
+ if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
+ if (stream.match(/^\.\d+/)) { floatLiteral = true; }
+ if (floatLiteral) {
+ // Float literals may be "imaginary"
+ stream.eat(/J/i);
+ return 'number';
+ }
+ // Integers
+ var intLiteral = false;
+ // Hex
+ if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
+ // Binary
+ if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
+ // Octal
+ if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
+ // Decimal
+ if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
+ // Decimal literals may be "imaginary"
+ stream.eat(/J/i);
+ // TODO - Can you have imaginary longs?
+ intLiteral = true;
+ }
+ // Zero by itself with no other piece of number.
+ if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
+ if (intLiteral) {
+ // Integer literals may be "long"
+ stream.eat(/L/i);
+ return 'number';
+ }
+ }
+
+ // Handle Strings
+ if (stream.match(stringPrefixes)) {
+ state.tokenize = tokenStringFactory(stream.current());
+ return state.tokenize(stream, state);
+ }
+
+ // Handle operators and Delimiters
+ if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
+ return null;
+ }
+ if (stream.match(doubleOperators)
+ || stream.match(singleOperators)
+ || stream.match(wordOperators)) {
+ return 'operator';
+ }
+ if (stream.match(singleDelimiters)) {
+ return null;
+ }
+
+ if (stream.match(keywords)) {
+ return 'keyword';
+ }
+
+ if (stream.match(builtins)) {
+ return 'builtin';
+ }
+
+ if (stream.match(identifiers)) {
+ return 'variable';
+ }
+
+ // Handle non-detected items
+ stream.next();
+ return ERRORCLASS;
+ }
+
+ function tokenStringFactory(delimiter) {
+ while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {
+ delimiter = delimiter.substr(1);
+ }
+ var singleline = delimiter.length == 1;
+ var OUTCLASS = 'string';
+
+ return function tokenString(stream, state) {
+ while (!stream.eol()) {
+ stream.eatWhile(/[^'"\\]/);
+ if (stream.eat('\\')) {
+ stream.next();
+ if (singleline && stream.eol()) {
+ return OUTCLASS;
+ }
+ } else if (stream.match(delimiter)) {
+ state.tokenize = tokenBase;
+ return OUTCLASS;
+ } else {
+ stream.eat(/['"]/);
+ }
+ }
+ if (singleline) {
+ if (parserConf.singleLineStringErrors) {
+ return ERRORCLASS;
+ } else {
+ state.tokenize = tokenBase;
+ }
+ }
+ return OUTCLASS;
+ };
+ }
+
+ function indent(stream, state, type) {
+ type = type || 'py';
+ var indentUnit = 0;
+ if (type === 'py') {
+ if (state.scopes[0].type !== 'py') {
+ state.scopes[0].offset = stream.indentation();
+ return;
+ }
+ for (var i = 0; i < state.scopes.length; ++i) {
+ if (state.scopes[i].type === 'py') {
+ indentUnit = state.scopes[i].offset + conf.indentUnit;
+ break;
+ }
+ }
+ } else {
+ indentUnit = stream.column() + stream.current().length;
+ }
+ state.scopes.unshift({
+ offset: indentUnit,
+ type: type
+ });
+ }
+
+ function dedent(stream, state, type) {
+ type = type || 'py';
+ if (state.scopes.length == 1) return;
+ if (state.scopes[0].type === 'py') {
+ var _indent = stream.indentation();
+ var _indent_index = -1;
+ for (var i = 0; i < state.scopes.length; ++i) {
+ if (_indent === state.scopes[i].offset) {
+ _indent_index = i;
+ break;
+ }
+ }
+ if (_indent_index === -1) {
+ return true;
+ }
+ while (state.scopes[0].offset !== _indent) {
+ state.scopes.shift();
+ }
+ return false
+ } else {
+ if (type === 'py') {
+ state.scopes[0].offset = stream.indentation();
+ return false;
+ } else {
+ if (state.scopes[0].type != type) {
+ return true;
+ }
+ state.scopes.shift();
+ return false;
+ }
+ }
+ }
+
+ function tokenLexer(stream, state) {
+ indentInfo = null;
+ var style = state.tokenize(stream, state);
+ var current = stream.current();
+
+ // Handle '.' connected identifiers
+ if (current === '.') {
+ style = stream.match(identifiers, false) ? null : ERRORCLASS;
+ if (style === null && state.lastToken === 'meta') {
+ // Apply 'meta' style to '.' connected identifiers when
+ // appropriate.
+ style = 'meta';
+ }
+ return style;
+ }
+
+ // Handle decorators
+ if (current === '@') {
+ return stream.match(identifiers, false) ? 'meta' : ERRORCLASS;
+ }
+
+ if ((style === 'variable' || style === 'builtin')
+ && state.lastToken === 'meta') {
+ style = 'meta';
+ }
+
+ // Handle scope changes.
+ if (current === 'pass' || current === 'return') {
+ state.dedent += 1;
+ }
+ if (current === 'lambda') state.lambda = true;
+ if ((current === ':' && !state.lambda && state.scopes[0].type == 'py')
+ || indentInfo === 'indent') {
+ indent(stream, state);
+ }
+ var delimiter_index = '[({'.indexOf(current);
+ if (delimiter_index !== -1) {
+ indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
+ }
+ if (indentInfo === 'dedent') {
+ if (dedent(stream, state)) {
+ return ERRORCLASS;
+ }
+ }
+ delimiter_index = '])}'.indexOf(current);
+ if (delimiter_index !== -1) {
+ if (dedent(stream, state, current)) {
+ return ERRORCLASS;
+ }
+ }
+ if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
+ if (state.scopes.length > 1) state.scopes.shift();
+ state.dedent -= 1;
+ }
+
+ return style;
+ }
+
+ var external = {
+ startState: function(basecolumn) {
+ return {
+ tokenize: tokenBase,
+ scopes: [{offset:basecolumn || 0, type:'py'}],
+ lastToken: null,
+ lambda: false,
+ dedent: 0
+ };
+ },
+
+ token: function(stream, state) {
+ var style = tokenLexer(stream, state);
+
+ state.lastToken = style;
+
+ if (stream.eol() && stream.lambda) {
+ state.lambda = false;
+ }
+
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != tokenBase) {
+ return 0;
+ }
+
+ return state.scopes[0].offset;
+ }
+
+ };
+ return external;
+});
+
+CodeMirror.defineMIME("text/x-python", "python");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/r/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/r/index.html
new file mode 100644
index 0000000..6977505
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/r/index.html
@@ -0,0 +1,73 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: R mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="r.js"></script>
+ <style>
+ .CodeMirror { border-top: 1px solid silver; border-bottom: 1px solid silver; }
+ .cm-s-default span.cm-semi { color: blue; font-weight: bold; }
+ .cm-s-default span.cm-dollar { color: orange; font-weight: bold; }
+ .cm-s-default span.cm-arrow { color: brown; }
+ .cm-s-default span.cm-arg-is { color: brown; }
+ </style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: R mode</h1>
+ <form><textarea id="code" name="code">
+# Code from http://www.mayin.org/ajayshah/KB/R/
+
+# FIRST LEARN ABOUT LISTS --
+X = list(height=5.4, weight=54)
+print("Use default printing --")
+print(X)
+print("Accessing individual elements --")
+cat("Your height is ", X$height, " and your weight is ", X$weight, "\n")
+
+# FUNCTIONS --
+square <- function(x) {
+ return(x*x)
+}
+cat("The square of 3 is ", square(3), "\n")
+
+ # default value of the arg is set to 5.
+cube <- function(x=5) {
+ return(x*x*x);
+}
+cat("Calling cube with 2 : ", cube(2), "\n") # will give 2^3
+cat("Calling cube : ", cube(), "\n") # will default to 5^3.
+
+# LEARN ABOUT FUNCTIONS THAT RETURN MULTIPLE OBJECTS --
+powers <- function(x) {
+ parcel = list(x2=x*x, x3=x*x*x, x4=x*x*x*x);
+ return(parcel);
+}
+
+X = powers(3);
+print("Showing powers of 3 --"); print(X);
+
+# WRITING THIS COMPACTLY (4 lines instead of 7)
+
+powerful <- function(x) {
+ return(list(x2=x*x, x3=x*x*x, x4=x*x*x*x));
+}
+print("Showing powers of 3 --"); print(powerful(3));
+
+# In R, the last expression in a function is, by default, what is
+# returned. So you could equally just say:
+powerful <- function(x) {list(x2=x*x, x3=x*x*x, x4=x*x*x*x)}
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-rsrc</code>.</p>
+
+ <p>Development of the CodeMirror R mode was kindly sponsored
+ by <a href="http://ubalo.com/">Ubalo</a>, who hold
+ the <a href="LICENSE">license</a>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/r/r.js b/codemirror_ui/lib/CodeMirror-2.3/mode/r/r.js
new file mode 100644
index 0000000..53647f2
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/r/r.js
@@ -0,0 +1,141 @@
+CodeMirror.defineMode("r", function(config) {
+ function wordObj(str) {
+ var words = str.split(" "), res = {};
+ for (var i = 0; i < words.length; ++i) res[words[i]] = true;
+ return res;
+ }
+ var atoms = wordObj("NULL NA Inf NaN NA_integer_ NA_real_ NA_complex_ NA_character_");
+ var builtins = wordObj("list quote bquote eval return call parse deparse");
+ var keywords = wordObj("if else repeat while function for in next break");
+ var blockkeywords = wordObj("if else repeat while function for");
+ var opChars = /[+\-*\/^<>=!&|~$:]/;
+ var curPunc;
+
+ function tokenBase(stream, state) {
+ curPunc = null;
+ var ch = stream.next();
+ if (ch == "#") {
+ stream.skipToEnd();
+ return "comment";
+ } else if (ch == "0" && stream.eat("x")) {
+ stream.eatWhile(/[\da-f]/i);
+ return "number";
+ } else if (ch == "." && stream.eat(/\d/)) {
+ stream.match(/\d*(?:e[+\-]?\d+)?/);
+ return "number";
+ } else if (/\d/.test(ch)) {
+ stream.match(/\d*(?:\.\d+)?(?:e[+\-]\d+)?L?/);
+ return "number";
+ } else if (ch == "'" || ch == '"') {
+ state.tokenize = tokenString(ch);
+ return "string";
+ } else if (ch == "." && stream.match(/.[.\d]+/)) {
+ return "keyword";
+ } else if (/[\w\.]/.test(ch) && ch != "_") {
+ stream.eatWhile(/[\w\.]/);
+ var word = stream.current();
+ if (atoms.propertyIsEnumerable(word)) return "atom";
+ if (keywords.propertyIsEnumerable(word)) {
+ if (blockkeywords.propertyIsEnumerable(word)) curPunc = "block";
+ return "keyword";
+ }
+ if (builtins.propertyIsEnumerable(word)) return "builtin";
+ return "variable";
+ } else if (ch == "%") {
+ if (stream.skipTo("%")) stream.next();
+ return "variable-2";
+ } else if (ch == "<" && stream.eat("-")) {
+ return "arrow";
+ } else if (ch == "=" && state.ctx.argList) {
+ return "arg-is";
+ } else if (opChars.test(ch)) {
+ if (ch == "$") return "dollar";
+ stream.eatWhile(opChars);
+ return "operator";
+ } else if (/[\(\){}\[\];]/.test(ch)) {
+ curPunc = ch;
+ if (ch == ";") return "semi";
+ return null;
+ } else {
+ return null;
+ }
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ if (stream.eat("\\")) {
+ var ch = stream.next();
+ if (ch == "x") stream.match(/^[a-f0-9]{2}/i);
+ else if ((ch == "u" || ch == "U") && stream.eat("{") && stream.skipTo("}")) stream.next();
+ else if (ch == "u") stream.match(/^[a-f0-9]{4}/i);
+ else if (ch == "U") stream.match(/^[a-f0-9]{8}/i);
+ else if (/[0-7]/.test(ch)) stream.match(/^[0-7]{1,2}/);
+ return "string-2";
+ } else {
+ var next;
+ while ((next = stream.next()) != null) {
+ if (next == quote) { state.tokenize = tokenBase; break; }
+ if (next == "\\") { stream.backUp(1); break; }
+ }
+ return "string";
+ }
+ };
+ }
+
+ function push(state, type, stream) {
+ state.ctx = {type: type,
+ indent: state.indent,
+ align: null,
+ column: stream.column(),
+ prev: state.ctx};
+ }
+ function pop(state) {
+ state.indent = state.ctx.indent;
+ state.ctx = state.ctx.prev;
+ }
+
+ return {
+ startState: function(base) {
+ return {tokenize: tokenBase,
+ ctx: {type: "top",
+ indent: -config.indentUnit,
+ align: false},
+ indent: 0,
+ afterIdent: false};
+ },
+
+ token: function(stream, state) {
+ if (stream.sol()) {
+ if (state.ctx.align == null) state.ctx.align = false;
+ state.indent = stream.indentation();
+ }
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ if (style != "comment" && state.ctx.align == null) state.ctx.align = true;
+
+ var ctype = state.ctx.type;
+ if ((curPunc == ";" || curPunc == "{" || curPunc == "}") && ctype == "block") pop(state);
+ if (curPunc == "{") push(state, "}", stream);
+ else if (curPunc == "(") {
+ push(state, ")", stream);
+ if (state.afterIdent) state.ctx.argList = true;
+ }
+ else if (curPunc == "[") push(state, "]", stream);
+ else if (curPunc == "block") push(state, "block", stream);
+ else if (curPunc == ctype) pop(state);
+ state.afterIdent = style == "variable" || style == "keyword";
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != tokenBase) return 0;
+ var firstChar = textAfter && textAfter.charAt(0), ctx = state.ctx,
+ closing = firstChar == ctx.type;
+ if (ctx.type == "block") return ctx.indent + (firstChar == "{" ? 0 : config.indentUnit);
+ else if (ctx.align) return ctx.column + (closing ? 0 : 1);
+ else return ctx.indent + (closing ? 0 : config.indentUnit);
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-rsrc", "r");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/changes/changes.js b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/changes/changes.js
new file mode 100644
index 0000000..cb45f9e
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/changes/changes.js
@@ -0,0 +1,19 @@
+CodeMirror.defineMode("changes", function(config, modeConfig) {
+ var headerSeperator = /^-+$/;
+ var headerLine = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ?\d{1,2} \d{2}:\d{2}(:\d{2})? [A-Z]{3,4} \d{4} - /;
+ var simpleEmail = /^[\w+.-]+@[\w.-]+/;
+
+ return {
+ token: function(stream) {
+ if (stream.sol()) {
+ if (stream.match(headerSeperator)) { return 'tag'; }
+ if (stream.match(headerLine)) { return 'tag'; }
+ }
+ if (stream.match(simpleEmail)) { return 'string'; }
+ stream.next();
+ return null;
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-rpm-changes", "changes");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/changes/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/changes/index.html
new file mode 100644
index 0000000..b7ff952
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/changes/index.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: RPM changes mode</title>
+ <link rel="stylesheet" href="../../../lib/codemirror.css">
+ <script src="../../../lib/codemirror.js"></script>
+ <script src="changes.js"></script>
+ <link rel="stylesheet" href="../../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: RPM changes mode</h1>
+
+ <div><textarea id="code" name="code">
+-------------------------------------------------------------------
+Tue Oct 18 13:58:40 UTC 2011 - misterx@example.com
+
+- Update to r60.3
+- Fixes bug in the reflect package
+ * disallow Interface method on Value obtained via unexported name
+
+-------------------------------------------------------------------
+Thu Oct 6 08:14:24 UTC 2011 - misterx@example.com
+
+- Update to r60.2
+- Fixes memory leak in certain map types
+
+-------------------------------------------------------------------
+Wed Oct 5 14:34:10 UTC 2011 - misterx@example.com
+
+- Tweaks for gdb debugging
+- go.spec changes:
+ - move %go_arch definition to %prep section
+ - pass correct location of go specific gdb pretty printer and
+ functions to cpp as HOST_EXTRA_CFLAGS macro
+ - install go gdb functions & printer
+- gdb-printer.patch
+ - patch linker (src/cmd/ld/dwarf.c) to emit correct location of go
+ gdb functions and pretty printer
+</textarea></div>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: {name: "changes"},
+ lineNumbers: true,
+ indentUnit: 4,
+ tabMode: "shift",
+ matchBrackets: true
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-rpm-changes</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/index.html
new file mode 100644
index 0000000..e3bca15
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/index.html
@@ -0,0 +1,99 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: RPM spec mode</title>
+ <link rel="stylesheet" href="../../../lib/codemirror.css">
+ <script src="../../../lib/codemirror.js"></script>
+ <script src="spec.js"></script>
+ <link rel="stylesheet" href="spec.css">
+ <link rel="stylesheet" href="../../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: RPM spec mode</h1>
+
+ <div><textarea id="code" name="code">
+#
+# spec file for package minidlna
+#
+# Copyright (c) 2011, Sascha Peilicke <saschpe@gmx.de>
+#
+# All modifications and additions to the file contributed by third parties
+# remain the property of their copyright owners, unless otherwise agreed
+# upon. The license for this file, and modifications and additions to the
+# file, is the same license as for the pristine package itself (unless the
+# license for the pristine package is not an Open Source License, in which
+# case the license is the MIT License). An "Open Source License" is a
+# license that conforms to the Open Source Definition (Version 1.9)
+# published by the Open Source Initiative.
+
+
+Name: libupnp6
+Version: 1.6.13
+Release: 0
+Summary: Portable Universal Plug and Play (UPnP) SDK
+Group: System/Libraries
+License: BSD-3-Clause
+Url: http://sourceforge.net/projects/pupnp/
+Source0: http://downloads.sourceforge.net/pupnp/libupnp-%{version}.tar.bz2
+BuildRoot: %{_tmppath}/%{name}-%{version}-build
+
+%description
+The portable Universal Plug and Play (UPnP) SDK provides support for building
+UPnP-compliant control points, devices, and bridges on several operating
+systems.
+
+%package -n libupnp-devel
+Summary: Portable Universal Plug and Play (UPnP) SDK
+Group: Development/Libraries/C and C++
+Provides: pkgconfig(libupnp)
+Requires: %{name} = %{version}
+
+%description -n libupnp-devel
+The portable Universal Plug and Play (UPnP) SDK provides support for building
+UPnP-compliant control points, devices, and bridges on several operating
+systems.
+
+%prep
+%setup -n libupnp-%{version}
+
+%build
+%configure --disable-static
+make %{?_smp_mflags}
+
+%install
+%makeinstall
+find %{buildroot} -type f -name '*.la' -exec rm -f {} ';'
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+%doc ChangeLog NEWS README TODO
+%{_libdir}/libixml.so.*
+%{_libdir}/libthreadutil.so.*
+%{_libdir}/libupnp.so.*
+
+%files -n libupnp-devel
+%defattr(-,root,root,-)
+%{_libdir}/pkgconfig/libupnp.pc
+%{_libdir}/libixml.so
+%{_libdir}/libthreadutil.so
+%{_libdir}/libupnp.so
+%{_includedir}/upnp/
+
+%changelog</textarea></div>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: {name: "spec"},
+ lineNumbers: true,
+ indentUnit: 4,
+ matchBrackets: true
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-rpm-spec</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/spec.css b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/spec.css
new file mode 100644
index 0000000..d0a5d43
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/spec.css
@@ -0,0 +1,5 @@
+.cm-s-default span.cm-preamble {color: #b26818; font-weight: bold;}
+.cm-s-default span.cm-macro {color: #b218b2;}
+.cm-s-default span.cm-section {color: green; font-weight: bold;}
+.cm-s-default span.cm-script {color: red;}
+.cm-s-default span.cm-issue {color: yellow;}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/spec.js b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/spec.js
new file mode 100644
index 0000000..902db6a
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/rpm/spec/spec.js
@@ -0,0 +1,66 @@
+// Quick and dirty spec file highlighting
+
+CodeMirror.defineMode("spec", function(config, modeConfig) {
+ var arch = /^(i386|i586|i686|x86_64|ppc64|ppc|ia64|s390x|s390|sparc64|sparcv9|sparc|noarch|alphaev6|alpha|hppa|mipsel)/;
+
+ var preamble = /^(Name|Version|Release|License|Summary|Url|Group|Source|BuildArch|BuildRequires|BuildRoot|AutoReqProv|Provides|Requires(\(\w+\))?|Obsoletes|Conflicts|Recommends|Source\d*|Patch\d*|ExclusiveArch|NoSource|Supplements):/;
+ var section = /^%(debug_package|package|description|prep|build|install|files|clean|changelog|preun|postun|pre|post|triggerin|triggerun|pretrans|posttrans|verifyscript|check|triggerpostun|triggerprein|trigger)/;
+ var control_flow_complex = /^%(ifnarch|ifarch|if)/; // rpm control flow macros
+ var control_flow_simple = /^%(else|endif)/; // rpm control flow macros
+ var operators = /^(\!|\?|\<\=|\<|\>\=|\>|\=\=|\&\&|\|\|)/; // operators in control flow macros
+
+ return {
+ startState: function () {
+ return {
+ controlFlow: false,
+ macroParameters: false,
+ section: false
+ };
+ },
+ token: function (stream, state) {
+ var ch = stream.peek();
+ if (ch == "#") { stream.skipToEnd(); return "comment"; }
+
+ if (stream.sol()) {
+ if (stream.match(preamble)) { return "preamble"; }
+ if (stream.match(section)) { return "section"; }
+ }
+
+ if (stream.match(/^\$\w+/)) { return "def"; } // Variables like '$RPM_BUILD_ROOT'
+ if (stream.match(/^\$\{\w+\}/)) { return "def"; } // Variables like '${RPM_BUILD_ROOT}'
+
+ if (stream.match(control_flow_simple)) { return "keyword"; }
+ if (stream.match(control_flow_complex)) {
+ state.controlFlow = true;
+ return "keyword";
+ }
+ if (state.controlFlow) {
+ if (stream.match(operators)) { return "operator"; }
+ if (stream.match(/^(\d+)/)) { return "number"; }
+ if (stream.eol()) { state.controlFlow = false; }
+ }
+
+ if (stream.match(arch)) { return "number"; }
+
+ // Macros like '%make_install' or '%attr(0775,root,root)'
+ if (stream.match(/^%[\w]+/)) {
+ if (stream.match(/^\(/)) { state.macroParameters = true; }
+ return "macro";
+ }
+ if (state.macroParameters) {
+ if (stream.match(/^\d+/)) { return "number";}
+ if (stream.match(/^\)/)) {
+ state.macroParameters = false;
+ return "macro";
+ }
+ }
+ if (stream.match(/^%\{\??[\w \-]+\}/)) { return "macro"; } // Macros like '%{defined fedora}'
+
+ //TODO: Include bash script sub-parser (CodeMirror supports that)
+ stream.next();
+ return null;
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-rpm-spec", "spec");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/rst/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/rst/index.html
new file mode 100644
index 0000000..fd75a28
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/rst/index.html
@@ -0,0 +1,525 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: reStructuredText mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="rst.js"></script>
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: reStructuredText mode</h1>
+
+<form><textarea id="code" name="code">
+.. This is an excerpt from Sphinx documentation: http://sphinx.pocoo.org/_sources/rest.txt
+
+.. highlightlang:: rest
+
+.. _rst-primer:
+
+reStructuredText Primer
+=======================
+
+This section is a brief introduction to reStructuredText (reST) concepts and
+syntax, intended to provide authors with enough information to author documents
+productively. Since reST was designed to be a simple, unobtrusive markup
+language, this will not take too long.
+
+.. seealso::
+
+ The authoritative `reStructuredText User Documentation
+ &lt;http://docutils.sourceforge.net/rst.html&gt;`_. The "ref" links in this
+ document link to the description of the individual constructs in the reST
+ reference.
+
+
+Paragraphs
+----------
+
+The paragraph (:duref:`ref &lt;paragraphs&gt;`) is the most basic block in a reST
+document. Paragraphs are simply chunks of text separated by one or more blank
+lines. As in Python, indentation is significant in reST, so all lines of the
+same paragraph must be left-aligned to the same level of indentation.
+
+
+.. _inlinemarkup:
+
+Inline markup
+-------------
+
+The standard reST inline markup is quite simple: use
+
+* one asterisk: ``*text*`` for emphasis (italics),
+* two asterisks: ``**text**`` for strong emphasis (boldface), and
+* backquotes: ````text```` for code samples.
+
+If asterisks or backquotes appear in running text and could be confused with
+inline markup delimiters, they have to be escaped with a backslash.
+
+Be aware of some restrictions of this markup:
+
+* it may not be nested,
+* content may not start or end with whitespace: ``* text*`` is wrong,
+* it must be separated from surrounding text by non-word characters. Use a
+ backslash escaped space to work around that: ``thisis\ *one*\ word``.
+
+These restrictions may be lifted in future versions of the docutils.
+
+reST also allows for custom "interpreted text roles"', which signify that the
+enclosed text should be interpreted in a specific way. Sphinx uses this to
+provide semantic markup and cross-referencing of identifiers, as described in
+the appropriate section. The general syntax is ``:rolename:`content```.
+
+Standard reST provides the following roles:
+
+* :durole:`emphasis` -- alternate spelling for ``*emphasis*``
+* :durole:`strong` -- alternate spelling for ``**strong**``
+* :durole:`literal` -- alternate spelling for ````literal````
+* :durole:`subscript` -- subscript text
+* :durole:`superscript` -- superscript text
+* :durole:`title-reference` -- for titles of books, periodicals, and other
+ materials
+
+See :ref:`inline-markup` for roles added by Sphinx.
+
+
+Lists and Quote-like blocks
+---------------------------
+
+List markup (:duref:`ref &lt;bullet-lists&gt;`) is natural: just place an asterisk at
+the start of a paragraph and indent properly. The same goes for numbered lists;
+they can also be autonumbered using a ``#`` sign::
+
+ * This is a bulleted list.
+ * It has two items, the second
+ item uses two lines.
+
+ 1. This is a numbered list.
+ 2. It has two items too.
+
+ #. This is a numbered list.
+ #. It has two items too.
+
+
+Nested lists are possible, but be aware that they must be separated from the
+parent list items by blank lines::
+
+ * this is
+ * a list
+
+ * with a nested list
+ * and some subitems
+
+ * and here the parent list continues
+
+Definition lists (:duref:`ref &lt;definition-lists&gt;`) are created as follows::
+
+ term (up to a line of text)
+ Definition of the term, which must be indented
+
+ and can even consist of multiple paragraphs
+
+ next term
+ Description.
+
+Note that the term cannot have more than one line of text.
+
+Quoted paragraphs (:duref:`ref &lt;block-quotes&gt;`) are created by just indenting
+them more than the surrounding paragraphs.
+
+Line blocks (:duref:`ref &lt;line-blocks&gt;`) are a way of preserving line breaks::
+
+ | These lines are
+ | broken exactly like in
+ | the source file.
+
+There are also several more special blocks available:
+
+* field lists (:duref:`ref &lt;field-lists&gt;`)
+* option lists (:duref:`ref &lt;option-lists&gt;`)
+* quoted literal blocks (:duref:`ref &lt;quoted-literal-blocks&gt;`)
+* doctest blocks (:duref:`ref &lt;doctest-blocks&gt;`)
+
+
+Source Code
+-----------
+
+Literal code blocks (:duref:`ref &lt;literal-blocks&gt;`) are introduced by ending a
+paragraph with the special marker ``::``. The literal block must be indented
+(and, like all paragraphs, separated from the surrounding ones by blank lines)::
+
+ This is a normal text paragraph. The next paragraph is a code sample::
+
+ It is not processed in any way, except
+ that the indentation is removed.
+
+ It can span multiple lines.
+
+ This is a normal text paragraph again.
+
+The handling of the ``::`` marker is smart:
+
+* If it occurs as a paragraph of its own, that paragraph is completely left
+ out of the document.
+* If it is preceded by whitespace, the marker is removed.
+* If it is preceded by non-whitespace, the marker is replaced by a single
+ colon.
+
+That way, the second sentence in the above example's first paragraph would be
+rendered as "The next paragraph is a code sample:".
+
+
+.. _rst-tables:
+
+Tables
+------
+
+Two forms of tables are supported. For *grid tables* (:duref:`ref
+&lt;grid-tables&gt;`), you have to "paint" the cell grid yourself. They look like
+this::
+
+ +------------------------+------------+----------+----------+
+ | Header row, column 1 | Header 2 | Header 3 | Header 4 |
+ | (header rows optional) | | | |
+ +========================+============+==========+==========+
+ | body row 1, column 1 | column 2 | column 3 | column 4 |
+ +------------------------+------------+----------+----------+
+ | body row 2 | ... | ... | |
+ +------------------------+------------+----------+----------+
+
+*Simple tables* (:duref:`ref &lt;simple-tables&gt;`) are easier to write, but
+limited: they must contain more than one row, and the first column cannot
+contain multiple lines. They look like this::
+
+ ===== ===== =======
+ A B A and B
+ ===== ===== =======
+ False False False
+ True False False
+ False True False
+ True True True
+ ===== ===== =======
+
+
+Hyperlinks
+----------
+
+External links
+^^^^^^^^^^^^^^
+
+Use ```Link text &lt;http://example.com/&gt;`_`` for inline web links. If the link
+text should be the web address, you don't need special markup at all, the parser
+finds links and mail addresses in ordinary text.
+
+You can also separate the link and the target definition (:duref:`ref
+&lt;hyperlink-targets&gt;`), like this::
+
+ This is a paragraph that contains `a link`_.
+
+ .. _a link: http://example.com/
+
+
+Internal links
+^^^^^^^^^^^^^^
+
+Internal linking is done via a special reST role provided by Sphinx, see the
+section on specific markup, :ref:`ref-role`.
+
+
+Sections
+--------
+
+Section headers (:duref:`ref &lt;sections&gt;`) are created by underlining (and
+optionally overlining) the section title with a punctuation character, at least
+as long as the text::
+
+ =================
+ This is a heading
+ =================
+
+Normally, there are no heading levels assigned to certain characters as the
+structure is determined from the succession of headings. However, for the
+Python documentation, this convention is used which you may follow:
+
+* ``#`` with overline, for parts
+* ``*`` with overline, for chapters
+* ``=``, for sections
+* ``-``, for subsections
+* ``^``, for subsubsections
+* ``"``, for paragraphs
+
+Of course, you are free to use your own marker characters (see the reST
+documentation), and use a deeper nesting level, but keep in mind that most
+target formats (HTML, LaTeX) have a limited supported nesting depth.
+
+
+Explicit Markup
+---------------
+
+"Explicit markup" (:duref:`ref &lt;explicit-markup-blocks&gt;`) is used in reST for
+most constructs that need special handling, such as footnotes,
+specially-highlighted paragraphs, comments, and generic directives.
+
+An explicit markup block begins with a line starting with ``..`` followed by
+whitespace and is terminated by the next paragraph at the same level of
+indentation. (There needs to be a blank line between explicit markup and normal
+paragraphs. This may all sound a bit complicated, but it is intuitive enough
+when you write it.)
+
+
+.. _directives:
+
+Directives
+----------
+
+A directive (:duref:`ref &lt;directives&gt;`) is a generic block of explicit markup.
+Besides roles, it is one of the extension mechanisms of reST, and Sphinx makes
+heavy use of it.
+
+Docutils supports the following directives:
+
+* Admonitions: :dudir:`attention`, :dudir:`caution`, :dudir:`danger`,
+ :dudir:`error`, :dudir:`hint`, :dudir:`important`, :dudir:`note`,
+ :dudir:`tip`, :dudir:`warning` and the generic :dudir:`admonition`.
+ (Most themes style only "note" and "warning" specially.)
+
+* Images:
+
+ - :dudir:`image` (see also Images_ below)
+ - :dudir:`figure` (an image with caption and optional legend)
+
+* Additional body elements:
+
+ - :dudir:`contents` (a local, i.e. for the current file only, table of
+ contents)
+ - :dudir:`container` (a container with a custom class, useful to generate an
+ outer ``&lt;div&gt;`` in HTML)
+ - :dudir:`rubric` (a heading without relation to the document sectioning)
+ - :dudir:`topic`, :dudir:`sidebar` (special highlighted body elements)
+ - :dudir:`parsed-literal` (literal block that supports inline markup)
+ - :dudir:`epigraph` (a block quote with optional attribution line)
+ - :dudir:`highlights`, :dudir:`pull-quote` (block quotes with their own
+ class attribute)
+ - :dudir:`compound` (a compound paragraph)
+
+* Special tables:
+
+ - :dudir:`table` (a table with title)
+ - :dudir:`csv-table` (a table generated from comma-separated values)
+ - :dudir:`list-table` (a table generated from a list of lists)
+
+* Special directives:
+
+ - :dudir:`raw` (include raw target-format markup)
+ - :dudir:`include` (include reStructuredText from another file)
+ -- in Sphinx, when given an absolute include file path, this directive takes
+ it as relative to the source directory
+ - :dudir:`class` (assign a class attribute to the next element) [1]_
+
+* HTML specifics:
+
+ - :dudir:`meta` (generation of HTML ``&lt;meta&gt;`` tags)
+ - :dudir:`title` (override document title)
+
+* Influencing markup:
+
+ - :dudir:`default-role` (set a new default role)
+ - :dudir:`role` (create a new role)
+
+ Since these are only per-file, better use Sphinx' facilities for setting the
+ :confval:`default_role`.
+
+Do *not* use the directives :dudir:`sectnum`, :dudir:`header` and
+:dudir:`footer`.
+
+Directives added by Sphinx are described in :ref:`sphinxmarkup`.
+
+Basically, a directive consists of a name, arguments, options and content. (Keep
+this terminology in mind, it is used in the next chapter describing custom
+directives.) Looking at this example, ::
+
+ .. function:: foo(x)
+ foo(y, z)
+ :module: some.module.name
+
+ Return a line of text input from the user.
+
+``function`` is the directive name. It is given two arguments here, the
+remainder of the first line and the second line, as well as one option
+``module`` (as you can see, options are given in the lines immediately following
+the arguments and indicated by the colons). Options must be indented to the
+same level as the directive content.
+
+The directive content follows after a blank line and is indented relative to the
+directive start.
+
+
+Images
+------
+
+reST supports an image directive (:dudir:`ref &lt;image&gt;`), used like so::
+
+ .. image:: gnu.png
+ (options)
+
+When used within Sphinx, the file name given (here ``gnu.png``) must either be
+relative to the source file, or absolute which means that they are relative to
+the top source directory. For example, the file ``sketch/spam.rst`` could refer
+to the image ``images/spam.png`` as ``../images/spam.png`` or
+``/images/spam.png``.
+
+Sphinx will automatically copy image files over to a subdirectory of the output
+directory on building (e.g. the ``_static`` directory for HTML output.)
+
+Interpretation of image size options (``width`` and ``height``) is as follows:
+if the size has no unit or the unit is pixels, the given size will only be
+respected for output channels that support pixels (i.e. not in LaTeX output).
+Other units (like ``pt`` for points) will be used for HTML and LaTeX output.
+
+Sphinx extends the standard docutils behavior by allowing an asterisk for the
+extension::
+
+ .. image:: gnu.*
+
+Sphinx then searches for all images matching the provided pattern and determines
+their type. Each builder then chooses the best image out of these candidates.
+For instance, if the file name ``gnu.*`` was given and two files :file:`gnu.pdf`
+and :file:`gnu.png` existed in the source tree, the LaTeX builder would choose
+the former, while the HTML builder would prefer the latter.
+
+.. versionchanged:: 0.4
+ Added the support for file names ending in an asterisk.
+
+.. versionchanged:: 0.6
+ Image paths can now be absolute.
+
+
+Footnotes
+---------
+
+For footnotes (:duref:`ref &lt;footnotes&gt;`), use ``[#name]_`` to mark the footnote
+location, and add the footnote body at the bottom of the document after a
+"Footnotes" rubric heading, like so::
+
+ Lorem ipsum [#f1]_ dolor sit amet ... [#f2]_
+
+ .. rubric:: Footnotes
+
+ .. [#f1] Text of the first footnote.
+ .. [#f2] Text of the second footnote.
+
+You can also explicitly number the footnotes (``[1]_``) or use auto-numbered
+footnotes without names (``[#]_``).
+
+
+Citations
+---------
+
+Standard reST citations (:duref:`ref &lt;citations&gt;`) are supported, with the
+additional feature that they are "global", i.e. all citations can be referenced
+from all files. Use them like so::
+
+ Lorem ipsum [Ref]_ dolor sit amet.
+
+ .. [Ref] Book or article reference, URL or whatever.
+
+Citation usage is similar to footnote usage, but with a label that is not
+numeric or begins with ``#``.
+
+
+Substitutions
+-------------
+
+reST supports "substitutions" (:duref:`ref &lt;substitution-definitions&gt;`), which
+are pieces of text and/or markup referred to in the text by ``|name|``. They
+are defined like footnotes with explicit markup blocks, like this::
+
+ .. |name| replace:: replacement *text*
+
+or this::
+
+ .. |caution| image:: warning.png
+ :alt: Warning!
+
+See the :duref:`reST reference for substitutions &lt;substitution-definitions&gt;`
+for details.
+
+If you want to use some substitutions for all documents, put them into
+:confval:`rst_prolog` or put them into a separate file and include it into all
+documents you want to use them in, using the :rst:dir:`include` directive. (Be
+sure to give the include file a file name extension differing from that of other
+source files, to avoid Sphinx finding it as a standalone document.)
+
+Sphinx defines some default substitutions, see :ref:`default-substitutions`.
+
+
+Comments
+--------
+
+Every explicit markup block which isn't a valid markup construct (like the
+footnotes above) is regarded as a comment (:duref:`ref &lt;comments&gt;`). For
+example::
+
+ .. This is a comment.
+
+You can indent text after a comment start to form multiline comments::
+
+ ..
+ This whole indented block
+ is a comment.
+
+ Still in the comment.
+
+
+Source encoding
+---------------
+
+Since the easiest way to include special characters like em dashes or copyright
+signs in reST is to directly write them as Unicode characters, one has to
+specify an encoding. Sphinx assumes source files to be encoded in UTF-8 by
+default; you can change this with the :confval:`source_encoding` config value.
+
+
+Gotchas
+-------
+
+There are some problems one commonly runs into while authoring reST documents:
+
+* **Separation of inline markup:** As said above, inline markup spans must be
+ separated from the surrounding text by non-word characters, you have to use a
+ backslash-escaped space to get around that. See `the reference
+ &lt;http://docutils.sf.net/docs/ref/rst/restructuredtext.html#inline-markup&gt;`_
+ for the details.
+
+* **No nested inline markup:** Something like ``*see :func:`foo`*`` is not
+ possible.
+
+
+.. rubric:: Footnotes
+
+.. [1] When the default domain contains a :rst:dir:`class` directive, this directive
+ will be shadowed. Therefore, Sphinx re-exports it as :rst:dir:`rst-class`.
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ });
+ </script>
+ <p>The reStructuredText mode supports one configuration parameter:</p>
+ <dl>
+ <dt><code>verbatim (string)</code></dt>
+ <dd>A name or MIME type of a mode that will be used for highlighting
+ verbatim blocks. By default, reStructuredText mode uses uniform color
+ for whole block of verbatim text if no mode is given.</dd>
+ </dl>
+ <p>If <code>python</code> mode is available,
+ it will be used for highlighting blocks containing Python/IPython terminal
+ sessions (blocks starting with <code>&gt;&gt;&gt;</code> (for Python) or
+ <code>In [num]:</code> (for IPython).
+
+ <p><strong>MIME types defined:</strong> <code>text/x-rst</code>.</p>
+ </body>
+</html>
+
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/rst/rst.js b/codemirror_ui/lib/CodeMirror-2.3/mode/rst/rst.js
new file mode 100644
index 0000000..c4ecdf4
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/rst/rst.js
@@ -0,0 +1,326 @@
+CodeMirror.defineMode('rst', function(config, options) {
+ function setState(state, fn, ctx) {
+ state.fn = fn;
+ setCtx(state, ctx);
+ }
+
+ function setCtx(state, ctx) {
+ state.ctx = ctx || {};
+ }
+
+ function setNormal(state, ch) {
+ if (ch && (typeof ch !== 'string')) {
+ var str = ch.current();
+ ch = str[str.length-1];
+ }
+
+ setState(state, normal, {back: ch});
+ }
+
+ function hasMode(mode) {
+ if (mode) {
+ var modes = CodeMirror.listModes();
+
+ for (var i in modes) {
+ if (modes[i] == mode) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ function getMode(mode) {
+ if (hasMode(mode)) {
+ return CodeMirror.getMode(config, mode);
+ } else {
+ return null;
+ }
+ }
+
+ var verbatimMode = getMode(options.verbatim);
+ var pythonMode = getMode('python');
+
+ var reSection = /^[!"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]/;
+ var reDirective = /^\s*\w([-:.\w]*\w)?::(\s|$)/;
+ var reHyperlink = /^\s*_[\w-]+:(\s|$)/;
+ var reFootnote = /^\s*\[(\d+|#)\](\s|$)/;
+ var reCitation = /^\s*\[[A-Za-z][\w-]*\](\s|$)/;
+ var reFootnoteRef = /^\[(\d+|#)\]_/;
+ var reCitationRef = /^\[[A-Za-z][\w-]*\]_/;
+ var reDirectiveMarker = /^\.\.(\s|$)/;
+ var reVerbatimMarker = /^::\s*$/;
+ var rePreInline = /^[-\s"([{</:]/;
+ var rePostInline = /^[-\s`'")\]}>/:.,;!?\\_]/;
+ var reEnumeratedList = /^\s*((\d+|[A-Za-z#])[.)]|\((\d+|[A-Z-a-z#])\))\s/;
+ var reBulletedList = /^\s*[-\+\*]\s/;
+ var reExamples = /^\s+(>>>|In \[\d+\]:)\s/;
+
+ function normal(stream, state) {
+ var ch, sol, i;
+
+ if (stream.eat(/\\/)) {
+ ch = stream.next();
+ setNormal(state, ch);
+ return null;
+ }
+
+ sol = stream.sol();
+
+ if (sol && (ch = stream.eat(reSection))) {
+ for (i = 0; stream.eat(ch); i++);
+
+ if (i >= 3 && stream.match(/^\s*$/)) {
+ setNormal(state, null);
+ return 'header';
+ } else {
+ stream.backUp(i + 1);
+ }
+ }
+
+ if (sol && stream.match(reDirectiveMarker)) {
+ if (!stream.eol()) {
+ setState(state, directive);
+ }
+ return 'meta';
+ }
+
+ if (stream.match(reVerbatimMarker)) {
+ if (!verbatimMode) {
+ setState(state, verbatim);
+ } else {
+ var mode = verbatimMode;
+
+ setState(state, verbatim, {
+ mode: mode,
+ local: mode.startState()
+ });
+ }
+ return 'meta';
+ }
+
+ if (sol && stream.match(reExamples, false)) {
+ if (!pythonMode) {
+ setState(state, verbatim);
+ return 'meta';
+ } else {
+ var mode = pythonMode;
+
+ setState(state, verbatim, {
+ mode: mode,
+ local: mode.startState()
+ });
+
+ return null;
+ }
+ }
+
+ function testBackward(re) {
+ return sol || !state.ctx.back || re.test(state.ctx.back);
+ }
+
+ function testForward(re) {
+ return stream.eol() || stream.match(re, false);
+ }
+
+ function testInline(re) {
+ return stream.match(re) && testBackward(/\W/) && testForward(/\W/);
+ }
+
+ if (testInline(reFootnoteRef)) {
+ setNormal(state, stream);
+ return 'footnote';
+ }
+
+ if (testInline(reCitationRef)) {
+ setNormal(state, stream);
+ return 'citation';
+ }
+
+ ch = stream.next();
+
+ if (testBackward(rePreInline)) {
+ if ((ch === ':' || ch === '|') && stream.eat(/\S/)) {
+ var token;
+
+ if (ch === ':') {
+ token = 'builtin';
+ } else {
+ token = 'atom';
+ }
+
+ setState(state, inline, {
+ ch: ch,
+ wide: false,
+ prev: null,
+ token: token
+ });
+
+ return token;
+ }
+
+ if (ch === '*' || ch === '`') {
+ var orig = ch,
+ wide = false;
+
+ ch = stream.next();
+
+ if (ch == orig) {
+ wide = true;
+ ch = stream.next();
+ }
+
+ if (ch && !/\s/.test(ch)) {
+ var token;
+
+ if (orig === '*') {
+ token = wide ? 'strong' : 'em';
+ } else {
+ token = wide ? 'string' : 'string-2';
+ }
+
+ setState(state, inline, {
+ ch: orig, // inline() has to know what to search for
+ wide: wide, // are we looking for `ch` or `chch`
+ prev: null, // terminator must not be preceeded with whitespace
+ token: token // I don't want to recompute this all the time
+ });
+
+ return token;
+ }
+ }
+ }
+
+ setNormal(state, ch);
+ return null;
+ }
+
+ function inline(stream, state) {
+ var ch = stream.next(),
+ token = state.ctx.token;
+
+ function finish(ch) {
+ state.ctx.prev = ch;
+ return token;
+ }
+
+ if (ch != state.ctx.ch) {
+ return finish(ch);
+ }
+
+ if (/\s/.test(state.ctx.prev)) {
+ return finish(ch);
+ }
+
+ if (state.ctx.wide) {
+ ch = stream.next();
+
+ if (ch != state.ctx.ch) {
+ return finish(ch);
+ }
+ }
+
+ if (!stream.eol() && !rePostInline.test(stream.peek())) {
+ if (state.ctx.wide) {
+ stream.backUp(1);
+ }
+
+ return finish(ch);
+ }
+
+ setState(state, normal);
+ setNormal(state, ch);
+
+ return token;
+ }
+
+ function directive(stream, state) {
+ var token = null;
+
+ if (stream.match(reDirective)) {
+ token = 'attribute';
+ } else if (stream.match(reHyperlink)) {
+ token = 'link';
+ } else if (stream.match(reFootnote)) {
+ token = 'quote';
+ } else if (stream.match(reCitation)) {
+ token = 'quote';
+ } else {
+ stream.eatSpace();
+
+ if (stream.eol()) {
+ setNormal(state, stream);
+ return null;
+ } else {
+ stream.skipToEnd();
+ setState(state, comment);
+ return 'comment';
+ }
+ }
+
+ // FIXME this is unreachable
+ setState(state, body, {start: true});
+ return token;
+ }
+
+ function body(stream, state) {
+ var token = 'body';
+
+ if (!state.ctx.start || stream.sol()) {
+ return block(stream, state, token);
+ }
+
+ stream.skipToEnd();
+ setCtx(state);
+
+ return token;
+ }
+
+ function comment(stream, state) {
+ return block(stream, state, 'comment');
+ }
+
+ function verbatim(stream, state) {
+ if (!verbatimMode) {
+ return block(stream, state, 'meta');
+ } else {
+ if (stream.sol()) {
+ if (!stream.eatSpace()) {
+ setNormal(state, stream);
+ }
+
+ return null;
+ }
+
+ return verbatimMode.token(stream, state.ctx.local);
+ }
+ }
+
+ function block(stream, state, token) {
+ if (stream.eol() || stream.eatSpace()) {
+ stream.skipToEnd();
+ return token;
+ } else {
+ setNormal(state, stream);
+ return null;
+ }
+ }
+
+ return {
+ startState: function() {
+ return {fn: normal, ctx: {}};
+ },
+
+ copyState: function(state) {
+ return {fn: state.fn, ctx: state.ctx};
+ },
+
+ token: function(stream, state) {
+ var token = state.fn(stream, state);
+ return token;
+ }
+ };
+}, "python");
+
+CodeMirror.defineMIME("text/x-rst", "rst");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/ruby/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/ruby/index.html
new file mode 100644
index 0000000..6d33db1
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/ruby/index.html
@@ -0,0 +1,171 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Ruby mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="ruby.js"></script>
+ <style>
+ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+ .cm-s-default span.cm-arrow { color: red; }
+ </style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Ruby mode</h1>
+ <form><textarea id="code" name="code">
+# Code from http://sandbox.mc.edu/~bennet/ruby/code/poly_rb.html
+#
+# This program evaluates polynomials. It first asks for the coefficients
+# of a polynomial, which must be entered on one line, highest-order first.
+# It then requests values of x and will compute the value of the poly for
+# each x. It will repeatly ask for x values, unless you the user enters
+# a blank line. It that case, it will ask for another polynomial. If the
+# user types quit for either input, the program immediately exits.
+#
+
+#
+# Function to evaluate a polynomial at x. The polynomial is given
+# as a list of coefficients, from the greatest to the least.
+def polyval(x, coef)
+ sum = 0
+ coef = coef.clone # Don't want to destroy the original
+ while true
+ sum += coef.shift # Add and remove the next coef
+ break if coef.empty? # If no more, done entirely.
+ sum *= x # This happens the right number of times.
+ end
+ return sum
+end
+
+#
+# Function to read a line containing a list of integers and return
+# them as an array of integers. If the string conversion fails, it
+# throws TypeError. If the input line is the word 'quit', then it
+# converts it to an end-of-file exception
+def readints(prompt)
+ # Read a line
+ print prompt
+ line = readline.chomp
+ raise EOFError.new if line == 'quit' # You can also use a real EOF.
+
+ # Go through each item on the line, converting each one and adding it
+ # to retval.
+ retval = [ ]
+ for str in line.split(/\s+/)
+ if str =~ /^\-?\d+$/
+ retval.push(str.to_i)
+ else
+ raise TypeError.new
+ end
+ end
+
+ return retval
+end
+
+#
+# Take a coeff and an exponent and return the string representation, ignoring
+# the sign of the coefficient.
+def term_to_str(coef, exp)
+ ret = ""
+
+ # Show coeff, unless it's 1 or at the right
+ coef = coef.abs
+ ret = coef.to_s unless coef == 1 && exp > 0
+ ret += "x" if exp > 0 # x if exponent not 0
+ ret += "^" + exp.to_s if exp > 1 # ^exponent, if > 1.
+
+ return ret
+end
+
+#
+# Create a string of the polynomial in sort-of-readable form.
+def polystr(p)
+ # Get the exponent of first coefficient, plus 1.
+ exp = p.length
+
+ # Assign exponents to each term, making pairs of coeff and exponent,
+ # Then get rid of the zero terms.
+ p = (p.map { |c| exp -= 1; [ c, exp ] }).select { |p| p[0] != 0 }
+
+ # If there's nothing left, it's a zero
+ return "0" if p.empty?
+
+ # *** Now p is a non-empty list of [ coef, exponent ] pairs. ***
+
+ # Convert the first term, preceded by a "-" if it's negative.
+ result = (if p[0][0] < 0 then "-" else "" end) + term_to_str(*p[0])
+
+ # Convert the rest of the terms, in each case adding the appropriate
+ # + or - separating them.
+ for term in p[1...p.length]
+ # Add the separator then the rep. of the term.
+ result += (if term[0] < 0 then " - " else " + " end) +
+ term_to_str(*term)
+ end
+
+ return result
+end
+
+#
+# Run until some kind of endfile.
+begin
+ # Repeat until an exception or quit gets us out.
+ while true
+ # Read a poly until it works. An EOF will except out of the
+ # program.
+ print "\n"
+ begin
+ poly = readints("Enter a polynomial coefficients: ")
+ rescue TypeError
+ print "Try again.\n"
+ retry
+ end
+ break if poly.empty?
+
+ # Read and evaluate x values until the user types a blank line.
+ # Again, an EOF will except out of the pgm.
+ while true
+ # Request an integer.
+ print "Enter x value or blank line: "
+ x = readline.chomp
+ break if x == ''
+ raise EOFError.new if x == 'quit'
+
+ # If it looks bad, let's try again.
+ if x !~ /^\-?\d+$/
+ print "That doesn't look like an integer. Please try again.\n"
+ next
+ end
+
+ # Convert to an integer and print the result.
+ x = x.to_i
+ print "p(x) = ", polystr(poly), "\n"
+ print "p(", x, ") = ", polyval(x, poly), "\n"
+ end
+ end
+rescue EOFError
+ print "\n=== EOF ===\n"
+rescue Interrupt, SignalException
+ print "\n=== Interrupted ===\n"
+else
+ print "--- Bye ---\n"
+end
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: "text/x-ruby",
+ tabMode: "indent",
+ matchBrackets: true,
+ indentUnit: 4
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-ruby</code>.</p>
+
+ <p>Development of the CodeMirror Ruby mode was kindly sponsored
+ by <a href="http://ubalo.com/">Ubalo</a>, who hold
+ the <a href="LICENSE">license</a>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/ruby/ruby.js b/codemirror_ui/lib/CodeMirror-2.3/mode/ruby/ruby.js
new file mode 100644
index 0000000..74ed7b9
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/ruby/ruby.js
@@ -0,0 +1,195 @@
+CodeMirror.defineMode("ruby", function(config, parserConfig) {
+ function wordObj(words) {
+ var o = {};
+ for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true;
+ return o;
+ }
+ var keywords = wordObj([
+ "alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else",
+ "elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or",
+ "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless",
+ "until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc",
+ "caller", "lambda", "proc", "public", "protected", "private", "require", "load",
+ "require_relative", "extend", "autoload"
+ ]);
+ var indentWords = wordObj(["def", "class", "case", "for", "while", "do", "module", "then",
+ "catch", "loop", "proc", "begin"]);
+ var dedentWords = wordObj(["end", "until"]);
+ var matching = {"[": "]", "{": "}", "(": ")"};
+ var curPunc;
+
+ function chain(newtok, stream, state) {
+ state.tokenize.push(newtok);
+ return newtok(stream, state);
+ }
+
+ function tokenBase(stream, state) {
+ curPunc = null;
+ if (stream.sol() && stream.match("=begin") && stream.eol()) {
+ state.tokenize.push(readBlockComment);
+ return "comment";
+ }
+ if (stream.eatSpace()) return null;
+ var ch = stream.next(), m;
+ if (ch == "`" || ch == "'" || ch == '"' ||
+ (ch == "/" && !stream.eol() && stream.peek() != " ")) {
+ return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state);
+ } else if (ch == "%") {
+ var style, embed = false;
+ if (stream.eat("s")) style = "atom";
+ else if (stream.eat(/[WQ]/)) { style = "string"; embed = true; }
+ else if (stream.eat(/[wxqr]/)) style = "string";
+ var delim = stream.eat(/[^\w\s]/);
+ if (!delim) return "operator";
+ if (matching.propertyIsEnumerable(delim)) delim = matching[delim];
+ return chain(readQuoted(delim, style, embed, true), stream, state);
+ } else if (ch == "#") {
+ stream.skipToEnd();
+ return "comment";
+ } else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) {
+ return chain(readHereDoc(m[1]), stream, state);
+ } else if (ch == "0") {
+ if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/);
+ else if (stream.eat("b")) stream.eatWhile(/[01]/);
+ else stream.eatWhile(/[0-7]/);
+ return "number";
+ } else if (/\d/.test(ch)) {
+ stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/);
+ return "number";
+ } else if (ch == "?") {
+ while (stream.match(/^\\[CM]-/)) {}
+ if (stream.eat("\\")) stream.eatWhile(/\w/);
+ else stream.next();
+ return "string";
+ } else if (ch == ":") {
+ if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state);
+ if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state);
+ stream.eatWhile(/[\w\?]/);
+ return "atom";
+ } else if (ch == "@") {
+ stream.eat("@");
+ stream.eatWhile(/[\w\?]/);
+ return "variable-2";
+ } else if (ch == "$") {
+ stream.next();
+ stream.eatWhile(/[\w\?]/);
+ return "variable-3";
+ } else if (/\w/.test(ch)) {
+ stream.eatWhile(/[\w\?]/);
+ if (stream.eat(":")) return "atom";
+ return "ident";
+ } else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) {
+ curPunc = "|";
+ return null;
+ } else if (/[\(\)\[\]{}\\;]/.test(ch)) {
+ curPunc = ch;
+ return null;
+ } else if (ch == "-" && stream.eat(">")) {
+ return "arrow";
+ } else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) {
+ stream.eatWhile(/[=+\-\/*:\.^%<>~|]/);
+ return "operator";
+ } else {
+ return null;
+ }
+ }
+
+ function tokenBaseUntilBrace() {
+ var depth = 1;
+ return function(stream, state) {
+ if (stream.peek() == "}") {
+ depth--;
+ if (depth == 0) {
+ state.tokenize.pop();
+ return state.tokenize[state.tokenize.length-1](stream, state);
+ }
+ } else if (stream.peek() == "{") {
+ depth++;
+ }
+ return tokenBase(stream, state);
+ };
+ }
+ function readQuoted(quote, style, embed, unescaped) {
+ return function(stream, state) {
+ var escaped = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == quote && (unescaped || !escaped)) {
+ state.tokenize.pop();
+ break;
+ }
+ if (embed && ch == "#" && !escaped && stream.eat("{")) {
+ state.tokenize.push(tokenBaseUntilBrace(arguments.callee));
+ break;
+ }
+ escaped = !escaped && ch == "\\";
+ }
+ return style;
+ };
+ }
+ function readHereDoc(phrase) {
+ return function(stream, state) {
+ if (stream.match(phrase)) state.tokenize.pop();
+ else stream.skipToEnd();
+ return "string";
+ };
+ }
+ function readBlockComment(stream, state) {
+ if (stream.sol() && stream.match("=end") && stream.eol())
+ state.tokenize.pop();
+ stream.skipToEnd();
+ return "comment";
+ }
+
+ return {
+ startState: function() {
+ return {tokenize: [tokenBase],
+ indented: 0,
+ context: {type: "top", indented: -config.indentUnit},
+ continuedLine: false,
+ lastTok: null,
+ varList: false};
+ },
+
+ token: function(stream, state) {
+ if (stream.sol()) state.indented = stream.indentation();
+ var style = state.tokenize[state.tokenize.length-1](stream, state), kwtype;
+ if (style == "ident") {
+ var word = stream.current();
+ style = keywords.propertyIsEnumerable(stream.current()) ? "keyword"
+ : /^[A-Z]/.test(word) ? "tag"
+ : (state.lastTok == "def" || state.lastTok == "class" || state.varList) ? "def"
+ : "variable";
+ if (indentWords.propertyIsEnumerable(word)) kwtype = "indent";
+ else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent";
+ else if ((word == "if" || word == "unless") && stream.column() == stream.indentation())
+ kwtype = "indent";
+ }
+ if (curPunc || (style && style != "comment")) state.lastTok = word || curPunc || style;
+ if (curPunc == "|") state.varList = !state.varList;
+
+ if (kwtype == "indent" || /[\(\[\{]/.test(curPunc))
+ state.context = {prev: state.context, type: curPunc || style, indented: state.indented};
+ else if ((kwtype == "dedent" || /[\)\]\}]/.test(curPunc)) && state.context.prev)
+ state.context = state.context.prev;
+
+ if (stream.eol())
+ state.continuedLine = (curPunc == "\\" || style == "operator");
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize[state.tokenize.length-1] != tokenBase) return 0;
+ var firstChar = textAfter && textAfter.charAt(0);
+ var ct = state.context;
+ var closing = ct.type == matching[firstChar] ||
+ ct.type == "keyword" && /^(?:end|until|else|elsif|when|rescue)\b/.test(textAfter);
+ return ct.indented + (closing ? 0 : config.indentUnit) +
+ (state.continuedLine ? config.indentUnit : 0);
+ },
+ electricChars: "}de" // enD and rescuE
+
+ };
+});
+
+CodeMirror.defineMIME("text/x-ruby", "ruby");
+
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/rust/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/rust/index.html
new file mode 100644
index 0000000..3b811e3
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/rust/index.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Rust mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="rust.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Rust mode</h1>
+
+<div><textarea id="code" name="code">
+// Demo code.
+
+type foo<T> = int;
+enum bar {
+ some(int, foo<float>),
+ none
+}
+
+fn check_crate(x: int) {
+ let v = 10;
+ alt foo {
+ 1 to 3 {
+ print_foo();
+ if x {
+ blah() + 10;
+ }
+ }
+ (x, y) { "bye" }
+ _ { "hi" }
+ }
+}
+</textarea></div>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ tabMode: "indent"
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-rustsrc</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/rust/rust.js b/codemirror_ui/lib/CodeMirror-2.3/mode/rust/rust.js
new file mode 100644
index 0000000..2a5caac
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/rust/rust.js
@@ -0,0 +1,432 @@
+CodeMirror.defineMode("rust", function() {
+ var indentUnit = 4, altIndentUnit = 2;
+ var valKeywords = {
+ "if": "if-style", "while": "if-style", "else": "else-style",
+ "do": "else-style", "ret": "else-style", "fail": "else-style",
+ "break": "atom", "cont": "atom", "const": "let", "resource": "fn",
+ "let": "let", "fn": "fn", "for": "for", "alt": "alt", "iface": "iface",
+ "impl": "impl", "type": "type", "enum": "enum", "mod": "mod",
+ "as": "op", "true": "atom", "false": "atom", "assert": "op", "check": "op",
+ "claim": "op", "native": "ignore", "unsafe": "ignore", "import": "else-style",
+ "export": "else-style", "copy": "op", "log": "op", "log_err": "op",
+ "use": "op", "bind": "op", "self": "atom"
+ };
+ var typeKeywords = function() {
+ var keywords = {"fn": "fn", "block": "fn", "obj": "obj"};
+ var atoms = "bool uint int i8 i16 i32 i64 u8 u16 u32 u64 float f32 f64 str char".split(" ");
+ for (var i = 0, e = atoms.length; i < e; ++i) keywords[atoms[i]] = "atom";
+ return keywords;
+ }();
+ var operatorChar = /[+\-*&%=<>!?|\.@]/;
+
+ // Tokenizer
+
+ // Used as scratch variable to communicate multiple values without
+ // consing up tons of objects.
+ var tcat, content;
+ function r(tc, style) {
+ tcat = tc;
+ return style;
+ }
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ if (ch == '"') {
+ state.tokenize = tokenString;
+ return state.tokenize(stream, state);
+ }
+ if (ch == "'") {
+ tcat = "atom";
+ if (stream.eat("\\")) {
+ if (stream.skipTo("'")) { stream.next(); return "string"; }
+ else { return "error"; }
+ } else {
+ stream.next();
+ return stream.eat("'") ? "string" : "error";
+ }
+ }
+ if (ch == "/") {
+ if (stream.eat("/")) { stream.skipToEnd(); return "comment"; }
+ if (stream.eat("*")) {
+ state.tokenize = tokenComment(1);
+ return state.tokenize(stream, state);
+ }
+ }
+ if (ch == "#") {
+ if (stream.eat("[")) { tcat = "open-attr"; return null; }
+ stream.eatWhile(/\w/);
+ return r("macro", "meta");
+ }
+ if (ch == ":" && stream.match(":<")) {
+ return r("op", null);
+ }
+ if (ch.match(/\d/) || (ch == "." && stream.eat(/\d/))) {
+ var flp = false;
+ if (!stream.match(/^x[\da-f]+/i) && !stream.match(/^b[01]+/)) {
+ stream.eatWhile(/\d/);
+ if (stream.eat(".")) { flp = true; stream.eatWhile(/\d/); }
+ if (stream.match(/^e[+\-]?\d+/i)) { flp = true; }
+ }
+ if (flp) stream.match(/^f(?:32|64)/);
+ else stream.match(/^[ui](?:8|16|32|64)/);
+ return r("atom", "number");
+ }
+ if (ch.match(/[()\[\]{}:;,]/)) return r(ch, null);
+ if (ch == "-" && stream.eat(">")) return r("->", null);
+ if (ch.match(operatorChar)) {
+ stream.eatWhile(operatorChar);
+ return r("op", null);
+ }
+ stream.eatWhile(/\w/);
+ content = stream.current();
+ if (stream.match(/^::\w/)) {
+ stream.backUp(1);
+ return r("prefix", "variable-2");
+ }
+ if (state.keywords.propertyIsEnumerable(content))
+ return r(state.keywords[content], content.match(/true|false/) ? "atom" : "keyword");
+ return r("name", "variable");
+ }
+
+ function tokenString(stream, state) {
+ var ch, escaped = false;
+ while (ch = stream.next()) {
+ if (ch == '"' && !escaped) {
+ state.tokenize = tokenBase;
+ return r("atom", "string");
+ }
+ escaped = !escaped && ch == "\\";
+ }
+ // Hack to not confuse the parser when a string is split in
+ // pieces.
+ return r("op", "string");
+ }
+
+ function tokenComment(depth) {
+ return function(stream, state) {
+ var lastCh = null, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && lastCh == "*") {
+ if (depth == 1) {
+ state.tokenize = tokenBase;
+ break;
+ } else {
+ state.tokenize = tokenComment(depth - 1);
+ return state.tokenize(stream, state);
+ }
+ }
+ if (ch == "*" && lastCh == "/") {
+ state.tokenize = tokenComment(depth + 1);
+ return state.tokenize(stream, state);
+ }
+ lastCh = ch;
+ }
+ return "comment";
+ };
+ }
+
+ // Parser
+
+ var cx = {state: null, stream: null, marked: null, cc: null};
+ function pass() {
+ for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
+ }
+ function cont() {
+ pass.apply(null, arguments);
+ return true;
+ }
+
+ function pushlex(type, info) {
+ var result = function() {
+ var state = cx.state;
+ state.lexical = {indented: state.indented, column: cx.stream.column(),
+ type: type, prev: state.lexical, info: info};
+ };
+ result.lex = true;
+ return result;
+ }
+ function poplex() {
+ var state = cx.state;
+ if (state.lexical.prev) {
+ if (state.lexical.type == ")")
+ state.indented = state.lexical.indented;
+ state.lexical = state.lexical.prev;
+ }
+ }
+ function typecx() { cx.state.keywords = typeKeywords; }
+ function valcx() { cx.state.keywords = valKeywords; }
+ poplex.lex = typecx.lex = valcx.lex = true;
+
+ function commasep(comb, end) {
+ function more(type) {
+ if (type == ",") return cont(comb, more);
+ if (type == end) return cont();
+ return cont(more);
+ }
+ return function(type) {
+ if (type == end) return cont();
+ return pass(comb, more);
+ };
+ }
+
+ function stat_of(comb, tag) {
+ return cont(pushlex("stat", tag), comb, poplex, block);
+ }
+ function block(type) {
+ if (type == "}") return cont();
+ if (type == "let") return stat_of(letdef1, "let");
+ if (type == "fn") return stat_of(fndef);
+ if (type == "type") return cont(pushlex("stat"), tydef, endstatement, poplex, block);
+ if (type == "enum") return stat_of(enumdef);
+ if (type == "mod") return stat_of(mod);
+ if (type == "iface") return stat_of(iface);
+ if (type == "impl") return stat_of(impl);
+ if (type == "open-attr") return cont(pushlex("]"), commasep(expression, "]"), poplex);
+ if (type == "ignore" || type.match(/[\]\);,]/)) return cont(block);
+ return pass(pushlex("stat"), expression, poplex, endstatement, block);
+ }
+ function endstatement(type) {
+ if (type == ";") return cont();
+ return pass();
+ }
+ function expression(type) {
+ if (type == "atom" || type == "name") return cont(maybeop);
+ if (type == "{") return cont(pushlex("}"), exprbrace, poplex);
+ if (type.match(/[\[\(]/)) return matchBrackets(type, expression);
+ if (type.match(/[\]\)\};,]/)) return pass();
+ if (type == "if-style") return cont(expression, expression);
+ if (type == "else-style" || type == "op") return cont(expression);
+ if (type == "for") return cont(pattern, maybetype, inop, expression, expression);
+ if (type == "alt") return cont(expression, altbody);
+ if (type == "fn") return cont(fndef);
+ if (type == "macro") return cont(macro);
+ return cont();
+ }
+ function maybeop(type) {
+ if (content == ".") return cont(maybeprop);
+ if (content == "::<"){return cont(typarams, maybeop);}
+ if (type == "op" || content == ":") return cont(expression);
+ if (type == "(" || type == "[") return matchBrackets(type, expression);
+ return pass();
+ }
+ function maybeprop(type) {
+ if (content.match(/^\w+$/)) {cx.marked = "variable"; return cont(maybeop);}
+ return pass(expression);
+ }
+ function exprbrace(type) {
+ if (type == "op") {
+ if (content == "|") return cont(blockvars, poplex, pushlex("}", "block"), block);
+ if (content == "||") return cont(poplex, pushlex("}", "block"), block);
+ }
+ if (content == "mutable" || (content.match(/^\w+$/) && cx.stream.peek() == ":"
+ && !cx.stream.match("::", false)))
+ return pass(record_of(expression));
+ return pass(block);
+ }
+ function record_of(comb) {
+ function ro(type) {
+ if (content == "mutable" || content == "with") {cx.marked = "keyword"; return cont(ro);}
+ if (content.match(/^\w*$/)) {cx.marked = "variable"; return cont(ro);}
+ if (type == ":") return cont(comb, ro);
+ if (type == "}") return cont();
+ return cont(ro);
+ }
+ return ro;
+ }
+ function blockvars(type) {
+ if (type == "name") {cx.marked = "def"; return cont(blockvars);}
+ if (type == "op" && content == "|") return cont();
+ return cont(blockvars);
+ }
+
+ function letdef1(type) {
+ if (type.match(/[\]\)\};]/)) return cont();
+ if (content == "=") return cont(expression, letdef2);
+ if (type == ",") return cont(letdef1);
+ return pass(pattern, maybetype, letdef1);
+ }
+ function letdef2(type) {
+ if (type.match(/[\]\)\};,]/)) return pass(letdef1);
+ else return pass(expression, letdef2);
+ }
+ function maybetype(type) {
+ if (type == ":") return cont(typecx, rtype, valcx);
+ return pass();
+ }
+ function inop(type) {
+ if (type == "name" && content == "in") {cx.marked = "keyword"; return cont();}
+ return pass();
+ }
+ function fndef(type) {
+ if (content == "@" || content == "~") {cx.marked = "keyword"; return cont(fndef);}
+ if (type == "name") {cx.marked = "def"; return cont(fndef);}
+ if (content == "<") return cont(typarams, fndef);
+ if (type == "{") return pass(expression);
+ if (type == "(") return cont(pushlex(")"), commasep(argdef, ")"), poplex, fndef);
+ if (type == "->") return cont(typecx, rtype, valcx, fndef);
+ if (type == ";") return cont();
+ return cont(fndef);
+ }
+ function tydef(type) {
+ if (type == "name") {cx.marked = "def"; return cont(tydef);}
+ if (content == "<") return cont(typarams, tydef);
+ if (content == "=") return cont(typecx, rtype, valcx);
+ return cont(tydef);
+ }
+ function enumdef(type) {
+ if (type == "name") {cx.marked = "def"; return cont(enumdef);}
+ if (content == "<") return cont(typarams, enumdef);
+ if (content == "=") return cont(typecx, rtype, valcx, endstatement);
+ if (type == "{") return cont(pushlex("}"), typecx, enumblock, valcx, poplex);
+ return cont(enumdef);
+ }
+ function enumblock(type) {
+ if (type == "}") return cont();
+ if (type == "(") return cont(pushlex(")"), commasep(rtype, ")"), poplex, enumblock);
+ if (content.match(/^\w+$/)) cx.marked = "def";
+ return cont(enumblock);
+ }
+ function mod(type) {
+ if (type == "name") {cx.marked = "def"; return cont(mod);}
+ if (type == "{") return cont(pushlex("}"), block, poplex);
+ return pass();
+ }
+ function iface(type) {
+ if (type == "name") {cx.marked = "def"; return cont(iface);}
+ if (content == "<") return cont(typarams, iface);
+ if (type == "{") return cont(pushlex("}"), block, poplex);
+ return pass();
+ }
+ function impl(type) {
+ if (content == "<") return cont(typarams, impl);
+ if (content == "of" || content == "for") {cx.marked = "keyword"; return cont(rtype, impl);}
+ if (type == "name") {cx.marked = "def"; return cont(impl);}
+ if (type == "{") return cont(pushlex("}"), block, poplex);
+ return pass();
+ }
+ function typarams(type) {
+ if (content == ">") return cont();
+ if (content == ",") return cont(typarams);
+ if (content == ":") return cont(rtype, typarams);
+ return pass(rtype, typarams);
+ }
+ function argdef(type) {
+ if (type == "name") {cx.marked = "def"; return cont(argdef);}
+ if (type == ":") return cont(typecx, rtype, valcx);
+ return pass();
+ }
+ function rtype(type) {
+ if (type == "name") {cx.marked = "variable-3"; return cont(rtypemaybeparam); }
+ if (content == "mutable") {cx.marked = "keyword"; return cont(rtype);}
+ if (type == "atom") return cont(rtypemaybeparam);
+ if (type == "op" || type == "obj") return cont(rtype);
+ if (type == "fn") return cont(fntype);
+ if (type == "{") return cont(pushlex("{"), record_of(rtype), poplex);
+ return matchBrackets(type, rtype);
+ }
+ function rtypemaybeparam(type) {
+ if (content == "<") return cont(typarams);
+ return pass();
+ }
+ function fntype(type) {
+ if (type == "(") return cont(pushlex("("), commasep(rtype, ")"), poplex, fntype);
+ if (type == "->") return cont(rtype);
+ return pass();
+ }
+ function pattern(type) {
+ if (type == "name") {cx.marked = "def"; return cont(patternmaybeop);}
+ if (type == "atom") return cont(patternmaybeop);
+ if (type == "op") return cont(pattern);
+ if (type.match(/[\]\)\};,]/)) return pass();
+ return matchBrackets(type, pattern);
+ }
+ function patternmaybeop(type) {
+ if (type == "op" && content == ".") return cont();
+ if (content == "to") {cx.marked = "keyword"; return cont(pattern);}
+ else return pass();
+ }
+ function altbody(type) {
+ if (type == "{") return cont(pushlex("}", "alt"), altblock1, poplex);
+ return pass();
+ }
+ function altblock1(type) {
+ if (type == "}") return cont();
+ if (type == "|") return cont(altblock1);
+ if (content == "when") {cx.marked = "keyword"; return cont(expression, altblock2);}
+ if (type.match(/[\]\);,]/)) return cont(altblock1);
+ return pass(pattern, altblock2);
+ }
+ function altblock2(type) {
+ if (type == "{") return cont(pushlex("}", "alt"), block, poplex, altblock1);
+ else return pass(altblock1);
+ }
+
+ function macro(type) {
+ if (type.match(/[\[\(\{]/)) return matchBrackets(type, expression);
+ return pass();
+ }
+ function matchBrackets(type, comb) {
+ if (type == "[") return cont(pushlex("]"), commasep(comb, "]"), poplex);
+ if (type == "(") return cont(pushlex(")"), commasep(comb, ")"), poplex);
+ if (type == "{") return cont(pushlex("}"), commasep(comb, "}"), poplex);
+ return cont();
+ }
+
+ function parse(state, stream, style) {
+ var cc = state.cc;
+ // Communicate our context to the combinators.
+ // (Less wasteful than consing up a hundred closures on every call.)
+ cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
+
+ while (true) {
+ var combinator = cc.length ? cc.pop() : block;
+ if (combinator(tcat)) {
+ while(cc.length && cc[cc.length - 1].lex)
+ cc.pop()();
+ return cx.marked || style;
+ }
+ }
+ }
+
+ return {
+ startState: function() {
+ return {
+ tokenize: tokenBase,
+ cc: [],
+ lexical: {indented: -indentUnit, column: 0, type: "top", align: false},
+ keywords: valKeywords,
+ indented: 0
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.sol()) {
+ if (!state.lexical.hasOwnProperty("align"))
+ state.lexical.align = false;
+ state.indented = stream.indentation();
+ }
+ if (stream.eatSpace()) return null;
+ tcat = content = null;
+ var style = state.tokenize(stream, state);
+ if (style == "comment") return style;
+ if (!state.lexical.hasOwnProperty("align"))
+ state.lexical.align = true;
+ if (tcat == "prefix") return style;
+ if (!content) content = stream.current();
+ return parse(state, stream, style);
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != tokenBase) return 0;
+ var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
+ type = lexical.type, closing = firstChar == type;
+ if (type == "stat") return lexical.indented + indentUnit;
+ if (lexical.align) return lexical.column + (closing ? 0 : 1);
+ return lexical.indented + (closing ? 0 : (lexical.info == "alt" ? altIndentUnit : indentUnit));
+ },
+
+ electricChars: "{}"
+ };
+});
+
+CodeMirror.defineMIME("text/x-rustsrc", "rust");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/scheme/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/scheme/index.html
new file mode 100644
index 0000000..2a6105f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/scheme/index.html
@@ -0,0 +1,64 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Scheme mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="scheme.js"></script>
+ <style>.CodeMirror {background: #f8f8f8;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Scheme mode</h1>
+ <form><textarea id="code" name="code">
+; See if the input starts with a given symbol.
+(define (match-symbol input pattern)
+ (cond ((null? (remain input)) #f)
+ ((eqv? (car (remain input)) pattern) (r-cdr input))
+ (else #f)))
+
+; Allow the input to start with one of a list of patterns.
+(define (match-or input pattern)
+ (cond ((null? pattern) #f)
+ ((match-pattern input (car pattern)))
+ (else (match-or input (cdr pattern)))))
+
+; Allow a sequence of patterns.
+(define (match-seq input pattern)
+ (if (null? pattern)
+ input
+ (let ((match (match-pattern input (car pattern))))
+ (if match (match-seq match (cdr pattern)) #f))))
+
+; Match with the pattern but no problem if it does not match.
+(define (match-opt input pattern)
+ (let ((match (match-pattern input (car pattern))))
+ (if match match input)))
+
+; Match anything (other than '()), until pattern is found. The rather
+; clumsy form of requiring an ending pattern is needed to decide where
+; the end of the match is. If none is given, this will match the rest
+; of the sentence.
+(define (match-any input pattern)
+ (cond ((null? (remain input)) #f)
+ ((null? pattern) (f-cons (remain input) (clear-remain input)))
+ (else
+ (let ((accum-any (collector)))
+ (define (match-pattern-any input pattern)
+ (cond ((null? (remain input)) #f)
+ (else (accum-any (car (remain input)))
+ (cond ((match-pattern (r-cdr input) pattern))
+ (else (match-pattern-any (r-cdr input) pattern))))))
+ (let ((retval (match-pattern-any input (car pattern))))
+ (if retval
+ (f-cons (accum-any) retval)
+ #f))))))
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-scheme</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/scheme/scheme.js b/codemirror_ui/lib/CodeMirror-2.3/mode/scheme/scheme.js
new file mode 100644
index 0000000..f981b23
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/scheme/scheme.js
@@ -0,0 +1,230 @@
+/**
+ * Author: Koh Zi Han, based on implementation by Koh Zi Chun
+ */
+CodeMirror.defineMode("scheme", function (config, mode) {
+ var BUILTIN = "builtin", COMMENT = "comment", STRING = "string",
+ ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD="keyword";
+ var INDENT_WORD_SKIP = 2, KEYWORDS_SKIP = 1;
+
+ function makeKeywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+
+ var keywords = makeKeywords("λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci<? char-ci=? char-ci>=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char<? char=? char>=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci<? string-ci=? string-ci>=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string<? string=? string>=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?");
+ var indentKeys = makeKeywords("define let letrec let* lambda");
+
+ function stateStack(indent, type, prev) { // represents a state stack object
+ this.indent = indent;
+ this.type = type;
+ this.prev = prev;
+ }
+
+ function pushStack(state, indent, type) {
+ state.indentStack = new stateStack(indent, type, state.indentStack);
+ }
+
+ function popStack(state) {
+ state.indentStack = state.indentStack.prev;
+ }
+
+ var binaryMatcher = new RegExp(/^(?:[-+]i|[-+][01]+#*(?:\/[01]+#*)?i|[-+]?[01]+#*(?:\/[01]+#*)?@[-+]?[01]+#*(?:\/[01]+#*)?|[-+]?[01]+#*(?:\/[01]+#*)?[-+](?:[01]+#*(?:\/[01]+#*)?)?i|[-+]?[01]+#*(?:\/[01]+#*)?)(?=[()\s;"]|$)/i);
+ var octalMatcher = new RegExp(/^(?:[-+]i|[-+][0-7]+#*(?:\/[0-7]+#*)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?@[-+]?[0-7]+#*(?:\/[0-7]+#*)?|[-+]?[0-7]+#*(?:\/[0-7]+#*)?[-+](?:[0-7]+#*(?:\/[0-7]+#*)?)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?)(?=[()\s;"]|$)/i);
+ var hexMatcher = new RegExp(/^(?:[-+]i|[-+][\da-f]+#*(?:\/[\da-f]+#*)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?@[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?[-+](?:[\da-f]+#*(?:\/[\da-f]+#*)?)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?)(?=[()\s;"]|$)/i);
+ var decimalMatcher = new RegExp(/^(?:[-+]i|[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)i|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)@[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)?i|(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*))(?=[()\s;"]|$)/i);
+
+ function isBinaryNumber (stream) {
+ return stream.match(binaryMatcher);
+ }
+
+ function isOctalNumber (stream) {
+ return stream.match(octalMatcher);
+ }
+
+ function isDecimalNumber (stream, backup) {
+ if (backup === true) {
+ stream.backUp(1);
+ }
+ return stream.match(decimalMatcher);
+ }
+
+ function isHexNumber (stream) {
+ return stream.match(hexMatcher);
+ }
+
+ return {
+ startState: function () {
+ return {
+ indentStack: null,
+ indentation: 0,
+ mode: false,
+ sExprComment: false
+ };
+ },
+
+ token: function (stream, state) {
+ if (state.indentStack == null && stream.sol()) {
+ // update indentation, but only if indentStack is empty
+ state.indentation = stream.indentation();
+ }
+
+ // skip spaces
+ if (stream.eatSpace()) {
+ return null;
+ }
+ var returnType = null;
+
+ switch(state.mode){
+ case "string": // multi-line string parsing mode
+ var next, escaped = false;
+ while ((next = stream.next()) != null) {
+ if (next == "\"" && !escaped) {
+
+ state.mode = false;
+ break;
+ }
+ escaped = !escaped && next == "\\";
+ }
+ returnType = STRING; // continue on in scheme-string mode
+ break;
+ case "comment": // comment parsing mode
+ var next, maybeEnd = false;
+ while ((next = stream.next()) != null) {
+ if (next == "#" && maybeEnd) {
+
+ state.mode = false;
+ break;
+ }
+ maybeEnd = (next == "|");
+ }
+ returnType = COMMENT;
+ break;
+ case "s-expr-comment": // s-expr commenting mode
+ state.mode = false;
+ if(stream.peek() == "(" || stream.peek() == "["){
+ // actually start scheme s-expr commenting mode
+ state.sExprComment = 0;
+ }else{
+ // if not we just comment the entire of the next token
+ stream.eatWhile(/[^/s]/); // eat non spaces
+ returnType = COMMENT;
+ break;
+ }
+ default: // default parsing mode
+ var ch = stream.next();
+
+ if (ch == "\"") {
+ state.mode = "string";
+ returnType = STRING;
+
+ } else if (ch == "'") {
+ returnType = ATOM;
+ } else if (ch == '#') {
+ if (stream.eat("|")) { // Multi-line comment
+ state.mode = "comment"; // toggle to comment mode
+ returnType = COMMENT;
+ } else if (stream.eat(/[tf]/i)) { // #t/#f (atom)
+ returnType = ATOM;
+ } else if (stream.eat(';')) { // S-Expr comment
+ state.mode = "s-expr-comment";
+ returnType = COMMENT;
+ } else {
+ var numTest = null, hasExactness = false, hasRadix = true;
+ if (stream.eat(/[ei]/i)) {
+ hasExactness = true;
+ } else {
+ stream.backUp(1); // must be radix specifier
+ }
+ if (stream.match(/^#b/i)) {
+ numTest = isBinaryNumber;
+ } else if (stream.match(/^#o/i)) {
+ numTest = isOctalNumber;
+ } else if (stream.match(/^#x/i)) {
+ numTest = isHexNumber;
+ } else if (stream.match(/^#d/i)) {
+ numTest = isDecimalNumber;
+ } else if (stream.match(/^[-+0-9.]/, false)) {
+ hasRadix = false;
+ numTest = isDecimalNumber;
+ // re-consume the intial # if all matches failed
+ } else if (!hasExactness) {
+ stream.eat('#');
+ }
+ if (numTest != null) {
+ if (hasRadix && !hasExactness) {
+ // consume optional exactness after radix
+ stream.match(/^#[ei]/i);
+ }
+ if (numTest(stream))
+ returnType = NUMBER;
+ }
+ }
+ } else if (/^[-+0-9.]/.test(ch) && isDecimalNumber(stream, true)) { // match non-prefixed number, must be decimal
+ returnType = NUMBER;
+ } else if (ch == ";") { // comment
+ stream.skipToEnd(); // rest of the line is a comment
+ returnType = COMMENT;
+ } else if (ch == "(" || ch == "[") {
+ var keyWord = ''; var indentTemp = stream.column();
+ /**
+ Either
+ (indent-word ..
+ (non-indent-word ..
+ (;something else, bracket, etc.
+ */
+
+ while ((letter = stream.eat(/[^\s\(\[\;\)\]]/)) != null) {
+ keyWord += letter;
+ }
+
+ if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word
+
+ pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
+ } else { // non-indent word
+ // we continue eating the spaces
+ stream.eatSpace();
+ if (stream.eol() || stream.peek() == ";") {
+ // nothing significant after
+ // we restart indentation 1 space after
+ pushStack(state, indentTemp + 1, ch);
+ } else {
+ pushStack(state, indentTemp + stream.current().length, ch); // else we match
+ }
+ }
+ stream.backUp(stream.current().length - 1); // undo all the eating
+
+ if(typeof state.sExprComment == "number") state.sExprComment++;
+
+ returnType = BRACKET;
+ } else if (ch == ")" || ch == "]") {
+ returnType = BRACKET;
+ if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) {
+ popStack(state);
+
+ if(typeof state.sExprComment == "number"){
+ if(--state.sExprComment == 0){
+ returnType = COMMENT; // final closing bracket
+ state.sExprComment = false; // turn off s-expr commenting mode
+ }
+ }
+ }
+ } else {
+ stream.eatWhile(/[\w\$_\-!$%&*+\.\/:<=>?@\^~]/);
+
+ if (keywords && keywords.propertyIsEnumerable(stream.current())) {
+ returnType = BUILTIN;
+ } else returnType = "variable";
+ }
+ }
+ return (typeof state.sExprComment == "number") ? COMMENT : returnType;
+ },
+
+ indent: function (state, textAfter) {
+ if (state.indentStack == null) return state.indentation;
+ return state.indentStack.indent;
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-scheme", "scheme");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/shell/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/shell/index.html
new file mode 100644
index 0000000..2d6d084
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/shell/index.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CodeMirror: Shell mode</title>
+
+<link rel=stylesheet href=../../lib/codemirror.css>
+<link rel=stylesheet href=../../doc/docs.css>
+
+<style type=text/css>
+ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+</style>
+
+<script src=../../lib/codemirror.js></script>
+<script src=shell.js></script>
+
+<h1>CodeMirror: Shell mode</h1>
+
+<textarea id=code>
+#!/bin/bash
+
+# clone the repository
+git clone http://github.com/garden/tree
+
+# generate HTTPS credentials
+cd tree
+openssl genrsa -aes256 -out https.key 1024
+openssl req -new -nodes -key https.key -out https.csr
+openssl x509 -req -days 365 -in https.csr -signkey https.key -out https.crt
+cp https.key{,.orig}
+openssl rsa -in https.key.orig -out https.key
+
+# start the server in HTTPS mode
+cd web
+sudo node ../server.js 443 'yes' &gt;&gt; ../node.log &amp;
+
+# here is how to stop the server
+for pid in `ps aux | grep 'node ../server.js' | awk '{print $2}'` ; do
+ sudo kill -9 $pid 2&gt; /dev/null
+done
+
+exit 0</textarea>
+
+<script>
+ var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
+ mode: 'shell',
+ lineNumbers: true,
+ matchBrackets: true
+ });
+</script>
+
+<p><strong>MIME types defined:</strong> <code>text/x-sh</code>.</p>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/shell/shell.js b/codemirror_ui/lib/CodeMirror-2.3/mode/shell/shell.js
new file mode 100644
index 0000000..dddca86
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/shell/shell.js
@@ -0,0 +1,103 @@
+CodeMirror.defineMode('shell', function(config) {
+
+ var atoms = ['true','false'],
+ keywords = ['if','then','do','else','elif','while','until','for','in','esac','fi','fin','fil','done','exit','set','unset','export','function'],
+ commands = ['ab','awk','bash','beep','cat','cc','cd','chown','chmod','chroot','clear','cp','curl','cut','diff','echo','find','gawk','gcc','get','git','grep','kill','killall','ls','make','mkdir','openssl','mv','nc','node','npm','ping','ps','restart','rm','rmdir','sed','service','sh','shopt','shred','source','sort','sleep','ssh','start','stop','su','sudo','tee','telnet','top','touch','vi','vim','wall','wc','wget','who','write','yes','zsh'];
+
+ function tokenBase(stream, state) {
+
+ var sol = stream.sol();
+ var ch = stream.next();
+
+ if (ch === '\'' || ch === '"' || ch === '`') {
+ state.tokens.unshift(tokenString(ch));
+ return tokenize(stream, state);
+ }
+ if (ch === '#') {
+ if (sol && stream.eat('!')) {
+ stream.skipToEnd();
+ return 'meta'; // 'comment'?
+ }
+ stream.skipToEnd();
+ return 'comment';
+ }
+ if (ch === '$') {
+ state.tokens.unshift(tokenDollar);
+ return tokenize(stream, state);
+ }
+ if (ch === '+' || ch === '=') {
+ return 'operator';
+ }
+ if (ch === '-') {
+ stream.eat('-');
+ stream.eatWhile(/\w/);
+ return 'attribute';
+ }
+ if (/\d/.test(ch)) {
+ stream.eatWhile(/\d/);
+ if(!/\w/.test(stream.peek())) {
+ return 'number';
+ }
+ }
+ stream.eatWhile(/\w/);
+ var cur = stream.current();
+ if (stream.peek() === '=' && /\w+/.test(cur)) return 'def';
+ if (atoms.indexOf(cur) !== -1) return 'atom';
+ if (commands.indexOf(cur) !== -1) return 'builtin';
+ if (keywords.indexOf(cur) !== -1) return 'keyword';
+ return 'word';
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var next, end = false, escaped = false;
+ while ((next = stream.next()) != null) {
+ if (next === quote && !escaped) {
+ end = true;
+ break;
+ }
+ if (next === '$' && !escaped && quote !== '\'') {
+ escaped = true;
+ stream.backUp(1);
+ state.tokens.unshift(tokenDollar);
+ break;
+ }
+ escaped = !escaped && next === '\\';
+ }
+ if (end || !escaped) {
+ state.tokens.shift();
+ }
+ return (quote === '`' || quote === ')' ? 'quote' : 'string');
+ };
+ };
+
+ var tokenDollar = function(stream, state) {
+ if (state.tokens.length > 1) stream.eat('$');
+ var ch = stream.next(), hungry = /\w/;
+ if (ch === '{') hungry = /[^}]/;
+ if (ch === '(') {
+ state.tokens[0] = tokenString(')');
+ return tokenize(stream, state);
+ }
+ if (!/\d/.test(ch)) {
+ stream.eatWhile(hungry);
+ stream.eat('}');
+ }
+ state.tokens.shift();
+ return 'def';
+ };
+
+ function tokenize(stream, state) {
+ return (state.tokens[0] || tokenBase) (stream, state);
+ };
+
+ return {
+ startState: function() {return {tokens:[]}},
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ return tokenize(stream, state);
+ }
+ };
+});
+
+CodeMirror.defineMIME('text/x-sh', 'shell');
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/smalltalk/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/smalltalk/index.html
new file mode 100644
index 0000000..8a85c39
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/smalltalk/index.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Smalltalk mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="smalltalk.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>
+ .CodeMirror {border: 2px solid #dee; border-right-width: 10px;}
+ .CodeMirror-gutter {border: none; background: #dee;}
+ .CodeMirror-gutter pre {color: white; font-weight: bold;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Smalltalk mode</h1>
+
+<form><textarea id="code" name="code">
+"
+ This is a test of the Smalltalk code
+"
+Seaside.WAComponent subclass: #MyCounter [
+ | count |
+ MyCounter class &gt;&gt; canBeRoot [ ^true ]
+
+ initialize [
+ super initialize.
+ count := 0.
+ ]
+ states [ ^{ self } ]
+ renderContentOn: html [
+ html heading: count.
+ html anchor callback: [ count := count + 1 ]; with: '++'.
+ html space.
+ html anchor callback: [ count := count - 1 ]; with: '--'.
+ ]
+]
+
+MyCounter registerAsApplication: 'mycounter'
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ mode: "text/x-stsrc",
+ indentUnit: 4
+ });
+ </script>
+
+ <p>Simple Smalltalk mode.</p>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-stsrc</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/smalltalk/smalltalk.js b/codemirror_ui/lib/CodeMirror-2.3/mode/smalltalk/smalltalk.js
new file mode 100644
index 0000000..e589332
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/smalltalk/smalltalk.js
@@ -0,0 +1,139 @@
+CodeMirror.defineMode('smalltalk', function(config, modeConfig) {
+
+ var specialChars = /[+\-/\\*~<>=@%|&?!.:;^]/;
+ var keywords = /true|false|nil|self|super|thisContext/;
+
+ var Context = function(tokenizer, parent) {
+ this.next = tokenizer;
+ this.parent = parent;
+ };
+
+ var Token = function(name, context, eos) {
+ this.name = name;
+ this.context = context;
+ this.eos = eos;
+ };
+
+ var State = function() {
+ this.context = new Context(next, null);
+ this.expectVariable = true;
+ this.indentation = 0;
+ this.userIndentationDelta = 0;
+ };
+
+ State.prototype.userIndent = function(indentation) {
+ this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0;
+ };
+
+ var next = function(stream, context, state) {
+ var token = new Token(null, context, false);
+ var aChar = stream.next();
+
+ if (aChar === '"') {
+ token = nextComment(stream, new Context(nextComment, context));
+
+ } else if (aChar === '\'') {
+ token = nextString(stream, new Context(nextString, context));
+
+ } else if (aChar === '#') {
+ stream.eatWhile(/[^ .]/);
+ token.name = 'string-2';
+
+ } else if (aChar === '$') {
+ stream.eatWhile(/[^ ]/);
+ token.name = 'string-2';
+
+ } else if (aChar === '|' && state.expectVariable) {
+ token.context = new Context(nextTemporaries, context);
+
+ } else if (/[\[\]{}()]/.test(aChar)) {
+ token.name = 'bracket';
+ token.eos = /[\[{(]/.test(aChar);
+
+ if (aChar === '[') {
+ state.indentation++;
+ } else if (aChar === ']') {
+ state.indentation = Math.max(0, state.indentation - 1);
+ }
+
+ } else if (specialChars.test(aChar)) {
+ stream.eatWhile(specialChars);
+ token.name = 'operator';
+ token.eos = aChar !== ';'; // ; cascaded message expression
+
+ } else if (/\d/.test(aChar)) {
+ stream.eatWhile(/[\w\d]/);
+ token.name = 'number'
+
+ } else if (/[\w_]/.test(aChar)) {
+ stream.eatWhile(/[\w\d_]/);
+ token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null;
+
+ } else {
+ token.eos = state.expectVariable;
+ }
+
+ return token;
+ };
+
+ var nextComment = function(stream, context) {
+ stream.eatWhile(/[^"]/);
+ return new Token('comment', stream.eat('"') ? context.parent : context, true);
+ };
+
+ var nextString = function(stream, context) {
+ stream.eatWhile(/[^']/);
+ return new Token('string', stream.eat('\'') ? context.parent : context, false);
+ };
+
+ var nextTemporaries = function(stream, context, state) {
+ var token = new Token(null, context, false);
+ var aChar = stream.next();
+
+ if (aChar === '|') {
+ token.context = context.parent;
+ token.eos = true;
+
+ } else {
+ stream.eatWhile(/[^|]/);
+ token.name = 'variable';
+ }
+
+ return token;
+ }
+
+ return {
+ startState: function() {
+ return new State;
+ },
+
+ token: function(stream, state) {
+ state.userIndent(stream.indentation());
+
+ if (stream.eatSpace()) {
+ return null;
+ }
+
+ var token = state.context.next(stream, state.context, state);
+ state.context = token.context;
+ state.expectVariable = token.eos;
+
+ state.lastToken = token;
+ return token.name;
+ },
+
+ blankLine: function(state) {
+ state.userIndent(0);
+ },
+
+ indent: function(state, textAfter) {
+ var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta;
+ return (state.indentation + i) * config.indentUnit;
+ },
+
+ electricChars: ']'
+ };
+
+});
+
+CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'}); \ No newline at end of file
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/smarty/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/smarty/index.html
new file mode 100644
index 0000000..ad4dccf
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/smarty/index.html
@@ -0,0 +1,82 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Smarty mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="smarty.js"></script>
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Smarty mode</h1>
+
+ <form><textarea id="code" name="code">
+{extends file="parent.tpl"}
+{include file="template.tpl"}
+
+{* some example Smarty content *}
+{if isset($name) && $name == 'Blog'}
+ This is a {$var}.
+ {$integer = 451}, {$array[] = "a"}, {$stringvar = "string"}
+ {assign var='bob' value=$var.prop}
+{elseif $name == $foo}
+ {function name=menu level=0}
+ {foreach $data as $entry}
+ {if is_array($entry)}
+ - {$entry@key}
+ {menu data=$entry level=$level+1}
+ {else}
+ {$entry}
+ {/if}
+ {/foreach}
+ {/function}
+{/if}</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ mode: "smarty"
+ });
+ </script>
+
+ <br />
+
+ <form><textarea id="code2" name="code2">
+{--extends file="parent.tpl"--}
+{--include file="template.tpl"--}
+
+{--* some example Smarty content *--}
+{--if isset($name) && $name == 'Blog'--}
+ This is a {--$var--}.
+ {--$integer = 451--}, {--$array[] = "a"--}, {--$stringvar = "string"--}
+ {--assign var='bob' value=$var.prop--}
+{--elseif $name == $foo--}
+ {--function name=menu level=0--}
+ {--foreach $data as $entry--}
+ {--if is_array($entry)--}
+ - {--$entry@key--}
+ {--menu data=$entry level=$level+1--}
+ {--else--}
+ {--$entry--}
+ {--/if--}
+ {--/foreach--}
+ {--/function--}
+{--/if--}</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code2"), {
+ lineNumbers: true,
+ mode: {
+ name: "smarty",
+ leftDelimiter: "{--",
+ rightDelimiter: "--}"
+ }
+ });
+ </script>
+
+ <p>A plain text/Smarty mode which allows for custom delimiter tags (defaults to <b>{</b> and <b>}</b>).</p>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-smarty</code></p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/smarty/smarty.js b/codemirror_ui/lib/CodeMirror-2.3/mode/smarty/smarty.js
new file mode 100644
index 0000000..9da7da6
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/smarty/smarty.js
@@ -0,0 +1,148 @@
+CodeMirror.defineMode("smarty", function(config, parserConfig) {
+ var keyFuncs = ["debug", "extends", "function", "include", "literal"];
+ var last;
+ var regs = {
+ operatorChars: /[+\-*&%=<>!?]/,
+ validIdentifier: /[a-zA-Z0-9\_]/,
+ stringChar: /[\'\"]/
+ }
+ var leftDelim = (typeof config.mode.leftDelimiter != 'undefined') ? config.mode.leftDelimiter : "{";
+ var rightDelim = (typeof config.mode.rightDelimiter != 'undefined') ? config.mode.rightDelimiter : "}";
+ function ret(style, lst) { last = lst; return style; }
+
+
+ function tokenizer(stream, state) {
+ function chain(parser) {
+ state.tokenize = parser;
+ return parser(stream, state);
+ }
+
+ if (stream.match(leftDelim, true)) {
+ if (stream.eat("*")) {
+ return chain(inBlock("comment", "*" + rightDelim));
+ }
+ else {
+ state.tokenize = inSmarty;
+ return "tag";
+ }
+ }
+ else {
+ // I'd like to do an eatWhile() here, but I can't get it to eat only up to the rightDelim string/char
+ stream.next();
+ return null;
+ }
+ }
+
+ function inSmarty(stream, state) {
+ if (stream.match(rightDelim, true)) {
+ state.tokenize = tokenizer;
+ return ret("tag", null);
+ }
+
+ var ch = stream.next();
+ if (ch == "$") {
+ stream.eatWhile(regs.validIdentifier);
+ return ret("variable-2", "variable");
+ }
+ else if (ch == ".") {
+ return ret("operator", "property");
+ }
+ else if (regs.stringChar.test(ch)) {
+ state.tokenize = inAttribute(ch);
+ return ret("string", "string");
+ }
+ else if (regs.operatorChars.test(ch)) {
+ stream.eatWhile(regs.operatorChars);
+ return ret("operator", "operator");
+ }
+ else if (ch == "[" || ch == "]") {
+ return ret("bracket", "bracket");
+ }
+ else if (/\d/.test(ch)) {
+ stream.eatWhile(/\d/);
+ return ret("number", "number");
+ }
+ else {
+ if (state.last == "variable") {
+ if (ch == "@") {
+ stream.eatWhile(regs.validIdentifier);
+ return ret("property", "property");
+ }
+ else if (ch == "|") {
+ stream.eatWhile(regs.validIdentifier);
+ return ret("qualifier", "modifier");
+ }
+ }
+ else if (state.last == "whitespace") {
+ stream.eatWhile(regs.validIdentifier);
+ return ret("attribute", "modifier");
+ }
+ else if (state.last == "property") {
+ stream.eatWhile(regs.validIdentifier);
+ return ret("property", null);
+ }
+ else if (/\s/.test(ch)) {
+ last = "whitespace";
+ return null;
+ }
+
+ var str = "";
+ if (ch != "/") {
+ str += ch;
+ }
+ var c = "";
+ while ((c = stream.eat(regs.validIdentifier))) {
+ str += c;
+ }
+ var i, j;
+ for (i=0, j=keyFuncs.length; i<j; i++) {
+ if (keyFuncs[i] == str) {
+ return ret("keyword", "keyword");
+ }
+ }
+ if (/\s/.test(ch)) {
+ return null;
+ }
+ return ret("tag", "tag");
+ }
+ }
+
+ function inAttribute(quote) {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ if (stream.next() == quote) {
+ state.tokenize = inSmarty;
+ break;
+ }
+ }
+ return "string";
+ };
+ }
+
+ function inBlock(style, terminator) {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ if (stream.match(terminator)) {
+ state.tokenize = tokenizer;
+ break;
+ }
+ stream.next();
+ }
+ return style;
+ };
+ }
+
+ return {
+ startState: function() {
+ return { tokenize: tokenizer, mode: "smarty", last: null };
+ },
+ token: function(stream, state) {
+ var style = state.tokenize(stream, state);
+ state.last = last;
+ return style;
+ },
+ electricChars: ""
+ }
+});
+
+CodeMirror.defineMIME("text/x-smarty", "smarty"); \ No newline at end of file
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/sparql/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/sparql/index.html
new file mode 100644
index 0000000..d7772f6
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/sparql/index.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: SPARQL mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="sparql.js"></script>
+ <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: SPARQL mode</h1>
+ <form><textarea id="code" name="code">
+PREFIX a: &lt;http://www.w3.org/2000/10/annotation-ns#>
+PREFIX dc: &lt;http://purl.org/dc/elements/1.1/>
+PREFIX foaf: &lt;http://xmlns.com/foaf/0.1/>
+
+# Comment!
+
+SELECT ?given ?family
+WHERE {
+ ?annot a:annotates &lt;http://www.w3.org/TR/rdf-sparql-query/> .
+ ?annot dc:creator ?c .
+ OPTIONAL {?c foaf:given ?given ;
+ foaf:family ?family } .
+ FILTER isBlank(?c)
+}
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: "application/x-sparql-query",
+ tabMode: "indent",
+ matchBrackets: true
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>application/x-sparql-query</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/sparql/sparql.js b/codemirror_ui/lib/CodeMirror-2.3/mode/sparql/sparql.js
new file mode 100644
index 0000000..ceb5294
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/sparql/sparql.js
@@ -0,0 +1,143 @@
+CodeMirror.defineMode("sparql", function(config) {
+ var indentUnit = config.indentUnit;
+ var curPunc;
+
+ function wordRegexp(words) {
+ return new RegExp("^(?:" + words.join("|") + ")$", "i");
+ }
+ var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri",
+ "isblank", "isliteral", "union", "a"]);
+ var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe",
+ "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional",
+ "graph", "by", "asc", "desc"]);
+ var operatorChars = /[*+\-<>=&|]/;
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ curPunc = null;
+ if (ch == "$" || ch == "?") {
+ stream.match(/^[\w\d]*/);
+ return "variable-2";
+ }
+ else if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) {
+ stream.match(/^[^\s\u00a0>]*>?/);
+ return "atom";
+ }
+ else if (ch == "\"" || ch == "'") {
+ state.tokenize = tokenLiteral(ch);
+ return state.tokenize(stream, state);
+ }
+ else if (/[{}\(\),\.;\[\]]/.test(ch)) {
+ curPunc = ch;
+ return null;
+ }
+ else if (ch == "#") {
+ stream.skipToEnd();
+ return "comment";
+ }
+ else if (operatorChars.test(ch)) {
+ stream.eatWhile(operatorChars);
+ return null;
+ }
+ else if (ch == ":") {
+ stream.eatWhile(/[\w\d\._\-]/);
+ return "atom";
+ }
+ else {
+ stream.eatWhile(/[_\w\d]/);
+ if (stream.eat(":")) {
+ stream.eatWhile(/[\w\d_\-]/);
+ return "atom";
+ }
+ var word = stream.current(), type;
+ if (ops.test(word))
+ return null;
+ else if (keywords.test(word))
+ return "keyword";
+ else
+ return "variable";
+ }
+ }
+
+ function tokenLiteral(quote) {
+ return function(stream, state) {
+ var escaped = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == quote && !escaped) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ escaped = !escaped && ch == "\\";
+ }
+ return "string";
+ };
+ }
+
+ function pushContext(state, type, col) {
+ state.context = {prev: state.context, indent: state.indent, col: col, type: type};
+ }
+ function popContext(state) {
+ state.indent = state.context.indent;
+ state.context = state.context.prev;
+ }
+
+ return {
+ startState: function(base) {
+ return {tokenize: tokenBase,
+ context: null,
+ indent: 0,
+ col: 0};
+ },
+
+ token: function(stream, state) {
+ if (stream.sol()) {
+ if (state.context && state.context.align == null) state.context.align = false;
+ state.indent = stream.indentation();
+ }
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+
+ if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") {
+ state.context.align = true;
+ }
+
+ if (curPunc == "(") pushContext(state, ")", stream.column());
+ else if (curPunc == "[") pushContext(state, "]", stream.column());
+ else if (curPunc == "{") pushContext(state, "}", stream.column());
+ else if (/[\]\}\)]/.test(curPunc)) {
+ while (state.context && state.context.type == "pattern") popContext(state);
+ if (state.context && curPunc == state.context.type) popContext(state);
+ }
+ else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state);
+ else if (/atom|string|variable/.test(style) && state.context) {
+ if (/[\}\]]/.test(state.context.type))
+ pushContext(state, "pattern", stream.column());
+ else if (state.context.type == "pattern" && !state.context.align) {
+ state.context.align = true;
+ state.context.col = stream.column();
+ }
+ }
+
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ var firstChar = textAfter && textAfter.charAt(0);
+ var context = state.context;
+ if (/[\]\}]/.test(firstChar))
+ while (context && context.type == "pattern") context = context.prev;
+
+ var closing = context && firstChar == context.type;
+ if (!context)
+ return 0;
+ else if (context.type == "pattern")
+ return context.col;
+ else if (context.align)
+ return context.col + (closing ? 0 : 1);
+ else
+ return context.indent + (closing ? 0 : indentUnit);
+ }
+ };
+});
+
+CodeMirror.defineMIME("application/x-sparql-query", "sparql");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/stex/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/stex/index.html
new file mode 100644
index 0000000..e49289e
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/stex/index.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: sTeX mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="stex.js"></script>
+ <style>.CodeMirror {background: #f8f8f8;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: sTeX mode</h1>
+ <form><textarea id="code" name="code">
+\begin{module}[id=bbt-size]
+\importmodule[balanced-binary-trees]{balanced-binary-trees}
+\importmodule[\KWARCslides{dmath/en/cardinality}]{cardinality}
+
+\begin{frame}
+ \frametitle{Size Lemma for Balanced Trees}
+ \begin{itemize}
+ \item
+ \begin{assertion}[id=size-lemma,type=lemma]
+ Let $G=\tup{V,E}$ be a \termref[cd=binary-trees]{balanced binary tree}
+ of \termref[cd=graph-depth,name=vertex-depth]{depth}$n>i$, then the set
+ $\defeq{\livar{V}i}{\setst{\inset{v}{V}}{\gdepth{v} = i}}$ of
+ \termref[cd=graphs-intro,name=node]{nodes} at
+ \termref[cd=graph-depth,name=vertex-depth]{depth} $i$ has
+ \termref[cd=cardinality,name=cardinality]{cardinality} $\power2i$.
+ \end{assertion}
+ \item
+ \begin{sproof}[id=size-lemma-pf,proofend=,for=size-lemma]{via induction over the depth $i$.}
+ \begin{spfcases}{We have to consider two cases}
+ \begin{spfcase}{$i=0$}
+ \begin{spfstep}[display=flow]
+ then $\livar{V}i=\set{\livar{v}r}$, where $\livar{v}r$ is the root, so
+ $\eq{\card{\livar{V}0},\card{\set{\livar{v}r}},1,\power20}$.
+ \end{spfstep}
+ \end{spfcase}
+ \begin{spfcase}{$i>0$}
+ \begin{spfstep}[display=flow]
+ then $\livar{V}{i-1}$ contains $\power2{i-1}$ vertexes
+ \begin{justification}[method=byIH](IH)\end{justification}
+ \end{spfstep}
+ \begin{spfstep}
+ By the \begin{justification}[method=byDef]definition of a binary
+ tree\end{justification}, each $\inset{v}{\livar{V}{i-1}}$ is a leaf or has
+ two children that are at depth $i$.
+ \end{spfstep}
+ \begin{spfstep}
+ As $G$ is \termref[cd=balanced-binary-trees,name=balanced-binary-tree]{balanced} and $\gdepth{G}=n>i$, $\livar{V}{i-1}$ cannot contain
+ leaves.
+ \end{spfstep}
+ \begin{spfstep}[type=conclusion]
+ Thus $\eq{\card{\livar{V}i},{\atimes[cdot]{2,\card{\livar{V}{i-1}}}},{\atimes[cdot]{2,\power2{i-1}}},\power2i}$.
+ \end{spfstep}
+ \end{spfcase}
+ \end{spfcases}
+ \end{sproof}
+ \item
+ \begin{assertion}[id=fbbt,type=corollary]
+ A fully balanced tree of depth $d$ has $\power2{d+1}-1$ nodes.
+ \end{assertion}
+ \item
+ \begin{sproof}[for=fbbt,id=fbbt-pf]{}
+ \begin{spfstep}
+ Let $\defeq{G}{\tup{V,E}}$ be a fully balanced tree
+ \end{spfstep}
+ \begin{spfstep}
+ Then $\card{V}=\Sumfromto{i}1d{\power2i}= \power2{d+1}-1$.
+ \end{spfstep}
+ \end{sproof}
+ \end{itemize}
+ \end{frame}
+\begin{note}
+ \begin{omtext}[type=conclusion,for=binary-tree]
+ This shows that balanced binary trees grow in breadth very quickly, a consequence of
+ this is that they are very shallow (and this compute very fast), which is the essence of
+ the next result.
+ \end{omtext}
+\end{note}
+\end{module}
+
+%%% Local Variables:
+%%% mode: LaTeX
+%%% TeX-master: "all"
+%%% End: \end{document}
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-stex</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/stex/stex.js b/codemirror_ui/lib/CodeMirror-2.3/mode/stex/stex.js
new file mode 100644
index 0000000..c0739de
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/stex/stex.js
@@ -0,0 +1,182 @@
+/*
+ * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de)
+ * Licence: MIT
+ */
+
+CodeMirror.defineMode("stex", function(cmCfg, modeCfg)
+{
+ function pushCommand(state, command) {
+ state.cmdState.push(command);
+ }
+
+ function peekCommand(state) {
+ if (state.cmdState.length>0)
+ return state.cmdState[state.cmdState.length-1];
+ else
+ return null;
+ }
+
+ function popCommand(state) {
+ if (state.cmdState.length>0) {
+ var plug = state.cmdState.pop();
+ plug.closeBracket();
+ }
+ }
+
+ function applyMostPowerful(state) {
+ var context = state.cmdState;
+ for (var i = context.length - 1; i >= 0; i--) {
+ var plug = context[i];
+ if (plug.name=="DEFAULT")
+ continue;
+ return plug.styleIdentifier();
+ }
+ return null;
+ }
+
+ function addPluginPattern(pluginName, cmdStyle, brackets, styles) {
+ return function () {
+ this.name=pluginName;
+ this.bracketNo = 0;
+ this.style=cmdStyle;
+ this.styles = styles;
+ this.brackets = brackets;
+
+ this.styleIdentifier = function(content) {
+ if (this.bracketNo<=this.styles.length)
+ return this.styles[this.bracketNo-1];
+ else
+ return null;
+ };
+ this.openBracket = function(content) {
+ this.bracketNo++;
+ return "bracket";
+ };
+ this.closeBracket = function(content) {
+ };
+ }
+ }
+
+ var plugins = new Array();
+
+ plugins["importmodule"] = addPluginPattern("importmodule", "tag", "{[", ["string", "builtin"]);
+ plugins["documentclass"] = addPluginPattern("documentclass", "tag", "{[", ["", "atom"]);
+ plugins["usepackage"] = addPluginPattern("documentclass", "tag", "[", ["atom"]);
+ plugins["begin"] = addPluginPattern("documentclass", "tag", "[", ["atom"]);
+ plugins["end"] = addPluginPattern("documentclass", "tag", "[", ["atom"]);
+
+ plugins["DEFAULT"] = function () {
+ this.name="DEFAULT";
+ this.style="tag";
+
+ this.styleIdentifier = function(content) {
+ };
+ this.openBracket = function(content) {
+ };
+ this.closeBracket = function(content) {
+ };
+ };
+
+ function setState(state, f) {
+ state.f = f;
+ }
+
+ function normal(source, state) {
+ if (source.match(/^\\[a-zA-Z@]+/)) {
+ var cmdName = source.current();
+ cmdName = cmdName.substr(1, cmdName.length-1);
+ var plug;
+ if (plugins.hasOwnProperty(cmdName)) {
+ plug = plugins[cmdName];
+ } else {
+ plug = plugins["DEFAULT"];
+ }
+ plug = new plug();
+ pushCommand(state, plug);
+ setState(state, beginParams);
+ return plug.style;
+ }
+
+ // escape characters
+ if (source.match(/^\\[$&%#{}_]/)) {
+ return "tag";
+ }
+
+ // white space control characters
+ if (source.match(/^\\[,;!\/]/)) {
+ return "tag";
+ }
+
+ var ch = source.next();
+ if (ch == "%") {
+ // special case: % at end of its own line; stay in same state
+ if (!source.eol()) {
+ setState(state, inCComment);
+ }
+ return "comment";
+ }
+ else if (ch=='}' || ch==']') {
+ plug = peekCommand(state);
+ if (plug) {
+ plug.closeBracket(ch);
+ setState(state, beginParams);
+ } else
+ return "error";
+ return "bracket";
+ } else if (ch=='{' || ch=='[') {
+ plug = plugins["DEFAULT"];
+ plug = new plug();
+ pushCommand(state, plug);
+ return "bracket";
+ }
+ else if (/\d/.test(ch)) {
+ source.eatWhile(/[\w.%]/);
+ return "atom";
+ }
+ else {
+ source.eatWhile(/[\w-_]/);
+ return applyMostPowerful(state);
+ }
+ }
+
+ function inCComment(source, state) {
+ source.skipToEnd();
+ setState(state, normal);
+ return "comment";
+ }
+
+ function beginParams(source, state) {
+ var ch = source.peek();
+ if (ch == '{' || ch == '[') {
+ var lastPlug = peekCommand(state);
+ var style = lastPlug.openBracket(ch);
+ source.eat(ch);
+ setState(state, normal);
+ return "bracket";
+ }
+ if (/[ \t\r]/.test(ch)) {
+ source.eat(ch);
+ return null;
+ }
+ setState(state, normal);
+ lastPlug = peekCommand(state);
+ if (lastPlug) {
+ popCommand(state);
+ }
+ return normal(source, state);
+ }
+
+ return {
+ startState: function() { return { f:normal, cmdState:[] }; },
+ copyState: function(s) { return { f: s.f, cmdState: s.cmdState.slice(0, s.cmdState.length) }; },
+
+ token: function(stream, state) {
+ var t = state.f(stream, state);
+ var w = stream.current();
+ return t;
+ }
+ };
+});
+
+
+CodeMirror.defineMIME("text/x-stex", "stex");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/stex/test.html b/codemirror_ui/lib/CodeMirror-2.3/mode/stex/test.html
new file mode 100644
index 0000000..a60f418
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/stex/test.html
@@ -0,0 +1,263 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: sTeX mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="stex.js"></script>
+ <link rel="stylesheet" href="../../test/mode_test.css">
+ <script src="../../test/mode_test.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>Tests for the sTeX Mode</h1>
+ <h2>Basics</h2>
+ <script language="javascript">
+ MT = ModeTest;
+
+ MT.test('foo',
+ null, 'foo');
+
+ MT.test('foo bar',
+ null, 'foo',
+ null, ' bar');
+ </script>
+
+ <h2>Tags</h2>
+ <script language="javascript">
+ MT.test('\\begin{document}\n\\end{document}',
+ 'tag', '\\begin',
+ 'bracket', '{',
+ 'atom', 'document',
+ 'bracket', '}',
+ 'tag', '\\end',
+ 'bracket', '{',
+ 'atom', 'document',
+ 'bracket', '}');
+
+ MT.test('\\begin{equation}\n E=mc^2\n\\end{equation}',
+ 'tag', '\\begin',
+ 'bracket', '{',
+ 'atom', 'equation',
+ 'bracket', '}',
+ null, ' ',
+ null, ' ',
+ null, 'E',
+ null, '=mc',
+ null, '^2',
+ 'tag', '\\end',
+ 'bracket', '{',
+ 'atom', 'equation',
+ 'bracket', '}');
+
+ MT.test('\\begin{module}[]',
+ 'tag', '\\begin',
+ 'bracket', '{',
+ 'atom', 'module',
+ 'bracket', '}',
+ 'bracket', '[',
+ 'bracket', ']');
+
+ MT.test('\\begin{module}[id=bbt-size]',
+ 'tag', '\\begin',
+ 'bracket', '{',
+ 'atom', 'module',
+ 'bracket', '}',
+ 'bracket', '[',
+ null, 'id',
+ null, '=bbt-size',
+ 'bracket', ']');
+
+ MT.test('\\importmodule[b-b-t]{b-b-t}',
+ 'tag', '\\importmodule',
+ 'bracket', '[',
+ 'string', 'b-b-t',
+ 'bracket', ']',
+ 'bracket', '{',
+ 'builtin', 'b-b-t',
+ 'bracket', '}');
+
+ MT.test('\\importmodule[\\KWARCslides{dmath/en/cardinality}]{card}',
+ 'tag', '\\importmodule',
+ 'bracket', '[',
+ 'tag', '\\KWARCslides',
+ 'bracket', '{',
+ 'string', 'dmath',
+ 'string', '/en',
+ 'string', '/cardinality',
+ 'bracket', '}',
+ 'bracket', ']',
+ 'bracket', '{',
+ 'builtin', 'card',
+ 'bracket', '}');
+
+ MT.test('\\PSforPDF[1]{#1}', // could treat #1 specially
+ 'tag', '\\PSforPDF',
+ 'bracket', '[',
+ 'atom', '1',
+ 'bracket', ']',
+ 'bracket', '{',
+ null, '#1',
+ 'bracket', '}');
+ </script>
+
+ <h2>Comments</h2>
+ <script language="javascript">
+ MT.test('% foo',
+ 'comment', '%',
+ 'comment', ' foo');
+
+ MT.test('\\item% bar',
+ 'tag', '\\item',
+ 'comment', '%',
+ 'comment', ' bar');
+
+ MT.test(' % \\item',
+ null, ' ',
+ 'comment', '%',
+ 'comment', ' \\item');
+
+ MT.test('%\nfoo',
+ 'comment', '%',
+ null, 'foo');
+ </script>
+
+ <h2>Errors</h2>
+ <script language="javascript">
+ MT.test('\\begin}{',
+ 'tag', '\\begin',
+ 'error', '}',
+ 'bracket', '{');
+
+ MT.test('\\item]{',
+ 'tag', '\\item',
+ 'error', ']',
+ 'bracket', '{');
+
+ MT.test('% }',
+ 'comment', '%',
+ 'comment', ' }');
+ </script>
+
+ <h2>Character Escapes</h2>
+ <script language="javascript">
+ MT.test('the \\# key',
+ null, 'the',
+ null, ' ',
+ 'tag', '\\#',
+ null, ' key');
+
+ MT.test('a \\$5 stetson',
+ null, 'a',
+ null, ' ',
+ 'tag', '\\$',
+ 'atom', 5,
+ null, ' stetson');
+
+ MT.test('100\\% beef',
+ 'atom', '100',
+ 'tag', '\\%',
+ null, ' beef');
+
+ MT.test('L \\& N',
+ null, 'L',
+ null, ' ',
+ 'tag', '\\&',
+ null, ' N');
+
+ MT.test('foo\\_bar',
+ null, 'foo',
+ 'tag', '\\_',
+ null, 'bar');
+
+ MT.test('\\emph{\\{}',
+ 'tag', '\\emph',
+ 'bracket','{',
+ 'tag', '\\{',
+ 'bracket','}');
+
+ MT.test('\\emph{\\}}',
+ 'tag', '\\emph',
+ 'bracket','{',
+ 'tag', '\\}',
+ 'bracket','}');
+
+ MT.test('section \\S1',
+ null, 'section',
+ null, ' ',
+ 'tag', '\\S',
+ 'atom', '1');
+
+ MT.test('para \\P2',
+ null, 'para',
+ null, ' ',
+ 'tag', '\\P',
+ 'atom', '2');
+
+ </script>
+
+ <h2>Spacing control</h2>
+
+ <script language="javascript">
+ MT.test('x\\,y', // thinspace
+ null, 'x',
+ 'tag', '\\,',
+ null, 'y');
+
+ MT.test('x\\;y', // thickspace
+ null, 'x',
+ 'tag', '\\;',
+ null, 'y');
+
+ MT.test('x\\!y', // negative thinspace
+ null, 'x',
+ 'tag', '\\!',
+ null, 'y');
+
+ MT.test('J.\\ L.\\ is', // period not ending a sentence
+ null, 'J',
+ null, '.',
+ null, '\\',
+ null, ' L',
+ null, '.',
+ null, '\\',
+ null, ' is'); // maybe could be better
+
+ MT.test('X\\@. The', // period ending a sentence
+ null, 'X',
+ 'tag', '\\@',
+ null, '.',
+ null, ' The');
+
+ MT.test('{\\em If\\/} I', // italic correction
+ 'bracket', '{',
+ 'tag', '\\em',
+ null, ' ',
+ null, 'If',
+ 'tag', '\\/',
+ 'bracket', '}',
+ null, ' ',
+ null, 'I');
+
+ </script>
+
+ <h2>New Commands</h2>
+
+ Should be able to define a new command that happens to be a method on Array
+ (e.g. <tt>pop</tt>):
+ <script language="javascript">
+ MT.test('\\newcommand{\\pop}',
+ 'tag', '\\newcommand',
+ 'bracket', '{',
+ 'tag', '\\pop',
+ 'bracket', '}');
+ </script>
+
+ <h2>Summary</h2>
+ <script language="javascript">
+ MT.printSummary();
+ </script>
+
+ </body>
+</html>
+
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/index.html
new file mode 100644
index 0000000..2f7da0e
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/index.html
@@ -0,0 +1,140 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: TiddlyWiki mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="tiddlywiki.js"></script>
+ <link rel="stylesheet" href="tiddlywiki.css">
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: TiddlyWiki mode</h1>
+
+<div><textarea id="code" name="code">
+!TiddlyWiki Formatting
+* Rendered versions can be found at: http://www.tiddlywiki.com/#Reference
+
+|!Option | !Syntax |
+|bold font | ''bold'' |
+|italic type | //italic// |
+|underlined text | __underlined__ |
+|strikethrough text | --strikethrough-- |
+|superscript text | super^^script^^ |
+|subscript text | sub~~script~~ |
+|highlighted text | @@highlighted@@ |
+|preformatted text | {{{preformatted}}} |
+
+!Block Elements
+<<<
+!Heading 1
+
+!!Heading 2
+
+!!!Heading 3
+
+!!!!Heading 4
+
+!!!!!Heading 5
+<<<
+
+!!Lists
+<<<
+* unordered list, level 1
+** unordered list, level 2
+*** unordered list, level 3
+
+# ordered list, level 1
+## ordered list, level 2
+### unordered list, level 3
+
+; definition list, term
+: definition list, description
+<<<
+
+!!Blockquotes
+<<<
+> blockquote, level 1
+>> blockquote, level 2
+>>> blockquote, level 3
+
+> blockquote
+<<<
+
+!!Preformatted Text
+<<<
+{{{
+preformatted (e.g. code)
+}}}
+<<<
+
+!!Code Sections
+<<<
+{{{
+Text style code
+}}}
+
+//{{{
+JS styled code. TiddlyWiki mixed mode should support highlighter switching in the future.
+//}}}
+
+<!--{{{-->
+XML styled code. TiddlyWiki mixed mode should support highlighter switching in the future.
+<!--}}}-->
+<<<
+
+!!Tables
+<<<
+|CssClass|k
+|!heading column 1|!heading column 2|
+|row 1, column 1|row 1, column 2|
+|row 2, column 1|row 2, column 2|
+|>|COLSPAN|
+|ROWSPAN| ... |
+|~| ... |
+|CssProperty:value;...| ... |
+|caption|c
+
+''Annotation:''
+* The {{{>}}} marker creates a "colspan", causing the current cell to merge with the one to the right.
+* The {{{~}}} marker creates a "rowspan", causing the current cell to merge with the one above.
+<<<
+!!Images /% TODO %/
+cf. [[TiddlyWiki.com|http://www.tiddlywiki.com/#EmbeddedImages]]
+
+!Hyperlinks
+* [[WikiWords|WikiWord]] are automatically transformed to hyperlinks to the respective tiddler
+** the automatic transformation can be suppressed by preceding the respective WikiWord with a tilde ({{{~}}}): {{{~WikiWord}}}
+* [[PrettyLinks]] are enclosed in square brackets and contain the desired tiddler name: {{{[[tiddler name]]}}}
+** optionally, a custom title or description can be added, separated by a pipe character ({{{|}}}): {{{[[title|target]]}}}<br>'''N.B.:''' In this case, the target can also be any website (i.e. URL).
+
+!Custom Styling
+* {{{@@CssProperty:value;CssProperty:value;...@@}}}<br>''N.B.:'' CSS color definitions should use lowercase letters to prevent the inadvertent creation of WikiWords.
+* <html><code>{{customCssClass{...}}}</code></html>
+* raw HTML can be inserted by enclosing the respective code in HTML tags: {{{<html> ... </html>}}}
+
+!Special Markers
+* {{{<br>}}} forces a manual line break
+* {{{----}}} creates a horizontal ruler
+* [[HTML entities|http://www.tiddlywiki.com/#HtmlEntities]]
+* [[HTML entities local|HtmlEntities]]
+* {{{<<macroName>>}}} calls the respective [[macro|Macros]]
+* To hide text within a tiddler so that it is not displayed, it can be wrapped in {{{/%}}} and {{{%/}}}.<br/>This can be a useful trick for hiding drafts or annotating complex markup.
+* To prevent wiki markup from taking effect for a particular section, that section can be enclosed in three double quotes: e.g. {{{"""WikiWord"""}}}.
+</textarea></div>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: 'tiddlywiki',
+ lineNumbers: true,
+ enterMode: 'keep',
+ matchBrackets: true
+ });
+ </script>
+
+ <p>TiddlyWiki mode supports a single configuration.</p>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-tiddlywiki</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/tiddlywiki.css b/codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/tiddlywiki.css
new file mode 100644
index 0000000..9a69b63
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/tiddlywiki.css
@@ -0,0 +1,14 @@
+span.cm-underlined {
+ text-decoration: underline;
+}
+span.cm-strikethrough {
+ text-decoration: line-through;
+}
+span.cm-brace {
+ color: #170;
+ font-weight: bold;
+}
+span.cm-table {
+ color: blue;
+ font-weight: bold;
+}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/tiddlywiki.js b/codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/tiddlywiki.js
new file mode 100644
index 0000000..74fcd49
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/tiddlywiki/tiddlywiki.js
@@ -0,0 +1,384 @@
+/***
+|''Name''|tiddlywiki.js|
+|''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror|
+|''Author''|PMario|
+|''Version''|0.1.7|
+|''Status''|''stable''|
+|''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]|
+|''Documentation''|http://codemirror.tiddlyspace.com/|
+|''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]|
+|''CoreVersion''|2.5.0|
+|''Requires''|codemirror.js|
+|''Keywords''|syntax highlighting color code mirror codemirror|
+! Info
+CoreVersion parameter is needed for TiddlyWiki only!
+***/
+//{{{
+CodeMirror.defineMode("tiddlywiki", function (config, parserConfig) {
+ var indentUnit = config.indentUnit;
+
+ // Tokenizer
+ var textwords = function () {
+ function kw(type) {
+ return {
+ type: type,
+ style: "text"
+ };
+ }
+ return {};
+ }();
+
+ var keywords = function () {
+ function kw(type) {
+ return { type: type, style: "macro"};
+ }
+ return {
+ "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'),
+ "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'),
+ "permaview": kw('permaview'), "saveChanges": kw('saveChanges'),
+ "search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'),
+ "tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'),
+ "tiddler": kw('tiddler'), "timeline": kw('timeline'),
+ "today": kw('today'), "version": kw('version'), "option": kw('option'),
+
+ "with": kw('with'),
+ "filter": kw('filter')
+ };
+ }();
+
+ var isSpaceName = /[\w_\-]/i,
+ reHR = /^\-\-\-\-+$/, // <hr>
+ reWikiCommentStart = /^\/\*\*\*$/, // /***
+ reWikiCommentStop = /^\*\*\*\/$/, // ***/
+ reBlockQuote = /^<<<$/,
+
+ reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ js block start
+ reJsCodeStop = /^\/\/\}\}\}$/, // //}}} js stop
+ reXmlCodeStart = /^<!--\{\{\{-->$/, // xml block start
+ reXmlCodeStop = /^<!--\}\}\}-->$/, // xml stop
+
+ reCodeBlockStart = /^\{\{\{$/, // {{{ TW text div block start
+ reCodeBlockStop = /^\}\}\}$/, // }}} TW text stop
+
+ reCodeStart = /\{\{\{/, // {{{ code span start
+ reUntilCodeStop = /.*?\}\}\}/;
+
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ // used for strings
+ function nextUntilUnescaped(stream, end) {
+ var escaped = false,
+ next;
+ while ((next = stream.next()) != null) {
+ if (next == end && !escaped) return false;
+ escaped = !escaped && next == "\\";
+ }
+ return escaped;
+ }
+
+ // Used as scratch variables to communicate multiple values without
+ // consing up tons of objects.
+ var type, content;
+
+ function ret(tp, style, cont) {
+ type = tp;
+ content = cont;
+ return style;
+ }
+
+ function jsTokenBase(stream, state) {
+ var sol = stream.sol(),
+ ch, tch;
+
+ state.block = false; // indicates the start of a code block.
+
+ ch = stream.peek(); // don't eat, to make matching simpler
+
+ // check start of blocks
+ if (sol && /[<\/\*{}\-]/.test(ch)) {
+ if (stream.match(reCodeBlockStart)) {
+ state.block = true;
+ return chain(stream, state, twTokenCode);
+ }
+ if (stream.match(reBlockQuote)) {
+ return ret('quote', 'quote');
+ }
+ if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) {
+ return ret('code', 'comment');
+ }
+ if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) {
+ return ret('code', 'comment');
+ }
+ if (stream.match(reHR)) {
+ return ret('hr', 'hr');
+ }
+ } // sol
+ ch = stream.next();
+
+ if (sol && /[\/\*!#;:>|]/.test(ch)) {
+ if (ch == "!") { // tw header
+ stream.skipToEnd();
+ return ret("header", "header");
+ }
+ if (ch == "*") { // tw list
+ stream.eatWhile('*');
+ return ret("list", "comment");
+ }
+ if (ch == "#") { // tw numbered list
+ stream.eatWhile('#');
+ return ret("list", "comment");
+ }
+ if (ch == ";") { // definition list, term
+ stream.eatWhile(';');
+ return ret("list", "comment");
+ }
+ if (ch == ":") { // definition list, description
+ stream.eatWhile(':');
+ return ret("list", "comment");
+ }
+ if (ch == ">") { // single line quote
+ stream.eatWhile(">");
+ return ret("quote", "quote");
+ }
+ if (ch == '|') {
+ return ret('table', 'header');
+ }
+ }
+
+ if (ch == '{' && stream.match(/\{\{/)) {
+ return chain(stream, state, twTokenCode);
+ }
+
+ // rudimentary html:// file:// link matching. TW knows much more ...
+ if (/[hf]/i.test(ch)) {
+ if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) {
+ return ret("link", "link");
+ }
+ }
+ // just a little string indicator, don't want to have the whole string covered
+ if (ch == '"') {
+ return ret('string', 'string');
+ }
+ if (ch == '~') { // _no_ CamelCase indicator should be bold
+ return ret('text', 'brace');
+ }
+ if (/[\[\]]/.test(ch)) { // check for [[..]]
+ if (stream.peek() == ch) {
+ stream.next();
+ return ret('brace', 'brace');
+ }
+ }
+ if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting
+ stream.eatWhile(isSpaceName);
+ return ret("link", "link");
+ }
+ if (/\d/.test(ch)) { // numbers
+ stream.eatWhile(/\d/);
+ return ret("number", "number");
+ }
+ if (ch == "/") { // tw invisible comment
+ if (stream.eat("%")) {
+ return chain(stream, state, twTokenComment);
+ }
+ else if (stream.eat("/")) { //
+ return chain(stream, state, twTokenEm);
+ }
+ }
+ if (ch == "_") { // tw underline
+ if (stream.eat("_")) {
+ return chain(stream, state, twTokenUnderline);
+ }
+ }
+ // strikethrough and mdash handling
+ if (ch == "-") {
+ if (stream.eat("-")) {
+ // if strikethrough looks ugly, change CSS.
+ if (stream.peek() != ' ')
+ return chain(stream, state, twTokenStrike);
+ // mdash
+ if (stream.peek() == ' ')
+ return ret('text', 'brace');
+ }
+ }
+ if (ch == "'") { // tw bold
+ if (stream.eat("'")) {
+ return chain(stream, state, twTokenStrong);
+ }
+ }
+ if (ch == "<") { // tw macro
+ if (stream.eat("<")) {
+ return chain(stream, state, twTokenMacro);
+ }
+ }
+ else {
+ return ret(ch);
+ }
+
+ // core macro handling
+ stream.eatWhile(/[\w\$_]/);
+ var word = stream.current(),
+ known = textwords.propertyIsEnumerable(word) && textwords[word];
+
+ return known ? ret(known.type, known.style, word) : ret("text", null, word);
+
+ } // jsTokenBase()
+
+ function twTokenString(quote) {
+ return function (stream, state) {
+ if (!nextUntilUnescaped(stream, quote)) state.tokenize = jsTokenBase;
+ return ret("string", "string");
+ };
+ }
+
+ // tw invisible comment
+ function twTokenComment(stream, state) {
+ var maybeEnd = false,
+ ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "%");
+ }
+ return ret("comment", "comment");
+ }
+
+ // tw strong / bold
+ function twTokenStrong(stream, state) {
+ var maybeEnd = false,
+ ch;
+ while (ch = stream.next()) {
+ if (ch == "'" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "'");
+ }
+ return ret("text", "strong");
+ }
+
+ // tw code
+ function twTokenCode(stream, state) {
+ var ch, sb = state.block;
+
+ if (sb && stream.current()) {
+ return ret("code", "comment");
+ }
+
+ if (!sb && stream.match(reUntilCodeStop)) {
+ state.tokenize = jsTokenBase;
+ return ret("code", "comment");
+ }
+
+ if (sb && stream.sol() && stream.match(reCodeBlockStop)) {
+ state.tokenize = jsTokenBase;
+ return ret("code", "comment");
+ }
+
+ ch = stream.next();
+ return (sb) ? ret("code", "comment") : ret("code", "comment");
+ }
+
+ // tw em / italic
+ function twTokenEm(stream, state) {
+ var maybeEnd = false,
+ ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "/");
+ }
+ return ret("text", "em");
+ }
+
+ // tw underlined text
+ function twTokenUnderline(stream, state) {
+ var maybeEnd = false,
+ ch;
+ while (ch = stream.next()) {
+ if (ch == "_" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "_");
+ }
+ return ret("text", "underlined");
+ }
+
+ // tw strike through text looks ugly
+ // change CSS if needed
+ function twTokenStrike(stream, state) {
+ var maybeEnd = false,
+ ch, nr;
+
+ while (ch = stream.next()) {
+ if (ch == "-" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "-");
+ }
+ return ret("text", "strikethrough");
+ }
+
+ // macro
+ function twTokenMacro(stream, state) {
+ var ch, tmp, word, known;
+
+ if (stream.current() == '<<') {
+ return ret('brace', 'macro');
+ }
+
+ ch = stream.next();
+ if (!ch) {
+ state.tokenize = jsTokenBase;
+ return ret(ch);
+ }
+ if (ch == ">") {
+ if (stream.peek() == '>') {
+ stream.next();
+ state.tokenize = jsTokenBase;
+ return ret("brace", "macro");
+ }
+ }
+
+ stream.eatWhile(/[\w\$_]/);
+ word = stream.current();
+ known = keywords.propertyIsEnumerable(word) && keywords[word];
+
+ if (known) {
+ return ret(known.type, known.style, word);
+ }
+ else {
+ return ret("macro", null, word);
+ }
+ }
+
+ // Interface
+ return {
+ startState: function (basecolumn) {
+ return {
+ tokenize: jsTokenBase,
+ indented: 0,
+ level: 0
+ };
+ },
+
+ token: function (stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ },
+
+ electricChars: ""
+ };
+});
+
+CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki");
+//}}}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/tiki/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/tiki/index.html
new file mode 100644
index 0000000..bf80040
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/tiki/index.html
@@ -0,0 +1,82 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>CodeMirror: Tiki wiki mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="tiki.js"></script>
+ <link rel="stylesheet" href="tiki.css">
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body style="padding: 20px;">
+ <h1>CodeMirror: Tiki wiki mode</h1>
+
+<div><textarea id="code" name="code">
+Headings
+!Header 1
+!!Header 2
+!!!Header 3
+!!!!Header 4
+!!!!!Header 5
+!!!!!!Header 6
+
+Styling
+-=titlebar=-
+^^ Box on multi
+lines
+of content^^
+__bold__
+''italic''
+===underline===
+::center::
+--Line Through--
+
+Operators
+~np~No parse~/np~
+
+Link
+[link|desc|nocache]
+
+Wiki
+((Wiki))
+((Wiki|desc))
+((Wiki|desc|timeout))
+
+Table
+||row1 col1|row1 col2|row1 col3
+row2 col1|row2 col2|row2 col3
+row3 col1|row3 col2|row3 col3||
+
+Lists:
+*bla
+**bla-1
+++continue-bla-1
+***bla-2
+++continue-bla-1
+*bla
++continue-bla
+#bla
+** tra-la-la
++continue-bla
+#bla
+
+Plugin (standard):
+{PLUGIN(attr="my attr")}
+Plugin Body
+{PLUGIN}
+
+Plugin (inline):
+{plugin attr="my attr"}
+</textarea></div>
+
+<script type="text/javascript">
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: 'tiki',
+ lineNumbers: true,
+ enterMode: 'keep',
+ matchBrackets: true
+ });
+</script>
+
+</body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/tiki/tiki.css b/codemirror_ui/lib/CodeMirror-2.3/mode/tiki/tiki.css
new file mode 100644
index 0000000..e3c3c0f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/tiki/tiki.css
@@ -0,0 +1,26 @@
+.cm-tw-syntaxerror {
+ color: #FFFFFF;
+ background-color: #990000;
+}
+
+.cm-tw-deleted {
+ text-decoration: line-through;
+}
+
+.cm-tw-header5 {
+ font-weight: bold;
+}
+.cm-tw-listitem:first-child { /*Added first child to fix duplicate padding when highlighting*/
+ padding-left: 10px;
+}
+
+.cm-tw-box {
+ border-top-width: 0px ! important;
+ border-style: solid;
+ border-width: 1px;
+ border-color: inherit;
+}
+
+.cm-tw-underline {
+ text-decoration: underline;
+} \ No newline at end of file
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/tiki/tiki.js b/codemirror_ui/lib/CodeMirror-2.3/mode/tiki/tiki.js
new file mode 100644
index 0000000..350dd51
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/tiki/tiki.js
@@ -0,0 +1,316 @@
+CodeMirror.defineMode('tiki', function(config, parserConfig) {
+ function inBlock(style, terminator, returnTokenizer) {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ if (stream.match(terminator)) {
+ state.tokenize = inText;
+ break;
+ }
+ stream.next();
+ }
+
+ if (returnTokenizer) state.tokenize = returnTokenizer;
+
+ return style;
+ };
+ }
+
+ function inLine(style, terminator) {
+ return function(stream, state) {
+ while(!stream.eol()) {
+ stream.next()
+ }
+ state.tokenize = inText;
+ return style;
+ };
+ }
+
+ function inText(stream, state) {
+ function chain(parser) {
+ state.tokenize = parser;
+ return parser(stream, state);
+ }
+
+ var sol = stream.sol();
+ var ch = stream.next();
+
+ //non start of line
+ switch (ch) { //switch is generally much faster than if, so it is used here
+ case "{": //plugin
+ type = stream.eat("/") ? "closeTag" : "openTag";
+ stream.eatSpace();
+ tagName = "";
+ var c;
+ while ((c = stream.eat(/[^\s\u00a0=\"\'\/?(}]/))) tagName += c;
+ state.tokenize = inPlugin;
+ return "tag";
+ break;
+ case "_": //bold
+ if (stream.eat("_")) {
+ return chain(inBlock("strong", "__", inText));
+ }
+ break;
+ case "'": //italics
+ if (stream.eat("'")) {
+ // Italic text
+ return chain(inBlock("em", "''", inText));
+ }
+ break;
+ case "(":// Wiki Link
+ if (stream.eat("(")) {
+ return chain(inBlock("variable-2", "))", inText));
+ }
+ break;
+ case "[":// Weblink
+ return chain(inBlock("variable-3", "]", inText));
+ break;
+ case "|": //table
+ if (stream.eat("|")) {
+ return chain(inBlock("comment", "||"));
+ }
+ break;
+ case "-":
+ if (stream.eat("=")) {//titleBar
+ return chain(inBlock("header string", "=-", inText));
+ } else if (stream.eat("-")) {//deleted
+ return chain(inBlock("error tw-deleted", "--", inText));
+ }
+ break;
+ case "=": //underline
+ if (stream.match("==")) {
+ return chain(inBlock("tw-underline", "===", inText));
+ }
+ break;
+ case ":":
+ if (stream.eat(":")) {
+ return chain(inBlock("comment", "::"));
+ }
+ break;
+ case "^": //box
+ return chain(inBlock("tw-box", "^"));
+ break;
+ case "~": //np
+ if (stream.match("np~")) {
+ return chain(inBlock("meta", "~/np~"));
+ }
+ break;
+ }
+
+ //start of line types
+ if (sol) {
+ switch (ch) {
+ case "!": //header at start of line
+ if (stream.match('!!!!!')) {
+ return chain(inLine("header string"));
+ } else if (stream.match('!!!!')) {
+ return chain(inLine("header string"));
+ } else if (stream.match('!!!')) {
+ return chain(inLine("header string"));
+ } else if (stream.match('!!')) {
+ return chain(inLine("header string"));
+ } else {
+ return chain(inLine("header string"));
+ }
+ break;
+ case "*": //unordered list line item, or <li /> at start of line
+ case "#": //ordered list line item, or <li /> at start of line
+ case "+": //ordered list line item, or <li /> at start of line
+ return chain(inLine("tw-listitem bracket"));
+ break;
+ }
+ }
+
+ //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki
+ return null;
+ }
+
+ var indentUnit = config.indentUnit;
+
+ // Return variables for tokenizers
+ var pluginName, type;
+ function inPlugin(stream, state) {
+ var ch = stream.next();
+ var peek = stream.peek();
+
+ if (ch == "}") {
+ state.tokenize = inText;
+ //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin
+ return "tag";
+ } else if (ch == "(" || ch == ")") {
+ return "bracket";
+ } else if (ch == "=") {
+ type = "equals";
+
+ if (peek == ">") {
+ ch = stream.next();
+ peek = stream.peek();
+ }
+
+ //here we detect values directly after equal character with no quotes
+ if (!/[\'\"]/.test(peek)) {
+ state.tokenize = inAttributeNoQuote();
+ }
+ //end detect values
+
+ return "operator";
+ } else if (/[\'\"]/.test(ch)) {
+ state.tokenize = inAttribute(ch);
+ return state.tokenize(stream, state);
+ } else {
+ stream.eatWhile(/[^\s\u00a0=\"\'\/?]/);
+ return "keyword";
+ }
+ }
+
+ function inAttribute(quote) {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ if (stream.next() == quote) {
+ state.tokenize = inPlugin;
+ break;
+ }
+ }
+ return "string";
+ };
+ }
+
+ function inAttributeNoQuote() {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ var ch = stream.next();
+ var peek = stream.peek();
+ if (ch == " " || ch == "," || /[ )}]/.test(peek)) {
+ state.tokenize = inPlugin;
+ break;
+ }
+ }
+ return "string";
+ };
+ }
+
+ var curState, setStyle;
+ function pass() {
+ for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
+ }
+
+ function cont() {
+ pass.apply(null, arguments);
+ return true;
+ }
+
+ function pushContext(pluginName, startOfLine) {
+ var noIndent = curState.context && curState.context.noIndent;
+ curState.context = {
+ prev: curState.context,
+ pluginName: pluginName,
+ indent: curState.indented,
+ startOfLine: startOfLine,
+ noIndent: noIndent
+ };
+ }
+
+ function popContext() {
+ if (curState.context) curState.context = curState.context.prev;
+ }
+
+ function element(type) {
+ if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));}
+ else if (type == "closePlugin") {
+ var err = false;
+ if (curState.context) {
+ err = curState.context.pluginName != pluginName;
+ popContext();
+ } else {
+ err = true;
+ }
+ if (err) setStyle = "error";
+ return cont(endcloseplugin(err));
+ }
+ else if (type == "string") {
+ if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
+ if (curState.tokenize == inText) popContext();
+ return cont();
+ }
+ else return cont();
+ }
+
+ function endplugin(startOfLine) {
+ return function(type) {
+ if (
+ type == "selfclosePlugin" ||
+ type == "endPlugin"
+ )
+ return cont();
+ if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();}
+ return cont();
+ };
+ }
+
+ function endcloseplugin(err) {
+ return function(type) {
+ if (err) setStyle = "error";
+ if (type == "endPlugin") return cont();
+ return pass();
+ }
+ }
+
+ function attributes(type) {
+ if (type == "keyword") {setStyle = "attribute"; return cont(attributes);}
+ if (type == "equals") return cont(attvalue, attributes);
+ return pass();
+ }
+ function attvalue(type) {
+ if (type == "keyword") {setStyle = "string"; return cont();}
+ if (type == "string") return cont(attvaluemaybe);
+ return pass();
+ }
+ function attvaluemaybe(type) {
+ if (type == "string") return cont(attvaluemaybe);
+ else return pass();
+ }
+ return {
+ startState: function() {
+ return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null};
+ },
+ token: function(stream, state) {
+ if (stream.sol()) {
+ state.startOfLine = true;
+ state.indented = stream.indentation();
+ }
+ if (stream.eatSpace()) return null;
+
+ setStyle = type = pluginName = null;
+ var style = state.tokenize(stream, state);
+ if ((style || type) && style != "comment") {
+ curState = state;
+ while (true) {
+ var comb = state.cc.pop() || element;
+ if (comb(type || style)) break;
+ }
+ }
+ state.startOfLine = false;
+ return setStyle || style;
+ },
+ indent: function(state, textAfter) {
+ var context = state.context;
+ if (context && context.noIndent) return 0;
+ if (context && /^{\//.test(textAfter))
+ context = context.prev;
+ while (context && !context.startOfLine)
+ context = context.prev;
+ if (context) return context.indent + indentUnit;
+ else return 0;
+ },
+ compareStates: function(a, b) {
+ if (a.indented != b.indented || a.pluginName != b.pluginName) return false;
+ for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
+ if (!ca || !cb) return ca == cb;
+ if (ca.pluginName != cb.pluginName) return false;
+ }
+ },
+ electricChars: "/"
+ };
+});
+
+//I figure, why not
+CodeMirror.defineMIME("text/tiki", "tiki");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/vbscript/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/vbscript/index.html
new file mode 100644
index 0000000..dd207ca
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/vbscript/index.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: VBScript mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="vbscript.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: VBScript mode</h1>
+
+<div><textarea id="code" name="code">
+' Pete Guhl
+' 03-04-2012
+'
+' Basic VBScript support for codemirror2
+
+Const ForReading = 1, ForWriting = 2, ForAppending = 8
+
+Call Sub020_PostBroadcastToUrbanAirship(strUserName, strPassword, intTransmitID, strResponse)
+
+If Not IsNull(strResponse) AND Len(strResponse) = 0 Then
+ boolTransmitOkYN = False
+Else
+ ' WScript.Echo "Oh Happy Day! Oh Happy DAY!"
+ boolTransmitOkYN = True
+End If
+</textarea></div>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/vbscript</code>.</p>
+ </body>
+</html>
+
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/vbscript/vbscript.js b/codemirror_ui/lib/CodeMirror-2.3/mode/vbscript/vbscript.js
new file mode 100644
index 0000000..65d6c21
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/vbscript/vbscript.js
@@ -0,0 +1,26 @@
+CodeMirror.defineMode("vbscript", function() {
+ var regexVBScriptKeyword = /^(?:Call|Case|CDate|Clear|CInt|CLng|Const|CStr|Description|Dim|Do|Each|Else|ElseIf|End|Err|Error|Exit|False|For|Function|If|LCase|Loop|LTrim|Next|Nothing|Now|Number|On|Preserve|Quit|ReDim|Resume|RTrim|Select|Set|Sub|Then|To|Trim|True|UBound|UCase|Until|VbCr|VbCrLf|VbLf|VbTab)$/im;
+
+ return {
+ token: function(stream) {
+ if (stream.eatSpace()) return null;
+ var ch = stream.next();
+ if (ch == "'") {
+ stream.skipToEnd();
+ return "comment";
+ }
+ if (ch == '"') {
+ stream.skipTo('"');
+ return "string";
+ }
+
+ if (/\w/.test(ch)) {
+ stream.eatWhile(/\w/);
+ if (regexVBScriptKeyword.test(stream.current())) return "keyword";
+ }
+ return null;
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/vbscript", "vbscript");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/velocity/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/velocity/index.html
new file mode 100644
index 0000000..49dba38
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/velocity/index.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Velocity mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="velocity.js"></script>
+ <link rel="stylesheet" href="../../theme/night.css">
+ <style>.CodeMirror {border: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: Velocity mode</h1>
+ <form><textarea id="code" name="code">
+## Velocity Code Demo
+#*
+ based on PL/SQL mode by Peter Raganitsch, adapted to Velocity by Steve O'Hara ( http://www.pivotal-solutions.co.uk )
+ August 2011
+*#
+
+#*
+ This is a multiline comment.
+ This is the second line
+*#
+
+#[[ hello steve
+ This has invalid syntax that would normally need "poor man's escaping" like:
+
+ #define()
+
+ ${blah
+]]#
+
+#include( "disclaimer.txt" "opinion.txt" )
+#include( $foo $bar )
+
+#parse( "lecorbusier.vm" )
+#parse( $foo )
+
+#evaluate( 'string with VTL #if(true)will be displayed#end' )
+
+#define( $hello ) Hello $who #end #set( $who = "World!") $hello ## displays Hello World!
+
+#foreach( $customer in $customerList )
+
+ $foreach.count $customer.Name
+
+ #if( $foo == ${bar})
+ it's true!
+ #break
+ #{else}
+ it's not!
+ #stop
+ #end
+
+ #if ($foreach.parent.hasNext)
+ $velocityCount
+ #end
+#end
+
+$someObject.getValues("this is a string split
+ across lines")
+
+#macro( tablerows $color $somelist )
+ #foreach( $something in $somelist )
+ <tr><td bgcolor=$color>$something</td></tr>
+ #end
+#end
+
+#tablerows("red" ["dadsdf","dsa"])
+
+ Variable reference: #set( $monkey = $bill )
+ String literal: #set( $monkey.Friend = 'monica' )
+ Property reference: #set( $monkey.Blame = $whitehouse.Leak )
+ Method reference: #set( $monkey.Plan = $spindoctor.weave($web) )
+ Number literal: #set( $monkey.Number = 123 )
+ Range operator: #set( $monkey.Numbers = [1..3] )
+ Object list: #set( $monkey.Say = ["Not", $my, "fault"] )
+ Object map: #set( $monkey.Map = {"banana" : "good", "roast beef" : "bad"})
+
+The RHS can also be a simple arithmetic expression, such as:
+Addition: #set( $value = $foo + 1 )
+ Subtraction: #set( $value = $bar - 1 )
+ Multiplication: #set( $value = $foo * $bar )
+ Division: #set( $value = $foo / $bar )
+ Remainder: #set( $value = $foo % $bar )
+
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ tabMode: "indent",
+ matchBrackets: true,
+ theme: "night",
+ lineNumbers: true,
+ indentUnit: 4,
+ mode: "text/velocity"
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/velocity</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/velocity/velocity.js b/codemirror_ui/lib/CodeMirror-2.3/mode/velocity/velocity.js
new file mode 100644
index 0000000..0b80c75
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/velocity/velocity.js
@@ -0,0 +1,146 @@
+CodeMirror.defineMode("velocity", function(config) {
+ function parseWords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+
+ var indentUnit = config.indentUnit
+ var keywords = parseWords("#end #else #break #stop #[[ #]] " +
+ "#{end} #{else} #{break} #{stop}");
+ var functions = parseWords("#if #elseif #foreach #set #include #parse #macro #define #evaluate " +
+ "#{if} #{elseif} #{foreach} #{set} #{include} #{parse} #{macro} #{define} #{evaluate}");
+ var specials = parseWords("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent $velocityCount");
+ var isOperatorChar = /[+\-*&%=<>!?:\/|]/;
+ var multiLineStrings =true;
+
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+ function tokenBase(stream, state) {
+ var beforeParams = state.beforeParams;
+ state.beforeParams = false;
+ var ch = stream.next();
+ // start of string?
+ if ((ch == '"' || ch == "'") && state.inParams)
+ return chain(stream, state, tokenString(ch));
+ // is it one of the special signs []{}().,;? Seperator?
+ else if (/[\[\]{}\(\),;\.]/.test(ch)) {
+ if (ch == "(" && beforeParams) state.inParams = true;
+ else if (ch == ")") state.inParams = false;
+ return null;
+ }
+ // start of a number value?
+ else if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return "number";
+ }
+ // multi line comment?
+ else if (ch == "#" && stream.eat("*")) {
+ return chain(stream, state, tokenComment);
+ }
+ // unparsed content?
+ else if (ch == "#" && stream.match(/ *\[ *\[/)) {
+ return chain(stream, state, tokenUnparsed);
+ }
+ // single line comment?
+ else if (ch == "#" && stream.eat("#")) {
+ stream.skipToEnd();
+ return "comment";
+ }
+ // variable?
+ else if (ch == "$") {
+ stream.eatWhile(/[\w\d\$_\.{}]/);
+ // is it one of the specials?
+ if (specials && specials.propertyIsEnumerable(stream.current().toLowerCase())) {
+ return "keyword";
+ }
+ else {
+ state.beforeParams = true;
+ return "builtin";
+ }
+ }
+ // is it a operator?
+ else if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return "operator";
+ }
+ else {
+ // get the whole word
+ stream.eatWhile(/[\w\$_{}]/);
+ var word = stream.current().toLowerCase();
+ // is it one of the listed keywords?
+ if (keywords && keywords.propertyIsEnumerable(word))
+ return "keyword";
+ // is it one of the listed functions?
+ if (functions && functions.propertyIsEnumerable(word) ||
+ stream.current().match(/^#[a-z0-9_]+ *$/i) && stream.peek()=="(") {
+ state.beforeParams = true;
+ return "keyword";
+ }
+ // default: just a "word"
+ return null;
+ }
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {
+ end = true;
+ break;
+ }
+ escaped = !escaped && next == "\\";
+ }
+ if (end) state.tokenize = tokenBase;
+ return "string";
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "#" && maybeEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return "comment";
+ }
+
+ function tokenUnparsed(stream, state) {
+ var maybeEnd = 0, ch;
+ while (ch = stream.next()) {
+ if (ch == "#" && maybeEnd == 2) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ if (ch == "]")
+ maybeEnd++;
+ else if (ch != " ")
+ maybeEnd = 0;
+ }
+ return "meta";
+ }
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: tokenBase,
+ beforeParams: false,
+ inParams: false
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ return state.tokenize(stream, state);
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/velocity", "velocity");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/verilog/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/verilog/index.html
new file mode 100644
index 0000000..775dd53
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/verilog/index.html
@@ -0,0 +1,210 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Verilog mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="verilog.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <style>.CodeMirror {border: 2px inset #dee;}</style>
+ </head>
+ <body>
+ <h1>CodeMirror: Verilog mode</h1>
+
+<form><textarea id="code" name="code">
+/* Verilog demo code */
+
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// wb_master_model.v ////
+//// ////
+//// This file is part of the SPI IP core project ////
+//// http://www.opencores.org/projects/spi/ ////
+//// ////
+//// Author(s): ////
+//// - Simon Srot (simons@opencores.org) ////
+//// ////
+//// Based on: ////
+//// - i2c/bench/verilog/wb_master_model.v ////
+//// Copyright (C) 2001 Richard Herveille ////
+//// ////
+//// All additional information is avaliable in the Readme.txt ////
+//// file. ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2002 Authors ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source is distributed in the hope that it will be ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
+//// PURPOSE. See the GNU Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from http://www.opencores.org/lgpl.shtml ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+
+`include "timescale.v"
+
+module wb_master_model(clk, rst, adr, din, dout, cyc, stb, we, sel, ack, err, rty);
+
+ parameter dwidth = 32;
+ parameter awidth = 32;
+
+ input clk, rst;
+ output [awidth -1:0] adr;
+ input [dwidth -1:0] din;
+ output [dwidth -1:0] dout;
+ output cyc, stb;
+ output we;
+ output [dwidth/8 -1:0] sel;
+ input ack, err, rty;
+
+ // Internal signals
+ reg [awidth -1:0] adr;
+ reg [dwidth -1:0] dout;
+ reg cyc, stb;
+ reg we;
+ reg [dwidth/8 -1:0] sel;
+
+ reg [dwidth -1:0] q;
+
+ // Memory Logic
+ initial
+ begin
+ adr = {awidth{1'bx}};
+ dout = {dwidth{1'bx}};
+ cyc = 1'b0;
+ stb = 1'bx;
+ we = 1'hx;
+ sel = {dwidth/8{1'bx}};
+ #1;
+ end
+
+ // Wishbone write cycle
+ task wb_write;
+ input delay;
+ integer delay;
+
+ input [awidth -1:0] a;
+ input [dwidth -1:0] d;
+
+ begin
+
+ // wait initial delay
+ repeat(delay) @(posedge clk);
+
+ // assert wishbone signal
+ #1;
+ adr = a;
+ dout = d;
+ cyc = 1'b1;
+ stb = 1'b1;
+ we = 1'b1;
+ sel = {dwidth/8{1'b1}};
+ @(posedge clk);
+
+ // wait for acknowledge from slave
+ while(~ack) @(posedge clk);
+
+ // negate wishbone signals
+ #1;
+ cyc = 1'b0;
+ stb = 1'bx;
+ adr = {awidth{1'bx}};
+ dout = {dwidth{1'bx}};
+ we = 1'hx;
+ sel = {dwidth/8{1'bx}};
+
+ end
+ endtask
+
+ // Wishbone read cycle
+ task wb_read;
+ input delay;
+ integer delay;
+
+ input [awidth -1:0] a;
+ output [dwidth -1:0] d;
+
+ begin
+
+ // wait initial delay
+ repeat(delay) @(posedge clk);
+
+ // assert wishbone signals
+ #1;
+ adr = a;
+ dout = {dwidth{1'bx}};
+ cyc = 1'b1;
+ stb = 1'b1;
+ we = 1'b0;
+ sel = {dwidth/8{1'b1}};
+ @(posedge clk);
+
+ // wait for acknowledge from slave
+ while(~ack) @(posedge clk);
+
+ // negate wishbone signals
+ #1;
+ cyc = 1'b0;
+ stb = 1'bx;
+ adr = {awidth{1'bx}};
+ dout = {dwidth{1'bx}};
+ we = 1'hx;
+ sel = {dwidth/8{1'bx}};
+ d = din;
+
+ end
+ endtask
+
+ // Wishbone compare cycle (read data from location and compare with expected data)
+ task wb_cmp;
+ input delay;
+ integer delay;
+
+ input [awidth -1:0] a;
+ input [dwidth -1:0] d_exp;
+
+ begin
+ wb_read (delay, a, q);
+
+ if (d_exp !== q) begin
+ $display("\n--- ERROR: At address 0x%0x, got 0x%0x, expected 0x%0x at time %t", a, q, d_exp, $time);
+ $stop;
+ end
+ end
+ endtask
+
+endmodule
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ mode: "text/x-verilog"
+ });
+ </script>
+
+ <p>Simple mode that tries to handle Verilog-like languages as well as it
+ can. Takes one configuration parameters: <code>keywords</code>, an
+ object whose property names are the keywords in the language.</p>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-verilog</code> (Verilog code).</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/verilog/verilog.js b/codemirror_ui/lib/CodeMirror-2.3/mode/verilog/verilog.js
new file mode 100644
index 0000000..736d16a
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/verilog/verilog.js
@@ -0,0 +1,194 @@
+CodeMirror.defineMode("verilog", function(config, parserConfig) {
+ var indentUnit = config.indentUnit,
+ keywords = parserConfig.keywords || {},
+ blockKeywords = parserConfig.blockKeywords || {},
+ atoms = parserConfig.atoms || {},
+ hooks = parserConfig.hooks || {},
+ multiLineStrings = parserConfig.multiLineStrings;
+ var isOperatorChar = /[&|~><!\)\(*#%@+\/=?\:;}{,\.\^\-\[\]]/;
+
+ var curPunc;
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ if (hooks[ch]) {
+ var result = hooks[ch](stream, state);
+ if (result !== false) return result;
+ }
+ if (ch == '"') {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ }
+ if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+ curPunc = ch;
+ return null
+ }
+ if (/[\d']/.test(ch)) {
+ stream.eatWhile(/[\w\.']/);
+ return "number";
+ }
+ if (ch == "/") {
+ if (stream.eat("*")) {
+ state.tokenize = tokenComment;
+ return tokenComment(stream, state);
+ }
+ if (stream.eat("/")) {
+ stream.skipToEnd();
+ return "comment";
+ }
+ }
+ if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return "operator";
+ }
+ stream.eatWhile(/[\w\$_]/);
+ var cur = stream.current();
+ if (keywords.propertyIsEnumerable(cur)) {
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+ return "keyword";
+ }
+ if (atoms.propertyIsEnumerable(cur)) return "atom";
+ return "word";
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {end = true; break;}
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = tokenBase;
+ return "string";
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return "comment";
+ }
+
+ function Context(indented, column, type, align, prev) {
+ this.indented = indented;
+ this.column = column;
+ this.type = type;
+ this.align = align;
+ this.prev = prev;
+ }
+ function pushContext(state, col, type) {
+ return state.context = new Context(state.indented, col, type, null, state.context);
+ }
+ function popContext(state) {
+ var t = state.context.type;
+ if (t == ")" || t == "]" || t == "}")
+ state.indented = state.context.indented;
+ return state.context = state.context.prev;
+ }
+
+ // Interface
+
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: null,
+ context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
+ indented: 0,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ var ctx = state.context;
+ if (stream.sol()) {
+ if (ctx.align == null) ctx.align = false;
+ state.indented = stream.indentation();
+ state.startOfLine = true;
+ }
+ if (stream.eatSpace()) return null;
+ curPunc = null;
+ var style = (state.tokenize || tokenBase)(stream, state);
+ if (style == "comment" || style == "meta") return style;
+ if (ctx.align == null) ctx.align = true;
+
+ if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
+ else if (curPunc == "{") pushContext(state, stream.column(), "}");
+ else if (curPunc == "[") pushContext(state, stream.column(), "]");
+ else if (curPunc == "(") pushContext(state, stream.column(), ")");
+ else if (curPunc == "}") {
+ while (ctx.type == "statement") ctx = popContext(state);
+ if (ctx.type == "}") ctx = popContext(state);
+ while (ctx.type == "statement") ctx = popContext(state);
+ }
+ else if (curPunc == ctx.type) popContext(state);
+ else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
+ pushContext(state, stream.column(), "statement");
+ state.startOfLine = false;
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ if (state.tokenize != tokenBase && state.tokenize != null) return 0;
+ var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type;
+ if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
+ else if (ctx.align) return ctx.column + (closing ? 0 : 1);
+ else return ctx.indented + (closing ? 0 : indentUnit);
+ },
+
+ electricChars: "{}"
+ };
+});
+
+(function() {
+ function words(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+
+ var verilogKeywords = "always and assign automatic begin buf bufif0 bufif1 case casex casez cell cmos config " +
+ "deassign default defparam design disable edge else end endcase endconfig endfunction endgenerate endmodule " +
+ "endprimitive endspecify endtable endtask event for force forever fork function generate genvar highz0 " +
+ "highz1 if ifnone incdir include initial inout input instance integer join large liblist library localparam " +
+ "macromodule medium module nand negedge nmos nor noshowcancelled not notif0 notif1 or output parameter pmos " +
+ "posedge primitive pull0 pull1 pulldown pullup pulsestyle_onevent pulsestyle_ondetect rcmos real realtime " +
+ "reg release repeat rnmos rpmos rtran rtranif0 rtranif1 scalared showcancelled signed small specify specparam " +
+ "strong0 strong1 supply0 supply1 table task time tran tranif0 tranif1 tri tri0 tri1 triand trior trireg " +
+ "unsigned use vectored wait wand weak0 weak1 while wire wor xnor xor";
+
+ var verilogBlockKeywords = "begin bufif0 bufif1 case casex casez config else end endcase endconfig endfunction " +
+ "endgenerate endmodule endprimitive endspecify endtable endtask for forever function generate if ifnone " +
+ "macromodule module primitive repeat specify table task while";
+
+ function metaHook(stream, state) {
+ stream.eatWhile(/[\w\$_]/);
+ return "meta";
+ }
+
+ // C#-style strings where "" escapes a quote.
+ function tokenAtString(stream, state) {
+ var next;
+ while ((next = stream.next()) != null) {
+ if (next == '"' && !stream.eat('"')) {
+ state.tokenize = null;
+ break;
+ }
+ }
+ return "string";
+ }
+
+ CodeMirror.defineMIME("text/x-verilog", {
+ name: "verilog",
+ keywords: words(verilogKeywords),
+ blockKeywords: words(verilogBlockKeywords),
+ atoms: words("null"),
+ hooks: {"`": metaHook, "$": metaHook}
+ });
+}());
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xml/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/xml/index.html
new file mode 100644
index 0000000..3b6d6af
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xml/index.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: XML mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="xml.js"></script>
+ <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: XML mode</h1>
+ <form><textarea id="code" name="code">
+&lt;html style="color: green"&gt;
+ &lt;!-- this is a comment --&gt;
+ &lt;head&gt;
+ &lt;title&gt;HTML Example&lt;/title&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ The indentation tries to be &lt;em&gt;somewhat &amp;quot;do what
+ I mean&amp;quot;&lt;/em&gt;... but might not match your style.
+ &lt;/body&gt;
+&lt;/html&gt;
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: {name: "xml", alignCDATA: true},
+ lineNumbers: true
+ });
+ </script>
+ <p>The XML mode supports two configuration parameters:</p>
+ <dl>
+ <dt><code>htmlMode (boolean)</code></dt>
+ <dd>This switches the mode to parse HTML instead of XML. This
+ means attributes do not have to be quoted, and some elements
+ (such as <code>br</code>) do not require a closing tag.</dd>
+ <dt><code>alignCDATA (boolean)</code></dt>
+ <dd>Setting this to true will force the opening tag of CDATA
+ blocks to not be indented.</dd>
+ </dl>
+
+ <p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/html</code>.</p>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xml/xml.js b/codemirror_ui/lib/CodeMirror-2.3/mode/xml/xml.js
new file mode 100644
index 0000000..3fbe98f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xml/xml.js
@@ -0,0 +1,325 @@
+CodeMirror.defineMode("xml", function(config, parserConfig) {
+ var indentUnit = config.indentUnit;
+ var Kludges = parserConfig.htmlMode ? {
+ autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
+ 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
+ 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
+ 'track': true, 'wbr': true},
+ implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
+ 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
+ 'th': true, 'tr': true},
+ contextGrabbers: {
+ 'dd': {'dd': true, 'dt': true},
+ 'dt': {'dd': true, 'dt': true},
+ 'li': {'li': true},
+ 'option': {'option': true, 'optgroup': true},
+ 'optgroup': {'optgroup': true},
+ 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
+ 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
+ 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
+ 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
+ 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
+ 'rp': {'rp': true, 'rt': true},
+ 'rt': {'rp': true, 'rt': true},
+ 'tbody': {'tbody': true, 'tfoot': true},
+ 'td': {'td': true, 'th': true},
+ 'tfoot': {'tbody': true},
+ 'th': {'td': true, 'th': true},
+ 'thead': {'tbody': true, 'tfoot': true},
+ 'tr': {'tr': true}
+ },
+ doNotIndent: {"pre": true},
+ allowUnquoted: true,
+ allowMissing: false
+ } : {
+ autoSelfClosers: {},
+ implicitlyClosed: {},
+ contextGrabbers: {},
+ doNotIndent: {},
+ allowUnquoted: false,
+ allowMissing: false
+ };
+ var alignCDATA = parserConfig.alignCDATA;
+
+ // Return variables for tokenizers
+ var tagName, type;
+
+ function inText(stream, state) {
+ function chain(parser) {
+ state.tokenize = parser;
+ return parser(stream, state);
+ }
+
+ var ch = stream.next();
+ if (ch == "<") {
+ if (stream.eat("!")) {
+ if (stream.eat("[")) {
+ if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
+ else return null;
+ }
+ else if (stream.match("--")) return chain(inBlock("comment", "-->"));
+ else if (stream.match("DOCTYPE", true, true)) {
+ stream.eatWhile(/[\w\._\-]/);
+ return chain(doctype(1));
+ }
+ else return null;
+ }
+ else if (stream.eat("?")) {
+ stream.eatWhile(/[\w\._\-]/);
+ state.tokenize = inBlock("meta", "?>");
+ return "meta";
+ }
+ else {
+ type = stream.eat("/") ? "closeTag" : "openTag";
+ stream.eatSpace();
+ tagName = "";
+ var c;
+ while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
+ state.tokenize = inTag;
+ return "tag";
+ }
+ }
+ else if (ch == "&") {
+ var ok;
+ if (stream.eat("#")) {
+ if (stream.eat("x")) {
+ ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
+ } else {
+ ok = stream.eatWhile(/[\d]/) && stream.eat(";");
+ }
+ } else {
+ ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
+ }
+ return ok ? "atom" : "error";
+ }
+ else {
+ stream.eatWhile(/[^&<]/);
+ return null;
+ }
+ }
+
+ function inTag(stream, state) {
+ var ch = stream.next();
+ if (ch == ">" || (ch == "/" && stream.eat(">"))) {
+ state.tokenize = inText;
+ type = ch == ">" ? "endTag" : "selfcloseTag";
+ return "tag";
+ }
+ else if (ch == "=") {
+ type = "equals";
+ return null;
+ }
+ else if (/[\'\"]/.test(ch)) {
+ state.tokenize = inAttribute(ch);
+ return state.tokenize(stream, state);
+ }
+ else {
+ stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
+ return "word";
+ }
+ }
+
+ function inAttribute(quote) {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ if (stream.next() == quote) {
+ state.tokenize = inTag;
+ break;
+ }
+ }
+ return "string";
+ };
+ }
+
+ function inBlock(style, terminator) {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ if (stream.match(terminator)) {
+ state.tokenize = inText;
+ break;
+ }
+ stream.next();
+ }
+ return style;
+ };
+ }
+ function doctype(depth) {
+ return function(stream, state) {
+ var ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == "<") {
+ state.tokenize = doctype(depth + 1);
+ return state.tokenize(stream, state);
+ } else if (ch == ">") {
+ if (depth == 1) {
+ state.tokenize = inText;
+ break;
+ } else {
+ state.tokenize = doctype(depth - 1);
+ return state.tokenize(stream, state);
+ }
+ }
+ }
+ return "meta";
+ };
+ }
+
+ var curState, setStyle;
+ function pass() {
+ for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
+ }
+ function cont() {
+ pass.apply(null, arguments);
+ return true;
+ }
+
+ function pushContext(tagName, startOfLine) {
+ var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
+ curState.context = {
+ prev: curState.context,
+ tagName: tagName,
+ indent: curState.indented,
+ startOfLine: startOfLine,
+ noIndent: noIndent
+ };
+ }
+ function popContext() {
+ if (curState.context) curState.context = curState.context.prev;
+ }
+
+ function element(type) {
+ if (type == "openTag") {
+ curState.tagName = tagName;
+ return cont(attributes, endtag(curState.startOfLine));
+ } else if (type == "closeTag") {
+ var err = false;
+ if (curState.context) {
+ if (curState.context.tagName != tagName) {
+ if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
+ popContext();
+ }
+ err = !curState.context || curState.context.tagName != tagName;
+ }
+ } else {
+ err = true;
+ }
+ if (err) setStyle = "error";
+ return cont(endclosetag(err));
+ }
+ return cont();
+ }
+ function endtag(startOfLine) {
+ return function(type) {
+ if (type == "selfcloseTag" ||
+ (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase()))) {
+ maybePopContext(curState.tagName.toLowerCase());
+ return cont();
+ }
+ if (type == "endTag") {
+ maybePopContext(curState.tagName.toLowerCase());
+ pushContext(curState.tagName, startOfLine);
+ return cont();
+ }
+ return cont();
+ };
+ }
+ function endclosetag(err) {
+ return function(type) {
+ if (err) setStyle = "error";
+ if (type == "endTag") { popContext(); return cont(); }
+ setStyle = "error";
+ return cont(arguments.callee);
+ }
+ }
+ function maybePopContext(nextTagName) {
+ var parentTagName;
+ while (true) {
+ if (!curState.context) {
+ return;
+ }
+ parentTagName = curState.context.tagName.toLowerCase();
+ if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
+ !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
+ return;
+ }
+ popContext();
+ }
+ }
+
+ function attributes(type) {
+ if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
+ if (type == "endTag" || type == "selfcloseTag") return pass();
+ setStyle = "error";
+ return cont(attributes);
+ }
+ function attribute(type) {
+ if (type == "equals") return cont(attvalue, attributes);
+ if (!Kludges.allowMissing) setStyle = "error";
+ return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
+ }
+ function attvalue(type) {
+ if (type == "string") return cont(attvaluemaybe);
+ if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
+ setStyle = "error";
+ return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
+ }
+ function attvaluemaybe(type) {
+ if (type == "string") return cont(attvaluemaybe);
+ else return pass();
+ }
+
+ return {
+ startState: function() {
+ return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
+ },
+
+ token: function(stream, state) {
+ if (stream.sol()) {
+ state.startOfLine = true;
+ state.indented = stream.indentation();
+ }
+ if (stream.eatSpace()) return null;
+
+ setStyle = type = tagName = null;
+ var style = state.tokenize(stream, state);
+ state.type = type;
+ if ((style || type) && style != "comment") {
+ curState = state;
+ while (true) {
+ var comb = state.cc.pop() || element;
+ if (comb(type || style)) break;
+ }
+ }
+ state.startOfLine = false;
+ return setStyle || style;
+ },
+
+ indent: function(state, textAfter, fullLine) {
+ var context = state.context;
+ if ((state.tokenize != inTag && state.tokenize != inText) ||
+ context && context.noIndent)
+ return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
+ if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
+ if (context && /^<\//.test(textAfter))
+ context = context.prev;
+ while (context && !context.startOfLine)
+ context = context.prev;
+ if (context) return context.indent + indentUnit;
+ else return 0;
+ },
+
+ compareStates: function(a, b) {
+ if (a.indented != b.indented || a.tokenize != b.tokenize) return false;
+ for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
+ if (!ca || !cb) return ca == cb;
+ if (ca.tagName != cb.tagName) return false;
+ }
+ },
+
+ electricChars: "/"
+ };
+});
+
+CodeMirror.defineMIME("application/xml", "xml");
+if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
+ CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/index.html
new file mode 100644
index 0000000..82f00d2
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/index.html
@@ -0,0 +1,222 @@
+<!doctype html>
+<html>
+<!--
+/*
+Copyright (C) 2011 by MarkLogic Corporation
+Author: Mike Brevoort <mike@brevoort.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+-->
+ <head>
+ <title>CodeMirror 2: JavaScript mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="http://codemirror.net/lib/codemirror.js"></script>
+ <script src="xquery.js"></script>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ <link rel="stylesheet" href="../../theme/xq-dark.css">
+ <style type="text/css">
+ .CodeMirror {
+ border-top: 1px solid black; border-bottom: 1px solid black;
+ }
+ .CodeMirror-scroll {
+ height:400px;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror 2: XQuery mode</h1>
+
+<div class="cm-s-default">
+ <textarea id="code" name="code">
+xquery version &quot;1.0-ml&quot;;
+(: this is
+ : a
+ "comment" :)
+let $let := &lt;x attr=&quot;value&quot;&gt;&quot;test&quot;&lt;func&gt;function() $var {function()} {$var}&lt;/func&gt;&lt;/x&gt;
+let $joe:=1
+return element element {
+ attribute attribute { 1 },
+ element test { &#39;a&#39; },
+ attribute foo { &quot;bar&quot; },
+ fn:doc()[ foo/@bar eq $let ],
+ //x }
+
+(: a more 'evil' test :)
+(: Modified Blakeley example (: with nested comment :) ... :)
+declare private function local:declare() {()};
+declare private function local:private() {()};
+declare private function local:function() {()};
+declare private function local:local() {()};
+let $let := &lt;let&gt;let $let := &quot;let&quot;&lt;/let&gt;
+return element element {
+ attribute attribute { try { xdmp:version() } catch($e) { xdmp:log($e) } },
+ attribute fn:doc { &quot;bar&quot; castable as xs:string },
+ element text { text { &quot;text&quot; } },
+ fn:doc()[ child::eq/(@bar | attribute::attribute) eq $let ],
+ //fn:doc
+}
+
+
+
+xquery version &quot;1.0-ml&quot;;
+
+(: Copyright 2006-2010 Mark Logic Corporation. :)
+
+(:
+ : Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+ : you may not use this file except in compliance with the License.
+ : You may obtain a copy of the License at
+ :
+ : http://www.apache.org/licenses/LICENSE-2.0
+ :
+ : Unless required by applicable law or agreed to in writing, software
+ : distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+ : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ : See the License for the specific language governing permissions and
+ : limitations under the License.
+ :)
+
+module namespace json = &quot;http://marklogic.com/json&quot;;
+declare default function namespace &quot;http://www.w3.org/2005/xpath-functions&quot;;
+
+(: Need to backslash escape any double quotes, backslashes, and newlines :)
+declare function json:escape($s as xs:string) as xs:string {
+ let $s := replace($s, &quot;\\&quot;, &quot;\\\\&quot;)
+ let $s := replace($s, &quot;&quot;&quot;&quot;, &quot;\\&quot;&quot;&quot;)
+ let $s := replace($s, codepoints-to-string((13, 10)), &quot;\\n&quot;)
+ let $s := replace($s, codepoints-to-string(13), &quot;\\n&quot;)
+ let $s := replace($s, codepoints-to-string(10), &quot;\\n&quot;)
+ return $s
+};
+
+declare function json:atomize($x as element()) as xs:string {
+ if (count($x/node()) = 0) then 'null'
+ else if ($x/@type = &quot;number&quot;) then
+ let $castable := $x castable as xs:float or
+ $x castable as xs:double or
+ $x castable as xs:decimal
+ return
+ if ($castable) then xs:string($x)
+ else error(concat(&quot;Not a number: &quot;, xdmp:describe($x)))
+ else if ($x/@type = &quot;boolean&quot;) then
+ let $castable := $x castable as xs:boolean
+ return
+ if ($castable) then xs:string(xs:boolean($x))
+ else error(concat(&quot;Not a boolean: &quot;, xdmp:describe($x)))
+ else concat('&quot;', json:escape($x), '&quot;')
+};
+
+(: Print the thing that comes after the colon :)
+declare function json:print-value($x as element()) as xs:string {
+ if (count($x/*) = 0) then
+ json:atomize($x)
+ else if ($x/@quote = &quot;true&quot;) then
+ concat('&quot;', json:escape(xdmp:quote($x/node())), '&quot;')
+ else
+ string-join(('{',
+ string-join(for $i in $x/* return json:print-name-value($i), &quot;,&quot;),
+ '}'), &quot;&quot;)
+};
+
+(: Print the name and value both :)
+declare function json:print-name-value($x as element()) as xs:string? {
+ let $name := name($x)
+ let $first-in-array :=
+ count($x/preceding-sibling::*[name(.) = $name]) = 0 and
+ (count($x/following-sibling::*[name(.) = $name]) &gt; 0 or $x/@array = &quot;true&quot;)
+ let $later-in-array := count($x/preceding-sibling::*[name(.) = $name]) &gt; 0
+ return
+
+ if ($later-in-array) then
+ () (: I was handled previously :)
+ else if ($first-in-array) then
+ string-join(('&quot;', json:escape($name), '&quot;:[',
+ string-join((for $i in ($x, $x/following-sibling::*[name(.) = $name]) return json:print-value($i)), &quot;,&quot;),
+ ']'), &quot;&quot;)
+ else
+ string-join(('&quot;', json:escape($name), '&quot;:', json:print-value($x)), &quot;&quot;)
+};
+
+(:~
+ Transforms an XML element into a JSON string representation. See http://json.org.
+ &lt;p/&gt;
+ Sample usage:
+ &lt;pre&gt;
+ xquery version &quot;1.0-ml&quot;;
+ import module namespace json=&quot;http://marklogic.com/json&quot; at &quot;json.xqy&quot;;
+ json:serialize(&amp;lt;foo&amp;gt;&amp;lt;bar&amp;gt;kid&amp;lt;/bar&amp;gt;&amp;lt;/foo&amp;gt;)
+ &lt;/pre&gt;
+ Sample transformations:
+ &lt;pre&gt;
+ &amp;lt;e/&amp;gt; becomes {&quot;e&quot;:null}
+ &amp;lt;e&amp;gt;text&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:&quot;text&quot;}
+ &amp;lt;e&amp;gt;quote &quot; escaping&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:&quot;quote \&quot; escaping&quot;}
+ &amp;lt;e&amp;gt;backslash \ escaping&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:&quot;backslash \\ escaping&quot;}
+ &amp;lt;e&amp;gt;&amp;lt;a&amp;gt;text1&amp;lt;/a&amp;gt;&amp;lt;b&amp;gt;text2&amp;lt;/b&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:&quot;text1&quot;,&quot;b&quot;:&quot;text2&quot;}}
+ &amp;lt;e&amp;gt;&amp;lt;a&amp;gt;text1&amp;lt;/a&amp;gt;&amp;lt;a&amp;gt;text2&amp;lt;/a&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:[&quot;text1&quot;,&quot;text2&quot;]}}
+ &amp;lt;e&amp;gt;&amp;lt;a array=&quot;true&quot;&amp;gt;text1&amp;lt;/a&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:[&quot;text1&quot;]}}
+ &amp;lt;e&amp;gt;&amp;lt;a type=&quot;boolean&quot;&amp;gt;false&amp;lt;/a&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:false}}
+ &amp;lt;e&amp;gt;&amp;lt;a type=&quot;number&quot;&amp;gt;123.5&amp;lt;/a&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:123.5}}
+ &amp;lt;e quote=&quot;true&quot;&amp;gt;&amp;lt;div attrib=&quot;value&quot;/&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:&quot;&amp;lt;div attrib=\&quot;value\&quot;/&amp;gt;&quot;}
+ &lt;/pre&gt;
+ &lt;p/&gt;
+ Namespace URIs are ignored. Namespace prefixes are included in the JSON name.
+ &lt;p/&gt;
+ Attributes are ignored, except for the special attribute @array=&quot;true&quot; that
+ indicates the JSON serialization should write the node, even if single, as an
+ array, and the attribute @type that can be set to &quot;boolean&quot; or &quot;number&quot; to
+ dictate the value should be written as that type (unquoted). There's also
+ an @quote attribute that when set to true writes the inner content as text
+ rather than as structured JSON, useful for sending some XHTML over the
+ wire.
+ &lt;p/&gt;
+ Text nodes within mixed content are ignored.
+
+ @param $x Element node to convert
+ @return String holding JSON serialized representation of $x
+
+ @author Jason Hunter
+ @version 1.0.1
+
+ Ported to xquery 1.0-ml; double escaped backslashes in json:escape
+:)
+declare function json:serialize($x as element()) as xs:string {
+ string-join(('{', json:print-name-value($x), '}'), &quot;&quot;)
+};
+ </textarea>
+</div>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ matchBrackets: true,
+ theme: "xq-dark"
+ });
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>application/xquery</code>.</p>
+
+ <p>Development of the CodeMirror XQuery mode was sponsored by
+ <a href="http://marklogic.com">MarkLogic</a> and developed by
+ <a href="https://twitter.com/mbrevoort">Mike Brevoort</a>.
+ </p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/index.html
new file mode 100644
index 0000000..ba82e54
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/index.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css"/>
+ <script src="http://code.jquery.com/jquery-latest.js"> </script>
+ <script type="text/javascript" src="http://code.jquery.com/qunit/qunit-git.js"></script>
+
+ <script src="../../../lib/codemirror.js"></script>
+ <script src="../xquery.js"></script>
+
+ <script type="text/javascript" src="testBase.js"></script>
+ <script type="text/javascript" src="testMultiAttr.js"></script>
+ <script type="text/javascript" src="testQuotes.js"></script>
+ <script type="text/javascript" src="testEmptySequenceKeyword.js"></script>
+ <script type="text/javascript" src="testProcessingInstructions.js"></script>
+ <script type="text/javascript" src="testNamespaces.js"></script>
+ </head>
+ <body>
+ <h1 id="qunit-header">XQuery CodeMirror Mode</h1>
+ <h2 id="qunit-banner"></h2>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests">
+ </ol>
+ <div id="sandbox" style="right:5000px; position:absolute; "></div>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testBase.js b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testBase.js
new file mode 100644
index 0000000..d40e9ee
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testBase.js
@@ -0,0 +1,42 @@
+ $(document).ready(function(){
+ module("testBase");
+ test("eviltest", function() {
+ expect(1);
+
+ var input = 'xquery version &quot;1.0-ml&quot;;\
+ (: this is\
+ : a \
+ "comment" :)\
+ let $let := &lt;x attr=&quot;value&quot;&gt;&quot;test&quot;&lt;func&gt;function() $var {function()} {$var}&lt;/func&gt;&lt;/x&gt;\
+ let $joe:=1\
+ return element element {\
+ attribute attribute { 1 },\
+ element test { &#39;a&#39; }, \
+ attribute foo { &quot;bar&quot; },\
+ fn:doc()[ foo/@bar eq $let ],\
+ //x } \
+ \
+ (: a more \'evil\' test :)\
+ (: Modified Blakeley example (: with nested comment :) ... :)\
+ declare private function local:declare() {()};\
+ declare private function local:private() {()};\
+ declare private function local:function() {()};\
+ declare private function local:local() {()};\
+ let $let := &lt;let&gt;let $let := &quot;let&quot;&lt;/let&gt;\
+ return element element {\
+ attribute attribute { try { xdmp:version() } catch($e) { xdmp:log($e) } },\
+ attribute fn:doc { &quot;bar&quot; castable as xs:string },\
+ element text { text { &quot;text&quot; } },\
+ fn:doc()[ child::eq/(@bar | attribute::attribute) eq $let ],\
+ //fn:doc\
+ }';
+ var expected = '<span class="cm-keyword">xquery</span> <span class="cm-keyword">version</span> <span class="cm-string">"1.0-ml"</span><span class="cm-variable cm-def">;</span> <span class="cm-comment">(: this is : a "comment" :)</span> <span class="cm-keyword">let</span> <span class="cm-variable">$let</span> <span class="cm-keyword">:=</span> <span class="cm-tag">&lt;x </span><span class="cm-attribute">attr</span>=<span class="cm-string">"value"</span><span class="cm-tag">&gt;</span><span class="cm-word">"test"</span><span class="cm-tag">&lt;func&gt;</span><span class="cm-word">function()</span> <span class="cm-word">$var</span> {<span class="cm-keyword">function</span>()} {<span class="cm-variable">$var</span>}<span class="cm-tag">&lt;/func&gt;&lt;/x&gt;</span> <span class="cm-keyword">let</span> <span class="cm-variable">$joe</span><span class="cm-keyword">:=</span><span class="cm-atom">1</span> <span class="cm-keyword">return</span> <span class="cm-keyword">element</span> <span class="cm-word">element</span> { <span class="cm-keyword">attribute</span> <span class="cm-word">attribute</span> { <span class="cm-atom">1</span> }, <span class="cm-keyword">element</span> <span class="cm-word">test</span> { <span class="cm-string">\'a\'</span> }, <span class="cm-keyword">attribute</span> <span class="cm-word">foo</span> { <span class="cm-string">"bar"</span> }, <span class="cm-variable cm-def">fn:doc</span>()[ <span class="cm-word">foo</span><span class="cm-keyword">/</span><span class="cm-word">@bar</span> <span class="cm-keyword">eq</span> <span class="cm-variable">$let</span> ], <span class="cm-keyword">//</span><span class="cm-word">x</span> } <span class="cm-comment">(: a more \'evil\' test :)</span> <span class="cm-comment">(: Modified Blakeley example (: with nested comment :) ... :)</span> <span class="cm-keyword">declare</span> <span class="cm-keyword">private</span> <span class="cm-keyword">function</span> <span class="cm-variable cm-def">local:declare</span>() {()}<span class="cm-word">;</span> <span class="cm-keyword">declare</span> <span class="cm-keyword">private</span> <span class="cm-keyword">function</span> <span class="cm-variable cm-def">local:private</span>() {()}<span class="cm-word">;</span> <span class="cm-keyword">declare</span> <span class="cm-keyword">private</span> <span class="cm-keyword">function</span> <span class="cm-variable cm-def">local:function</span>() {()}<span class="cm-word">;</span> <span class="cm-keyword">declare</span> <span class="cm-keyword">private</span> <span class="cm-keyword">function</span> <span class="cm-variable cm-def">local:local</span>() {()}<span class="cm-word">;</span> <span class="cm-keyword">let</span> <span class="cm-variable">$let</span> <span class="cm-keyword">:=</span> <span class="cm-tag">&lt;let&gt;</span><span class="cm-word">let</span> <span class="cm-word">$let</span> <span class="cm-word">:=</span> <span class="cm-word">"let"</span><span class="cm-tag">&lt;/let&gt;</span> <span class="cm-keyword">return</span> <span class="cm-keyword">element</span> <span class="cm-word">element</span> { <span class="cm-keyword">attribute</span> <span class="cm-word">attribute</span> { <span class="cm-keyword">try</span> { <span class="cm-variable cm-def">xdmp:version</span>() } <span class="cm-keyword">catch</span>(<span class="cm-variable">$e</span>) { <span class="cm-variable cm-def">xdmp:log</span>(<span class="cm-variable">$e</span>) } }, <span class="cm-keyword">attribute</span> <span class="cm-word">fn:doc</span> { <span class="cm-string">"bar"</span> <span class="cm-word">castable</span> <span class="cm-keyword">as</span> <span class="cm-atom">xs:string</span> }, <span class="cm-keyword">element</span> <span class="cm-word">text</span> { <span class="cm-keyword">text</span> { <span class="cm-string">"text"</span> } }, <span class="cm-variable cm-def">fn:doc</span>()[ <span class="cm-qualifier">child::</span><span class="cm-word">eq</span><span class="cm-keyword">/</span>(<span class="cm-word">@bar</span> <span class="cm-keyword">|</span> <span class="cm-qualifier">attribute::</span><span class="cm-word">attribute</span>) <span class="cm-keyword">eq</span> <span class="cm-variable">$let</span> ], <span class="cm-keyword">//</span><span class="cm-word">fn:doc</span> }';
+
+ $("#sandbox").html('<textarea id="editor">' + input + '</textarea>');
+ var editor = CodeMirror.fromTextArea($("#editor")[0]);
+ var result = $(".CodeMirror-lines div div pre")[0].innerHTML;
+
+ equal(result, expected);
+ $("#editor").html("");
+ });
+ });
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testEmptySequenceKeyword.js b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testEmptySequenceKeyword.js
new file mode 100644
index 0000000..39ed090
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testEmptySequenceKeyword.js
@@ -0,0 +1,16 @@
+$(document).ready(function(){
+ module("testEmptySequenceKeyword");
+ test("testEmptySequenceKeyword", function() {
+ expect(1);
+
+ var input = '"foo" instance of empty-sequence()';
+ var expected = '<span class="cm-string">"foo"</span> <span class="cm-keyword">instance</span> <span class="cm-keyword">of</span> <span class="cm-keyword">empty-sequence</span>()';
+
+ $("#sandbox").html('<textarea id="editor">' + input + '</textarea>');
+ var editor = CodeMirror.fromTextArea($("#editor")[0]);
+ var result = $(".CodeMirror-lines div div pre")[0].innerHTML;
+
+ equal(result, expected);
+ $("#editor").html("");
+ });
+});
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testMultiAttr.js b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testMultiAttr.js
new file mode 100644
index 0000000..8e98c47
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testMultiAttr.js
@@ -0,0 +1,16 @@
+ $(document).ready(function(){
+ module("testMultiAttr");
+ test("test1", function() {
+ expect(1);
+
+ var expected = '<span class="cm-tag">&lt;p </span><span class="cm-attribute">a1</span>=<span class="cm-string">"foo"</span> <span class="cm-attribute">a2</span>=<span class="cm-string">"bar"</span><span class="cm-tag">&gt;</span><span class="cm-word">hello</span> <span class="cm-word">world</span><span class="cm-tag">&lt;/p&gt;</span>';
+
+ $("#sandbox").html('<textarea id="editor"></textarea>');
+ $("#editor").html('<p a1="foo" a2="bar">hello world</p>');
+ var editor = CodeMirror.fromTextArea($("#editor")[0]);
+ var result = $(".CodeMirror-lines div div pre")[0].innerHTML;
+
+ equal(result, expected);
+ $("#editor").html("");
+ });
+ }); \ No newline at end of file
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testNamespaces.js b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testNamespaces.js
new file mode 100644
index 0000000..4efea63
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testNamespaces.js
@@ -0,0 +1,91 @@
+$(document).ready(function(){
+ module("test namespaces");
+
+// --------------------------------------------------------------------------------
+// this test is based on this:
+//http://mbrevoort.github.com/CodeMirror2/#!exprSeqTypes/PrologExpr/VariableProlog/ExternalVariablesWith/K2-ExternalVariablesWith-10.xq
+// --------------------------------------------------------------------------------
+ test("test namespaced variable", function() {
+ expect(1);
+
+ var input = 'declare namespace e = "http://example.com/ANamespace";\
+declare variable $e:exampleComThisVarIsNotRecognized as element(*) external;';
+
+ var expected = '<span class="cm-keyword">declare</span> <span class="cm-keyword">namespace</span> <span class="cm-word">e</span> <span class="cm-keyword">=</span> <span class="cm-string">"http://example.com/ANamespace"</span><span class="cm-word">;declare</span> <span class="cm-keyword">variable</span> <span class="cm-variable">$e:exampleComThisVarIsNotRecognized</span> <span class="cm-keyword">as</span> <span class="cm-keyword">element</span>(<span class="cm-keyword">*</span>) <span class="cm-word">external;</span>';
+
+ $("#sandbox").html('<textarea id="editor">' + input + '</textarea>');
+ var editor = CodeMirror.fromTextArea($("#editor")[0]);
+ var result = $(".CodeMirror-lines div div pre")[0].innerHTML;
+
+ equal(result, expected);
+ $("#editor").html("");
+ });
+
+
+// --------------------------------------------------------------------------------
+// this test is based on:
+// http://mbrevoort.github.com/CodeMirror2/#!Basics/EQNames/eqname-002.xq
+// --------------------------------------------------------------------------------
+ test("test EQName variable", function() {
+ expect(1);
+
+ var input = 'declare variable $"http://www.example.com/ns/my":var := 12;\
+<out>{$"http://www.example.com/ns/my":var}</out>';
+
+ var expected = '<span class="cm-keyword">declare</span> <span class="cm-keyword">variable</span> <span class="cm-variable">$"http://www.example.com/ns/my":var</span> <span class="cm-keyword">:=</span> <span class="cm-atom">12</span><span class="cm-word">;</span><span class="cm-tag">&lt;out&gt;</span>{<span class="cm-variable">$"http://www.example.com/ns/my":var</span>}<span class="cm-tag">&lt;/out&gt;</span>';
+
+ $("#sandbox").html('<textarea id="editor">' + input + '</textarea>');
+ var editor = CodeMirror.fromTextArea($("#editor")[0]);
+ var result = $(".CodeMirror-lines div div pre")[0].innerHTML;
+
+ equal(result, expected);
+ $("#editor").html("");
+ });
+
+// --------------------------------------------------------------------------------
+// this test is based on:
+// http://mbrevoort.github.com/CodeMirror2/#!Basics/EQNames/eqname-003.xq
+// --------------------------------------------------------------------------------
+ test("test EQName function", function() {
+ expect(1);
+
+ var input = 'declare function "http://www.example.com/ns/my":fn ($a as xs:integer) as xs:integer {\
+ $a + 2\
+};\
+<out>{"http://www.example.com/ns/my":fn(12)}</out>';
+
+ var expected = '<span class="cm-keyword">declare</span> <span class="cm-keyword">function</span> <span class="cm-variable cm-def">"http://www.example.com/ns/my":fn</span> (<span class="cm-variable">$a</span> <span class="cm-keyword">as</span> <span class="cm-atom">xs:integer</span>) <span class="cm-keyword">as</span> <span class="cm-atom">xs:integer</span> { <span class="cm-variable">$a</span> <span class="cm-keyword">+</span> <span class="cm-atom">2</span>}<span class="cm-word">;</span><span class="cm-tag">&lt;out&gt;</span>{<span class="cm-variable cm-def">"http://www.example.com/ns/my":fn</span>(<span class="cm-atom">12</span>)}<span class="cm-tag">&lt;/out&gt;</span>';
+
+ $("#sandbox").html('<textarea id="editor">' + input + '</textarea>');
+ var editor = CodeMirror.fromTextArea($("#editor")[0]);
+ var result = $(".CodeMirror-lines div div pre")[0].innerHTML;
+
+ equal(result, expected);
+ $("#editor").html("");
+ });
+
+// --------------------------------------------------------------------------------
+// this test is based on:
+// http://mbrevoort.github.com/CodeMirror2/#!Basics/EQNames/eqname-003.xq
+// --------------------------------------------------------------------------------
+ test("test EQName function with single quotes", function() {
+ expect(1);
+
+ var input = 'declare function \'http://www.example.com/ns/my\':fn ($a as xs:integer) as xs:integer {\
+ $a + 2\
+};\
+<out>{\'http://www.example.com/ns/my\':fn(12)}</out>';
+
+ var expected = '<span class="cm-keyword">declare</span> <span class="cm-keyword">function</span> <span class="cm-variable cm-def">\'http://www.example.com/ns/my\':fn</span> (<span class="cm-variable">$a</span> <span class="cm-keyword">as</span> <span class="cm-atom">xs:integer</span>) <span class="cm-keyword">as</span> <span class="cm-atom">xs:integer</span> { <span class="cm-variable">$a</span> <span class="cm-keyword">+</span> <span class="cm-atom">2</span>}<span class="cm-word">;</span><span class="cm-tag">&lt;out&gt;</span>{<span class="cm-variable cm-def">\'http://www.example.com/ns/my\':fn</span>(<span class="cm-atom">12</span>)}<span class="cm-tag">&lt;/out&gt;</span>';
+
+ $("#sandbox").html('<textarea id="editor">' + input + '</textarea>');
+ var editor = CodeMirror.fromTextArea($("#editor")[0]);
+ var result = $(".CodeMirror-lines div div pre")[0].innerHTML;
+
+ equal(result, expected);
+ $("#editor").html("");
+ });
+
+});
+
+
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testProcessingInstructions.js b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testProcessingInstructions.js
new file mode 100644
index 0000000..9b75305
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testProcessingInstructions.js
@@ -0,0 +1,16 @@
+$(document).ready(function(){
+ module("testProcessingInstructions");
+ test("testProcessingInstructions", function() {
+ expect(1);
+
+ var input = 'data(<?target content?>) instance of xs:string';
+ var expected = '<span class="cm-variable cm-def">data</span>(<span class="cm-comment cm-meta">&lt;?target content?&gt;</span>) <span class="cm-keyword">instance</span> <span class="cm-keyword">of</span> <span class="cm-atom">xs:string</span>';
+
+ $("#sandbox").html('<textarea id="editor">' + input + '</textarea>');
+ var editor = CodeMirror.fromTextArea($("#editor")[0]);
+ var result = $(".CodeMirror-lines div div pre")[0].innerHTML;
+
+ equal(result, expected);
+ $("#editor").html("");
+ });
+});
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testQuotes.js b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testQuotes.js
new file mode 100644
index 0000000..79e5142
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/test/testQuotes.js
@@ -0,0 +1,19 @@
+ $(document).ready(function(){
+ module("testQuoteEscape");
+ test("testQuoteEscapeDouble", function() {
+ expect(1);
+
+ var input = 'let $rootfolder := "c:\\builds\\winnt\\HEAD\\qa\\scripts\\"\
+let $keysfolder := concat($rootfolder, "keys\\")\
+return\
+$keysfolder';
+ var expected = '<span class="cm-keyword">let</span> <span class="cm-variable">$rootfolder</span> <span class="cm-keyword">:=</span> <span class="cm-string">"c:\\builds\\winnt\\HEAD\\qa\\scripts\\"</span><span class="cm-keyword">let</span> <span class="cm-variable">$keysfolder</span> <span class="cm-keyword">:=</span> <span class="cm-variable cm-def">concat</span>(<span class="cm-variable">$rootfolder</span>, <span class="cm-string">"keys\\"</span>)<span class="cm-word">return$keysfolder</span>';
+
+ $("#sandbox").html('<textarea id="editor">' + input + '</textarea>');
+ var editor = CodeMirror.fromTextArea($("#editor")[0]);
+ var result = $(".CodeMirror-lines div div pre")[0].innerHTML;
+
+ equal(result, expected);
+ $("#editor").html("");
+ });
+ });
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/xquery.js b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/xquery.js
new file mode 100644
index 0000000..78916da
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/xquery/xquery.js
@@ -0,0 +1,448 @@
+/*
+Copyright (C) 2011 by MarkLogic Corporation
+Author: Mike Brevoort <mike@brevoort.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+CodeMirror.defineMode("xquery", function(config, parserConfig) {
+
+ // The keywords object is set to the result of this self executing
+ // function. Each keyword is a property of the keywords object whose
+ // value is {type: atype, style: astyle}
+ var keywords = function(){
+ // conveinence functions used to build keywords object
+ function kw(type) {return {type: type, style: "keyword"};}
+ var A = kw("keyword a")
+ , B = kw("keyword b")
+ , C = kw("keyword c")
+ , operator = kw("operator")
+ , atom = {type: "atom", style: "atom"}
+ , punctuation = {type: "punctuation", style: ""}
+ , qualifier = {type: "axis_specifier", style: "qualifier"};
+
+ // kwObj is what is return from this function at the end
+ var kwObj = {
+ 'if': A, 'switch': A, 'while': A, 'for': A,
+ 'else': B, 'then': B, 'try': B, 'finally': B, 'catch': B,
+ 'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C,
+ 'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C,
+ ',': punctuation,
+ 'null': atom, 'fn:false()': atom, 'fn:true()': atom
+ };
+
+ // a list of 'basic' keywords. For each add a property to kwObj with the value of
+ // {type: basic[i], style: "keyword"} e.g. 'after' --> {type: "after", style: "keyword"}
+ var basic = ['after','ancestor','ancestor-or-self','and','as','ascending','assert','attribute','before',
+ 'by','case','cast','child','comment','declare','default','define','descendant','descendant-or-self',
+ 'descending','document','document-node','element','else','eq','every','except','external','following',
+ 'following-sibling','follows','for','function','if','import','in','instance','intersect','item',
+ 'let','module','namespace','node','node','of','only','or','order','parent','precedes','preceding',
+ 'preceding-sibling','processing-instruction','ref','return','returns','satisfies','schema','schema-element',
+ 'self','some','sortby','stable','text','then','to','treat','typeswitch','union','variable','version','where',
+ 'xquery', 'empty-sequence'];
+ for(var i=0, l=basic.length; i < l; i++) { kwObj[basic[i]] = kw(basic[i])};
+
+ // a list of types. For each add a property to kwObj with the value of
+ // {type: "atom", style: "atom"}
+ var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime',
+ 'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary',
+ 'xs:base64Binary', 'xs:anyURI', 'xs:QName', 'xs:byte','xs:boolean','xs:anyURI','xf:yearMonthDuration'];
+ for(var i=0, l=types.length; i < l; i++) { kwObj[types[i]] = atom;};
+
+ // each operator will add a property to kwObj with value of {type: "operator", style: "keyword"}
+ var operators = ['eq', 'ne', 'lt', 'le', 'gt', 'ge', ':=', '=', '>', '>=', '<', '<=', '.', '|', '?', 'and', 'or', 'div', 'idiv', 'mod', '*', '/', '+', '-'];
+ for(var i=0, l=operators.length; i < l; i++) { kwObj[operators[i]] = operator;};
+
+ // each axis_specifiers will add a property to kwObj with value of {type: "axis_specifier", style: "qualifier"}
+ var axis_specifiers = ["self::", "attribute::", "child::", "descendant::", "descendant-or-self::", "parent::",
+ "ancestor::", "ancestor-or-self::", "following::", "preceding::", "following-sibling::", "preceding-sibling::"];
+ for(var i=0, l=axis_specifiers.length; i < l; i++) { kwObj[axis_specifiers[i]] = qualifier; };
+
+ return kwObj;
+ }();
+
+ // Used as scratch variables to communicate multiple values without
+ // consing up tons of objects.
+ var type, content;
+
+ function ret(tp, style, cont) {
+ type = tp; content = cont;
+ return style;
+ }
+
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ // the primary mode tokenizer
+ function tokenBase(stream, state) {
+ var ch = stream.next(),
+ mightBeFunction = false,
+ isEQName = isEQNameAhead(stream);
+
+ // an XML tag (if not in some sub, chained tokenizer)
+ if (ch == "<") {
+ if(stream.match("!--", true))
+ return chain(stream, state, tokenXMLComment);
+
+ if(stream.match("![CDATA", false)) {
+ state.tokenize = tokenCDATA;
+ return ret("tag", "tag");
+ }
+
+ if(stream.match("?", false)) {
+ return chain(stream, state, tokenPreProcessing);
+ }
+
+ var isclose = stream.eat("/");
+ stream.eatSpace();
+ var tagName = "", c;
+ while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
+
+ return chain(stream, state, tokenTag(tagName, isclose));
+ }
+ // start code block
+ else if(ch == "{") {
+ pushStateStack(state,{ type: "codeblock"});
+ return ret("", "");
+ }
+ // end code block
+ else if(ch == "}") {
+ popStateStack(state);
+ return ret("", "");
+ }
+ // if we're in an XML block
+ else if(isInXmlBlock(state)) {
+ if(ch == ">")
+ return ret("tag", "tag");
+ else if(ch == "/" && stream.eat(">")) {
+ popStateStack(state);
+ return ret("tag", "tag");
+ }
+ else
+ return ret("word", "word");
+ }
+ // if a number
+ else if (/\d/.test(ch)) {
+ stream.match(/^\d*(?:\.\d*)?(?:E[+\-]?\d+)?/);
+ return ret("number", "atom");
+ }
+ // comment start
+ else if (ch === "(" && stream.eat(":")) {
+ pushStateStack(state, { type: "comment"});
+ return chain(stream, state, tokenComment);
+ }
+ // quoted string
+ else if ( !isEQName && (ch === '"' || ch === "'"))
+ return chain(stream, state, tokenString(ch));
+ // variable
+ else if(ch === "$") {
+ return chain(stream, state, tokenVariable);
+ }
+ // assignment
+ else if(ch ===":" && stream.eat("=")) {
+ return ret("operator", "keyword");
+ }
+ // open paren
+ else if(ch === "(") {
+ pushStateStack(state, { type: "paren"});
+ return ret("", "");
+ }
+ // close paren
+ else if(ch === ")") {
+ popStateStack(state);
+ return ret("", "");
+ }
+ // open paren
+ else if(ch === "[") {
+ pushStateStack(state, { type: "bracket"});
+ return ret("", "");
+ }
+ // close paren
+ else if(ch === "]") {
+ popStateStack(state);
+ return ret("", "");
+ }
+ else {
+ var known = keywords.propertyIsEnumerable(ch) && keywords[ch];
+
+ // if there's a EQName ahead, consume the rest of the string portion, it's likely a function
+ if(isEQName && ch === '\"') while(stream.next() !== '"'){}
+ if(isEQName && ch === '\'') while(stream.next() !== '\''){}
+
+ // gobble up a word if the character is not known
+ if(!known) stream.eatWhile(/[\w\$_-]/);
+
+ // gobble a colon in the case that is a lib func type call fn:doc
+ var foundColon = stream.eat(":")
+
+ // if there's not a second colon, gobble another word. Otherwise, it's probably an axis specifier
+ // which should get matched as a keyword
+ if(!stream.eat(":") && foundColon) {
+ stream.eatWhile(/[\w\$_-]/);
+ }
+ // if the next non whitespace character is an open paren, this is probably a function (if not a keyword of other sort)
+ if(stream.match(/^[ \t]*\(/, false)) {
+ mightBeFunction = true;
+ }
+ // is the word a keyword?
+ var word = stream.current();
+ known = keywords.propertyIsEnumerable(word) && keywords[word];
+
+ // if we think it's a function call but not yet known,
+ // set style to variable for now for lack of something better
+ if(mightBeFunction && !known) known = {type: "function_call", style: "variable def"};
+
+ // if the previous word was element, attribute, axis specifier, this word should be the name of that
+ if(isInXmlConstructor(state)) {
+ popStateStack(state);
+ return ret("word", "word", word);
+ }
+ // as previously checked, if the word is element,attribute, axis specifier, call it an "xmlconstructor" and
+ // push the stack so we know to look for it on the next word
+ if(word == "element" || word == "attribute" || known.type == "axis_specifier") pushStateStack(state, {type: "xmlconstructor"});
+
+ // if the word is known, return the details of that else just call this a generic 'word'
+ return known ? ret(known.type, known.style, word) :
+ ret("word", "word", word);
+ }
+ }
+
+ // handle comments, including nested
+ function tokenComment(stream, state) {
+ var maybeEnd = false, maybeNested = false, nestedCount = 0, ch;
+ while (ch = stream.next()) {
+ if (ch == ")" && maybeEnd) {
+ if(nestedCount > 0)
+ nestedCount--;
+ else {
+ popStateStack(state);
+ break;
+ }
+ }
+ else if(ch == ":" && maybeNested) {
+ nestedCount++;
+ }
+ maybeEnd = (ch == ":");
+ maybeNested = (ch == "(");
+ }
+
+ return ret("comment", "comment");
+ }
+
+ // tokenizer for string literals
+ // optionally pass a tokenizer function to set state.tokenize back to when finished
+ function tokenString(quote, f) {
+ return function(stream, state) {
+ var ch;
+
+ if(isInString(state) && stream.current() == quote) {
+ popStateStack(state);
+ if(f) state.tokenize = f;
+ return ret("string", "string");
+ }
+
+ pushStateStack(state, { type: "string", name: quote, tokenize: tokenString(quote, f) });
+
+ // if we're in a string and in an XML block, allow an embedded code block
+ if(stream.match("{", false) && isInXmlAttributeBlock(state)) {
+ state.tokenize = tokenBase;
+ return ret("string", "string");
+ }
+
+
+ while (ch = stream.next()) {
+ if (ch == quote) {
+ popStateStack(state);
+ if(f) state.tokenize = f;
+ break;
+ }
+ else {
+ // if we're in a string and in an XML block, allow an embedded code block in an attribute
+ if(stream.match("{", false) && isInXmlAttributeBlock(state)) {
+ state.tokenize = tokenBase;
+ return ret("string", "string");
+ }
+
+ }
+ }
+
+ return ret("string", "string");
+ };
+ }
+
+ // tokenizer for variables
+ function tokenVariable(stream, state) {
+ var isVariableChar = /[\w\$_-]/;
+
+ // a variable may start with a quoted EQName so if the next character is quote, consume to the next quote
+ if(stream.eat("\"")) {
+ while(stream.next() !== '\"'){};
+ stream.eat(":");
+ } else {
+ stream.eatWhile(isVariableChar);
+ if(!stream.match(":=", false)) stream.eat(":");
+ }
+ stream.eatWhile(isVariableChar);
+ state.tokenize = tokenBase;
+ return ret("variable", "variable");
+ }
+
+ // tokenizer for XML tags
+ function tokenTag(name, isclose) {
+ return function(stream, state) {
+ stream.eatSpace();
+ if(isclose && stream.eat(">")) {
+ popStateStack(state);
+ state.tokenize = tokenBase;
+ return ret("tag", "tag");
+ }
+ // self closing tag without attributes?
+ if(!stream.eat("/"))
+ pushStateStack(state, { type: "tag", name: name, tokenize: tokenBase});
+ if(!stream.eat(">")) {
+ state.tokenize = tokenAttribute;
+ return ret("tag", "tag");
+ }
+ else {
+ state.tokenize = tokenBase;
+ }
+ return ret("tag", "tag");
+ }
+ }
+
+ // tokenizer for XML attributes
+ function tokenAttribute(stream, state) {
+ var ch = stream.next();
+
+ if(ch == "/" && stream.eat(">")) {
+ if(isInXmlAttributeBlock(state)) popStateStack(state);
+ if(isInXmlBlock(state)) popStateStack(state);
+ return ret("tag", "tag");
+ }
+ if(ch == ">") {
+ if(isInXmlAttributeBlock(state)) popStateStack(state);
+ return ret("tag", "tag");
+ }
+ if(ch == "=")
+ return ret("", "");
+ // quoted string
+ if (ch == '"' || ch == "'")
+ return chain(stream, state, tokenString(ch, tokenAttribute));
+
+ if(!isInXmlAttributeBlock(state))
+ pushStateStack(state, { type: "attribute", name: name, tokenize: tokenAttribute});
+
+ stream.eat(/[a-zA-Z_:]/);
+ stream.eatWhile(/[-a-zA-Z0-9_:.]/);
+ stream.eatSpace();
+
+ // the case where the attribute has not value and the tag was closed
+ if(stream.match(">", false) || stream.match("/", false)) {
+ popStateStack(state);
+ state.tokenize = tokenBase;
+ }
+
+ return ret("attribute", "attribute");
+ }
+
+ // handle comments, including nested
+ function tokenXMLComment(stream, state) {
+ while (ch = stream.next()) {
+ if (ch == "-" && stream.match("->", true)) {
+ state.tokenize = tokenBase;
+ return ret("comment", "comment");
+ }
+ }
+ }
+
+
+ // handle CDATA
+ function tokenCDATA(stream, state) {
+ while (ch = stream.next()) {
+ if (ch == "]" && stream.match("]", true)) {
+ state.tokenize = tokenBase;
+ return ret("comment", "comment");
+ }
+ }
+ }
+
+ // handle preprocessing instructions
+ function tokenPreProcessing(stream, state) {
+ while (ch = stream.next()) {
+ if (ch == "?" && stream.match(">", true)) {
+ state.tokenize = tokenBase;
+ return ret("comment", "comment meta");
+ }
+ }
+ }
+
+
+ // functions to test the current context of the state
+ function isInXmlBlock(state) { return isIn(state, "tag"); }
+ function isInXmlAttributeBlock(state) { return isIn(state, "attribute"); }
+ function isInCodeBlock(state) { return isIn(state, "codeblock"); }
+ function isInXmlConstructor(state) { return isIn(state, "xmlconstructor"); }
+ function isInString(state) { return isIn(state, "string"); }
+
+ function isEQNameAhead(stream) {
+ // assume we've already eaten a quote (")
+ if(stream.current() === '"')
+ return stream.match(/^[^\"]+\"\:/, false);
+ else if(stream.current() === '\'')
+ return stream.match(/^[^\"]+\'\:/, false);
+ else
+ return false;
+ }
+
+ function isIn(state, type) {
+ return (state.stack.length && state.stack[state.stack.length - 1].type == type);
+ }
+
+ function pushStateStack(state, newState) {
+ state.stack.push(newState);
+ }
+
+ function popStateStack(state) {
+ var popped = state.stack.pop();
+ var reinstateTokenize = state.stack.length && state.stack[state.stack.length-1].tokenize
+ state.tokenize = reinstateTokenize || tokenBase;
+ }
+
+ // the interface for the mode API
+ return {
+ startState: function(basecolumn) {
+ return {
+ tokenize: tokenBase,
+ cc: [],
+ stack: []
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ }
+ };
+
+});
+
+CodeMirror.defineMIME("application/xquery", "xquery");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/yaml/index.html b/codemirror_ui/lib/CodeMirror-2.3/mode/yaml/index.html
new file mode 100644
index 0000000..7f2c792
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/yaml/index.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: YAML mode</title>
+ <link rel="stylesheet" href="../../lib/codemirror.css">
+ <script src="../../lib/codemirror.js"></script>
+ <script src="yaml.js"></script>
+ <style>.CodeMirror { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; }</style>
+ <link rel="stylesheet" href="../../doc/docs.css">
+ </head>
+ <body>
+ <h1>CodeMirror: YAML mode</h1>
+ <form><textarea id="code" name="code">
+--- # Favorite movies
+- Casablanca
+- North by Northwest
+- The Man Who Wasn't There
+--- # Shopping list
+[milk, pumpkin pie, eggs, juice]
+--- # Indented Blocks, common in YAML data files, use indentation and new lines to separate the key: value pairs
+ name: John Smith
+ age: 33
+--- # Inline Blocks, common in YAML data streams, use commas to separate the key: value pairs between braces
+{name: John Smith, age: 33}
+---
+receipt: Oz-Ware Purchase Invoice
+date: 2007-08-06
+customer:
+ given: Dorothy
+ family: Gale
+
+items:
+ - part_no: A4786
+ descrip: Water Bucket (Filled)
+ price: 1.47
+ quantity: 4
+
+ - part_no: E1628
+ descrip: High Heeled "Ruby" Slippers
+ size: 8
+ price: 100.27
+ quantity: 1
+
+bill-to: &id001
+ street: |
+ 123 Tornado Alley
+ Suite 16
+ city: East Centerville
+ state: KS
+
+ship-to: *id001
+
+specialDelivery: >
+ Follow the Yellow Brick
+ Road to the Emerald City.
+ Pay no attention to the
+ man behind the curtain.
+...
+</textarea></form>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+ </script>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-yaml</code>.</p>
+
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/mode/yaml/yaml.js b/codemirror_ui/lib/CodeMirror-2.3/mode/yaml/yaml.js
new file mode 100644
index 0000000..59e2641
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/mode/yaml/yaml.js
@@ -0,0 +1,95 @@
+CodeMirror.defineMode("yaml", function() {
+
+ var cons = ['true', 'false', 'on', 'off', 'yes', 'no'];
+ var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i');
+
+ return {
+ token: function(stream, state) {
+ var ch = stream.peek();
+ var esc = state.escaped;
+ state.escaped = false;
+ /* comments */
+ if (ch == "#") { stream.skipToEnd(); return "comment"; }
+ if (state.literal && stream.indentation() > state.keyCol) {
+ stream.skipToEnd(); return "string";
+ } else if (state.literal) { state.literal = false; }
+ if (stream.sol()) {
+ state.keyCol = 0;
+ state.pair = false;
+ state.pairStart = false;
+ /* document start */
+ if(stream.match(/---/)) { return "def"; }
+ /* document end */
+ if (stream.match(/\.\.\./)) { return "def"; }
+ /* array list item */
+ if (stream.match(/\s*-\s+/)) { return 'meta'; }
+ }
+ /* pairs (associative arrays) -> key */
+ if (!state.pair && stream.match(/^\s*([a-z0-9\._-])+(?=\s*:)/i)) {
+ state.pair = true;
+ state.keyCol = stream.indentation();
+ return "atom";
+ }
+ if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; }
+
+ /* inline pairs/lists */
+ if (stream.match(/^(\{|\}|\[|\])/)) {
+ if (ch == '{')
+ state.inlinePairs++;
+ else if (ch == '}')
+ state.inlinePairs--;
+ else if (ch == '[')
+ state.inlineList++;
+ else
+ state.inlineList--;
+ return 'meta';
+ }
+
+ /* list seperator */
+ if (state.inlineList > 0 && !esc && ch == ',') {
+ stream.next();
+ return 'meta';
+ }
+ /* pairs seperator */
+ if (state.inlinePairs > 0 && !esc && ch == ',') {
+ state.keyCol = 0;
+ state.pair = false;
+ state.pairStart = false;
+ stream.next();
+ return 'meta';
+ }
+
+ /* start of value of a pair */
+ if (state.pairStart) {
+ /* block literals */
+ if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; };
+ /* references */
+ if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; }
+ /* numbers */
+ if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; }
+ if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; }
+ /* keywords */
+ if (stream.match(keywordRegex)) { return 'keyword'; }
+ }
+
+ /* nothing found, continue */
+ state.pairStart = false;
+ state.escaped = (ch == '\\');
+ stream.next();
+ return null;
+ },
+ startState: function() {
+ return {
+ pair: false,
+ pairStart: false,
+ keyCol: 0,
+ inlinePairs: 0,
+ inlineList: 0,
+ literal: false,
+ escaped: false
+ };
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/x-yaml", "yaml");
diff --git a/codemirror_ui/lib/CodeMirror-2.3/package.json b/codemirror_ui/lib/CodeMirror-2.3/package.json
new file mode 100644
index 0000000..22645dc
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "CodeMirror",
+ "version":"2.30.0",
+ "main": "codemirror.js",
+ "description": "In-browser code editing made bearable",
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "http://codemirror.net/LICENSE"
+ }
+ ],
+ "directories": {
+ "lib": "./lib"
+ },
+ "bugs": "http://github.com/marijnh/CodeMirror2/issues",
+ "keywords": ["JavaScript", "CodeMirror", "Editor"],
+ "homepage": "http://codemirror.net",
+ "maintainers":[ {
+ "name": "Marijn Haverbeke",
+ "email": "marijnh@gmail.com",
+ "web": "http://codemirror.net"
+ }],
+ "repositories": [
+ {
+ "type": "git",
+ "url": "https://github.com/marijnh/CodeMirror2.git"
+ }
+ ]
+}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/test/index.html b/codemirror_ui/lib/CodeMirror-2.3/test/index.html
new file mode 100644
index 0000000..53471b1
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/test/index.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html>
+ <head>
+ <title>CodeMirror: Test Suite</title>
+ <link rel="stylesheet" href="../lib/codemirror.css">
+ <script src="../lib/codemirror.js"></script>
+ <script src="../mode/javascript/javascript.js"></script>
+
+ <style type="text/css">
+ .ok {color: #0e0;}
+ .failure {color: #e00;}
+ .error {color: #c90;}
+ </style>
+ </head>
+ <body>
+ <h1>CodeMirror: Test Suite</h1>
+
+ <p>A limited set of programmatic sanity tests for CodeMirror.</p>
+
+ <pre id=output></pre>
+
+ <div style="visibility: hidden" id=testground>
+ <form><textarea id="code" name="code"></textarea><input type=submit value=ok name=submit></form>
+ </div>
+
+ <script src="test.js"></script>
+ </body>
+</html>
diff --git a/codemirror_ui/lib/CodeMirror-2.3/test/mode_test.css b/codemirror_ui/lib/CodeMirror-2.3/test/mode_test.css
new file mode 100644
index 0000000..f425922
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/test/mode_test.css
@@ -0,0 +1,22 @@
+.mt-output .mt-token {
+ border: 1px solid #ddd;
+ white-space: pre;
+ font-family: "Consolas", monospace;
+ text-align: center;
+}
+
+.mt-output .mt-style {
+ font-size: x-small;
+}
+
+.mt-test {
+ border-left: 10px solid #fff;
+}
+
+.mt-pass {
+ border-left: 10px solid #cfc;
+}
+
+.mt-fail {
+ border-left: 10px solid #fcc;
+}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/test/mode_test.js b/codemirror_ui/lib/CodeMirror-2.3/test/mode_test.js
new file mode 100644
index 0000000..d77ac14
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/test/mode_test.js
@@ -0,0 +1,164 @@
+/**
+ * Helper to test CodeMirror highlighting modes. It pretty prints output of the
+ * highlighter and can check against expected styles.
+ *
+ * See test.html in the stex mode for examples.
+ */
+ModeTest = {};
+
+ModeTest.modeOptions = {};
+ModeTest.modeName = CodeMirror.defaults.mode;
+
+/* keep track of results for printSummary */
+ModeTest.tests = 0;
+ModeTest.passes = 0;
+
+/**
+ * Run a test; prettyprints the results using document.write().
+ *
+ * @param string to highlight
+ *
+ * @param style[i] expected style of the i'th token in string
+ *
+ * @param token[i] expected value for the i'th token in string
+ */
+ModeTest.test = function() {
+ ModeTest.tests += 1;
+
+ var mode = CodeMirror.getMode(ModeTest.modeOptions, ModeTest.modeName);
+
+ if (arguments.length < 1) {
+ throw "must have text for test";
+ }
+ if (arguments.length % 2 != 1) {
+ throw "must have text for test plus expected (style, token) pairs";
+ }
+
+ var text = arguments[0];
+ var expectedOutput = [];
+ for (var i = 1; i < arguments.length; i += 2) {
+ expectedOutput.push([arguments[i],arguments[i + 1]]);
+ }
+
+ var observedOutput = ModeTest.highlight(text, mode)
+
+ var pass, passStyle = "";
+ if (expectedOutput.length > 0) {
+ pass = ModeTest.highlightOutputsEqual(expectedOutput, observedOutput);
+ passStyle = pass ? 'mt-pass' : 'mt-fail';
+ ModeTest.passes += pass ? 1 : 0;
+ }
+
+ var s = '';
+ s += '<div class="mt-test ' + passStyle + '">';
+ s += '<pre>' + ModeTest.htmlEscape(text) + '</pre>';
+ s += '<div class="cm-s-default">';
+ if (pass || expectedOutput.length == 0) {
+ s += ModeTest.prettyPrintOutputTable(observedOutput);
+ } else {
+ s += 'expected:';
+ s += ModeTest.prettyPrintOutputTable(expectedOutput);
+ s += 'observed:';
+ s += ModeTest.prettyPrintOutputTable(observedOutput);
+ }
+ s += '</div>';
+ s += '</div>';
+ document.write(s);
+}
+
+/**
+ * Emulation of CodeMirror's internal highlight routine for testing. Multi-line
+ * input is supported.
+ *
+ * @param string to highlight
+ *
+ * @param mode the mode that will do the actual highlighting
+ *
+ * @return array of [style, token] pairs
+ */
+ModeTest.highlight = function(string, mode) {
+ var state = mode.startState()
+
+ var lines = string.replace(/\r\n/g,'\n').split('\n');
+ var output = [];
+ for (var i = 0; i < lines.length; ++i) {
+ var line = lines[i];
+ var stream = new CodeMirror.StringStream(line);
+ if (line == "" && mode.blankLine) mode.blankLine(state);
+ while (!stream.eol()) {
+ var style = mode.token(stream, state);
+ var substr = line.slice(stream.start, stream.pos);
+ output.push([style, substr]);
+ stream.start = stream.pos;
+ }
+ }
+
+ return output;
+}
+
+/**
+ * Compare two arrays of output from ModeTest.highlight.
+ *
+ * @param o1 array of [style, token] pairs
+ *
+ * @param o2 array of [style, token] pairs
+ *
+ * @return boolean; true iff outputs equal
+ */
+ModeTest.highlightOutputsEqual = function(o1, o2) {
+ var eq = (o1.length == o2.length);
+ if (eq) {
+ for (var j in o1) {
+ eq = eq &&
+ o1[j].length == 2 && o1[j][0] == o2[j][0] && o1[j][1] == o2[j][1];
+ }
+ }
+ return eq;
+}
+
+/**
+ * Print tokens and corresponding styles in a table. Spaces in the token are
+ * replaced with 'interpunct' dots (&middot;).
+ *
+ * @param output array of [style, token] pairs
+ *
+ * @return html string
+ */
+ModeTest.prettyPrintOutputTable = function(output) {
+ var s = '<table class="mt-output">';
+ s += '<tr>';
+ for (var i = 0; i < output.length; ++i) {
+ var token = output[i];
+ s +=
+ '<td class="mt-token">' +
+ '<span class="cm-' + token[0] + '">' +
+ ModeTest.htmlEscape(token[1]).replace(/ /g,'&middot;') +
+ '</span>' +
+ '</td>';
+ }
+ s += '</tr><tr>';
+ for (var i = 0; i < output.length; ++i) {
+ var token = output[i];
+ s +=
+ '<td class="mt-style"><span>' + token[0] + '</span></td>';
+ }
+ s += '</table>';
+ return s;
+}
+
+/**
+ * Print how many tests have run so far and how many of those passed.
+ */
+ModeTest.printSummary = function() {
+ document.write(ModeTest.passes + ' passes for ' + ModeTest.tests + ' tests');
+}
+
+/**
+ * Basic HTML escaping.
+ */
+ModeTest.htmlEscape = function(str) {
+ str = str.toString();
+ return str.replace(/[<&]/g,
+ function(str) {return str == "&" ? "&amp;" : "&lt;";});
+}
+
diff --git a/codemirror_ui/lib/CodeMirror-2.3/test/test.js b/codemirror_ui/lib/CodeMirror-2.3/test/test.js
new file mode 100644
index 0000000..e556156
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/test/test.js
@@ -0,0 +1,344 @@
+var tests = [];
+
+test("fromTextArea", function() {
+ var te = document.getElementById("code");
+ te.value = "CONTENT";
+ var cm = CodeMirror.fromTextArea(te);
+ is(!te.offsetHeight);
+ eq(cm.getValue(), "CONTENT");
+ cm.setValue("foo\nbar");
+ eq(cm.getValue(), "foo\nbar");
+ cm.save();
+ is(/^foo\r?\nbar$/.test(te.value));
+ cm.setValue("xxx");
+ cm.toTextArea();
+ is(te.offsetHeight);
+ eq(te.value, "xxx");
+});
+
+testCM("getRange", function(cm) {
+ eq(cm.getLine(0), "1234");
+ eq(cm.getLine(1), "5678");
+ eq(cm.getLine(2), null);
+ eq(cm.getLine(-1), null);
+ eq(cm.getRange({line: 0, ch: 0}, {line: 0, ch: 3}), "123");
+ eq(cm.getRange({line: 0, ch: -1}, {line: 0, ch: 200}), "1234");
+ eq(cm.getRange({line: 0, ch: 2}, {line: 1, ch: 2}), "34\n56");
+ eq(cm.getRange({line: 1, ch: 2}, {line: 100, ch: 0}), "78");
+}, {value: "1234\n5678"});
+
+testCM("replaceRange", function(cm) {
+ eq(cm.getValue(), "");
+ cm.replaceRange("foo\n", {line: 0, ch: 0});
+ eq(cm.getValue(), "foo\n");
+ cm.replaceRange("a\nb", {line: 0, ch: 1});
+ eq(cm.getValue(), "fa\nboo\n");
+ eq(cm.lineCount(), 3);
+ cm.replaceRange("xyzzy", {line: 0, ch: 0}, {line: 1, ch: 1});
+ eq(cm.getValue(), "xyzzyoo\n");
+ cm.replaceRange("abc", {line: 0, ch: 0}, {line: 10, ch: 0});
+ eq(cm.getValue(), "abc");
+ eq(cm.lineCount(), 1);
+});
+
+testCM("selection", function(cm) {
+ cm.setSelection({line: 0, ch: 4}, {line: 2, ch: 2});
+ is(cm.somethingSelected());
+ eq(cm.getSelection(), "11\n222222\n33");
+ eqPos(cm.getCursor(false), {line: 2, ch: 2});
+ eqPos(cm.getCursor(true), {line: 0, ch: 4});
+ cm.setSelection({line: 1, ch: 0});
+ is(!cm.somethingSelected());
+ eq(cm.getSelection(), "");
+ eqPos(cm.getCursor(true), {line: 1, ch: 0});
+ cm.replaceSelection("abc");
+ eq(cm.getSelection(), "abc");
+ eq(cm.getValue(), "111111\nabc222222\n333333");
+ cm.replaceSelection("def", "end");
+ eq(cm.getSelection(), "");
+ eqPos(cm.getCursor(true), {line: 1, ch: 3});
+ cm.setCursor({line: 2, ch: 1});
+ eqPos(cm.getCursor(true), {line: 2, ch: 1});
+ cm.setCursor(1, 2);
+ eqPos(cm.getCursor(true), {line: 1, ch: 2});
+}, {value: "111111\n222222\n333333"});
+
+testCM("lines", function(cm) {
+ eq(cm.getLine(0), "111111");
+ eq(cm.getLine(1), "222222");
+ eq(cm.getLine(-1), null);
+ cm.removeLine(1);
+ cm.setLine(1, "abc");
+ eq(cm.getValue(), "111111\nabc");
+}, {value: "111111\n222222\n333333"});
+
+testCM("indent", function(cm) {
+ cm.indentLine(1);
+ eq(cm.getLine(1), " blah();");
+ cm.setOption("indentUnit", 8);
+ cm.indentLine(1);
+ eq(cm.getLine(1), "\tblah();");
+}, {value: "if (x) {\nblah();\n}", indentUnit: 3, indentWithTabs: true, tabSize: 8});
+
+test("defaults", function() {
+ var olddefaults = CodeMirror.defaults, defs = CodeMirror.defaults = {};
+ for (var opt in olddefaults) defs[opt] = olddefaults[opt];
+ defs.indentUnit = 5;
+ defs.value = "uu";
+ defs.enterMode = "keep";
+ defs.tabindex = 55;
+ var place = document.getElementById("testground"), cm = CodeMirror(place);
+ try {
+ eq(cm.getOption("indentUnit"), 5);
+ cm.setOption("indentUnit", 10);
+ eq(defs.indentUnit, 5);
+ eq(cm.getValue(), "uu");
+ eq(cm.getOption("enterMode"), "keep");
+ eq(cm.getInputField().tabIndex, 55);
+ }
+ finally {
+ CodeMirror.defaults = olddefaults;
+ place.removeChild(cm.getWrapperElement());
+ }
+});
+
+testCM("lineInfo", function(cm) {
+ eq(cm.lineInfo(-1), null);
+ var lh = cm.setMarker(1, "FOO", "bar");
+ var info = cm.lineInfo(1);
+ eq(info.text, "222222");
+ eq(info.markerText, "FOO");
+ eq(info.markerClass, "bar");
+ eq(info.line, 1);
+ eq(cm.lineInfo(2).markerText, null);
+ cm.clearMarker(lh);
+ eq(cm.lineInfo(1).markerText, null);
+}, {value: "111111\n222222\n333333"});
+
+testCM("coords", function(cm) {
+ var scroller = cm.getScrollerElement();
+ scroller.style.height = "100px";
+ var content = [];
+ for (var i = 0; i < 200; ++i) content.push("------------------------------" + i);
+ cm.setValue(content.join("\n"));
+ var top = cm.charCoords({line: 0, ch: 0});
+ var bot = cm.charCoords({line: 200, ch: 30});
+ is(top.x < bot.x);
+ is(top.y < bot.y);
+ is(top.y < top.yBot);
+ cm.scrollTo(null, 100);
+ var top2 = cm.charCoords({line: 0, ch: 0});
+ is(top.y > top2.y);
+ eq(top.x, top2.x);
+});
+
+testCM("coordsChar", function(cm) {
+ var content = [];
+ for (var i = 0; i < 70; ++i) content.push("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ cm.setValue(content.join("\n"));
+ for (var ch = 0; ch < 35; ch += 2) {
+ for (var line = 0; line < 70; line += 5) {
+ cm.setCursor(line, ch);
+ var coords = cm.charCoords({line: line, ch: ch});
+ var pos = cm.coordsChar({x: coords.x, y: coords.y + 1});
+ eq(pos.line, line);
+ eq(pos.ch, ch);
+ }
+ }
+});
+
+testCM("posFromIndex", function(cm) {
+ cm.setValue(
+ "This function should\n" +
+ "convert a zero based index\n" +
+ "to line and ch."
+ );
+
+ var examples = [
+ { index: -1, line: 0, ch: 0 }, // <- Tests clipping
+ { index: 0, line: 0, ch: 0 },
+ { index: 10, line: 0, ch: 10 },
+ { index: 39, line: 1, ch: 18 },
+ { index: 55, line: 2, ch: 7 },
+ { index: 63, line: 2, ch: 15 },
+ { index: 64, line: 2, ch: 15 } // <- Tests clipping
+ ];
+
+ for (var i = 0; i < examples.length; i++) {
+ var example = examples[i];
+ var pos = cm.posFromIndex(example.index);
+ eq(pos.line, example.line);
+ eq(pos.ch, example.ch);
+ if (example.index >= 0 && example.index < 64)
+ eq(cm.indexFromPos(pos), example.index);
+ }
+});
+
+testCM("undo", function(cm) {
+ cm.setLine(0, "def");
+ eq(cm.historySize().undo, 1);
+ cm.undo();
+ eq(cm.getValue(), "abc");
+ eq(cm.historySize().undo, 0);
+ eq(cm.historySize().redo, 1);
+ cm.redo();
+ eq(cm.getValue(), "def");
+ eq(cm.historySize().undo, 1);
+ eq(cm.historySize().redo, 0);
+ cm.setValue("1\n\n\n2");
+ cm.clearHistory();
+ eq(cm.historySize().undo, 0);
+ for (var i = 0; i < 20; ++i) {
+ cm.replaceRange("a", {line: 0, ch: 0});
+ cm.replaceRange("b", {line: 3, ch: 0});
+ }
+ eq(cm.historySize().undo, 40);
+ for (var i = 0; i < 40; ++i)
+ cm.undo();
+ eq(cm.historySize().redo, 40);
+ eq(cm.getValue(), "1\n\n\n2");
+}, {value: "abc"});
+
+testCM("undoMultiLine", function(cm) {
+ cm.replaceRange("x", {line:0, ch: 0});
+ cm.replaceRange("y", {line:1, ch: 0});
+ cm.undo();
+ eq(cm.getValue(), "abc\ndef\nghi");
+ cm.replaceRange("y", {line:1, ch: 0});
+ cm.replaceRange("x", {line:0, ch: 0});
+ cm.undo();
+ eq(cm.getValue(), "abc\ndef\nghi");
+ cm.replaceRange("y", {line:2, ch: 0});
+ cm.replaceRange("x", {line:1, ch: 0});
+ cm.replaceRange("z", {line:2, ch: 0});
+ cm.undo();
+ eq(cm.getValue(), "abc\ndef\nghi");
+}, {value: "abc\ndef\nghi"});
+
+testCM("markTextSingleLine", function(cm) {
+ forEach([{a: 0, b: 1, c: "", f: 2, t: 5},
+ {a: 0, b: 4, c: "", f: 0, t: 2},
+ {a: 1, b: 2, c: "x", f: 3, t: 6},
+ {a: 4, b: 5, c: "", f: 3, t: 5},
+ {a: 4, b: 5, c: "xx", f: 3, t: 7},
+ {a: 2, b: 5, c: "", f: 2, t: 3},
+ {a: 2, b: 5, c: "abcd", f: 6, t: 7},
+ {a: 2, b: 6, c: "x", f: null, t: null},
+ {a: 3, b: 6, c: "", f: null, t: null},
+ {a: 0, b: 9, c: "hallo", f: null, t: null},
+ {a: 4, b: 6, c: "x", f: 3, t: 4},
+ {a: 4, b: 8, c: "", f: 3, t: 4},
+ {a: 6, b: 6, c: "a", f: 3, t: 6},
+ {a: 8, b: 9, c: "", f: 3, t: 6}], function(test) {
+ cm.setValue("1234567890");
+ var r = cm.markText({line: 0, ch: 3}, {line: 0, ch: 6}, "foo");
+ cm.replaceRange(test.c, {line: 0, ch: test.a}, {line: 0, ch: test.b});
+ var f = r.find();
+ eq(f.from && f.from.ch, test.f); eq(f.to && f.to.ch, test.t);
+ });
+});
+
+testCM("markTextMultiLine", function(cm) {
+ function p(v) { return v && {line: v[0], ch: v[1]}; }
+ forEach([{a: [0, 0], b: [0, 5], c: "", f: [0, 0], t: [2, 5]},
+ {a: [0, 1], b: [0, 10], c: "", f: [0, 1], t: [2, 5]},
+ {a: [0, 5], b: [0, 6], c: "x", f: [0, 6], t: [2, 5]},
+ {a: [0, 0], b: [1, 0], c: "", f: [0, 0], t: [1, 5]},
+ {a: [0, 6], b: [2, 4], c: "", f: [0, 5], t: [0, 7]},
+ {a: [0, 6], b: [2, 4], c: "aa", f: [0, 5], t: [0, 9]},
+ {a: [1, 2], b: [1, 8], c: "", f: [0, 5], t: [2, 5]},
+ {a: [0, 5], b: [2, 5], c: "xx", f: null, t: null},
+ {a: [0, 0], b: [2, 10], c: "x", f: null, t: null},
+ {a: [1, 5], b: [2, 5], c: "", f: [0, 5], t: [1, 5]},
+ {a: [2, 0], b: [2, 3], c: "", f: [0, 5], t: [2, 2]},
+ {a: [2, 5], b: [3, 0], c: "a\nb", f: [0, 5], t: [2, 5]},
+ {a: [2, 3], b: [3, 0], c: "x", f: [0, 5], t: [2, 4]},
+ {a: [1, 1], b: [1, 9], c: "1\n2\n3", f: [0, 5], t: [4, 5]}], function(test) {
+ cm.setValue("aaaaaaaaaa\nbbbbbbbbbb\ncccccccccc\ndddddddd\n");
+ var r = cm.markText({line: 0, ch: 5}, {line: 2, ch: 5}, "foo");
+ cm.replaceRange(test.c, p(test.a), p(test.b));
+ var f = r.find();
+ eqPos(f.from, p(test.f)); eqPos(f.to, p(test.t));
+ });
+});
+
+testCM("bookmark", function(cm) {
+ function p(v) { return v && {line: v[0], ch: v[1]}; }
+ forEach([{a: [1, 0], b: [1, 1], c: "", d: [1, 4]},
+ {a: [1, 1], b: [1, 1], c: "xx", d: [1, 7]},
+ {a: [1, 4], b: [1, 5], c: "ab", d: [1, 6]},
+ {a: [1, 4], b: [1, 6], c: "", d: null},
+ {a: [1, 5], b: [1, 6], c: "abc", d: [1, 5]},
+ {a: [1, 6], b: [1, 8], c: "", d: [1, 5]},
+ {a: [1, 4], b: [1, 4], c: "\n\n", d: [3, 1]},
+ {bm: [1, 9], a: [1, 1], b: [1, 1], c: "\n", d: [2, 8]}], function(test) {
+ cm.setValue("1234567890\n1234567890\n1234567890");
+ var b = cm.setBookmark(p(test.bm) || {line: 1, ch: 5});
+ cm.replaceRange(test.c, p(test.a), p(test.b));
+ eqPos(b.find(), p(test.d));
+ });
+});
+
+testCM("bug577", function(cm) {
+ cm.setValue("a\nb");
+ cm.clearHistory();
+ cm.setValue("fooooo");
+ cm.undo();
+});
+
+// Scaffolding
+
+function htmlEscape(str) {
+ return str.replace(/[<&]/g, function(str) {return str == "&" ? "&amp;" : "&lt;";});
+}
+function forEach(arr, f) {
+ for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
+}
+
+function Failure(why) {this.message = why;}
+
+function test(name, run) {tests.push({name: name, func: run});}
+function testCM(name, run, opts) {
+ test(name, function() {
+ var place = document.getElementById("testground"), cm = CodeMirror(place, opts);
+ try {run(cm);}
+ finally {place.removeChild(cm.getWrapperElement());}
+ });
+}
+
+function runTests() {
+ var failures = [], run = 0;
+ for (var i = 0; i < tests.length; ++i) {
+ var test = tests[i];
+ try {test.func();}
+ catch(e) {
+ if (e instanceof Failure)
+ failures.push({type: "failure", test: test.name, text: e.message});
+ else
+ failures.push({type: "error", test: test.name, text: e.toString()});
+ }
+ run++;
+ }
+ var html = [run + " tests run."];
+ if (failures.length)
+ forEach(failures, function(fail) {
+ html.push(fail.test + ': <span class="' + fail.type + '">' + htmlEscape(fail.text) + "</span>");
+ });
+ else html.push('<span class="ok">All passed.</span>');
+ document.getElementById("output").innerHTML = html.join("\n");
+}
+
+function eq(a, b, msg) {
+ if (a != b) throw new Failure(a + " != " + b + (msg ? " (" + msg + ")" : ""));
+}
+function eqPos(a, b, msg) {
+ if (a == b) return;
+ if (a == null || b == null) throw new Failure("comparing point to null");
+ eq(a.line, b.line, msg);
+ eq(a.ch, b.ch, msg);
+}
+function is(a, msg) {
+ if (!a) throw new Failure("assertion failed" + (msg ? " (" + msg + ")" : ""));
+}
+
+window.onload = runTests;
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/ambiance.css b/codemirror_ui/lib/CodeMirror-2.3/theme/ambiance.css
new file mode 100644
index 0000000..ef5f8d0
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/ambiance.css
@@ -0,0 +1,81 @@
+/* ambiance theme for code-mirror */
+
+/* Color scheme */
+
+.cm-s-ambiance .cm-keyword { color: #cda869; }
+.cm-s-ambiance .cm-atom { color: #CF7EA9; }
+.cm-s-ambiance .cm-number { color: #78CF8A; }
+.cm-s-ambiance .cm-def { color: #aac6e3; }
+.cm-s-ambiance .cm-variable { color: #ffb795; }
+.cm-s-ambiance .cm-variable-2 { color: #eed1b3; }
+.cm-s-ambiance .cm-variable-3 { color: #faded3; }
+.cm-s-ambiance .cm-property { color: #eed1b3; }
+.cm-s-ambiance .cm-operator {color: #fa8d6a;}
+.cm-s-ambiance .cm-comment { color: #555; font-style:italic; }
+.cm-s-ambiance .cm-string { color: #8f9d6a; }
+.cm-s-ambiance .cm-string-2 { color: #9d937c; }
+.cm-s-ambiance .cm-meta { color: #D2A8A1; }
+.cm-s-ambiance .cm-error { color: #AF2018; }
+.cm-s-ambiance .cm-qualifier { color: yellow; }
+.cm-s-ambiance .cm-builtin { color: #9999cc; }
+.cm-s-ambiance .cm-bracket { color: #24C2C7; }
+.cm-s-ambiance .cm-tag { color: #fee4ff }
+.cm-s-ambiance .cm-attribute { color: #9B859D; }
+.cm-s-ambiance .cm-header {color: blue;}
+.cm-s-ambiance .cm-quote { color: #24C2C7; }
+.cm-s-ambiance .cm-hr { color: pink; }
+.cm-s-ambiance .cm-link { color: #F4C20B; }
+.cm-s-ambiance .cm-special { color: #FF9D00; }
+
+.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; }
+.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; }
+
+.cm-s-ambiance .CodeMirror-selected {
+ background: rgba(255, 255, 255, 0.15);
+}
+.CodeMirror-focused .cm-s-ambiance .CodeMirror-selected {
+ background: rgba(255, 255, 255, 0.10);
+}
+
+/* Editor styling */
+
+.cm-s-ambiance {
+ line-height: 1.40em;
+ font-family: Monaco, Menlo,"Andale Mono","lucida console","Courier New",monospace !important;
+ color: #E6E1DC;
+ background-color: #202020;
+ -webkit-box-shadow: inset 0 0 10px black;
+ -moz-box-shadow: inset 0 0 10px black;
+ -o-box-shadow: inset 0 0 10px black;
+ box-shadow: inset 0 0 10px black;
+}
+
+.cm-s-ambiance .CodeMirror-gutter {
+ background: #3D3D3D;
+ padding: 0 5px;
+ text-shadow: #333 1px 1px;
+ border-right: 1px solid #4D4D4D;
+ box-shadow: 0 10px 20px black;
+}
+
+.cm-s-ambiance .CodeMirror-gutter .CodeMirror-gutter-text {
+ text-shadow: 0px 1px 1px #4d4d4d;
+ color: #222;
+}
+
+.cm-s-ambiance .CodeMirror-lines {
+
+}
+
+.cm-s-ambiance .CodeMirror-lines .CodeMirror-cursor {
+ border-left: 1px solid #7991E8;
+}
+
+.cm-s-ambiance .activeline {
+ background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031);
+}
+
+.cm-s-ambiance,
+.cm-s-ambiance .CodeMirror-gutter {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC");
+}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/blackboard.css b/codemirror_ui/lib/CodeMirror-2.3/theme/blackboard.css
new file mode 100644
index 0000000..7b73a92
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/blackboard.css
@@ -0,0 +1,25 @@
+/* Port of TextMate's Blackboard theme */
+
+.cm-s-blackboard { background: #0C1021; color: #F8F8F8; }
+.cm-s-blackboard .CodeMirror-selected { background: #253B76 !important; }
+.cm-s-blackboard .CodeMirror-gutter { background: #0C1021; border-right: 0; }
+.cm-s-blackboard .CodeMirror-gutter-text { color: #888; }
+.cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; }
+
+.cm-s-blackboard .cm-keyword { color: #FBDE2D; }
+.cm-s-blackboard .cm-atom { color: #D8FA3C; }
+.cm-s-blackboard .cm-number { color: #D8FA3C; }
+.cm-s-blackboard .cm-def { color: #8DA6CE; }
+.cm-s-blackboard .cm-variable { color: #FF6400; }
+.cm-s-blackboard .cm-operator { color: #FBDE2D;}
+.cm-s-blackboard .cm-comment { color: #AEAEAE; }
+.cm-s-blackboard .cm-string { color: #61CE3C; }
+.cm-s-blackboard .cm-string-2 { color: #61CE3C; }
+.cm-s-blackboard .cm-meta { color: #D8FA3C; }
+.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }
+.cm-s-blackboard .cm-builtin { color: #8DA6CE; }
+.cm-s-blackboard .cm-tag { color: #8DA6CE; }
+.cm-s-blackboard .cm-attribute { color: #8DA6CE; }
+.cm-s-blackboard .cm-header { color: #FF6400; }
+.cm-s-blackboard .cm-hr { color: #AEAEAE; }
+.cm-s-blackboard .cm-link { color: #8DA6CE; }
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/cobalt.css b/codemirror_ui/lib/CodeMirror-2.3/theme/cobalt.css
new file mode 100644
index 0000000..dbbb7e4
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/cobalt.css
@@ -0,0 +1,18 @@
+.cm-s-cobalt { background: #002240; color: white; }
+.cm-s-cobalt div.CodeMirror-selected { background: #b36539 !important; }
+.cm-s-cobalt .CodeMirror-gutter { background: #002240; border-right: 1px solid #aaa; }
+.cm-s-cobalt .CodeMirror-gutter-text { color: #d0d0d0; }
+.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white !important; }
+
+.cm-s-cobalt span.cm-comment { color: #08f; }
+.cm-s-cobalt span.cm-atom { color: #845dc4; }
+.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; }
+.cm-s-cobalt span.cm-keyword { color: #ffee80; }
+.cm-s-cobalt span.cm-string { color: #3ad900; }
+.cm-s-cobalt span.cm-meta { color: #ff9d00; }
+.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }
+.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; }
+.cm-s-cobalt span.cm-error { color: #9d1e15; }
+.cm-s-cobalt span.cm-bracket { color: #d8d8d8; }
+.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }
+.cm-s-cobalt span.cm-link { color: #845dc4; }
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/eclipse.css b/codemirror_ui/lib/CodeMirror-2.3/theme/eclipse.css
new file mode 100644
index 0000000..47d66a0
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/eclipse.css
@@ -0,0 +1,25 @@
+.cm-s-eclipse span.cm-meta {color: #FF1717;}
+.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }
+.cm-s-eclipse span.cm-atom {color: #219;}
+.cm-s-eclipse span.cm-number {color: #164;}
+.cm-s-eclipse span.cm-def {color: #00f;}
+.cm-s-eclipse span.cm-variable {color: black;}
+.cm-s-eclipse span.cm-variable-2 {color: #0000C0;}
+.cm-s-eclipse span.cm-variable-3 {color: #0000C0;}
+.cm-s-eclipse span.cm-property {color: black;}
+.cm-s-eclipse span.cm-operator {color: black;}
+.cm-s-eclipse span.cm-comment {color: #3F7F5F;}
+.cm-s-eclipse span.cm-string {color: #2A00FF;}
+.cm-s-eclipse span.cm-string-2 {color: #f50;}
+.cm-s-eclipse span.cm-error {color: #f00;}
+.cm-s-eclipse span.cm-qualifier {color: #555;}
+.cm-s-eclipse span.cm-builtin {color: #30a;}
+.cm-s-eclipse span.cm-bracket {color: #cc7;}
+.cm-s-eclipse span.cm-tag {color: #170;}
+.cm-s-eclipse span.cm-attribute {color: #00c;}
+.cm-s-eclipse span.cm-link {color: #219;}
+
+.cm-s-eclipse .CodeMirror-matchingbracket {
+ border:1px solid grey;
+ color:black !important;;
+}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/elegant.css b/codemirror_ui/lib/CodeMirror-2.3/theme/elegant.css
new file mode 100644
index 0000000..d0ce0cb
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/elegant.css
@@ -0,0 +1,10 @@
+.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;}
+.cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;}
+.cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;}
+.cm-s-elegant span.cm-variable {color: black;}
+.cm-s-elegant span.cm-variable-2 {color: #b11;}
+.cm-s-elegant span.cm-qualifier {color: #555;}
+.cm-s-elegant span.cm-keyword {color: #730;}
+.cm-s-elegant span.cm-builtin {color: #30a;}
+.cm-s-elegant span.cm-error {background-color: #fdd;}
+.cm-s-elegant span.cm-link {color: #762;}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/erlang-dark.css b/codemirror_ui/lib/CodeMirror-2.3/theme/erlang-dark.css
new file mode 100644
index 0000000..486b1c4
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/erlang-dark.css
@@ -0,0 +1,21 @@
+.cm-s-erlang-dark { background: #002240; color: white; }
+.cm-s-erlang-dark div.CodeMirror-selected { background: #b36539 !important; }
+.cm-s-erlang-dark .CodeMirror-gutter { background: #002240; border-right: 1px solid #aaa; }
+.cm-s-erlang-dark .CodeMirror-gutter-text { color: #d0d0d0; }
+.cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
+
+.cm-s-erlang-dark span.cm-atom { color: #845dc4; }
+.cm-s-erlang-dark span.cm-attribute { color: #ff80e1; }
+.cm-s-erlang-dark span.cm-bracket { color: #ff9d00; }
+.cm-s-erlang-dark span.cm-builtin { color: #eeaaaa; }
+.cm-s-erlang-dark span.cm-comment { color: #7777ff; }
+.cm-s-erlang-dark span.cm-def { color: #ee77aa; }
+.cm-s-erlang-dark span.cm-error { color: #9d1e15; }
+.cm-s-erlang-dark span.cm-keyword { color: #ffee80; }
+.cm-s-erlang-dark span.cm-meta { color: #50fefe; }
+.cm-s-erlang-dark span.cm-number { color: #ffd0d0; }
+.cm-s-erlang-dark span.cm-operator { color: #dd1111; }
+.cm-s-erlang-dark span.cm-string { color: #3ad900; }
+.cm-s-erlang-dark span.cm-tag { color: #9effff; }
+.cm-s-erlang-dark span.cm-variable { color: #50fe50; }
+.cm-s-erlang-dark span.cm-variable-2 { color: #ee00ee; }
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/lesser-dark.css b/codemirror_ui/lib/CodeMirror-2.3/theme/lesser-dark.css
new file mode 100644
index 0000000..ffa6a3f
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/lesser-dark.css
@@ -0,0 +1,44 @@
+/*
+http://lesscss.org/ dark theme
+Ported to CodeMirror by Peter Kroon
+*/
+.cm-s-lesser-dark {
+ line-height: 1.3em;
+}
+.cm-s-lesser-dark {
+ font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Monaco', Courier, monospace !important;
+}
+
+.cm-s-lesser-dark { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }
+.cm-s-lesser-dark div.CodeMirror-selected {background: #45443B !important;} /* 33322B*/
+.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
+.cm-s-lesser-dark .CodeMirror-lines { margin-left:3px; margin-right:3px; }/*editable code holder*/
+
+div.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/
+
+.cm-s-lesser-dark .CodeMirror-gutter { background: #262626; border-right:1px solid #aaa; padding-right:3px; min-width:2.5em; }
+.cm-s-lesser-dark .CodeMirror-gutter-text { color: #777; }
+
+.cm-s-lesser-dark span.cm-keyword { color: #599eff; }
+.cm-s-lesser-dark span.cm-atom { color: #C2B470; }
+.cm-s-lesser-dark span.cm-number { color: #B35E4D; }
+.cm-s-lesser-dark span.cm-def {color: white;}
+.cm-s-lesser-dark span.cm-variable { color:#D9BF8C; }
+.cm-s-lesser-dark span.cm-variable-2 { color: #669199; }
+.cm-s-lesser-dark span.cm-variable-3 { color: white; }
+.cm-s-lesser-dark span.cm-property {color: #92A75C;}
+.cm-s-lesser-dark span.cm-operator {color: #92A75C;}
+.cm-s-lesser-dark span.cm-comment { color: #666; }
+.cm-s-lesser-dark span.cm-string { color: #BCD279; }
+.cm-s-lesser-dark span.cm-string-2 {color: #f50;}
+.cm-s-lesser-dark span.cm-meta { color: #738C73; }
+.cm-s-lesser-dark span.cm-error { color: #9d1e15; }
+.cm-s-lesser-dark span.cm-qualifier {color: #555;}
+.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; }
+.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; }
+.cm-s-lesser-dark span.cm-tag { color: #669199; }
+.cm-s-lesser-dark span.cm-attribute {color: #00c;}
+.cm-s-lesser-dark span.cm-header {color: #a0a;}
+.cm-s-lesser-dark span.cm-quote {color: #090;}
+.cm-s-lesser-dark span.cm-hr {color: #999;}
+.cm-s-lesser-dark span.cm-link {color: #00c;}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/monokai.css b/codemirror_ui/lib/CodeMirror-2.3/theme/monokai.css
new file mode 100644
index 0000000..f01d066
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/monokai.css
@@ -0,0 +1,28 @@
+/* Based on Sublime Text's Monokai theme */
+
+.cm-s-monokai {background: #272822; color: #f8f8f2;}
+.cm-s-monokai div.CodeMirror-selected {background: #49483E !important;}
+.cm-s-monokai .CodeMirror-gutter {background: #272822; border-right: 0px;}
+.cm-s-monokai .CodeMirror-gutter-text {color: #d0d0d0;}
+.cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;}
+
+.cm-s-monokai span.cm-comment {color: #75715e;}
+.cm-s-monokai span.cm-atom {color: #ae81ff;}
+.cm-s-monokai span.cm-number {color: #ae81ff;}
+
+.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;}
+.cm-s-monokai span.cm-keyword {color: #f92672;}
+.cm-s-monokai span.cm-string {color: #e6db74;}
+
+.cm-s-monokai span.cm-variable {color: #a6e22e;}
+.cm-s-monokai span.cm-variable-2 {color: #9effff;}
+.cm-s-monokai span.cm-def {color: #fd971f;}
+.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}
+.cm-s-monokai span.cm-bracket {color: #f8f8f2;}
+.cm-s-monokai span.cm-tag {color: #f92672;}
+.cm-s-monokai span.cm-link {color: #ae81ff;}
+
+.cm-s-monokai .CodeMirror-matchingbracket {
+ text-decoration: underline;
+ color: white !important;
+}
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/neat.css b/codemirror_ui/lib/CodeMirror-2.3/theme/neat.css
new file mode 100644
index 0000000..8a307f8
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/neat.css
@@ -0,0 +1,9 @@
+.cm-s-neat span.cm-comment { color: #a86; }
+.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; }
+.cm-s-neat span.cm-string { color: #a22; }
+.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }
+.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }
+.cm-s-neat span.cm-variable { color: black; }
+.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }
+.cm-s-neat span.cm-meta {color: #555;}
+.cm-s-neat span.cm-link { color: #3a3; }
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/night.css b/codemirror_ui/lib/CodeMirror-2.3/theme/night.css
new file mode 100644
index 0000000..9d51d95
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/night.css
@@ -0,0 +1,21 @@
+/* Loosely based on the Midnight Textmate theme */
+
+.cm-s-night { background: #0a001f; color: #f8f8f8; }
+.cm-s-night div.CodeMirror-selected { background: #447 !important; }
+.cm-s-night .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
+.cm-s-night .CodeMirror-gutter-text { color: #f8f8f8; }
+.cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; }
+
+.cm-s-night span.cm-comment { color: #6900a1; }
+.cm-s-night span.cm-atom { color: #845dc4; }
+.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }
+.cm-s-night span.cm-keyword { color: #599eff; }
+.cm-s-night span.cm-string { color: #37f14a; }
+.cm-s-night span.cm-meta { color: #7678e2; }
+.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
+.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }
+.cm-s-night span.cm-error { color: #9d1e15; }
+.cm-s-night span.cm-bracket { color: #8da6ce; }
+.cm-s-night span.cm-comment { color: #6900a1; }
+.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
+.cm-s-night span.cm-link { color: #845dc4; }
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/rubyblue.css b/codemirror_ui/lib/CodeMirror-2.3/theme/rubyblue.css
new file mode 100644
index 0000000..502817a
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/rubyblue.css
@@ -0,0 +1,21 @@
+.cm-s-rubyblue { font:13px/1.4em Trebuchet, Verdana, sans-serif; } /* - customized editor font - */
+
+.cm-s-rubyblue { background: #112435; color: white; }
+.cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; }
+.cm-s-rubyblue .CodeMirror-gutter { background: #1F4661; border-right: 7px solid #3E7087; min-width:2.5em; }
+.cm-s-rubyblue .CodeMirror-gutter-text { color: white; }
+.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white !important; }
+
+.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; }
+.cm-s-rubyblue span.cm-atom { color: #F4C20B; }
+.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; }
+.cm-s-rubyblue span.cm-keyword { color: #F0F; }
+.cm-s-rubyblue span.cm-string { color: #F08047; }
+.cm-s-rubyblue span.cm-meta { color: #F0F; }
+.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }
+.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; }
+.cm-s-rubyblue span.cm-error { color: #AF2018; }
+.cm-s-rubyblue span.cm-bracket { color: #F0F; }
+.cm-s-rubyblue span.cm-link { color: #F4C20B; }
+.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; }
+.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; }
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/vibrant-ink.css b/codemirror_ui/lib/CodeMirror-2.3/theme/vibrant-ink.css
new file mode 100644
index 0000000..e025e50
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/vibrant-ink.css
@@ -0,0 +1,27 @@
+/* Taken from the popular Visual Studio Vibrant Ink Schema */
+
+.cm-s-vibrant-ink { background: black; color: white; }
+.cm-s-vibrant-ink .CodeMirror-selected { background: #35493c !important; }
+
+.cm-s-vibrant-ink .CodeMirror-gutter { background: #002240; border-right: 1px solid #aaa; }
+.cm-s-vibrant-ink .CodeMirror-gutter-text { color: #d0d0d0; }
+.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white !important; }
+
+.cm-s-vibrant-ink .cm-keyword { color: #CC7832; }
+.cm-s-vibrant-ink .cm-atom { color: #FC0; }
+.cm-s-vibrant-ink .cm-number { color: #FFEE98; }
+.cm-s-vibrant-ink .cm-def { color: #8DA6CE; }
+.cm-s-vibrant-ink span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #FFC66D }
+.cm-s-vibrant-ink span.cm-variable-3, .cm-s-cobalt span.cm-def { color: #FFC66D }
+.cm-s-vibrant-ink .cm-operator { color: #888; }
+.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; }
+.cm-s-vibrant-ink .cm-string { color: #A5C25C }
+.cm-s-vibrant-ink .cm-string-2 { color: red }
+.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; }
+.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }
+.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; }
+.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; }
+.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; }
+.cm-s-vibrant-ink .cm-header { color: #FF6400; }
+.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; }
+.cm-s-vibrant-ink .cm-link { color: blue; }
diff --git a/codemirror_ui/lib/CodeMirror-2.3/theme/xq-dark.css b/codemirror_ui/lib/CodeMirror-2.3/theme/xq-dark.css
new file mode 100644
index 0000000..493e3a6
--- /dev/null
+++ b/codemirror_ui/lib/CodeMirror-2.3/theme/xq-dark.css
@@ -0,0 +1,46 @@
+/*
+Copyright (C) 2011 by MarkLogic Corporation
+Author: Mike Brevoort <mike@brevoort.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+.cm-s-xq-dark { background: #0a001f; color: #f8f8f8; }
+.cm-s-xq-dark span.CodeMirror-selected { background: #a8f !important; }
+.cm-s-xq-dark .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
+.cm-s-xq-dark .CodeMirror-gutter-text { color: #f8f8f8; }
+.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
+
+.cm-s-xq-dark span.cm-keyword {color: #FFBD40;}
+.cm-s-xq-dark span.cm-atom {color: #6C8CD5;}
+.cm-s-xq-dark span.cm-number {color: #164;}
+.cm-s-xq-dark span.cm-def {color: #FFF; text-decoration:underline;}
+.cm-s-xq-dark span.cm-variable {color: #FFF;}
+.cm-s-xq-dark span.cm-variable-2 {color: #EEE;}
+.cm-s-xq-dark span.cm-variable-3 {color: #DDD;}
+.cm-s-xq-dark span.cm-property {}
+.cm-s-xq-dark span.cm-operator {}
+.cm-s-xq-dark span.cm-comment {color: gray;}
+.cm-s-xq-dark span.cm-string {color: #9FEE00;}
+.cm-s-xq-dark span.cm-meta {color: yellow;}
+.cm-s-xq-dark span.cm-error {color: #f00;}
+.cm-s-xq-dark span.cm-qualifier {color: #FFF700;}
+.cm-s-xq-dark span.cm-builtin {color: #30a;}
+.cm-s-xq-dark span.cm-bracket {color: #cc7;}
+.cm-s-xq-dark span.cm-tag {color: #FFBD40;}
+.cm-s-xq-dark span.cm-attribute {color: #FFF700;}
diff --git a/codemirror_ui/localization/cs_CZ.inc b/codemirror_ui/localization/cs_CZ.inc
new file mode 100644
index 0000000..1379cd9
--- /dev/null
+++ b/codemirror_ui/localization/cs_CZ.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/codemirror_ui/localization/cs_CZ.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2014, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: tachec - 04/10/2014 10:50:18
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Pomocný doplněk pro editaci kódu';
+$labels['plugindescription'] = 'Jednoduchý doplněk pro editaci kódu.';
+
+?> \ No newline at end of file
diff --git a/codemirror_ui/localization/da_DK.inc b/codemirror_ui/localization/da_DK.inc
new file mode 100644
index 0000000..8d6b7b3
--- /dev/null
+++ b/codemirror_ui/localization/da_DK.inc
@@ -0,0 +1,20 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| language/da_DK/labels.inc |
+| |
+| Language file of the RoundCube Webmail client |
+| Copyright (C) 2008-2012, RoundQube Dev. - Switzerland |
+| |
++-----------------------------------------------------------------------+
+| Author: |
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Hjælper modul til kode redigering';
+$labels['plugindescription'] = 'Et letvægts hjælper modul til kode redigering';
+
+?> \ No newline at end of file
diff --git a/codemirror_ui/localization/de_DE.inc b/codemirror_ui/localization/de_DE.inc
new file mode 100644
index 0000000..1b4d578
--- /dev/null
+++ b/codemirror_ui/localization/de_DE.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/codemirror_ui/localization/de_DE.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: myroundcube@mail4us.net - 08/19/2013 18:34:10
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Hilfserweiterung zum editieren von Code';
+$labels['plugindescription'] = 'Hilfserweiterung zum editieren von Code';
+
+?> \ No newline at end of file
diff --git a/codemirror_ui/localization/en_US.inc b/codemirror_ui/localization/en_US.inc
new file mode 100644
index 0000000..89430d7
--- /dev/null
+++ b/codemirror_ui/localization/en_US.inc
@@ -0,0 +1,5 @@
+<?php
+$labels = array();
+$labels['pluginname'] = 'Helper plugin for code editing';
+$labels['plugindescription'] = 'A lightweight helper plugin for code editing.';
+?> \ No newline at end of file
diff --git a/codemirror_ui/localization/es_ES.inc b/codemirror_ui/localization/es_ES.inc
new file mode 100644
index 0000000..ddd41f1
--- /dev/null
+++ b/codemirror_ui/localization/es_ES.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/codemirror_ui/localization/es_ES.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 10/11/2013 12:11:44
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Complemento auxiliar para la edición de código';
+$labels['plugindescription'] = 'Un complemento auxiliar ligero para la edición de código.';
+
+?> \ No newline at end of file
diff --git a/codemirror_ui/localization/fi_FI.inc b/codemirror_ui/localization/fi_FI.inc
new file mode 100644
index 0000000..36d9ec8
--- /dev/null
+++ b/codemirror_ui/localization/fi_FI.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/codemirror_ui/localization/fi_FI.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Markku Virtanen - 01/12/2015 08:27:32
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Helperlisäosa koodin muokkaamiseen';
+$labels['plugindescription'] = 'Kevyt helper lisäosa koodin muokkaukseen';
+
+?> \ No newline at end of file
diff --git a/codemirror_ui/localization/pl_PL.inc b/codemirror_ui/localization/pl_PL.inc
new file mode 100644
index 0000000..593e1e6
--- /dev/null
+++ b/codemirror_ui/localization/pl_PL.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/codemirror_ui/localization/pl_PL.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Tomasz - 07/28/2013 20:46:46
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Wtyczka wspomagająca edycję kodu';
+$labels['plugindescription'] = 'Lekka wtyczka wspomagająca edycję kodu.';
+
+?> \ No newline at end of file
diff --git a/codemirror_ui/localization/revision.inc.php b/codemirror_ui/localization/revision.inc.php
new file mode 100644
index 0000000..d6e3d35
--- /dev/null
+++ b/codemirror_ui/localization/revision.inc.php
@@ -0,0 +1,11 @@
+<?php
+
+$ps_localization_update = serialize(
+ array(
+ 'translator' => 'Markku Virtanen',
+ 'language ' => 'fi_FI',
+ 'date' => '01/12/2015 08:27:32'
+ )
+);
+
+?> \ No newline at end of file
diff --git a/codemirror_ui/package.xml b/codemirror_ui/package.xml
new file mode 100644
index 0000000..924dc55
--- /dev/null
+++ b/codemirror_ui/package.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+ http://pear.php.net/dtd/tasks-1.0.xsd
+ http://pear.php.net/dtd/package-2.0
+ http://pear.php.net/dtd/package-2.0.xsd">
+ <name>codemirror_ui</name>
+ <lead>
+ <name>Myroundcube Dev Team</name>
+ <user>rosali</user>
+ <email>dev-team@myroundcube.com</email>
+ <active>yes</active>
+ </lead><date>2014-05-08</date>
+ <version>
+ <release>1.0.5</release>
+ <api>1.0.5</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.gnu.org/licenses/gpl.html">GNU GPLv3+</license>
+</package>
diff --git a/compose_addressbook b/compose_addressbook
new file mode 160000
+Subproject 165c5c8ebcc8c67c81369356d1c860b37ae1ae1
diff --git a/contextmenu b/contextmenu
new file mode 160000
+Subproject 7f47e85b5000d971b6cbda18d60464d44eaccc9
diff --git a/db_config/CHANGELOG b/db_config/CHANGELOG
new file mode 100644
index 0000000..73178d9
--- /dev/null
+++ b/db_config/CHANGELOG
@@ -0,0 +1,19 @@
+VERSION COMMENT
+-----------------------------------------------------------------------------------------------------------------
+1.0 - Initial release
+1.1 - Be ready for Roundcube 1.0
+1.1.1 - Skip plugins where config is loaded in plugin's init method
+1.1.2 - 1.1.4 - Added sort order for Account administration section
+1.1.5 - Database collation utf8_general_ci
+1.1.6 - Skip companyaddressbook (see 1.1.1)
+1.1.7 - Implemented mysqladmin
+1.1.8 - Roundcube 1.0 compatibility
+1.1.9 - 1.1.10 - Code cleanup
+1.1.11 - Skip 'idle_timeout' plugin (config is loaded directly there)
+1.1.12 - Revert 1.1.11
+1.1.13 - Added MSSQL support (third party contribution (https://asphostpage.com/)
+1.1.14 - Implement rcube_db::limitquery
+1.1.15 - 1.1.17 - Make sure that MySQL database fields collation is UTF-8
+ https://code.google.com/p/myroundcube/issues/detail?id=747
+1.1.18 - Load calendar configuration in calendar plugin
+1.1.19 - Revert 1.1.18 \ No newline at end of file
diff --git a/db_config/LICENSE b/db_config/LICENSE
new file mode 100644
index 0000000..e0d8242
--- /dev/null
+++ b/db_config/LICENSE
@@ -0,0 +1,71 @@
+TERMS AND CONDITIONS
+--------------------
+
+User Agreement
+
+MyRoundcube Developers provides MyRoundcube Plugins (code) shall provide ("MyRoundcube Plugins") to
+you ("User") under the terms and conditions of this User Agreement ("the Agreement"). USER UNDERSTANDS
+AND ACKNOWLEDGES THAT USER IS ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers AND NOT THE WEB
+SITE WITH WHOM ANYTHING HAS ASSOCIATED TO BRING YOU THIS CODE. BY USING ("MyRoundcube Plugins") OR ANY
+PART OF ITS CODE YOU ARE AGREEING TO BECOME A PARTY TO THIS AGREEMENT WITH MyRoundcube Developers AND
+TO THE TERMS AND CONDITIONS HEREIN AND ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND ANY APPLICABLE
+ASSOCIATE STATEMENT IN THIS DOCUMENT. ALL MyRoundcube Developers SERVICES ARE PROVIDED ONLINE. PERSONS
+UNDER 13 MAY NOT BE ELEGIBLE TO ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers OR PURCHASE OUR
+SERVICES AND CODE DOWNLOADS.
+
+Acceptable Use Policy
+
+The following policy governs the use of the MyRoundcube Developers code. User will comply with the terms
+and spirit of the Agreement.
+
+(a) User shall not use MyRoundcube Plugins (code) in a manner that violates any city, state, national
+or international law or regulation, or which fails to comply with accepted Internet protocol. User
+shall not attempt to interfere in any way with MyRoundcube Plugins networks or network security, or
+attempt to use the MyRoundcube Plugins code to gain unauthorized access to any other computer system.
+(b) User shall at all times provide MyRoundcube Developers with accurate information. User shall not
+interfere in any way with another User's use of, or MyRoundcube Developers provision of the MyRoundcube
+Plugins. User shall not resell, rent, lease, grant a security interest in, or make commercial use of
+the MyRoundcube Plugins without the express written consent of MyRoundcube Developers.
+(c) User agrees not to transfer MyRoundcube Plugins (code) for gain or otherwise. Transfer of such code
+will result in termination of contract with end user.
+
+Limitation of Liability
+
+UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, TORT, CONTRACT, OR OTHERWISE, SHALL MyRoundcube
+Developers OR ITS LICENSORS OR RESELLERS BE LIABLE TO USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL,
+INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES RESULTING
+FROM THE USE OF OR THE INABILITY TO USE THE MyRoundcube Plugins (code), THE PERFORMANCE OF MyRoundcube
+Plugins (code) SERVICE, OR DAMAGES FOR LOSS OF GOODWILL, BUSINESS PROFIT, BUSINESS STOPPAGE, LOSS OF
+DATA OR BUSINESS INFORMATION, COMPUTER DAMAGE, OR DAMAGES RESULTING FROM UNAUTHORIZED ACCESS TO OR
+CHANGES MADE TO USER'S TRANSMISSIONS OR DATA, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES.
+IN NO EVENT WILL MyRoundcube Developers BE LIABLE FOR ANY DAMAGES IN EXCESS OF WHAT ANYTHING MyRoundcube
+Developers RECEIVED FROM USER FOR THE MyRoundcube Plugins (code).
+
+Terms
+
+You (the User) are permitted to use the code on unlimited servers you may own, rented or leased, as
+long as you own, rent or lease the server in which MyRoundcube plugins code is hosted.
+Exclusive: You (the User) agree to use the code in one server at a time. Multiple server deployments
+(multiserver setup), clusters or any other form of deployment that simultaneously executes MyRoundcube
+plugins in a live environment must purchase a separate download per server or installation thereof.
+
+Warranties
+
+Our code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+Terms Modifications
+
+We reserve the right to change or modify our Terms and Conditions at any time without prior notice.
+For questions, please contact our team at dev-team [at] myroundcube [dot] com.
+
+Copyright (c) 2012 - 2015
+MyRoundcube.com - A Division of Informative Computing Consultants, LLC.
+All rights reserved
+
+Informative Computing Consultants, LLC.
+21741 NW 8th CT
+Pembroke Pines
+Florida, 33029
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
diff --git a/db_config/README b/db_config/README
new file mode 100644
index 0000000..cecda6b
--- /dev/null
+++ b/db_config/README
@@ -0,0 +1,8 @@
+db_config
+---------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/db_config-plugin
+
+
+MyRoundcube Dev Team
+www.myroundcube.com \ No newline at end of file
diff --git a/db_config/SQL/mssql.20131110.sql b/db_config/SQL/mssql.20131110.sql
new file mode 100644
index 0000000..eb35e62
--- /dev/null
+++ b/db_config/SQL/mssql.20131110.sql
@@ -0,0 +1,2 @@
+UPDATE [system] SET [value]='initial|20131110' WHERE [name]='myrc_db_config'
+GO
diff --git a/db_config/SQL/mssql.20141115.sql b/db_config/SQL/mssql.20141115.sql
new file mode 100644
index 0000000..0819c6e
--- /dev/null
+++ b/db_config/SQL/mssql.20141115.sql
@@ -0,0 +1,2 @@
+UPDATE [system] SET [value]='initial|20131110|20141115' WHERE [name]='myrc_db_config'
+GO
diff --git a/db_config/SQL/mssql.initial.sql b/db_config/SQL/mssql.initial.sql
new file mode 100644
index 0000000..1e806b0
--- /dev/null
+++ b/db_config/SQL/mssql.initial.sql
@@ -0,0 +1,12 @@
+IF NOT EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'[dbo].[db_config]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
+CREATE TABLE [db_config] (
+ [id] int NOT NULL IDENTITY(1,1),
+ [env] nvarchar(255) NOT NULL,
+ [conf] nvarchar(MAX) NOT NULL,
+ [admin] nvarchar(128) NOT NULL,
+ PRIMARY KEY ([id])
+)
+GO
+
+INSERT INTO [system] (name, value) VALUES ('myrc_db_config', 'initial')
+GO
diff --git a/db_config/SQL/mysql.20131110.sql b/db_config/SQL/mysql.20131110.sql
new file mode 100644
index 0000000..e0a4247
--- /dev/null
+++ b/db_config/SQL/mysql.20131110.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `db_config` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
+UPDATE `system` SET `value`='initial|20131110' WHERE `name`='myrc_db_config'; \ No newline at end of file
diff --git a/db_config/SQL/mysql.20141115.sql b/db_config/SQL/mysql.20141115.sql
new file mode 100644
index 0000000..57e1605
--- /dev/null
+++ b/db_config/SQL/mysql.20141115.sql
@@ -0,0 +1,4 @@
+ALTER TABLE `db_config` CHANGE `env` `env` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
+ALTER TABLE `db_config` CHANGE `conf` `conf` LONGTEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
+ALTER TABLE `db_config` CHANGE `admin` `admin` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
+UPDATE `system` SET `value`='initial|20131110|20141115' WHERE `name`='myrc_db_config'; \ No newline at end of file
diff --git a/db_config/SQL/mysql.initial.sql b/db_config/SQL/mysql.initial.sql
new file mode 100644
index 0000000..6d02e7c
--- /dev/null
+++ b/db_config/SQL/mysql.initial.sql
@@ -0,0 +1,15 @@
+CREATE TABLE IF NOT EXISTS `db_config` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `env` varchar(255) NOT NULL,
+ `conf` longtext NOT NULL,
+ `admin` varchar(128) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+CREATE TABLE IF NOT EXISTS `system` (
+ `name` varchar(64) NOT NULL,
+ `value` mediumtext,
+ PRIMARY KEY(`name`)
+);
+
+INSERT INTO `system` (name, value) VALUES ('myrc_db_config', 'initial'); \ No newline at end of file
diff --git a/db_config/SQL/pgsql.20131110.sql b/db_config/SQL/pgsql.20131110.sql
new file mode 100644
index 0000000..e5d0335
--- /dev/null
+++ b/db_config/SQL/pgsql.20131110.sql
@@ -0,0 +1 @@
+UPDATE "system" SET value='initial|20131110' WHERE name='myrc_db_config'; \ No newline at end of file
diff --git a/db_config/SQL/pgsql.20141115.sql b/db_config/SQL/pgsql.20141115.sql
new file mode 100644
index 0000000..d3df0b4
--- /dev/null
+++ b/db_config/SQL/pgsql.20141115.sql
@@ -0,0 +1 @@
+UPDATE "system" SET value='initial|20131110|20141115' WHERE name='myrc_db_config'; \ No newline at end of file
diff --git a/db_config/SQL/pgsql.initial.sql b/db_config/SQL/pgsql.initial.sql
new file mode 100644
index 0000000..e6f53fa
--- /dev/null
+++ b/db_config/SQL/pgsql.initial.sql
@@ -0,0 +1,13 @@
+CREATE TABLE IF NOT EXISTS db_config (
+ id serial PRIMARY KEY,
+ env varchar(255) DEFAULT NULL,
+ conf text,
+ admin varchar(128) NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS "system" (
+ name varchar(64) NOT NULL PRIMARY KEY,
+ value text
+);
+
+INSERT INTO "system" (name, value) VALUES ('myrc_db_config', 'initial'); \ No newline at end of file
diff --git a/db_config/SQL/sqlite.20131110.sql b/db_config/SQL/sqlite.20131110.sql
new file mode 100644
index 0000000..f4c349d
--- /dev/null
+++ b/db_config/SQL/sqlite.20131110.sql
@@ -0,0 +1 @@
+UPDATE 'system' SET value='initial|20131110' WHERE name='myrc_db_config'; \ No newline at end of file
diff --git a/db_config/SQL/sqlite.20141115.sql b/db_config/SQL/sqlite.20141115.sql
new file mode 100644
index 0000000..6d13072
--- /dev/null
+++ b/db_config/SQL/sqlite.20141115.sql
@@ -0,0 +1 @@
+UPDATE 'system' SET value='initial|20131110|20141115' WHERE name='myrc_db_config'; \ No newline at end of file
diff --git a/db_config/SQL/sqlite.initial.sql b/db_config/SQL/sqlite.initial.sql
new file mode 100644
index 0000000..d1d81ec
--- /dev/null
+++ b/db_config/SQL/sqlite.initial.sql
@@ -0,0 +1,13 @@
+CREATE TABLE IF NOT EXISTS 'db_config' (
+ 'id' INTEGER NOT NULL PRIMARY KEY ASC,
+ 'env' varchar(255) NOT NULL,
+ 'conf' text NOT NULL,
+ 'admin' varchar(128) NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS 'system' (
+ name varchar(64) NOT NULL PRIMARY KEY,
+ value text NOT NULL
+);
+
+INSERT INTO system (name, value) VALUES ('myrc_db_config', 'initial'); \ No newline at end of file
diff --git a/db_config/config.inc.php.dist b/db_config/config.inc.php.dist
new file mode 100644
index 0000000..7173105
--- /dev/null
+++ b/db_config/config.inc.php.dist
@@ -0,0 +1,86 @@
+<?php
+
+/* Configuration for Account administration section (use this instead of $GLOBALS in the
+ configuration of plugins which hooks into this settings section)
+*/
+
+/*
+ 'part' => currently not used
+ 'label' => label for the plugin name
+ 'descr' => label for the plugin description
+ 'href' => navigation into settings edit iFrame
+ 'onclick' => javascript code to be executed on click event
+*/
+$config['settingsnav']['summary'] = array(
+ 'part' => '',
+ 'label' => 'accountsummary',
+ 'href' => '#',
+ 'onclick' => 'parent.location.href="./?_task=mail&_action=plugin.summary"', 'descr' => 'summary'
+);
+$config['settingsnav']['moreuserinfo'] = array(
+ 'part' => '',
+ 'label' => 'accountinformation',
+ 'href' => './?_task=settings&_action=plugin.moreuserinfo&_framed=1',
+ 'onclick' => '',
+ 'descr' =>
+ 'moreuserinfo'
+);
+$config['settingsnav']['hmail_pop3'] = array(
+ 'part' => '',
+ 'label' => 'externalaccounts',
+ 'href' => './?_task=settings&_action=plugin.hmail_pop3&_framed=1',
+ 'onclick' => '',
+ 'descr' => 'hmail_pop3'
+);
+$config['settingsnav']['hmail_autoresponder'] = array(
+ 'part' => '',
+ 'label' => 'autoresponder',
+ 'href' => './?_task=settings&_action=plugin.hmail_autoresponder&_framed=1',
+ 'onclick' => '',
+ 'descr' => 'hmail_autoresponder'
+);
+$config['settingsnav']['hmail_forwarding'] = array(
+ 'part' => '',
+ 'label' => 'forwarding',
+ 'href' => './?_task=settings&_action=plugin.hmail_forwarding&_framed=1',
+ 'onclick' => '',
+ 'descr' =>
+ 'hmail_forwarding'
+);
+$config['settingsnav']['hmail_signature'] = array(
+ 'part' => '',
+ 'label' => 'signature',
+ 'href' => './?_task=settings&_action=plugin.hmail_signature&_framed=1',
+ 'onclick' => '',
+ 'descr' => 'hmail_signature'
+);
+$config['settingsnav']['hmail_spamfilter'] = array(
+ 'part' => '',
+ 'label' => 'spamfilter',
+ 'href' => './?_task=settings&_action=plugin.hmail_spamfilter&_framed=1',
+ 'onclick' => '',
+ 'descr' => 'hmail_spamfilter'
+);
+$config['settingsnav']['hmail_rules'] = array(
+ 'part' => '',
+ 'label' => 'rules',
+ 'href' => './?_task=settings&_action=plugin.hmail_rules&_framed=1',
+ 'onclick' => '',
+ 'descr' => 'hmail_rules'
+);
+$config['settingsnav']['hmail_password'] = array(
+ 'part' => '',
+ 'label' => 'changepasswd',
+ 'href' => './?_task=settings&_action=plugin.hmail_password&_framed=1',
+ 'onclick' => '',
+ 'descr' => 'hmail_password'
+);
+$config['settingsnav']['pwtools'] = array(
+ 'part' => '',
+ 'label' => 'pwreminder',
+ 'href' => './?_task=settings&_action=plugin.pwtools&_framed=1',
+ 'onclick' => '',
+ 'descr' => 'pwtools'
+);
+
+?> \ No newline at end of file
diff --git a/db_config/db_config.php b/db_config/db_config.php
new file mode 100644
index 0000000..a2275be
--- /dev/null
+++ b/db_config/db_config.php
@@ -0,0 +1,15 @@
+<?php
+#
+# This file is part of Roundcube "db_config" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] net
+# http://myroundcube.com
+#
+class db_config extends rcube_plugin{var$skip=array('companyaddressbook','dblog','demologin','newuser','load_splitter','register');static private$plugin='db_config';static private$author='myroundcube@mail4us.net';static private$authors_comments='<a href="http://myroundcube.com/myroundcube-plugins/db_config-plugin" target="_blank">Documentation</a>';static private$version='1.1.19';static private$date='30-12-2014';static private$licence='All Rights reserved';static private$requirements=array('Roundcube'=>'1.0','PHP'=>'5.3','required_plugins'=>array('plugin_manager'=>'require_plugin','db_version'=>'require_plugin',),);static private$sqladmin=array('db_dsnw','db_config');static private$prefs=null;static private$tables=array('db_config',);static private$db_version=array('initial','20131110','20141115',);function init(){$rcmail=rcmail::get_instance();if(!in_array('global_config',$rcmail->config->get('plugins'))){$this->load_config();}if(is_dir(INSTALL_PATH.'plugins/db_version')){$this->require_plugin('db_version');if(!$load=db_version::exec(self::$plugin,self::$tables,self::$db_version)){return;}}if(!empty($rcmail->user->ID)){$sql='SELECT * FROM '.get_table_name('users').' WHERE user_id=?';$res=$rcmail->db->limitquery($sql,0,1,$rcmail->user->ID);$user=$rcmail->db->fetch_assoc($res);$user=(array)unserialize($user['preferences']);}else{$user=array();}foreach($this->skip as$key=>$plugin){$this->skip[$key]=$rcmail->db->quote($plugin);}$append=implode(' AND env <> ',$this->skip);$sql='SELECT * FROM '.get_table_name('db_config').' WHERE env <> '.$append;$res=$rcmail->db->query($sql);while($conf=$rcmail->db->fetch_assoc($res)){$config=array();$rcmail_config=array();if(eval($conf['conf'])===null){$config=array_merge($rcmail_config,$config);foreach($config as$key=>$val){if(!isset($user[$key])||in_array($key,$rcmail->config->get('dont_override',array()))){$rcmail->config->set($key,$val);}}}else{write_log('db_config',$conf);}}}static function about($keys=false){$requirements=self::$requirements;foreach(array('required_','recommended_')as$prefix){if(is_array($requirements[$prefix.'plugins'])){foreach($requirements[$prefix.'plugins']as$plugin=>$method){if(class_exists($plugin)&&method_exists($plugin,'about')){$class=new$plugin(false);$requirements[$prefix.'plugins'][$plugin]=array('method'=>$method,'plugin'=>$class->about($keys),);}else{$requirements[$prefix.'plugins'][$plugin]=array('method'=>$method,'plugin'=>$plugin,);}}}}return array('plugin'=>self::$plugin,'version'=>self::$version,'db_version'=>self::$db_version,'date'=>self::$date,'author'=>self::$author,'comments'=>self::$authors_comments,'licence'=>self::$licence,'sqladmin'=>self::$sqladmin,'requirements'=>$requirements);}} \ No newline at end of file
diff --git a/db_config/localization/cs_CZ.inc b/db_config/localization/cs_CZ.inc
new file mode 100644
index 0000000..5d1ab05
--- /dev/null
+++ b/db_config/localization/cs_CZ.inc
@@ -0,0 +1,15 @@
+<?php
+#
+# This file is part of Roundcube "db_config" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] net
+# http://myroundcube.com
+#
+$labels=array();$labels['pluginname']='Konfigurace doplňků pomocí databáze';$labels['plugindescription']='Umožní konfiguraci doplňků pomocí databáze namísto souborového systému.'; \ No newline at end of file
diff --git a/db_config/localization/da_DK.inc b/db_config/localization/da_DK.inc
new file mode 100644
index 0000000..80d58b0
--- /dev/null
+++ b/db_config/localization/da_DK.inc
@@ -0,0 +1,15 @@
+<?php
+#
+# This file is part of Roundcube "db_config" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] net
+# http://myroundcube.com
+#
+$labels=array();$labels['pluginname']='Database baseret konfigurerings modul';$labels['plugindescription']='Konfigurer moduler i databasen i stedet for filsystem.'; \ No newline at end of file
diff --git a/db_config/localization/de_DE.inc b/db_config/localization/de_DE.inc
new file mode 100644
index 0000000..3b5d186
--- /dev/null
+++ b/db_config/localization/de_DE.inc
@@ -0,0 +1,15 @@
+<?php
+#
+# This file is part of Roundcube "db_config" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] net
+# http://myroundcube.com
+#
+$labels=array();$labels['pluginname']='Erweiterungen datenbankbasiert konfigurieren';$labels['plugindescription']='Erweiterungen datenbankbasiert konfigurieren.'; \ No newline at end of file
diff --git a/db_config/localization/en_US.inc b/db_config/localization/en_US.inc
new file mode 100644
index 0000000..64324f9
--- /dev/null
+++ b/db_config/localization/en_US.inc
@@ -0,0 +1,15 @@
+<?php
+#
+# This file is part of Roundcube "db_config" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] net
+# http://myroundcube.com
+#
+$labels=array();$labels['pluginname']='Database based plugins configuration';$labels['plugindescription']='Configure plugins by database instead of filesystem.'; \ No newline at end of file
diff --git a/db_config/localization/es_ES.inc b/db_config/localization/es_ES.inc
new file mode 100644
index 0000000..ab2ba81
--- /dev/null
+++ b/db_config/localization/es_ES.inc
@@ -0,0 +1,15 @@
+<?php
+#
+# This file is part of Roundcube "db_config" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] net
+# http://myroundcube.com
+#
+$labels=array();$labels['pluginname']='Configuración de complementos utilizando base ​​de datos';$labels['plugindescription']='Guardar configuraciones de complementos en la base de datos de Roundcube en vez de utilizar configuraciones de archivos.'; \ No newline at end of file
diff --git a/db_config/localization/fi_FI.inc b/db_config/localization/fi_FI.inc
new file mode 100644
index 0000000..12e79fc
--- /dev/null
+++ b/db_config/localization/fi_FI.inc
@@ -0,0 +1,15 @@
+<?php
+#
+# This file is part of Roundcube "db_config" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] net
+# http://myroundcube.com
+#
+$labels=array();$labels['pluginname']='TIetokantapohjainen liitännäisten asetusten muokkaus';$labels['plugindescription']='Muokkaa asetuksia tietokantaan tiedoston sijaan.'; \ No newline at end of file
diff --git a/db_config/localization/fr_FR.inc b/db_config/localization/fr_FR.inc
new file mode 100644
index 0000000..0d6df0a
--- /dev/null
+++ b/db_config/localization/fr_FR.inc
@@ -0,0 +1,15 @@
+<?php
+#
+# This file is part of Roundcube "db_config" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] net
+# http://myroundcube.com
+#
+$labels=array();$labels['pluginname']='Plugin paramètres de configuration en DB';$labels['plugindescription']='Configurer les plugins via une database au lieu de fichiers'; \ No newline at end of file
diff --git a/db_config/localization/revision.inc.php b/db_config/localization/revision.inc.php
new file mode 100644
index 0000000..32efb00
--- /dev/null
+++ b/db_config/localization/revision.inc.php
@@ -0,0 +1,11 @@
+<?php
+
+$ps_localization_update = serialize(
+ array(
+ 'translator' => 'Yoni',
+ 'language ' => 'es_ES',
+ 'date' => '01/15/2015 14:15:36'
+ )
+);
+
+?> \ No newline at end of file
diff --git a/db_config/localization/tr_TR.inc b/db_config/localization/tr_TR.inc
new file mode 100644
index 0000000..7d0eea9
--- /dev/null
+++ b/db_config/localization/tr_TR.inc
@@ -0,0 +1,15 @@
+<?php
+#
+# This file is part of Roundcube "db_config" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] net
+# http://myroundcube.com
+#
+$labels=array();$labels['pluginname']='Veritabani bazli eklenti yapilandirma';$labels['plugindescription']='Dosya sistemi yerine veritabani ile eklentileri yapilandirir.'; \ No newline at end of file
diff --git a/db_config/package.xml b/db_config/package.xml
new file mode 100644
index 0000000..5b7f9bb
--- /dev/null
+++ b/db_config/package.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+ http://pear.php.net/dtd/tasks-1.0.xsd
+ http://pear.php.net/dtd/package-2.0
+ http://pear.php.net/dtd/package-2.0.xsd">
+ <name>db_config</name>
+ <lead>
+ <name>Myroundcube Dev Team</name>
+ <user>rosali</user>
+ <email>dev-team@myroundcube.com</email>
+ <active>yes</active>
+ </lead><date>2014-12-30</date>
+ <version>
+ <release>1.1.19</release>
+ <api>1.1.19</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://dev.myroundcube.com/index.php?_action=plugin.plugin_server_license&amp;_plugin=db_config">All Rights reserved</license>
+</package>
diff --git a/db_version/CHANGELOG b/db_version/CHANGELOG
new file mode 100644
index 0000000..a93f7c2
--- /dev/null
+++ b/db_version/CHANGELOG
@@ -0,0 +1,21 @@
+VERSION COMMENT
+-----------------------------------------------------------------------------------------------------------------
+1.0 - Initial release
+2.0 - Completely recoded from scratch
+2.0.1 - 2.0.2 - GUI improvements
+2.0.3 - 2.0.5 - Fix for *NIX OS (workaround for case sensitivity of SQL folder)
+2.0.6 - Added sqlite3 to database map
+2.0.7 - Fixed Roundcube version detection
+2.0.8 - 2.0.10 - Prepare for Roundcube 1.0
+3.0 - Support for sqlite (https://code.google.com/p/myroundcube/issues/detail?id=624);
+3.1 - Better support for database prefixes
+3.1.1 - Implement rcube_db::factory
+3.1.2 - Implement rcube_db::limitquery
+3.1.3 - 3.1.4 - Don't load plugin if database access to system table fails (should avoid to display
+ database update prompt to "normal" users in case of database connection failures)
+3.1.5 - Don't exit for plugin.plugin_manager_update_notifications action
+3.1.6 - Make sure that db_config plugin is always loaded
+3.1.7 - Do not load plugin on Plugin Manager Update request
+3.1.8 - Always load plugins on about request
+3.1.9 - Remove reward logging (MSSQL will be deprecated)
+3.1.10 - Better RegEx for custom table names replacement \ No newline at end of file
diff --git a/db_version/LICENSE b/db_version/LICENSE
new file mode 100644
index 0000000..11b1f5e
--- /dev/null
+++ b/db_version/LICENSE
@@ -0,0 +1,84 @@
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+
+
+
+TERMS AND CONDITIONS
+--------------------
+
+User Agreement
+
+MyRoundcube Developers provides MyRoundcube Plugins (code) shall provide ("MyRoundcube Plugins") to
+you ("User") under the terms and conditions of this User Agreement ("the Agreement"). USER UNDERSTANDS
+AND ACKNOWLEDGES THAT USER IS ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers AND NOT THE WEB
+SITE WITH WHOM ANYTHING HAS ASSOCIATED TO BRING YOU THIS CODE. BY USING ("MyRoundcube Plugins") OR ANY
+PART OF ITS CODE YOU ARE AGREEING TO BECOME A PARTY TO THIS AGREEMENT WITH MyRoundcube Developers AND
+TO THE TERMS AND CONDITIONS HEREIN AND ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND ANY APPLICABLE
+ASSOCIATE STATEMENT IN THIS DOCUMENT. ALL MyRoundcube Developers SERVICES ARE PROVIDED ONLINE. PERSONS
+UNDER 13 MAY NOT BE ELEGIBLE TO ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers OR PURCHASE OUR
+SERVICES AND CODE DOWNLOADS.
+
+Acceptable Use Policy
+
+The following policy governs the use of the MyRoundcube Developers code. User will comply with the terms
+and spirit of the Agreement.
+
+(a) User shall not use MyRoundcube Plugins (code) in a manner that violates any city, state, national
+or international law or regulation, or which fails to comply with accepted Internet protocol. User
+shall not attempt to interfere in any way with MyRoundcube Plugins networks or network security, or
+attempt to use the MyRoundcube Plugins code to gain unauthorized access to any other computer system.
+(b) User shall at all times provide MyRoundcube Developers with accurate information. User shall not
+interfere in any way with another User's use of, or MyRoundcube Developers provision of the MyRoundcube
+Plugins. User shall not resell, rent, lease, grant a security interest in, or make commercial use of
+the MyRoundcube Plugins without the express written consent of MyRoundcube Developers.
+(c) User agrees not to transfer MyRoundcube Plugins (code) for gain or otherwise. Transfer of such code
+will result in termination of contract with end user.
+
+Limitation of Liability
+
+UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, TORT, CONTRACT, OR OTHERWISE, SHALL MyRoundcube
+Developers OR ITS LICENSORS OR RESELLERS BE LIABLE TO USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL,
+INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES RESULTING
+FROM THE USE OF OR THE INABILITY TO USE THE MyRoundcube Plugins (code), THE PERFORMANCE OF MyRoundcube
+Plugins (code) SERVICE, OR DAMAGES FOR LOSS OF GOODWILL, BUSINESS PROFIT, BUSINESS STOPPAGE, LOSS OF
+DATA OR BUSINESS INFORMATION, COMPUTER DAMAGE, OR DAMAGES RESULTING FROM UNAUTHORIZED ACCESS TO OR
+CHANGES MADE TO USER'S TRANSMISSIONS OR DATA, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES.
+IN NO EVENT WILL MyRoundcube Developers BE LIABLE FOR ANY DAMAGES IN EXCESS OF WHAT ANYTHING MyRoundcube
+Developers RECEIVED FROM USER FOR THE MyRoundcube Plugins (code).
+
+Terms
+
+You (the User) are permitted to use the code on unlimited servers you may own, rented or leased, as
+long as you own, rent or lease the server in which MyRoundcube plugins code is hosted.
+Exclusive: You (the User) agree to use the code in one server at a time. Multiple server deployments
+(multiserver setup), clusters or any other form of deployment that simultaneously executes MyRoundcube
+plugins in a live environment must purchase a separate download per server or installation thereof.
+
+Warranties
+
+Our code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+Terms Modifications
+
+We reserve the right to change or modify our Terms and Conditions at any time without prior notice.
+For questions, please contact our team at dev-team [at] myroundcube [dot] com.
+
+Copyright (c) 2012 - 2014
+MyRoundcube.com - A Division of Informative Computing Consultants, LLC.
+All rights reserved
+
+Informative Computing Consultants, LLC.
+21741 NW 8th CT
+Pembroke Pines
+Florida, 33029
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
diff --git a/db_version/README b/db_version/README
new file mode 100644
index 0000000..1530f52
--- /dev/null
+++ b/db_version/README
@@ -0,0 +1,8 @@
+db_version
+----------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/
+
+
+MyRoundcube Dev Team
+www.myroundcube.com \ No newline at end of file
diff --git a/db_version/SQL/mssql.initial.sql b/db_version/SQL/mssql.initial.sql
new file mode 100644
index 0000000..80261cf
--- /dev/null
+++ b/db_version/SQL/mssql.initial.sql
@@ -0,0 +1,5 @@
+CREATE TABLE [dbo].[system] (
+ [name] [varchar] (64) COLLATE Latin1_General_CI_AI NOT NULL ,
+ [value] [text] COLLATE Latin1_General_CI_AI NOT NULL
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
+GO
diff --git a/db_version/SQL/mysql.initial.sql b/db_version/SQL/mysql.initial.sql
new file mode 100644
index 0000000..bb10b47
--- /dev/null
+++ b/db_version/SQL/mysql.initial.sql
@@ -0,0 +1,13 @@
+CREATE TABLE IF NOT EXISTS `myrc` (
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `user_id` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `user_id` (`user_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
+
+ALTER TABLE `myrc`
+ ADD CONSTRAINT `myrc_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;
+
+CREATE INDEX myrc_idx ON myrc (`user_id`);
+
+DROP TABLE `myrc`; \ No newline at end of file
diff --git a/db_version/SQL/pgsql.initial.sql b/db_version/SQL/pgsql.initial.sql
new file mode 100644
index 0000000..d7b974e
--- /dev/null
+++ b/db_version/SQL/pgsql.initial.sql
@@ -0,0 +1,12 @@
+CREATE TABLE IF NOT EXISTS myrc (
+ id serial NOT NULL,
+ user_id integer NOT NULL,
+ PRIMARY KEY (id)
+);
+
+ALTER TABLE myrc
+ ADD CONSTRAINT myrc_ibfk_1 FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE;
+
+CREATE INDEX myrc_idx ON myrc (user_id);
+
+DROP TABLE myrc; \ No newline at end of file
diff --git a/db_version/SQL/sqlite.initial.sql b/db_version/SQL/sqlite.initial.sql
new file mode 100644
index 0000000..776c0e4
--- /dev/null
+++ b/db_version/SQL/sqlite.initial.sql
@@ -0,0 +1,12 @@
+PRAGMA foreign_keys = ON;
+
+CREATE TABLE IF NOT EXISTS myrc (
+ id serial NOT NULL,
+ user_id integer NOT NULL,
+ PRIMARY KEY (id),
+ FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+CREATE INDEX myrc_idx ON myrc (user_id);
+
+DROP TABLE myrc; \ No newline at end of file
diff --git a/db_version/db_version.php b/db_version/db_version.php
new file mode 100644
index 0000000..6b43e98
--- /dev/null
+++ b/db_version/db_version.php
@@ -0,0 +1,474 @@
+<?php
+#
+# This file is part of MyRoundcube "db_version" plugin.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl
+# dev-team [at] myroundcube [dot] com
+# http://myroundcube.com
+#
+class db_version extends rcube_plugin{
+
+ static private $done = false;
+ static private $map = array('mysql' => 'MySQL', 'pgsql' => 'PostGreSQL', 'sqlite' => 'Sqlite v.3', 'mssql' => 'MSSQL');
+
+ /* unified plugin properties */
+ static private $plugin = 'db_version';
+ static private $author = 'myroundcube@mail4us.net';
+ static private $authors_comments = '<a href="http://myroundcube.com/myroundcube-plugins/helper-plugin?db_version" target="_blank">Documentation</a>';
+ static private $download = 'http://myroundcube.googlecode.com';
+ static private $version = '3.1.10';
+ static private $date = '21-01-2015';
+ static private $licence = 'All Rights reserved';
+ static private $requirements = array(
+ 'Roundcube' => '1.0',
+ 'PHP' => '5.3',
+ 'required_plugins' => array(
+ 'codemirror_ui' => 'require_plugin',
+ ),
+ );
+ static private $prefs = array(
+ );
+ static private $config_dist = null;
+ static private $db_map = array(
+ 'sqlite' => 'sqlite',
+ 'sqlite2' => 'sqlite',
+ 'sqlite3' => 'sqlite',
+ 'sybase' => 'mssql',
+ 'dblib' => 'mssql',
+ 'sqlsrv' => 'mssql',
+ 'mssql' => 'mssql',
+ 'mysql' => 'mysql',
+ 'mysqli' => 'mysql',
+ 'pgsql' => 'pgsql',
+ 'postgresql' => 'pgsql',
+ );
+ static private $default_tables = array(
+ 'users',
+ 'attachments',
+ 'cache',
+ 'cache_index',
+ 'cache_thread',
+ 'cache_tables',
+ 'cache_messages',
+ 'cache_shared',
+ 'contactgroupmembers',
+ 'contactgroups',
+ 'contacts',
+ 'dictionary',
+ 'identities',
+ 'searches',
+ 'system'
+ );
+ static private $f;
+
+ function init(){
+ self::$f = $this;
+ }
+
+ static public function about($keys = false){
+ $requirements = self::$requirements;
+ foreach(array('required_', 'recommended_') as $prefix){
+ if(is_array($requirements[$prefix.'plugins'])){
+ foreach($requirements[$prefix.'plugins'] as $plugin => $method){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $class->about($keys),
+ );
+ }
+ else{
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $plugin,
+ );
+ }
+ }
+ }
+ }
+ return array(
+ 'plugin' => self::$plugin,
+ 'version' => self::$version,
+ 'date' => self::$date,
+ 'author' => self::$author,
+ 'comments' => self::$authors_comments,
+ 'licence' => self::$licence,
+ 'requirements' => $requirements,
+ );
+ }
+
+ function form($p){
+ return self::$out;
+ }
+
+ static public function exec($plugin, $tables, $dbversion){
+ $rcmail = rcmail::get_instance();
+ /*
+ if($rcmail->action == 'plugin.plugin_manager_update' || $rcmail->action == 'about' || $rcmail->action == 'alive' || $rcmail->action == 'refresh'){
+ return true;
+ }
+ */
+ if($rcmail->action == 'about'){ // Do not force database adjustments on about request
+ return true;
+ }
+ if(get_input_value('_load_pm_settings', RCUBE_INPUT_GET)){
+ if($plugin = get_input_value('_plugin', RCUBE_INPUT_GET)){
+ $append = '&_plugin=' . $plugin;
+ }
+ else{
+ $append = '';
+ }
+ if(!self::$done){
+ self::$done = true;
+ if($rcmail->config->get('skin', 'classic') == 'classic'){
+ $frame = 'prefs-frame';
+ }
+ else{
+ $frame = 'preferences-frame';
+ }
+ $rcmail->output->add_script('$("#'. $frame . '").attr("src", "./?_task=settings&_action=edit-prefs&_section=plugin_manager_settings&_framed=1' . $append . '");', 'docready');
+ }
+ return false;
+ }
+ $return = false;
+ $dbversion = implode('|', $dbversion);
+ $query = 'SELECT * FROM ' . get_table_name('system') . ' WHERE ' . $rcmail->db->quoteIdentifier('name') . '=?';
+ $res = $rcmail->db->limitquery($query, 0, 1, 'myrc_' . $plugin);
+ $version = $rcmail->db->fetch_assoc($res);
+ if($error = $rcmail->db->is_error()){
+ write_log('db_version', $error);
+ return false;
+ }
+ if($version['value'] == $dbversion){
+ $return = true;
+ }
+ else if($plugin == 'plugin_manager' || $rcmail->config->get('plugin_manager_hash')){
+ $hash = $rcmail->config->get('plugin_manager_hash');
+ if(($plugin == 'plugin_manager' && !is_array($version)) || ($rcmail->task != 'logout' && file_exists(INSTALL_PATH . $hash . '.myrc'))){
+ if(get_input_value('_framed', RCUBE_INPUT_GPC)){
+ return false;
+ }
+ $type = current(explode(':', $rcmail->config->get('db_dsnw'), 2));
+ $type = self::$db_map[$type];
+ if(!$type){
+ if(!file_exists(slashify($rcmail->config->get('log_dir', 'logs/')) . 'dbtypefailure')){
+ write_log('dbtypefailure', 'MyRoundcube Fatal Error');
+ write_log('dbtypefailure', '-----------------------');
+ write_log('dbtypefailure', 'Failed to detect database type.');
+ write_log('dbtypefailure', 'Please contact MyRoundcube Dev Team (dev-team@myroundcube.com) and mail the following string (don\'t miss to mask password and to clear your Browser cache):');
+ write_log('dbtypefailure', ' ');
+ write_log('dbtypefailure', $rcmail->config->get('db_dsnw'));
+ }
+ $content = file_get_contents(slashify($rcmail->config->get('log_dir', 'logs/')) . 'dbtypefailure');
+ $content = explode("\n", $content);
+ $out = '';
+ foreach($content as $nb => $line){
+ $line = explode("]: ", $line);
+ $out .= $line[1] . "\n";
+ }
+ $rcmail->output->nocacheing_headers();
+ die('<html><head><title>MyRoundcube Fatal Error</title></head><body><pre>' . $out . '</pre></body></html>');
+ }
+ if(get_input_value('_remote', RCUBE_INPUT_GPC) && get_input_value('_action', RCUBE_INPUT_GPC) != 'plugin.plugin_manager_update_notifier' && !$_SESSION['db_version_lock']){
+ $db_version = explode('|', $dbversion);
+ $redirect = true;
+ $reward = false;
+ $missing = '';
+ foreach($db_version as $script){
+ if(!file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql') && !file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')){
+ $rcmail->output->show_message('Plugin "' . $plugin . '": Can\'t load plugin. ' . self::$map[strtolower($type)] . ' database scripts are incomplete.', 'error');
+ $redirect = false;
+ $missing .= $plugin . ': plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql does not exist!';
+ //$reward = '--> REWARD MyRC$ 5: Create missing scripts and mail it to dev-team@myroundcube.com (include your customer ID)!';
+ }
+ }
+ if($reward && !$_SESSION['db_version_missing_logged_' . $plugin]){
+ $_SESSION['db_version_missing_logged_' . $plugin] = true;
+ write_log('errors', $missing);
+ //write_log('errors', $reward);
+ }
+ if($redirect){
+ echo json_encode(array('exec' => 'document.location.href="./"'));
+ exit;
+ }
+ }
+ $return = db_version::db_versioning($plugin, array_merge(array('system'), $tables));
+ }
+ }
+ else if($plugin == 'db_config'){
+ $return = true;
+ }
+ return $return;
+ }
+
+ static public function test_permissions($type, $db){
+ if($type == 'sqlite'){
+ return true;
+ }
+ $sql = @file_get_contents(INSTALL_PATH . 'plugins/db_version/SQL/' . $type . '.initial.sql');
+ if(!$sql){
+ $sql = @file_get_contents(INSTALL_PATH . 'plugins/db_version/sql/' . $type . '.initial.sql');
+ }
+ if($sql){
+ $sql = trim($sql) . "\r\n";
+ $sql = self::fix_table_names($sql, array('myrc'));
+ $sql = explode(';', $sql);
+ foreach($sql as $line){
+ if(trim($line)){
+ if(!$db->query($line)){
+ $command = explode(' ', $line);
+ return $command[0];
+ }
+ }
+ }
+ return true;
+ }
+ else{
+ return $type;
+ }
+ }
+
+ static public function db_versioning($plugin, $tables){
+ $rcmail = rcmail::get_instance();
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $db_version = $class->about(array('db_version'));
+ $db_version = $db_version['db_version'];
+ if(is_array($db_version)){
+ $database = parse_url($rcmail->config->get('db_dsnw'));
+ if(!$database){
+ $database = parse_url(end(explode(':', $rcmail->config->get('db_dsnw'), 2)));
+ $database['scheme'] = current(explode(':', $rcmail->config->get('db_dsnw'), 2));
+ }
+ $type = self::$db_map[$database['scheme']];
+ $sql = 'SELECT * FROM ' . get_table_name('system') . ' WHERE ' . $rcmail->db->quote_identifier('name') . '=?';
+ $res = $rcmail->db->limitquery($sql, 0, 1, 'myrc_' . $plugin);
+ $system = $rcmail->db->fetch_assoc($res);
+ if($system){
+ $versions = explode('|', $system['value']);
+ }
+ if(implode('|', $db_version) == $system['value']){
+ return true;
+ }
+ if(count($_POST) == 0){
+ $sql = '';
+ foreach($db_version as $script){
+ if(!is_array($versions) || !in_array($script, $versions)){
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')){
+ $sql .= trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')) . "\r\n";
+ }
+ else if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')){
+ $sql .= trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')) . "\r\n";
+ }
+ else{
+ return false;
+ }
+ }
+ }
+ if($sql){
+ $disable = '';
+ if($plugin != 'plugin_manager'){
+ $res = $rcmail->db->limitquery('SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $rcmail->db->quote_identifier('conf') . '=?', 0, 1, '_plugin_manager_file_based_config');
+ $fb = $rcmail->db->fetch_assoc($res);
+ if($fb['value'] == 0){
+ $disable = '&nbsp;' . html::tag('input', array('onclick' => 'document.location.href="./?_task=settings&_load_pm_settings=1&_plugin=' . $plugin . '"', 'type' => 'button', 'class' => 'button', 'value' => 'Disable Plugin'));
+ }
+ }
+ if($database['user']){
+ $dsnw = $database['scheme'] . '://' . $database['user'] . ':***masked***@' . $database['host'] . $database['path'];
+ }
+ else{
+ $dsnw = $rcmail->config->get('db_dsnw');
+ }
+ $v = explode('-', RCMAIL_VERSION);
+ $v = trim($v[0]);
+ if(version_compare($v, '0.9', '>=')){
+ $out =
+ html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -400px; width: 800px;'),
+ html::tag('h3', null, 'Plugin Manager database versioning: Plugin "' . $plugin . '"') .
+ 'Plugin Manager has detected required missing adjustments in your database. The following commands will be executed against your database ' .
+ html::tag('b', null, $dsnw . ':') . html::tag('br') . html::tag('br') .
+ html::tag('textarea', array('readonly' => true, 'rows' => '18', 'cols' => '95', 'id' => 'code'), self::fix_table_names($sql, $tables)) .
+ html::tag('table', null,
+ html::tag('tr', null, html::tag('td', null, html::tag('input', array('type' => 'radio', 'name' => '_dbadjust_agreed', 'checked' => true, 'value' => 1, 'onclick' => '$("#submitbutton").show();$("#donebox").hide()')) .
+ html::tag('td', null, 'I have a recent database backup. I understand the code and I agree to execute it. '))) .
+ html::tag('tr', null, html::tag('td', null, html::tag('input', array('type' => 'radio', 'name' => '_dbadjust_agreed', 'value' => 0, 'onclick' => '$("#submitbutton").hide();$("#donebox").show()')) .
+ html::tag('td', null, 'I will take care of the necessary ' .
+ html::tag('a', array('href' => 'http://myroundcube.com/myroundcube-plugins/faqs/myroundcube-plugins-database-versioning-support', 'target' => '_new'), 'database adjustments') . ' by myself. ' .
+ 'I\'m aware that MyRoundcube "' . $plugin . '" plugin does not work without these database adjustments. ')))
+ ) .
+ html::tag('center', null, html::tag('input', array('id' => 'submitbutton', 'type' => 'submit', 'value' => 'Submit')) . $disable) . html::tag('br') .
+ html::tag('center', array('style' => 'display: none;', 'id' => 'donebox'), html::tag('input', array('type' => 'checkbox', 'onclick' => '$("#submitbutton").show();$("#donebox").hide();$(this).prop("checked", false)')) . html::tag('span', null, '&nbsp;' .
+ html::tag('b', null, 'I have unregistered this plugin or I have already applied database adjustments manually.')))
+ );
+ $hidden = new html_hiddenfield(array('name' => '_token', 'value' => $rcmail->get_request_token()));
+ $out .= "\n" . $hidden->show();
+ $out .= html::tag('script', array('type' => 'text/javascript'), '$("#taskbar.topright").hide();');
+ $section = '';
+ if($section = get_input_value('_plugin_manager_settings_section', RCUBE_INPUT_GET)){
+ $section = '&_plugin_manager_settings_section=' . $section . '&_expand=' . $plugin;
+ }
+ $form = html::tag('form', array('method' => 'post', 'action' => './?_task=' . $rcmail->task . $section), $out);
+ }
+ else{
+ $out =
+ html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -400px; width: 800px;'),
+ html::tag('h3', null, 'Plugin Manager database versioning: Plugin "' . $plugin . '"') .
+ 'Plugin Manager has detected required missing adjustments in your database. Please execute the following commands against your database ' .
+ html::tag('b', null, $database['scheme'] . '://' . $database['user'] . ':***masked***@' . $database['host'] . $database['path'] . ':') . html::tag('br') . html::tag('br') .
+ html::tag('textarea', array('readonly' => true, 'rows' => '18', 'cols' => '95', 'id' => 'code'), self::fix_table_names($sql, $tables)) .
+ html::tag('table', null,
+ html::tag('tr', null, html::tag('td', null,
+ html::tag('td', null, 'Please backup your database. ' .
+ 'Please note, that MyRoundcube "' . $plugin . '" plugin does not work without these database adjustments.')))
+ ) .
+ html::tag('center', null, html::tag('input', array('id' => 'submitbutton', 'type' => 'submit', 'value' => 'Database has been backed up and commands have been executed.')))
+ );
+ $hidden = new html_hiddenfield(array('name' => '_token', 'value' => $rcmail->get_request_token()));
+ $out .= "\n" . $hidden->show();
+ $out .= html::tag('script', array('type' => 'text/javascript'), '$("#taskbar.topright").hide();');
+ $section = '';
+ if($section = get_input_value('_plugin_manager_settings_section', RCUBE_INPUT_GET)){
+ $section = '&_plugin_manager_settings_section=' . $section . '&_expand=' . $plugin;
+ }
+ $form = html::tag('form', array('method' => 'post', 'action' => './?_task=' . $rcmail->task . $section), $out);
+ }
+ $out = str_replace('##FORM##', $form, @file_get_contents(INSTALL_PATH . 'plugins/db_version/skins/' . $rcmail->config->get('skin', 'classic') . '/sql.html'));
+ if(method_exists($rcmail->output, 'just_parse')){
+ send_nocacheing_headers();
+ header('Content-Type: text/html; charset=' . RCMAIL_CHARSET);
+ echo $rcmail->output->just_parse($out);
+ exit;
+ }
+ }
+ }
+ else{
+ if(get_input_value('_dbadjust_agreed', RCUBE_INPUT_POST)){
+ unset($_POST);
+ $rcmail->session->remove('db_version_lock');
+ if($dsn = $rcmail->config->get('db_dsnw_superadmin')){
+ $rcmail->db = rcube_db::factory($dsn . '?new_link=true', '', false);
+ $rcmail->db = $rcmail->db->factory($dsn . '?new_link=true');
+ $rcmail->db->set_debug((bool)$rcmail->config->get('sql_debug'));
+ $rcmail->db->db_connect('r');
+ }
+ $ret = self::test_permissions($type, $rcmail->db);
+ $sversions = is_array($system) ? $system['value'] : '';
+ $sversions = explode('|', $sversions);
+ if($ret !== true){
+ $sql = '';
+ foreach($db_version as $script){
+ if(!in_array($script, $sversions)){
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')){
+ $sql .= self::fix_table_names(trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')) . "\r\n", $tables);
+ }
+ else if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')){
+ $sql .= self::fix_table_names(trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')) . "\r\n", $tables);
+ }
+ }
+ }
+ if($ret === $type){
+ $rcmail->output->show_message('Plugin "db_version": ' . self::$map[strtolower($type)] . ' database is not supported!', 'error');
+ return false;
+ }
+ self::html_output($sql, $ret);
+ }
+ foreach($db_version as $script){
+ if(!in_array($script, $sversions)){
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')){
+ $sql = self::fix_table_names(trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')) . "\r\n", $tables);
+ $lines = explode(';', $sql);
+ foreach($lines as $line){
+ if(trim($line)){
+ $rcmail->db->query(trim($line));
+ }
+ }
+ }
+ else if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')){
+ $sql = self::fix_table_names(trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')) . "\r\n", $tables);
+ $lines = explode(';', $sql);
+ foreach($lines as $line){
+ if(trim($line)){
+ $rcmail->db->query(trim($line));
+ }
+ }
+ }
+ }
+ }
+ $sql = 'DELETE from ' . get_table_name('system') . ' WHERE ' . $rcmail->db->quoteIdentifier('name') . '=?';
+ $rcmail->db->query($sql, 'myrc_' . $plugin);
+ $sql = 'INSERT INTO ' . get_table_name('system') . ' (' . $rcmail->db->quote_identifier('name') . ', ' . $rcmail->db->quote_identifier('value') . ') VALUES(?, ?)';
+ $res = $rcmail->db->query($sql, 'myrc_' . $plugin, implode('|', $db_version));
+ if($rcmail->db->affected_rows($res)){
+ return true;
+ }
+ else{
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ static public function html_output($script, $command = false){
+ $rcmail = rcmail::get_instance();
+ $config_var = '$config';
+ $config_file = 'config.inc.php';
+ $v = current(explode('-', RCMAIL_VERSION));
+ if(version_compare($v, '1.0', '<')){
+ $config_var = '$rcmail_config';
+ $config_file = 'db.inc.php';
+ }
+ $dbconfig = parse_url($rcmail->config->get('db_dsnw'));
+ $out = html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -400px; width: 800px;'),
+ html::tag('h3', null, sprintf('Database adjustment failed (Command: %s)', $command)) .
+ html::tag('span', null, 'The user ' .
+ html::tag('b', null, '"' . ($dbconfig['user'] ? $dbconfig['user'] : get_current_user()) . '"') .' does not seem to have sufficient permissions on the database ' .
+ html::tag('b', null, '"' . ($dbconfig['path'] ? substr($dbconfig['path'], 1) : $rcmail->config->get('db_dsnw')) . '"') . ':' . html::tag('br') . html::tag('br') .
+ ' ' . html::tag('center', null, html::tag('i', null, 'Required permissions: SELECT / INSERT / UPDATE / DELETE / CREATE / ALTER / INDEX / DROP')) .
+ html::tag('br') .
+ 'Please, grant the user sufficient permissions on the database or execute the following database script manually:') . html::tag('br') . html::tag('br') .
+ html::tag('textarea', array('readonly' => true, 'rows' => '10', 'cols' => '95', 'id' => 'code'), self::fix_table_names($script, array('plugin_manager'))) .
+ html::tag('br') . html::tag('br') .
+ html::tag('div', array('style' => $display_superadmin ? 'block' : 'none'),
+ $dbconfig['user'] ?
+ (
+ html::tag('left', null, html::tag('b', null, 'Alternatively') . ' add a different database user with sufficient permissions to your configuration in ' .
+ html::tag('b', null, '"./config/' . $config_file . '"') . ':' . html::tag('br') . html::tag('br') .
+ html::tag('textarea', array('readonly' => true, 'cols' => '95', 'rows' => '2'),
+ $config_var . '[\'db_dsnw_superadmin\'] = \'' . $dbconfig['scheme'] . '://root:password@' . $dbconfig['host'] . $dbconfig['path'] . '\';')) .
+ html::tag('br') . html::tag('br')
+ ) : ''
+ ) .
+ html::tag('div', array('style' => 'display: inline; float: left'),
+ html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => 'document.location.href=\'./\''), 'Done')
+ )
+ );
+ $out .= html::tag('script', array('type' => 'text/javascript'), '$("#taskbar.topright").hide();');
+ $out = str_replace('##FORM##', $out, @file_get_contents(INSTALL_PATH . 'plugins/db_version/skins/' . $rcmail->config->get('skin', 'classic') . '/sql.html'));
+ send_nocacheing_headers();
+ header('Content-Type: text/html; charset=' . RCMAIL_CHARSET);
+ echo $rcmail->output->just_parse($out);
+ exit;
+ }
+
+ static public function fix_table_names($sql, $tables){
+ $tables = array_merge(self::$default_tables, $tables);
+ $DB = rcmail::get_instance()->db;
+ if(is_array($tables)){
+ foreach($tables as $table){
+ $real_table = $DB->table_name($table);
+ if($real_table != $table){
+ $sql = preg_replace("/([^a-z0-9_'])$table([^a-z0-9_'])/i", "\\1$real_table\\2", $sql);
+ }
+ }
+ }
+ return $sql;
+ }
+}
+?> \ No newline at end of file
diff --git a/db_version/package.xml b/db_version/package.xml
new file mode 100644
index 0000000..3710a27
--- /dev/null
+++ b/db_version/package.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+ http://pear.php.net/dtd/tasks-1.0.xsd
+ http://pear.php.net/dtd/package-2.0
+ http://pear.php.net/dtd/package-2.0.xsd">
+ <name>db_version</name>
+ <lead>
+ <name>Myroundcube Dev Team</name>
+ <user>rosali</user>
+ <email>dev-team@myroundcube.com</email>
+ <active>yes</active>
+ </lead><date>2014-07-05</date>
+ <version>
+ <release>3.1.4</release>
+ <api>3.1.4</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://dev.myroundcube.com/index.php?_action=plugin.plugin_server_license&amp;_plugin=db_version">All Rights reserved</license>
+</package>
diff --git a/db_version/skins/classic/sql.html b/db_version/skins/classic/sql.html
new file mode 100644
index 0000000..36a73e4
--- /dev/null
+++ b/db_version/skins/classic/sql.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<roundcube:include file="/includes/links.html" />
+<script src="program/js/jquery.min.js" type="text/javascript"></script>
+<script src="program/js/common.js" type="text/javascript"></script>
+<script src="program/js/app.js" type="text/javascript"></script>
+<script type="text/javascript">
+var rcmail = new rcube_webmail();
+</script>
+</head>
+<body>
+
+<roundcube:include file="/includes/taskbar.html" />
+<roundcube:include file="/includes/header.html" />
+<roundcube:if condition="env:task == 'settings'" />
+ <roundcube:include file="/includes/settingstabs.html" />
+<roundcube:endif />
+
+<div id="mainscreen">
+##FORM##
+</div>
+<script type="text/javascript">
+$(document).ready(function(){
+rcmail.init();
+$('.button-logout').attr('onclick', '');
+});
+</script>
+</body>
+</html>
diff --git a/db_version/skins/larry/sql.html b/db_version/skins/larry/sql.html
new file mode 100644
index 0000000..99cd78a
--- /dev/null
+++ b/db_version/skins/larry/sql.html
@@ -0,0 +1,48 @@
+<roundcube:object name="doctype" value="html5" />
+<html>
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<roundcube:include file="/includes/links.html" />
+<link rel="stylesheet" type="text/css" href="plugins/codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.css">
+<style type="text/css">.CodeMirror {height: 93%; border-top: 1px solid black; border-bottom: 1px solid black; .CodeMirror-scroll {height: 100%} </style>
+<script src="program/js/jquery.min.js" type="text/javascript"></script>
+<script src="program/js/common.js" type="text/javascript"></script>
+<script src="program/js/app.js" type="text/javascript"></script>
+<script type="text/javascript" src="plugins/codemirror_ui/lib/CodeMirror-2.3/lib/codemirror.js"></script>
+<script type="text/javascript" src="plugins/codemirror_ui/lib/CodeMirror-2.3/lib/util/searchcursor.js"></script>
+<script type="text/javascript" src="plugins/codemirror_ui/lib/CodeMirror-2.3/mode/mysql/mysql.js"></script>
+<script type="text/javascript">
+var rcmail = new rcube_webmail();
+</script>
+</head>
+<body class="noscroll">
+
+<roundcube:include file="/includes/header.html" />
+
+<div id="mainscreen" class="offset">
+
+<roundcube:if condition="env:task == 'settings'" />
+ <roundcube:include file="/includes/settingstabs.html" />
+<roundcube:endif />
+
+<div id="pluginbody" class="uibox contentbox">
+##FORM##
+<roundcube:object name="message" id="message" class="statusbar" />
+</div>
+</div>
+<script type="text/javascript">
+$(document).ready(function(){
+rcmail.init();
+$('.button-logout').attr('onclick', '');
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ readOnly: true,
+ mode: "text/x-mysql",
+ tabMode: "indent",
+ matchBrackets: true
+ });
+});
+</script>
+<roundcube:include file="/includes/footer.html" />
+</body>
+</html>
diff --git a/libgpl/CHANGELOG b/libgpl/CHANGELOG
new file mode 100644
index 0000000..9defcc5
--- /dev/null
+++ b/libgpl/CHANGELOG
@@ -0,0 +1,39 @@
+VERSION COMMENT
+----------------------------------------------------------------------------------
+1.0 - Initial release
+1.0.1 - Added log option to CalDAV client
+1.0.2 - Added date.js toolbox
+ (http://www.mattkruse.com/javascript/date)
+1.0.3 - Added sync interval property to caldav sync client
+1.0.4 - Moved ical_sync to libgpl
+1.0.5 - Include querystring.js for tasklist
+1.0.6 - Replace the big close button in jquery dialogs
+1.0.7 - 1.0.9 - Fetch reminders almost immediately after page
+ initialization and not with a delay of 1 minute
+1.0.10 - 1.0.12 - Include jquery contexmenu
+ (http://medialize.github.io/jQuery-contextMenu/demo.html)
+1.0.13 - Include date.js for sticky_notes
+1.0.14 - Larry skin improvements
+1.0.15 - Implement contextmenu for sticky_notes
+1.0.16 - Include fancybox
+1.0.17 - Re-organize folder structure
+1.0.18 - Clean up larry skin images
+1.0.19 - Include jquery timepicker
+1.0.20 - Include http_request
+1.0.21 - Make sure jqueryui plugin is loaded first of all
+1.0.22 - 1.0.23 - Include qtip
+1.0.24 - Fix javascript error in libcalendaring.js if date format
+ is undefined
+1.0.25 - Move label overwrites to libgpl
+1.0.26 - Add password.js overwrite
+1.0.27 - CalDAV: Send User-Agent header
+1.0.28 - 1.0.29 - Implement gzip decompression in ical driver
+1.0.30 - css fix: min-width for jqueryui dialogs (calendar/
+ carddav plugins)
+1.0.31 - CalDAV: Implemented digest authentication
+1.0.32 - 1.0.33 - CardDAV: Overwrite default subscribed label
+1.0.34 - Header User-Agent: MyRoundcube-SabreDAV
+1.0.35 - Move SabreDAV components to libcalendaring plugin
+1.0.36 - CalDAV: Don't use gmdate for UTC timezone conversion
+1.0.37 - CalDAV: Make cURL verify host configurable
+1.0.38 - CalDAV: Implement DELETE request \ No newline at end of file
diff --git a/libgpl/LICENSE b/libgpl/LICENSE
new file mode 100644
index 0000000..56c3b5b
--- /dev/null
+++ b/libgpl/LICENSE
@@ -0,0 +1,671 @@
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/libgpl/README b/libgpl/README
new file mode 100644
index 0000000..df9059f
--- /dev/null
+++ b/libgpl/README
@@ -0,0 +1,8 @@
+libgpl
+------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/
+
+
+MyRoundcube Dev Team
+www.myroundcube.com \ No newline at end of file
diff --git a/libgpl/caldav/caldav-client.php b/libgpl/caldav/caldav-client.php
new file mode 100644
index 0000000..417c42b
--- /dev/null
+++ b/libgpl/caldav/caldav-client.php
@@ -0,0 +1,468 @@
+<?php
+
+/**
+ * CalDAV Client
+ *
+ * @version @package_version@
+ * @author Daniel Morlock <daniel.morlock@awesome-it.de>
+ *
+ * Copyright (C) 2013, Awesome IT GbR <info@awesome-it.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require_once (dirname(__FILE__).'/../../libcalendaring/SabreDAV/vendor/autoload.php');
+require_once (dirname(__FILE__).'/vobject_sanitize.php');
+
+
+class caldav_client extends Sabre\DAV\Client
+{
+ const CLARK_GETCTAG = '{http://calendarserver.org/ns/}getctag';
+ const CLARK_GETETAG = '{DAV:}getetag';
+ const CLARK_CALDATA = '{urn:ietf:params:xml:ns:caldav}calendar-data';
+
+ public $base_uri;
+ public $path;
+ private $libvcal;
+ private $rc;
+ private $user_agent;
+
+ /**
+ * Default constructor for CalDAV client.
+ *
+ * @param string Caldav URI to appropriate calendar.
+ * @param string Username for HTTP basic auth.
+ * @param string Password for HTTP basic auth.
+ * @param boolean Verify SSL cert. // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1)
+ */
+ public function __construct($uri, $user = null, $pass = null, $verifySSL = array(true, true)) // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1)
+ {
+ $this->user_agent = 'MyRoundcube-SabreDAV/' . Sabre\DAV\Version::VERSION;
+
+ // Include libvcalendar on demand ...
+ if(!class_exists("libvcalendar"))
+ require_once (dirname(__FILE__).'/../../libcalendaring/libvcalendar.php');
+
+ $this->libvcal = new libvcalendar();
+ $this->rc = rcube::get_instance();
+
+ $tokens = parse_url($uri);
+ $this->base_uri = $tokens['scheme']."://".$tokens['host'].($tokens['port'] ? ":".$tokens['port'] : null);
+ $this->path = $tokens['path'].($tokens['query'] ? "?".$tokens['query'] : null);
+ $settings = array(
+ 'baseUri' => $this->base_uri,
+ 'authType' => Sabre\DAV\Client::AUTH_BASIC
+ );
+
+ if ($user) $settings['userName'] = $user;
+ if ($pass) $settings['password'] = $pass;
+
+ parent::__construct($settings);
+
+ $this->verifyPeer = $verifySSL[0];
+ $this->verifyHost = $verifySSL[1];
+ $this->authType = CURLAUTH_BASIC | CURLAUTH_ANY;
+ }
+
+ /**
+ * Fetches calendar ctag.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Retrieving_calendar_information
+ * @return Calendar ctag or null on error.
+ */
+ public function get_ctag()
+ {
+ try
+ {
+ $arr = $this->propFind($this->path, array(self::CLARK_GETCTAG));
+
+ if (isset($arr[self::CLARK_GETCTAG]))
+ return $arr[self::CLARK_GETCTAG];
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+
+ return null;
+ }
+
+ /**
+ * Fetches event etags and urls.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Finding_out_if_anything_changed
+ *
+ * @param array Optional list of relative event URL's to retrieve specific etags. If not specified, all etags of the current calendar are returned.
+ * @return array List of etag properties with keys:
+ * url: Event ical path relative to the calendar URL.
+ * etag: Current event etag.
+ */
+ public function get_etags(array $event_urls = array())
+ {
+ $etags = array();
+
+ try
+ {
+ $arr = $this->prop_report($this->path, array(self::CLARK_GETETAG), $event_urls);
+ foreach ($arr as $path => $data)
+ {
+ // Some caldav server return an empty calendar as event where etag is missing. Skip this!
+ if($data[self::CLARK_GETETAG])
+ {
+ array_push($etags, array(
+ "url" => $path,
+ "etag" => str_replace('"', null, $data[self::CLARK_GETETAG])
+ ));
+ }
+ }
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+
+ return $etags;
+ }
+
+ /**
+ * Fetches calendar events.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Downloading_objects
+ * @param array $urls = array() Optional list of event URL's to fetch. If non is specified, all
+ * events from the appropriate calendar will be fetched.
+ * @return Array hash list that maps the events URL to the appropriate event properties.
+ */
+ public function get_events($urls = array())
+ {
+ $events = array();
+
+ try
+ {
+ $vcals = $this->prop_report($this->path, array(
+ self::CLARK_GETETAG,
+ self::CLARK_CALDATA
+ ), $urls);
+
+ foreach ($vcals as $path => $response)
+ {
+ $vcal = $response[self::CLARK_CALDATA];
+ $vobject_sanitize = new vobject_sanitize($vcal, array('CATEGORIES'), 'serialize');
+ $vcal = $vobject_sanitize->vobject;
+ $vobject_sanitize = new vobject_sanitize($vcal, array('RDATE'), 'unserialize');
+ $vcal = $vobject_sanitize->vobject;
+ foreach ($this->libvcal->import($vcal) as $event) {
+ $events[$path] = $event;
+ }
+ }
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+ return $events;
+ }
+
+ /**
+ * Does a REPORT request
+ *
+ * @param string $url
+ * @param array $properties List of requested properties must be specified as an array, in clark
+ * notation.
+ * @param array $event_urls If specified, a multiget report request will be initiated with the
+ * specified event urls.
+ * @param int $depth = 1 Depth should be either 0 or 1. A depth of 1 will cause a request to be
+ * made to the server to also return all child resources.
+ * @return array Hash with ics event path as key and a hash array with properties and appropriate values.
+ */
+ public function prop_report($url, array $properties, array $event_urls = array(), $depth = 1)
+ {
+ $url = slashify($url); // iCloud
+
+ $parent_tag = sizeof($event_urls) > 0 ? "c:calendar-multiget" : "d:propfind";
+ $method = sizeof($event_urls) > 0 ? 'REPORT' : 'PROPFIND';
+
+ $body = '<?xml version="1.0"?>'."\n".'<'.$parent_tag.' xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">'."\n";
+
+ $body .= ' <d:prop>'."\n";
+ foreach ($properties as $property)
+ {
+
+ list($namespace, $elementName) = Sabre\DAV\XMLUtil::parseClarkNotation($property);
+
+ if ($namespace === 'DAV:')
+ {
+ $body .= ' <d:'.$elementName.' />'."\n";
+ }
+ else
+ {
+ $body .= ' <x:'.$elementName.' xmlns:x="'.$namespace.'"/>'."\n";
+ }
+ }
+ $body .= ' </d:prop>'."\n";
+
+ // http://tools.ietf.org/html/rfc4791#page-90
+ // http://www.bedework.org/trac/bedework/wiki/Bedework/DevDocs/Filters
+ /*
+ if($start && $end)
+ {
+ $body.= ' <c:filter>'."\n".
+ ' <c:comp-filter name="VCALENDAR">'."\n".
+ ' <c:comp-filter name="VEVENT">'."\n".
+ ' <c:time-range start="'.$start.'" end="'.$end.'" />'."\n".
+ ' </c:comp-filter>'."\n".
+ ' </c:comp-filter>'."\n".
+ ' </c:filter>' . "\n";
+ }
+ */
+
+ foreach ($event_urls as $event_url)
+ {
+ $body .= '<d:href>'.$event_url.'</d:href>'."\n";
+ }
+
+ $body .= '</'.$parent_tag.'>';
+
+ $response = $this->request($method, $url, $body, array(
+ 'Depth' => $depth,
+ 'Content-Type' => 'application/xml',
+ 'User-Agent' => $this->user_agent
+ ));
+
+ $result = $this->parseMultiStatus($response['body']);
+
+ // If depth was 0, we only return the top item
+ if ($depth === 0)
+ {
+ reset($result);
+ $result = current($result);
+ return isset($result[200]) ? $result[200] : array();
+ }
+
+ $new_result = array();
+ foreach ($result as $href => $status_list)
+ {
+ $new_result[$href] = isset($status_list[200]) ? $status_list[200] : array();
+ }
+
+ return $new_result;
+ }
+
+ /**
+ * Updates or creates a calendar event.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Updating_a_calendar_object
+ * @param string Event ics path for the event.
+ * @param array Hash array with event properties.
+ * @param string Current event etag to match against server data. Pass null for new events.
+ * @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error.
+ */
+ public function put_event($path, $event, $etag = null)
+ {
+ try
+ {
+ $headers = array(
+ 'Content-Type' => 'text/calendar; charset=utf-8',
+ 'User-Agent' => $this->user_agent
+ );
+ if ($etag) $headers["If-Match"] = '"'.$etag.'"';
+
+ // Temporarily disable error reporting since libvcal seems not checking array key properly.
+ // TODO: Remove this todo if we could ensure that those errors come not from incomplete event properties.
+ //$err_rep = error_reporting(E_ERROR);
+ $vcal = $this->libvcal->export(array($event));
+ if (is_array($vcal))
+ $vcal = array_shift($vcal);
+
+ //error_reporting($err_rep);
+ $response = $this->request('PUT', $path, $vcal, $headers);
+
+ // Following http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Creating_a_calendar_object, the
+ // caldav server must not always return the new etag.
+
+ return $response["statusCode"] == 201 || // 201 (created, successfully created)
+ $response["statusCode"] == 204; // 204 (no content, successfully updated)
+ }
+ catch(Sabre\DAV\Exception\PreconditionFailed $err)
+ {
+ // Event tag not up to date, must be updated first ...
+ return -1;
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+ return false;
+ }
+
+ /**
+ * Removes event of given URL.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Deleting_a_calendar_object
+ * @param string Event ics path for the event.
+ * @param string Current event etag to match against server data. Pass null to force removing the event.
+ * @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error.
+ **/
+ public function remove_event($path, $etag = null)
+ {
+ return $this->delete_request($path, $etag);
+ }
+
+ /**
+ * Fires a DELETE request to a given URL.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Deleting_a_calendar_object
+ * @param string Path.
+ * @param string Current etag to match against server data or null.
+ * @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error.
+ **/
+ public function delete_request($path, $etag = null)
+ {
+ try
+ {
+ $headers = array(
+ 'Content-Type' => 'text/calendar; charset=utf-8',
+ 'User-Agent' => $this->user_agent
+ );
+ if ($etag) $headers["If-Match"] = '"'.$etag.'"';
+
+ $response = $this->request('DELETE', $path, null, $headers);
+ return $response["statusCode"] == 204; // 204 (no content, successfully deleted);
+ }
+ catch(Sabre\DAV\Exception\PreconditionFailed $err)
+ {
+ // Event tag not up to date, must be updated first ...
+ return -1;
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+ return false;
+ }
+
+ /**
+ * Make a propFind query to caldav server
+ * @param string $path absolute or relative URL to Resource
+ * @param array $props list of properties to use for the query. Properties must have clark-notation.
+ * @param int $depth 0 means no recurse while 1 means recurse
+ * @param boolean $log log exception
+ * @return array
+ */
+ public function prop_find($path, $props, $depth, $log = true)
+ {
+ try {
+ $response = $this->propFind($path, $props, $depth);
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), $log, false);
+ }
+ return $response;
+ }
+
+ /**
+ * Add a caldendar collection
+ * @param string collection URL
+ * @parma string displayname
+ * @param string resource type
+ * @param string namespace
+ * @return array response
+ */
+ public function add_collection($url, $displayname, $resourcetype, $namespace)
+ {
+ $body = '<?xml version="1.0" encoding="utf-8" ?>' .
+ '<D:mkcol xmlns:D="DAV:"xmlns:C="urn:ietf:params:xml:ns:' . $namespace . '">' .
+ ' <D:set>' .
+ ' <D:prop>' .
+ ' <D:resourcetype>' .
+ ' <D:collection/> ' .
+ ' <C:' . $resourcetype . '/>' .
+ ' </D:resourcetype>' .
+ ' <D:displayname>' . $displayname . '</D:displayname>' .
+ ' </D:prop>' .
+ ' </D:set>' .
+ ' </D:mkcol>';
+
+ try {
+ $response = $this->request('MKCOL', $url, $body, array(
+ 'Content-Type' => 'application/xml',
+ 'User-Agent' => $this->user_agent
+ ));
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ return false;
+ }
+ return $response;
+ }
+
+ /**
+ * Freebusy request for a given user
+ * @param string username
+ * @param path relative path to base uri
+ * @param integer unix timestamp
+ * @param integer unix timestamp
+ * @retrun array List of busy timeslots within the requested range
+ */
+ public function freebusy($user, $path, $start, $end)
+ {
+ $body = '<?xml version="1.0" encoding="utf-8" ?>' .
+ '<C:free-busy-query xmlns:C="urn:ietf:params:xml:ns:caldav">' .
+ '<C:time-range start="' . gmdate("Ymd\THis\Z", $start) . '"' .
+ ' end="' . gmdate("Ymd\THis\Z", $end) . '"/>' .
+ '</C:free-busy-query>';
+ return $this->request('REPORT', $path, $body, array(
+ 'Content-Type' => 'application/xml',
+ 'Depth' => 1,
+ 'User-Agent' => $this->user_agent
+ ));
+ }
+};
+?>
diff --git a/libgpl/caldav/caldav_sync.php b/libgpl/caldav/caldav_sync.php
new file mode 100644
index 0000000..0266af4
--- /dev/null
+++ b/libgpl/caldav/caldav_sync.php
@@ -0,0 +1,284 @@
+<?php
+/**
+ * CalDAV sync for the Calendar plugin
+ *
+ * @version @package_version@
+ * @author Daniel Morlock <daniel.morlock@awesome-it.de>
+ *
+ * Copyright (C) 2013, Awesome IT GbR <info@awesome-it.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require_once (dirname(__FILE__) . '/caldav-client.php');
+
+class caldav_sync
+{
+ const ACTION_NONE = 1;
+ const ACTION_UPDATE = 2;
+ const ACTION_CREATE = 4;
+
+ private $cal_id = null;
+ private $ctag = null;
+ private $user = null;
+ private $pass = null;
+ private $url = null;
+ private $env;
+
+ public $sync = 0;
+
+ /**
+ * Default constructor for calendar synchronization adapter.
+ *
+ * @param int Calendar id.
+ * @param array Hash array with caldav properties:
+ * url: Caldav calendar URL.
+ * user: Caldav http basic auth user.
+ * pass: Password für caldav user.
+ * ctag: Caldav ctag for calendar.
+ * @param boolean verify SSL Cert // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1)
+ */
+ public function __construct($cal_id, $props, $verifySSL, $env)
+ {
+ $this->env = $env;
+ $this->cal_id = $cal_id;
+
+ $this->url = $props["url"];
+ $this->ctag = isset($props["tag"]) ? $props["tag"] : null;
+ $this->user = isset($props["user"]) ? $props["user"] : null;
+ $this->pass = isset($props["pass"]) ? $props["pass"] : null;
+ $this->sync = isset($props["sync"]) ? $props["sync"] : 0;
+
+ $this->caldav = new caldav_client($this->url, $this->user, $this->pass, $verifySSL); // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1)
+ }
+
+ /**
+ * Getter for current calendar ctag.
+ * @return string
+ */
+ public function get_ctag()
+ {
+ return $this->ctag;
+ }
+
+ /**
+ * Determines whether current calendar needs to be synced
+ * regarding the CalDAV ctag.
+ *
+ * @return True if the current calendar ctag differs from the CalDAV tag which
+ * indicates that there are changes that must be synched. Returns false
+ * if the calendar is up to date, no sync necesarry.
+ */
+ public function is_synced($force = false)
+ {
+ $is_synced = $this->ctag == $this->caldav->get_ctag() && $this->ctag;
+ $env = $this->env;
+ $env::debug_log("Ctag indicates that calendar \"$this->cal_id\" ".($is_synced ? "is synced." : "needs update!"));
+
+ return $is_synced;
+ }
+
+ /**
+ * Synchronizes given events with caldav server and returns updates.
+ *
+ * @param array List of local events.
+ * @param array List of caldav properties for each event.
+ * @return array Tuple containing the following lists:
+ *
+ * Caldav properties for events to be created or to be updated with the keys:
+ * url: Event ical URL relative to calendar URL
+ * etag: Remote etag of the event
+ * local_event: The local event in case of an update.
+ * remote_event: The current event retrieved from caldav server.
+ *
+ * A list of event ids that are in sync.
+ */
+ public function get_updates($events, $caldav_props)
+ {
+ $ctag = $this->caldav->get_ctag();
+
+ if($ctag)
+ {
+ $this->ctag = $ctag;
+ $etags = $this->caldav->get_etags();
+ list($updates, $synced_event_ids) = $this->_get_event_updates($events, $caldav_props, $etags);
+ return array($this->_get_event_data($updates), $synced_event_ids);
+ }
+ else
+ {
+ $env = $this->env;
+ $env::debug_log("Unkown error while fetching calendar ctag for calendar \"$this->cal_id\"!");
+ }
+
+ return null;
+ }
+
+ /**
+ * Determines sync status and requried updates for the given events using given list of etags.
+ *
+ * @param array List of local events.
+ * @param array List of caldav properties for each event.
+ * @param array List of current remote etags.
+ * @return array Tuple containing the following lists:
+ *
+ * Caldav properties for events to be created or to be updated with the keys:
+ * url: Event ical URL relative to calendar URL
+ * etag: Remote etag of the event
+ * local_event: The local event in case of an update.
+ *
+ * A list of event ids that are in sync.
+ */
+ private function _get_event_updates($events, $caldav_props, $etags)
+ {
+ $updates = array();
+ $in_sync = array();
+
+ foreach ($etags as $etag)
+ {
+ $url = $etag["url"];
+ $etag = $etag["etag"];
+ $event_found = false;
+ for($i = 0; $i < sizeof($events); $i ++)
+ {
+ if ($caldav_props[$i]["url"] == $url)
+ {
+ $event_found = true;
+
+ if ($caldav_props[$i]["tag"] != $etag)
+ {
+ $env = $this->env;
+ $env::debug_log("Event ".$events[$i]["uid"]." needs update.");
+
+ array_push($updates, array(
+ "local_event" => $events[$i],
+ "etag" => $etag,
+ "url" => $url
+ ));
+ }
+ else
+ {
+ array_push($in_sync, $events[$i]["id"]);
+ }
+ }
+ }
+
+ if (!$event_found)
+ {
+ $env = $this->env;
+ $env::debug_log("Found new event ".$url);
+
+ array_push($updates, array(
+ "url" => $url,
+ "etag" => $etag
+ ));
+ }
+ }
+
+ return array($updates, $in_sync);
+ }
+
+ /**
+ * Fetches event data and attaches it to the given update properties.
+ *
+ * @param $updates List of update properties.
+ * @return array List of update properties with additional key "remote_event" containing the current caldav event.
+ */
+ private function _get_event_data($updates)
+ {
+ $urls = array();
+
+ foreach ($updates as $update)
+ {
+ array_push($urls, $update["url"]);
+ }
+
+ $events = $this->caldav->get_events($urls);
+
+ foreach($updates as &$update)
+ {
+ // Attach remote events to the appropriate updates.
+ // Note that this assumes unique event URL's!
+ $url = $update["url"];
+ if($events[$url]) {
+ $update["remote_event"] = $events[$url];
+ $update["remote_event"]["calendar"] = $this->cal_id;
+ }
+ }
+
+ return $updates;
+ }
+
+ /**
+ * Creates the given event on the caldav server.
+ *
+ * @param array Hash array with event properties.
+ * @return Caldav properties with created URL on success, false on error.
+ */
+ public function create_event($event)
+ {
+ $props = array(
+ "url" => parse_url($this->url, PHP_URL_PATH)."/".$event["uid"].".ics",
+ "tag" => null
+ );
+
+ $env = $this->env;
+ $env::debug_log("Push new event to url ".$props["url"]);
+ $result = $this->caldav->put_event($props["url"], $event);
+
+ if($result == false || $result < 0) return false;
+ return $props;
+ }
+
+ /**
+ * Updates the given event on the caldav server.
+ *
+ * @param array Hash array with event properties to update.
+ * @param array Hash array with caldav properties "url" and "tag" for the event.
+ * @return True on success, false on error, -1 if the given event/etag is not up to date.
+ */
+ public function update_event($event, $props)
+ {
+ $env = $this->env;
+ $env::debug_log("Updating event uid \"".$event["uid"]."\".");
+ return $this->caldav->put_event($props["url"], $event, $props["tag"]);
+ }
+
+ /**
+ * Removes the given event from the caldav server.
+ *
+ * @param array Hash array with caldav properties "url" and "tag" for the event.
+ * @return True on success, false on error.
+ */
+ public function remove_event($props)
+ {
+ $env = $this->env;
+ $env::debug_log("Removing event url \"".$props["url"]."\".");
+ return $this->caldav->remove_event($props["url"]);
+ }
+
+ /**
+ * Freebusy request for a given user.
+ *
+ * @param string username
+ * @param string relative path to caldav base uri
+ * @param integer unix timestamp
+ * @param integer unix timestamp
+ * @retrun array List of busy timeslots within the requested range
+ */
+ public function freebusy($user, $path, $start, $end)
+ {
+ return $this->caldav->freebusy($user, $path, $start, $end);
+ }
+};
+?> \ No newline at end of file
diff --git a/libgpl/caldav/vobject_sanitize.php b/libgpl/caldav/vobject_sanitize.php
new file mode 100644
index 0000000..9db4b41
--- /dev/null
+++ b/libgpl/caldav/vobject_sanitize.php
@@ -0,0 +1,110 @@
+<?php
+class vobject_sanitize
+{
+ public $vobject;
+ private $components = array('VEVENT', 'VTODO', 'VJOURNAL', 'VFREEBUSY', 'VTIMEZONE', 'VCARD', 'VALARM');
+ private $properties = array();
+
+ public function __construct($vobject, $properties = array(), $method = 'serialize')
+ {
+ $this->vobject = $vobject;
+ $this->properties = (array) $properties;
+ $this->_unfoald();
+ $this->_eol();
+ switch($method){
+ case 'serialize':
+ $this->_serialize();
+ break;
+ case 'unserialize':
+ $this->_unserialize();
+ break;
+ }
+ }
+
+ private function _unfoald()
+ {
+ $data = array();
+ $content = explode("\n", $this->vobject);
+ for($i = 0; $i < count($content); $i++){
+ $line = rtrim($content[$i]);
+ while(isset($content[$i + 1]) && strlen($content[$i + 1]) > 0 && ($content[$i+1]{0} == ' ' || $content[$i + 1]{0} == "\t" )){
+ $line .= rtrim(substr($content[++$i], 1));
+ }
+ $data[] = $line;
+ }
+ $this->vobject = implode(PHP_EOL, $data);
+ }
+
+ private function _eol()
+ {
+ $this->vobject = preg_replace('/\s\s+/', PHP_EOL, $this->vobject);
+ }
+
+ private function _serialize()
+ {
+ $tokens = array();
+ foreach($this->components as $component){
+ $regex = '#BEGIN:' . $component . '(?:(?!BEGIN:' . $component . ').)*?END:' . $component . '#si';
+ preg_match_all($regex, $this->vobject, $matches);
+ foreach($matches as $part){
+ foreach($part as $match){
+ $token = md5($match);
+ $tokens[$token] = $match;
+ $this->vobject = str_replace($match, '***' . $token . '***', $this->vobject);
+ }
+ }
+ foreach($tokens as $token => $content){
+ foreach($this->properties as $property){
+ $content = preg_replace('#' . PHP_EOL . $property . ':#i', PHP_EOL . 'X-ICAL-SANITIZE-' . $property . ':', $content, 1);
+ $content = preg_replace('#' . PHP_EOL . $property . ':#i', ',', $content);
+ $content = str_replace(PHP_EOL . 'X-ICAL-SANITIZE-' . $property . ':', PHP_EOL . $property . ':', $content);
+ $this->vobject = str_replace('***' . $token . '***', $content, $this->vobject);
+ }
+ }
+ }
+ }
+
+ private function _unserialize()
+ {
+ foreach($this->properties as $property){
+ preg_match_all('#' . PHP_EOL . $property . '.*:.*,.*' . PHP_EOL . '#i', $this->vobject, $matches);
+ $content = $this->vobject;
+ if(is_array($matches)){
+ foreach($matches[0] as $match){
+ $temp = explode(':', $match, 2);
+ $field = $temp[0];
+ $values = $temp[1];
+ $properties = explode(';', $field);
+ $tz = false;
+ foreach($properties as $idx => $property){
+ if(strtolower(substr($property, 0, 5)) == 'tzid='){
+ $temp = explode('=', $property, 2);
+ $tz = $temp[1];
+ unset($properties[$idx]);
+ }
+ if(strtolower(substr($property, 0, 6)) == 'value='){
+ $temp = explode('=', $property, 2);
+ $daot = $temp[1];
+ }
+ }
+ $field = implode(';', $properties);
+ $values = explode(',', $values);
+ $line = '';
+ foreach($values as $value){
+ if($tz){
+ $datetime = new DateTime($value, new DateTimeZone($tz));
+ if(strtolower($daot) == 'date-time'){
+ $ts = $datetime->format('U');
+ $value = gmdate('Ymd\THis\Z', $ts);
+ }
+ }
+ $line .= $field . ':' . $value . PHP_EOL;
+ }
+ $content = preg_replace('/\s\s+/', PHP_EOL, str_replace($match, $line, $content));
+ }
+ }
+ $this->vobject = $content;
+ }
+ }
+}
+?> \ No newline at end of file
diff --git a/libgpl/contextmenu/jquery.contextMenu.js b/libgpl/contextmenu/jquery.contextMenu.js
new file mode 100644
index 0000000..103a585
--- /dev/null
+++ b/libgpl/contextmenu/jquery.contextMenu.js
@@ -0,0 +1,1686 @@
+/*!
+ * jQuery contextMenu - Plugin for simple contextMenu handling
+ *
+ * Version: git-master
+ *
+ * Authors: Rodney Rehm, Addy Osmani (patches for FF)
+ * Web: http://medialize.github.com/jQuery-contextMenu/
+ *
+ * Licensed under
+ * MIT License http://www.opensource.org/licenses/mit-license
+ * GPL v3 http://opensource.org/licenses/GPL-3.0
+ *
+ */
+
+(function($, undefined){
+
+ // TODO: -
+ // ARIA stuff: menuitem, menuitemcheckbox und menuitemradio
+ // create <menu> structure if $.support[htmlCommand || htmlMenuitem] and !opt.disableNative
+
+// determine html5 compatibility
+$.support.htmlMenuitem = ('HTMLMenuItemElement' in window);
+$.support.htmlCommand = ('HTMLCommandElement' in window);
+$.support.eventSelectstart = ("onselectstart" in document.documentElement);
+/* // should the need arise, test for css user-select
+$.support.cssUserSelect = (function(){
+ var t = false,
+ e = document.createElement('div');
+
+ $.each('Moz|Webkit|Khtml|O|ms|Icab|'.split('|'), function(i, prefix) {
+ var propCC = prefix + (prefix ? 'U' : 'u') + 'serSelect',
+ prop = (prefix ? ('-' + prefix.toLowerCase() + '-') : '') + 'user-select';
+
+ e.style.cssText = prop + ': text;';
+ if (e.style[propCC] == 'text') {
+ t = true;
+ return false;
+ }
+
+ return true;
+ });
+
+ return t;
+})();
+*/
+
+if (!$.ui || !$.ui.widget) {
+ // duck punch $.cleanData like jQueryUI does to get that remove event
+ // https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js#L16-24
+ var _cleanData = $.cleanData;
+ $.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ try {
+ $( elem ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ }
+ _cleanData( elems );
+ };
+}
+
+var // currently active contextMenu trigger
+ $currentTrigger = null,
+ // is contextMenu initialized with at least one menu?
+ initialized = false,
+ // window handle
+ $win = $(window),
+ // number of registered menus
+ counter = 0,
+ // mapping selector to namespace
+ namespaces = {},
+ // mapping namespace to options
+ menus = {},
+ // custom command type handlers
+ types = {},
+ // default values
+ defaults = {
+ // selector of contextMenu trigger
+ selector: null,
+ // where to append the menu to
+ appendTo: null,
+ // method to trigger context menu ["right", "left", "hover"]
+ trigger: "right",
+ // hide menu when mouse leaves trigger / menu elements
+ autoHide: false,
+ // ms to wait before showing a hover-triggered context menu
+ delay: 200,
+ // flag denoting if a second trigger should simply move (true) or rebuild (false) an open menu
+ // as long as the trigger happened on one of the trigger-element's child nodes
+ reposition: true,
+ // determine position to show menu at
+ determinePosition: function($menu) {
+ // position to the lower middle of the trigger element
+ if ($.ui && $.ui.position) {
+ // .position() is provided as a jQuery UI utility
+ // (...and it won't work on hidden elements)
+ $menu.css('display', 'block').position({
+ my: "center top",
+ at: "center bottom",
+ of: this,
+ offset: "0 5",
+ collision: "fit"
+ }).css('display', 'none');
+ } else {
+ // determine contextMenu position
+ var offset = this.offset();
+ offset.top += this.outerHeight();
+ offset.left += this.outerWidth() / 2 - $menu.outerWidth() / 2;
+ $menu.css(offset);
+ }
+ },
+ // position menu
+ position: function(opt, x, y) {
+ var $this = this,
+ offset;
+ // determine contextMenu position
+ if (!x && !y) {
+ opt.determinePosition.call(this, opt.$menu);
+ return;
+ } else if (x === "maintain" && y === "maintain") {
+ // x and y must not be changed (after re-show on command click)
+ offset = opt.$menu.position();
+ } else {
+ // x and y are given (by mouse event)
+ offset = {top: y, left: x};
+ }
+
+ // correct offset if viewport demands it
+ var bottom = $win.scrollTop() + $win.height(),
+ right = $win.scrollLeft() + $win.width(),
+ height = opt.$menu.height(),
+ width = opt.$menu.width();
+
+ if (offset.top + height > bottom) {
+ offset.top -= height;
+ }
+
+ if (offset.left + width > right) {
+ offset.left -= width;
+ }
+
+ opt.$menu.css(offset);
+ },
+ // position the sub-menu
+ positionSubmenu: function($menu) {
+ if ($.ui && $.ui.position) {
+ // .position() is provided as a jQuery UI utility
+ // (...and it won't work on hidden elements)
+ $menu.css('display', 'block').position({
+ my: "left top",
+ at: "right top",
+ of: this,
+ collision: "flipfit fit"
+ }).css('display', '');
+ } else {
+ // determine contextMenu position
+ var offset = {
+ top: 0,
+ left: this.outerWidth()
+ };
+ $menu.css(offset);
+ }
+ },
+ // offset to add to zIndex
+ zIndex: 1,
+ // show hide animation settings
+ animation: {
+ duration: 50,
+ show: 'slideDown',
+ hide: 'slideUp'
+ },
+ // events
+ events: {
+ show: $.noop,
+ hide: $.noop
+ },
+ // default callback
+ callback: null,
+ // list of contextMenu items
+ items: {}
+ },
+ // mouse position for hover activation
+ hoveract = {
+ timer: null,
+ pageX: null,
+ pageY: null
+ },
+ // determine zIndex
+ zindex = function($t) {
+ var zin = 0,
+ $tt = $t;
+
+ while (true) {
+ zin = Math.max(zin, parseInt($tt.css('z-index'), 10) || 0);
+ $tt = $tt.parent();
+ if (!$tt || !$tt.length || "html body".indexOf($tt.prop('nodeName').toLowerCase()) > -1 ) {
+ break;
+ }
+ }
+
+ return zin;
+ },
+ // event handlers
+ handle = {
+ // abort anything
+ abortevent: function(e){
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ },
+
+ // contextmenu show dispatcher
+ contextmenu: function(e) {
+ var $this = $(this);
+
+ // disable actual context-menu
+ e.preventDefault();
+ e.stopImmediatePropagation();
+
+ // abort native-triggered events unless we're triggering on right click
+ if (e.data.trigger != 'right' && e.originalEvent) {
+ return;
+ }
+
+ // abort event if menu is visible for this trigger
+ if ($this.hasClass('context-menu-active')) {
+ return;
+ }
+
+ if (!$this.hasClass('context-menu-disabled')) {
+ // theoretically need to fire a show event at <menu>
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#context-menus
+ // var evt = jQuery.Event("show", { data: data, pageX: e.pageX, pageY: e.pageY, relatedTarget: this });
+ // e.data.$menu.trigger(evt);
+
+ $currentTrigger = $this;
+ if (e.data.build) {
+ var built = e.data.build($currentTrigger, e);
+ // abort if build() returned false
+ if (built === false) {
+ return;
+ }
+
+ // dynamically build menu on invocation
+ e.data = $.extend(true, {}, defaults, e.data, built || {});
+
+ // abort if there are no items to display
+ if (!e.data.items || $.isEmptyObject(e.data.items)) {
+ // Note: jQuery captures and ignores errors from event handlers
+ if (window.console) {
+ (console.error || console.log)("No items specified to show in contextMenu");
+ }
+
+ throw new Error('No Items specified');
+ }
+
+ // backreference for custom command type creation
+ e.data.$trigger = $currentTrigger;
+
+ op.create(e.data);
+ }
+ // show menu
+ op.show.call($this, e.data, e.pageX, e.pageY);
+ }
+ },
+ // contextMenu left-click trigger
+ click: function(e) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ $(this).trigger($.Event("contextmenu", { data: e.data, pageX: e.pageX, pageY: e.pageY }));
+ },
+ // contextMenu right-click trigger
+ mousedown: function(e) {
+ // register mouse down
+ var $this = $(this);
+
+ // hide any previous menus
+ if ($currentTrigger && $currentTrigger.length && !$currentTrigger.is($this)) {
+ $currentTrigger.data('contextMenu').$menu.trigger('contextmenu:hide');
+ }
+
+ // activate on right click
+ if (e.button == 2) {
+ $currentTrigger = $this.data('contextMenuActive', true);
+ }
+ },
+ // contextMenu right-click trigger
+ mouseup: function(e) {
+ // show menu
+ var $this = $(this);
+ if ($this.data('contextMenuActive') && $currentTrigger && $currentTrigger.length && $currentTrigger.is($this) && !$this.hasClass('context-menu-disabled')) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ $currentTrigger = $this;
+ $this.trigger($.Event("contextmenu", { data: e.data, pageX: e.pageX, pageY: e.pageY }));
+ }
+
+ $this.removeData('contextMenuActive');
+ },
+ // contextMenu hover trigger
+ mouseenter: function(e) {
+ var $this = $(this),
+ $related = $(e.relatedTarget),
+ $document = $(document);
+
+ // abort if we're coming from a menu
+ if ($related.is('.context-menu-list') || $related.closest('.context-menu-list').length) {
+ return;
+ }
+
+ // abort if a menu is shown
+ if ($currentTrigger && $currentTrigger.length) {
+ return;
+ }
+
+ hoveract.pageX = e.pageX;
+ hoveract.pageY = e.pageY;
+ hoveract.data = e.data;
+ $document.on('mousemove.contextMenuShow', handle.mousemove);
+ hoveract.timer = setTimeout(function() {
+ hoveract.timer = null;
+ $document.off('mousemove.contextMenuShow');
+ $currentTrigger = $this;
+ $this.trigger($.Event("contextmenu", { data: hoveract.data, pageX: hoveract.pageX, pageY: hoveract.pageY }));
+ }, e.data.delay );
+ },
+ // contextMenu hover trigger
+ mousemove: function(e) {
+ hoveract.pageX = e.pageX;
+ hoveract.pageY = e.pageY;
+ },
+ // contextMenu hover trigger
+ mouseleave: function(e) {
+ // abort if we're leaving for a menu
+ var $related = $(e.relatedTarget);
+ if ($related.is('.context-menu-list') || $related.closest('.context-menu-list').length) {
+ return;
+ }
+
+ try {
+ clearTimeout(hoveract.timer);
+ } catch(e) {}
+
+ hoveract.timer = null;
+ },
+
+ // click on layer to hide contextMenu
+ layerClick: function(e) {
+ var $this = $(this),
+ root = $this.data('contextMenuRoot'),
+ mouseup = false,
+ button = e.button,
+ x = e.pageX,
+ y = e.pageY,
+ target,
+ offset,
+ selectors;
+
+ e.preventDefault();
+ e.stopImmediatePropagation();
+
+ setTimeout(function() {
+ var $window, hideshow, possibleTarget;
+ var triggerAction = ((root.trigger == 'left' && button === 0) || (root.trigger == 'right' && button === 2));
+
+ // find the element that would've been clicked, wasn't the layer in the way
+ if (document.elementFromPoint) {
+ root.$layer.hide();
+ target = document.elementFromPoint(x - $win.scrollLeft(), y - $win.scrollTop());
+ root.$layer.show();
+ }
+
+ if (root.reposition && triggerAction) {
+ if (document.elementFromPoint) {
+ if (root.$trigger.is(target) || root.$trigger.has(target).length) {
+ root.position.call(root.$trigger, root, x, y);
+ return;
+ }
+ } else {
+ offset = root.$trigger.offset();
+ $window = $(window);
+ // while this looks kinda awful, it's the best way to avoid
+ // unnecessarily calculating any positions
+ offset.top += $window.scrollTop();
+ if (offset.top <= e.pageY) {
+ offset.left += $window.scrollLeft();
+ if (offset.left <= e.pageX) {
+ offset.bottom = offset.top + root.$trigger.outerHeight();
+ if (offset.bottom >= e.pageY) {
+ offset.right = offset.left + root.$trigger.outerWidth();
+ if (offset.right >= e.pageX) {
+ // reposition
+ root.position.call(root.$trigger, root, x, y);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (target && triggerAction) {
+ root.$trigger.one('contextmenu:hidden', function() {
+ $(target).contextMenu({x: x, y: y});
+ });
+ }
+
+ root.$menu.trigger('contextmenu:hide');
+ }, 50);
+ },
+ // key handled :hover
+ keyStop: function(e, opt) {
+ if (!opt.isInput) {
+ e.preventDefault();
+ }
+
+ e.stopPropagation();
+ },
+ key: function(e) {
+ var opt = $currentTrigger.data('contextMenu') || {};
+
+ switch (e.keyCode) {
+ case 9:
+ case 38: // up
+ handle.keyStop(e, opt);
+ // if keyCode is [38 (up)] or [9 (tab) with shift]
+ if (opt.isInput) {
+ if (e.keyCode == 9 && e.shiftKey) {
+ e.preventDefault();
+ opt.$selected && opt.$selected.find('input, textarea, select').blur();
+ opt.$menu.trigger('prevcommand');
+ return;
+ } else if (e.keyCode == 38 && opt.$selected.find('input, textarea, select').prop('type') == 'checkbox') {
+ // checkboxes don't capture this key
+ e.preventDefault();
+ return;
+ }
+ } else if (e.keyCode != 9 || e.shiftKey) {
+ opt.$menu.trigger('prevcommand');
+ return;
+ }
+ // omitting break;
+
+ // case 9: // tab - reached through omitted break;
+ case 40: // down
+ handle.keyStop(e, opt);
+ if (opt.isInput) {
+ if (e.keyCode == 9) {
+ e.preventDefault();
+ opt.$selected && opt.$selected.find('input, textarea, select').blur();
+ opt.$menu.trigger('nextcommand');
+ return;
+ } else if (e.keyCode == 40 && opt.$selected.find('input, textarea, select').prop('type') == 'checkbox') {
+ // checkboxes don't capture this key
+ e.preventDefault();
+ return;
+ }
+ } else {
+ opt.$menu.trigger('nextcommand');
+ return;
+ }
+ break;
+
+ case 37: // left
+ handle.keyStop(e, opt);
+ if (opt.isInput || !opt.$selected || !opt.$selected.length) {
+ break;
+ }
+
+ if (!opt.$selected.parent().hasClass('context-menu-root')) {
+ var $parent = opt.$selected.parent().parent();
+ opt.$selected.trigger('contextmenu:blur');
+ opt.$selected = $parent;
+ return;
+ }
+ break;
+
+ case 39: // right
+ handle.keyStop(e, opt);
+ if (opt.isInput || !opt.$selected || !opt.$selected.length) {
+ break;
+ }
+
+ var itemdata = opt.$selected.data('contextMenu') || {};
+ if (itemdata.$menu && opt.$selected.hasClass('context-menu-submenu')) {
+ opt.$selected = null;
+ itemdata.$selected = null;
+ itemdata.$menu.trigger('nextcommand');
+ return;
+ }
+ break;
+
+ case 35: // end
+ case 36: // home
+ if (opt.$selected && opt.$selected.find('input, textarea, select').length) {
+ return;
+ } else {
+ (opt.$selected && opt.$selected.parent() || opt.$menu)
+ .children(':not(.disabled, .not-selectable)')[e.keyCode == 36 ? 'first' : 'last']()
+ .trigger('contextmenu:focus');
+ e.preventDefault();
+ return;
+ }
+ break;
+
+ case 13: // enter
+ handle.keyStop(e, opt);
+ if (opt.isInput) {
+ if (opt.$selected && !opt.$selected.is('textarea, select')) {
+ e.preventDefault();
+ return;
+ }
+ break;
+ }
+ opt.$selected && opt.$selected.trigger('mouseup');
+ return;
+
+ case 32: // space
+ case 33: // page up
+ case 34: // page down
+ // prevent browser from scrolling down while menu is visible
+ handle.keyStop(e, opt);
+ return;
+
+ case 27: // esc
+ handle.keyStop(e, opt);
+ opt.$menu.trigger('contextmenu:hide');
+ return;
+
+ default: // 0-9, a-z
+ var k = (String.fromCharCode(e.keyCode)).toUpperCase();
+ if (opt.accesskeys[k]) {
+ // according to the specs accesskeys must be invoked immediately
+ opt.accesskeys[k].$node.trigger(opt.accesskeys[k].$menu
+ ? 'contextmenu:focus'
+ : 'mouseup'
+ );
+ return;
+ }
+ break;
+ }
+ // pass event to selected item,
+ // stop propagation to avoid endless recursion
+ e.stopPropagation();
+ opt.$selected && opt.$selected.trigger(e);
+ },
+
+ // select previous possible command in menu
+ prevItem: function(e) {
+ e.stopPropagation();
+ var opt = $(this).data('contextMenu') || {};
+
+ // obtain currently selected menu
+ if (opt.$selected) {
+ var $s = opt.$selected;
+ opt = opt.$selected.parent().data('contextMenu') || {};
+ opt.$selected = $s;
+ }
+
+ var $children = opt.$menu.children(),
+ $prev = !opt.$selected || !opt.$selected.prev().length ? $children.last() : opt.$selected.prev(),
+ $round = $prev;
+
+ // skip disabled
+ while ($prev.hasClass('disabled') || $prev.hasClass('not-selectable')) {
+ if ($prev.prev().length) {
+ $prev = $prev.prev();
+ } else {
+ $prev = $children.last();
+ }
+ if ($prev.is($round)) {
+ // break endless loop
+ return;
+ }
+ }
+
+ // leave current
+ if (opt.$selected) {
+ handle.itemMouseleave.call(opt.$selected.get(0), e);
+ }
+
+ // activate next
+ handle.itemMouseenter.call($prev.get(0), e);
+
+ // focus input
+ var $input = $prev.find('input, textarea, select');
+ if ($input.length) {
+ $input.focus();
+ }
+ },
+ // select next possible command in menu
+ nextItem: function(e) {
+ e.stopPropagation();
+ var opt = $(this).data('contextMenu') || {};
+
+ // obtain currently selected menu
+ if (opt.$selected) {
+ var $s = opt.$selected;
+ opt = opt.$selected.parent().data('contextMenu') || {};
+ opt.$selected = $s;
+ }
+
+ var $children = opt.$menu.children(),
+ $next = !opt.$selected || !opt.$selected.next().length ? $children.first() : opt.$selected.next(),
+ $round = $next;
+
+ // skip disabled
+ while ($next.hasClass('disabled') || $next.hasClass('not-selectable')) {
+ if ($next.next().length) {
+ $next = $next.next();
+ } else {
+ $next = $children.first();
+ }
+ if ($next.is($round)) {
+ // break endless loop
+ return;
+ }
+ }
+
+ // leave current
+ if (opt.$selected) {
+ handle.itemMouseleave.call(opt.$selected.get(0), e);
+ }
+
+ // activate next
+ handle.itemMouseenter.call($next.get(0), e);
+
+ // focus input
+ var $input = $next.find('input, textarea, select');
+ if ($input.length) {
+ $input.focus();
+ }
+ },
+
+ // flag that we're inside an input so the key handler can act accordingly
+ focusInput: function(e) {
+ var $this = $(this).closest('.context-menu-item'),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ root.$selected = opt.$selected = $this;
+ root.isInput = opt.isInput = true;
+ },
+ // flag that we're inside an input so the key handler can act accordingly
+ blurInput: function(e) {
+ var $this = $(this).closest('.context-menu-item'),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ root.isInput = opt.isInput = false;
+ },
+
+ // :hover on menu
+ menuMouseenter: function(e) {
+ var root = $(this).data().contextMenuRoot;
+ root.hovering = true;
+ },
+ // :hover on menu
+ menuMouseleave: function(e) {
+ var root = $(this).data().contextMenuRoot;
+ if (root.$layer && root.$layer.is(e.relatedTarget)) {
+ root.hovering = false;
+ }
+ },
+
+ // :hover done manually so key handling is possible
+ itemMouseenter: function(e) {
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ root.hovering = true;
+
+ // abort if we're re-entering
+ if (e && root.$layer && root.$layer.is(e.relatedTarget)) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ }
+
+ // make sure only one item is selected
+ (opt.$menu ? opt : root).$menu
+ .children('.hover').trigger('contextmenu:blur');
+
+ if ($this.hasClass('disabled') || $this.hasClass('not-selectable')) {
+ opt.$selected = null;
+ return;
+ }
+
+ $this.trigger('contextmenu:focus');
+ },
+ // :hover done manually so key handling is possible
+ itemMouseleave: function(e) {
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ if (root !== opt && root.$layer && root.$layer.is(e.relatedTarget)) {
+ root.$selected && root.$selected.trigger('contextmenu:blur');
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ root.$selected = opt.$selected = opt.$node;
+ return;
+ }
+
+ $this.trigger('contextmenu:blur');
+ },
+ // contextMenu item click
+ itemClick: function(e) {
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot,
+ key = data.contextMenuKey,
+ callback;
+
+ // abort if the key is unknown or disabled or is a menu
+ if (!opt.items[key] || $this.is('.disabled, .context-menu-submenu, .context-menu-separator, .not-selectable')) {
+ return;
+ }
+
+ e.preventDefault();
+ e.stopImmediatePropagation();
+
+ if ($.isFunction(root.callbacks[key]) && Object.prototype.hasOwnProperty.call(root.callbacks, key)) {
+ // item-specific callback
+ callback = root.callbacks[key];
+ } else if ($.isFunction(root.callback)) {
+ // default callback
+ callback = root.callback;
+ } else {
+ // no callback, no action
+ return;
+ }
+
+ // hide menu if callback doesn't stop that
+ if (callback.call(root.$trigger, key, root) !== false) {
+ root.$menu.trigger('contextmenu:hide');
+ } else if (root.$menu.parent().length) {
+ op.update.call(root.$trigger, root);
+ }
+ },
+ // ignore click events on input elements
+ inputClick: function(e) {
+ e.stopImmediatePropagation();
+ },
+
+ // hide <menu>
+ hideMenu: function(e, data) {
+ var root = $(this).data('contextMenuRoot');
+ op.hide.call(root.$trigger, root, data && data.force);
+ },
+ // focus <command>
+ focusItem: function(e) {
+ e.stopPropagation();
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ $this.addClass('hover')
+ .siblings('.hover').trigger('contextmenu:blur');
+
+ // remember selected
+ opt.$selected = root.$selected = $this;
+
+ // position sub-menu - do after show so dumb $.ui.position can keep up
+ if (opt.$node) {
+ root.positionSubmenu.call(opt.$node, opt.$menu);
+ }
+ },
+ // blur <command>
+ blurItem: function(e) {
+ e.stopPropagation();
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ $this.removeClass('hover');
+ opt.$selected = null;
+ }
+ },
+ // operations
+ op = {
+ show: function(opt, x, y) {
+ var $trigger = $(this),
+ offset,
+ css = {};
+
+ // hide any open menus
+ $('#context-menu-layer').trigger('mousedown');
+
+ // backreference for callbacks
+ opt.$trigger = $trigger;
+
+ // show event
+ if (opt.events.show.call($trigger, opt) === false) {
+ $currentTrigger = null;
+ return;
+ }
+
+ // create or update context menu
+ op.update.call($trigger, opt);
+
+ // position menu
+ opt.position.call($trigger, opt, x, y);
+
+ // make sure we're in front
+ if (opt.zIndex) {
+ css.zIndex = zindex($trigger) + opt.zIndex;
+ }
+
+ // add layer
+ op.layer.call(opt.$menu, opt, css.zIndex);
+
+ // adjust sub-menu zIndexes
+ opt.$menu.find('ul').css('zIndex', css.zIndex + 1);
+
+ // position and show context menu
+ opt.$menu.css( css )[opt.animation.show](opt.animation.duration, function() {
+ $trigger.trigger('contextmenu:visible');
+ });
+ // make options available and set state
+ $trigger
+ .data('contextMenu', opt)
+ .addClass("context-menu-active");
+
+ // register key handler
+ $(document).off('keydown.contextMenu').on('keydown.contextMenu', handle.key);
+ // register autoHide handler
+ if (opt.autoHide) {
+ // mouse position handler
+ $(document).on('mousemove.contextMenuAutoHide', function(e) {
+ // need to capture the offset on mousemove,
+ // since the page might've been scrolled since activation
+ var pos = $trigger.offset();
+ pos.right = pos.left + $trigger.outerWidth();
+ pos.bottom = pos.top + $trigger.outerHeight();
+
+ if (opt.$layer && !opt.hovering && (!(e.pageX >= pos.left && e.pageX <= pos.right) || !(e.pageY >= pos.top && e.pageY <= pos.bottom))) {
+ // if mouse in menu...
+ opt.$menu.trigger('contextmenu:hide');
+ }
+ });
+ }
+ },
+ hide: function(opt, force) {
+ var $trigger = $(this);
+ if (!opt) {
+ opt = $trigger.data('contextMenu') || {};
+ }
+
+ // hide event
+ if (!force && opt.events && opt.events.hide.call($trigger, opt) === false) {
+ return;
+ }
+
+ // remove options and revert state
+ $trigger
+ .removeData('contextMenu')
+ .removeClass("context-menu-active");
+
+ if (opt.$layer) {
+ // keep layer for a bit so the contextmenu event can be aborted properly by opera
+ setTimeout((function($layer) {
+ return function(){
+ $layer.remove();
+ };
+ })(opt.$layer), 10);
+
+ try {
+ delete opt.$layer;
+ } catch(e) {
+ opt.$layer = null;
+ }
+ }
+
+ // remove handle
+ $currentTrigger = null;
+ // remove selected
+ opt.$menu.find('.hover').trigger('contextmenu:blur');
+ opt.$selected = null;
+ // unregister key and mouse handlers
+ //$(document).off('.contextMenuAutoHide keydown.contextMenu'); // http://bugs.jquery.com/ticket/10705
+ $(document).off('.contextMenuAutoHide').off('keydown.contextMenu');
+ // hide menu
+ opt.$menu && opt.$menu[opt.animation.hide](opt.animation.duration, function (){
+ // tear down dynamically built menu after animation is completed.
+ if (opt.build) {
+ opt.$menu.remove();
+ $.each(opt, function(key, value) {
+ switch (key) {
+ case 'ns':
+ case 'selector':
+ case 'build':
+ case 'trigger':
+ return true;
+
+ default:
+ opt[key] = undefined;
+ try {
+ delete opt[key];
+ } catch (e) {}
+ return true;
+ }
+ });
+ }
+
+ setTimeout(function() {
+ $trigger.trigger('contextmenu:hidden');
+ }, 10);
+ });
+ },
+ create: function(opt, root) {
+ if (root === undefined) {
+ root = opt;
+ }
+ // create contextMenu
+ opt.$menu = $('<ul class="context-menu-list"></ul>').addClass(opt.className || "").data({
+ 'contextMenu': opt,
+ 'contextMenuRoot': root
+ });
+
+ $.each(['callbacks', 'commands', 'inputs'], function(i,k){
+ opt[k] = {};
+ if (!root[k]) {
+ root[k] = {};
+ }
+ });
+
+ root.accesskeys || (root.accesskeys = {});
+
+ // create contextMenu items
+ $.each(opt.items, function(key, item){
+ var $t = $('<li class="context-menu-item"></li>').addClass(item.className || ""),
+ $label = null,
+ $input = null;
+
+ // iOS needs to see a click-event bound to an element to actually
+ // have the TouchEvents infrastructure trigger the click event
+ $t.on('click', $.noop);
+
+ item.$node = $t.data({
+ 'contextMenu': opt,
+ 'contextMenuRoot': root,
+ 'contextMenuKey': key
+ });
+
+ // register accesskey
+ // NOTE: the accesskey attribute should be applicable to any element, but Safari5 and Chrome13 still can't do that
+ if (item.accesskey) {
+ var aks = splitAccesskey(item.accesskey);
+ for (var i=0, ak; ak = aks[i]; i++) {
+ if (!root.accesskeys[ak]) {
+ root.accesskeys[ak] = item;
+ item._name = item.name.replace(new RegExp('(' + ak + ')', 'i'), '<span class="context-menu-accesskey">$1</span>');
+ break;
+ }
+ }
+ }
+
+ if (typeof item == "string") {
+ $t.addClass('context-menu-separator not-selectable');
+ } else if (item.type && types[item.type]) {
+ // run custom type handler
+ types[item.type].call($t, item, opt, root);
+ // register commands
+ $.each([opt, root], function(i,k){
+ k.commands[key] = item;
+ if ($.isFunction(item.callback)) {
+ k.callbacks[key] = item.callback;
+ }
+ });
+ } else {
+ // add label for input
+ if (item.type == 'html') {
+ $t.addClass('context-menu-html not-selectable');
+ } else if (item.type) {
+ $label = $('<label></label>').appendTo($t);
+ $('<span></span>').html(item._name || item.name).appendTo($label);
+ $t.addClass('context-menu-input');
+ opt.hasTypes = true;
+ $.each([opt, root], function(i,k){
+ k.commands[key] = item;
+ k.inputs[key] = item;
+ });
+ } else if (item.items) {
+ item.type = 'sub';
+ }
+
+ switch (item.type) {
+ case 'text':
+ $input = $('<input type="text" value="1" name="" value="">')
+ .attr('name', 'context-menu-input-' + key)
+ .val(item.value || "")
+ .appendTo($label);
+ break;
+
+ case 'textarea':
+ $input = $('<textarea name=""></textarea>')
+ .attr('name', 'context-menu-input-' + key)
+ .val(item.value || "")
+ .appendTo($label);
+
+ if (item.height) {
+ $input.height(item.height);
+ }
+ break;
+
+ case 'checkbox':
+ $input = $('<input type="checkbox" value="1" name="" value="">')
+ .attr('name', 'context-menu-input-' + key)
+ .val(item.value || "")
+ .prop("checked", !!item.selected)
+ .prependTo($label);
+ break;
+
+ case 'radio':
+ $input = $('<input type="radio" value="1" name="" value="">')
+ .attr('name', 'context-menu-input-' + item.radio)
+ .val(item.value || "")
+ .prop("checked", !!item.selected)
+ .prependTo($label);
+ break;
+
+ case 'select':
+ $input = $('<select name="">')
+ .attr('name', 'context-menu-input-' + key)
+ .appendTo($label);
+ if (item.options) {
+ $.each(item.options, function(value, text) {
+ $('<option></option>').val(value).text(text).appendTo($input);
+ });
+ $input.val(item.selected);
+ }
+ break;
+
+ case 'sub':
+ // FIXME: shouldn't this .html() be a .text()?
+ $('<span></span>').html(item._name || item.name).appendTo($t);
+ item.appendTo = item.$node;
+ op.create(item, root);
+ $t.data('contextMenu', item).addClass('context-menu-submenu');
+ item.callback = null;
+ break;
+
+ case 'html':
+ $(item.html).appendTo($t);
+ break;
+
+ default:
+ $.each([opt, root], function(i,k){
+ k.commands[key] = item;
+ if ($.isFunction(item.callback)) {
+ k.callbacks[key] = item.callback;
+ }
+ });
+ // FIXME: shouldn't this .html() be a .text()?
+ $('<span></span>').html(item._name || item.name || "").appendTo($t);
+ break;
+ }
+
+ // disable key listener in <input>
+ if (item.type && item.type != 'sub' && item.type != 'html') {
+ $input
+ .on('focus', handle.focusInput)
+ .on('blur', handle.blurInput);
+
+ if (item.events) {
+ $input.on(item.events, opt);
+ }
+ }
+
+ // add icons
+ if (item.icon) {
+ $t.addClass("icon icon-" + item.icon);
+ }
+ }
+
+ // cache contained elements
+ item.$input = $input;
+ item.$label = $label;
+
+ // attach item to menu
+ $t.appendTo(opt.$menu);
+
+ // Disable text selection
+ if (!opt.hasTypes && $.support.eventSelectstart) {
+ // browsers support user-select: none,
+ // IE has a special event for text-selection
+ // browsers supporting neither will not be preventing text-selection
+ $t.on('selectstart.disableTextSelect', handle.abortevent);
+ }
+ });
+ // attach contextMenu to <body> (to bypass any possible overflow:hidden issues on parents of the trigger element)
+ if (!opt.$node) {
+ opt.$menu.css('display', 'none').addClass('context-menu-root');
+ }
+ opt.$menu.appendTo(opt.appendTo || document.body);
+ },
+ resize: function($menu, nested) {
+ // determine widths of submenus, as CSS won't grow them automatically
+ // position:absolute within position:absolute; min-width:100; max-width:200; results in width: 100;
+ // kinda sucks hard...
+
+ // determine width of absolutely positioned element
+ $menu.css({position: 'absolute', display: 'block'});
+ // don't apply yet, because that would break nested elements' widths
+ // add a pixel to circumvent word-break issue in IE9 - #80
+ $menu.data('width', Math.ceil($menu.width()) + 1);
+ // reset styles so they allow nested elements to grow/shrink naturally
+ $menu.css({
+ position: 'static',
+ minWidth: '0px',
+ maxWidth: '100000px'
+ });
+ // identify width of nested menus
+ $menu.find('> li > ul').each(function() {
+ op.resize($(this), true);
+ });
+ // reset and apply changes in the end because nested
+ // elements' widths wouldn't be calculatable otherwise
+ if (!nested) {
+ $menu.find('ul').andSelf().css({
+ position: '',
+ display: '',
+ minWidth: '',
+ maxWidth: ''
+ }).width(function() {
+ return $(this).data('width');
+ });
+ }
+ },
+ update: function(opt, root) {
+ var $trigger = this;
+ if (root === undefined) {
+ root = opt;
+ op.resize(opt.$menu);
+ }
+ // re-check disabled for each item
+ opt.$menu.children().each(function(){
+ var $item = $(this),
+ key = $item.data('contextMenuKey'),
+ item = opt.items[key],
+ disabled = ($.isFunction(item.disabled) && item.disabled.call($trigger, key, root)) || item.disabled === true;
+
+ // dis- / enable item
+ $item[disabled ? 'addClass' : 'removeClass']('disabled');
+
+ if (item.type) {
+ // dis- / enable input elements
+ $item.find('input, select, textarea').prop('disabled', disabled);
+
+ // update input states
+ switch (item.type) {
+ case 'text':
+ case 'textarea':
+ item.$input.val(item.value || "");
+ break;
+
+ case 'checkbox':
+ case 'radio':
+ item.$input.val(item.value || "").prop('checked', !!item.selected);
+ break;
+
+ case 'select':
+ item.$input.val(item.selected || "");
+ break;
+ }
+ }
+
+ if (item.$menu) {
+ // update sub-menu
+ op.update.call($trigger, item, root);
+ }
+ });
+ },
+ layer: function(opt, zIndex) {
+ // add transparent layer for click area
+ // filter and background for Internet Explorer, Issue #23
+ var $layer = opt.$layer = $('<div id="context-menu-layer" style="position:fixed; z-index:' + zIndex + '; top:0; left:0; opacity: 0; filter: alpha(opacity=0); background-color: #000;"></div>')
+ .css({height: $win.height(), width: $win.width(), display: 'block'})
+ .data('contextMenuRoot', opt)
+ .insertBefore(this)
+ .on('contextmenu', handle.abortevent)
+ .on('mousedown', handle.layerClick);
+
+ // IE6 doesn't know position:fixed;
+ if (!$.support.fixedPosition) {
+ $layer.css({
+ 'position' : 'absolute',
+ 'height' : $(document).height()
+ });
+ }
+
+ return $layer;
+ }
+ };
+
+// split accesskey according to http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#assigned-access-key
+function splitAccesskey(val) {
+ var t = val.split(/\s+/),
+ keys = [];
+
+ for (var i=0, k; k = t[i]; i++) {
+ k = k[0].toUpperCase(); // first character only
+ // theoretically non-accessible characters should be ignored, but different systems, different keyboard layouts, ... screw it.
+ // a map to look up already used access keys would be nice
+ keys.push(k);
+ }
+
+ return keys;
+}
+
+// handle contextMenu triggers
+$.fn.contextMenu = function(operation) {
+ if (operation === undefined) {
+ this.first().trigger('contextmenu');
+ } else if (operation.x && operation.y) {
+ this.first().trigger($.Event("contextmenu", {pageX: operation.x, pageY: operation.y}));
+ } else if (operation === "hide") {
+ var $menu = this.data('contextMenu').$menu;
+ $menu && $menu.trigger('contextmenu:hide');
+ } else if (operation === "destroy") {
+ $.contextMenu("destroy", {context: this});
+ } else if ($.isPlainObject(operation)) {
+ operation.context = this;
+ $.contextMenu("create", operation);
+ } else if (operation) {
+ this.removeClass('context-menu-disabled');
+ } else if (!operation) {
+ this.addClass('context-menu-disabled');
+ }
+
+ return this;
+};
+
+// manage contextMenu instances
+$.contextMenu = function(operation, options) {
+ if (typeof operation != 'string') {
+ options = operation;
+ operation = 'create';
+ }
+
+ if (typeof options == 'string') {
+ options = {selector: options};
+ } else if (options === undefined) {
+ options = {};
+ }
+
+ // merge with default options
+ var o = $.extend(true, {}, defaults, options || {});
+ var $document = $(document);
+ var $context = $document;
+ var _hasContext = false;
+
+ if (!o.context || !o.context.length) {
+ o.context = document;
+ } else {
+ // you never know what they throw at you...
+ $context = $(o.context).first();
+ o.context = $context.get(0);
+ _hasContext = o.context !== document;
+ }
+
+ switch (operation) {
+ case 'create':
+ // no selector no joy
+ if (!o.selector) {
+ throw new Error('No selector specified');
+ }
+ // make sure internal classes are not bound to
+ if (o.selector.match(/.context-menu-(list|item|input)($|\s)/)) {
+ throw new Error('Cannot bind to selector "' + o.selector + '" as it contains a reserved className');
+ }
+ if (!o.build && (!o.items || $.isEmptyObject(o.items))) {
+ throw new Error('No Items specified');
+ }
+ counter ++;
+ o.ns = '.contextMenu' + counter;
+ if (!_hasContext) {
+ namespaces[o.selector] = o.ns;
+ }
+ menus[o.ns] = o;
+
+ // default to right click
+ if (!o.trigger) {
+ o.trigger = 'right';
+ }
+
+ if (!initialized) {
+ // make sure item click is registered first
+ $document
+ .on({
+ 'contextmenu:hide.contextMenu': handle.hideMenu,
+ 'prevcommand.contextMenu': handle.prevItem,
+ 'nextcommand.contextMenu': handle.nextItem,
+ 'contextmenu.contextMenu': handle.abortevent,
+ 'mouseenter.contextMenu': handle.menuMouseenter,
+ 'mouseleave.contextMenu': handle.menuMouseleave
+ }, '.context-menu-list')
+ .on('mouseup.contextMenu', '.context-menu-input', handle.inputClick)
+ .on({
+ 'mouseup.contextMenu': handle.itemClick,
+ 'contextmenu:focus.contextMenu': handle.focusItem,
+ 'contextmenu:blur.contextMenu': handle.blurItem,
+ 'contextmenu.contextMenu': handle.abortevent,
+ 'mouseenter.contextMenu': handle.itemMouseenter,
+ 'mouseleave.contextMenu': handle.itemMouseleave
+ }, '.context-menu-item');
+
+ initialized = true;
+ }
+
+ // engage native contextmenu event
+ $context
+ .on('contextmenu' + o.ns, o.selector, o, handle.contextmenu);
+
+ if (_hasContext) {
+ // add remove hook, just in case
+ $context.on('remove' + o.ns, function() {
+ $(this).contextMenu("destroy");
+ });
+ }
+
+ switch (o.trigger) {
+ case 'hover':
+ $context
+ .on('mouseenter' + o.ns, o.selector, o, handle.mouseenter)
+ .on('mouseleave' + o.ns, o.selector, o, handle.mouseleave);
+ break;
+
+ case 'left':
+ $context.on('click' + o.ns, o.selector, o, handle.click);
+ break;
+ /*
+ default:
+ // http://www.quirksmode.org/dom/events/contextmenu.html
+ $document
+ .on('mousedown' + o.ns, o.selector, o, handle.mousedown)
+ .on('mouseup' + o.ns, o.selector, o, handle.mouseup);
+ break;
+ */
+ }
+
+ // create menu
+ if (!o.build) {
+ op.create(o);
+ }
+ break;
+
+ case 'destroy':
+ var $visibleMenu;
+ if (_hasContext) {
+ // get proper options
+ var context = o.context;
+ $.each(menus, function(ns, o) {
+ if (o.context !== context) {
+ return true;
+ }
+
+ $visibleMenu = $('.context-menu-list').filter(':visible');
+ if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is($(o.context).find(o.selector))) {
+ $visibleMenu.trigger('contextmenu:hide', {force: true});
+ }
+
+ try {
+ if (menus[o.ns].$menu) {
+ menus[o.ns].$menu.remove();
+ }
+
+ delete menus[o.ns];
+ } catch(e) {
+ menus[o.ns] = null;
+ }
+
+ $(o.context).off(o.ns);
+
+ return true;
+ });
+ } else if (!o.selector) {
+ $document.off('.contextMenu .contextMenuAutoHide');
+ $.each(menus, function(ns, o) {
+ $(o.context).off(o.ns);
+ });
+
+ namespaces = {};
+ menus = {};
+ counter = 0;
+ initialized = false;
+
+ $('#context-menu-layer, .context-menu-list').remove();
+ } else if (namespaces[o.selector]) {
+ $visibleMenu = $('.context-menu-list').filter(':visible');
+ if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is(o.selector)) {
+ $visibleMenu.trigger('contextmenu:hide', {force: true});
+ }
+
+ try {
+ if (menus[namespaces[o.selector]].$menu) {
+ menus[namespaces[o.selector]].$menu.remove();
+ }
+
+ delete menus[namespaces[o.selector]];
+ } catch(e) {
+ menus[namespaces[o.selector]] = null;
+ }
+
+ $document.off(namespaces[o.selector]);
+ }
+ break;
+
+ case 'html5':
+ // if <command> or <menuitem> are not handled by the browser,
+ // or options was a bool true,
+ // initialize $.contextMenu for them
+ if ((!$.support.htmlCommand && !$.support.htmlMenuitem) || (typeof options == "boolean" && options)) {
+ $('menu[type="context"]').each(function() {
+ if (this.id) {
+ $.contextMenu({
+ selector: '[contextmenu=' + this.id +']',
+ items: $.contextMenu.fromMenu(this)
+ });
+ }
+ }).css('display', 'none');
+ }
+ break;
+
+ default:
+ throw new Error('Unknown operation "' + operation + '"');
+ }
+
+ return this;
+};
+
+// import values into <input> commands
+$.contextMenu.setInputValues = function(opt, data) {
+ if (data === undefined) {
+ data = {};
+ }
+
+ $.each(opt.inputs, function(key, item) {
+ switch (item.type) {
+ case 'text':
+ case 'textarea':
+ item.value = data[key] || "";
+ break;
+
+ case 'checkbox':
+ item.selected = data[key] ? true : false;
+ break;
+
+ case 'radio':
+ item.selected = (data[item.radio] || "") == item.value ? true : false;
+ break;
+
+ case 'select':
+ item.selected = data[key] || "";
+ break;
+ }
+ });
+};
+
+// export values from <input> commands
+$.contextMenu.getInputValues = function(opt, data) {
+ if (data === undefined) {
+ data = {};
+ }
+
+ $.each(opt.inputs, function(key, item) {
+ switch (item.type) {
+ case 'text':
+ case 'textarea':
+ case 'select':
+ data[key] = item.$input.val();
+ break;
+
+ case 'checkbox':
+ data[key] = item.$input.prop('checked');
+ break;
+
+ case 'radio':
+ if (item.$input.prop('checked')) {
+ data[item.radio] = item.value;
+ }
+ break;
+ }
+ });
+
+ return data;
+};
+
+// find <label for="xyz">
+function inputLabel(node) {
+ return (node.id && $('label[for="'+ node.id +'"]').val()) || node.name;
+}
+
+// convert <menu> to items object
+function menuChildren(items, $children, counter) {
+ if (!counter) {
+ counter = 0;
+ }
+
+ $children.each(function() {
+ var $node = $(this),
+ node = this,
+ nodeName = this.nodeName.toLowerCase(),
+ label,
+ item;
+
+ // extract <label><input>
+ if (nodeName == 'label' && $node.find('input, textarea, select').length) {
+ label = $node.text();
+ $node = $node.children().first();
+ node = $node.get(0);
+ nodeName = node.nodeName.toLowerCase();
+ }
+
+ /*
+ * <menu> accepts flow-content as children. that means <embed>, <canvas> and such are valid menu items.
+ * Not being the sadistic kind, $.contextMenu only accepts:
+ * <command>, <menuitem>, <hr>, <span>, <p> <input [text, radio, checkbox]>, <textarea>, <select> and of course <menu>.
+ * Everything else will be imported as an html node, which is not interfaced with contextMenu.
+ */
+
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#concept-command
+ switch (nodeName) {
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#the-menu-element
+ case 'menu':
+ item = {name: $node.attr('label'), items: {}};
+ counter = menuChildren(item.items, $node.children(), counter);
+ break;
+
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-a-element-to-define-a-command
+ case 'a':
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-button-element-to-define-a-command
+ case 'button':
+ item = {
+ name: $node.text(),
+ disabled: !!$node.attr('disabled'),
+ callback: (function(){ return function(){ $node.click(); }; })()
+ };
+ break;
+
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-command-element-to-define-a-command
+
+ case 'menuitem':
+ case 'command':
+ switch ($node.attr('type')) {
+ case undefined:
+ case 'command':
+ case 'menuitem':
+ item = {
+ name: $node.attr('label'),
+ disabled: !!$node.attr('disabled'),
+ callback: (function(){ return function(){ $node.click(); }; })()
+ };
+ break;
+
+ case 'checkbox':
+ item = {
+ type: 'checkbox',
+ disabled: !!$node.attr('disabled'),
+ name: $node.attr('label'),
+ selected: !!$node.attr('checked')
+ };
+ break;
+
+ case 'radio':
+ item = {
+ type: 'radio',
+ disabled: !!$node.attr('disabled'),
+ name: $node.attr('label'),
+ radio: $node.attr('radiogroup'),
+ value: $node.attr('id'),
+ selected: !!$node.attr('checked')
+ };
+ break;
+
+ default:
+ item = undefined;
+ }
+ break;
+
+ case 'hr':
+ item = '-------';
+ break;
+
+ case 'input':
+ switch ($node.attr('type')) {
+ case 'text':
+ item = {
+ type: 'text',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ value: $node.val()
+ };
+ break;
+
+ case 'checkbox':
+ item = {
+ type: 'checkbox',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ selected: !!$node.attr('checked')
+ };
+ break;
+
+ case 'radio':
+ item = {
+ type: 'radio',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ radio: !!$node.attr('name'),
+ value: $node.val(),
+ selected: !!$node.attr('checked')
+ };
+ break;
+
+ default:
+ item = undefined;
+ break;
+ }
+ break;
+
+ case 'select':
+ item = {
+ type: 'select',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ selected: $node.val(),
+ options: {}
+ };
+ $node.children().each(function(){
+ item.options[this.value] = $(this).text();
+ });
+ break;
+
+ case 'textarea':
+ item = {
+ type: 'textarea',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ value: $node.val()
+ };
+ break;
+
+ case 'label':
+ break;
+
+ default:
+ item = {type: 'html', html: $node.clone(true)};
+ break;
+ }
+
+ if (item) {
+ counter++;
+ items['key' + counter] = item;
+ }
+ });
+
+ return counter;
+}
+
+// convert html5 menu
+$.contextMenu.fromMenu = function(element) {
+ var $this = $(element),
+ items = {};
+
+ menuChildren(items, $this.children());
+
+ return items;
+};
+
+// make defaults accessible
+$.contextMenu.defaults = defaults;
+$.contextMenu.types = types;
+// export internal functions - undocumented, for hacking only!
+$.contextMenu.handle = handle;
+$.contextMenu.op = op;
+$.contextMenu.menus = menus;
+
+})(jQuery);
diff --git a/libgpl/contextmenu/jquery.ui.position.js b/libgpl/contextmenu/jquery.ui.position.js
new file mode 100644
index 0000000..08ce445
--- /dev/null
+++ b/libgpl/contextmenu/jquery.ui.position.js
@@ -0,0 +1,497 @@
+/*!
+ * jQuery UI Position v1.10.0
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/position/
+ */
+(function( $, undefined ) {
+
+$.ui = $.ui || {};
+
+var cachedScrollbarWidth,
+ max = Math.max,
+ abs = Math.abs,
+ round = Math.round,
+ rhorizontal = /left|center|right/,
+ rvertical = /top|center|bottom/,
+ roffset = /[\+\-]\d+%?/,
+ rposition = /^\w+/,
+ rpercent = /%$/,
+ _position = $.fn.position;
+
+function getOffsets( offsets, width, height ) {
+ return [
+ parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
+ parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
+ ];
+}
+
+function parseCss( element, property ) {
+ return parseInt( $.css( element, property ), 10 ) || 0;
+}
+
+function getDimensions( elem ) {
+ var raw = elem[0];
+ if ( raw.nodeType === 9 ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: 0, left: 0 }
+ };
+ }
+ if ( $.isWindow( raw ) ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
+ };
+ }
+ if ( raw.preventDefault ) {
+ return {
+ width: 0,
+ height: 0,
+ offset: { top: raw.pageY, left: raw.pageX }
+ };
+ }
+ return {
+ width: elem.outerWidth(),
+ height: elem.outerHeight(),
+ offset: elem.offset()
+ };
+}
+
+$.position = {
+ scrollbarWidth: function() {
+ if ( cachedScrollbarWidth !== undefined ) {
+ return cachedScrollbarWidth;
+ }
+ var w1, w2,
+ div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
+ innerDiv = div.children()[0];
+
+ $( "body" ).append( div );
+ w1 = innerDiv.offsetWidth;
+ div.css( "overflow", "scroll" );
+
+ w2 = innerDiv.offsetWidth;
+
+ if ( w1 === w2 ) {
+ w2 = div[0].clientWidth;
+ }
+
+ div.remove();
+
+ return (cachedScrollbarWidth = w1 - w2);
+ },
+ getScrollInfo: function( within ) {
+ var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
+ overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
+ hasOverflowX = overflowX === "scroll" ||
+ ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
+ hasOverflowY = overflowY === "scroll" ||
+ ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
+ return {
+ width: hasOverflowX ? $.position.scrollbarWidth() : 0,
+ height: hasOverflowY ? $.position.scrollbarWidth() : 0
+ };
+ },
+ getWithinInfo: function( element ) {
+ var withinElement = $( element || window ),
+ isWindow = $.isWindow( withinElement[0] );
+ return {
+ element: withinElement,
+ isWindow: isWindow,
+ offset: withinElement.offset() || { left: 0, top: 0 },
+ scrollLeft: withinElement.scrollLeft(),
+ scrollTop: withinElement.scrollTop(),
+ width: isWindow ? withinElement.width() : withinElement.outerWidth(),
+ height: isWindow ? withinElement.height() : withinElement.outerHeight()
+ };
+ }
+};
+
+$.fn.position = function( options ) {
+ if ( !options || !options.of ) {
+ return _position.apply( this, arguments );
+ }
+
+ // make a copy, we don't want to modify arguments
+ options = $.extend( {}, options );
+
+ var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
+ target = $( options.of ),
+ within = $.position.getWithinInfo( options.within ),
+ scrollInfo = $.position.getScrollInfo( within ),
+ collision = ( options.collision || "flip" ).split( " " ),
+ offsets = {};
+
+ dimensions = getDimensions( target );
+ if ( target[0].preventDefault ) {
+ // force left top to allow flipping
+ options.at = "left top";
+ }
+ targetWidth = dimensions.width;
+ targetHeight = dimensions.height;
+ targetOffset = dimensions.offset;
+ // clone to reuse original targetOffset later
+ basePosition = $.extend( {}, targetOffset );
+
+ // force my and at to have valid horizontal and vertical positions
+ // if a value is missing or invalid, it will be converted to center
+ $.each( [ "my", "at" ], function() {
+ var pos = ( options[ this ] || "" ).split( " " ),
+ horizontalOffset,
+ verticalOffset;
+
+ if ( pos.length === 1) {
+ pos = rhorizontal.test( pos[ 0 ] ) ?
+ pos.concat( [ "center" ] ) :
+ rvertical.test( pos[ 0 ] ) ?
+ [ "center" ].concat( pos ) :
+ [ "center", "center" ];
+ }
+ pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
+ pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
+
+ // calculate offsets
+ horizontalOffset = roffset.exec( pos[ 0 ] );
+ verticalOffset = roffset.exec( pos[ 1 ] );
+ offsets[ this ] = [
+ horizontalOffset ? horizontalOffset[ 0 ] : 0,
+ verticalOffset ? verticalOffset[ 0 ] : 0
+ ];
+
+ // reduce to just the positions without the offsets
+ options[ this ] = [
+ rposition.exec( pos[ 0 ] )[ 0 ],
+ rposition.exec( pos[ 1 ] )[ 0 ]
+ ];
+ });
+
+ // normalize collision option
+ if ( collision.length === 1 ) {
+ collision[ 1 ] = collision[ 0 ];
+ }
+
+ if ( options.at[ 0 ] === "right" ) {
+ basePosition.left += targetWidth;
+ } else if ( options.at[ 0 ] === "center" ) {
+ basePosition.left += targetWidth / 2;
+ }
+
+ if ( options.at[ 1 ] === "bottom" ) {
+ basePosition.top += targetHeight;
+ } else if ( options.at[ 1 ] === "center" ) {
+ basePosition.top += targetHeight / 2;
+ }
+
+ atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
+ basePosition.left += atOffset[ 0 ];
+ basePosition.top += atOffset[ 1 ];
+
+ return this.each(function() {
+ var collisionPosition, using,
+ elem = $( this ),
+ elemWidth = elem.outerWidth(),
+ elemHeight = elem.outerHeight(),
+ marginLeft = parseCss( this, "marginLeft" ),
+ marginTop = parseCss( this, "marginTop" ),
+ collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
+ collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
+ position = $.extend( {}, basePosition ),
+ myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
+
+ if ( options.my[ 0 ] === "right" ) {
+ position.left -= elemWidth;
+ } else if ( options.my[ 0 ] === "center" ) {
+ position.left -= elemWidth / 2;
+ }
+
+ if ( options.my[ 1 ] === "bottom" ) {
+ position.top -= elemHeight;
+ } else if ( options.my[ 1 ] === "center" ) {
+ position.top -= elemHeight / 2;
+ }
+
+ position.left += myOffset[ 0 ];
+ position.top += myOffset[ 1 ];
+
+ // if the browser doesn't support fractions, then round for consistent results
+ if ( !$.support.offsetFractions ) {
+ position.left = round( position.left );
+ position.top = round( position.top );
+ }
+
+ collisionPosition = {
+ marginLeft: marginLeft,
+ marginTop: marginTop
+ };
+
+ $.each( [ "left", "top" ], function( i, dir ) {
+ if ( $.ui.position[ collision[ i ] ] ) {
+ $.ui.position[ collision[ i ] ][ dir ]( position, {
+ targetWidth: targetWidth,
+ targetHeight: targetHeight,
+ elemWidth: elemWidth,
+ elemHeight: elemHeight,
+ collisionPosition: collisionPosition,
+ collisionWidth: collisionWidth,
+ collisionHeight: collisionHeight,
+ offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
+ my: options.my,
+ at: options.at,
+ within: within,
+ elem : elem
+ });
+ }
+ });
+
+ if ( options.using ) {
+ // adds feedback as second argument to using callback, if present
+ using = function( props ) {
+ var left = targetOffset.left - position.left,
+ right = left + targetWidth - elemWidth,
+ top = targetOffset.top - position.top,
+ bottom = top + targetHeight - elemHeight,
+ feedback = {
+ target: {
+ element: target,
+ left: targetOffset.left,
+ top: targetOffset.top,
+ width: targetWidth,
+ height: targetHeight
+ },
+ element: {
+ element: elem,
+ left: position.left,
+ top: position.top,
+ width: elemWidth,
+ height: elemHeight
+ },
+ horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
+ vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
+ };
+ if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
+ feedback.horizontal = "center";
+ }
+ if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
+ feedback.vertical = "middle";
+ }
+ if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
+ feedback.important = "horizontal";
+ } else {
+ feedback.important = "vertical";
+ }
+ options.using.call( this, props, feedback );
+ };
+ }
+
+ elem.offset( $.extend( position, { using: using } ) );
+ });
+};
+
+$.ui.position = {
+ fit: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
+ outerWidth = within.width,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = withinOffset - collisionPosLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
+ newOverRight;
+
+ // element is wider than within
+ if ( data.collisionWidth > outerWidth ) {
+ // element is initially over the left side of within
+ if ( overLeft > 0 && overRight <= 0 ) {
+ newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
+ position.left += overLeft - newOverRight;
+ // element is initially over right side of within
+ } else if ( overRight > 0 && overLeft <= 0 ) {
+ position.left = withinOffset;
+ // element is initially over both left and right sides of within
+ } else {
+ if ( overLeft > overRight ) {
+ position.left = withinOffset + outerWidth - data.collisionWidth;
+ } else {
+ position.left = withinOffset;
+ }
+ }
+ // too far left -> align with left edge
+ } else if ( overLeft > 0 ) {
+ position.left += overLeft;
+ // too far right -> align with right edge
+ } else if ( overRight > 0 ) {
+ position.left -= overRight;
+ // adjust based on position and margin
+ } else {
+ position.left = max( position.left - collisionPosLeft, position.left );
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
+ outerHeight = data.within.height,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = withinOffset - collisionPosTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
+ newOverBottom;
+
+ // element is taller than within
+ if ( data.collisionHeight > outerHeight ) {
+ // element is initially over the top of within
+ if ( overTop > 0 && overBottom <= 0 ) {
+ newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
+ position.top += overTop - newOverBottom;
+ // element is initially over bottom of within
+ } else if ( overBottom > 0 && overTop <= 0 ) {
+ position.top = withinOffset;
+ // element is initially over both top and bottom of within
+ } else {
+ if ( overTop > overBottom ) {
+ position.top = withinOffset + outerHeight - data.collisionHeight;
+ } else {
+ position.top = withinOffset;
+ }
+ }
+ // too far up -> align with top
+ } else if ( overTop > 0 ) {
+ position.top += overTop;
+ // too far down -> align with bottom edge
+ } else if ( overBottom > 0 ) {
+ position.top -= overBottom;
+ // adjust based on position and margin
+ } else {
+ position.top = max( position.top - collisionPosTop, position.top );
+ }
+ }
+ },
+ flip: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.left + within.scrollLeft,
+ outerWidth = within.width,
+ offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = collisionPosLeft - offsetLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
+ myOffset = data.my[ 0 ] === "left" ?
+ -data.elemWidth :
+ data.my[ 0 ] === "right" ?
+ data.elemWidth :
+ 0,
+ atOffset = data.at[ 0 ] === "left" ?
+ data.targetWidth :
+ data.at[ 0 ] === "right" ?
+ -data.targetWidth :
+ 0,
+ offset = -2 * data.offset[ 0 ],
+ newOverRight,
+ newOverLeft;
+
+ if ( overLeft < 0 ) {
+ newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
+ if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overRight > 0 ) {
+ newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
+ if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.top + within.scrollTop,
+ outerHeight = within.height,
+ offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = collisionPosTop - offsetTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
+ top = data.my[ 1 ] === "top",
+ myOffset = top ?
+ -data.elemHeight :
+ data.my[ 1 ] === "bottom" ?
+ data.elemHeight :
+ 0,
+ atOffset = data.at[ 1 ] === "top" ?
+ data.targetHeight :
+ data.at[ 1 ] === "bottom" ?
+ -data.targetHeight :
+ 0,
+ offset = -2 * data.offset[ 1 ],
+ newOverTop,
+ newOverBottom;
+ if ( overTop < 0 ) {
+ newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
+ if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overBottom > 0 ) {
+ newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
+ if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ }
+ },
+ flipfit: {
+ left: function() {
+ $.ui.position.flip.left.apply( this, arguments );
+ $.ui.position.fit.left.apply( this, arguments );
+ },
+ top: function() {
+ $.ui.position.flip.top.apply( this, arguments );
+ $.ui.position.fit.top.apply( this, arguments );
+ }
+ }
+};
+
+// fraction support test
+(function () {
+ var testElement, testElementParent, testElementStyle, offsetLeft, i,
+ body = document.getElementsByTagName( "body" )[ 0 ],
+ div = document.createElement( "div" );
+
+ //Create a "fake body" for testing based on method used in jQuery.support
+ testElement = document.createElement( body ? "div" : "body" );
+ testElementStyle = {
+ visibility: "hidden",
+ width: 0,
+ height: 0,
+ border: 0,
+ margin: 0,
+ background: "none"
+ };
+ if ( body ) {
+ $.extend( testElementStyle, {
+ position: "absolute",
+ left: "-1000px",
+ top: "-1000px"
+ });
+ }
+ for ( i in testElementStyle ) {
+ testElement.style[ i ] = testElementStyle[ i ];
+ }
+ testElement.appendChild( div );
+ testElementParent = body || document.documentElement;
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+ div.style.cssText = "position: absolute; left: 10.7432222px;";
+
+ offsetLeft = $( div ).offset().left;
+ $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
+
+ testElement.innerHTML = "";
+ testElementParent.removeChild( testElement );
+})();
+
+}( jQuery ) );
diff --git a/libgpl/date/date.js b/libgpl/date/date.js
new file mode 100644
index 0000000..984adb5
--- /dev/null
+++ b/libgpl/date/date.js
@@ -0,0 +1,335 @@
+// ===================================================================
+// Author: Matt Kruse <matt@mattkruse.com>
+// WWW: http://www.mattkruse.com/
+//
+// NOTICE: You may use this code for any purpose, commercial or
+// private, without any further permission from the author. You may
+// remove this notice from your final code if you wish, however it is
+// appreciated by the author if at least my web site address is kept.
+//
+// You may *NOT* re-distribute this code in any way except through its
+// use. That means, you can include it in your product, or your web
+// site, or any other form where the code is actually being used. You
+// may not put the plain javascript up on your site for download or
+// include it in your javascript libraries for download.
+// If you wish to share this code with others, please just point them
+// to the URL instead.
+// Please DO NOT link directly to my .js files from your site. Copy
+// the files to your server and use them there. Thank you.
+// ===================================================================
+
+// HISTORY
+// ------------------------------------------------------------------
+// May 17, 2003: Fixed bug in parseDate() for dates <1970
+// March 11, 2003: Added parseDate() function
+// March 11, 2003: Added "NNN" formatting option. Doesn't match up
+// perfectly with SimpleDateFormat formats, but
+// backwards-compatability was required.
+
+// ------------------------------------------------------------------
+// These functions use the same 'format' strings as the
+// java.text.SimpleDateFormat class, with minor exceptions.
+// The format string consists of the following abbreviations:
+//
+// Field | Full Form | Short Form
+// -------------+--------------------+-----------------------
+// Year | yyyy (4 digits) | yy (2 digits), y (2 or 4 digits)
+// Month | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
+// | NNN (abbr.) |
+// Day of Month | dd (2 digits) | d (1 or 2 digits)
+// Day of Week | EE (name) | E (abbr)
+// Hour (1-12) | hh (2 digits) | h (1 or 2 digits)
+// Hour (0-23) | HH (2 digits) | H (1 or 2 digits)
+// Hour (0-11) | KK (2 digits) | K (1 or 2 digits)
+// Hour (1-24) | kk (2 digits) | k (1 or 2 digits)
+// Minute | mm (2 digits) | m (1 or 2 digits)
+// Second | ss (2 digits) | s (1 or 2 digits)
+// AM/PM | a |
+//
+// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
+// Examples:
+// "MMM d, y" matches: January 01, 2000
+// Dec 1, 1900
+// Nov 20, 00
+// "M/d/yy" matches: 01/20/00
+// 9/2/00
+// "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
+// ------------------------------------------------------------------
+
+var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
+var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
+function LZ(x) {return(x<0||x>9?"":"0")+x}
+
+// ------------------------------------------------------------------
+// isDate ( date_string, format_string )
+// Returns true if date string matches format of format string and
+// is a valid date. Else returns false.
+// It is recommended that you trim whitespace around the value before
+// passing it to this function, as whitespace is NOT ignored!
+// ------------------------------------------------------------------
+function isDate(val,format) {
+ var date=getDateFromFormat(val,format);
+ if (date==0) { return false; }
+ return true;
+ }
+
+// -------------------------------------------------------------------
+// compareDates(date1,date1format,date2,date2format)
+// Compare two date strings to see which is greater.
+// Returns:
+// 1 if date1 is greater than date2
+// 0 if date2 is greater than date1 of if they are the same
+// -1 if either of the dates is in an invalid format
+// -------------------------------------------------------------------
+function compareDates(date1,dateformat1,date2,dateformat2) {
+ var d1=getDateFromFormat(date1,dateformat1);
+ var d2=getDateFromFormat(date2,dateformat2);
+ if (d1==0 || d2==0) {
+ return -1;
+ }
+ else if (d1 > d2) {
+ return 1;
+ }
+ return 0;
+ }
+
+// ------------------------------------------------------------------
+// formatDate (date_object, format)
+// Returns a date in the output format specified.
+// The format string uses the same abbreviations as in getDateFromFormat()
+// ------------------------------------------------------------------
+function formatDate(date,format) {
+ format=format+"";
+ var result="";
+ var i_format=0;
+ var c="";
+ var token="";
+ var y=date.getYear()+"";
+ var M=date.getMonth()+1;
+ var d=date.getDate();
+ var E=date.getDay();
+ var H=date.getHours();
+ var m=date.getMinutes();
+ var s=date.getSeconds();
+ var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
+ // Convert real date parts into formatted versions
+ var value=new Object();
+ if (y.length < 4) {y=""+(y-0+1900);}
+ value["y"]=""+y;
+ value["yyyy"]=y;
+ value["yy"]=y.substring(2,4);
+ value["M"]=M;
+ value["MM"]=LZ(M);
+ value["MMM"]=MONTH_NAMES[M-1];
+ value["NNN"]=MONTH_NAMES[M+11];
+ value["d"]=d;
+ value["dd"]=LZ(d);
+ value["E"]=DAY_NAMES[E+7];
+ value["EE"]=DAY_NAMES[E];
+ value["H"]=H;
+ value["HH"]=LZ(H);
+ if (H==0){value["h"]=12;}
+ else if (H>12){value["h"]=H-12;}
+ else {value["h"]=H;}
+ value["hh"]=LZ(value["h"]);
+ if (H>11){value["K"]=H-12;} else {value["K"]=H;}
+ value["k"]=H+1;
+ value["KK"]=LZ(value["K"]);
+ value["kk"]=LZ(value["k"]);
+ if (H > 11) { value["a"]="PM"; }
+ else { value["a"]="AM"; }
+ value["m"]=m;
+ value["mm"]=LZ(m);
+ value["s"]=s;
+ value["ss"]=LZ(s);
+ while (i_format < format.length) {
+ c=format.charAt(i_format);
+ token="";
+ while ((format.charAt(i_format)==c) && (i_format < format.length)) {
+ token += format.charAt(i_format++);
+ }
+ if (value[token] != null) { result=result + value[token]; }
+ else { result=result + token; }
+ }
+ return result;
+ }
+
+// ------------------------------------------------------------------
+// Utility functions for parsing in getDateFromFormat()
+// ------------------------------------------------------------------
+function _isInteger(val) {
+ var digits="1234567890";
+ for (var i=0; i < val.length; i++) {
+ if (digits.indexOf(val.charAt(i))==-1) { return false; }
+ }
+ return true;
+ }
+function _getInt(str,i,minlength,maxlength) {
+ for (var x=maxlength; x>=minlength; x--) {
+ var token=str.substring(i,i+x);
+ if (token.length < minlength) { return null; }
+ if (_isInteger(token)) { return token; }
+ }
+ return null;
+ }
+
+// ------------------------------------------------------------------
+// getDateFromFormat( date_string , format_string )
+//
+// This function takes a date string and a format string. It matches
+// If the date string matches the format string, it returns the
+// getTime() of the date. If it does not match, it returns 0.
+// ------------------------------------------------------------------
+function getDateFromFormat(val,format) {
+ val=val+"";
+ format=format+"";
+ var i_val=0;
+ var i_format=0;
+ var c="";
+ var token="";
+ var token2="";
+ var x,y;
+ var now=new Date();
+ var year=now.getYear();
+ var month=now.getMonth()+1;
+ var date=1;
+ var hh=now.getHours();
+ var mm=now.getMinutes();
+ var ss=now.getSeconds();
+ var ampm="";
+
+ while (i_format < format.length) {
+ // Get next token from format string
+ c=format.charAt(i_format);
+ token="";
+ while ((format.charAt(i_format)==c) && (i_format < format.length)) {
+ token += format.charAt(i_format++);
+ }
+ // Extract contents of value based on format token
+ if (token=="yyyy" || token=="yy" || token=="y") {
+ if (token=="yyyy") { x=4;y=4; }
+ if (token=="yy") { x=2;y=2; }
+ if (token=="y") { x=2;y=4; }
+ year=_getInt(val,i_val,x,y);
+ if (year==null) { return 0; }
+ i_val += year.length;
+ if (year.length==2) {
+ if (year > 70) { year=1900+(year-0); }
+ else { year=2000+(year-0); }
+ }
+ }
+ else if (token=="MMM"||token=="NNN"){
+ month=0;
+ for (var i=0; i<MONTH_NAMES.length; i++) {
+ var month_name=MONTH_NAMES[i];
+ if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
+ if (token=="MMM"||(token=="NNN"&&i>11)) {
+ month=i+1;
+ if (month>12) { month -= 12; }
+ i_val += month_name.length;
+ break;
+ }
+ }
+ }
+ if ((month < 1)||(month>12)){return 0;}
+ }
+ else if (token=="EE"||token=="E"){
+ for (var i=0; i<DAY_NAMES.length; i++) {
+ var day_name=DAY_NAMES[i];
+ if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
+ i_val += day_name.length;
+ break;
+ }
+ }
+ }
+ else if (token=="MM"||token=="M") {
+ month=_getInt(val,i_val,token.length,2);
+ if(month==null||(month<1)||(month>12)){return 0;}
+ i_val+=month.length;}
+ else if (token=="dd"||token=="d") {
+ date=_getInt(val,i_val,token.length,2);
+ if(date==null||(date<1)||(date>31)){return 0;}
+ i_val+=date.length;}
+ else if (token=="hh"||token=="h") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<1)||(hh>12)){return 0;}
+ i_val+=hh.length;}
+ else if (token=="HH"||token=="H") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<0)||(hh>23)){return 0;}
+ i_val+=hh.length;}
+ else if (token=="KK"||token=="K") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<0)||(hh>11)){return 0;}
+ i_val+=hh.length;}
+ else if (token=="kk"||token=="k") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<1)||(hh>24)){return 0;}
+ i_val+=hh.length;hh--;}
+ else if (token=="mm"||token=="m") {
+ mm=_getInt(val,i_val,token.length,2);
+ if(mm==null||(mm<0)||(mm>59)){return 0;}
+ i_val+=mm.length;}
+ else if (token=="ss"||token=="s") {
+ ss=_getInt(val,i_val,token.length,2);
+ if(ss==null||(ss<0)||(ss>59)){return 0;}
+ i_val+=ss.length;}
+ else if (token=="a") {
+ if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
+ else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
+ else {return 0;}
+ i_val+=2;}
+ else {
+ if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
+ else {i_val+=token.length;}
+ }
+ }
+ // If there are any trailing characters left in the value, it doesn't match
+ if (i_val != val.length) { return 0; }
+ // Is date valid for month?
+ if (month==2) {
+ // Check for leap year
+ if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
+ if (date > 29){ return 0; }
+ }
+ else { if (date > 28) { return 0; } }
+ }
+ if ((month==4)||(month==6)||(month==9)||(month==11)) {
+ if (date > 30) { return 0; }
+ }
+ // Correct hours value
+ if (hh<12 && ampm=="PM") { hh=hh-0+12; }
+ else if (hh>11 && ampm=="AM") { hh-=12; }
+ var newdate=new Date(year,month-1,date,hh,mm,ss);
+ return newdate.getTime();
+ }
+
+// ------------------------------------------------------------------
+// parseDate( date_string [, prefer_euro_format] )
+//
+// This function takes a date string and tries to match it to a
+// number of possible date formats to get the value. It will try to
+// match against the following international formats, in this order:
+// y-M-d MMM d, y MMM d,y y-MMM-d d-MMM-y MMM d
+// M/d/y M-d-y M.d.y MMM-d M/d M-d
+// d/M/y d-M-y d.M.y d-MMM d/M d-M
+// A second argument may be passed to instruct the method to search
+// for formats like d/M/y (european format) before M/d/y (American).
+// Returns a Date object or null if no patterns match.
+// ------------------------------------------------------------------
+function parseDate(val) {
+ var preferEuro=(arguments.length==2)?arguments[1]:false;
+ generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
+ monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');
+ dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');
+ var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
+ var d=null;
+ for (var i=0; i<checkList.length; i++) {
+ var l=window[checkList[i]];
+ for (var j=0; j<l.length; j++) {
+ d=getDateFromFormat(val,l[j]);
+ if (d!=0) { return new Date(d); }
+ }
+ }
+ return null;
+ } \ No newline at end of file
diff --git a/libgpl/dialogextend/jquery.dialogextend.js b/libgpl/dialogextend/jquery.dialogextend.js
new file mode 100644
index 0000000..f633829
--- /dev/null
+++ b/libgpl/dialogextend/jquery.dialogextend.js
@@ -0,0 +1,509 @@
+(function() {
+ var $;
+
+ $ = jQuery;
+
+ $.widget("ui.dialogExtend", {
+ version: "2.0.0",
+ modes: {},
+ options: {
+ "closable": true,
+ "dblclick": false,
+ "titlebar": false,
+ "icons": {
+ "close": "ui-icon-closethick",
+ "restore": "ui-icon-newwin"
+ },
+ "load": null,
+ "beforeRestore": null,
+ "restore": null
+ },
+ _create: function() {
+ this._state = "normal";
+ if (!$(this.element[0]).data("ui-dialog")) {
+ $.error("jQuery.dialogExtend Error : Only jQuery UI Dialog element is accepted");
+ }
+ this._verifyOptions();
+ this._initStyles();
+ this._initButtons();
+ this._initTitleBar();
+ this._setState("normal");
+ this._on("load", function(e) {
+ return console.log("test", e);
+ });
+ return this._trigger("load");
+ },
+ _setState: function(state) {
+ $(this.element[0]).removeClass("ui-dialog-" + this._state).addClass("ui-dialog-" + state);
+ return this._state = state;
+ },
+ _verifyOptions: function() {
+ var name, _ref, _results;
+
+ if (this.options.dblclick && !(this.options.dblclick in this.modes)) {
+ $.error("jQuery.dialogExtend Error : Invalid <dblclick> value '" + this.options.dblclick + "'");
+ this.options.dblclick = false;
+ }
+ if (this.options.titlebar && ((_ref = this.options.titlebar) !== "none" && _ref !== "transparent")) {
+ $.error("jQuery.dialogExtend Error : Invalid <titlebar> value '" + this.options.titlebar + "'");
+ this.options.titlebar = false;
+ }
+ _results = [];
+ for (name in this.modes) {
+ if (this["_verifyOptions_" + name]) {
+ _results.push(this["_verifyOptions_" + name]());
+ } else {
+ _results.push(void 0);
+ }
+ }
+ return _results;
+ },
+ _initStyles: function() {
+ var name, style, _results;
+
+ if (!$(".dialog-extend-css").length) {
+ style = '';
+ style += '<style class="dialog-extend-css" type="text/css">';
+ style += '.ui-dialog .ui-dialog-titlebar-buttonpane>a { float: right; }';
+ style += '.ui-dialog .ui-dialog-titlebar-restore { width: 19px; height: 18px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-restore span { display: block; margin: 1px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-restore:hover,';
+ style += '.ui-dialog .ui-dialog-titlebar-restore:focus { padding: 0; }';
+ style += '.ui-dialog .ui-dialog-titlebar ::selection { background-color: transparent; }';
+ style += '</style>';
+ $(style).appendTo("body");
+ }
+ _results = [];
+ for (name in this.modes) {
+ _results.push(this["_initStyles_" + name]());
+ }
+ return _results;
+ },
+ _initButtons: function() {
+ var buttonPane, mode, name, titlebar, _ref,
+ _this = this;
+
+ titlebar = $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar");
+ buttonPane = $('<div class="ui-dialog-titlebar-buttonpane"></div>').appendTo(titlebar);
+ buttonPane.css({
+ "position": "absolute",
+ "top": "50%",
+ "right": "0.3em",
+ "margin-top": "-10px",
+ "height": "18px"
+ });
+ titlebar.find(".ui-dialog-titlebar-close").css({
+ "position": "relative",
+ "float": "right",
+ "top": "auto",
+ "right": "auto",
+ "margin": 0
+ }).find(".ui-icon").removeClass("ui-icon-closethick").addClass(this.options.icons.close).end().appendTo(buttonPane).end();
+ buttonPane.append('<a class="ui-dialog-titlebar-restore ui-corner-all ui-state-default" href="#"><span class="ui-icon ' + this.options.icons.restore + '" title="restore">restore</span></a>').find('.ui-dialog-titlebar-restore').attr("role", "button").mouseover(function() {
+ return $(this).addClass("ui-state-hover");
+ }).mouseout(function() {
+ return $(this).removeClass("ui-state-hover");
+ }).focus(function() {
+ return $(this).addClass("ui-state-focus");
+ }).blur(function() {
+ return $(this).removeClass("ui-state-focus");
+ }).end().find(".ui-dialog-titlebar-close").toggle(this.options.closable).end().find(".ui-dialog-titlebar-restore").hide().click(function(e) {
+ e.preventDefault();
+ return _this.restore();
+ }).end();
+ _ref = this.modes;
+ for (name in _ref) {
+ mode = _ref[name];
+ this._initModuleButton(name, mode);
+ }
+ return titlebar.dblclick(function(evt) {
+ if (_this.options.dblclick) {
+ if (_this._state !== "normal") {
+ return _this.restore();
+ } else {
+ return _this[_this.options.dblclick]();
+ }
+ }
+ }).select(function() {
+ return false;
+ });
+ },
+ _initModuleButton: function(name, mode) {
+ var buttonPane,
+ _this = this;
+
+ buttonPane = $(this.element[0]).dialog("widget").find('.ui-dialog-titlebar-buttonpane');
+ return buttonPane.append('<a class="ui-dialog-titlebar-' + name + ' ui-corner-all ui-state-default" href="#" title="' + name + '"><span class="ui-icon ' + this.options.icons[name] + '">' + name + '</span></a>').find(".ui-dialog-titlebar-" + name).attr("role", "button").mouseover(function() {
+ return $(this).addClass("ui-state-hover");
+ }).mouseout(function() {
+ return $(this).removeClass("ui-state-hover");
+ }).focus(function() {
+ return $(this).addClass("ui-state-focus");
+ }).blur(function() {
+ return $(this).removeClass("ui-state-focus");
+ }).end().find(".ui-dialog-titlebar-" + name).toggle(this.options[mode.option]).click(function(e) {
+ e.preventDefault();
+ return _this[name]();
+ }).end();
+ },
+ _initTitleBar: function() {
+ var handle;
+
+ switch (this.options.titlebar) {
+ case false:
+ return 0;
+ case "none":
+ if ($(this.element[0]).dialog("option", "draggable")) {
+ handle = $("<div />").addClass("ui-dialog-draggable-handle").css("cursor", "move").height(5);
+ $(this.element[0]).dialog("widget").prepend(handle).draggable("option", "handle", handle);
+ }
+ return $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").find(".ui-dialog-title").html("&nbsp;").end().css({
+ "background-color": "transparent",
+ "background-image": "none",
+ "border": 0,
+ "position": "absolute",
+ "right": 0,
+ "top": 0,
+ "z-index": 9999
+ }).end();
+ case "transparent":
+ return $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css({
+ "background-color": "transparent",
+ "background-image": "none",
+ "border": 0
+ });
+ default:
+ return $.error("jQuery.dialogExtend Error : Invalid <titlebar> value '" + this.options.titlebar + "'");
+ }
+ },
+ state: function() {
+ return this._state;
+ },
+ restore: function() {
+ this._trigger("beforeRestore");
+ this._restore();
+ this._toggleButtons();
+ return this._trigger("restore");
+ },
+ _restore: function() {
+ if (this._state !== "normal") {
+ this["_restore_" + this._state]();
+ this._setState("normal");
+ return $(this.element[0]).dialog("widget").focus();
+ }
+ },
+ _saveSnapshot: function() {
+ if (this._state === "normal") {
+ this.original_config_resizable = $(this.element[0]).dialog("option", "resizable");
+ this.original_config_draggable = $(this.element[0]).dialog("option", "draggable");
+ this.original_size_height = $(this.element[0]).dialog("widget").outerHeight();
+ this.original_size_width = $(this.element[0]).dialog("option", "width");
+ this.original_size_maxHeight = $(this.element[0]).dialog("option", "maxHeight");
+ this.original_position_mode = $(this.element[0]).dialog("widget").css("position");
+ this.original_position_left = $(this.element[0]).dialog("widget").offset().left - $('body').scrollLeft();
+ this.original_position_top = $(this.element[0]).dialog("widget").offset().top - $('body').scrollTop();
+ return this.original_titlebar_wrap = $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css("white-space");
+ }
+ },
+ _loadSnapshot: function() {
+ return {
+ "config": {
+ "resizable": this.original_config_resizable,
+ "draggable": this.original_config_draggable
+ },
+ "size": {
+ "height": this.original_size_height,
+ "width": this.original_size_width,
+ "maxHeight": this.original_size_maxHeight
+ },
+ "position": {
+ "mode": this.original_position_mode,
+ "left": this.original_position_left,
+ "top": this.original_position_top
+ },
+ "titlebar": {
+ "wrap": this.original_titlebar_wrap
+ }
+ };
+ },
+ _toggleButtons: function(newstate) {
+ var mode, name, state, _ref, _ref1, _results;
+
+ state = newstate || this._state;
+ $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").toggle(state !== "normal").css({
+ "right": "1.4em"
+ }).end();
+ _ref = this.modes;
+ for (name in _ref) {
+ mode = _ref[name];
+ $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-" + name).toggle(state !== mode.state && this.options[mode.option]);
+ }
+ _ref1 = this.modes;
+ _results = [];
+ for (name in _ref1) {
+ mode = _ref1[name];
+ if (mode.state === state) {
+ _results.push($(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").insertAfter($(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-" + name)).end());
+ } else {
+ _results.push(void 0);
+ }
+ }
+ return _results;
+ }
+ });
+
+}).call(this);
+
+(function() {
+ var $;
+
+ $ = jQuery;
+
+ $.extend(true, $.ui.dialogExtend.prototype, {
+ modes: {
+ "collapse": {
+ option: "collapsable",
+ state: "collapsed"
+ }
+ },
+ options: {
+ "collapsable": false,
+ "icons": {
+ "collapse": "ui-icon-triangle-1-s"
+ },
+ "beforeCollapse": null,
+ "collapse": null
+ },
+ collapse: function() {
+ var newHeight, pos;
+
+ newHeight = $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").height() + 15;
+ this._trigger("beforeCollapse");
+ if (this._state !== "normal") {
+ this._restore();
+ }
+ this._saveSnapshot();
+ pos = $(this.element[0]).dialog("widget").position();
+ $(this.element[0]).dialog("option", {
+ "resizable": false,
+ "height": newHeight,
+ "maxHeight": newHeight,
+ "position": [pos.left - $(document).scrollLeft(), pos.top - $(document).scrollTop()]
+ }).on('dialogclose', this._collapse_restore).hide().dialog("widget").find(".ui-dialog-buttonpane:visible").hide().end().find(".ui-dialog-titlebar").css("white-space", "nowrap").end().find(".ui-dialog-content");
+ this._setState("collapsed");
+ this._toggleButtons();
+ return this._trigger("collapse");
+ },
+ _restore_collapsed: function() {
+ var original;
+
+ original = this._loadSnapshot();
+ return $(this.element[0]).show().dialog("widget").find(".ui-dialog-buttonpane:hidden").show().end().find(".ui-dialog-titlebar").css("white-space", original.titlebar.wrap).end().find(".ui-dialog-content").dialog("option", {
+ "resizable": original.config.resizable,
+ "height": original.size.height,
+ "maxHeight": original.size.maxHeight
+ }).off('dialogclose', this._collapse_restore);
+ },
+ _initStyles_collapse: function() {
+ var style;
+
+ if (!$(".dialog-extend-collapse-css").length) {
+ style = '';
+ style += '<style class="dialog-extend-collapse-css" type="text/css">';
+ style += '.ui-dialog .ui-dialog-titlebar-collapse { width: 19px; height: 18px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-collapse span { display: block; margin: 1px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-collapse:hover,';
+ style += '.ui-dialog .ui-dialog-titlebar-collapse:focus { padding: 0; }';
+ style += '</style>';
+ return $(style).appendTo("body");
+ }
+ },
+ _collapse_restore: function() {
+ return $(this).dialogExtend("restore");
+ }
+ });
+
+}).call(this);
+
+(function() {
+ var $;
+
+ $ = jQuery;
+
+ $.extend(true, $.ui.dialogExtend.prototype, {
+ modes: {
+ "maximize": {
+ option: "maximizable",
+ state: "maximized"
+ }
+ },
+ options: {
+ "maximizable": false,
+ "icons": {
+ "maximize": "ui-icon-extlink"
+ },
+ "beforeMaximize": null,
+ "maximize": null
+ },
+ maximize: function() {
+ var newHeight, newWidth;
+
+ newHeight = $(window).height() - 11;
+ newWidth = $(window).width() - 11;
+ this._trigger("beforeMaximize");
+ if (this._state !== "normal") {
+ this._restore();
+ }
+ this._saveSnapshot();
+ if ($(this.element[0]).dialog("option", "draggable")) {
+ $(this.element[0]).dialog("widget").draggable("option", "handle", null).find(".ui-dialog-draggable-handle").css("cursor", "text").end();
+ }
+ $(this.element[0]).dialog("widget").css("position", "fixed").find(".ui-dialog-content").show().dialog("widget").find(".ui-dialog-buttonpane").show().end().find(".ui-dialog-content").dialog("option", {
+ "resizable": false,
+ "draggable": false,
+ "height": newHeight,
+ "width": newWidth,
+ "position": {
+ my: "left top",
+ at: "left top",
+ of: window
+ }
+ });
+ this._setState("maximized");
+ this._toggleButtons();
+ return this._trigger("maximize");
+ },
+ _restore_maximized: function() {
+ var original;
+
+ original = this._loadSnapshot();
+ $(this.element[0]).dialog("widget").css("position", original.position.mode).find(".ui-dialog-titlebar").css("white-space", original.titlebar.wrap).end().find(".ui-dialog-content").dialog("option", {
+ "resizable": original.config.resizable,
+ "draggable": original.config.draggable,
+ "height": original.size.height,
+ "width": original.size.width,
+ "maxHeight": original.size.maxHeight,
+ "position": {
+ my: "left top",
+ at: "left+" + original.position.left + " top+" + original.position.top,
+ of: window
+ }
+ });
+ if ($(this.element[0]).dialog("option", "draggable")) {
+ return $(this.element[0]).dialog("widget").draggable("option", "handle", $(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle").length ? $(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle") : ".ui-dialog-titlebar").find(".ui-dialog-draggable-handle").css("cursor", "move");
+ }
+ },
+ _initStyles_maximize: function() {
+ var style;
+
+ if (!$(".dialog-extend-maximize-css").length) {
+ style = '';
+ style += '<style class="dialog-extend-maximize-css" type="text/css">';
+ style += '.ui-dialog .ui-dialog-titlebar-maximize { width: 19px; height: 18px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-maximize span { display: block; margin: 1px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-maximize:hover,';
+ style += '.ui-dialog .ui-dialog-titlebar-maximize:focus { padding: 0; }';
+ style += '</style>';
+ return $(style).appendTo("body");
+ }
+ }
+ });
+
+}).call(this);
+
+(function() {
+ var $;
+
+ $ = jQuery;
+
+ $.extend(true, $.ui.dialogExtend.prototype, {
+ modes: {
+ "minimize": {
+ option: "minimizable",
+ state: "minimized"
+ }
+ },
+ options: {
+ "minimizable": false,
+ "minimizeLocation": "left",
+ "icons": {
+ "minimize": "ui-icon-minus"
+ },
+ "beforeMinimize": null,
+ "minimize": null
+ },
+ minimize: function() {
+ var dialogcontrols, fixedContainer, newWidth;
+
+ this._trigger("beforeMinimize");
+ if (this._state !== "normal") {
+ this._restore();
+ }
+ newWidth = 200;
+ if ($("#dialog-extend-fixed-container").length) {
+ fixedContainer = $("#dialog-extend-fixed-container");
+ } else {
+ fixedContainer = $('<div id="dialog-extend-fixed-container"></div>').appendTo("body");
+ fixedContainer.css({
+ "position": "fixed",
+ "bottom": 1,
+ "left": 1,
+ "right": 1,
+ "z-index": 9999
+ });
+ }
+ this._toggleButtons("minimized");
+ dialogcontrols = $(this.element[0]).dialog("widget").clone().children().remove().end();
+ $(this.element[0]).dialog("widget").find('.ui-dialog-titlebar').clone(true, true).appendTo(dialogcontrols);
+ dialogcontrols.css({
+ "float": this.options.minimizeLocation,
+ "margin": 1
+ });
+ fixedContainer.append(dialogcontrols);
+ $(this.element[0]).data("dialog-extend-minimize-controls", dialogcontrols);
+ if ($(this.element[0]).dialog("option", "draggable")) {
+ dialogcontrols.removeClass("ui-draggable");
+ }
+ dialogcontrols.css({
+ "height": "auto",
+ "width": newWidth,
+ "position": "static"
+ });
+ $(this.element[0]).on('dialogbeforeclose', this._minimize_restoreOnClose).dialog("widget").hide();
+ this._setState("minimized");
+ return this._trigger("minimize");
+ },
+ _restore_minimized: function() {
+ $(this.element[0]).dialog("widget").show();
+ $(this.element[0]).off('dialogbeforeclose', this._minimize_restoreOnClose);
+ $(this.element[0]).data("dialog-extend-minimize-controls").remove();
+ return $(this.element[0]).removeData("dialog-extend-minimize-controls");
+ },
+ _initStyles_minimize: function() {
+ var style;
+
+ if (!$(".dialog-extend-minimize-css").length) {
+ style = '';
+ style += '<style class="dialog-extend-minimize-css" type="text/css">';
+ style += '.ui-dialog .ui-dialog-titlebar-minimize { width: 19px; height: 18px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-minimize span { display: block; margin: 1px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-minimize:hover,';
+ style += '.ui-dialog .ui-dialog-titlebar-minimize:focus { padding: 0; }';
+ style += '</style>';
+ return $(style).appendTo("body");
+ }
+ },
+ _verifyOptions_minimize: function() {
+ var _ref;
+
+ if (!this.options.minimizeLocation || ((_ref = this.options.minimizeLocation) !== 'left' && _ref !== 'right')) {
+ $.error("jQuery.dialogExtend Error : Invalid <minimizeLocation> value '" + this.options.minimizeLocation + "'");
+ return this.options.minimizeLocation = "left";
+ }
+ },
+ _minimize_restoreOnClose: function() {
+ return $(this).dialogExtend("restore");
+ }
+ });
+
+}).call(this);
diff --git a/libgpl/dialogextend/jquery.dialogextend.min.js b/libgpl/dialogextend/jquery.dialogextend.min.js
new file mode 100644
index 0000000..0d943a1
--- /dev/null
+++ b/libgpl/dialogextend/jquery.dialogextend.min.js
@@ -0,0 +1,2 @@
+/*! jquery-dialogextend 2.0.3 2014-07-08 */
+(function(){var i;i=jQuery,i.widget("ui.dialogExtend",{version:"2.0.0",modes:{},options:{closable:!0,dblclick:!1,titlebar:!1,icons:{close:"ui-icon-closethick",restore:"ui-icon-newwin"},load:null,beforeRestore:null,restore:null},_create:function(){return this._state="normal",i(this.element[0]).data("ui-dialog")||i.error("jQuery.dialogExtend Error : Only jQuery UI Dialog element is accepted"),this._verifyOptions(),this._initStyles(),this._initButtons(),this._initTitleBar(),this._setState("normal"),this._on("load",function(i){return console.log("test",i)}),this._trigger("load")},_setState:function(t){return i(this.element[0]).removeClass("ui-dialog-"+this._state).addClass("ui-dialog-"+t),this._state=t},_verifyOptions:function(){var t,e,o;!this.options.dblclick||this.options.dblclick in this.modes||(i.error("jQuery.dialogExtend Error : Invalid <dblclick> value '"+this.options.dblclick+"'"),this.options.dblclick=!1),this.options.titlebar&&"none"!==(e=this.options.titlebar)&&"transparent"!==e&&(i.error("jQuery.dialogExtend Error : Invalid <titlebar> value '"+this.options.titlebar+"'"),this.options.titlebar=!1),o=[];for(t in this.modes)this["_verifyOptions_"+t]?o.push(this["_verifyOptions_"+t]()):o.push(void 0);return o},_initStyles:function(){var t,e,o;i(".dialog-extend-css").length||(e="",e+='<style class="dialog-extend-css" type="text/css">',e+=".ui-dialog .ui-dialog-titlebar-buttonpane>a { float: right; }",e+=".ui-dialog .ui-dialog-titlebar-restore { width: 19px; height: 18px; }",e+=".ui-dialog .ui-dialog-titlebar-restore span { display: block; margin: 1px; }",e+=".ui-dialog .ui-dialog-titlebar-restore:hover,",e+=".ui-dialog .ui-dialog-titlebar-restore:focus { padding: 0; }",e+=".ui-dialog .ui-dialog-titlebar ::selection { background-color: transparent; }",e+="</style>",i(e).appendTo("body")),o=[];for(t in this.modes)o.push(this["_initStyles_"+t]());return o},_initButtons:function(){var t,e,o,n,a,l=this;n=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar"),t=i('<div class="ui-dialog-titlebar-buttonpane"></div>').appendTo(n),t.css({position:"absolute",top:"50%",right:"0.3em","margin-top":"-10px",height:"18px"}),n.find(".ui-dialog-titlebar-close").css({position:"relative","float":"right",top:"auto",right:"auto",margin:0}).find(".ui-icon").removeClass("ui-icon-closethick").addClass(this.options.icons.close).end().appendTo(t).end(),t.append('<a class="ui-dialog-titlebar-restore ui-corner-all ui-state-default" href="#"><span class="ui-icon '+this.options.icons.restore+'" title="restore">restore</span></a>').find(".ui-dialog-titlebar-restore").attr("role","button").mouseover(function(){return i(this).addClass("ui-state-hover")}).mouseout(function(){return i(this).removeClass("ui-state-hover")}).focus(function(){return i(this).addClass("ui-state-focus")}).blur(function(){return i(this).removeClass("ui-state-focus")}).end().find(".ui-dialog-titlebar-close").toggle(this.options.closable).end().find(".ui-dialog-titlebar-restore").hide().click(function(i){return i.preventDefault(),l.restore()}).end(),a=this.modes;for(o in a)e=a[o],this._initModuleButton(o,e);return n.dblclick(function(){return l.options.dblclick?"normal"!==l._state?l.restore():l[l.options.dblclick]():void 0}).select(function(){return!1})},_initModuleButton:function(t,e){var o,n=this;return o=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-buttonpane"),o.append('<a class="ui-dialog-titlebar-'+t+' ui-corner-all ui-state-default" href="#" title="'+t+'"><span class="ui-icon '+this.options.icons[t]+'">'+t+"</span></a>").find(".ui-dialog-titlebar-"+t).attr("role","button").mouseover(function(){return i(this).addClass("ui-state-hover")}).mouseout(function(){return i(this).removeClass("ui-state-hover")}).focus(function(){return i(this).addClass("ui-state-focus")}).blur(function(){return i(this).removeClass("ui-state-focus")}).end().find(".ui-dialog-titlebar-"+t).toggle(this.options[e.option]).click(function(i){return i.preventDefault(),n[t]()}).end()},_initTitleBar:function(){var t;switch(this.options.titlebar){case!1:return 0;case"none":return i(this.element[0]).dialog("option","draggable")&&(t=i("<div />").addClass("ui-dialog-draggable-handle").css("cursor","move").height(5),i(this.element[0]).dialog("widget").prepend(t).draggable("option","handle",t)),i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").find(".ui-dialog-title").html("&nbsp;").end().css({"background-color":"transparent","background-image":"none",border:0,position:"absolute",right:0,top:0,"z-index":9999}).end();case"transparent":return i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css({"background-color":"transparent","background-image":"none",border:0});default:return i.error("jQuery.dialogExtend Error : Invalid <titlebar> value '"+this.options.titlebar+"'")}},state:function(){return this._state},restore:function(){return this._trigger("beforeRestore"),this._restore(),this._toggleButtons(),this._trigger("restore")},_restore:function(){return"normal"!==this._state?(this["_restore_"+this._state](),this._setState("normal"),i(this.element[0]).dialog("widget").focus()):void 0},_saveSnapshot:function(){return"normal"===this._state?(this.original_config_resizable=i(this.element[0]).dialog("option","resizable"),this.original_config_draggable=i(this.element[0]).dialog("option","draggable"),this.original_size_height=i(this.element[0]).dialog("widget").outerHeight(),this.original_size_width=i(this.element[0]).dialog("option","width"),this.original_size_maxHeight=i(this.element[0]).dialog("option","maxHeight"),this.original_position_mode=i(this.element[0]).dialog("widget").css("position"),this.original_position_left=i(this.element[0]).dialog("widget").offset().left-i("body").scrollLeft(),this.original_position_top=i(this.element[0]).dialog("widget").offset().top-i("body").scrollTop(),this.original_titlebar_wrap=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css("white-space")):void 0},_loadSnapshot:function(){return{config:{resizable:this.original_config_resizable,draggable:this.original_config_draggable},size:{height:this.original_size_height,width:this.original_size_width,maxHeight:this.original_size_maxHeight},position:{mode:this.original_position_mode,left:this.original_position_left,top:this.original_position_top},titlebar:{wrap:this.original_titlebar_wrap}}},_toggleButtons:function(t){var e,o,n,a,l,s;n=t||this._state,i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").toggle("normal"!==n).css({right:"1.4em"}).end(),a=this.modes;for(o in a)e=a[o],i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-"+o).toggle(n!==e.state&&this.options[e.option]);l=this.modes,s=[];for(o in l)e=l[o],e.state===n?s.push(i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").insertAfter(i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-"+o)).end()):s.push(void 0);return s}})}).call(this),function(){var i;i=jQuery,i.extend(!0,i.ui.dialogExtend.prototype,{modes:{collapse:{option:"collapsable",state:"collapsed"}},options:{collapsable:!1,icons:{collapse:"ui-icon-triangle-1-s"},beforeCollapse:null,collapse:null},collapse:function(){var t,e;return t=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").height()+15,this._trigger("beforeCollapse"),"normal"!==this._state&&this._restore(),this._saveSnapshot(),e=i(this.element[0]).dialog("widget").position(),i(this.element[0]).dialog("option",{resizable:!1,height:t,maxHeight:t,position:[e.left-i(document).scrollLeft(),e.top-i(document).scrollTop()]}).on("dialogclose",this._collapse_restore).hide().dialog("widget").find(".ui-dialog-buttonpane:visible").hide().end().find(".ui-dialog-titlebar").css("white-space","nowrap").end().find(".ui-dialog-content"),this._setState("collapsed"),this._toggleButtons(),this._trigger("collapse")},_restore_collapsed:function(){var t;return t=this._loadSnapshot(),i(this.element[0]).show().dialog("widget").find(".ui-dialog-buttonpane:hidden").show().end().find(".ui-dialog-titlebar").css("white-space",t.titlebar.wrap).end().find(".ui-dialog-content").dialog("option",{resizable:t.config.resizable,height:t.size.height,maxHeight:t.size.maxHeight}).off("dialogclose",this._collapse_restore)},_initStyles_collapse:function(){var t;return i(".dialog-extend-collapse-css").length?void 0:(t="",t+='<style class="dialog-extend-collapse-css" type="text/css">',t+=".ui-dialog .ui-dialog-titlebar-collapse { width: 19px; height: 18px; }",t+=".ui-dialog .ui-dialog-titlebar-collapse span { display: block; margin: 1px; }",t+=".ui-dialog .ui-dialog-titlebar-collapse:hover,",t+=".ui-dialog .ui-dialog-titlebar-collapse:focus { padding: 0; }",t+="</style>",i(t).appendTo("body"))},_collapse_restore:function(){return i(this).dialogExtend("restore")}})}.call(this),function(){var i;i=jQuery,i.extend(!0,i.ui.dialogExtend.prototype,{modes:{maximize:{option:"maximizable",state:"maximized"}},options:{maximizable:!1,icons:{maximize:"ui-icon-extlink"},beforeMaximize:null,maximize:null},maximize:function(){var t,e;return t=i(window).height()-11,e=i(window).width()-11,this._trigger("beforeMaximize"),"normal"!==this._state&&this._restore(),this._saveSnapshot(),i(this.element[0]).dialog("option","draggable")&&i(this.element[0]).dialog("widget").draggable("option","handle",null).find(".ui-dialog-draggable-handle").css("cursor","text").end(),i(this.element[0]).dialog("widget").css("position","fixed").find(".ui-dialog-content").show().dialog("widget").find(".ui-dialog-buttonpane").show().end().find(".ui-dialog-content").dialog("option",{resizable:!1,draggable:!1,height:t,width:e,position:{my:"left top",at:"left top",of:window}}),this._setState("maximized"),this._toggleButtons(),this._trigger("maximize")},_restore_maximized:function(){var t;return t=this._loadSnapshot(),i(this.element[0]).dialog("widget").css("position",t.position.mode).find(".ui-dialog-titlebar").css("white-space",t.titlebar.wrap).end().find(".ui-dialog-content").dialog("option",{resizable:t.config.resizable,draggable:t.config.draggable,height:t.size.height,width:t.size.width,maxHeight:t.size.maxHeight,position:{my:"left top",at:"left+"+t.position.left+" top+"+t.position.top,of:window}}),i(this.element[0]).dialog("option","draggable")?i(this.element[0]).dialog("widget").draggable("option","handle",i(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle").length?i(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle"):".ui-dialog-titlebar").find(".ui-dialog-draggable-handle").css("cursor","move"):void 0},_initStyles_maximize:function(){var t;return i(".dialog-extend-maximize-css").length?void 0:(t="",t+='<style class="dialog-extend-maximize-css" type="text/css">',t+=".ui-dialog .ui-dialog-titlebar-maximize { width: 19px; height: 18px; }",t+=".ui-dialog .ui-dialog-titlebar-maximize span { display: block; margin: 1px; }",t+=".ui-dialog .ui-dialog-titlebar-maximize:hover,",t+=".ui-dialog .ui-dialog-titlebar-maximize:focus { padding: 0; }",t+="</style>",i(t).appendTo("body"))}})}.call(this),function(){var i;i=jQuery,i.extend(!0,i.ui.dialogExtend.prototype,{modes:{minimize:{option:"minimizable",state:"minimized"}},options:{minimizable:!1,minimizeLocation:"left",icons:{minimize:"ui-icon-minus"},beforeMinimize:null,minimize:null},minimize:function(){var t,e,o;return this._trigger("beforeMinimize"),"normal"!==this._state&&this._restore(),o=200,i("#dialog-extend-fixed-container").length?e=i("#dialog-extend-fixed-container"):(e=i('<div id="dialog-extend-fixed-container"></div>').appendTo("body"),e.css({position:"fixed",bottom:1,left:1,right:1,"z-index":9999})),this._toggleButtons("minimized"),t=i(this.element[0]).dialog("widget").clone().children().remove().end(),i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").clone(!0,!0).appendTo(t),t.css({"float":this.options.minimizeLocation,margin:1}),e.append(t),i(this.element[0]).data("dialog-extend-minimize-controls",t),i(this.element[0]).dialog("option","draggable")&&t.removeClass("ui-draggable"),t.css({height:"auto",width:o,position:"static"}),i(this.element[0]).on("dialogbeforeclose",this._minimize_restoreOnClose).dialog("widget").hide(),this._setState("minimized"),this._trigger("minimize")},_restore_minimized:function(){return i(this.element[0]).dialog("widget").show(),i(this.element[0]).off("dialogbeforeclose",this._minimize_restoreOnClose),i(this.element[0]).data("dialog-extend-minimize-controls").remove(),i(this.element[0]).removeData("dialog-extend-minimize-controls")},_initStyles_minimize:function(){var t;return i(".dialog-extend-minimize-css").length?void 0:(t="",t+='<style class="dialog-extend-minimize-css" type="text/css">',t+=".ui-dialog .ui-dialog-titlebar-minimize { width: 19px; height: 18px; }",t+=".ui-dialog .ui-dialog-titlebar-minimize span { display: block; margin: 1px; }",t+=".ui-dialog .ui-dialog-titlebar-minimize:hover,",t+=".ui-dialog .ui-dialog-titlebar-minimize:focus { padding: 0; }",t+="</style>",i(t).appendTo("body"))},_verifyOptions_minimize:function(){var t;return!this.options.minimizeLocation||"left"!==(t=this.options.minimizeLocation)&&"right"!==t?(i.error("jQuery.dialogExtend Error : Invalid <minimizeLocation> value '"+this.options.minimizeLocation+"'"),this.options.minimizeLocation="left"):void 0},_minimize_restoreOnClose:function(){return i(this).dialogExtend("restore")}})}.call(this); \ No newline at end of file
diff --git a/libgpl/encryption/encryption.php b/libgpl/encryption/encryption.php
new file mode 100644
index 0000000..c503109
--- /dev/null
+++ b/libgpl/encryption/encryption.php
@@ -0,0 +1,166 @@
+<?php
+/**
+ * A class to handle secure encryption and decryption of arbitrary data
+ * Copyright http://stackoverflow.com/users/338665/ircmaxell
+ * http://stackoverflow.com/questions/5089841/php-2-way-encryption-i-need-to-store-passwords-that-can-be-retrieved
+ *
+ *
+ * Note that this is not just straight encryption. It also has a few other
+ * features in it to make the encrypted data far more secure. Note that any
+ * other implementations used to decrypt data will have to do the same exact
+ * operations.
+ *
+ * Security Benefits:
+ *
+ * - Uses Key stretching
+ * - Hides the Initialization Vector
+ * - Does HMAC verification of source data
+ *
+ */
+class Encryption {
+
+ /**
+ * @var string $cipher The mcrypt cipher to use for this instance
+ */
+ protected $cipher = '';
+
+ /**
+ * @var int $mode The mcrypt cipher mode to use
+ */
+ protected $mode = '';
+
+ /**
+ * @var int $rounds The number of rounds to feed into PBKDF2 for key generation
+ */
+ protected $rounds = 100;
+
+ /**
+ * Constructor!
+ *
+ * @param string $cipher The MCRYPT_* cypher to use for this instance
+ * @param int $mode The MCRYPT_MODE_* mode to use for this instance
+ * @param int $rounds The number of PBKDF2 rounds to do on the key
+ */
+ public function __construct($cipher, $mode, $rounds = 100) {
+ $this->cipher = $cipher;
+ $this->mode = $mode;
+ $this->rounds = (int) $rounds;
+ }
+
+ /**
+ * Decrypt the data with the provided key
+ *
+ * @param string $data The encrypted datat to decrypt
+ * @param string $key The key to use for decryption
+ *
+ * @returns string|false The returned string if decryption is successful
+ * false if it is not
+ */
+ public function decrypt($data, $key) {
+ $salt = substr($data, 0, 128);
+ $enc = substr($data, 128, -64);
+ $mac = substr($data, -64);
+
+ list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
+
+ if ($mac !== hash_hmac('sha512', $enc, $macKey, true)) {
+ return false;
+ }
+
+ $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);
+
+ $data = $this->unpad($dec);
+
+ return $data;
+ }
+
+ /**
+ * Encrypt the supplied data using the supplied key
+ *
+ * @param string $data The data to encrypt
+ * @param string $key The key to encrypt with
+ *
+ * @returns string The encrypted data
+ */
+ public function encrypt($data, $key) {
+ $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
+ list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
+
+ $data = $this->pad($data);
+
+ $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);
+
+ $mac = hash_hmac('sha512', $enc, $macKey, true);
+ return $salt . $enc . $mac;
+ }
+
+ /**
+ * Generates a set of keys given a random salt and a master key
+ *
+ * @param string $salt A random string to change the keys each encryption
+ * @param string $key The supplied key to encrypt with
+ *
+ * @returns array An array of keys (a cipher key, a mac key, and a IV)
+ */
+ protected function getKeys($salt, $key) {
+ $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
+ $keySize = mcrypt_get_key_size($this->cipher, $this->mode);
+ $length = 2 * $keySize + $ivSize;
+
+ $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);
+
+ $cipherKey = substr($key, 0, $keySize);
+ $macKey = substr($key, $keySize, $keySize);
+ $iv = substr($key, 2 * $keySize);
+ return array($cipherKey, $macKey, $iv);
+ }
+
+ /**
+ * Stretch the key using the PBKDF2 algorithm
+ *
+ * @see http://en.wikipedia.org/wiki/PBKDF2
+ *
+ * @param string $algo The algorithm to use
+ * @param string $key The key to stretch
+ * @param string $salt A random salt
+ * @param int $rounds The number of rounds to derive
+ * @param int $length The length of the output key
+ *
+ * @returns string The derived key.
+ */
+ protected function pbkdf2($algo, $key, $salt, $rounds, $length) {
+ $size = strlen(hash($algo, '', true));
+ $len = ceil($length / $size);
+ $result = '';
+ for ($i = 1; $i <= $len; $i++) {
+ $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
+ $res = $tmp;
+ for ($j = 1; $j < $rounds; $j++) {
+ $tmp = hash_hmac($algo, $tmp, $key, true);
+ $res ^= $tmp;
+ }
+ $result .= $res;
+ }
+ return substr($result, 0, $length);
+ }
+
+ protected function pad($data) {
+ $length = mcrypt_get_block_size($this->cipher, $this->mode);
+ $padAmount = $length - strlen($data) % $length;
+ if ($padAmount == 0) {
+ $padAmount = $length;
+ }
+ return $data . str_repeat(chr($padAmount), $padAmount);
+ }
+
+ protected function unpad($data) {
+ $length = mcrypt_get_block_size($this->cipher, $this->mode);
+ $last = ord($data[strlen($data) - 1]);
+ if ($last > $length) return false;
+ if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) {
+ return false;
+ }
+ return substr($data, 0, -1 * $last);
+ }
+}
+?>
diff --git a/libgpl/fancybox/blank.gif b/libgpl/fancybox/blank.gif
new file mode 100644
index 0000000..35d42e8
--- /dev/null
+++ b/libgpl/fancybox/blank.gif
Binary files differ
diff --git a/libgpl/fancybox/fancy_close.png b/libgpl/fancybox/fancy_close.png
new file mode 100644
index 0000000..0703530
--- /dev/null
+++ b/libgpl/fancybox/fancy_close.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_closebox.png b/libgpl/fancybox/fancy_closebox.png
new file mode 100644
index 0000000..4de4396
--- /dev/null
+++ b/libgpl/fancybox/fancy_closebox.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_left.png b/libgpl/fancybox/fancy_left.png
new file mode 100644
index 0000000..61494e6
--- /dev/null
+++ b/libgpl/fancybox/fancy_left.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_loading.png b/libgpl/fancybox/fancy_loading.png
new file mode 100644
index 0000000..2503017
--- /dev/null
+++ b/libgpl/fancybox/fancy_loading.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_nav_left.png b/libgpl/fancybox/fancy_nav_left.png
new file mode 100644
index 0000000..ebaa6a4
--- /dev/null
+++ b/libgpl/fancybox/fancy_nav_left.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_nav_right.png b/libgpl/fancybox/fancy_nav_right.png
new file mode 100644
index 0000000..873294e
--- /dev/null
+++ b/libgpl/fancybox/fancy_nav_right.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_progress.png b/libgpl/fancybox/fancy_progress.png
new file mode 100644
index 0000000..06b7c89
--- /dev/null
+++ b/libgpl/fancybox/fancy_progress.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_right.png b/libgpl/fancybox/fancy_right.png
new file mode 100644
index 0000000..0a56042
--- /dev/null
+++ b/libgpl/fancybox/fancy_right.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_e.png b/libgpl/fancybox/fancy_shadow_e.png
new file mode 100644
index 0000000..2eda089
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_e.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_n.png b/libgpl/fancybox/fancy_shadow_n.png
new file mode 100644
index 0000000..69aa10e
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_n.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_ne.png b/libgpl/fancybox/fancy_shadow_ne.png
new file mode 100644
index 0000000..79f6980
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_ne.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_nw.png b/libgpl/fancybox/fancy_shadow_nw.png
new file mode 100644
index 0000000..7182cd9
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_nw.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_s.png b/libgpl/fancybox/fancy_shadow_s.png
new file mode 100644
index 0000000..d8858bf
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_s.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_se.png b/libgpl/fancybox/fancy_shadow_se.png
new file mode 100644
index 0000000..541e3ff
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_se.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_sw.png b/libgpl/fancybox/fancy_shadow_sw.png
new file mode 100644
index 0000000..b451689
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_sw.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_w.png b/libgpl/fancybox/fancy_shadow_w.png
new file mode 100644
index 0000000..8a4e4a8
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_w.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_title_left.png b/libgpl/fancybox/fancy_title_left.png
new file mode 100644
index 0000000..6049223
--- /dev/null
+++ b/libgpl/fancybox/fancy_title_left.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_title_main.png b/libgpl/fancybox/fancy_title_main.png
new file mode 100644
index 0000000..8044271
--- /dev/null
+++ b/libgpl/fancybox/fancy_title_main.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_title_over.png b/libgpl/fancybox/fancy_title_over.png
new file mode 100644
index 0000000..d9f458f
--- /dev/null
+++ b/libgpl/fancybox/fancy_title_over.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_title_right.png b/libgpl/fancybox/fancy_title_right.png
new file mode 100644
index 0000000..e36d9db
--- /dev/null
+++ b/libgpl/fancybox/fancy_title_right.png
Binary files differ
diff --git a/libgpl/fancybox/fancybox-x.png b/libgpl/fancybox/fancybox-x.png
new file mode 100644
index 0000000..c2130f8
--- /dev/null
+++ b/libgpl/fancybox/fancybox-x.png
Binary files differ
diff --git a/libgpl/fancybox/fancybox-y.png b/libgpl/fancybox/fancybox-y.png
new file mode 100644
index 0000000..7ef399b
--- /dev/null
+++ b/libgpl/fancybox/fancybox-y.png
Binary files differ
diff --git a/libgpl/fancybox/fancybox.png b/libgpl/fancybox/fancybox.png
new file mode 100644
index 0000000..65e14f6
--- /dev/null
+++ b/libgpl/fancybox/fancybox.png
Binary files differ
diff --git a/libgpl/fancybox/jquery.easing-1.3.pack.js b/libgpl/fancybox/jquery.easing-1.3.pack.js
new file mode 100644
index 0000000..9028179
--- /dev/null
+++ b/libgpl/fancybox/jquery.easing-1.3.pack.js
@@ -0,0 +1,72 @@
+/*
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
+ *
+ * Uses the built in easing capabilities added In jQuery 1.1
+ * to offer multiple easing options
+ *
+ * TERMS OF USE - jQuery Easing
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2008 George McGinley Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+
+// t: current time, b: begInnIng value, c: change In value, d: duration
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('h.i[\'1a\']=h.i[\'z\'];h.O(h.i,{y:\'D\',z:9(x,t,b,c,d){6 h.i[h.i.y](x,t,b,c,d)},17:9(x,t,b,c,d){6 c*(t/=d)*t+b},D:9(x,t,b,c,d){6-c*(t/=d)*(t-2)+b},13:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t+b;6-c/2*((--t)*(t-2)-1)+b},X:9(x,t,b,c,d){6 c*(t/=d)*t*t+b},U:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t+1)+b},R:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t+b;6 c/2*((t-=2)*t*t+2)+b},N:9(x,t,b,c,d){6 c*(t/=d)*t*t*t+b},M:9(x,t,b,c,d){6-c*((t=t/d-1)*t*t*t-1)+b},L:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t+b;6-c/2*((t-=2)*t*t*t-2)+b},K:9(x,t,b,c,d){6 c*(t/=d)*t*t*t*t+b},J:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t*t*t+1)+b},I:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t*t+b;6 c/2*((t-=2)*t*t*t*t+2)+b},G:9(x,t,b,c,d){6-c*8.C(t/d*(8.g/2))+c+b},15:9(x,t,b,c,d){6 c*8.n(t/d*(8.g/2))+b},12:9(x,t,b,c,d){6-c/2*(8.C(8.g*t/d)-1)+b},Z:9(x,t,b,c,d){6(t==0)?b:c*8.j(2,10*(t/d-1))+b},Y:9(x,t,b,c,d){6(t==d)?b+c:c*(-8.j(2,-10*t/d)+1)+b},W:9(x,t,b,c,d){e(t==0)6 b;e(t==d)6 b+c;e((t/=d/2)<1)6 c/2*8.j(2,10*(t-1))+b;6 c/2*(-8.j(2,-10*--t)+2)+b},V:9(x,t,b,c,d){6-c*(8.o(1-(t/=d)*t)-1)+b},S:9(x,t,b,c,d){6 c*8.o(1-(t=t/d-1)*t)+b},Q:9(x,t,b,c,d){e((t/=d/2)<1)6-c/2*(8.o(1-t*t)-1)+b;6 c/2*(8.o(1-(t-=2)*t)+1)+b},P:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6-(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b},H:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6 a*8.j(2,-10*t)*8.n((t*d-s)*(2*8.g)/p)+c+b},T:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d/2)==2)6 b+c;e(!p)p=d*(.3*1.5);e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);e(t<1)6-.5*(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b;6 a*8.j(2,-10*(t-=1))*8.n((t*d-s)*(2*8.g)/p)*.5+c+b},F:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*(t/=d)*t*((s+1)*t-s)+b},E:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},16:9(x,t,b,c,d,s){e(s==u)s=1.l;e((t/=d/2)<1)6 c/2*(t*t*(((s*=(1.B))+1)*t-s))+b;6 c/2*((t-=2)*t*(((s*=(1.B))+1)*t+s)+2)+b},A:9(x,t,b,c,d){6 c-h.i.v(x,d-t,0,c,d)+b},v:9(x,t,b,c,d){e((t/=d)<(1/2.k)){6 c*(7.q*t*t)+b}m e(t<(2/2.k)){6 c*(7.q*(t-=(1.5/2.k))*t+.k)+b}m e(t<(2.5/2.k)){6 c*(7.q*(t-=(2.14/2.k))*t+.11)+b}m{6 c*(7.q*(t-=(2.18/2.k))*t+.19)+b}},1b:9(x,t,b,c,d){e(t<d/2)6 h.i.A(x,t*2,0,c,d)*.5+b;6 h.i.v(x,t*2-d,0,c,d)*.5+c*.5+b}});',62,74,'||||||return||Math|function|||||if|var|PI|jQuery|easing|pow|75|70158|else|sin|sqrt||5625|asin|||undefined|easeOutBounce|abs||def|swing|easeInBounce|525|cos|easeOutQuad|easeOutBack|easeInBack|easeInSine|easeOutElastic|easeInOutQuint|easeOutQuint|easeInQuint|easeInOutQuart|easeOutQuart|easeInQuart|extend|easeInElastic|easeInOutCirc|easeInOutCubic|easeOutCirc|easeInOutElastic|easeOutCubic|easeInCirc|easeInOutExpo|easeInCubic|easeOutExpo|easeInExpo||9375|easeInOutSine|easeInOutQuad|25|easeOutSine|easeInOutBack|easeInQuad|625|984375|jswing|easeInOutBounce'.split('|'),0,{}))
+
+/*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
diff --git a/libgpl/fancybox/jquery.fancybox-1.3.4.css b/libgpl/fancybox/jquery.fancybox-1.3.4.css
new file mode 100644
index 0000000..6f53d8f
--- /dev/null
+++ b/libgpl/fancybox/jquery.fancybox-1.3.4.css
@@ -0,0 +1,359 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+#fancybox-loading {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ margin-left: -20px;
+ cursor: pointer;
+ overflow: hidden;
+ z-index: 1104;
+ display: none;
+}
+
+#fancybox-loading div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 40px;
+ height: 480px;
+ background-image: url('fancybox.png');
+}
+
+#fancybox-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ z-index: 1100;
+ display: none;
+}
+
+#fancybox-tmp {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ overflow: auto;
+ display: none;
+}
+
+#fancybox-wrap {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 20px;
+ z-index: 1101;
+ outline: none;
+ display: none;
+}
+
+#fancybox-outer {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background: #fff;
+}
+
+#fancybox-content {
+ width: 0;
+ height: 0;
+ padding: 0;
+ outline: none;
+ position: relative;
+ overflow: hidden;
+ z-index: 1102;
+ border: 0px solid #fff;
+}
+
+#fancybox-hide-sel-frame {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: transparent;
+ z-index: 1101;
+}
+
+#fancybox-close {
+ position: absolute;
+ top: -15px;
+ right: -15px;
+ width: 30px;
+ height: 30px;
+ background: transparent url('fancybox.png') -40px 0px;
+ cursor: pointer;
+ z-index: 1103;
+ display: none;
+}
+
+#fancybox-error {
+ color: #444;
+ font: normal 12px/20px Arial;
+ padding: 14px;
+ margin: 0;
+}
+
+#fancybox-img {
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ border: none;
+ outline: none;
+ line-height: 0;
+ vertical-align: top;
+}
+
+#fancybox-frame {
+ width: 100%;
+ height: 100%;
+ border: none;
+ display: block;
+}
+
+#fancybox-left, #fancybox-right {
+ position: absolute;
+ bottom: 0px;
+ height: 100%;
+ width: 35%;
+ cursor: pointer;
+ outline: none;
+ background: transparent url('blank.gif');
+ z-index: 1102;
+ display: none;
+}
+
+#fancybox-left {
+ left: 0px;
+}
+
+#fancybox-right {
+ right: 0px;
+}
+
+#fancybox-left-ico, #fancybox-right-ico {
+ position: absolute;
+ top: 50%;
+ left: -9999px;
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ cursor: pointer;
+ z-index: 1102;
+ display: block;
+}
+
+#fancybox-left-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -30px;
+}
+
+#fancybox-right-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -60px;
+}
+
+#fancybox-left:hover, #fancybox-right:hover {
+ visibility: visible; /* IE6 */
+}
+
+#fancybox-left:hover span {
+ left: 20px;
+}
+
+#fancybox-right:hover span {
+ left: auto;
+ right: 20px;
+}
+
+.fancybox-bg {
+ position: absolute;
+ padding: 0;
+ margin: 0;
+ border: 0;
+ width: 20px;
+ height: 20px;
+ z-index: 1001;
+}
+
+#fancybox-bg-n {
+ top: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+}
+
+#fancybox-bg-ne {
+ top: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -162px;
+}
+
+#fancybox-bg-e {
+ top: 0;
+ right: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+ background-position: -20px 0px;
+}
+
+#fancybox-bg-se {
+ bottom: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -182px;
+}
+
+#fancybox-bg-s {
+ bottom: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+ background-position: 0px -20px;
+}
+
+#fancybox-bg-sw {
+ bottom: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -142px;
+}
+
+#fancybox-bg-w {
+ top: 0;
+ left: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+}
+
+#fancybox-bg-nw {
+ top: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -122px;
+}
+
+#fancybox-title {
+ font-family: Helvetica;
+ font-size: 12px;
+ z-index: 1102;
+}
+
+.fancybox-title-inside {
+ padding-bottom: 10px;
+ text-align: center;
+ color: #333;
+ background: #fff;
+ position: relative;
+}
+
+.fancybox-title-outside {
+ padding-top: 10px;
+ color: #fff;
+}
+
+.fancybox-title-over {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ color: #FFF;
+ text-align: left;
+}
+
+#fancybox-title-over {
+ padding: 10px;
+ background-image: url('fancy_title_over.png');
+ display: block;
+}
+
+.fancybox-title-float {
+ position: absolute;
+ left: 0;
+ bottom: -20px;
+ height: 32px;
+}
+
+#fancybox-title-float-wrap {
+ border: none;
+ border-collapse: collapse;
+ width: auto;
+}
+
+#fancybox-title-float-wrap td {
+ border: none;
+ white-space: nowrap;
+}
+
+#fancybox-title-float-left {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -40px -90px no-repeat;
+}
+
+#fancybox-title-float-main {
+ color: #FFF;
+ line-height: 29px;
+ font-weight: bold;
+ padding: 0 0 3px 0;
+ background: url('fancybox-x.png') 0px -40px;
+}
+
+#fancybox-title-float-right {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -55px -90px no-repeat;
+}
+
+/* IE6 */
+
+.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
+.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
+ height: expression(this.parentNode.clientHeight + "px");
+}
+
+#fancybox-loading.fancybox-ie6 {
+ position: absolute; margin-top: 0;
+ top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
+}
+
+#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
+
+/* IE6, IE7, IE8 */
+
+.fancybox-ie .fancybox-bg { background: transparent !important; }
+
+.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); } \ No newline at end of file
diff --git a/libgpl/fancybox/jquery.fancybox-1.3.4.js b/libgpl/fancybox/jquery.fancybox-1.3.4.js
new file mode 100644
index 0000000..be77275
--- /dev/null
+++ b/libgpl/fancybox/jquery.fancybox-1.3.4.js
@@ -0,0 +1,1156 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function($) {
+ var tmp, loading, overlay, wrap, outer, content, close, title, nav_left, nav_right,
+
+ selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],
+
+ ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i,
+
+ loadingTimer, loadingFrame = 1,
+
+ titleHeight = 0, titleStr = '', start_pos, final_pos, busy = false, fx = $.extend($('<div/>')[0], { prop: 0 }),
+
+ isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest,
+
+ /*
+ * Private methods
+ */
+
+ _abort = function() {
+ loading.hide();
+
+ imgPreloader.onerror = imgPreloader.onload = null;
+
+ if (ajaxLoader) {
+ ajaxLoader.abort();
+ }
+
+ tmp.empty();
+ },
+
+ _error = function() {
+ if (false === selectedOpts.onError(selectedArray, selectedIndex, selectedOpts)) {
+ loading.hide();
+ busy = false;
+ return;
+ }
+
+ selectedOpts.titleShow = false;
+
+ selectedOpts.width = 'auto';
+ selectedOpts.height = 'auto';
+
+ tmp.html( '<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>' );
+
+ _process_inline();
+ },
+
+ _start = function() {
+ var obj = selectedArray[ selectedIndex ],
+ href,
+ type,
+ title,
+ str,
+ emb,
+ ret;
+
+ _abort();
+
+ selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));
+
+ ret = selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts);
+
+ if (ret === false) {
+ busy = false;
+ return;
+ } else if (typeof ret == 'object') {
+ selectedOpts = $.extend(selectedOpts, ret);
+ }
+
+ title = selectedOpts.title || (obj.nodeName ? $(obj).attr('title') : obj.title) || '';
+
+ if (obj.nodeName && !selectedOpts.orig) {
+ selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj);
+ }
+
+ if (title === '' && selectedOpts.orig && selectedOpts.titleFromAlt) {
+ title = selectedOpts.orig.attr('alt');
+ }
+
+ href = selectedOpts.href || (obj.nodeName ? $(obj).attr('href') : obj.href) || null;
+
+ if ((/^(?:javascript)/i).test(href) || href == '#') {
+ href = null;
+ }
+
+ if (selectedOpts.type) {
+ type = selectedOpts.type;
+
+ if (!href) {
+ href = selectedOpts.content;
+ }
+
+ } else if (selectedOpts.content) {
+ type = 'html';
+
+ } else if (href) {
+ if (href.match(imgRegExp)) {
+ type = 'image';
+
+ } else if (href.match(swfRegExp)) {
+ type = 'swf';
+
+ } else if ($(obj).hasClass("iframe")) {
+ type = 'iframe';
+
+ } else if (href.indexOf("#") === 0) {
+ type = 'inline';
+
+ } else {
+ type = 'ajax';
+ }
+ }
+
+ if (!type) {
+ _error();
+ return;
+ }
+
+ if (type == 'inline') {
+ obj = href.substr(href.indexOf("#"));
+ type = $(obj).length > 0 ? 'inline' : 'ajax';
+ }
+
+ selectedOpts.type = type;
+ selectedOpts.href = href;
+ selectedOpts.title = title;
+
+ if (selectedOpts.autoDimensions) {
+ if (selectedOpts.type == 'html' || selectedOpts.type == 'inline' || selectedOpts.type == 'ajax') {
+ selectedOpts.width = 'auto';
+ selectedOpts.height = 'auto';
+ } else {
+ selectedOpts.autoDimensions = false;
+ }
+ }
+
+ if (selectedOpts.modal) {
+ selectedOpts.overlayShow = true;
+ selectedOpts.hideOnOverlayClick = false;
+ selectedOpts.hideOnContentClick = false;
+ selectedOpts.enableEscapeButton = false;
+ selectedOpts.showCloseButton = false;
+ }
+
+ selectedOpts.padding = parseInt(selectedOpts.padding, 10);
+ selectedOpts.margin = parseInt(selectedOpts.margin, 10);
+
+ tmp.css('padding', (selectedOpts.padding + selectedOpts.margin));
+
+ $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {
+ $(this).replaceWith(content.children());
+ });
+
+ switch (type) {
+ case 'html' :
+ tmp.html( selectedOpts.content );
+ _process_inline();
+ break;
+
+ case 'inline' :
+ if ( $(obj).parent().is('#fancybox-content') === true) {
+ busy = false;
+ return;
+ }
+
+ $('<div class="fancybox-inline-tmp" />')
+ .hide()
+ .insertBefore( $(obj) )
+ .bind('fancybox-cleanup', function() {
+ $(this).replaceWith(content.children());
+ }).bind('fancybox-cancel', function() {
+ $(this).replaceWith(tmp.children());
+ });
+
+ $(obj).appendTo(tmp);
+
+ _process_inline();
+ break;
+
+ case 'image':
+ busy = false;
+
+ $.fancybox.showActivity();
+
+ imgPreloader = new Image();
+
+ imgPreloader.onerror = function() {
+ _error();
+ };
+
+ imgPreloader.onload = function() {
+ busy = true;
+
+ imgPreloader.onerror = imgPreloader.onload = null;
+
+ _process_image();
+ };
+
+ imgPreloader.src = href;
+ break;
+
+ case 'swf':
+ selectedOpts.scrolling = 'no';
+
+ str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>';
+ emb = '';
+
+ $.each(selectedOpts.swf, function(name, val) {
+ str += '<param name="' + name + '" value="' + val + '"></param>';
+ emb += ' ' + name + '="' + val + '"';
+ });
+
+ str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>';
+
+ tmp.html(str);
+
+ _process_inline();
+ break;
+
+ case 'ajax':
+ busy = false;
+
+ $.fancybox.showActivity();
+
+ selectedOpts.ajax.win = selectedOpts.ajax.success;
+
+ ajaxLoader = $.ajax($.extend({}, selectedOpts.ajax, {
+ url : href,
+ data : selectedOpts.ajax.data || {},
+ error : function(XMLHttpRequest, textStatus, errorThrown) {
+ if ( XMLHttpRequest.status > 0 ) {
+ _error();
+ }
+ },
+ success : function(data, textStatus, XMLHttpRequest) {
+ var o = typeof XMLHttpRequest == 'object' ? XMLHttpRequest : ajaxLoader;
+ if (o.status == 200) {
+ if ( typeof selectedOpts.ajax.win == 'function' ) {
+ ret = selectedOpts.ajax.win(href, data, textStatus, XMLHttpRequest);
+
+ if (ret === false) {
+ loading.hide();
+ return;
+ } else if (typeof ret == 'string' || typeof ret == 'object') {
+ data = ret;
+ }
+ }
+
+ tmp.html( data );
+ _process_inline();
+ }
+ }
+ }));
+
+ break;
+
+ case 'iframe':
+ _show();
+ break;
+ }
+ },
+
+ _process_inline = function() {
+ var
+ w = selectedOpts.width,
+ h = selectedOpts.height;
+
+ if (w.toString().indexOf('%') > -1) {
+ w = parseInt( ($(window).width() - (selectedOpts.margin * 2)) * parseFloat(w) / 100, 10) + 'px';
+
+ } else {
+ w = w == 'auto' ? 'auto' : w + 'px';
+ }
+
+ if (h.toString().indexOf('%') > -1) {
+ h = parseInt( ($(window).height() - (selectedOpts.margin * 2)) * parseFloat(h) / 100, 10) + 'px';
+
+ } else {
+ h = h == 'auto' ? 'auto' : h + 'px';
+ }
+
+ tmp.wrapInner('<div style="width:' + w + ';height:' + h + ';overflow: ' + (selectedOpts.scrolling == 'auto' ? 'auto' : (selectedOpts.scrolling == 'yes' ? 'scroll' : 'hidden')) + ';position:relative;"></div>');
+
+ selectedOpts.width = tmp.width();
+ selectedOpts.height = tmp.height();
+
+ _show();
+ },
+
+ _process_image = function() {
+ selectedOpts.width = imgPreloader.width;
+ selectedOpts.height = imgPreloader.height;
+
+ $("<img />").attr({
+ 'id' : 'fancybox-img',
+ 'src' : imgPreloader.src,
+ 'alt' : selectedOpts.title
+ }).appendTo( tmp );
+
+ _show();
+ },
+
+ _show = function() {
+ var pos, equal;
+
+ loading.hide();
+
+ if (wrap.is(":visible") && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
+ $.event.trigger('fancybox-cancel');
+
+ busy = false;
+ return;
+ }
+
+ busy = true;
+
+ $(content.add( overlay )).unbind();
+
+ $(window).unbind("resize.fb scroll.fb");
+ $(document).unbind('keydown.fb');
+
+ if (wrap.is(":visible") && currentOpts.titlePosition !== 'outside') {
+ wrap.css('height', wrap.height());
+ }
+
+ currentArray = selectedArray;
+ currentIndex = selectedIndex;
+ currentOpts = selectedOpts;
+
+ if (currentOpts.overlayShow) {
+ overlay.css({
+ 'background-color' : currentOpts.overlayColor,
+ 'opacity' : currentOpts.overlayOpacity,
+ 'cursor' : currentOpts.hideOnOverlayClick ? 'pointer' : 'auto',
+ 'height' : $(document).height()
+ });
+
+ if (!overlay.is(':visible')) {
+ if (isIE6) {
+ $('select:not(#fancybox-tmp select)').filter(function() {
+ return this.style.visibility !== 'hidden';
+ }).css({'visibility' : 'hidden'}).one('fancybox-cleanup', function() {
+ this.style.visibility = 'inherit';
+ });
+ }
+
+ overlay.show();
+ }
+ } else {
+ overlay.hide();
+ }
+
+ final_pos = _get_zoom_to();
+
+ _process_title();
+
+ if (wrap.is(":visible")) {
+ $( close.add( nav_left ).add( nav_right ) ).hide();
+
+ pos = wrap.position(),
+
+ start_pos = {
+ top : pos.top,
+ left : pos.left,
+ width : wrap.width(),
+ height : wrap.height()
+ };
+
+ equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);
+
+ content.fadeTo(currentOpts.changeFade, 0.3, function() {
+ var finish_resizing = function() {
+ content.html( tmp.contents() ).fadeTo(currentOpts.changeFade, 1, _finish);
+ };
+
+ $.event.trigger('fancybox-change');
+
+ content
+ .empty()
+ .removeAttr('filter')
+ .css({
+ 'border-width' : currentOpts.padding,
+ 'width' : final_pos.width - currentOpts.padding * 2,
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
+ });
+
+ if (equal) {
+ finish_resizing();
+
+ } else {
+ fx.prop = 0;
+
+ $(fx).animate({prop: 1}, {
+ duration : currentOpts.changeSpeed,
+ easing : currentOpts.easingChange,
+ step : _draw,
+ complete : finish_resizing
+ });
+ }
+ });
+
+ return;
+ }
+
+ wrap.removeAttr("style");
+
+ content.css('border-width', currentOpts.padding);
+
+ if (currentOpts.transitionIn == 'elastic') {
+ start_pos = _get_zoom_from();
+
+ content.html( tmp.contents() );
+
+ wrap.show();
+
+ if (currentOpts.opacity) {
+ final_pos.opacity = 0;
+ }
+
+ fx.prop = 0;
+
+ $(fx).animate({prop: 1}, {
+ duration : currentOpts.speedIn,
+ easing : currentOpts.easingIn,
+ step : _draw,
+ complete : _finish
+ });
+
+ return;
+ }
+
+ if (currentOpts.titlePosition == 'inside' && titleHeight > 0) {
+ title.show();
+ }
+
+ content
+ .css({
+ 'width' : final_pos.width - currentOpts.padding * 2,
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
+ })
+ .html( tmp.contents() );
+
+ wrap
+ .css(final_pos)
+ .fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );
+ },
+
+ _format_title = function(title) {
+ if (title && title.length) {
+ if (currentOpts.titlePosition == 'float') {
+ return '<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">' + title + '</td><td id="fancybox-title-float-right"></td></tr></table>';
+ }
+
+ return '<div id="fancybox-title-' + currentOpts.titlePosition + '">' + title + '</div>';
+ }
+
+ return false;
+ },
+
+ _process_title = function() {
+ titleStr = currentOpts.title || '';
+ titleHeight = 0;
+
+ title
+ .empty()
+ .removeAttr('style')
+ .removeClass();
+
+ if (currentOpts.titleShow === false) {
+ title.hide();
+ return;
+ }
+
+ titleStr = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(titleStr, currentArray, currentIndex, currentOpts) : _format_title(titleStr);
+
+ if (!titleStr || titleStr === '') {
+ title.hide();
+ return;
+ }
+
+ title
+ .addClass('fancybox-title-' + currentOpts.titlePosition)
+ .html( titleStr )
+ .appendTo( 'body' )
+ .show();
+
+ switch (currentOpts.titlePosition) {
+ case 'inside':
+ title
+ .css({
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'marginLeft' : currentOpts.padding,
+ 'marginRight' : currentOpts.padding
+ });
+
+ titleHeight = title.outerHeight(true);
+
+ title.appendTo( outer );
+
+ final_pos.height += titleHeight;
+ break;
+
+ case 'over':
+ title
+ .css({
+ 'marginLeft' : currentOpts.padding,
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'bottom' : currentOpts.padding
+ })
+ .appendTo( outer );
+ break;
+
+ case 'float':
+ title
+ .css('left', parseInt((title.width() - final_pos.width - 40)/ 2, 10) * -1)
+ .appendTo( wrap );
+ break;
+
+ default:
+ title
+ .css({
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'paddingLeft' : currentOpts.padding,
+ 'paddingRight' : currentOpts.padding
+ })
+ .appendTo( wrap );
+ break;
+ }
+
+ title.hide();
+ },
+
+ _set_navigation = function() {
+ if (currentOpts.enableEscapeButton || currentOpts.enableKeyboardNav) {
+ $(document).bind('keydown.fb', function(e) {
+ if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
+ e.preventDefault();
+ $.fancybox.close();
+
+ } else if ((e.keyCode == 37 || e.keyCode == 39) && currentOpts.enableKeyboardNav && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {
+ e.preventDefault();
+ $.fancybox[ e.keyCode == 37 ? 'prev' : 'next']();
+ }
+ });
+ }
+
+ if (!currentOpts.showNavArrows) {
+ nav_left.hide();
+ nav_right.hide();
+ return;
+ }
+
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {
+ nav_left.show();
+ }
+
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {
+ nav_right.show();
+ }
+ },
+
+ _finish = function () {
+ if (!$.support.opacity) {
+ content.get(0).style.removeAttribute('filter');
+ wrap.get(0).style.removeAttribute('filter');
+ }
+
+ if (selectedOpts.autoDimensions) {
+ content.css('height', 'auto');
+ }
+
+ wrap.css('height', 'auto');
+
+ if (titleStr && titleStr.length) {
+ title.show();
+ }
+
+ if (currentOpts.showCloseButton) {
+ close.show();
+ }
+
+ _set_navigation();
+
+ if (currentOpts.hideOnContentClick) {
+ content.bind('click', $.fancybox.close);
+ }
+
+ if (currentOpts.hideOnOverlayClick) {
+ overlay.bind('click', $.fancybox.close);
+ }
+
+ $(window).bind("resize.fb", $.fancybox.resize);
+
+ if (currentOpts.centerOnScroll) {
+ $(window).bind("scroll.fb", $.fancybox.center);
+ }
+
+ if (currentOpts.type == 'iframe') {
+ $('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" ' + ($.browser.msie ? 'allowtransparency="true""' : '') + ' scrolling="' + selectedOpts.scrolling + '" src="' + currentOpts.href + '"></iframe>').appendTo(content);
+ }
+
+ wrap.show();
+
+ busy = false;
+
+ $.fancybox.center();
+
+ currentOpts.onComplete(currentArray, currentIndex, currentOpts);
+
+ _preload_images();
+ },
+
+ _preload_images = function() {
+ var href,
+ objNext;
+
+ if ((currentArray.length -1) > currentIndex) {
+ href = currentArray[ currentIndex + 1 ].href;
+
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+
+ if (currentIndex > 0) {
+ href = currentArray[ currentIndex - 1 ].href;
+
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+ },
+
+ _draw = function(pos) {
+ var dim = {
+ width : parseInt(start_pos.width + (final_pos.width - start_pos.width) * pos, 10),
+ height : parseInt(start_pos.height + (final_pos.height - start_pos.height) * pos, 10),
+
+ top : parseInt(start_pos.top + (final_pos.top - start_pos.top) * pos, 10),
+ left : parseInt(start_pos.left + (final_pos.left - start_pos.left) * pos, 10)
+ };
+
+ if (typeof final_pos.opacity !== 'undefined') {
+ dim.opacity = pos < 0.5 ? 0.5 : pos;
+ }
+
+ wrap.css(dim);
+
+ content.css({
+ 'width' : dim.width - currentOpts.padding * 2,
+ 'height' : dim.height - (titleHeight * pos) - currentOpts.padding * 2
+ });
+ },
+
+ _get_viewport = function() {
+ return [
+ $(window).width() - (currentOpts.margin * 2),
+ $(window).height() - (currentOpts.margin * 2),
+ $(document).scrollLeft() + currentOpts.margin,
+ $(document).scrollTop() + currentOpts.margin
+ ];
+ },
+
+ _get_zoom_to = function () {
+ var view = _get_viewport(),
+ to = {},
+ resize = currentOpts.autoScale,
+ double_padding = currentOpts.padding * 2,
+ ratio;
+
+ if (currentOpts.width.toString().indexOf('%') > -1) {
+ to.width = parseInt((view[0] * parseFloat(currentOpts.width)) / 100, 10);
+ } else {
+ to.width = currentOpts.width + double_padding;
+ }
+
+ if (currentOpts.height.toString().indexOf('%') > -1) {
+ to.height = parseInt((view[1] * parseFloat(currentOpts.height)) / 100, 10);
+ } else {
+ to.height = currentOpts.height + double_padding;
+ }
+
+ if (resize && (to.width > view[0] || to.height > view[1])) {
+ if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {
+ ratio = (currentOpts.width ) / (currentOpts.height );
+
+ if ((to.width ) > view[0]) {
+ to.width = view[0];
+ to.height = parseInt(((to.width - double_padding) / ratio) + double_padding, 10);
+ }
+
+ if ((to.height) > view[1]) {
+ to.height = view[1];
+ to.width = parseInt(((to.height - double_padding) * ratio) + double_padding, 10);
+ }
+
+ } else {
+ to.width = Math.min(to.width, view[0]);
+ to.height = Math.min(to.height, view[1]);
+ }
+ }
+
+ to.top = parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - to.height - 40) * 0.5)), 10);
+ to.left = parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - to.width - 40) * 0.5)), 10);
+
+ return to;
+ },
+
+ _get_obj_pos = function(obj) {
+ var pos = obj.offset();
+
+ pos.top += parseInt( obj.css('paddingTop'), 10 ) || 0;
+ pos.left += parseInt( obj.css('paddingLeft'), 10 ) || 0;
+
+ pos.top += parseInt( obj.css('border-top-width'), 10 ) || 0;
+ pos.left += parseInt( obj.css('border-left-width'), 10 ) || 0;
+
+ pos.width = obj.width();
+ pos.height = obj.height();
+
+ return pos;
+ },
+
+ _get_zoom_from = function() {
+ var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,
+ from = {},
+ pos,
+ view;
+
+ if (orig && orig.length) {
+ pos = _get_obj_pos(orig);
+
+ from = {
+ width : pos.width + (currentOpts.padding * 2),
+ height : pos.height + (currentOpts.padding * 2),
+ top : pos.top - currentOpts.padding - 20,
+ left : pos.left - currentOpts.padding - 20
+ };
+
+ } else {
+ view = _get_viewport();
+
+ from = {
+ width : currentOpts.padding * 2,
+ height : currentOpts.padding * 2,
+ top : parseInt(view[3] + view[1] * 0.5, 10),
+ left : parseInt(view[2] + view[0] * 0.5, 10)
+ };
+ }
+
+ return from;
+ },
+
+ _animate_loading = function() {
+ if (!loading.is(':visible')){
+ clearInterval(loadingTimer);
+ return;
+ }
+
+ $('div', loading).css('top', (loadingFrame * -40) + 'px');
+
+ loadingFrame = (loadingFrame + 1) % 12;
+ };
+
+ /*
+ * Public methods
+ */
+
+ $.fn.fancybox = function(options) {
+ if (!$(this).length) {
+ return this;
+ }
+
+ $(this)
+ .data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))
+ .unbind('click.fb')
+ .bind('click.fb', function(e) {
+ e.preventDefault();
+
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+
+ $(this).blur();
+
+ selectedArray = [];
+ selectedIndex = 0;
+
+ var rel = $(this).attr('rel') || '';
+
+ if (!rel || rel == '' || rel === 'nofollow') {
+ selectedArray.push(this);
+
+ } else {
+ selectedArray = $("a[rel=" + rel + "], area[rel=" + rel + "]");
+ selectedIndex = selectedArray.index( this );
+ }
+
+ _start();
+
+ return;
+ });
+
+ return this;
+ };
+
+ $.fancybox = function(obj) {
+ var opts;
+
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+ opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};
+
+ selectedArray = [];
+ selectedIndex = parseInt(opts.index, 10) || 0;
+
+ if ($.isArray(obj)) {
+ for (var i = 0, j = obj.length; i < j; i++) {
+ if (typeof obj[i] == 'object') {
+ $(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));
+ } else {
+ obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));
+ }
+ }
+
+ selectedArray = jQuery.merge(selectedArray, obj);
+
+ } else {
+ if (typeof obj == 'object') {
+ $(obj).data('fancybox', $.extend({}, opts, obj));
+ } else {
+ obj = $({}).data('fancybox', $.extend({content : obj}, opts));
+ }
+
+ selectedArray.push(obj);
+ }
+
+ if (selectedIndex > selectedArray.length || selectedIndex < 0) {
+ selectedIndex = 0;
+ }
+
+ _start();
+ };
+
+ $.fancybox.showActivity = function() {
+ clearInterval(loadingTimer);
+
+ loading.show();
+ loadingTimer = setInterval(_animate_loading, 66);
+ };
+
+ $.fancybox.hideActivity = function() {
+ loading.hide();
+ };
+
+ $.fancybox.next = function() {
+ return $.fancybox.pos( currentIndex + 1);
+ };
+
+ $.fancybox.prev = function() {
+ return $.fancybox.pos( currentIndex - 1);
+ };
+
+ $.fancybox.pos = function(pos) {
+ if (busy) {
+ return;
+ }
+
+ pos = parseInt(pos);
+
+ selectedArray = currentArray;
+
+ if (pos > -1 && pos < currentArray.length) {
+ selectedIndex = pos;
+ _start();
+
+ } else if (currentOpts.cyclic && currentArray.length > 1) {
+ selectedIndex = pos >= currentArray.length ? 0 : currentArray.length - 1;
+ _start();
+ }
+
+ return;
+ };
+
+ $.fancybox.cancel = function() {
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+
+ $.event.trigger('fancybox-cancel');
+
+ _abort();
+
+ selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);
+
+ busy = false;
+ };
+
+ // Note: within an iframe use - parent.$.fancybox.close();
+ $.fancybox.close = function() {
+ if (busy || wrap.is(':hidden')) {
+ return;
+ }
+
+ busy = true;
+
+ if (currentOpts && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
+ busy = false;
+ return;
+ }
+
+ _abort();
+
+ $(close.add( nav_left ).add( nav_right )).hide();
+
+ $(content.add( overlay )).unbind();
+
+ $(window).unbind("resize.fb scroll.fb");
+ $(document).unbind('keydown.fb');
+
+ content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank');
+
+ if (currentOpts.titlePosition !== 'inside') {
+ title.empty();
+ }
+
+ wrap.stop();
+
+ function _cleanup() {
+ overlay.fadeOut('fast');
+
+ title.empty().hide();
+ wrap.hide();
+
+ $.event.trigger('fancybox-cleanup');
+
+ content.empty();
+
+ currentOpts.onClosed(currentArray, currentIndex, currentOpts);
+
+ currentArray = selectedOpts = [];
+ currentIndex = selectedIndex = 0;
+ currentOpts = selectedOpts = {};
+
+ busy = false;
+ }
+
+ if (currentOpts.transitionOut == 'elastic') {
+ start_pos = _get_zoom_from();
+
+ var pos = wrap.position();
+
+ final_pos = {
+ top : pos.top ,
+ left : pos.left,
+ width : wrap.width(),
+ height : wrap.height()
+ };
+
+ if (currentOpts.opacity) {
+ final_pos.opacity = 1;
+ }
+
+ title.empty().hide();
+
+ fx.prop = 1;
+
+ $(fx).animate({ prop: 0 }, {
+ duration : currentOpts.speedOut,
+ easing : currentOpts.easingOut,
+ step : _draw,
+ complete : _cleanup
+ });
+
+ } else {
+ wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);
+ }
+ };
+
+ $.fancybox.resize = function() {
+ if (overlay.is(':visible')) {
+ overlay.css('height', $(document).height());
+ }
+
+ $.fancybox.center(true);
+ };
+
+ $.fancybox.center = function() {
+ var view, align;
+
+ if (busy) {
+ return;
+ }
+
+ align = arguments[0] === true ? 1 : 0;
+ view = _get_viewport();
+
+ if (!align && (wrap.width() > view[0] || wrap.height() > view[1])) {
+ return;
+ }
+
+ wrap
+ .stop()
+ .animate({
+ 'top' : parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - content.height() - 40) * 0.5) - currentOpts.padding)),
+ 'left' : parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - content.width() - 40) * 0.5) - currentOpts.padding))
+ }, typeof arguments[0] == 'number' ? arguments[0] : 200);
+ };
+
+ $.fancybox.init = function() {
+ if ($("#fancybox-wrap").length) {
+ return;
+ }
+
+ $('body').append(
+ tmp = $('<div id="fancybox-tmp"></div>'),
+ loading = $('<div id="fancybox-loading"><div></div></div>'),
+ overlay = $('<div id="fancybox-overlay"></div>'),
+ wrap = $('<div id="fancybox-wrap"></div>')
+ );
+
+ outer = $('<div id="fancybox-outer"></div>')
+ .append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>')
+ .appendTo( wrap );
+
+ outer.append(
+ content = $('<div id="fancybox-content"></div>'),
+ close = $('<a id="fancybox-close"></a>'),
+ title = $('<div id="fancybox-title"></div>'),
+
+ nav_left = $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),
+ nav_right = $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>')
+ );
+
+ close.click($.fancybox.close);
+ loading.click($.fancybox.cancel);
+
+ nav_left.click(function(e) {
+ e.preventDefault();
+ $.fancybox.prev();
+ });
+
+ nav_right.click(function(e) {
+ e.preventDefault();
+ $.fancybox.next();
+ });
+
+ if ($.fn.mousewheel) {
+ wrap.bind('mousewheel.fb', function(e, delta) {
+ if (busy) {
+ e.preventDefault();
+
+ } else if ($(e.target).get(0).clientHeight == 0 || $(e.target).get(0).scrollHeight === $(e.target).get(0).clientHeight) {
+ e.preventDefault();
+ $.fancybox[ delta > 0 ? 'prev' : 'next']();
+ }
+ });
+ }
+
+ if (!$.support.opacity) {
+ wrap.addClass('fancybox-ie');
+ }
+
+ if (isIE6) {
+ loading.addClass('fancybox-ie6');
+ wrap.addClass('fancybox-ie6');
+
+ $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank' ) + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer);
+ }
+ };
+
+ $.fn.fancybox.defaults = {
+ padding : 10,
+ margin : 40,
+ opacity : false,
+ modal : false,
+ cyclic : false,
+ scrolling : 'auto', // 'auto', 'yes' or 'no'
+
+ width : 560,
+ height : 340,
+
+ autoScale : true,
+ autoDimensions : true,
+ centerOnScroll : false,
+
+ ajax : {},
+ swf : { wmode: 'transparent' },
+
+ hideOnOverlayClick : true,
+ hideOnContentClick : false,
+
+ overlayShow : true,
+ overlayOpacity : 0.7,
+ overlayColor : '#777',
+
+ titleShow : true,
+ titlePosition : 'float', // 'float', 'outside', 'inside' or 'over'
+ titleFormat : null,
+ titleFromAlt : false,
+
+ transitionIn : 'fade', // 'elastic', 'fade' or 'none'
+ transitionOut : 'fade', // 'elastic', 'fade' or 'none'
+
+ speedIn : 300,
+ speedOut : 300,
+
+ changeSpeed : 300,
+ changeFade : 'fast',
+
+ easingIn : 'swing',
+ easingOut : 'swing',
+
+ showCloseButton : true,
+ showNavArrows : true,
+ enableEscapeButton : true,
+ enableKeyboardNav : true,
+
+ onStart : function(){},
+ onCancel : function(){},
+ onComplete : function(){},
+ onCleanup : function(){},
+ onClosed : function(){},
+ onError : function(){}
+ };
+
+ $(document).ready(function() {
+ $.fancybox.init();
+ });
+
+})(jQuery); \ No newline at end of file
diff --git a/libgpl/fancybox/jquery.fancybox-1.3.4.pack.js b/libgpl/fancybox/jquery.fancybox-1.3.4.pack.js
new file mode 100644
index 0000000..1373ed0
--- /dev/null
+++ b/libgpl/fancybox/jquery.fancybox-1.3.4.pack.js
@@ -0,0 +1,46 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
+F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
+c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
+false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel",
+function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+
+'"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win==
+"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+
+";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor,
+opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?
+d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
+y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==
+i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents());
+f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==
+37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto");
+s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j);
+f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);
+j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==
+"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"),
+10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};
+b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
+0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
+1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
+true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
+b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
+d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
+D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
+b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
+b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
+easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery); \ No newline at end of file
diff --git a/libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js b/libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js
new file mode 100644
index 0000000..cb66588
--- /dev/null
+++ b/libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js
@@ -0,0 +1,14 @@
+/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
+* Licensed under the MIT License (LICENSE.txt).
+*
+* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+* Thanks to: Seamus Leahy for adding deltaX and deltaY
+*
+* Version: 3.0.4
+*
+* Requires: 1.2.2+
+*/
+
+(function(d){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),c=0,h=0,e=0;a=d.event.fix(b);a.type="mousewheel";if(a.wheelDelta)c=a.wheelDelta/120;if(a.detail)c=-a.detail/3;e=c;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){e=0;h=-1*c}if(b.wheelDeltaY!==undefined)e=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,c,h,e);return d.event.handle.apply(this,i)}var f=["DOMMouseScroll","mousewheel"];d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=
+f.length;a;)this.addEventListener(f[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=f.length;a;)this.removeEventListener(f[--a],g,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery); \ No newline at end of file
diff --git a/libgpl/flashclipboard/clipboard.swf b/libgpl/flashclipboard/clipboard.swf
new file mode 100644
index 0000000..13bf8e3
--- /dev/null
+++ b/libgpl/flashclipboard/clipboard.swf
Binary files differ
diff --git a/libgpl/flashclipboard/flashclipboard_libgpl.js b/libgpl/flashclipboard/flashclipboard_libgpl.js
new file mode 100644
index 0000000..cdbb2ed
--- /dev/null
+++ b/libgpl/flashclipboard/flashclipboard_libgpl.js
@@ -0,0 +1,309 @@
+$(window).load(function(){
+ $(function() {
+ $(".zclip").each(function() {
+ //Create a new clipboard client
+ var clip = new ZeroClipboard.Client();
+
+ clip.glue($(this).get(0));
+
+ var txt = $(this).prev().val();
+ clip.setText(txt);
+
+ clip.addEventListener('complete', function(client, text) {
+ $('#zclipdialog').html(txt);
+ $('#zclipdialog').dialog({ height : 110, width : 'auto' });
+ });
+ });
+ });
+});
+
+// Simple Set Clipboard System
+// Author: Joseph Huckaby
+
+var ZeroClipboard = {
+
+ version: "1.0.4",
+ clients: {}, // registered upload clients on page, indexed by id
+ moviePath: 'plugins/libgpl/flashclipboard/clipboard.swf', // URL to movie
+ nextId: 1, // ID of next movie
+
+ $: function(thingy) {
+ // simple DOM lookup utility function
+ if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
+ if (!thingy.addClass) {
+ // extend element with a few useful methods
+ thingy.hide = function() { this.style.display = 'none'; };
+ thingy.show = function() { this.style.display = ''; };
+ thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
+ thingy.removeClass = function(name) {
+ this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
+ };
+ thingy.hasClass = function(name) {
+ return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
+ }
+ }
+ return thingy;
+ },
+
+ setMoviePath: function(path) {
+ // set path to ZeroClipboard.swf
+ this.moviePath = path;
+ },
+
+ dispatch: function(id, eventName, args) {
+ // receive event from flash movie, send to client
+ var client = this.clients[id];
+ if (client) {
+ client.receiveEvent(eventName, args);
+ }
+ },
+
+ register: function(id, client) {
+ // register new client to receive events
+ this.clients[id] = client;
+ },
+
+ getDOMObjectPosition: function(obj) {
+ // get absolute coordinates for dom element
+ var info = {
+ left: 0,
+ top: 0,
+ width: obj.width ? obj.width : obj.offsetWidth,
+ height: obj.height ? obj.height : obj.offsetHeight
+ };
+
+ while (obj) {
+ info.left += obj.offsetLeft;
+ info.top += obj.offsetTop;
+ obj = obj.offsetParent;
+ }
+
+ return info;
+ },
+
+ Client: function(elem) {
+ // constructor for new simple upload client
+ this.handlers = {};
+
+ // unique ID
+ this.id = ZeroClipboard.nextId++;
+ this.movieId = 'ZeroClipboardMovie_' + this.id;
+
+ // register client with singleton to receive flash events
+ ZeroClipboard.register(this.id, this);
+
+ // create movie
+ if (elem) this.glue(elem);
+ }
+};
+
+ZeroClipboard.Client.prototype = {
+
+ id: 0, // unique ID for us
+ ready: false, // whether movie is ready to receive events or not
+ movie: null, // reference to movie object
+ clipText: '', // text to copy to clipboard
+ handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
+ cssEffects: true, // enable CSS mouse effects on dom container
+ handlers: null, // user event handlers
+
+ glue: function(elem) {
+ // glue to DOM element
+ // elem can be ID or actual DOM element object
+ this.domElement = ZeroClipboard.$(elem);
+
+ // float just above object, or zIndex 99 if dom element isn't set
+ var zIndex = 99;
+ if (this.domElement.style.zIndex) {
+ zIndex = parseInt(this.domElement.style.zIndex) + 1;
+ }
+
+ // find X/Y position of domElement
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+
+ // create floating DIV above element
+ this.div = document.createElement('div');
+ var style = this.div.style;
+ style.position = 'absolute';
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ style.width = '' + box.width + 'px';
+ style.height = '' + box.height + 'px';
+ style.zIndex = zIndex;
+
+ // style.backgroundColor = '#f00'; // debug
+
+ var body = document.getElementsByTagName('body')[0];
+ body.appendChild(this.div);
+
+ this.div.innerHTML = this.getHTML( box.width, box.height );
+ },
+
+ getHTML: function(width, height) {
+ // return HTML for movie
+ var html = '';
+ var flashvars = 'id=' + this.id +
+ '&width=' + width +
+ '&height=' + height;
+
+ if (navigator.userAgent.match(/MSIE/)) {
+ // IE gets an OBJECT tag
+ var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
+ html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
+ }
+ else {
+ // all other browsers get an EMBED tag
+ html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
+ }
+ return html;
+ },
+
+ hide: function() {
+ // temporarily hide floater offscreen
+ if (this.div) {
+ this.div.style.left = '-2000px';
+ }
+ },
+
+ show: function() {
+ // show ourselves after a call to hide()
+ this.reposition();
+ },
+
+ destroy: function() {
+ // destroy control and floater
+ if (this.domElement && this.div) {
+ this.hide();
+ this.div.innerHTML = '';
+
+ var body = document.getElementsByTagName('body')[0];
+ try { body.removeChild( this.div ); } catch(e) {;}
+
+ this.domElement = null;
+ this.div = null;
+ }
+ },
+
+ reposition: function(elem) {
+ // reposition our floating div, optionally to new container
+ // warning: container CANNOT change size, only position
+ if (elem) {
+ this.domElement = ZeroClipboard.$(elem);
+ if (!this.domElement) this.hide();
+ }
+
+ if (this.domElement && this.div) {
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+ var style = this.div.style;
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ }
+ },
+
+ setText: function(newText) {
+ // set text to be copied to clipboard
+ this.clipText = newText;
+ if (this.ready) this.movie.setText(newText);
+ },
+
+ addEventListener: function(eventName, func) {
+ // add user event listener for event
+ // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+ if (!this.handlers[eventName]) this.handlers[eventName] = [];
+ this.handlers[eventName].push(func);
+ },
+
+ setHandCursor: function(enabled) {
+ // enable hand cursor (true), or default arrow cursor (false)
+ this.handCursorEnabled = enabled;
+ if (this.ready) this.movie.setHandCursor(enabled);
+ },
+
+ setCSSEffects: function(enabled) {
+ // enable or disable CSS effects on DOM container
+ this.cssEffects = !!enabled;
+ },
+
+ receiveEvent: function(eventName, args) {
+ // receive event from flash
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+
+ // special behavior for certain events
+ switch (eventName) {
+ case 'load':
+ // movie claims it is ready, but in IE this isn't always the case...
+ // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
+ this.movie = document.getElementById(this.movieId);
+ if (!this.movie) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 1 );
+ return;
+ }
+
+ // firefox on pc needs a "kick" in order to set these in certain cases
+ if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 100 );
+ this.ready = true;
+ return;
+ }
+
+ this.ready = true;
+ this.movie.setText( this.clipText );
+ this.movie.setHandCursor( this.handCursorEnabled );
+ break;
+
+ case 'mouseover':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('hover');
+ if (this.recoverActive) this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseout':
+ if (this.domElement && this.cssEffects) {
+ this.recoverActive = false;
+ if (this.domElement.hasClass('active')) {
+ this.domElement.removeClass('active');
+ this.recoverActive = true;
+ }
+ this.domElement.removeClass('hover');
+ }
+ break;
+
+ case 'mousedown':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseup':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.removeClass('active');
+ this.recoverActive = false;
+ }
+ break;
+ } // switch eventName
+
+ if (this.handlers[eventName]) {
+ for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
+ var func = this.handlers[eventName][idx];
+
+ if (typeof(func) == 'function') {
+ // actual function reference
+ func(this, args);
+ }
+ else if ((typeof(func) == 'object') && (func.length == 2)) {
+ // PHP style object + method, i.e. [myObject, 'myMethod']
+ func[0][ func[1] ](this, args);
+ }
+ else if (typeof(func) == 'string') {
+ // name of function
+ window[func](this, args);
+ }
+ } // foreach event handler defined
+ } // user defined handler for event
+ }
+
+};
diff --git a/libgpl/flashclipboard/flashclipboard_moreuserinfo.js b/libgpl/flashclipboard/flashclipboard_moreuserinfo.js
new file mode 100644
index 0000000..46042c1
--- /dev/null
+++ b/libgpl/flashclipboard/flashclipboard_moreuserinfo.js
@@ -0,0 +1,290 @@
+// Simple Set Clipboard System
+// Author: Joseph Huckaby
+
+var ZeroClipboard = {
+
+ version: "1.0.4",
+ clients: {}, // registered upload clients on page, indexed by id
+ moviePath: 'plugins/libgpl/flashclipboard/clipboard.swf', // URL to movie
+ nextId: 1, // ID of next movie
+
+ $: function(thingy) {
+ // simple DOM lookup utility function
+ if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
+ if (!thingy.addClass) {
+ // extend element with a few useful methods
+ thingy.hide = function() { this.style.display = 'none'; };
+ thingy.show = function() { this.style.display = ''; };
+ thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
+ thingy.removeClass = function(name) {
+ this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
+ };
+ thingy.hasClass = function(name) {
+ return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
+ }
+ }
+ return thingy;
+ },
+
+ setMoviePath: function(path) {
+ // set path to ZeroClipboard.swf
+ this.moviePath = path;
+ },
+
+ dispatch: function(id, eventName, args) {
+ // receive event from flash movie, send to client
+ var client = this.clients[id];
+ if (client) {
+ client.receiveEvent(eventName, args);
+ }
+ },
+
+ register: function(id, client) {
+ // register new client to receive events
+ this.clients[id] = client;
+ },
+
+ getDOMObjectPosition: function(obj) {
+ // get absolute coordinates for dom element
+ var info = {
+ left: 0,
+ top: 0,
+ width: obj.width ? obj.width : obj.offsetWidth,
+ height: obj.height ? obj.height : obj.offsetHeight
+ };
+
+ while (obj) {
+ info.left += obj.offsetLeft;
+ info.top += obj.offsetTop;
+ obj = obj.offsetParent;
+ }
+
+ return info;
+ },
+
+ Client: function(elem) {
+ // constructor for new simple upload client
+ this.handlers = {};
+
+ // unique ID
+ this.id = ZeroClipboard.nextId++;
+ this.movieId = 'ZeroClipboardMovie_' + this.id;
+
+ // register client with singleton to receive flash events
+ ZeroClipboard.register(this.id, this);
+
+ // create movie
+ if (elem) this.glue(elem);
+ }
+};
+
+ZeroClipboard.Client.prototype = {
+
+ id: 0, // unique ID for us
+ ready: false, // whether movie is ready to receive events or not
+ movie: null, // reference to movie object
+ clipText: '', // text to copy to clipboard
+ handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
+ cssEffects: true, // enable CSS mouse effects on dom container
+ handlers: null, // user event handlers
+
+ glue: function(elem) {
+ // glue to DOM element
+ // elem can be ID or actual DOM element object
+ this.domElement = ZeroClipboard.$(elem);
+
+ // float just above object, or zIndex 99 if dom element isn't set
+ var zIndex = 99;
+ if (this.domElement.style.zIndex) {
+ zIndex = parseInt(this.domElement.style.zIndex) + 1;
+ }
+
+ // find X/Y position of domElement
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+
+ // create floating DIV above element
+ this.div = document.createElement('div');
+ var style = this.div.style;
+ style.position = 'absolute';
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ style.width = '' + box.width + 'px';
+ style.height = '' + box.height + 'px';
+ style.zIndex = zIndex;
+
+ // style.backgroundColor = '#f00'; // debug
+
+ var body = document.getElementsByTagName('body')[0];
+ body.appendChild(this.div);
+
+ this.div.innerHTML = this.getHTML( box.width, box.height );
+ },
+
+ getHTML: function(width, height) {
+ // return HTML for movie
+ var html = '';
+ var flashvars = 'id=' + this.id +
+ '&width=' + width +
+ '&height=' + height;
+
+ if (navigator.userAgent.match(/MSIE/)) {
+ // IE gets an OBJECT tag
+ var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
+ html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
+ }
+ else {
+ // all other browsers get an EMBED tag
+ html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
+ }
+ return html;
+ },
+
+ hide: function() {
+ // temporarily hide floater offscreen
+ if (this.div) {
+ this.div.style.left = '-2000px';
+ }
+ },
+
+ show: function() {
+ // show ourselves after a call to hide()
+ this.reposition();
+ },
+
+ destroy: function() {
+ // destroy control and floater
+ if (this.domElement && this.div) {
+ this.hide();
+ this.div.innerHTML = '';
+
+ var body = document.getElementsByTagName('body')[0];
+ try { body.removeChild( this.div ); } catch(e) {;}
+
+ this.domElement = null;
+ this.div = null;
+ }
+ },
+
+ reposition: function(elem) {
+ // reposition our floating div, optionally to new container
+ // warning: container CANNOT change size, only position
+ if (elem) {
+ this.domElement = ZeroClipboard.$(elem);
+ if (!this.domElement) this.hide();
+ }
+
+ if (this.domElement && this.div) {
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+ var style = this.div.style;
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ }
+ },
+
+ setText: function(newText) {
+ // set text to be copied to clipboard
+ this.clipText = newText;
+ if (this.ready) this.movie.setText(newText);
+ },
+
+ addEventListener: function(eventName, func) {
+ // add user event listener for event
+ // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+ if (!this.handlers[eventName]) this.handlers[eventName] = [];
+ this.handlers[eventName].push(func);
+ },
+
+ setHandCursor: function(enabled) {
+ // enable hand cursor (true), or default arrow cursor (false)
+ this.handCursorEnabled = enabled;
+ if (this.ready) this.movie.setHandCursor(enabled);
+ },
+
+ setCSSEffects: function(enabled) {
+ // enable or disable CSS effects on DOM container
+ this.cssEffects = !!enabled;
+ },
+
+ receiveEvent: function(eventName, args) {
+ // receive event from flash
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+
+ // special behavior for certain events
+ switch (eventName) {
+ case 'load':
+ // movie claims it is ready, but in IE this isn't always the case...
+ // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
+ this.movie = document.getElementById(this.movieId);
+ if (!this.movie) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 1 );
+ return;
+ }
+
+ // firefox on pc needs a "kick" in order to set these in certain cases
+ if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 100 );
+ this.ready = true;
+ return;
+ }
+
+ this.ready = true;
+ this.movie.setText( this.clipText );
+ this.movie.setHandCursor( this.handCursorEnabled );
+ break;
+
+ case 'mouseover':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('hover');
+ if (this.recoverActive) this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseout':
+ if (this.domElement && this.cssEffects) {
+ this.recoverActive = false;
+ if (this.domElement.hasClass('active')) {
+ this.domElement.removeClass('active');
+ this.recoverActive = true;
+ }
+ this.domElement.removeClass('hover');
+ }
+ break;
+
+ case 'mousedown':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseup':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.removeClass('active');
+ this.recoverActive = false;
+ }
+ break;
+ } // switch eventName
+
+ if (this.handlers[eventName]) {
+ for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
+ var func = this.handlers[eventName][idx];
+
+ if (typeof(func) == 'function') {
+ // actual function reference
+ func(this, args);
+ }
+ else if ((typeof(func) == 'object') && (func.length == 2)) {
+ // PHP style object + method, i.e. [myObject, 'myMethod']
+ func[0][ func[1] ](this, args);
+ }
+ else if (typeof(func) == 'string') {
+ // name of function
+ window[func](this, args);
+ }
+ } // foreach event handler defined
+ } // user defined handler for event
+ }
+
+};
diff --git a/libgpl/gibberish/GibberishAES.php b/libgpl/gibberish/GibberishAES.php
new file mode 100644
index 0000000..8ce069a
--- /dev/null
+++ b/libgpl/gibberish/GibberishAES.php
@@ -0,0 +1,213 @@
+<?php
+
+/**
+ * Gibberish AES, a PHP Implementation
+ *
+ * @author Ivan Tcholakov <ivantcholakov@gmail.com>, 2012-2013.
+ * @link https://github.com/ivantcholakov/gibberish-aes-php
+ *
+ * @license The MIT License (MIT)
+ * @link http://opensource.org/licenses/MIT
+ *
+ * This class is based on initial code proposed by nbari at dalmp dot com
+ * @link http://www.php.net/manual/en/function.openssl-decrypt.php#107210
+ *
+ * See also Gibberish AES javascript encryption library
+ * @link https://github.com/mdp/gibberish-aes
+ *
+ * Requirements:
+ *
+ * OpenSSL functions installed and PHP version >= 5.3.3 (preferred case)
+ * or
+ * Mcrypt functions installed.
+ *
+ * Usage:
+ *
+ * // This is a secret key, keep it in a safe place and don't loose it.
+ * $key = 'my secret key';
+ *
+ * // The string to be encrypted.
+ * $string = 'my secret message';
+ *
+ * // This is the result after encryption of the given string.
+ * $encrypted_string = GibberishAES::enc($string, $key);
+ *
+ * // This is the result after decryption of the previously encrypted string.
+ * // $decrypted_string == $string (should be).
+ * $decrypted_string = GibberishAES::dec($encrypted_string, $key);
+ *
+ */
+
+class GibberishAES {
+
+ protected static $openssl_random_pseudo_bytes_exists;
+ protected static $openssl_encrypt_exists;
+ protected static $openssl_decrypt_exists;
+
+ // This is a static class, instances are disabled.
+ final private function __construct() {}
+ final private function __clone() {}
+
+ /**
+ * Crypt AES 256
+ *
+ * @param data $string
+ * @param string $pass
+ * @return base64 encrypted string
+ */
+ public static function enc($string, $pass) {
+
+ // Set a random salt.
+ $salt = self::random_pseudo_bytes(8);
+
+ $salted = '';
+ $dx = '';
+
+ // Salt the key(32) and iv(16) = 48
+ while (strlen($salted) < 48) {
+ $dx = md5($dx.$pass.$salt, true);
+ $salted .= $dx;
+ }
+
+ $key = substr($salted, 0, 32);
+ $iv = substr($salted, 32, 16);
+
+ return base64_encode('Salted__' . $salt . self::aes_256_cbc_encrypt($string, $key, $iv));
+ }
+
+ /**
+ * Decrypt AES 256
+ *
+ * @param data $string
+ * @param string $pass
+ * @return dencrypted string
+ */
+ public static function dec($string, $pass) {
+
+ $data = base64_decode($string);
+ $salt = substr($data, 8, 8);
+ $ct = substr($data, 16);
+
+ /**
+ * From https://github.com/mdp/gibberish-aes
+ *
+ * Number of rounds depends on the size of the AES in use
+ * 3 rounds for 256
+ * 2 rounds for the key, 1 for the IV
+ * 2 rounds for 128
+ * 1 round for the key, 1 round for the IV
+ * 3 rounds for 192 since it's not evenly divided by 128 bits
+ */
+ $rounds = 3;
+ $data00 = $pass.$salt;
+ $md5_hash = array();
+ $md5_hash[0] = md5($data00, true);
+ $result = $md5_hash[0];
+ for ($i = 1; $i < $rounds; $i++) {
+ $md5_hash[$i] = md5($md5_hash[$i - 1].$data00, true);
+ $result .= $md5_hash[$i];
+ }
+ $key = substr($result, 0, 32);
+ $iv = substr($result, 32, 16);
+
+ return self::aes_256_cbc_decrypt($ct, $key, $iv);
+ }
+
+ // Non-public methods ------------------------------------------------------
+
+ protected static function random_pseudo_bytes($length) {
+
+ if (!isset(self::$openssl_random_pseudo_bytes_exists)) {
+ self::$openssl_random_pseudo_bytes_exists = function_exists('openssl_random_pseudo_bytes');
+ }
+
+ if (self::$openssl_random_pseudo_bytes_exists) {
+ return openssl_random_pseudo_bytes($length);
+ }
+
+ // Borrowed from http://phpseclib.com/
+ $rnd = '';
+ for ($i = 0; $i < $length; $i++) {
+ $sha = hash('sha256', mt_rand());
+ $char = mt_rand(0, 30);
+ $rnd .= chr(hexdec($sha[$char].$sha[$char + 1]));
+ }
+ return $rnd;
+ }
+
+ protected static function aes_256_cbc_encrypt($string, $key, $iv) {
+
+ if (!isset(self::$openssl_encrypt_exists)) {
+ self::$openssl_encrypt_exists = function_exists('openssl_encrypt')
+ && version_compare(PHP_VERSION, '5.3.3', '>='); // We need $iv parameter.
+ }
+
+ if (self::$openssl_encrypt_exists) {
+ return openssl_encrypt($string, 'aes-256-cbc', $key, true, $iv);
+ }
+
+ // Info: http://www.chilkatsoft.com/p/php_aes.asp
+ $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
+
+ if (mcrypt_generic_init($cipher, $key, $iv) != -1) {
+ $encrypted = mcrypt_generic($cipher, self::pkcs7_pad($string));
+ mcrypt_generic_deinit($cipher);
+ mcrypt_module_close($cipher);
+ return $encrypted;
+ }
+
+ return false;
+ }
+
+ protected static function aes_256_cbc_decrypt($crypted, $key, $iv) {
+
+ if (!isset(self::$openssl_decrypt_exists)) {
+ self::$openssl_decrypt_exists = function_exists('openssl_decrypt')
+ && version_compare(PHP_VERSION, '5.3.3', '>='); // We need $iv parameter.
+ }
+
+ if (self::$openssl_decrypt_exists) {
+ return openssl_decrypt($crypted, 'aes-256-cbc', $key, true, $iv);
+ }
+
+ $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
+
+ if (mcrypt_generic_init($cipher, $key, $iv) != -1) {
+ $decrypted = mdecrypt_generic($cipher, $crypted);
+ mcrypt_generic_deinit($cipher);
+ mcrypt_module_close($cipher);
+ return self::remove_pkcs7_pad($decrypted);
+ }
+
+ return false;
+ }
+
+ // See http://www.php.net/manual/en/function.mcrypt-decrypt.php#105985
+ protected static function pkcs7_pad($string) {
+
+ $blocksize = 16; // 128 bits: $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+ $pad = $blocksize - (strlen($string) % $blocksize);
+ return $string.str_repeat(chr($pad), $pad);
+ }
+
+ protected static function remove_pkcs7_pad($string) {
+
+ $blocksize = 16; // 128 bits: $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+ $len = strlen($string);
+ $pad = ord($string[$len - 1]);
+ if ($pad > 0 && $pad <= $blocksize) {
+ $valid_pad = true;
+ for ($i = 1; $i <= $pad; $i++) {
+ if (ord($string[$len - $i]) != $pad) {
+ $valid_pad = false;
+ break;
+ }
+ }
+ if ($valid_pad) {
+ $string = substr($string, 0, $len - $pad);
+ }
+ }
+ return $string;
+ }
+
+} \ No newline at end of file
diff --git a/libgpl/gibberish/gibberish-aes.js b/libgpl/gibberish/gibberish-aes.js
new file mode 100644
index 0000000..f1b836b
--- /dev/null
+++ b/libgpl/gibberish/gibberish-aes.js
@@ -0,0 +1,36 @@
+/*
+ Gibberish-AES
+ A lightweight Javascript Libray for OpenSSL compatible AES CBC encryption.
+
+ Author: Mark Percival
+ Email: mark@mpercival.com
+ Copyright: Mark Percival - http://mpercival.com 2008
+
+ With thanks to:
+ Josh Davis - http://www.josh-davis.org/ecmaScrypt
+ Chris Veness - http://www.movable-type.co.uk/scripts/aes.html
+ Michel I. Gallant - http://www.jensign.com/
+ Jean-Luc Cooke <jlcooke@certainkey.com> 2012-07-12: added strhex + invertArr to compress G2X/G3X/G9X/GBX/GEX/SBox/SBoxInv/Rcon saving over 7KB, and added encString, decString, also made the MD5 routine more easlier compressible using yuicompressor.
+
+ License: MIT
+
+ Usage: GibberishAES.enc("secret", "password")
+ Outputs: AES Encrypted text encoded in Base64
+*/
+(function(r,n){"object"===typeof exports?module.exports=n():"function"===typeof define&&define.amd?define(n):r.GibberishAES=n()})(this,function(){var r=14,n=8,u=!1,O=function(a,d){var b="",c,k;if(d){c=a[15];if(16<c)throw"Decryption error: Maybe bad key";if(16===c)return"";for(k=0;k<16-c;k++)b+=String.fromCharCode(a[k])}else for(k=0;16>k;k++)b+=String.fromCharCode(a[k]);return b},z=function(a,d){var b=[],c;if(!d)try{a=unescape(encodeURIComponent(a))}catch(k){throw"Error on UTF-8 encode";}for(c=0;c<
+a.length;c++)b[c]=a.charCodeAt(c);return b},K=function(a,d){var b=12<=r?3:2,c=[],k=[],c=[],k=[],m=a.concat(d),p;c[0]=J(m);k=c[0];for(p=1;p<b;p++)c[p]=J(c[p-1].concat(m)),k=k.concat(c[p]);c=k.slice(0,4*n);k=k.slice(4*n,4*n+16);return{key:c,iv:k}},Q=function(a,d,b){d=L(d);var c=Math.ceil(a.length/16),k=[],m,p=[];for(m=0;m<c;m++){var j=k,t=m,n=a.slice(16*m,16*m+16),s=[],q=void 0,q=void 0;16>n.length&&(q=16-n.length,s=[q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]);for(q=0;q<n.length;q++)s[q]=n[q];j[t]=s}0===a.length%
+16&&k.push([16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16]);for(m=0;m<k.length;m++)k[m]=0===m?A(k[m],b):A(k[m],p[m-1]),p[m]=P(k[m],d);return p},S=function(a,d,b,c){d=L(d);var k=a.length/16,m=[],p,j=[],t="";for(p=0;p<k;p++)m.push(a.slice(16*p,16*(p+1)));for(p=m.length-1;0<=p;p--)j[p]=R(m[p],d),j[p]=0===p?A(j[p],b):A(j[p],m[p-1]);for(p=0;p<k-1;p++)t+=O(j[p]);var t=t+O(j[p],!0),n;if(c)n=t;else try{n=decodeURIComponent(escape(t))}catch(s){throw"Bad Key";}return n},P=function(a,d){u=!1;var b=B(a,d,0),
+c;for(c=1;c<r+1;c++)b=T(b),b=U(b),c<r&&(b=V(b)),b=B(b,d,c);return b},R=function(a,d){u=!0;var b=B(a,d,r),c;for(c=r-1;-1<c;c--)b=U(b),b=T(b),b=B(b,d,c),0<c&&(b=V(b));return b},T=function(a){var d=u?W:M,b=[],c;for(c=0;16>c;c++)b[c]=d[a[c]];return b},U=function(a){var d=[],b=u?[0,13,10,7,4,1,14,11,8,5,2,15,12,9,6,3]:[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11],c;for(c=0;16>c;c++)d[c]=a[b[c]];return d},V=function(a){var d=[],b;if(u)for(b=0;4>b;b++)d[4*b]=C[a[4*b]]^D[a[1+4*b]]^E[a[2+4*b]]^F[a[3+4*b]],d[1+4*
+b]=F[a[4*b]]^C[a[1+4*b]]^D[a[2+4*b]]^E[a[3+4*b]],d[2+4*b]=E[a[4*b]]^F[a[1+4*b]]^C[a[2+4*b]]^D[a[3+4*b]],d[3+4*b]=D[a[4*b]]^E[a[1+4*b]]^F[a[2+4*b]]^C[a[3+4*b]];else for(b=0;4>b;b++)d[4*b]=G[a[4*b]]^H[a[1+4*b]]^a[2+4*b]^a[3+4*b],d[1+4*b]=a[4*b]^G[a[1+4*b]]^H[a[2+4*b]]^a[3+4*b],d[2+4*b]=a[4*b]^a[1+4*b]^G[a[2+4*b]]^H[a[3+4*b]],d[3+4*b]=H[a[4*b]]^a[1+4*b]^a[2+4*b]^G[a[3+4*b]];return d},B=function(a,d,b){var c=[],k;for(k=0;16>k;k++)c[k]=a[k]^d[b][k];return c},A=function(a,d){var b=[],c;for(c=0;16>c;c++)b[c]=
+a[c]^d[c];return b},L=function(a){var d=[],b=[],c,k,m=[];for(c=0;c<n;c++)k=[a[4*c],a[4*c+1],a[4*c+2],a[4*c+3]],d[c]=k;for(c=n;c<4*(r+1);c++){d[c]=[];for(a=0;4>a;a++)b[a]=d[c-1][a];if(0===c%n){a=b[0];k=void 0;for(k=0;3>k;k++)b[k]=b[k+1];b[3]=a;b=X(b);b[0]^=$[c/n-1]}else 6<n&&4===c%n&&(b=X(b));for(a=0;4>a;a++)d[c][a]=d[c-n][a]^b[a]}for(c=0;c<r+1;c++){m[c]=[];for(b=0;4>b;b++)m[c].push(d[4*c+b][0],d[4*c+b][1],d[4*c+b][2],d[4*c+b][3])}return m},X=function(a){for(var d=0;4>d;d++)a[d]=M[a[d]];return a},
+N=function(a,d){var b,c=[];for(b=0;b<a.length;b+=d)c[b/d]=parseInt(a.substr(b,d),16);return c},v=function(a){var d,b=[];for(d=0;256>d;d++){for(var c=b,k=d,m=a,p=d,j=void 0,n=void 0,j=n=0;8>j;j++)n=1===(p&1)?n^m:n,m=127<m?283^m<<1:m<<1,p>>>=1;c[k]=n}return b},M=N("637c777bf26b6fc53001672bfed7ab76ca82c97dfa5947f0add4a2af9ca472c0b7fd9326363ff7cc34a5e5f171d8311504c723c31896059a071280e2eb27b27509832c1a1b6e5aa0523bd6b329e32f8453d100ed20fcb15b6acbbe394a4c58cfd0efaafb434d338545f9027f503c9fa851a3408f929d38f5bcb6da2110fff3d2cd0c13ec5f974417c4a77e3d645d197360814fdc222a908846eeb814de5e0bdbe0323a0a4906245cc2d3ac629195e479e7c8376d8dd54ea96c56f4ea657aae08ba78252e1ca6b4c6e8dd741f4bbd8b8a703eb5664803f60e613557b986c11d9ee1f8981169d98e949b1e87e9ce5528df8ca1890dbfe6426841992d0fb054bb16",
+2),W,Y=M,x,Z=[];for(x=0;x<Y.length;x++)Z[Y[x]]=x;W=Z;var $=N("01020408102040801b366cd8ab4d9a2f5ebc63c697356ad4b37dfaefc591",2),G=v(2),H=v(3),F=v(9),D=v(11),E=v(13),C=v(14),J=function(a){function d(a,b){var c,d,e,g,f;e=a&2147483648;g=b&2147483648;c=a&1073741824;d=b&1073741824;f=(a&1073741823)+(b&1073741823);return c&d?f^2147483648^e^g:c|d?f&1073741824?f^3221225472^e^g:f^1073741824^e^g:f^e^g}function b(a,b,c,e,f,g,h){a=d(a,d(d(b&c|~b&e,f),h));return d(a<<g|a>>>32-g,b)}function c(a,b,c,e,g,f,h){a=d(a,
+d(d(b&e|c&~e,g),h));return d(a<<f|a>>>32-f,b)}function k(a,b,c,e,f,g,h){a=d(a,d(d(b^c^e,f),h));return d(a<<g|a>>>32-g,b)}function m(a,b,c,e,g,f,h){a=d(a,d(d(c^(b|~e),g),h));return d(a<<f|a>>>32-f,b)}function p(a){var b,c,d=[];for(c=0;3>=c;c++)b=a>>>8*c&255,d=d.concat(b);return d}var j=[],n,r,s,q,e,g,f,h,l=N("67452301efcdab8998badcfe10325476d76aa478e8c7b756242070dbc1bdceeef57c0faf4787c62aa8304613fd469501698098d88b44f7afffff5bb1895cd7be6b901122fd987193a679438e49b40821f61e2562c040b340265e5a51e9b6c7aad62f105d02441453d8a1e681e7d3fbc821e1cde6c33707d6f4d50d87455a14eda9e3e905fcefa3f8676f02d98d2a4c8afffa39428771f6816d9d6122fde5380ca4beea444bdecfa9f6bb4b60bebfbc70289b7ec6eaa127fad4ef308504881d05d9d4d039e6db99e51fa27cf8c4ac5665f4292244432aff97ab9423a7fc93a039655b59c38f0ccc92ffeff47d85845dd16fa87e4ffe2ce6e0a30143144e0811a1f7537e82bd3af2352ad7d2bbeb86d391",
+8),j=a.length;n=j+8;r=16*((n-n%64)/64+1);s=[];for(e=q=0;e<j;)n=(e-e%4)/4,q=8*(e%4),s[n]|=a[e]<<q,e++;n=(e-e%4)/4;s[n]|=128<<8*(e%4);s[r-2]=j<<3;s[r-1]=j>>>29;j=s;e=l[0];g=l[1];f=l[2];h=l[3];for(a=0;a<j.length;a+=16)n=e,r=g,s=f,q=h,e=b(e,g,f,h,j[a+0],7,l[4]),h=b(h,e,g,f,j[a+1],12,l[5]),f=b(f,h,e,g,j[a+2],17,l[6]),g=b(g,f,h,e,j[a+3],22,l[7]),e=b(e,g,f,h,j[a+4],7,l[8]),h=b(h,e,g,f,j[a+5],12,l[9]),f=b(f,h,e,g,j[a+6],17,l[10]),g=b(g,f,h,e,j[a+7],22,l[11]),e=b(e,g,f,h,j[a+8],7,l[12]),h=b(h,e,g,f,j[a+9],
+12,l[13]),f=b(f,h,e,g,j[a+10],17,l[14]),g=b(g,f,h,e,j[a+11],22,l[15]),e=b(e,g,f,h,j[a+12],7,l[16]),h=b(h,e,g,f,j[a+13],12,l[17]),f=b(f,h,e,g,j[a+14],17,l[18]),g=b(g,f,h,e,j[a+15],22,l[19]),e=c(e,g,f,h,j[a+1],5,l[20]),h=c(h,e,g,f,j[a+6],9,l[21]),f=c(f,h,e,g,j[a+11],14,l[22]),g=c(g,f,h,e,j[a+0],20,l[23]),e=c(e,g,f,h,j[a+5],5,l[24]),h=c(h,e,g,f,j[a+10],9,l[25]),f=c(f,h,e,g,j[a+15],14,l[26]),g=c(g,f,h,e,j[a+4],20,l[27]),e=c(e,g,f,h,j[a+9],5,l[28]),h=c(h,e,g,f,j[a+14],9,l[29]),f=c(f,h,e,g,j[a+3],14,l[30]),
+g=c(g,f,h,e,j[a+8],20,l[31]),e=c(e,g,f,h,j[a+13],5,l[32]),h=c(h,e,g,f,j[a+2],9,l[33]),f=c(f,h,e,g,j[a+7],14,l[34]),g=c(g,f,h,e,j[a+12],20,l[35]),e=k(e,g,f,h,j[a+5],4,l[36]),h=k(h,e,g,f,j[a+8],11,l[37]),f=k(f,h,e,g,j[a+11],16,l[38]),g=k(g,f,h,e,j[a+14],23,l[39]),e=k(e,g,f,h,j[a+1],4,l[40]),h=k(h,e,g,f,j[a+4],11,l[41]),f=k(f,h,e,g,j[a+7],16,l[42]),g=k(g,f,h,e,j[a+10],23,l[43]),e=k(e,g,f,h,j[a+13],4,l[44]),h=k(h,e,g,f,j[a+0],11,l[45]),f=k(f,h,e,g,j[a+3],16,l[46]),g=k(g,f,h,e,j[a+6],23,l[47]),e=k(e,g,
+f,h,j[a+9],4,l[48]),h=k(h,e,g,f,j[a+12],11,l[49]),f=k(f,h,e,g,j[a+15],16,l[50]),g=k(g,f,h,e,j[a+2],23,l[51]),e=m(e,g,f,h,j[a+0],6,l[52]),h=m(h,e,g,f,j[a+7],10,l[53]),f=m(f,h,e,g,j[a+14],15,l[54]),g=m(g,f,h,e,j[a+5],21,l[55]),e=m(e,g,f,h,j[a+12],6,l[56]),h=m(h,e,g,f,j[a+3],10,l[57]),f=m(f,h,e,g,j[a+10],15,l[58]),g=m(g,f,h,e,j[a+1],21,l[59]),e=m(e,g,f,h,j[a+8],6,l[60]),h=m(h,e,g,f,j[a+15],10,l[61]),f=m(f,h,e,g,j[a+6],15,l[62]),g=m(g,f,h,e,j[a+13],21,l[63]),e=m(e,g,f,h,j[a+4],6,l[64]),h=m(h,e,g,f,j[a+
+11],10,l[65]),f=m(f,h,e,g,j[a+2],15,l[66]),g=m(g,f,h,e,j[a+9],21,l[67]),e=d(e,n),g=d(g,r),f=d(f,s),h=d(h,q);return p(e).concat(p(g),p(f),p(h))},I,w="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",y=w.split("");"function"===typeof Array.indexOf&&(w=y);I={encode:function(a){var d=[],b="",c;for(c=0;c<16*a.length;c++)d.push(a[Math.floor(c/16)][c%16]);for(c=0;c<d.length;c+=3)b+=y[d[c]>>2],b+=y[(d[c]&3)<<4|d[c+1]>>4],b=void 0!==d[c+1]?b+y[(d[c+1]&15)<<2|d[c+2]>>6]:b+"=",b=void 0!==d[c+
+2]?b+y[d[c+2]&63]:b+"=";a=b.slice(0,64)+"\n";for(c=1;c<Math.ceil(b.length/64);c++)a+=b.slice(64*c,64*c+64)+(Math.ceil(b.length/64)===c+1?"":"\n");return a},decode:function(a){a=a.replace(/\n/g,"");var d=[],b=[],c=[],k;for(k=0;k<a.length;k+=4)b[0]=w.indexOf(a.charAt(k)),b[1]=w.indexOf(a.charAt(k+1)),b[2]=w.indexOf(a.charAt(k+2)),b[3]=w.indexOf(a.charAt(k+3)),c[0]=b[0]<<2|b[1]>>4,c[1]=(b[1]&15)<<4|b[2]>>2,c[2]=(b[2]&3)<<6|b[3],d.push(c[0],c[1],c[2]);return d=d.slice(0,d.length-d.length%16)}};return{size:function(a){switch(a){case 128:r=
+10;n=4;break;case 192:r=12;n=6;break;case 256:r=14;n=8;break;default:throw"Invalid Key Size Specified:"+a;}},h2a:function(a){var d=[];a.replace(/(..)/g,function(a){d.push(parseInt(a,16))});return d},expandKey:L,encryptBlock:P,decryptBlock:R,Decrypt:u,s2a:z,rawEncrypt:Q,rawDecrypt:S,dec:function(a,d,b){a=I.decode(a);var c=a.slice(8,16),c=K(z(d,b),c);d=c.key;c=c.iv;a=a.slice(16,a.length);return a=S(a,d,c,b)},openSSLKey:K,a2h:function(a){var d="",b;for(b=0;b<a.length;b++)d+=(16>a[b]?"0":"")+a[b].toString(16);
+return d},enc:function(a,d,b){var c;c=[];var k;for(k=0;8>k;k++)c=c.concat(Math.floor(256*Math.random()));k=K(z(d,b),c);d=k.key;k=k.iv;c=[[83,97,108,116,101,100,95,95].concat(c)];a=z(a,b);a=Q(a,d,k);a=c.concat(a);return I.encode(a)},Hash:{MD5:J},Base64:I}}); \ No newline at end of file
diff --git a/libgpl/gibberish/gibberish-aes.js.comp.src b/libgpl/gibberish/gibberish-aes.js.comp.src
new file mode 100644
index 0000000..ca7f01f
--- /dev/null
+++ b/libgpl/gibberish/gibberish-aes.js.comp.src
@@ -0,0 +1,1017 @@
+/**
+* @license Gibberish-AES
+* A lightweight Javascript Libray for OpenSSL compatible AES CBC encryption.
+*
+* Author: Mark Percival
+* Email: mark@mpercival.com
+* Copyright: Mark Percival - http://mpercival.com 2008
+*
+* With thanks to:
+* Josh Davis - http://www.josh-davis.org/ecmaScrypt
+* Chris Veness - http://www.movable-type.co.uk/scripts/aes.html
+* Michel I. Gallant - http://www.jensign.com/
+* Jean-Luc Cooke <jlcooke@certainkey.com> 2012-07-12: added strhex + invertArr to compress G2X/G3X/G9X/GBX/GEX/SBox/SBoxInv/Rcon saving over 7KB, and added encString, decString, also made the MD5 routine more easlier compressible using yuicompressor.
+*
+* License: MIT
+*
+* Usage: GibberishAES.enc("secret", "password")
+* Outputs: AES Encrypted text encoded in Base64
+*/
+
+
+(function (root, factory) {
+ if (typeof exports === 'object') {
+ // Node.
+ module.exports = factory();
+ } else if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(factory);
+ } else {
+ // Browser globals (root is window)
+ root.GibberishAES = factory();
+ }
+}(this, function () {
+ 'use strict';
+
+ var Nr = 14,
+ /* Default to 256 Bit Encryption */
+ Nk = 8,
+ Decrypt = false,
+
+ enc_utf8 = function(s)
+ {
+ try {
+ return unescape(encodeURIComponent(s));
+ }
+ catch(e) {
+ throw 'Error on UTF-8 encode';
+ }
+ },
+
+ dec_utf8 = function(s)
+ {
+ try {
+ return decodeURIComponent(escape(s));
+ }
+ catch(e) {
+ throw ('Bad Key');
+ }
+ },
+
+ padBlock = function(byteArr)
+ {
+ var array = [], cpad, i;
+ if (byteArr.length < 16) {
+ cpad = 16 - byteArr.length;
+ array = [cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad];
+ }
+ for (i = 0; i < byteArr.length; i++)
+ {
+ array[i] = byteArr[i];
+ }
+ return array;
+ },
+
+ block2s = function(block, lastBlock)
+ {
+ var string = '', padding, i;
+ if (lastBlock) {
+ padding = block[15];
+ if (padding > 16) {
+ throw ('Decryption error: Maybe bad key');
+ }
+ if (padding === 16) {
+ return '';
+ }
+ for (i = 0; i < 16 - padding; i++) {
+ string += String.fromCharCode(block[i]);
+ }
+ } else {
+ for (i = 0; i < 16; i++) {
+ string += String.fromCharCode(block[i]);
+ }
+ }
+ return string;
+ },
+
+ a2h = function(numArr)
+ {
+ var string = '', i;
+ for (i = 0; i < numArr.length; i++) {
+ string += (numArr[i] < 16 ? '0': '') + numArr[i].toString(16);
+ }
+ return string;
+ },
+
+ h2a = function(s)
+ {
+ var ret = [];
+ s.replace(/(..)/g,
+ function(s) {
+ ret.push(parseInt(s, 16));
+ });
+ return ret;
+ },
+
+ s2a = function(string, binary) {
+ var array = [], i;
+
+ if (! binary) {
+ string = enc_utf8(string);
+ }
+
+ for (i = 0; i < string.length; i++)
+ {
+ array[i] = string.charCodeAt(i);
+ }
+
+ return array;
+ },
+
+ size = function(newsize)
+ {
+ switch (newsize)
+ {
+ case 128:
+ Nr = 10;
+ Nk = 4;
+ break;
+ case 192:
+ Nr = 12;
+ Nk = 6;
+ break;
+ case 256:
+ Nr = 14;
+ Nk = 8;
+ break;
+ default:
+ throw ('Invalid Key Size Specified:' + newsize);
+ }
+ },
+
+ randArr = function(num) {
+ var result = [], i;
+ for (i = 0; i < num; i++) {
+ result = result.concat(Math.floor(Math.random() * 256));
+ }
+ return result;
+ },
+
+ openSSLKey = function(passwordArr, saltArr) {
+ // Number of rounds depends on the size of the AES in use
+ // 3 rounds for 256
+ // 2 rounds for the key, 1 for the IV
+ // 2 rounds for 128
+ // 1 round for the key, 1 round for the IV
+ // 3 rounds for 192 since it's not evenly divided by 128 bits
+ var rounds = Nr >= 12 ? 3: 2,
+ key = [],
+ iv = [],
+ md5_hash = [],
+ result = [],
+ data00 = passwordArr.concat(saltArr),
+ i;
+ md5_hash[0] = MD5(data00);
+ result = md5_hash[0];
+ for (i = 1; i < rounds; i++) {
+ md5_hash[i] = MD5(md5_hash[i - 1].concat(data00));
+ result = result.concat(md5_hash[i]);
+ }
+ key = result.slice(0, 4 * Nk);
+ iv = result.slice(4 * Nk, 4 * Nk + 16);
+ return {
+ key: key,
+ iv: iv
+ };
+ },
+
+ rawEncrypt = function(plaintext, key, iv) {
+ // plaintext, key and iv as byte arrays
+ key = expandKey(key);
+ var numBlocks = Math.ceil(plaintext.length / 16),
+ blocks = [],
+ i,
+ cipherBlocks = [];
+ for (i = 0; i < numBlocks; i++) {
+ blocks[i] = padBlock(plaintext.slice(i * 16, i * 16 + 16));
+ }
+ if (plaintext.length % 16 === 0) {
+ blocks.push([16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16]);
+ // CBC OpenSSL padding scheme
+ numBlocks++;
+ }
+ for (i = 0; i < blocks.length; i++) {
+ blocks[i] = (i === 0) ? xorBlocks(blocks[i], iv) : xorBlocks(blocks[i], cipherBlocks[i - 1]);
+ cipherBlocks[i] = encryptBlock(blocks[i], key);
+ }
+ return cipherBlocks;
+ },
+
+ rawDecrypt = function(cryptArr, key, iv, binary) {
+ // cryptArr, key and iv as byte arrays
+ key = expandKey(key);
+ var numBlocks = cryptArr.length / 16,
+ cipherBlocks = [],
+ i,
+ plainBlocks = [],
+ string = '';
+ for (i = 0; i < numBlocks; i++) {
+ cipherBlocks.push(cryptArr.slice(i * 16, (i + 1) * 16));
+ }
+ for (i = cipherBlocks.length - 1; i >= 0; i--) {
+ plainBlocks[i] = decryptBlock(cipherBlocks[i], key);
+ plainBlocks[i] = (i === 0) ? xorBlocks(plainBlocks[i], iv) : xorBlocks(plainBlocks[i], cipherBlocks[i - 1]);
+ }
+ for (i = 0; i < numBlocks - 1; i++) {
+ string += block2s(plainBlocks[i]);
+ }
+ string += block2s(plainBlocks[i], true);
+ return binary ? string : dec_utf8(string);
+ },
+
+ encryptBlock = function(block, words) {
+ Decrypt = false;
+ var state = addRoundKey(block, words, 0),
+ round;
+ for (round = 1; round < (Nr + 1); round++) {
+ state = subBytes(state);
+ state = shiftRows(state);
+ if (round < Nr) {
+ state = mixColumns(state);
+ }
+ //last round? don't mixColumns
+ state = addRoundKey(state, words, round);
+ }
+
+ return state;
+ },
+
+ decryptBlock = function(block, words) {
+ Decrypt = true;
+ var state = addRoundKey(block, words, Nr),
+ round;
+ for (round = Nr - 1; round > -1; round--) {
+ state = shiftRows(state);
+ state = subBytes(state);
+ state = addRoundKey(state, words, round);
+ if (round > 0) {
+ state = mixColumns(state);
+ }
+ //last round? don't mixColumns
+ }
+
+ return state;
+ },
+
+ subBytes = function(state) {
+ var S = Decrypt ? SBoxInv: SBox,
+ temp = [],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = S[state[i]];
+ }
+ return temp;
+ },
+
+ shiftRows = function(state) {
+ var temp = [],
+ shiftBy = Decrypt ? [0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3] : [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = state[shiftBy[i]];
+ }
+ return temp;
+ },
+
+ mixColumns = function(state) {
+ var t = [],
+ c;
+ if (!Decrypt) {
+ for (c = 0; c < 4; c++) {
+ t[c * 4] = G2X[state[c * 4]] ^ G3X[state[1 + c * 4]] ^ state[2 + c * 4] ^ state[3 + c * 4];
+ t[1 + c * 4] = state[c * 4] ^ G2X[state[1 + c * 4]] ^ G3X[state[2 + c * 4]] ^ state[3 + c * 4];
+ t[2 + c * 4] = state[c * 4] ^ state[1 + c * 4] ^ G2X[state[2 + c * 4]] ^ G3X[state[3 + c * 4]];
+ t[3 + c * 4] = G3X[state[c * 4]] ^ state[1 + c * 4] ^ state[2 + c * 4] ^ G2X[state[3 + c * 4]];
+ }
+ }else {
+ for (c = 0; c < 4; c++) {
+ t[c*4] = GEX[state[c*4]] ^ GBX[state[1+c*4]] ^ GDX[state[2+c*4]] ^ G9X[state[3+c*4]];
+ t[1+c*4] = G9X[state[c*4]] ^ GEX[state[1+c*4]] ^ GBX[state[2+c*4]] ^ GDX[state[3+c*4]];
+ t[2+c*4] = GDX[state[c*4]] ^ G9X[state[1+c*4]] ^ GEX[state[2+c*4]] ^ GBX[state[3+c*4]];
+ t[3+c*4] = GBX[state[c*4]] ^ GDX[state[1+c*4]] ^ G9X[state[2+c*4]] ^ GEX[state[3+c*4]];
+ }
+ }
+
+ return t;
+ },
+
+ addRoundKey = function(state, words, round) {
+ var temp = [],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = state[i] ^ words[round][i];
+ }
+ return temp;
+ },
+
+ xorBlocks = function(block1, block2) {
+ var temp = [],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = block1[i] ^ block2[i];
+ }
+ return temp;
+ },
+
+ expandKey = function(key) {
+ // Expects a 1d number array
+ var w = [],
+ temp = [],
+ i,
+ r,
+ t,
+ flat = [],
+ j;
+
+ for (i = 0; i < Nk; i++) {
+ r = [key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]];
+ w[i] = r;
+ }
+
+ for (i = Nk; i < (4 * (Nr + 1)); i++) {
+ w[i] = [];
+ for (t = 0; t < 4; t++) {
+ temp[t] = w[i - 1][t];
+ }
+ if (i % Nk === 0) {
+ temp = subWord(rotWord(temp));
+ temp[0] ^= Rcon[i / Nk - 1];
+ } else if (Nk > 6 && i % Nk === 4) {
+ temp = subWord(temp);
+ }
+ for (t = 0; t < 4; t++) {
+ w[i][t] = w[i - Nk][t] ^ temp[t];
+ }
+ }
+ for (i = 0; i < (Nr + 1); i++) {
+ flat[i] = [];
+ for (j = 0; j < 4; j++) {
+ flat[i].push(w[i * 4 + j][0], w[i * 4 + j][1], w[i * 4 + j][2], w[i * 4 + j][3]);
+ }
+ }
+ return flat;
+ },
+
+ subWord = function(w) {
+ // apply SBox to 4-byte word w
+ for (var i = 0; i < 4; i++) {
+ w[i] = SBox[w[i]];
+ }
+ return w;
+ },
+
+ rotWord = function(w) {
+ // rotate 4-byte word w left by one byte
+ var tmp = w[0],
+ i;
+ for (i = 0; i < 3; i++) {
+ w[i] = w[i + 1];
+ }
+ w[3] = tmp;
+ return w;
+ },
+
+// jlcooke: 2012-07-12: added strhex + invertArr to compress G2X/G3X/G9X/GBX/GEX/SBox/SBoxInv/Rcon saving over 7KB, and added encString, decString
+ strhex = function(str,size) {
+ var i, ret = [];
+ for (i=0; i<str.length; i+=size){
+ ret[i/size] = parseInt(str.substr(i,size), 16);
+ }
+ return ret;
+ },
+ invertArr = function(arr) {
+ var i, ret = [];
+ for (i=0; i<arr.length; i++){
+ ret[arr[i]] = i;
+ }
+ return ret;
+ },
+ Gxx = function(a, b) {
+ var i, ret;
+
+ ret = 0;
+ for (i=0; i<8; i++) {
+ ret = ((b&1)===1) ? ret^a : ret;
+ /* xmult */
+ a = (a>0x7f) ? 0x11b^(a<<1) : (a<<1);
+ b >>>= 1;
+ }
+
+ return ret;
+ },
+ Gx = function(x) {
+ var i, r = [];
+ for (i=0; i<256; i++){
+ r[i] = Gxx(x, i);
+ }
+ return r;
+ },
+
+ // S-box
+/*
+ SBox = [
+ 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171,
+ 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
+ 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113,
+ 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
+ 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214,
+ 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
+ 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69,
+ 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
+ 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68,
+ 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
+ 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73,
+ 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
+ 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37,
+ 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
+ 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225,
+ 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187,
+ 22], //*/ SBox = strhex('637c777bf26b6fc53001672bfed7ab76ca82c97dfa5947f0add4a2af9ca472c0b7fd9326363ff7cc34a5e5f171d8311504c723c31896059a071280e2eb27b27509832c1a1b6e5aa0523bd6b329e32f8453d100ed20fcb15b6acbbe394a4c58cfd0efaafb434d338545f9027f503c9fa851a3408f929d38f5bcb6da2110fff3d2cd0c13ec5f974417c4a77e3d645d197360814fdc222a908846eeb814de5e0bdbe0323a0a4906245cc2d3ac629195e479e7c8376d8dd54ea96c56f4ea657aae08ba78252e1ca6b4c6e8dd741f4bbd8b8a703eb5664803f60e613557b986c11d9ee1f8981169d98e949b1e87e9ce5528df8ca1890dbfe6426841992d0fb054bb16',2),
+
+ // Precomputed lookup table for the inverse SBox
+/* SBoxInv = [
+ 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215,
+ 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222,
+ 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66,
+ 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73,
+ 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92,
+ 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21,
+ 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247,
+ 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220,
+ 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173,
+ 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29,
+ 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75,
+ 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168,
+ 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81,
+ 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160,
+ 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12,
+ 125], //*/ SBoxInv = invertArr(SBox),
+
+ // Rijndael Rcon
+/*
+ Rcon = [1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154, 47, 94,
+ 188, 99, 198, 151, 53, 106, 212, 179, 125, 250, 239, 197, 145],
+//*/ Rcon = strhex('01020408102040801b366cd8ab4d9a2f5ebc63c697356ad4b37dfaefc591',2),
+
+/*
+ G2X = [
+ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16,
+ 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e,
+ 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46,
+ 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
+ 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76,
+ 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
+ 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6,
+ 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
+ 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6,
+ 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee,
+ 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d,
+ 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
+ 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d,
+ 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55,
+ 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d,
+ 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
+ 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d,
+ 0x83, 0x81, 0x87, 0x85, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5,
+ 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd,
+ 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
+ 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed,
+ 0xe3, 0xe1, 0xe7, 0xe5
+ ], //*/ G2X = Gx(2),
+
+/* G3X = [
+ 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d,
+ 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39,
+ 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65,
+ 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
+ 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d,
+ 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9,
+ 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5,
+ 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
+ 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd,
+ 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99,
+ 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e,
+ 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
+ 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6,
+ 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2,
+ 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce,
+ 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
+ 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46,
+ 0x4f, 0x4c, 0x49, 0x4a, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62,
+ 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e,
+ 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
+ 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16,
+ 0x1f, 0x1c, 0x19, 0x1a
+ ], //*/ G3X = Gx(3),
+
+/*
+ G9X = [
+ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53,
+ 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf,
+ 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20,
+ 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
+ 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8,
+ 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49,
+ 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd,
+ 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
+ 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e,
+ 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2,
+ 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7,
+ 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
+ 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f,
+ 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8,
+ 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c,
+ 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
+ 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9,
+ 0xf6, 0xff, 0xe4, 0xed, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35,
+ 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba,
+ 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
+ 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62,
+ 0x5d, 0x54, 0x4f, 0x46
+ ], //*/ G9X = Gx(9),
+
+/* GBX = [
+ 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45,
+ 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81,
+ 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66,
+ 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
+ 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e,
+ 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7,
+ 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b,
+ 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
+ 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8,
+ 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c,
+ 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea,
+ 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
+ 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02,
+ 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd,
+ 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21,
+ 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
+ 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44,
+ 0x75, 0x7e, 0x63, 0x68, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80,
+ 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67,
+ 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
+ 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f,
+ 0xbe, 0xb5, 0xa8, 0xa3
+ ], //*/ GBX = Gx(0xb),
+
+/*
+ GDX = [
+ 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f,
+ 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3,
+ 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac,
+ 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
+ 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14,
+ 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e,
+ 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa,
+ 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
+ 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9,
+ 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25,
+ 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd,
+ 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
+ 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75,
+ 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42,
+ 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6,
+ 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
+ 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8,
+ 0xeb, 0xe6, 0xf1, 0xfc, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44,
+ 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b,
+ 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
+ 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3,
+ 0x80, 0x8d, 0x9a, 0x97
+ ], //*/ GDX = Gx(0xd),
+
+/*
+ GEX = [
+ 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62,
+ 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca,
+ 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9,
+ 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
+ 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59,
+ 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87,
+ 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f,
+ 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
+ 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14,
+ 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc,
+ 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53,
+ 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
+ 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3,
+ 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0,
+ 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68,
+ 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
+ 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e,
+ 0xa4, 0xaa, 0xb8, 0xb6, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26,
+ 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25,
+ 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
+ 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5,
+ 0x9f, 0x91, 0x83, 0x8d
+ ], //*/ GEX = Gx(0xe),
+
+ enc = function(string, pass, binary) {
+ // string, password in plaintext
+ var salt = randArr(8),
+ pbe = openSSLKey(s2a(pass, binary), salt),
+ key = pbe.key,
+ iv = pbe.iv,
+ cipherBlocks,
+ saltBlock = [[83, 97, 108, 116, 101, 100, 95, 95].concat(salt)];
+ string = s2a(string, binary);
+ cipherBlocks = rawEncrypt(string, key, iv);
+ // Spells out 'Salted__'
+ cipherBlocks = saltBlock.concat(cipherBlocks);
+ return Base64.encode(cipherBlocks);
+ },
+
+ dec = function(string, pass, binary) {
+ // string, password in plaintext
+ var cryptArr = Base64.decode(string),
+ salt = cryptArr.slice(8, 16),
+ pbe = openSSLKey(s2a(pass, binary), salt),
+ key = pbe.key,
+ iv = pbe.iv;
+ cryptArr = cryptArr.slice(16, cryptArr.length);
+ // Take off the Salted__ffeeddcc
+ string = rawDecrypt(cryptArr, key, iv, binary);
+ return string;
+ },
+
+ MD5 = function(numArr) {
+
+ function rotateLeft(lValue, iShiftBits) {
+ return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
+ }
+
+ function addUnsigned(lX, lY) {
+ var lX4,
+ lY4,
+ lX8,
+ lY8,
+ lResult;
+ lX8 = (lX & 0x80000000);
+ lY8 = (lY & 0x80000000);
+ lX4 = (lX & 0x40000000);
+ lY4 = (lY & 0x40000000);
+ lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
+ if (lX4 & lY4) {
+ return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
+ }
+ if (lX4 | lY4) {
+ if (lResult & 0x40000000) {
+ return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
+ } else {
+ return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
+ }
+ } else {
+ return (lResult ^ lX8 ^ lY8);
+ }
+ }
+
+ function f(x, y, z) {
+ return (x & y) | ((~x) & z);
+ }
+ function g(x, y, z) {
+ return (x & z) | (y & (~z));
+ }
+ function h(x, y, z) {
+ return (x ^ y ^ z);
+ }
+ function funcI(x, y, z) {
+ return (y ^ (x | (~z)));
+ }
+
+ function ff(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(f(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function gg(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(g(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function hh(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(h(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function ii(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(funcI(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function convertToWordArray(numArr) {
+ var lWordCount,
+ lMessageLength = numArr.length,
+ lNumberOfWords_temp1 = lMessageLength + 8,
+ lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64,
+ lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16,
+ lWordArray = [],
+ lBytePosition = 0,
+ lByteCount = 0;
+ while (lByteCount < lMessageLength) {
+ lWordCount = (lByteCount - (lByteCount % 4)) / 4;
+ lBytePosition = (lByteCount % 4) * 8;
+ lWordArray[lWordCount] = (lWordArray[lWordCount] | (numArr[lByteCount] << lBytePosition));
+ lByteCount++;
+ }
+ lWordCount = (lByteCount - (lByteCount % 4)) / 4;
+ lBytePosition = (lByteCount % 4) * 8;
+ lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
+ lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
+ lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
+ return lWordArray;
+ }
+
+ function wordToHex(lValue) {
+ var lByte,
+ lCount,
+ wordToHexArr = [];
+ for (lCount = 0; lCount <= 3; lCount++) {
+ lByte = (lValue >>> (lCount * 8)) & 255;
+ wordToHexArr = wordToHexArr.concat(lByte);
+ }
+ return wordToHexArr;
+ }
+
+ /*function utf8Encode(string) {
+ string = string.replace(/\r\n/g, "\n");
+ var utftext = "",
+ n,
+ c;
+
+ for (n = 0; n < string.length; n++) {
+
+ c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if ((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+
+ }
+
+ return utftext;
+ }*/
+
+ var x = [],
+ k,
+ AA,
+ BB,
+ CC,
+ DD,
+ a,
+ b,
+ c,
+ d,
+ rnd = strhex('67452301efcdab8998badcfe10325476d76aa478e8c7b756242070dbc1bdceeef57c0faf4787c62aa8304613fd469501698098d88b44f7afffff5bb1895cd7be6b901122fd987193a679438e49b40821f61e2562c040b340265e5a51e9b6c7aad62f105d02441453d8a1e681e7d3fbc821e1cde6c33707d6f4d50d87455a14eda9e3e905fcefa3f8676f02d98d2a4c8afffa39428771f6816d9d6122fde5380ca4beea444bdecfa9f6bb4b60bebfbc70289b7ec6eaa127fad4ef308504881d05d9d4d039e6db99e51fa27cf8c4ac5665f4292244432aff97ab9423a7fc93a039655b59c38f0ccc92ffeff47d85845dd16fa87e4ffe2ce6e0a30143144e0811a1f7537e82bd3af2352ad7d2bbeb86d391',8);
+
+ x = convertToWordArray(numArr);
+
+ a = rnd[0];
+ b = rnd[1];
+ c = rnd[2];
+ d = rnd[3];
+
+ for (k = 0; k < x.length; k += 16) {
+ AA = a;
+ BB = b;
+ CC = c;
+ DD = d;
+ a = ff(a, b, c, d, x[k + 0], 7, rnd[4]);
+ d = ff(d, a, b, c, x[k + 1], 12, rnd[5]);
+ c = ff(c, d, a, b, x[k + 2], 17, rnd[6]);
+ b = ff(b, c, d, a, x[k + 3], 22, rnd[7]);
+ a = ff(a, b, c, d, x[k + 4], 7, rnd[8]);
+ d = ff(d, a, b, c, x[k + 5], 12, rnd[9]);
+ c = ff(c, d, a, b, x[k + 6], 17, rnd[10]);
+ b = ff(b, c, d, a, x[k + 7], 22, rnd[11]);
+ a = ff(a, b, c, d, x[k + 8], 7, rnd[12]);
+ d = ff(d, a, b, c, x[k + 9], 12, rnd[13]);
+ c = ff(c, d, a, b, x[k + 10], 17, rnd[14]);
+ b = ff(b, c, d, a, x[k + 11], 22, rnd[15]);
+ a = ff(a, b, c, d, x[k + 12], 7, rnd[16]);
+ d = ff(d, a, b, c, x[k + 13], 12, rnd[17]);
+ c = ff(c, d, a, b, x[k + 14], 17, rnd[18]);
+ b = ff(b, c, d, a, x[k + 15], 22, rnd[19]);
+ a = gg(a, b, c, d, x[k + 1], 5, rnd[20]);
+ d = gg(d, a, b, c, x[k + 6], 9, rnd[21]);
+ c = gg(c, d, a, b, x[k + 11], 14, rnd[22]);
+ b = gg(b, c, d, a, x[k + 0], 20, rnd[23]);
+ a = gg(a, b, c, d, x[k + 5], 5, rnd[24]);
+ d = gg(d, a, b, c, x[k + 10], 9, rnd[25]);
+ c = gg(c, d, a, b, x[k + 15], 14, rnd[26]);
+ b = gg(b, c, d, a, x[k + 4], 20, rnd[27]);
+ a = gg(a, b, c, d, x[k + 9], 5, rnd[28]);
+ d = gg(d, a, b, c, x[k + 14], 9, rnd[29]);
+ c = gg(c, d, a, b, x[k + 3], 14, rnd[30]);
+ b = gg(b, c, d, a, x[k + 8], 20, rnd[31]);
+ a = gg(a, b, c, d, x[k + 13], 5, rnd[32]);
+ d = gg(d, a, b, c, x[k + 2], 9, rnd[33]);
+ c = gg(c, d, a, b, x[k + 7], 14, rnd[34]);
+ b = gg(b, c, d, a, x[k + 12], 20, rnd[35]);
+ a = hh(a, b, c, d, x[k + 5], 4, rnd[36]);
+ d = hh(d, a, b, c, x[k + 8], 11, rnd[37]);
+ c = hh(c, d, a, b, x[k + 11], 16, rnd[38]);
+ b = hh(b, c, d, a, x[k + 14], 23, rnd[39]);
+ a = hh(a, b, c, d, x[k + 1], 4, rnd[40]);
+ d = hh(d, a, b, c, x[k + 4], 11, rnd[41]);
+ c = hh(c, d, a, b, x[k + 7], 16, rnd[42]);
+ b = hh(b, c, d, a, x[k + 10], 23, rnd[43]);
+ a = hh(a, b, c, d, x[k + 13], 4, rnd[44]);
+ d = hh(d, a, b, c, x[k + 0], 11, rnd[45]);
+ c = hh(c, d, a, b, x[k + 3], 16, rnd[46]);
+ b = hh(b, c, d, a, x[k + 6], 23, rnd[47]);
+ a = hh(a, b, c, d, x[k + 9], 4, rnd[48]);
+ d = hh(d, a, b, c, x[k + 12], 11, rnd[49]);
+ c = hh(c, d, a, b, x[k + 15], 16, rnd[50]);
+ b = hh(b, c, d, a, x[k + 2], 23, rnd[51]);
+ a = ii(a, b, c, d, x[k + 0], 6, rnd[52]);
+ d = ii(d, a, b, c, x[k + 7], 10, rnd[53]);
+ c = ii(c, d, a, b, x[k + 14], 15, rnd[54]);
+ b = ii(b, c, d, a, x[k + 5], 21, rnd[55]);
+ a = ii(a, b, c, d, x[k + 12], 6, rnd[56]);
+ d = ii(d, a, b, c, x[k + 3], 10, rnd[57]);
+ c = ii(c, d, a, b, x[k + 10], 15, rnd[58]);
+ b = ii(b, c, d, a, x[k + 1], 21, rnd[59]);
+ a = ii(a, b, c, d, x[k + 8], 6, rnd[60]);
+ d = ii(d, a, b, c, x[k + 15], 10, rnd[61]);
+ c = ii(c, d, a, b, x[k + 6], 15, rnd[62]);
+ b = ii(b, c, d, a, x[k + 13], 21, rnd[63]);
+ a = ii(a, b, c, d, x[k + 4], 6, rnd[64]);
+ d = ii(d, a, b, c, x[k + 11], 10, rnd[65]);
+ c = ii(c, d, a, b, x[k + 2], 15, rnd[66]);
+ b = ii(b, c, d, a, x[k + 9], 21, rnd[67]);
+ a = addUnsigned(a, AA);
+ b = addUnsigned(b, BB);
+ c = addUnsigned(c, CC);
+ d = addUnsigned(d, DD);
+ }
+
+ return wordToHex(a).concat(wordToHex(b), wordToHex(c), wordToHex(d));
+ },
+
+ encString = function(plaintext, key, iv) {
+ var i;
+ plaintext = s2a(plaintext);
+
+ key = s2a(key);
+ for (i=key.length; i<32; i++){
+ key[i] = 0;
+ }
+
+ if (iv === undefined) {
+ // TODO: This is not defined anywhere... commented out...
+ // iv = genIV();
+ } else {
+ iv = s2a(iv);
+ for (i=iv.length; i<16; i++){
+ iv[i] = 0;
+ }
+ }
+
+ var ct = rawEncrypt(plaintext, key, iv);
+ var ret = [iv];
+ for (i=0; i<ct.length; i++){
+ ret[ret.length] = ct[i];
+ }
+ return Base64.encode(ret);
+ },
+
+ decString = function(ciphertext, key) {
+ var tmp = Base64.decode(ciphertext);
+ var iv = tmp.slice(0, 16);
+ var ct = tmp.slice(16, tmp.length);
+ var i;
+
+ key = s2a(key);
+ for (i=key.length; i<32; i++){
+ key[i] = 0;
+ }
+
+ var pt = rawDecrypt(ct, key, iv, false);
+ return pt;
+ },
+
+ Base64 = (function(){
+ // Takes a Nx16x1 byte array and converts it to Base64
+ var _chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
+ chars = _chars.split(''),
+
+ encode = function(b, withBreaks) {
+ var flatArr = [],
+ b64 = '',
+ i,
+ broken_b64,
+ totalChunks = Math.floor(b.length * 16 / 3);
+ for (i = 0; i < b.length * 16; i++) {
+ flatArr.push(b[Math.floor(i / 16)][i % 16]);
+ }
+ for (i = 0; i < flatArr.length; i = i + 3) {
+ b64 += chars[flatArr[i] >> 2];
+ b64 += chars[((flatArr[i] & 3) << 4) | (flatArr[i + 1] >> 4)];
+ if ( flatArr[i + 1] !== undefined ) {
+ b64 += chars[((flatArr[i + 1] & 15) << 2) | (flatArr[i + 2] >> 6)];
+ } else {
+ b64 += '=';
+ }
+ if ( flatArr[i + 2] !== undefined ) {
+ b64 += chars[flatArr[i + 2] & 63];
+ } else {
+ b64 += '=';
+ }
+ }
+ // OpenSSL is super particular about line breaks
+ broken_b64 = b64.slice(0, 64) + '\n';
+ for (i = 1; i < (Math.ceil(b64.length / 64)); i++) {
+ broken_b64 += b64.slice(i * 64, i * 64 + 64) + (Math.ceil(b64.length / 64) === i + 1 ? '': '\n');
+ }
+ return broken_b64;
+ },
+
+ decode = function(string) {
+ string = string.replace(/\n/g, '');
+ var flatArr = [],
+ c = [],
+ b = [],
+ i;
+ for (i = 0; i < string.length; i = i + 4) {
+ c[0] = _chars.indexOf(string.charAt(i));
+ c[1] = _chars.indexOf(string.charAt(i + 1));
+ c[2] = _chars.indexOf(string.charAt(i + 2));
+ c[3] = _chars.indexOf(string.charAt(i + 3));
+
+ b[0] = (c[0] << 2) | (c[1] >> 4);
+ b[1] = ((c[1] & 15) << 4) | (c[2] >> 2);
+ b[2] = ((c[2] & 3) << 6) | c[3];
+ flatArr.push(b[0], b[1], b[2]);
+ }
+ flatArr = flatArr.slice(0, flatArr.length - (flatArr.length % 16));
+ return flatArr;
+ };
+
+ //internet explorer
+ if(typeof Array.indexOf === "function") {
+ _chars = chars;
+ }
+
+ /*
+ //other way to solve internet explorer problem
+ if(!Array.indexOf){
+ Array.prototype.indexOf = function(obj){
+ for(var i=0; i<this.length; i++){
+ if(this[i]===obj){
+ return i;
+ }
+ }
+ return -1;
+ }
+ }
+ */
+
+
+ return {
+ "encode": encode,
+ "decode": decode
+ };
+ })();
+
+ return {
+ "size": size,
+ "h2a":h2a,
+ "expandKey":expandKey,
+ "encryptBlock":encryptBlock,
+ "decryptBlock":decryptBlock,
+ "Decrypt":Decrypt,
+ "s2a":s2a,
+ "rawEncrypt":rawEncrypt,
+ "rawDecrypt":rawDecrypt,
+ "dec":dec,
+ "openSSLKey":openSSLKey,
+ "a2h":a2h,
+ "enc":enc,
+ "Hash":{"MD5":MD5},
+ "Base64":Base64
+ };
+
+})); \ No newline at end of file
diff --git a/libgpl/http_request/class.http.php b/libgpl/http_request/class.http.php
new file mode 100644
index 0000000..a41d070
--- /dev/null
+++ b/libgpl/http_request/class.http.php
@@ -0,0 +1,1190 @@
+<?php
+
+/**
+ * HTTP Class
+ *
+ * This is a wrapper HTTP class that uses either cURL or fsockopen to
+ * harvest resources from web. This can be used with scripts that need
+ * a way to communicate with various APIs who support REST.
+ *
+ * @author Md Emran Hasan <phpfour@gmail.com>
+ * @package HTTP Library
+ * @copyright 2007-2008 Md Emran Hasan
+ * @link http://www.phpfour.com/lib/http
+ * @since Version 0.1
+ */
+
+class MyRCHttp
+{
+ /**
+ * Contains the target URL
+ *
+ * @var string
+ */
+ var $target;
+
+ /**
+ * Contains the target host
+ *
+ * @var string
+ */
+ var $host;
+
+ /**
+ * Contains the target port
+ *
+ * @var integer
+ */
+ var $port;
+
+ /**
+ * Contains the target path
+ *
+ * @var string
+ */
+ var $path;
+
+ /**
+ * Contains the target schema
+ *
+ * @var string
+ */
+ var $schema;
+
+ /**
+ * Contains the http method (GET or POST)
+ *
+ * @var string
+ */
+ var $method;
+
+ /**
+ * Contains the parameters for request
+ *
+ * @var array
+ */
+ var $params;
+
+ /**
+ * Contains the cookies for request
+ *
+ * @var array
+ */
+ var $cookies;
+
+ /**
+ * Contains the cookies retrieved from response
+ *
+ * @var array
+ */
+ var $_cookies;
+
+ /**
+ * Number of seconds to timeout
+ *
+ * @var integer
+ */
+ var $timeout;
+
+ /**
+ * Whether to use cURL or not
+ *
+ * @var boolean
+ */
+ var $useCurl;
+
+ /**
+ * Contains the referrer URL
+ *
+ * @var string
+ */
+ var $referrer;
+
+ /**
+ * Contains the User agent string
+ *
+ * @var string
+ */
+ var $userAgent;
+
+ /**
+ * Contains the cookie path (to be used with cURL)
+ *
+ * @var string
+ */
+ var $cookiePath;
+
+ /**
+ * Whether to use cookie at all
+ *
+ * @var boolean
+ */
+ var $useCookie;
+
+ /**
+ * Whether to store cookie for subsequent requests
+ *
+ * @var boolean
+ */
+ var $saveCookie;
+
+ /**
+ * Contains the Username (for authentication)
+ *
+ * @var string
+ */
+ var $username;
+
+ /**
+ * Contains the Password (for authentication)
+ *
+ * @var string
+ */
+ var $password;
+
+ /**
+ * Contains the fetched web source
+ *
+ * @var string
+ */
+ var $result;
+
+ /**
+ * Contains the last headers
+ *
+ * @var string
+ */
+ var $headers;
+
+ /**
+ * Contains the last call's http status code
+ *
+ * @var string
+ */
+ var $status;
+
+ /**
+ * Whether to follow http redirect or not
+ *
+ * @var boolean
+ */
+ var $redirect;
+
+ /**
+ * The maximum number of redirect to follow
+ *
+ * @var integer
+ */
+ var $maxRedirect;
+
+ /**
+ * The current number of redirects
+ *
+ * @var integer
+ */
+ var $curRedirect;
+
+ /**
+ * Contains any error occurred
+ *
+ * @var string
+ */
+ var $error;
+
+ /**
+ * Store the next token
+ *
+ * @var string
+ */
+ var $nextToken;
+
+ /**
+ * Whether to keep debug messages
+ *
+ * @var boolean
+ */
+ var $debug;
+
+ /**
+ * Stores the debug messages
+ *
+ * @var array
+ * @todo will keep debug messages
+ */
+ var $debugMsg;
+
+ /**
+ * Constructor for initializing the class with default values.
+ *
+ * @return void
+ */
+ function Http()
+ {
+ $this->clear();
+ }
+
+ /**
+ * Initialize preferences
+ *
+ * This function will take an associative array of config values and
+ * will initialize the class variables using them.
+ *
+ * Example use:
+ *
+ * <pre>
+ * $httpConfig['method'] = 'GET';
+ * $httpConfig['target'] = 'http://www.somedomain.com/index.html';
+ * $httpConfig['referrer'] = 'http://www.somedomain.com';
+ * $httpConfig['user_agent'] = 'My Crawler';
+ * $httpConfig['timeout'] = '30';
+ * $httpConfig['params'] = array('var1' => 'testvalue', 'var2' => 'somevalue');
+ *
+ * $http = new Http();
+ * $http->initialize($httpConfig);
+ * </pre>
+ *
+ * @param array Config values as associative array
+ * @return void
+ */
+ function initialize($config = array())
+ {
+ $this->clear();
+ foreach ($config as $key => $val)
+ {
+ if (isset($this->$key))
+ {
+ $method = 'set' . ucfirst(str_replace('_', '', $key));
+
+ if (method_exists($this, $method))
+ {
+ $this->$method($val);
+ }
+ else
+ {
+ $this->$key = $val;
+ }
+ }
+ }
+ }
+
+ /**
+ * Clear Everything
+ *
+ * Clears all the properties of the class and sets the object to
+ * the beginning state. Very handy if you are doing subsequent calls
+ * with different data.
+ *
+ * @return void
+ */
+ function clear()
+ {
+ // Set the request defaults
+ $this->host = '';
+ $this->port = 0;
+ $this->path = '';
+ $this->target = '';
+ $this->method = 'GET';
+ $this->schema = 'http';
+ $this->params = array();
+ $this->headers = array();
+ $this->cookies = array();
+ $this->_cookies = array();
+
+ // Set the config details
+ $this->debug = FALSE;
+ $this->error = '';
+ $this->status = 0;
+ $this->timeout = '25';
+ $this->useCurl = TRUE;
+ $this->referrer = '';
+ $this->username = '';
+ $this->password = '';
+ $this->redirect = TRUE;
+
+ // Set the cookie and agent defaults
+ $this->nextToken = '';
+ $this->useCookie = TRUE;
+ $this->saveCookie = TRUE;
+ $this->maxRedirect = 3;
+ $this->cookiePath = 'cookie.txt';
+ $this->userAgent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.9';
+ }
+
+ /**
+ * Set target URL
+ *
+ * @param string URL of target resource
+ * @return void
+ */
+ function setTarget($url)
+ {
+ if ($url)
+ {
+ $this->target = $url;
+ }
+ }
+
+ /**
+ * Set http method
+ *
+ * @param string HTTP method to use (GET or POST)
+ * @return void
+ */
+ function setMethod($method)
+ {
+ if ($method == 'GET' || $method == 'POST')
+ {
+ $this->method = $method;
+ }
+ }
+
+ /**
+ * Set referrer URL
+ *
+ * @param string URL of referrer page
+ * @return void
+ */
+ function setReferrer($referrer)
+ {
+ if ($referrer)
+ {
+ $this->referrer = $referrer;
+ }
+ }
+
+ /**
+ * Set User agent string
+ *
+ * @param string Full user agent string
+ * @return void
+ */
+ function setUseragent($agent)
+ {
+ if ($agent)
+ {
+ $this->userAgent = $agent;
+ }
+ }
+
+ /**
+ * Set timeout of execution
+ *
+ * @param integer Timeout delay in seconds
+ * @return void
+ */
+ function setTimeout($seconds)
+ {
+ if ($seconds > 0)
+ {
+ $this->timeout = $seconds;
+ }
+ }
+
+ /**
+ * Set cookie path (cURL only)
+ *
+ * @param string File location of cookiejar
+ * @return void
+ */
+ function setCookiepath($path)
+ {
+ if ($path)
+ {
+ $this->cookiePath = $path;
+ }
+ }
+
+ /**
+ * Set request parameters
+ *
+ * @param array All the parameters for GET or POST
+ * @return void
+ */
+ function setParams($dataArray)
+ {
+ if (is_array($dataArray))
+ {
+ $this->params = array_merge($this->params, $dataArray);
+ }
+ }
+
+ /**
+ * Set basic http authentication realm
+ *
+ * @param string Username for authentication
+ * @param string Password for authentication
+ * @return void
+ */
+ function setAuth($username, $password)
+ {
+ if (!empty($username) && !empty($password))
+ {
+ $this->username = $username;
+ $this->password = $password;
+ }
+ }
+
+ /**
+ * Set maximum number of redirection to follow
+ *
+ * @param integer Maximum number of redirects
+ * @return void
+ */
+ function setMaxredirect($value)
+ {
+ if (!empty($value))
+ {
+ $this->maxRedirect = $value;
+ }
+ }
+
+ /**
+ * Add request parameters
+ *
+ * @param string Name of the parameter
+ * @param string Value of the parameter
+ * @return void
+ */
+ function addParam($name, $value)
+ {
+ if (!empty($name) && !empty($value))
+ {
+ $this->params[$name] = $value;
+ }
+ }
+
+ /**
+ * Add a cookie to the request
+ *
+ * @param string Name of cookie
+ * @param string Value of cookie
+ * @return void
+ */
+ function addCookie($name, $value)
+ {
+ if (!empty($name) && !empty($value))
+ {
+ $this->cookies[$name] = $value;
+ }
+ }
+
+ /**
+ * Whether to use cURL or not
+ *
+ * @param boolean Whether to use cURL or not
+ * @return void
+ */
+ function useCurl($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->useCurl = $value;
+ }
+ }
+
+ /**
+ * Whether to use cookies or not
+ *
+ * @param boolean Whether to use cookies or not
+ * @return void
+ */
+ function useCookie($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->useCookie = $value;
+ }
+ }
+
+ /**
+ * Whether to save persistent cookies in subsequent calls
+ *
+ * @param boolean Whether to save persistent cookies or not
+ * @return void
+ */
+ function saveCookie($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->saveCookie = $value;
+ }
+ }
+
+ /**
+ * Whether to follow HTTP redirects
+ *
+ * @param boolean Whether to follow HTTP redirects or not
+ * @return void
+ */
+ function followRedirects($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->redirect = $value;
+ }
+ }
+
+ /**
+ * Get execution result body
+ *
+ * @return string output of execution
+ */
+ function getResult()
+ {
+ return $this->result;
+ }
+
+ /**
+ * Get execution result headers
+ *
+ * @return array last headers of execution
+ */
+ function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Get execution status code
+ *
+ * @return integer last http status code
+ */
+ function getStatus()
+ {
+ return $this->status;
+ }
+
+ /**
+ * Get last execution error
+ *
+ * @return string last error message (if any)
+ */
+ function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * Execute a HTTP request
+ *
+ * Executes the http fetch using all the set properties. Intellegently
+ * switch to fsockopen if cURL is not present. And be smart to follow
+ * redirects (if asked so).
+ *
+ * @param string URL of the target page (optional)
+ * @param string URL of the referrer page (optional)
+ * @param string The http method (GET or POST) (optional)
+ * @param array Parameter array for GET or POST (optional)
+ * @return string Response body of the target page
+ */
+ function execute($target = '', $referrer = '', $method = '', $data = array())
+ {
+ // Populate the properties
+ $this->target = ($target) ? $target : $this->target;
+ $this->method = ($method) ? $method : $this->method;
+
+ $this->referrer = ($referrer) ? $referrer : $this->referrer;
+
+ // Add the new params
+ if (is_array($data) && count($data) > 0)
+ {
+ $this->params = array_merge($this->params, $data);
+ }
+
+ // Process data, if presented
+ if(is_array($this->params) && count($this->params) > 0)
+ {
+ // Get a blank slate
+ $tempString = array();
+
+ // Convert data array into a query string (ie animal=dog&sport=baseball)
+ foreach ($this->params as $key => $value)
+ {
+ if(strlen(trim($value))>0)
+ {
+ $tempString[] = $key . "=" . urlencode($value);
+ }
+ }
+
+ $queryString = join('&', $tempString);
+ }
+
+ // If cURL is not installed, we'll force fscokopen
+ $this->useCurl = $this->useCurl && in_array('curl', get_loaded_extensions());
+
+ // GET method configuration
+ if($this->method == 'GET')
+ {
+ if(isset($queryString))
+ {
+ $this->target = $this->target . "?" . $queryString;
+ }
+ }
+
+ // Parse target URL
+ $urlParsed = parse_url($this->target);
+
+ // Handle SSL connection request
+ if ($urlParsed['scheme'] == 'https')
+ {
+ $this->host = 'ssl://' . $urlParsed['host'];
+ $this->port = ($this->port != 0) ? $this->port : 443;
+ }
+ else
+ {
+ $this->host = $urlParsed['host'];
+ $this->port = ($this->port != 0) ? $this->port : 80;
+ }
+
+ // Finalize the target path
+ $this->path = (isset($urlParsed['path']) ? $urlParsed['path'] : '/') . (isset($urlParsed['query']) ? '?' . $urlParsed['query'] : '');
+ $this->schema = $urlParsed['scheme'];
+
+ // Pass the requred cookies
+ $this->_passCookies();
+
+ // Process cookies, if requested
+ if(is_array($this->cookies) && count($this->cookies) > 0)
+ {
+ // Get a blank slate
+ $tempString = array();
+
+ // Convert cookiesa array into a query string (ie animal=dog&sport=baseball)
+ foreach ($this->cookies as $key => $value)
+ {
+ if(strlen(trim($value)) > 0)
+ {
+ $tempString[] = $key . "=" . urlencode($value);
+ }
+ }
+
+ $cookieString = join('&', $tempString);
+ }
+
+ // Do we need to use cURL
+ if ($this->useCurl)
+ {
+ // Initialize PHP cURL handle
+ $ch = curl_init();
+
+ // GET method configuration
+ if($this->method == 'GET')
+ {
+ curl_setopt ($ch, CURLOPT_HTTPGET, TRUE);
+ curl_setopt ($ch, CURLOPT_POST, FALSE);
+ }
+ // POST method configuration
+ else
+ {
+ if(isset($queryString))
+ {
+ curl_setopt ($ch, CURLOPT_POSTFIELDS, $queryString);
+ }
+
+ curl_setopt ($ch, CURLOPT_POST, TRUE);
+ curl_setopt ($ch, CURLOPT_HTTPGET, FALSE);
+ }
+
+ // Basic Authentication configuration
+ if ($this->username && $this->password)
+ {
+ curl_setopt($ch, CURLOPT_USERPWD, $this->username . ':' . $this->password);
+ }
+
+ // Custom cookie configuration
+ if($this->useCookie && isset($cookieString))
+ {
+ curl_setopt ($ch, CURLOPT_COOKIE, $cookieString);
+ }
+
+ curl_setopt($ch, CURLOPT_HEADER, TRUE); // No need of headers
+ curl_setopt($ch, CURLOPT_NOBODY, FALSE); // Return body
+
+ curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookiePath); // Cookie management.
+ curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); // Timeout
+ curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent); // Webbot name
+ curl_setopt($ch, CURLOPT_URL, $this->target); // Target site
+ curl_setopt($ch, CURLOPT_REFERER, $this->referrer); // Referer value
+
+ curl_setopt($ch, CURLOPT_VERBOSE, FALSE); // Minimize logs
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // No certificate
+ if(!ini_get('safe_mode') && !ini_get('open_basedir')){
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->redirect); // Follow redirects
+ }
+ curl_setopt($ch, CURLOPT_MAXREDIRS, $this->maxRedirect); // Limit redirections to four
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // Return in string
+
+ // Get the target contents
+ $content = curl_exec($ch);
+ $contentArray = explode("\r\n\r\n", $content);
+
+ // Get the request info
+ $status = curl_getinfo($ch);
+
+ // Store the contents
+ $this->result = $contentArray[count($contentArray) - 1];
+
+ // Parse the headers
+ $this->_parseHeaders($contentArray[count($contentArray) - 2]);
+
+ // Store the error (is any)
+ $this->_setError(curl_error($ch));
+
+ // Close PHP cURL handle
+ curl_close($ch);
+ }
+ else
+ {
+ // Get a file pointer
+ $filePointer = fsockopen($this->host, $this->port, $errorNumber, $errorString, $this->timeout);
+
+ // We have an error if pointer is not there
+ if (!$filePointer)
+ {
+ $this->_setError('Failed opening http socket connection: ' . $errorString . ' (' . $errorNumber . ')');
+ return FALSE;
+ }
+
+ // Set http headers with host, user-agent and content type
+ $requestHeader = $this->method . " " . $this->path . " HTTP/1.1\r\n";
+ $requestHeader .= "Host: " . $urlParsed['host'] . "\r\n";
+ $requestHeader .= "User-Agent: " . $this->userAgent . "\r\n";
+ $requestHeader .= "Content-Type: application/x-www-form-urlencoded\r\n";
+
+ // Specify the custom cookies
+ if ($this->useCookie && $cookieString != '')
+ {
+ $requestHeader.= "Cookie: " . $cookieString . "\r\n";
+ }
+
+ // POST method configuration
+ if ($this->method == "POST")
+ {
+ $requestHeader.= "Content-Length: " . strlen($queryString) . "\r\n";
+ }
+
+ // Specify the referrer
+ if ($this->referrer != '')
+ {
+ $requestHeader.= "Referer: " . $this->referrer . "\r\n";
+ }
+
+ // Specify http authentication (basic)
+ if ($this->username && $this->password)
+ {
+ $requestHeader.= "Authorization: Basic " . base64_encode($this->username . ':' . $this->password) . "\r\n";
+ }
+
+ $requestHeader.= "Connection: close\r\n\r\n";
+
+ // POST method configuration
+ if ($this->method == "POST")
+ {
+ $requestHeader .= $queryString;
+ }
+
+ // We're ready to launch
+ fwrite($filePointer, $requestHeader);
+
+ // Clean the slate
+ $responseHeader = '';
+ $responseContent = '';
+
+ // 3...2...1...Launch !
+ do
+ {
+ $responseHeader .= fread($filePointer, 1);
+ }
+ while (!preg_match('/\\r\\n\\r\\n$/', $responseHeader));
+
+ // Parse the headers
+ $this->_parseHeaders($responseHeader);
+
+ // Do we have a 301/302 redirect ?
+ if (($this->status == '301' || $this->status == '302') && $this->redirect == TRUE)
+ {
+ if ($this->curRedirect < $this->maxRedirect)
+ {
+ // Let's find out the new redirect URL
+ $newUrlParsed = parse_url($this->headers['location']);
+
+ if ($newUrlParsed['host'])
+ {
+ $newTarget = $this->headers['location'];
+ }
+ else
+ {
+ $newTarget = $this->schema . '://' . $this->host . '/' . $this->headers['location'];
+ }
+
+ // Reset some of the properties
+ $this->port = 0;
+ $this->status = 0;
+ $this->params = array();
+ $this->method = 'GET';
+ $this->referrer = $this->target;
+
+ // Increase the redirect counter
+ $this->curRedirect++;
+
+ // Let's go, go, go !
+ $this->result = $this->execute($newTarget);
+ }
+ else
+ {
+ $this->_setError('Too many redirects.');
+ return FALSE;
+ }
+ }
+ else
+ {
+ // Nope...so lets get the rest of the contents (non-chunked)
+ if ($this->headers['transfer-encoding'] != 'chunked')
+ {
+ while (!feof($filePointer))
+ {
+ $responseContent .= fgets($filePointer, 128);
+ }
+ }
+ else
+ {
+ // Get the contents (chunked)
+ while ($chunkLength = hexdec(fgets($filePointer)))
+ {
+ $responseContentChunk = '';
+ $readLength = 0;
+
+ while ($readLength < $chunkLength)
+ {
+ $responseContentChunk .= fread($filePointer, $chunkLength - $readLength);
+ $readLength = strlen($responseContentChunk);
+ }
+
+ $responseContent .= $responseContentChunk;
+ fgets($filePointer);
+ }
+ }
+
+ // Store the target contents
+ $this->result = chop($responseContent);
+ }
+ }
+
+ // There it is! We have it!! Return to base !!!
+ return $this->result;
+ }
+
+ /**
+ * Parse Headers (internal)
+ *
+ * Parse the response headers and store them for finding the resposne
+ * status, redirection location, cookies, etc.
+ *
+ * @param string Raw header response
+ * @return void
+ * @access private
+ */
+ function _parseHeaders($responseHeader)
+ {
+ // Break up the headers
+ $headers = explode("\r\n", $responseHeader);
+
+ // Clear the header array
+ $this->_clearHeaders();
+
+ // Get response status
+ if($this->status == 0)
+ {
+
+ // Oooops!
+ if(!preg_match("/^http\/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)\$/i", $headers[0], $matches))
+ {
+ $this->_setError('Unexpected HTTP response status');
+ return FALSE;
+ }
+
+ // Gotcha!
+ $this->status = $matches[1];
+ array_shift($headers);
+ }
+
+ // Prepare all the other headers
+ foreach ($headers as $header)
+ {
+ // Get name and value
+ $headerName = strtolower($this->_tokenize($header, ':'));
+ $headerValue = trim(chop($this->_tokenize("\r\n")));
+
+ // If its already there, then add as an array. Otherwise, just keep there
+ if(isset($this->headers[$headerName]))
+ {
+ if(gettype($this->headers[$headerName]) == "string")
+ {
+ $this->headers[$headerName] = array($this->headers[$headerName]);
+ }
+
+ $this->headers[$headerName][] = $headerValue;
+ }
+ else
+ {
+ $this->headers[$headerName] = $headerValue;
+ }
+ }
+
+ // Save cookies if asked
+ if ($this->saveCookie && isset($this->headers['set-cookie']))
+ {
+ $this->_parseCookie();
+ }
+ }
+
+ /**
+ * Clear the headers array (internal)
+ *
+ * @return void
+ * @access private
+ */
+ function _clearHeaders()
+ {
+ $this->headers = array();
+ }
+
+ /**
+ * Parse Cookies (internal)
+ *
+ * Parse the set-cookie headers from response and add them for inclusion.
+ *
+ * @return void
+ * @access private
+ */
+ function _parseCookie()
+ {
+ // Get the cookie header as array
+ if(gettype($this->headers['set-cookie']) == "array")
+ {
+ $cookieHeaders = $this->headers['set-cookie'];
+ }
+ else
+ {
+ $cookieHeaders = array($this->headers['set-cookie']);
+ }
+
+ // Loop through the cookies
+ for ($cookie = 0; $cookie < count($cookieHeaders); $cookie++)
+ {
+ $cookieName = trim($this->_tokenize($cookieHeaders[$cookie], "="));
+ $cookieValue = $this->_tokenize(";");
+
+ $urlParsed = parse_url($this->target);
+
+ $domain = $urlParsed['host'];
+ $secure = '0';
+
+ $path = "/";
+ $expires = "";
+
+ while(($name = trim(urldecode($this->_tokenize("=")))) != "")
+ {
+ $value = urldecode($this->_tokenize(";"));
+
+ switch($name)
+ {
+ case "path" : $path = $value; break;
+ case "domain" : $domain = $value; break;
+ case "secure" : $secure = ($value != '') ? '1' : '0'; break;
+ }
+ }
+
+ $this->_setCookie($cookieName, $cookieValue, $expires, $path , $domain, $secure);
+ }
+ }
+
+ /**
+ * Set cookie (internal)
+ *
+ * Populate the internal _cookies array for future inclusion in
+ * subsequent requests. This actually validates and then populates
+ * the object properties with a dimensional entry for cookie.
+ *
+ * @param string Cookie name
+ * @param string Cookie value
+ * @param string Cookie expire date
+ * @param string Cookie path
+ * @param string Cookie domain
+ * @param string Cookie security (0 = non-secure, 1 = secure)
+ * @return void
+ * @access private
+ */
+ function _setCookie($name, $value, $expires = "" , $path = "/" , $domain = "" , $secure = 0)
+ {
+ if(strlen($name) == 0)
+ {
+ return($this->_setError("No valid cookie name was specified."));
+ }
+
+ if(strlen($path) == 0 || strcmp($path[0], "/"))
+ {
+ return($this->_setError("$path is not a valid path for setting cookie $name."));
+ }
+
+ if($domain == "" || !strpos($domain, ".", $domain[0] == "." ? 1 : 0))
+ {
+ return($this->_setError("$domain is not a valid domain for setting cookie $name."));
+ }
+
+ $domain = strtolower($domain);
+
+ if(!strcmp($domain[0], "."))
+ {
+ $domain = substr($domain, 1);
+ }
+
+ $name = $this->_encodeCookie($name, true);
+ $value = $this->_encodeCookie($value, false);
+
+ $secure = intval($secure);
+
+ $this->_cookies[] = array( "name" => $name,
+ "value" => $value,
+ "domain" => $domain,
+ "path" => $path,
+ "expires" => $expires,
+ "secure" => $secure
+ );
+ }
+
+ /**
+ * Encode cookie name/value (internal)
+ *
+ * @param string Value of cookie to encode
+ * @param string Name of cookie to encode
+ * @return string encoded string
+ * @access private
+ */
+ function _encodeCookie($value, $name)
+ {
+ return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
+ }
+
+ /**
+ * Pass Cookies (internal)
+ *
+ * Get the cookies which are valid for the current request. Checks
+ * domain and path to decide the return.
+ *
+ * @return void
+ * @access private
+ */
+ function _passCookies()
+ {
+ if (is_array($this->_cookies) && count($this->_cookies) > 0)
+ {
+ $urlParsed = parse_url($this->target);
+ $tempCookies = array();
+
+ foreach($this->_cookies as $cookie)
+ {
+ if ($this->_domainMatch($urlParsed['host'], $cookie['domain']) && (0 === strpos($urlParsed['path'], $cookie['path']))
+ && (empty($cookie['secure']) || $urlParsed['protocol'] == 'https'))
+ {
+ $tempCookies[$cookie['name']][strlen($cookie['path'])] = $cookie['value'];
+ }
+ }
+
+ // cookies with longer paths go first
+ foreach ($tempCookies as $name => $values)
+ {
+ krsort($values);
+ foreach ($values as $value)
+ {
+ $this->addCookie($name, $value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if cookie domain matches a request host (internal)
+ *
+ * Cookie domain can begin with a dot, it also must contain at least
+ * two dots.
+ *
+ * @param string Request host
+ * @param string Cookie domain
+ * @return bool Match success
+ * @access private
+ */
+ function _domainMatch($requestHost, $cookieDomain)
+ {
+ if ('.' != $cookieDomain{0})
+ {
+ return $requestHost == $cookieDomain;
+ }
+ elseif (substr_count($cookieDomain, '.') < 2)
+ {
+ return false;
+ }
+ else
+ {
+ return substr('.'. $requestHost, - strlen($cookieDomain)) == $cookieDomain;
+ }
+ }
+
+ /**
+ * Tokenize String (internal)
+ *
+ * Tokenize string for various internal usage. Omit the second parameter
+ * to tokenize the previous string that was provided in the prior call to
+ * the function.
+ *
+ * @param string The string to tokenize
+ * @param string The seperator to use
+ * @return string Tokenized string
+ * @access private
+ */
+ function _tokenize($string, $separator = '')
+ {
+ if(!strcmp($separator, ''))
+ {
+ $separator = $string;
+ $string = $this->nextToken;
+ }
+
+ for($character = 0; $character < strlen($separator); $character++)
+ {
+ if(gettype($position = strpos($string, $separator[$character])) == "integer")
+ {
+ $found = (isset($found) ? min($found, $position) : $position);
+ }
+ }
+
+ if(isset($found))
+ {
+ $this->nextToken = substr($string, $found + 1);
+ return(substr($string, 0, $found));
+ }
+ else
+ {
+ $this->nextToken = '';
+ return($string);
+ }
+ }
+
+ /**
+ * Set error message (internal)
+ *
+ * @param string Error message
+ * @return string Error message
+ * @access private
+ */
+ function _setError($error)
+ {
+ if ($error != '')
+ {
+ $this->error = $error;
+ return $error;
+ }
+ }
+}
+
+?> \ No newline at end of file
diff --git a/libgpl/ical/ical_sync.php b/libgpl/ical/ical_sync.php
new file mode 100644
index 0000000..b513574
--- /dev/null
+++ b/libgpl/ical/ical_sync.php
@@ -0,0 +1,144 @@
+<?php
+/**
+ * iCalendar sync for the Calendar plugin
+ *
+ * @version @package_version@
+ * @author Daniel Morlock <daniel.morlock@awesome-it.de>
+ *
+ * Copyright (C) 2013, Awesome IT GbR <info@awesome-it.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+class ical_sync
+{
+ const ACTION_NONE = 1;
+ const ACTION_UPDATE = 2;
+ const ACTION_CREATE = 4;
+
+ private $cal_id = null;
+ private $url = null;
+ private $user = null;
+ private $pass = null;
+ private $ical = null;
+
+ public $sync = 0;
+
+ /**
+ * Default constructor for calendar synchronization adapter.
+ *
+ * @param int Calendar id.
+ * @param array Hash array with ical properties:
+ * url: Absolute URL to iCAL resource.
+ */
+ public function __construct($cal_id, $props)
+ {
+ $this->ical = libcalendaring::get_ical();
+ $this->cal_id = $cal_id;
+
+ $this->url = $props["url"];
+ $this->user = isset($props["user"]) ? $props["user"] : null;
+ $this->pass = isset($props["pass"]) ? $props["pass"] : null;
+ $this->sync = isset($props["sync"]) ? $props["sync"] : 0;
+ }
+
+ /**
+ * Determines whether current calendar needs to be synced.
+ *
+ * @return True if the current calendar needs to be synced, false otherwise.
+ */
+ public function is_synced()
+ {
+ // No change to check that so far.
+ return false;
+ }
+
+ /**
+ * Fetches events from iCAL resource and returns updates.
+ *
+ * @param array List of local events.
+ * @return array Tuple containing the following lists:
+ *
+ * Hash list for iCAL events to be created or to be updated with the keys:
+ * local_event: The local event in case of an update.
+ * remote_event: The current event retrieved from caldav server.
+ *
+ * A list of event ids that are in sync.
+ */
+ public function get_updates($events)
+ {
+ $context = null;
+ if($this->user != null && $this->pass != null)
+ {
+ $context = stream_context_create(array(
+ 'http' => array(
+ 'header' => "Authorization: Basic " . base64_encode("$this->user:$this->pass") . "\r\n" .
+ "User-Agent: PHP/" . PHP_VERSION
+ )
+ ));
+ }
+
+ $vcal = file_get_contents($this->url, false, $context);
+ $charset = 'UTF-8';
+ foreach($http_response_header as $c => $h)
+ {
+ if(stristr($h, 'content-type') && stristr($h, 'charset'))
+ {
+ preg_match('@Content-Type:\s+([\w/+]+)(;\s+charset=(\S+))?@i', $h, $matches);
+ if(isset($matches[3]))
+ {
+ $charset = strtoupper(trim($matches[3]));
+ }
+ }
+ if(stristr($h, 'content-encoding') && stristr($h, 'gzip'))
+ {
+ $vcal = gzinflate(substr($vcal, 10, -8));
+ }
+ }
+
+ $updates = array();
+ $synced = array();
+ if($vcal !== false)
+ {
+ // Hash existing events by uid.
+ $events_hash = array();
+ foreach($events as $event) {
+ $events_hash[$event['uid']] = $event;
+ }
+ foreach ($this->ical->import($vcal, $charset, false, false) as $remote_event) {
+ // Attach remote event to current calendar
+ $remote_event["calendar"] = $this->cal_id;
+
+ $local_event = null;
+ if($events_hash[$remote_event['uid']])
+ $local_event = $events_hash[$remote_event['uid']];
+
+ // Determine whether event don't need an update.
+ if($local_event && $local_event["changed"] >= $remote_event["changed"])
+ {
+ array_push($synced, $local_event["id"]);
+ }
+ else
+ {
+ array_push($updates, array('local_event' => $local_event, 'remote_event' => $remote_event));
+ }
+ }
+ }
+
+ return array($updates, $synced);
+ }
+}
+
+;
+?> \ No newline at end of file
diff --git a/libgpl/jquery_migrate/jquery.migrate.js b/libgpl/jquery_migrate/jquery.migrate.js
new file mode 100644
index 0000000..5e73954
--- /dev/null
+++ b/libgpl/jquery_migrate/jquery.migrate.js
@@ -0,0 +1,521 @@
+/*!
+ * jQuery Migrate - v1.2.1 - 2013-05-08
+ * https://github.com/jquery/jquery-migrate
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
+ */
+(function( jQuery, window, undefined ) {
+// See http://bugs.jquery.com/ticket/13335
+// "use strict";
+
+
+var warnedAbout = {};
+
+// List of warnings already given; public read only
+jQuery.migrateWarnings = [];
+
+// Set to true to prevent console output; migrateWarnings still maintained
+jQuery.migrateMute = true;
+
+// Show a message on the console so devs know we're active
+if ( !jQuery.migrateMute && window.console && window.console.log ) {
+ window.console.log("JQMIGRATE: Logging is active");
+}
+
+// Set to false to disable traces that appear with warnings
+if ( jQuery.migrateTrace === undefined ) {
+ jQuery.migrateTrace = true;
+}
+
+// Forget any warnings we've already given; public
+jQuery.migrateReset = function() {
+ warnedAbout = {};
+ jQuery.migrateWarnings.length = 0;
+};
+
+function migrateWarn( msg) {
+ var console = window.console;
+ if ( !warnedAbout[ msg ] ) {
+ warnedAbout[ msg ] = true;
+ jQuery.migrateWarnings.push( msg );
+ if ( console && console.warn && !jQuery.migrateMute ) {
+ console.warn( "JQMIGRATE: " + msg );
+ if ( jQuery.migrateTrace && console.trace ) {
+ console.trace();
+ }
+ }
+ }
+}
+
+function migrateWarnProp( obj, prop, value, msg ) {
+ if ( Object.defineProperty ) {
+ // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
+ // allow property to be overwritten in case some other plugin wants it
+ try {
+ Object.defineProperty( obj, prop, {
+ configurable: true,
+ enumerable: true,
+ get: function() {
+ migrateWarn( msg );
+ return value;
+ },
+ set: function( newValue ) {
+ migrateWarn( msg );
+ value = newValue;
+ }
+ });
+ return;
+ } catch( err ) {
+ // IE8 is a dope about Object.defineProperty, can't warn there
+ }
+ }
+
+ // Non-ES5 (or broken) browser; just set the property
+ jQuery._definePropertyBroken = true;
+ obj[ prop ] = value;
+}
+
+if ( document.compatMode === "BackCompat" ) {
+ // jQuery has never supported or tested Quirks Mode
+ migrateWarn( "jQuery is not compatible with Quirks Mode" );
+}
+
+
+var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
+ oldAttr = jQuery.attr,
+ valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
+ function() { return null; },
+ valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
+ function() { return undefined; },
+ rnoType = /^(?:input|button)$/i,
+ rnoAttrNodeType = /^[238]$/,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ ruseDefault = /^(?:checked|selected)$/i;
+
+// jQuery.attrFn
+migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
+
+jQuery.attr = function( elem, name, value, pass ) {
+ var lowerName = name.toLowerCase(),
+ nType = elem && elem.nodeType;
+
+ if ( pass ) {
+ // Since pass is used internally, we only warn for new jQuery
+ // versions where there isn't a pass arg in the formal params
+ if ( oldAttr.length < 4 ) {
+ migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
+ }
+ if ( elem && !rnoAttrNodeType.test( nType ) &&
+ (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
+ return jQuery( elem )[ name ]( value );
+ }
+ }
+
+ // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
+ // for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
+ if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
+ migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
+ }
+
+ // Restore boolHook for boolean property/attribute synchronization
+ if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
+ jQuery.attrHooks[ lowerName ] = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" &&
+ ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+ };
+
+ // Warn only for attributes that can remain distinct from their properties post-1.9
+ if ( ruseDefault.test( lowerName ) ) {
+ migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" );
+ }
+ }
+
+ return oldAttr.call( jQuery, elem, name, value );
+};
+
+// attrHooks: value
+jQuery.attrHooks.value = {
+ get: function( elem, name ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrGet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value') no longer gets properties");
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrSet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+};
+
+
+var matched, browser,
+ oldInit = jQuery.fn.init,
+ oldParseJSON = jQuery.parseJSON,
+ // Note: XSS check is done below after string is trimmed
+ rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;
+
+// $(html) "looks like html" rule change
+jQuery.fn.init = function( selector, context, rootjQuery ) {
+ var match;
+
+ if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
+ (match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
+ // This is an HTML string according to the "old" rules; is it still?
+ if ( selector.charAt( 0 ) !== "<" ) {
+ migrateWarn("$(html) HTML strings must start with '<' character");
+ }
+ if ( match[ 3 ] ) {
+ migrateWarn("$(html) HTML text after last tag is ignored");
+ }
+ // Consistently reject any HTML-like string starting with a hash (#9521)
+ // Note that this may break jQuery 1.6.x code that otherwise would work.
+ if ( match[ 0 ].charAt( 0 ) === "#" ) {
+ migrateWarn("HTML string cannot start with a '#' character");
+ jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
+ }
+ // Now process using loose rules; let pre-1.8 play too
+ if ( context && context.context ) {
+ // jQuery object as context; parseHTML expects a DOM object
+ context = context.context;
+ }
+ if ( jQuery.parseHTML ) {
+ return oldInit.call( this, jQuery.parseHTML( match[ 2 ], context, true ),
+ context, rootjQuery );
+ }
+ }
+ return oldInit.apply( this, arguments );
+};
+jQuery.fn.init.prototype = jQuery.fn;
+
+// Let $.parseJSON(falsy_value) return null
+jQuery.parseJSON = function( json ) {
+ if ( !json && json !== null ) {
+ migrateWarn("jQuery.parseJSON requires a valid JSON string");
+ return null;
+ }
+ return oldParseJSON.apply( this, arguments );
+};
+
+jQuery.uaMatch = function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+};
+
+// Don't clobber any existing jQuery.browser in case it's different
+if ( !jQuery.browser ) {
+ matched = jQuery.uaMatch( navigator.userAgent );
+ browser = {};
+
+ if ( matched.browser ) {
+ browser[ matched.browser ] = true;
+ browser.version = matched.version;
+ }
+
+ // Chrome is Webkit, but Webkit is also Safari.
+ if ( browser.chrome ) {
+ browser.webkit = true;
+ } else if ( browser.webkit ) {
+ browser.safari = true;
+ }
+
+ jQuery.browser = browser;
+}
+
+// Warn if the code tries to get jQuery.browser
+migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
+
+jQuery.sub = function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ migrateWarn( "jQuery.sub() is deprecated" );
+ return jQuerySub;
+};
+
+
+// Ensure that $.ajax gets the new parseJSON defined in core.js
+jQuery.ajaxSetup({
+ converters: {
+ "text json": jQuery.parseJSON
+ }
+});
+
+
+var oldFnData = jQuery.fn.data;
+
+jQuery.fn.data = function( name ) {
+ var ret, evt,
+ elem = this[0];
+
+ // Handles 1.7 which has this behavior and 1.8 which doesn't
+ if ( elem && name === "events" && arguments.length === 1 ) {
+ ret = jQuery.data( elem, name );
+ evt = jQuery._data( elem, name );
+ if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
+ migrateWarn("Use of jQuery.fn.data('events') is deprecated");
+ return evt;
+ }
+ }
+ return oldFnData.apply( this, arguments );
+};
+
+
+var rscriptType = /\/(java|ecma)script/i,
+ oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
+
+jQuery.fn.andSelf = function() {
+ migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
+ return oldSelf.apply( this, arguments );
+};
+
+// Since jQuery.clean is used internally on older versions, we only shim if it's missing
+if ( !jQuery.clean ) {
+ jQuery.clean = function( elems, context, fragment, scripts ) {
+ // Set context per 1.8 logic
+ context = context || document;
+ context = !context.nodeType && context[0] || context;
+ context = context.ownerDocument || context;
+
+ migrateWarn("jQuery.clean() is deprecated");
+
+ var i, elem, handleScript, jsTags,
+ ret = [];
+
+ jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
+
+ // Complex logic lifted directly from jQuery 1.8
+ if ( fragment ) {
+ // Special handling of each script element
+ handleScript = function( elem ) {
+ // Check if we consider it executable
+ if ( !elem.type || rscriptType.test( elem.type ) ) {
+ // Detach the script and store it in the scripts array (if provided) or the fragment
+ // Return truthy to indicate that it has been handled
+ return scripts ?
+ scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
+ fragment.appendChild( elem );
+ }
+ };
+
+ for ( i = 0; (elem = ret[i]) != null; i++ ) {
+ // Check if we're done after handling an executable script
+ if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
+ // Append to fragment and handle embedded scripts
+ fragment.appendChild( elem );
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
+ jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
+
+ // Splice the scripts into ret after their former ancestor and advance our index beyond them
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ i += jsTags.length;
+ }
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var eventAdd = jQuery.event.add,
+ eventRemove = jQuery.event.remove,
+ eventTrigger = jQuery.event.trigger,
+ oldToggle = jQuery.fn.toggle,
+ oldLive = jQuery.fn.live,
+ oldDie = jQuery.fn.die,
+ ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
+ rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
+ rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
+ hoverHack = function( events ) {
+ if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
+ return events;
+ }
+ if ( rhoverHack.test( events ) ) {
+ migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
+ }
+ return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+// Event props removed in 1.9, put them back if needed; no practical way to warn them
+if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
+ jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
+}
+
+// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
+if ( jQuery.event.dispatch ) {
+ migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
+}
+
+// Support for 'hover' pseudo-event and ajax event warnings
+jQuery.event.add = function( elem, types, handler, data, selector ){
+ if ( elem !== document && rajaxEvent.test( types ) ) {
+ migrateWarn( "AJAX events should be attached to document: " + types );
+ }
+ eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
+};
+jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
+ eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
+};
+
+jQuery.fn.error = function() {
+ var args = Array.prototype.slice.call( arguments, 0);
+ migrateWarn("jQuery.fn.error() is deprecated");
+ args.splice( 0, 0, "error" );
+ if ( arguments.length ) {
+ return this.bind.apply( this, args );
+ }
+ // error event should not bubble to window, although it does pre-1.7
+ this.triggerHandler.apply( this, args );
+ return this;
+};
+
+jQuery.fn.toggle = function( fn, fn2 ) {
+
+ // Don't mess with animation or css toggles
+ if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
+ return oldToggle.apply( this, arguments );
+ }
+ migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
+
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+};
+
+jQuery.fn.live = function( types, data, fn ) {
+ migrateWarn("jQuery.fn.live() is deprecated");
+ if ( oldLive ) {
+ return oldLive.apply( this, arguments );
+ }
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+};
+
+jQuery.fn.die = function( types, fn ) {
+ migrateWarn("jQuery.fn.die() is deprecated");
+ if ( oldDie ) {
+ return oldDie.apply( this, arguments );
+ }
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+};
+
+// Turn global events into document-triggered events
+jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
+ if ( !elem && !rajaxEvent.test( event ) ) {
+ migrateWarn( "Global events are undocumented and deprecated" );
+ }
+ return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
+};
+jQuery.each( ajaxEvents.split("|"),
+ function( _, name ) {
+ jQuery.event.special[ name ] = {
+ setup: function() {
+ var elem = this;
+
+ // The document needs no shimming; must be !== for oldIE
+ if ( elem !== document ) {
+ jQuery.event.add( document, name + "." + jQuery.guid, function() {
+ jQuery.event.trigger( name, null, elem, true );
+ });
+ jQuery._data( this, name, jQuery.guid++ );
+ }
+ return false;
+ },
+ teardown: function() {
+ if ( this !== document ) {
+ jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
+ }
+ return false;
+ }
+ };
+ }
+);
+
+
+})( jQuery, window ); \ No newline at end of file
diff --git a/libgpl/libcalendaring/libcalendaring.js b/libgpl/libcalendaring/libcalendaring.js
new file mode 100644
index 0000000..00878be
--- /dev/null
+++ b/libgpl/libcalendaring/libcalendaring.js
@@ -0,0 +1,676 @@
+/**
+ * Basic Javascript utilities for calendar-related plugins
+ *
+ * @version @package_version@
+ * @author Thomas Bruederli <bruederli@kolabsys.com>
+ *
+ * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+function rcube_libcalendaring(settings)
+{
+ // member vars
+ this.settings = settings;
+ this.alarm_ids = [];
+ this.alarm_dialog = null;
+ this.snooze_popup = null;
+ this.dismiss_link = null;
+
+ // private vars
+ var me = this;
+ var gmt_offset = (new Date().getTimezoneOffset() / -60) - (settings.timezone || 0) - (settings.dst || 0);
+ var client_timezone = new Date().getTimezoneOffset();
+
+ // general datepicker settings
+ var datepicker_settings = {
+ // translate from fullcalendar format to datepicker format
+ dateFormat: settings.date_format ? settings.date_format.replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/yy/g, 'y') : 'yy-mm-dd',
+ firstDay : settings.first_day,
+ dayNamesMin: settings.days_short,
+ monthNames: settings.months,
+ monthNamesShort: settings.months,
+ changeMonth: false,
+ showOtherMonths: true,
+ selectOtherMonths: true
+ };
+
+
+ /**
+ * Quote html entities
+ */
+ var Q = this.quote_html = function(str)
+ {
+ return String(str).replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+ };
+
+ /**
+ * Create a nice human-readable string for the date/time range
+ */
+ this.event_date_text = function(event)
+ {
+ if (!event.start)
+ return '';
+ if (!event.end)
+ event.end = event.start;
+
+ var fromto, duration = event.end.getTime() / 1000 - event.start.getTime() / 1000;
+ if (event.allDay && !event.allDayfake) {
+ fromto = this.format_datetime(event.start, 1)
+ + (duration > 86400 || event.start.getDay() != event.end.getDay() ? ' &mdash; ' + this.format_datetime(event.end, 1) : '');
+ }
+ else if (duration < 86400 && event.start.getDay() == event.end.getDay()) {
+ fromto = this.format_datetime(event.start, 0)
+ + (duration > 0 ? ' &mdash; ' + this.format_datetime(event.end, 2) : '');
+ }
+ else {
+ fromto = this.format_datetime(event.start, 0)
+ + (duration > 0 ? ' &mdash; ' + this.format_datetime(event.end, 0) : '');
+ }
+
+ return fromto;
+ };
+
+
+ /**
+ * From time and date strings to a real date object
+ */
+ this.parse_datetime = function(time, date)
+ {
+ // we use the utility function from datepicker to parse dates
+ var date = date ? $.datepicker.parseDate(datepicker_settings.dateFormat, date, datepicker_settings) : new Date();
+
+ var time_arr = time.replace(/\s*[ap][.m]*/i, '').replace(/0([0-9])/g, '$1').split(/[:.]/);
+ if (!isNaN(time_arr[0])) {
+ date.setHours(time_arr[0]);
+ if (time.match(/p[.m]*/i) && date.getHours() < 12)
+ date.setHours(parseInt(time_arr[0]) + 12);
+ else if (time.match(/a[.m]*/i) && date.getHours() == 12)
+ date.setHours(0);
+ }
+ if (!isNaN(time_arr[1]))
+ date.setMinutes(time_arr[1]);
+
+ return date;
+ }
+
+ /**
+ * Convert an ISO 8601 formatted date string from the server into a Date object.
+ * Timezone information will be ignored, the server already provides dates in user's timezone.
+ */
+ this.parseISO8601 = function(s)
+ {
+ // force d to be on check's YMD, for daylight savings purposes
+ var fixDate = function(d, check) {
+ if (+d) { // prevent infinite looping on invalid dates
+ while (d.getDate() != check.getDate()) {
+ d.setTime(+d + (d < check ? 1 : -1) * 3600000);
+ }
+ }
+ }
+
+ // derived from http://delete.me.uk/2005/03/iso8601.html
+ var m = s && s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);
+ if (!m) {
+ return null;
+ }
+
+ var date = new Date(m[1], 0, 1),
+ check = new Date(m[1], 0, 1, 9, 0);
+ if (m[3]) {
+ date.setMonth(m[3] - 1);
+ check.setMonth(m[3] - 1);
+ }
+ if (m[5]) {
+ date.setDate(m[5]);
+ check.setDate(m[5]);
+ }
+ fixDate(date, check);
+ if (m[7]) {
+ date.setHours(m[7]);
+ }
+ if (m[8]) {
+ date.setMinutes(m[8]);
+ }
+ if (m[10]) {
+ date.setSeconds(m[10]);
+ }
+ if (m[12]) {
+ date.setMilliseconds(Number("0." + m[12]) * 1000);
+ }
+ fixDate(date, check);
+
+ return date;
+ }
+
+ /**
+ * Turn the given date into an ISO 8601 date string understandable by PHPs strtotime()
+ */
+ this.date2ISO8601 = function(date)
+ {
+ var zeropad = function(num) { return (num < 10 ? '0' : '') + num; };
+
+ return date.getFullYear() + '-' + zeropad(date.getMonth()+1) + '-' + zeropad(date.getDate())
+ + 'T' + zeropad(date.getHours()) + ':' + zeropad(date.getMinutes()) + ':' + zeropad(date.getSeconds());
+ };
+
+ /**
+ * Format the given date object according to user's prefs
+ */
+ this.format_datetime = function(date, mode)
+ {
+ var res = '';
+ if (!mode || mode == 1)
+ res += $.datepicker.formatDate(datepicker_settings.dateFormat, date, datepicker_settings);
+ if (!mode)
+ res += ' ';
+ if (!mode || mode == 2)
+ res += this.format_time(date);
+
+ return res;
+ }
+
+ /**
+ * Clone from fullcalendar.js
+ */
+ this.format_time = function(date)
+ {
+ var zeroPad = function(n) { return (n < 10 ? '0' : '') + n; }
+ var formatters = {
+ s : function(d) { return d.getSeconds() },
+ ss : function(d) { return zeroPad(d.getSeconds()) },
+ m : function(d) { return d.getMinutes() },
+ mm : function(d) { return zeroPad(d.getMinutes()) },
+ h : function(d) { return d.getHours() % 12 || 12 },
+ hh : function(d) { return zeroPad(d.getHours() % 12 || 12) },
+ H : function(d) { return d.getHours() },
+ HH : function(d) { return zeroPad(d.getHours()) },
+ t : function(d) { return d.getHours() < 12 ? 'a' : 'p' },
+ tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' },
+ T : function(d) { return d.getHours() < 12 ? 'A' : 'P' },
+ TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' }
+ };
+
+ var i, i2, c, formatter, res = '', format = settings['time_format'];
+ for (i=0; i < format.length; i++) {
+ c = format.charAt(i);
+ for (i2=Math.min(i+2, format.length); i2 > i; i2--) {
+ if (formatter = formatters[format.substring(i, i2)]) {
+ res += formatter(date);
+ i = i2 - 1;
+ break;
+ }
+ }
+ if (i2 == i) {
+ res += c;
+ }
+ }
+
+ return res;
+ }
+
+ /**
+ * Convert the given Date object into a unix timestamp respecting browser's and user's timezone settings
+ */
+ this.date2unixtime = function(date)
+ {
+ var dst_offset = (client_timezone - date.getTimezoneOffset()) * 60; // adjust DST offset
+ return Math.round(date.getTime()/1000 + gmt_offset * 3600 + dst_offset);
+ }
+
+ /**
+ * Turn a unix timestamp value into a Date object
+ */
+ this.fromunixtime = function(ts)
+ {
+ ts -= gmt_offset * 3600;
+ var date = new Date(ts * 1000),
+ dst_offset = (client_timezone - date.getTimezoneOffset()) * 60;
+ if (dst_offset) // adjust DST offset
+ date.setTime((ts + 3600) * 1000);
+ return date;
+ }
+
+ /**
+ * Simple plaintext to HTML converter, makig URLs clickable
+ */
+ this.text2html = function(str, maxlen, maxlines)
+ {
+ var html = Q(String(str));
+
+ // limit visible text length
+ if (maxlen) {
+ var morelink = ' <a href="#more" onclick="$(this).hide().next().show();return false" class="morelink">'+rcmail.gettext('showmore','libcalendaring')+'</a><span style="display:none">',
+ lines = html.split(/\r?\n/),
+ words, out = '', len = 0;
+
+ for (var i=0; i < lines.length; i++) {
+ len += lines[i].length;
+ if (maxlines && i == maxlines - 1) {
+ out += lines[i] + '\n' + morelink;
+ maxlen = html.length * 2;
+ }
+ else if (len > maxlen) {
+ len = out.length;
+ words = lines[i].split(' ');
+ for (var j=0; j < words.length; j++) {
+ len += words[j].length + 1;
+ out += words[j] + ' ';
+ if (len > maxlen) {
+ out += morelink;
+ maxlen = html.length * 2;
+ }
+ }
+ out += '\n';
+ }
+ else
+ out += lines[i] + '\n';
+ }
+
+ if (maxlen > str.length)
+ out += '</span>';
+
+ html = out;
+ }
+
+ // simple link parser (similar to rcube_string_replacer class in PHP)
+ var utf_domain = '[^?&@"\'/\\(\\)\\s\\r\\t\\n]+\\.([^\x00-\x2f\x3b-\x40\x5b-\x60\x7b-\x7f]{2,}|xn--[a-z0-9]{2,})';
+ var url1 = '.:;,', url2 = 'a-z0-9%=#@+?&/_~\\[\\]-';
+ var link_pattern = new RegExp('([hf]t+ps?://)('+utf_domain+'(['+url1+']?['+url2+']+)*)?', 'ig');
+ var mailto_pattern = new RegExp('([^\\s\\n\\(\\);]+@'+utf_domain+')', 'ig');
+
+ return html
+ .replace(link_pattern, '<a href="$1$2" class="extlink" target="_blank">$1$2</a>')
+ .replace(mailto_pattern, '<a href="mailto:$1">$1</a>')
+ .replace(/(mailto:)([^"]+)"/g, '$1$2" onclick="rcmail.command(\'compose\', \'$2\');return false"')
+ .replace(/\n/g, "<br/>");
+ };
+
+ this.init_alarms_edit = function(prefix)
+ {
+ // register events on alarm fields
+ $(prefix+' select.edit-alarm-type').change(function(){
+ $(this).parent().find('span.edit-alarm-values')[(this.selectedIndex>0?'show':'hide')]();
+ });
+ $(prefix+' select.edit-alarm-offset').change(function(){
+ var mode = $(this).val() == '@' ? 'show' : 'hide';
+ $(this).parent().find('.edit-alarm-date, .edit-alarm-time')[mode]();
+ $(this).parent().find('.edit-alarm-value').prop('disabled', mode == 'show');
+ });
+
+ $(prefix+' .edit-alarm-date').datepicker(datepicker_settings);
+ }
+
+
+ /***** Alarms handling *****/
+
+ /**
+ * Display a notification for the given pending alarms
+ */
+ this.display_alarms = function(alarms)
+ {
+ if (parent.tabbed && !self.tabbed) { // Mod by Rosali (tabbed plugin compatibility)
+ return;
+ }
+
+ var focused = $(':focus');
+ var is_minimized = false;
+
+ // clear old alert first
+ if (this.alarm_dialog) {
+ // Begin Mod by Rosali (remove previously added divs)
+ this.alarm_dialog.dialog('destroy').remove();
+ if($('#dialog-extend-fixed-container').get(0)){
+ is_minimized = true;
+ }
+ $('#dialog-extend-fixed-container').remove();
+ // End Mod by Rosali
+ }
+
+ this.alarm_dialog = $('<div>').attr('id', 'alarm-display');
+
+ var actions, adismiss, asnooze, alarm, html, event_ids = [];
+ for (var i=0; i < alarms.length; i++) {
+ alarm = alarms[i];
+ alarm.start = this.parseISO8601(alarm.start);
+ alarm.end = this.parseISO8601(alarm.end);
+ event_ids.push(alarm.id);
+
+ html = '<h3 class="event-title">' + Q(alarm.title) + '</h3>';
+ html += '<div class="event-section">' + Q(alarm.location || '') + '</div>';
+ html += '<div class="event-section">' + Q(this.event_date_text(alarm)) + '</div>';
+
+ adismiss = $('<a href="#" class="alarm-action-dismiss"></a>').html(rcmail.gettext('dismiss','libcalendaring')).click(function(){
+ me.dismiss_link = $(this);
+ me.dismiss_alarm(me.dismiss_link.data('id'), 0);
+ });
+ asnooze = $('<a href="#" class="alarm-action-snooze"></a>').html(rcmail.gettext('snooze','libcalendaring')).click(function(e){
+ me.snooze_dropdown($(this));
+ e.stopPropagation();
+ return false;
+ });
+ actions = $('<div>').addClass('alarm-actions').append(adismiss.data('id', alarm.id)).append(asnooze.data('id', alarm.id));
+
+ $('<div>').addClass('alarm-item').html(html).append(actions).appendTo(this.alarm_dialog);
+ }
+
+ var buttons = {};
+ buttons[rcmail.gettext('dismissall','libcalendaring')] = function() {
+ // submit dismissed event_ids to server
+ me.dismiss_alarm(me.alarm_ids.join(','), 0);
+ $(this).dialog('close');
+ };
+
+ // Begin Mod by Rosali
+ // dialog-extend options
+ var dialogExtendOptions = {
+ 'closable' : true,
+ 'maximizable' : false,
+ 'minimizable' : true,
+ 'minimizeLocation' : 'right',
+ 'collapsable' : false,
+ 'dblclick' : 'maximize',
+ 'load' : function(evt, dlg) {
+ if ((rcmail.task == 'mail' && (rcmail.env.action == 'compose' || rcmail.env.action == 'show')) || is_minimized == true) {
+ $('#alarm-display').dialogExtend('minimize');
+ $('#dialog-extend-fixed-container').children().width(300);
+ if (focused.is('input') || focused.is('textarea')) {
+ $(focused).focus();
+ }
+ else if (typeof tinymce == 'object') {
+ window.setTimeout("tinymce.get(rcmail.env.composebody).getBody().focus();", 100);
+ }
+ }
+ },
+ 'minimize' : function (evt, dlg) {
+ $('#dialog-extend-fixed-container').children().width(300);
+ },
+ };
+ // End Mod by Rosali
+
+ this.alarm_dialog.appendTo(document.body).dialog({
+ modal: false,
+ resizable: true,
+ closeOnEscape: false,
+ dialogClass: 'alarm',
+ title: '<span class="ui-icon ui-icon-alarms" style="float:left; margin:0 4px 0 0"></span>' + rcmail.gettext('alarmtitle','libcalendaring'),
+ buttons: buttons,
+ close: function() {
+ $('#alarm-snooze-dropdown').hide();
+ $(this).dialog('destroy').remove();
+ me.alarm_dialog = null;
+ me.alarm_ids = null;
+ },
+ drag: function(event, ui) {
+ $('#alarm-snooze-dropdown').hide();
+ }
+ }).dialogExtend(dialogExtendOptions); // Mod by Rosali
+
+ this.alarm_ids = event_ids;
+ };
+
+ /**
+ * Show a drop-down menu with a selection of snooze times
+ */
+ this.snooze_dropdown = function(link)
+ {
+ if (!this.snooze_popup) {
+ this.snooze_popup = $('#alarm-snooze-dropdown');
+ // create popup if not found
+ if (!this.snooze_popup.length) {
+ this.snooze_popup = $('<div>').attr('id', 'alarm-snooze-dropdown').addClass('popupmenu').appendTo(document.body);
+ this.snooze_popup.html(rcmail.env.snooze_select)
+ }
+ $('#alarm-snooze-dropdown a').click(function(e){
+ var time = String(this.href).replace(/.+#/, '');
+ me.dismiss_alarm($('#alarm-snooze-dropdown').data('id'), time);
+ return false;
+ });
+ }
+
+ // hide visible popup
+ if (this.snooze_popup.is(':visible') && this.snooze_popup.data('id') == link.data('id')) {
+ this.snooze_popup.hide();
+ this.dismiss_link = null;
+ }
+ else { // open popup below the clicked link
+ var pos = link.offset();
+ pos.top += link.height() + 2;
+ this.snooze_popup.data('id', link.data('id')).css({ top:Math.floor(pos.top)+'px', left:Math.floor(pos.left)+'px' }).show();
+ this.dismiss_link = link;
+ }
+ };
+
+ /**
+ * Dismiss or snooze alarms for the given event
+ */
+ this.dismiss_alarm = function(id, snooze)
+ {
+ $('#alarm-snooze-dropdown').hide();
+ rcmail.http_post('utils/plugin.alarms', { action:'dismiss', data:{ id:id, snooze:snooze } });
+
+ // remove dismissed alarm from list
+ if (this.dismiss_link) {
+ this.dismiss_link.closest('div.alarm-item').hide();
+ var new_ids = jQuery.grep(this.alarm_ids, function(v){ return v != id; });
+ if (new_ids.length)
+ this.alarm_ids = new_ids;
+ else
+ this.alarm_dialog.dialog('close');
+ }
+
+ this.dismiss_link = null;
+ };
+
+ /***** Recurrence form handling *****/
+
+ /**
+ * Install event handlers on recurrence form elements
+ */
+ this.init_recurrence_edit = function(prefix)
+ {
+ // toggle recurrence frequency forms
+ $('#edit-recurrence-frequency').change(function(e){
+ var freq = $(this).val().toLowerCase();
+ $('.recurrence-form').hide();
+ if (freq) {
+ $('#recurrence-form-'+freq).show();
+ if (freq != 'rdate')
+ $('#recurrence-form-until').show();
+ }
+ });
+ $('#recurrence-form-rdate input.button.add').click(function(e){
+ var dt, dv = $('#edit-recurrence-rdate-input').val();
+ if (dv && (dt = me.parse_datetime('12:00', dv))) {
+ me.add_rdate(dt);
+ me.sort_rdates();
+ $('#edit-recurrence-rdate-input').val('')
+ }
+ else {
+ $('#edit-recurrence-rdate-input').select();
+ }
+ });
+ $('#edit-recurrence-rdates').on('click', 'a.delete', function(e){
+ $(this).closest('li').remove();
+ return false;
+ });
+
+ $('#edit-recurrence-enddate').datepicker(datepicker_settings).click(function(){ $("#edit-recurrence-repeat-until").prop('checked', true) });
+ $('#edit-recurrence-repeat-times').change(function(e){ $('#edit-recurrence-repeat-count').prop('checked', true); });
+ $('#edit-recurrence-rdate-input').datepicker(datepicker_settings);
+ };
+
+ /**
+ * Set recurrence form according to the given event/task record
+ */
+ this.set_recurrence_edit = function(rec)
+ {
+ var recurrence = $('#edit-recurrence-frequency').val(rec.recurrence ? rec.recurrence.FREQ || (rec.recurrence.RDATE ? 'RDATE' : '') : '').change(),
+ interval = $('.recurrence-form select.edit-recurrence-interval').val(rec.recurrence ? rec.recurrence.INTERVAL || 1 : 1),
+ rrtimes = $('#edit-recurrence-repeat-times').val(rec.recurrence ? rec.recurrence.COUNT || 1 : 1),
+ rrenddate = $('#edit-recurrence-enddate').val(rec.recurrence && rec.recurrence.UNTIL ? this.format_datetime(this.parseISO8601(rec.recurrence.UNTIL), 1) : '');
+ $('.recurrence-form input.edit-recurrence-until:checked').prop('checked', false);
+ $('#edit-recurrence-rdates').html('');
+
+ var weekdays = ['SU','MO','TU','WE','TH','FR','SA'],
+ rrepeat_id = '#edit-recurrence-repeat-forever';
+ if (rec.recurrence && rec.recurrence.COUNT) rrepeat_id = '#edit-recurrence-repeat-count';
+ else if (rec.recurrence && rec.recurrence.UNTIL) rrepeat_id = '#edit-recurrence-repeat-until';
+ $(rrepeat_id).prop('checked', true);
+
+ if (rec.recurrence && rec.recurrence.BYDAY && rec.recurrence.FREQ == 'WEEKLY') {
+ var wdays = rec.recurrence.BYDAY.split(',');
+ $('input.edit-recurrence-weekly-byday').val(wdays);
+ }
+ if (rec.recurrence && rec.recurrence.BYMONTHDAY) {
+ $('input.edit-recurrence-monthly-bymonthday').val(String(rec.recurrence.BYMONTHDAY).split(','));
+ $('input.edit-recurrence-monthly-mode').val(['BYMONTHDAY']);
+ }
+ if (rec.recurrence && rec.recurrence.BYDAY && (rec.recurrence.FREQ == 'MONTHLY' || rec.recurrence.FREQ == 'YEARLY')) {
+ var byday, section = rec.recurrence.FREQ.toLowerCase();
+ if ((byday = String(rec.recurrence.BYDAY).match(/(-?[1-4])([A-Z]+)/))) {
+ $('#edit-recurrence-'+section+'-prefix').val(byday[1]);
+ $('#edit-recurrence-'+section+'-byday').val(byday[2]);
+ }
+ $('input.edit-recurrence-'+section+'-mode').val(['BYDAY']);
+ }
+ else if (rec.start) {
+ $('#edit-recurrence-monthly-byday').val(weekdays[rec.start.getDay()]);
+ }
+ if (rec.recurrence && rec.recurrence.BYMONTH) {
+ $('input.edit-recurrence-yearly-bymonth').val(String(rec.recurrence.BYMONTH).split(','));
+ }
+ else if (rec.start) {
+ $('input.edit-recurrence-yearly-bymonth').val([String(rec.start.getMonth()+1)]);
+ }
+ if (rec.recurrence && rec.recurrence.RDATE) {
+ $.each(rec.recurrence.RDATE, function(i,rdate){
+ me.add_rdate(me.parseISO8601(rdate));
+ });
+ }
+ };
+
+ /**
+ * Gather recurrence settings from form
+ */
+ this.serialize_recurrence = function(timestr)
+ {
+ var recurrence = '',
+ freq = $('#edit-recurrence-frequency').val();
+
+ if (freq != '') {
+ recurrence = {
+ FREQ: freq,
+ INTERVAL: $('#edit-recurrence-interval-'+freq.toLowerCase()).val()
+ };
+
+ var until = $('input.edit-recurrence-until:checked').val();
+
+ if (until == 'count')
+ recurrence.COUNT = $('#edit-recurrence-repeat-times').val();
+ else if (until == 'until')
+ recurrence.UNTIL = me.date2ISO8601(me.parse_datetime(timestr || '00:00', $('#edit-recurrence-enddate').val()));
+
+ if (freq == 'WEEKLY') {
+ var byday = [];
+ $('input.edit-recurrence-weekly-byday:checked').each(function(){ byday.push(this.value); });
+ if (byday.length)
+ recurrence.BYDAY = byday.join(',');
+ }
+ else if (freq == 'MONTHLY') {
+ var mode = $('input.edit-recurrence-monthly-mode:checked').val(), bymonday = [];
+ if (mode == 'BYMONTHDAY') {
+ $('input.edit-recurrence-monthly-bymonthday:checked').each(function(){ bymonday.push(this.value); });
+ if (bymonday.length)
+ recurrence.BYMONTHDAY = bymonday.join(',');
+ }
+ else
+ recurrence.BYDAY = $('#edit-recurrence-monthly-prefix').val() + $('#edit-recurrence-monthly-byday').val();
+ }
+ else if (freq == 'YEARLY') {
+ var byday, bymonth = [];
+ $('input.edit-recurrence-yearly-bymonth:checked').each(function(){ bymonth.push(this.value); });
+ if (bymonth.length)
+ recurrence.BYMONTH = bymonth.join(',');
+ if ((byday = $('#edit-recurrence-yearly-byday').val()))
+ recurrence.BYDAY = $('#edit-recurrence-yearly-prefix').val() + byday;
+ }
+ else if (freq == 'RDATE') {
+ recurrence = { RDATE:[] };
+ // take selected but not yet added date into account
+ if ($('#edit-recurrence-rdate-input').val() != '') {
+ $('#recurrence-form-rdate input.button.add').click();
+ }
+ $('#edit-recurrence-rdates li').each(function(i, li){
+ recurrence.RDATE.push($(li).attr('data-value'));
+ });
+ }
+ }
+
+ return recurrence;
+ };
+
+ // add the given date to the RDATE list
+ this.add_rdate = function(date)
+ {
+ var li = $('<li>')
+ .attr('data-value', this.date2ISO8601(date))
+ .html('<span>' + Q(this.format_datetime(date, 1)) + '</span>')
+ .appendTo('#edit-recurrence-rdates');
+
+ $('<a>').attr('href', '#del')
+ .addClass('iconbutton delete')
+ .html(rcmail.get_label('delete', 'libcalendaring'))
+ .attr('title', rcmail.get_label('delete', 'libcalendaring'))
+ .appendTo(li);
+ };
+
+ // re-sort the list items by their 'data-value' attribute
+ this.sort_rdates = function()
+ {
+ var mylist = $('#edit-recurrence-rdates'),
+ listitems = mylist.children('li').get();
+ listitems.sort(function(a, b) {
+ var compA = $(a).attr('data-value');
+ var compB = $(b).attr('data-value');
+ return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
+ })
+ $.each(listitems, function(idx, item) { mylist.append(item); });
+ };
+}
+
+
+// extend jQuery
+(function($){
+ $.fn.serializeJSON = function(){
+ var json = {};
+ jQuery.map($(this).serializeArray(), function(n, i) {
+ json[n['name']] = n['value'];
+ });
+ return json;
+ };
+})(jQuery);
+
+
+/* libcalendaring plugin initialization */
+window.rcmail && rcmail.addEventListener('init', function(evt) {
+ if (rcmail.env.libcal_settings) {
+ var libcal = new rcube_libcalendaring(rcmail.env.libcal_settings);
+ rcmail.addEventListener('plugin.display_alarms', function(alarms){ libcal.display_alarms(alarms); });
+ if (!rcmail.env.framed && !rcmail.env.extwin && rcmail.env.username) {
+ window.setTimeout("rcmail.http_post('refresh', '');", 1000); // Mod by Rosali (fetch reminders almost immediately)
+ }
+ }
+});
diff --git a/libgpl/libgpl.php b/libgpl/libgpl.php
new file mode 100644
index 0000000..de9747f
--- /dev/null
+++ b/libgpl/libgpl.php
@@ -0,0 +1,189 @@
+<?php
+#
+# This file is part of MyRoundcube "libgpl" plugin.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl
+# dev-team [at] myroundcube [dot] com
+# http://myroundcube.com
+#
+class libgpl extends rcube_plugin
+{
+ private $labels_merged;
+
+ /* unified plugin properties */
+ static private $plugin = 'libgpl';
+ static private $author = 'myroundcube@mail4us.net';
+ static private $authors_comments = '<a href="http://myroundcube.com/myroundcube-plugins/helper-plugin?libgpl" target="_blank">Documentation</a>';
+ static private $version = '1.0.38';
+ static private $date = '12-02-2014';
+ static private $licence = 'GPL';
+ static private $requirements = array(
+ 'Roundcube' => '1.0',
+ 'PHP' => '5.3',
+ 'required_plugins' => array(
+ 'jqueryui' => 'require_plugin',
+ ),
+ );
+ static private $f;
+
+ function init(){
+ self::$f = $this;
+ $this->add_texts('localization/');
+ $this->require_plugin('jqueryui');
+ $this->include_stylesheet('qtip/qtip.css');
+ $this->include_stylesheet($this->local_skin_path() . '/calendar.css');
+ $this->include_script('timepicker2/jquery.timepicker.js');
+ $this->include_stylesheet($this->local_skin_path() . '/timepicker2.css');
+ $this->include_script('dialogextend/jquery.dialogextend.js');
+ $this->include_script('libcalendaring/libcalendaring.js');
+ $this->include_script('jquery_migrate/jquery.migrate.js');
+ $this->include_script('qtip/qtip.js');
+ $this->add_hook('render_page', array($this, 'render_page'));
+ $this->add_hook('send_page', array($this, 'send_page'));
+ $this->add_hook('preferences_list', array($this, 'preferences_list'));
+ if(!class_exists('MyRCHttp')){
+ require_once('http_request/class.http.php');
+ }
+ if(!$this->labels_merged){
+ $this->labels_merged = true;
+ $this->_merge_labels(
+ array(
+ 'tasks' => 'calendar',
+ 'calendar_kolab' => 'calendar',
+ 'calendar_database' => 'calendar',
+ 'calendar_caldav' => 'calendar',
+ 'calendar_ical' => 'calendar',
+ 'calendar_google_xml' => 'calendar',
+ 'errorimportingtask' => 'calendar',
+ 'treat_as_allday' => 'calendar',
+ 'hours' => 'calendar',
+ 'movetotasks' => 'calendar',
+ 'movetocalendar' => 'calendar',
+ 'emailevent' => 'calendar',
+ 'movetonotes' => 'calendar',
+ 'quit' => 'calendar',
+ 'eventaction' => 'calendar',
+ 'gooledisabled' => 'calendar',
+ 'googledisabled_redirect' => 'calendar',
+ 'allowfreebusy' => 'calendar',
+ 'freebusy' => 'calendar',
+ 'sync_interval' => 'calendar',
+ 'minute_s' => 'calendar',
+ 'unabletoadddefaultcalendars' => 'calendar',
+ 'list' => 'tasklist',
+ 'editlist' => 'tasklist',
+ 'tags' => 'tasklist',
+ 'subscribe' => 'tasklist',
+ 'is_subtask' => 'tasklist',
+ 'due' => 'tasklist',
+ 'taskaction' => 'tasklist',
+ 'emailtask' => 'tasklist',
+ 'subscribed' => 'carddav',
+ )
+ );
+ }
+ }
+
+ static public function include_js($js){
+ self::$f->include_script($js);
+ }
+
+ static public function include_php($php){
+ require_once INSTALL_PATH . $php;
+ }
+
+ static public function about($keys = false){
+ $requirements = self::$requirements;
+ foreach(array('required_', 'recommended_') as $prefix){
+ if(is_array($requirements[$prefix.'plugins'])){
+ foreach($requirements[$prefix.'plugins'] as $plugin => $method){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $class->about($keys),
+ );
+ }
+ else{
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $plugin,
+ );
+ }
+ }
+ }
+ }
+ return array(
+ 'plugin' => self::$plugin,
+ 'version' => self::$version,
+ 'date' => self::$date,
+ 'author' => self::$author,
+ 'comments' => self::$authors_comments,
+ 'licence' => self::$licence,
+ 'requirements' => $requirements,
+ );
+ }
+
+ public function render_page($p){
+ if($this->rc->user->data['username']){
+ $this->rc->output->set_env('username', $this->rc->user->data['username']);
+ }
+ if($p['template'] == 'calendar.calendar' || $p['template'] == 'calendar.print' || $p['template'] == 'tasklist.mainview'){
+ $this->include_script('querystring/querystring.js');
+ $this->include_script('date/date.js');
+ $this->include_stylesheet($this->local_skin_path() . '/jquery.contextMenu.css');
+ $this->include_script('contextmenu/jquery.contextMenu.js');
+ $this->include_script('contextmenu/jquery.ui.position.js');
+ }
+ else if($p['template'] == 'sticky_notes.sticky_notes'){
+ $this->include_stylesheet('fancybox/jquery.fancybox-1.3.4.css');
+ $this->include_script("fancybox/jquery.fancybox-1.3.4.pack.js");
+ $this->include_script('date/date.js');
+ $this->include_stylesheet($this->local_skin_path() . '/jquery.contextMenu.css');
+ $this->include_script('contextmenu/jquery.contextMenu.js');
+ $this->include_script('contextmenu/jquery.ui.position.js');
+ }
+ if(class_exists('password_plus')){
+ $this->include_script('password/password.js');
+ }
+ return $p;
+ }
+
+ public function send_page($args)
+ {
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/libcalendaring\/libcalendaring.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/libcalendaring\/libcalendaring.min.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ if(class_exists('password_plus')){
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/password\/password.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/password\/password.min.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ }
+ return $args;
+ }
+
+ public function preferences_list($args){
+ if($args['section'] == 'calendarsharing'|| $args['section'] == 'addressbooksharing'){
+ $rcmail = rcube::get_instance();
+ if(!$args['current']){
+ $args['blocks']['view']['content'] = true;
+ return $args;
+ }
+ if($dsn = $rcmail->config->get('db_sabredav_dsn')){
+ $this->include_script('flashclipboard/flashclipboard_libgpl.js');
+ }
+ }
+ return $args;
+ }
+
+ private function _merge_labels($labels){
+ foreach($labels as $label => $env){
+ rcube::get_instance()->load_language(null, array(), array($env . '.' . $label => $this->gettext($label)));
+ }
+ }
+
+}
+?> \ No newline at end of file
diff --git a/libgpl/localization/cs_CZ.inc b/libgpl/localization/cs_CZ.inc
new file mode 100644
index 0000000..eca44df
--- /dev/null
+++ b/libgpl/localization/cs_CZ.inc
@@ -0,0 +1,48 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/libgpl/localization/cs_CZ.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: tachec - 01/22/2015 08:02:38
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'CalDAV kalendář';
+$labels['calendar_kolab'] = 'Kolab kalendář';
+$labels['calendar_database'] = 'lokální kalendář';
+$labels['calendar_ical'] = 'iCAL kalendář';
+$labels['calendar_google_xml'] = 'Google XML kalendář';
+$labels['sync_interval'] = 'Synchronizovat každých';
+$labels['minute_s'] = 'minut(y)';
+$labels['tasks'] = 'Úkoly';
+$labels['errorimportingtask'] = 'Nepodařilo se naimportovat úkoly';
+$labels['treat_as_allday'] = 'Zobrazit událost jako celodenní pokud trvá déle než';
+$labels['hours'] = 'Hodin';
+$labels['movetotasks'] = 'Přesunout do úkolů';
+$labels['movetocalendar'] = 'Přesunout do kalendáře';
+$labels['emailevent'] = 'Poslat událost';
+$labels['emailnote'] = 'Poslat poznámku';
+$labels['emailtask'] = 'Poslat úkol';
+$labels['movetonotes'] = 'Přesunout do poznámek';
+$labels['quit'] = 'Ukončit';
+$labels['eventaction'] = 'Akce události...';
+$labels['googledisabled'] = 'Povolte prosím přístup k vašemu účtu Google (přejděte na "Nastavení" -> "Správa účtu" -> "Další nastavení účtu" a proveďte patřičná nastavení).';
+$labels['googledisabled_redirect'] = 'Povolte prosím přístup k vašemu účtu Google.';
+$labels['allowfreebusy'] = 'Povolit požadavek na obsazenost';
+$labels['freebusy'] = 'Obsazenost';
+$labels['unabletoadddefaultcalendars'] = 'Nelze přidat výchozí kalendář';
+$labels['taskaction'] = 'Akce úkolu...';
+$labels['due'] = ' ';
+$labels['is_subtask'] = 'Dílčí úkol';
+$labels['subscribe'] = 'Abyste mohli vytvářet úkoly, tak si je prosím povolte ve svém kalendáři.';
+$labels['subscribed'] = 'Přihlášeno';
+$labels['tags'] = 'Kategorie';
+$labels['list'] = 'Kalendář';
+$labels['editlist'] = 'Upravit kalendář';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/en_US.inc b/libgpl/localization/en_US.inc
new file mode 100644
index 0000000..22c7c1b
--- /dev/null
+++ b/libgpl/localization/en_US.inc
@@ -0,0 +1,36 @@
+<?php
+$labels = array();
+$labels['calendar_caldav'] = 'CalDAV Calendar';
+$labels['calendar_kolab'] = 'Kolab Calendar';
+$labels['calendar_database'] = 'Local Calendar';
+$labels['calendar_ical'] = 'iCAL Calendar';
+$labels['calendar_google_xml'] = 'Google XML Calendar';
+$labels['sync_interval'] = 'Synchronization every';
+$labels['minute_s'] = 'minute(s)';
+$labels['tasks'] = 'Tasks';
+$labels['errorimportingtask'] = 'Failed to import the task';
+$labels['treat_as_allday'] = 'Show event as all-day if it takes more than';
+$labels['hours'] = 'Hours';
+$labels['movetotasks'] = 'Move to tasks';
+$labels['movetocalendar'] = 'Move to calendar';
+$labels['emailevent'] = 'Email event';
+$labels['emailnote'] = 'Email note';
+$labels['emailtask'] = 'Email task';
+$labels['movetonotes'] = 'Move to notes';
+$labels['quit'] = 'Quit';
+$labels['eventaction'] = 'Event action...';
+$labels['googledisabled'] = 'Please authorize access to your Google account (browse to <i>"Settings"</i> -> <i>"Account Administration" </i> -> <i>"Other account\'s settings"</i> and proceed).';
+$labels['googledisabled_redirect'] = 'Please authorize access to your Google account.';
+$labels['allowfreebusy'] = 'Allow freebusy requests';
+$labels['freebusy'] = 'Freebusy';
+$labels['unabletoadddefaultcalendars'] = 'Unable to add default calendars';
+$labels['taskaction'] = 'Task action...';
+$labels['due'] = 'due';
+$labels['is_subtask'] = 'Subtask';
+$labels['subscribe'] = 'Please subscribe to a calendar in order to create a task.';
+$labels['subscribed'] = 'Subscribed';
+$labels['tags'] = 'Categories';
+$labels['list'] = 'Calendar';
+$labels['editlist'] = 'Edit calendar';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/es_ES.inc b/libgpl/localization/es_ES.inc
new file mode 100644
index 0000000..d84590b
--- /dev/null
+++ b/libgpl/localization/es_ES.inc
@@ -0,0 +1,48 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/libgpl/localization/es_ES.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 01/10/2015 10:46:25
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'Calendario CalDAV';
+$labels['calendar_kolab'] = 'Calendario Kolab';
+$labels['calendar_database'] = 'Calendario Local';
+$labels['calendar_ical'] = 'Calendario iCAL';
+$labels['calendar_google_xml'] = 'Calendario Google XML';
+$labels['sync_interval'] = 'Sincronización cada';
+$labels['minute_s'] = 'minuto(s)';
+$labels['tasks'] = 'Tareas';
+$labels['errorimportingtask'] = 'No se pudo importar la tarea';
+$labels['treat_as_allday'] = 'Mostrar evento como \'todo el día\' si toma más de';
+$labels['hours'] = 'Horas';
+$labels['movetotasks'] = 'Mover a tareas';
+$labels['movetocalendar'] = 'Mover al calendario';
+$labels['emailevent'] = 'Enviar evento por correo';
+$labels['emailnote'] = 'Enviar nota por correo';
+$labels['emailtask'] = 'Enviar tarea por correo';
+$labels['movetonotes'] = 'Mover a notas';
+$labels['quit'] = 'Salir';
+$labels['eventaction'] = 'Acción de evento...';
+$labels['googledisabled'] = 'Please authorize access to your Google account (browse to "Settings" -> "Account Administration" -> "Other account\'s settings" and proceed). Por favor, autorizar el acceso a su cuenta de Google (vaya a "Configuración" -> "Administración de Cuenta" -> "Otros ajustes de cuentas" y proceda).';
+$labels['googledisabled_redirect'] = 'Por favor, autorizar el acceso a su cuenta de Google.';
+$labels['allowfreebusy'] = 'Permitir solicitudes Libre/Ocupado';
+$labels['freebusy'] = 'Libre/Ocupado';
+$labels['unabletoadddefaultcalendars'] = 'No se pudo agregar calendarios predeterminados';
+$labels['taskaction'] = 'Acción de tarea...';
+$labels['due'] = 'debido el';
+$labels['is_subtask'] = 'Subtarea';
+$labels['subscribe'] = 'Por favor, suscribirse a un calendario para poder crear tarea.';
+$labels['subscribed'] = 'Suscrito';
+$labels['tags'] = 'Categorías';
+$labels['list'] = 'Calendario';
+$labels['editlist'] = 'Editar calendario';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/fi_FI.inc b/libgpl/localization/fi_FI.inc
new file mode 100644
index 0000000..021ab3d
--- /dev/null
+++ b/libgpl/localization/fi_FI.inc
@@ -0,0 +1,48 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/libgpl/localization/fi_FI.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Markku Virtanen - 01/12/2015 07:37:20
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'CalDAV kalenteri';
+$labels['calendar_kolab'] = 'Kolab kalenteri';
+$labels['calendar_database'] = 'Paikallinen kalenteri';
+$labels['calendar_ical'] = 'iCal kalenteri';
+$labels['calendar_google_xml'] = 'Google XML kalenteri';
+$labels['sync_interval'] = 'Synkronisointi joka';
+$labels['minute_s'] = 'minuutti(a)';
+$labels['tasks'] = 'Tehtävät';
+$labels['errorimportingtask'] = 'Tehtävän tuonti epäonnistui';
+$labels['treat_as_allday'] = 'Näytä tapahtumat koko päivän tapahtumana jos ne kestävät enemmän kuin';
+$labels['hours'] = 'Tuntia';
+$labels['movetotasks'] = 'Siirrä tehtäviin';
+$labels['movetocalendar'] = 'Siirrä kalenteriin';
+$labels['emailevent'] = 'Lähetä tapahtuma';
+$labels['emailnote'] = 'Lähetä viesti';
+$labels['emailtask'] = 'Lähetä tehtävä';
+$labels['movetonotes'] = 'Siirrä muistioon';
+$labels['quit'] = 'Poistu';
+$labels['eventaction'] = 'Tapahtuman toiminto...';
+$labels['googledisabled'] = 'Anna valtuutus Google tilille ("Asetukset" -> "Tilin hallinta" -> "Muut tilin asetukset")';
+$labels['googledisabled_redirect'] = 'Anna valtuutus Google tilillesi';
+$labels['allowfreebusy'] = 'Salli freebusy pyynnöt';
+$labels['freebusy'] = 'Freebusy';
+$labels['unabletoadddefaultcalendars'] = 'Oletuskalenterien lisäys epäonnistui';
+$labels['taskaction'] = 'Tehtävän toiminto...';
+$labels['due'] = 'valmistuu';
+$labels['is_subtask'] = 'Alatehtävä';
+$labels['subscribe'] = 'Tee tilaus kalenteriin jotta voit luoda tehtäviä.';
+$labels['subscribed'] = 'Tilattu';
+$labels['tags'] = 'Kategoriat';
+$labels['list'] = 'Kalenteri';
+$labels['editlist'] = 'Muokkaa kalenteria';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/fr_FR.inc b/libgpl/localization/fr_FR.inc
new file mode 100644
index 0000000..9344bc3
--- /dev/null
+++ b/libgpl/localization/fr_FR.inc
@@ -0,0 +1,51 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| language/fr_FR/labels.inc |
+| |
+| Language file of the RoundCube Webmail client |
+| Copyright (C) 2008-2012, RoundQube Dev. - Switzerland |
+| Licensed under the GNU GPL |
+| |
++-----------------------------------------------------------------------+
+| Author: Olivier Zolli - 01/11/2015 |
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'Agenda CalDAV';
+$labels['calendar_kolab'] = 'Agenda Kolab';
+$labels['calendar_database'] = 'Agenda local';
+$labels['calendar_ical'] = 'Agenda iCAL';
+$labels['calendar_google_xml'] = 'Agenda Google XML';
+$labels['sync_interval'] = 'Synchronisation chaque';
+$labels['minute_s'] = 'minute(s)';
+$labels['tasks'] = 'Tâches';
+$labels['errorimportingtask'] = 'Echec d\'importation de la tâche';
+$labels['treat_as_allday'] = 'Montrer l\'évènement comme "Toute la journée" s\'il dure plus de';
+$labels['hours'] = 'Heures';
+$labels['movetotasks'] = 'Déplacer vers les tâches';
+$labels['movetocalendar'] = 'Déplacer vers l\'agenda';
+$labels['emailevent'] = 'Evènement courriel';
+$labels['emailnote'] = 'Evènement note';
+$labels['emailtask'] = 'Evènement tâche';
+$labels['movetonotes'] = 'Déplacer vers les notes';
+$labels['quit'] = 'Quitter';
+$labels['eventaction'] = 'Action d\'évènement';
+$labels['googledisabled'] = 'Veuillez autoriser l\'accès à votre compte Google (<i>"Paramètres"</i> -> <i>"Administration du compte"</i> -> <i>"Autres paramètres du compte"</i>';
+$labels['googledisabled_redirect'] = 'Veuillez autoriser l\'accès à votre compte Google';
+$labels['allowfreebusy'] = 'Autoriser les requêtes Libre/Occupé';
+$labels['freebusy'] = 'Libre/Occupé';
+$labels['unabletoadddefaultcalendars'] = 'Impossible d\'ajouter les agendas par défaut';
+$labels['taskaction'] = 'Action de tâche';
+$labels['due'] = 'requis';
+$labels['is_subtask'] = 'Sous-tâche';
+$labels['subscribe'] = 'Veuillez vous inscrire à un agenda pour créer une tâche';
+$labels['subscribed'] = 'Inscrit';
+$labels['tags'] = 'Catégories';
+$labels['list'] = 'Agenda';
+$labels['editlist'] = 'Editer l\'agenda';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/revision.inc.php b/libgpl/localization/revision.inc.php
new file mode 100644
index 0000000..e9f587a
--- /dev/null
+++ b/libgpl/localization/revision.inc.php
@@ -0,0 +1,11 @@
+<?php
+
+$ps_localization_update = serialize(
+ array(
+ 'translator' => 'tachec',
+ 'language ' => 'cs_CZ',
+ 'date' => '01/22/2015 08:02:38'
+ )
+);
+
+?> \ No newline at end of file
diff --git a/libgpl/package.xml b/libgpl/package.xml
new file mode 100644
index 0000000..f9cc54d
--- /dev/null
+++ b/libgpl/package.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+ http://pear.php.net/dtd/tasks-1.0.xsd
+ http://pear.php.net/dtd/package-2.0
+ http://pear.php.net/dtd/package-2.0.xsd">
+ <name>libgpl</name>
+ <lead>
+ <name>Myroundcube Dev Team</name>
+ <user>rosali</user>
+ <email>dev-team@myroundcube.com</email>
+ <active>yes</active>
+ </lead><date>2014-02-12</date>
+ <version>
+ <release>1.0.38</release>
+ <api>1.0.38</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.gnu.org/licenses/gpl.html">GNU GPLv3+</license>
+</package>
diff --git a/libgpl/password/password.js b/libgpl/password/password.js
new file mode 100644
index 0000000..6b17b64
--- /dev/null
+++ b/libgpl/password/password.js
@@ -0,0 +1,36 @@
+/**
+ * Password plugin script
+ * @version @package_version@
+ */
+
+if (window.rcmail) {
+ rcmail.addEventListener('init', function(evt) {
+
+ // register command handler
+ rcmail.register_command('plugin.password-save', function() {
+ var input_curpasswd = rcube_find_object('_curpasswd'),
+ input_newpasswd = rcube_find_object('_newpasswd'),
+ input_confpasswd = rcube_find_object('_confpasswd');
+ input_pwstrength = rcube_find_object('_pwstrength');
+
+ if (input_curpasswd && input_curpasswd.value == '') {
+ rcmail.display_message(rcmail.gettext('nocurpassword', 'password'), 'error');
+ input_curpasswd.focus();
+ } else if (input_newpasswd && input_newpasswd.value == '') {
+ rcmail.display_message(rcmail.gettext('nopassword', 'password'), 'error');
+ input_newpasswd.focus();
+ } else if (input_confpasswd && input_confpasswd.value == '') {
+ rcmail.display_message(rcmail.gettext('nopassword', 'password'), 'error');
+ input_confpasswd.focus();
+ } else if (input_newpasswd && input_confpasswd && input_newpasswd.value != input_confpasswd.value) {
+ rcmail.display_message(rcmail.gettext('passwordinconsistency', 'password'), 'error');
+ input_newpasswd.focus();
+ } else if (input_pwstrength.value == 0) {
+ rcmail.display_message(rcmail.gettext('passwordweak', 'pwstrength'), 'error');
+ input_newpasswd.focus();
+ } else {
+ rcmail.gui_objects.passform.submit();
+ }
+ }, true);
+ })
+}
diff --git a/libgpl/qtip/qtip.css b/libgpl/qtip/qtip.css
new file mode 100644
index 0000000..9147bd7
--- /dev/null
+++ b/libgpl/qtip/qtip.css
@@ -0,0 +1 @@
+.ui-tooltip-fluid{display:block;visibility:hidden;position:static!important;float:left!important;}.ui-tooltip,.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:10.5px;line-height:12px;}.ui-tooltip-content{position:relative;padding:5px 9px;overflow:hidden;border-width:1px;border-style:solid;text-align:left;word-wrap:break-word;overflow:hidden;}.ui-tooltip-titlebar{position:relative;min-height:14px;padding:5px 35px 5px 10px;overflow:hidden;border-width:1px 1px 0;border-style:solid;font-weight:bold;}.ui-tooltip-titlebar+.ui-tooltip-content{border-top-width:0!important;}/*!Default close button class */ .ui-tooltip-titlebar .ui-state-default{position:absolute;right:4px;top:50%;margin-top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;}* html .ui-tooltip-titlebar .ui-state-default{top:16px;}.ui-tooltip-titlebar .ui-icon,.ui-tooltip-icon .ui-icon{display:block;text-indent:-1000em;}.ui-tooltip-icon,.ui-tooltip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}.ui-tooltip-icon .ui-icon{width:18px;height:14px;text-align:center;text-indent:0;font:normal bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em;}/*!Default tooltip style */ .ui-tooltip-titlebar,.ui-tooltip-content{border-color:#F1D031;background-color:#FFFFA3;color:#555;}.ui-tooltip-titlebar{background-color:#FFEF93;}.ui-tooltip-titlebar .ui-tooltip-icon{border-color:#CCC;background:#F1F1F1;color:#777;}.ui-tooltip-titlebar .ui-state-hover{border-color:#AAA;color:#111;}/*!Light tooltip style */ .ui-tooltip-light .ui-tooltip-titlebar,.ui-tooltip-light .ui-tooltip-content{border-color:#E2E2E2;color:#454545;}.ui-tooltip-light .ui-tooltip-content{background-color:white;}.ui-tooltip-light .ui-tooltip-titlebar{background-color:#f1f1f1;}/*!Dark tooltip style */ .ui-tooltip-dark .ui-tooltip-titlebar,.ui-tooltip-dark .ui-tooltip-content{border-color:#303030;color:#f3f3f3;}.ui-tooltip-dark .ui-tooltip-content{background-color:#505050;}.ui-tooltip-dark .ui-tooltip-titlebar{background-color:#404040;}.ui-tooltip-dark .ui-tooltip-icon{border-color:#444;}.ui-tooltip-dark .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}/*!Cream tooltip style */ .ui-tooltip-cream .ui-tooltip-titlebar,.ui-tooltip-cream .ui-tooltip-content{border-color:#F9E98E;color:#A27D35;}.ui-tooltip-cream .ui-tooltip-content{background-color:#FBF7AA;}.ui-tooltip-cream .ui-tooltip-titlebar{background-color:#F0DE7D;}.ui-tooltip-cream .ui-state-default .ui-tooltip-icon{background-position:-82px 0;}/*!Red tooltip style */ .ui-tooltip-red .ui-tooltip-titlebar,.ui-tooltip-red .ui-tooltip-content{border-color:#D95252;color:#912323;}.ui-tooltip-red .ui-tooltip-content{background-color:#F78B83;}.ui-tooltip-red .ui-tooltip-titlebar{background-color:#F06D65;}.ui-tooltip-red .ui-state-default .ui-tooltip-icon{background-position:-102px 0;}.ui-tooltip-red .ui-tooltip-icon{border-color:#D95252;}.ui-tooltip-red .ui-tooltip-titlebar .ui-state-hover{border-color:#D95252;}/*!Green tooltip style */ .ui-tooltip-green .ui-tooltip-titlebar,.ui-tooltip-green .ui-tooltip-content{border-color:#90D93F;color:#3F6219;}.ui-tooltip-green .ui-tooltip-content{background-color:#CAED9E;}.ui-tooltip-green .ui-tooltip-titlebar{background-color:#B0DE78;}.ui-tooltip-green .ui-state-default .ui-tooltip-icon{background-position:-42px 0;}/*!Blue tooltip style */ .ui-tooltip-blue .ui-tooltip-titlebar,.ui-tooltip-blue .ui-tooltip-content{border-color:#ADD9ED;color:#5E99BD;}.ui-tooltip-blue .ui-tooltip-content{background-color:#E5F6FE;}.ui-tooltip-blue .ui-tooltip-titlebar{background-color:#D0E9F5;}.ui-tooltip-blue .ui-state-default .ui-tooltip-icon{background-position:-2px 0;}.ui-tooltip .ui-tooltip-tip{margin:0 auto;overflow:hidden;background:transparent!important;border:0 dashed transparent!important;z-index:10;}.ui-tooltip .ui-tooltip-tip,.ui-tooltip .ui-tooltip-tip *{position:absolute;line-height:.1px!important;font-size:.1px!important;color:#123456;background:transparent;border:0 dashed transparent;}.ui-tooltip .ui-tooltip-tip canvas{position:static;}#qtip-overlay{position:absolute;left:-10000em;top:-10000em;background-color:black;opacity:.7;filter:alpha(opacity=70);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";}/*!Add shadows to your tooltips in:FF3+,Chrome 2+,Opera 10.6+,IE6+,Safari 2+*/ .ui-tooltip-shadow{-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);-moz-box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);}.ui-tooltip-shadow .ui-tooltip-titlebar,.ui-tooltip-shadow .ui-tooltip-content{filter:progid:DXImageTransform.Microsoft.Shadow(Color='gray',Direction=135,Strength=3);-ms-filter:"progid:DXImageTransform.Microsoft.Shadow(Color='gray',Direction=135,Strength=3)";_margin-bottom:-3px;.margin-bottom:-3px;}/*!Add rounded corners to your tooltips in:FF3+,Chrome 2+,Opera 10.6+,IE9+,Safari 2+*/ .ui-tooltip-rounded,.ui-tooltip-rounded .ui-tooltip-content,.ui-tooltip-tipsy,.ui-tooltip-tipsy .ui-tooltip-content,.ui-tooltip-youtube,.ui-tooltip-youtube .ui-tooltip-content{-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;}.ui-tooltip-rounded .ui-tooltip-titlebar,.ui-tooltip-tipsy .ui-tooltip-titlebar,.ui-tooltip-youtube .ui-tooltip-titlebar{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}.ui-tooltip-rounded .ui-tooltip-titlebar+.ui-tooltip-content,.ui-tooltip-tipsy .ui-tooltip-titlebar+.ui-tooltip-content,.ui-tooltip-youtube .ui-tooltip-titlebar+.ui-tooltip-content{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;}/*!Youtube tooltip style */ .ui-tooltip-youtube{-webkit-box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;box-shadow:0 0 3px #333;}.ui-tooltip-youtube .ui-tooltip-titlebar,.ui-tooltip-youtube .ui-tooltip-content{background:transparent;background:rgba(0,0,0,0.85);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)";color:white;border-color:#CCC;}.ui-tooltip-youtube .ui-tooltip-icon{border-color:#222;}.ui-tooltip-youtube .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}.ui-tooltip-jtools{background:#232323;background:rgba(0,0,0,0.7);background-image:-moz-linear-gradient(top,#717171,#232323);background-image:-webkit-gradient(linear,left top,left bottom,from(#717171),to(#232323));border:2px solid #ddd;border:2px solid rgba(241,241,241,1);-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 12px #333;-moz-box-shadow:0 0 12px #333;box-shadow:0 0 12px #333;}.ui-tooltip-jtools .ui-tooltip-titlebar{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A)";}.ui-tooltip-jtools .ui-tooltip-content{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323)";}.ui-tooltip-jtools .ui-tooltip-titlebar,.ui-tooltip-jtools .ui-tooltip-content{background:transparent;color:white;border:0 dashed transparent;}.ui-tooltip-jtools .ui-tooltip-icon{border-color:#555;}.ui-tooltip-jtools .ui-tooltip-titlebar .ui-state-hover{border-color:#333;}.ui-tooltip-cluetip{-webkit-box-shadow:4px 4px 5px rgba(0,0,0,0.4);-moz-box-shadow:4px 4px 5px rgba(0,0,0,0.4);box-shadow:4px 4px 5px rgba(0,0,0,0.4);}.ui-tooltip-cluetip .ui-tooltip-titlebar{background-color:#87876A;color:white;border:0 dashed transparent;}.ui-tooltip-cluetip .ui-tooltip-content{background-color:#D9D9C2;color:#111;border:0 dashed transparent;}.ui-tooltip-cluetip .ui-tooltip-icon{border-color:#808064;}.ui-tooltip-cluetip .ui-tooltip-titlebar .ui-state-hover{border-color:#696952;color:#696952;}.ui-tooltip-tipsy{border:0;}.ui-tooltip-tipsy .ui-tooltip-titlebar,.ui-tooltip-tipsy .ui-tooltip-content{background:transparent;background:rgba(0,0,0,.87);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)";color:white;border:0 transparent;font-size:11px;font-family:'Lucida Grande',sans-serif;font-weight:bold;line-height:16px;text-shadow:0 1px black;}.ui-tooltip-tipsy .ui-tooltip-titlebar{padding:6px 35px 0 10;}.ui-tooltip-tipsy .ui-tooltip-content{padding:6px 10;}.ui-tooltip-tipsy .ui-tooltip-icon{border-color:#222;text-shadow:none;}.ui-tooltip-tipsy .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}.ui-tooltip-tipped .ui-tooltip-titlebar,.ui-tooltip-tipped .ui-tooltip-content{border:3px solid #959FA9;}.ui-tooltip-tipped .ui-tooltip-titlebar{background:#3A79B8;background-image:-moz-linear-gradient(top,#3A79B8,#2E629D);background-image:-webkit-gradient(linear,left top,left bottom,from(#3A79B8),to(#2E629D));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D)";color:white;font-weight:normal;font-family:serif;border-bottom-width:0;-moz-border-radius:3px 3px 0 0;-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;}.ui-tooltip-tipped .ui-tooltip-content{background-color:#F9F9F9;color:#454545;-moz-border-radius:0 0 3px 3px;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;}.ui-tooltip-tipped .ui-tooltip-icon{border:2px solid #285589;background:#285589;}.ui-tooltip-tipped .ui-tooltip-icon .ui-icon{background-color:#FBFBFB;color:#555;} \ No newline at end of file
diff --git a/libgpl/qtip/qtip.js b/libgpl/qtip/qtip.js
new file mode 100644
index 0000000..7f5b9d9
--- /dev/null
+++ b/libgpl/qtip/qtip.js
@@ -0,0 +1,68 @@
+(function(c,C,N){function X(a){var b=this,f=a.elements,e=f.tooltip,g=".bgiframe-"+a.id;c.extend(b,{init:function(){f.bgiframe=c('<iframe class="ui-tooltip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>');f.bgiframe.appendTo(e);e.bind("tooltipmove"+g,b.adjust)},adjust:function(){var b=a.get("dimensions"),c=a.plugins.tip,h=f.tip,g,
+i;i=parseInt(e.css("border-left-width"),10)||0;i={left:-i,top:-i};c&&h&&(g="x"===c.corner.precedance?["width","left"]:["height","top"],i[g[1]]-=h[g[0]]());f.bgiframe.css(i).css(b)},destroy:function(){f.bgiframe.remove();e.unbind(g)}});b.init()}function Y(a){var b=this,f=a.options.show.modal,e=a.elements,r=e.tooltip,o=".qtipmodal"+a.id,m;a.checks.modal={"^show.modal.(on|blur)$":function(){b.init();e.overlay.toggle(r.is(":visible"))}};c.extend(b,{init:function(){if(!f.on)return b;m=b.create();r.attr("is-modal-qtip",
+p).unbind(".qtipmodal").unbind(o).bind("tooltipshow.qtipmodal tooltiphide.qtipmodal",function(a,c,f){b[a.type.replace("tooltip","")](a,f)}).bind("tooltipfocus.qtipmodal",function(a,c,b){m[0].style.zIndex=b-1}).bind("tooltipblur.qtipmodal",function(a){c("[is-modal-qtip]:visible").not(r).last().qtip("focus",a)});f.escape&&c(C).unbind(o).bind("keydown"+o,function(c){27===c.keyCode&&r.hasClass(P)&&a.hide(c)});f.blur&&e.overlay.unbind(o).bind("click"+o,function(c){r.hasClass(P)&&a.hide(c)});return b},
+create:function(){var a=c("#qtip-overlay");if(a.length)return e.overlay=a;m=e.overlay=c("<div />",{id:"qtip-overlay",css:{position:"absolute",top:0,left:0,display:"none"},mousedown:function(){return g}}).appendTo(document.body);c(C).unbind(".qtipmodal").bind("resize.qtipmodal",function(){m.css({height:Math.max(c(C).height(),c(document).height()),width:Math.max(c(C).width(),c(document).width())})}).trigger("resize");return m},toggle:function(a,q,i){if(a&&a.isDefaultPrevented())return b;var a=f.effect,
+o=q?"show":"hide",t=c("[is-modal-qtip]:visible").not(r);m||(m=b.create());if(m.is(":animated")&&!q||!q&&t.length)return b;q&&e.overlay.css("cursor",f.blur?"pointer":"");m.stop(p,g);c.isFunction(a)?a.call(m,q):a===g?m[o]():m.fadeTo(parseInt(i,10)||90,q?0.7:0,function(){q||c(this).hide()});return b},show:function(a,c){return b.toggle(a,p,c)},hide:function(a,c){return b.toggle(a,g,c)},destroy:function(){var b=m;b&&(b=1>c("[is-modal-qtip]").not(r).length,b?(e.overlay.remove(),c(C).unbind(".qtipmodal")):
+e.overlay.unbind(".qtipmodal"+a.id));return r.removeAttr("is-modal-qtip").unbind(".qtipmodal")}});b.init()}function Z(a){function b(a){var c="y"===a.precedance,b=A[c?"width":"height"],d=A[c?"height":"width"],f=-1<a.string().indexOf("center"),k=b*(f?0.5:1),u=Math.pow,a=Math.round,F=Math.sqrt(u(k,2)+u(d,2)),k=[v/k*F,v/d*F];k[2]=Math.sqrt(u(k[0],2)-u(v,2));k[3]=Math.sqrt(u(k[1],2)-u(v,2));f=(F+k[2]+k[3]+(f?0:k[0]))/F;b=[a(f*d),a(f*b)];return{height:b[c?0:1],width:b[c?1:0]}}function f(a,c,b){c=c?c:a[a.precedance];
+c="border-"+c+"-width";a=parseInt((i.titlebar&&"top"===a.y?i.titlebar:i.content).css(c),10);return(b?a||parseInt(n.css(c),10):a)||0}function e(b,d,f){if(i.tip){var b=c.extend({},h.corner),d=f.adjusted,e=a.options.position.adjust.method.split(" "),v=e[0],e=e[1]||e[0],k=g,u=g,F=0,K=0,l,D={},M;h.corner.fixed!==p&&("shift"===v&&"x"===b.precedance&&d.left&&"center"!==b.y?b.precedance="x"===b.precedance?"y":"x":"flip"===v&&d.left&&(b.x="center"===b.x?0<d.left?"left":"right":"left"===b.x?"right":"left"),
+"shift"===e&&"y"===b.precedance&&d.top&&"center"!==b.x?b.precedance="y"===b.precedance?"x":"y":"flip"===e&&d.top&&(b.y="center"===b.y?0<d.top?"top":"bottom":"top"===b.y?"bottom":"top"),b.string()!==r&&(o!==d.top||m!==d.left)&&h.update(b,g));l=h.position(b,d);l.right!==N&&(l.left=-l.right);l.bottom!==N&&(l.top=-l.bottom);l.user=Math.max(0,q.offset);if(k="shift"===v&&!!d.left)"center"===b.x?D["margin-left"]=F=l["margin-left"]-d.left:(M=l.right!==N?[d.left,-l.left]:[-d.left,l.left],(F=Math.max(M[0],
+M[1]))>M[0]&&(f.left-=d.left,k=g),D[l.right!==N?"right":"left"]=F);if(u="shift"===e&&!!d.top)"center"===b.y?D["margin-top"]=K=l["margin-top"]-d.top:(M=l.bottom!==N?[d.top,-l.top]:[-d.top,l.top],(K=Math.max(M[0],M[1]))>M[0]&&(f.top-=d.top,u=g),D[l.bottom!==N?"bottom":"top"]=K);i.tip.css(D).toggle(!(F&&K||"center"===b.x&&K||"center"===b.y&&F));f.left-=l.left.charAt?l.user:"shift"!==v||u||!k&&!u?l.left:0;f.top-=l.top.charAt?l.user:"shift"!==e||k||!k&&!u?l.top:0;m=d.left;o=d.top;r=b.string()}}var r,o,
+m,h=this,q=a.options.style.tip,i=a.elements,n=i.tooltip;m=o=0;r="";var A={width:q.width,height:q.height},y,d,v=q.border||0,G=c("<canvas />")[0].getContext;h.corner=x;h.mimic=x;h.position={};a.checks.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){h.init()||h.destroy();a.reposition()},"^style.tip.(height|width)$":function(){A={width:q.width,height:q.height};h.create();h.update();a.reposition()},"^content.title.text|style.(classes|widget)$":function(){i.tip&&h.update()}};c.extend(h,
+{init:function(){var a=h.detectCorner()&&(G||c.browser.msie);a&&(h.create(),h.update(),n.unbind(".qtip-tip").bind("tooltipmove.qtip-tip",e));return a},detectCorner:function(){var b=q.corner,c=a.options.position,d=c.at,c=c.my.string?c.my.string():c.my;if(b===g||c===g&&d===g)return g;b===p?h.corner=new t.Corner(c):b.string||(h.corner=new t.Corner(b),h.corner.fixed=p);return"centercenter"!==h.corner.string()},detectColours:function(){var b,f,j=i.tip.css({backgroundColor:"",border:""});b=h.corner;var e=
+b[b.precedance],g="border-"+e+"-color";f="border"+e.charAt(0)+e.substr(1)+"Color";var e=/rgba?\(0, 0, 0(, 0)?\)|transparent/i,k=c(document.body).css("color"),u=a.elements.content.css("color"),F=i.titlebar&&("top"===b.y||"center"===b.y&&j.position().top+A.height/2+q.offset<i.titlebar.outerHeight(1))?i.titlebar:i.content;n.addClass("ui-tooltip-fluid");b=j.css("background-color")||"transparent";f=j[0].style[f];if(!b||e.test(b))y=F.css("background-color"),e.test(y)&&(y=n.css("background-color")||b);if(!f||
+e.test(f))if(d=n.css(g),e.test(d)||d===k)d=F.css(g),d===u&&(d=f);c("*",j).add(j).css("background-color","transparent").css("border","");n.removeClass("ui-tooltip-fluid")},create:function(){var a=A.width,b=A.height;i.tip&&i.tip.remove();i.tip=c("<div />",{"class":"ui-tooltip-tip"}).css({width:a,height:b}).prependTo(n);G?c("<canvas />").appendTo(i.tip)[0].getContext("2d").save():i.tip.html(v?'<vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape><vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape>':
+'<vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape>')},update:function(a,e){var j=i.tip,r=j.children(),o=A.width,k=A.height,u=q.mimic,F=Math.round,K,l,D,m,n;a||(a=h.corner);u===g?u=a:(u=new t.Corner(u),u.precedance=a.precedance,"inherit"===u.x?u.x=a.x:"inherit"===u.y?u.y=a.y:u.x===u.y&&(u[a.precedance]=a[a.precedance]));K=u.precedance;h.detectColours();v="transparent"===d||"#123456"===d?0:q.border===p?f(a,x,p):q.border;n=u;var B=
+o,S=Math.ceil(B/2),W=Math.ceil(k/2),B={bottomright:[[0,0],[B,k],[B,0]],bottomleft:[[0,0],[B,0],[0,k]],topright:[[0,k],[B,0],[B,k]],topleft:[[0,0],[0,k],[B,k]],topcenter:[[0,k],[S,0],[B,k]],bottomcenter:[[0,0],[B,0],[S,k]],rightcenter:[[0,0],[B,W],[0,k]],leftcenter:[[B,0],[B,k],[0,W]]};B.lefttop=B.bottomright;B.righttop=B.bottomleft;B.leftbottom=B.topright;B.rightbottom=B.topleft;D=B[n.string()];n=b(a);j.css(n);"y"===a.precedance?m=[F("left"===u.x?v:"right"===u.x?n.width-o-v:(n.width-o)/2),F("top"===
+u.y?n.height-k:0)]:m=[F("left"===u.x?n.width-o:0),F("top"===u.y?v:"bottom"===u.y?n.height-k-v:(n.height-k)/2)];G?(r.attr(n),l=r[0].getContext("2d"),l.restore(),l.save(),l.clearRect(0,0,3E3,3E3),l.translate(m[0],m[1]),l.beginPath(),l.moveTo(D[0][0],D[0][1]),l.lineTo(D[1][0],D[1][1]),l.lineTo(D[2][0],D[2][1]),l.closePath(),l.fillStyle=y,l.strokeStyle=d,l.lineWidth=2*v,l.lineJoin="miter",l.miterLimit=100,l.stroke(),l.fill()):(D="m"+D[0][0]+","+D[0][1]+" l"+D[1][0]+","+D[1][1]+" "+D[2][0]+","+D[2][1]+
+" xe",m[2]=v&&/^(r|b)/i.test(a.string())?8===parseFloat(c.browser.version,10)?2:1:0,r.css({antialias:""+(-1<u.string().indexOf("center")),left:m[0]-m[2]*Number("x"===K),top:m[1]-m[2]*Number("y"===K),width:o+v,height:k+v}).each(function(a){var b=c(this);b.attr({coordsize:o+v+" "+(k+v),path:D,fillcolor:y,filled:!!a,stroked:!a}).css({display:v||a?"block":"none"});!a&&0<v&&""===b.html()&&b.html('<vml:stroke weight="'+2*v+'px" color="'+d+'" miterlimit="1000" joinstyle="miter" style="behavior:url(#default#VML); display:inline-block;" />')}));
+e!==g&&h.position(a)},position:function(a){var d=i.tip,e={},r=Math.max(0,q.offset),m,k,u;if(q.corner===g||!d)return g;a=a||h.corner;m=a.precedance;k=b(a);u=[a.x,a.y];"x"===m&&u.reverse();c.each(u,function(b,d){var u;if("center"===d)u="y"===m?"left":"top",e[u]="50%",e["margin-"+u]=-Math.round(k["y"===m?"width":"height"]/2)+r;else{u=f(a,d,p);var g;g=c.browser.mozilla;var h=a.y+(g?"":"-")+a.x;g=(g?"-moz-":c.browser.webkit?"-webkit-":"")+(g?"border-radius-"+h:"border-"+h+"-radius");g=parseInt((i.titlebar&&
+"top"===a.y?i.titlebar:i.content).css(g),10)||parseInt(n.css(g),10)||0;e[d]=b?f(a,d):r+(g>u?g:0)}});e[a[m]]-=k["x"===m?"width":"height"];d.css({top:"",bottom:"",left:"",right:"",margin:""}).css(e);return e},destroy:function(){i.tip&&i.tip.remove();n.unbind(".qtip-tip")}});h.init()}function $(a){var b=this,f=a.elements.tooltip,e=a.options.content.ajax,r=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;a.checks.ajax={"^content.ajax":function(a,c,g){"ajax"===c&&(e=g);"once"===c?b.init():e&&e.url?
+b.load():f.unbind(".qtip-ajax")}};c.extend(b,{init:function(){e&&e.url&&f.unbind(".qtip-ajax")[e.once?"one":"bind"]("tooltipshow.qtip-ajax",b.load);return b},load:function(o,m){function h(){p&&(f.css("visibility",""),m=g)}if(o&&o.isDefaultPrevented())return b;var q=e.url.indexOf(" "),i=e.url,n,p=e.once&&!e.loading&&m;p&&f.css("visibility","hidden");-1<q&&(n=i.substr(q),i=i.substr(0,q));c.ajax(c.extend({success:function(b){n&&(b=c("<div/>").append(b.replace(r,"")).find(n));a.set("content.text",b);
+h()},error:function(b,c,f){a.set("content.text",c+": "+f);h()},context:a},e,{url:i}));return b}});b.init()}function aa(a,b,f,e){function r(a,u,e,g){var g=0!==parseInt(g,10),l=".qtip-"+f,j=a&&b.show.target[0],u=u&&b.hide.target[0],h=e&&d.rendered&&w.tooltip[0],e=e&&d.rendered&&w.content[0],i=g&&b.position.container[0]===v?document:b.position.container[0],g=g&&C;d.rendered?c([]).pushStack(c.grep([j,u,h,i,e,g],function(a){return"object"===typeof a})).unbind(l):a&&b.show.target.unbind(l+"-create")}function o(k,
+u,e,h){function l(a){j.is(":visible")&&d.reposition(a)}function i(a){if(j.hasClass(L))return g;clearTimeout(d.timers.inactive);d.timers.inactive=setTimeout(function(){d.hide(a)},b.hide.inactive)}function r(a){if(j.hasClass(L))return g;var k=c(a.relatedTarget||a.target),f=k.closest(T)[0]===j[0],k=k[0]===q[0];clearTimeout(d.timers.show);clearTimeout(d.timers.hide);if("mouse"===t.target&&f||b.hide.fixed&&/mouse(out|leave|move)/.test(a.type)&&(f||k))return a.stopPropagation(),a.preventDefault(),g;0<b.hide.delay?
+d.timers.hide=setTimeout(function(){d.hide(a)},b.hide.delay):d.hide(a)}function m(a){if(j.hasClass(L))return g;q.trigger("qtip-"+f+"-inactive");clearTimeout(d.timers.show);clearTimeout(d.timers.hide);var c=function(){d.show(a)};0<b.show.delay?d.timers.show=setTimeout(c,b.show.delay):c()}var q,o,p,n=".qtip-"+f,t=b.position;q=b.show.target;o=b.hide.target;t.container[0]===v&&c(document);p=c(document);var y=c.trim(""+b.show.event).split(" "),z=c.trim(""+b.hide.event).split(" "),s=c.browser.msie&&6===
+parseInt(c.browser.version,10);e&&(b.hide.fixed&&(o=o.add(j),j.bind("mouseover"+n,function(){j.hasClass(L)||clearTimeout(d.timers.hide)})),"mouse"===t.target&&t.adjust.mouse&&b.hide.event&&j.bind("mouseleave"+n,function(a){(a.relatedTarget||a.target)!==q[0]&&d.hide(a)}),j.bind("mouseenter"+n,function(a){d["mouseenter"===a.type?"focus":"blur"](a)}),j.bind("mouseenter"+n+" mouseleave"+n,function(a){j.toggleClass(ba,"mouseenter"===a.type)}));u&&("number"===typeof b.hide.inactive&&(q.bind("qtip-"+f+"-inactive",
+i),c.each(H.inactiveEvents,function(a,b){o.add(w.tooltip).bind(b+n+"-inactive",i)})),/mouse(over|enter)/i.test(b.show.event)&&!/mouse(out|leave)/i.test(b.hide.event)&&o.bind("mouseleave"+n,function(){clearTimeout(d.timers.show)}),c.each(z,function(a,b){var k=c.inArray(b,y),d=c(o);-1<k&&d.add(q).length===d.length||"unfocus"===b?(q.bind(b+n,function(a){j.is(":visible")?r(a):m(a)}),delete y[k]):o.bind(b+n,r)}));k&&(c.each(y,function(a,b){q.bind(b+n,m)}),"number"===typeof b.hide.distance&&q.bind("mousemove"+
+n,function(a){var c=E.origin||{},k=b.hide.distance,f=Math.abs;c&&(f(a.pageX-c.pageX)>=k||f(a.pageY-c.pageY)>=k)&&d.hide(a)}));h&&((t.adjust.resize||t.viewport)&&c(c.event.special.resize?t.viewport:C).bind("resize"+n,l),(t.viewport||s&&"fixed"===j.css("position"))&&c(t.viewport).bind("scroll"+n,l),/unfocus/i.test(b.hide.event)&&p.bind("mousedown"+n,function(b){var k=c(b.target);0===k.parents(T).length&&1<k.add(a).length&&j.is(":visible")&&!j.hasClass(L)&&d.hide(b)}),b.hide.leave&&/mouseleave|mouseout/i.test(b.hide.event)&&
+c(C).bind("blur"+n+" mouse"+(-1<b.hide.leave.indexOf("frame")?"out":"leave")+n,function(a){a.relatedTarget||d.hide(a)}),"mouse"===t.target&&p.bind("mousemove"+n,function(a){t.adjust.mouse&&!j.hasClass(L)&&j.is(":visible")&&d.reposition(a||Q)}))}function m(k){function f(a){function b(){0===(c=c.not(this)).length&&(d.redraw(),d.reposition(E.event),a())}var c;if(0===(c=e.find("img:not([height]):not([width])")).length)return b.call(c);c.each(function(a,c){(function S(){var k=d.timers.img;if(c.height&&
+c.width)return clearTimeout(k[a]),b.call(c);k[a]=setTimeout(S,20)})()})}var e=w.content,k=k||b.content.text;if(!d.rendered||!k)return g;c.isFunction(k)&&(k=k.call(a,d)||"");k.jquery&&0<k.length?e.empty().append(k.css({display:"block"})):e.html(k);0>d.rendered?j.queue("fx",f):(J=0,f(c.noop));return d}function h(b){var f=w.title;if(!d.rendered||!b)return g;c.isFunction(b)&&(b=b.call(a,d)||"");b.jquery&&0<b.length?f.empty().append(b.css({display:"block"})):f.html(b);d.redraw();d.rendered&&j.is(":visible")&&
+d.reposition(E.event)}function q(){var a=G+"-title";w.titlebar&&n();w.titlebar=c("<div />",{"class":I+"-titlebar "+(b.style.widget?"ui-widget-header":"")}).append(w.title=c("<div />",{id:a,"class":I+"-title","aria-atomic":p})).insertBefore(w.content);b.content.title.button?i():d.rendered&&d.redraw()}function i(){var a=b.content.title.button,f="string"===typeof a?a:"Close tooltip";w.button&&w.button.remove();a.jquery?w.button=a:w.button=c("<a />",{"class":"ui-state-default "+(b.style.widget?"":I+"-icon"),
+title:f,"aria-label":f}).prepend(c("<span />",{"class":"ui-icon ui-icon-close",html:"&times;"}));w.button.appendTo(w.titlebar).attr("role","button").hover(function(a){c(this).toggleClass("ui-state-hover","mouseenter"===a.type)}).click(function(a){j.hasClass(L)||d.hide(a);return g}).bind("mousedown keydown mouseup keyup mouseout",function(a){c(this).toggleClass("ui-state-active ui-state-focus","down"===a.type.substr(-4))});d.redraw()}function n(){w.title&&(w.titlebar.remove(),w.titlebar=w.title=w.button=
+x,d.reposition())}function A(){var a=b.style.widget;j.toggleClass(V,a);w.content.toggleClass(V+"-content",a);w.titlebar&&w.titlebar.toggleClass(V+"-header",a);w.button&&w.button.toggleClass(I+"-icon",!a)}function y(a){for(var c=0,d,f=b,a=a.split(".");f=f[a[c++]];)c<a.length&&(d=f);return[d||b,a.pop()]}var d=this,v=document.body,G=I+"-"+f,R=0,J=0,j=c(),w,E;d.id=f;d.rendered=g;d.elements=w={target:a};d.timers={img:[]};d.options=b;d.checks={};d.plugins={};d.cache=E={event:{},target:x,disabled:g,attr:e};
+d.checks.builtin={"^id$":function(a,b,d){a=d===p?H.nextid:d;b=I+"-"+a;a!==g&&0<a.length&&!c("#"+b).length&&(j[0].id=b,w.content[0].id=b+"-content",w.title[0].id=b+"-title")},"^content.text$":function(a,b,c){m(c)},"^content.title.text$":function(a,b,c){if(!c)return n();!w.title&&c&&q();h(c)},"^content.title.button$":function(a,b,c){a=w.button;b=w.title;d.rendered&&(c?(b||q(),i()):a.remove())},"^position.(my|at)$":function(a,b,c){"string"===typeof c&&(a[b]=new t.Corner(c))},"^position.container$":function(a,
+b,c){d.rendered&&j.appendTo(c)},"^(show|hide).(event|target|fixed|delay|inactive)$":function(a,b,c,f,e){a=[1,0,0];a["show"===e[1]?"push":"unshift"](0);r.apply(d,a);o.apply(d,[1,1,0,0])},"^show.ready$":function(){d.rendered?d.show():d.render(1)},"^style.classes$":function(a,b,d){c.attr(j[0],"class",I+" qtip ui-helper-reset "+d)},"^style.widget|content.title":A,"^events.(render|show|move|hide|focus|blur)$":function(a,b,d){j[(c.isFunction(d)?"":"un")+"bind"]("tooltip"+b,d)}};c.extend(d,{render:function(k){if(d.rendered)return d;
+var f=b.content.title.text,e=c.Event("tooltiprender");c.attr(a[0],"aria-describedby",G);j=w.tooltip=c("<div/>",{id:G,"class":I+" qtip ui-helper-reset "+b.style.classes,width:b.style.width||"",role:"alert","aria-live":"polite","aria-atomic":g,"aria-describedby":G+"-content","aria-hidden":p}).toggleClass(L,E.disabled).data("qtip",d).appendTo(b.position.container).append(w.content=c("<div />",{"class":I+"-content",id:G+"-content","aria-atomic":p}));d.rendered=-1;J=1;f&&(q(),h(f));m();d.rendered=p;A();
+c.each(b.events,function(a,b){c.isFunction(b)&&j.bind("toggle"===a?"tooltipshow tooltiphide":"tooltip"+a,b)});c.each(t,function(){"render"===this.initialize&&this(d)});o(1,1,1,1);j.queue("fx",function(a){e.originalEvent=E.event;j.trigger(e,[d]);J=0;d.redraw();(b.show.ready||k)&&d.show(E.event);a()});return d},get:function(a){switch(a.toLowerCase()){case "dimensions":a={height:j.outerHeight(),width:j.outerWidth()};break;case "offset":a=t.offset(j,b.position.container);break;default:a=y(a.toLowerCase()),
+a=a[0][a[1]],a=a.precedance?a.string():a}return a},set:function(a,f){var e=/^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,h=/^content\.(title|attr)|style/i,l=g,i=g,r=d.checks,q;"string"===typeof a?(q=a,a={},a[q]=f):a=c.extend(p,{},a);c.each(a,function(b,d){var f=y(b.toLowerCase()),g;g=f[0][f[1]];f[0][f[1]]="object"===typeof d&&d.nodeType?c(d):d;a[b]=[f[0],f[1],d,g];l=e.test(b)||l;i=h.test(b)||i});U(b);R=J=1;c.each(a,function(a,b){var c,f,k;for(c in r)for(f in r[c])if(k=RegExp(f,
+"i").exec(a))b.push(k),r[c][f].apply(d,b)});R=J=0;j.is(":visible")&&d.rendered&&(l&&d.reposition("mouse"===b.position.target?x:E.event),i&&d.redraw());return d},toggle:function(a,e){function h(){a?(c.browser.msie&&j[0].style.removeAttribute("filter"),j.css("overflow","")):j.css({display:"",visibility:"",width:"",opacity:"",left:"",top:""})}if(!d.rendered)if(a)d.render(1);else return d;var i=a?"show":"hide",l=b[i],r=j.is(":visible");(typeof a).search("boolean|number")&&(a=!r);if(r===a)return d;if(e){if(/over|enter/.test(e.type)&&
+/out|leave/.test(E.event.type)&&e.target===b.show.target[0]&&j.has(e.relatedTarget).length)return d;E.event=c.extend({},e)}r=c.Event("tooltip"+i);r.originalEvent=e?E.event:x;j.trigger(r,[d,90]);if(r.isDefaultPrevented())return d;c.attr(j[0],"aria-hidden",!a);a?(E.origin=c.extend({},Q),d.focus(e),c.isFunction(b.content.text)&&m(),d.reposition(e),l.solo&&c(T,l.solo).not(j).qtip("hide",r)):(clearTimeout(d.timers.show),delete E.origin,d.blur(e));j.stop(0,1);c.isFunction(l.effect)?(l.effect.call(j,d),
+j.queue("fx",function(a){h();a()})):l.effect===g?(j[i](),h.call(j)):j.fadeTo(90,a?1:0,h);a&&l.target.trigger("qtip-"+f+"-inactive");return d},show:function(a){return d.toggle(p,a)},hide:function(a){return d.toggle(g,a)},focus:function(a){if(!d.rendered)return d;var b=c(T),f=parseInt(j[0].style.zIndex,10),e=H.zindex+b.length,a=c.extend({},a),g;j.hasClass(P)||(g=c.Event("tooltipfocus"),g.originalEvent=a,j.trigger(g,[d,e]),g.isDefaultPrevented()||(f!==e&&(b.each(function(){this.style.zIndex>f&&(this.style.zIndex-=
+1)}),b.filter("."+P).qtip("blur",a)),j.addClass(P)[0].style.zIndex=e));return d},blur:function(a){var a=c.extend({},a),b;j.removeClass(P);b=c.Event("tooltipblur");b.originalEvent=a;j.trigger(b,[d]);return d},reposition:function(a,f){if(!d.rendered||R)return d;R=1;var e=b.position.target,h=b.position,l=h.my,i=h.at,r=h.adjust,q=r.method.split(" "),m=j.outerWidth(),n=j.outerHeight(),o=0,p=0,y=c.Event("tooltipmove"),w="fixed"===j.css("position"),z=h.viewport,s={left:0,top:0},A=(d.plugins.tip||{}).corner,
+x={horizontal:q[0],vertical:q[1]||q[0],tip:b.style.tip||{},left:function(a){var b="shift"===x.horizontal,c=z.offset.left+z.scrollLeft,d="left"===l.x?m:"right"===l.x?-m:-m/2,f="left"===i.x?o:"right"===i.x?-o:-o/2,e=x.tip.width+2*x.tip.border||0,g=A&&"x"===A.precedance&&!b?e:0,h=c-a-g,k=a+m-z.width-c+g,f=d-("x"===l.precedance||l.x===l.y?f:0),j="center"===l.x;b?(g=A&&"y"===A.precedance?e:0,f=("left"===l.x?1:-1)*d-g,s.left+=0<h?h:0<k?-k:0,s.left=Math.max(z.offset.left+(g&&"center"===A.x?x.tip.offset:
+0),a-f,Math.min(Math.max(z.offset.left+z.width,a+f),s.left))):(0<h&&("left"!==l.x||0<k)?s.left-=f+(j?0:2*r.x):0<k&&("right"!==l.x||0<h)&&(s.left-=j?-f:f+2*r.x),s.left!==a&&j&&(s.left-=r.x),s.left<c&&-s.left>k&&(s.left=a));return s.left-a},top:function(a){var b="shift"===x.vertical,c=z.offset.top+z.scrollTop,d="top"===l.y?n:"bottom"===l.y?-n:-n/2,f="top"===i.y?p:"bottom"===i.y?-p:-p/2,e=x.tip.height+2*x.tip.border||0,g=A&&"y"===A.precedance&&!b?e:0,h=c-a-g,c=a+n-z.height-c+g,f=d-("y"===l.precedance||
+l.x===l.y?f:0),k="center"===l.y;b?(g=A&&"x"===A.precedance?e:0,f=("top"===l.y?1:-1)*d-g,s.top+=0<h?h:0<c?-c:0,s.top=Math.max(z.offset.top+(g&&"center"===A.x?x.tip.offset:0),a-f,Math.min(Math.max(z.offset.top+z.height,a+f),s.top))):(0<h&&("top"!==l.y||0<c)?s.top-=f+(k?0:2*r.y):0<c&&("bottom"!==l.y||0<h)&&(s.top-=k?-f:f+2*r.y),s.top!==a&&k&&(s.top-=r.y),0>s.top&&-s.top>c&&(s.top=a));return s.top-a}};if("mouse"===e)i={x:"left",y:"top"},a=a&&("resize"===a.type||"scroll"===a.type)?E.event:!r.mouse&&E.origin?
+E.origin:Q&&(r.mouse||!a||!a.pageX)?{pageX:Q.pageX,pageY:Q.pageY}:a,s={top:a.pageY,left:a.pageX};else{"event"===e&&(a&&a.target&&"scroll"!==a.type&&"resize"!==a.type?e=E.target=c(a.target):e=E.target);e=c(e).eq(0);if(0===e.length)return d;e[0]===document||e[0]===C?(o=t.iOS?C.innerWidth:e.width(),p=t.iOS?C.innerHeight:e.height(),e[0]===C&&(s={top:!w||t.iOS?z.scrollTop():0,left:!w||t.iOS?z.scrollLeft():0})):e.is("area")&&t.imagemap?s=t.imagemap(e,i):"http://www.w3.org/2000/svg"===e[0].namespaceURI&&
+t.svg?s=t.svg(e,i):(o=e.outerWidth(),p=e.outerHeight(),s=t.offset(e,h.container,w));s.offset&&(o=s.width,p=s.height,s=s.offset);s.left+="right"===i.x?o:"center"===i.x?o/2:0;s.top+="bottom"===i.y?p:"center"===i.y?p/2:0}s.left+=r.x+("right"===l.x?-m:"center"===l.x?-m/2:0);s.top+=r.y+("bottom"===l.y?-n:"center"===l.y?-n/2:0);z.jquery&&e[0]!==C&&e[0]!==v&&"nonenone"!==x.vertical+x.horizontal?(z={elem:z,height:z[(z[0]===C?"h":"outerH")+"eight"](),width:z[(z[0]===C?"w":"outerW")+"idth"](),scrollLeft:z.scrollLeft(),
+scrollTop:z.scrollTop(),offset:z.offset()||{left:0,top:0}},s.adjusted={left:"none"!==x.horizontal?x.left(s.left):0,top:"none"!==x.vertical?x.top(s.top):0}):s.adjusted={left:0,top:0};j.attr("class",function(){return c.attr(this,"class").replace(/ui-tooltip-pos-\w+/i,"")}).addClass(I+"-pos-"+l.abbreviation());y.originalEvent=c.extend({},a);j.trigger(y,[d,s,z.elem||z]);if(y.isDefaultPrevented())return d;delete s.adjusted;f===g||isNaN(s.left)||isNaN(s.top)||!c.isFunction(h.effect)?j.css(s):c.isFunction(h.effect)&&
+(h.effect.call(j,d,c.extend({},s)),j.queue(function(a){c(this).css({opacity:"",height:""});c.browser.msie&&this.style.removeAttribute("filter");a()}));R=0;return d},redraw:function(){if(1>d.rendered||b.style.width||J)return d;var a=I+"-fluid",f=b.position.container,e,g,h;J=1;j.css("width","").addClass(a);e=j.width()+(c.browser.mozilla?1:0);g=j.css("max-width")||"";h=j.css("min-width")||"";f=-1<(g+h).indexOf("%")?f.width()/100:0;g=(-1<g.indexOf("%")?f:1)*parseInt(g,10)||e;h=(-1<h.indexOf("%")?f:1)*
+parseInt(h,10)||0;e=g+h?Math.min(Math.max(e,h),g):e;j.css("width",Math.round(e)).removeClass(a);J=0;return d},disable:function(a){var b=L;"boolean"!==typeof a&&(a=!j.hasClass(b)&&!E.disabled);d.rendered?(j.toggleClass(b,a),c.attr(j[0],"aria-disabled",a)):E.disabled=!!a;return d},enable:function(){return d.disable(g)},destroy:function(){var b=a[0],f=c.attr(b,O);d.rendered&&(j.remove(),c.each(d.plugins,function(){this.destroy&&this.destroy()}));clearTimeout(d.timers.show);clearTimeout(d.timers.hide);
+r(1,1,1,1);c.removeData(b,"qtip");f&&(c.attr(b,"title",f),a.removeAttr(O));a.removeAttr("aria-describedby").unbind(".qtip");return a}})}function U(a){var b;if(!a||"object"!==typeof a)return g;"object"!==typeof a.metadata&&(a.metadata={type:a.metadata});if("content"in a){if("object"!==typeof a.content||a.content.jquery)a.content={text:a.content};b=a.content.text||g;!c.isFunction(b)&&(!b&&!b.attr||1>b.length||"object"===typeof b&&!b.jquery)&&(a.content.text=g);"title"in a.content&&("object"!==typeof a.content.title&&
+(a.content.title={text:a.content.title}),b=a.content.title.text||g,!c.isFunction(b)&&(!b&&!b.attr||1>b.length||"object"===typeof b&&!b.jquery)&&(a.content.title.text=g))}"position"in a&&"object"!==typeof a.position&&(a.position={my:a.position,at:a.position});"show"in a&&"object"!==typeof a.show&&(a.show.jquery?a.show={target:a.show}:a.show={event:a.show});"hide"in a&&"object"!==typeof a.hide&&(a.hide.jquery?a.hide={target:a.hide}:a.hide={event:a.hide});"style"in a&&"object"!==typeof a.style&&(a.style=
+{classes:a.style});c.each(t,function(){this.sanitize&&this.sanitize(a)});return a}function ca(){var a=C.console;return a&&(a.error||a.log||c.noop).apply(a,arguments)}var p=!0,g=!1,x=null,H,t,Q,I="ui-tooltip",V="ui-widget",L="ui-state-disabled",T="div.qtip."+I,P=I+"-focus",ba=I+"-hover",O="oldtitle";H=c.fn.qtip=function(a,b,f){var e=(""+a).toLowerCase(),r=x,o="disable"===e?[p]:c.makeArray(arguments).slice(1,10),m=o[o.length-1],h=this[0]?c.data(this[0],"qtip"):x;if(!arguments.length&&h||"api"===e)return h;
+if("string"===typeof a)return this.each(function(){var a=c.data(this,"qtip");if(!a)return p;m&&m.timeStamp&&(a.cache.event=m);if("option"!==e&&"options"!==e||!b)a[e]&&a[e].apply(a[e],o);else if(c.isPlainObject(b)||f!==N)a.set(b,f);else return r=a.get(b),g}),r!==x?r:this;if("object"===typeof a||!arguments.length)return h=U(c.extend(p,{},a)),H.bind.call(this,h,m)};H.bind=function(a,b){return this.each(function(){function f(a){function b(){n.render("object"===typeof a||h.show.ready);o.unbind(e);m.unbind(r)}
+if(n.cache.disabled)return g;n.cache.event=c.extend({},a);0<h.show.delay?(clearTimeout(n.timers.show),n.timers.show=setTimeout(b,h.show.delay),e!==r&&m.bind(r,function(){clearTimeout(n.timers.show)})):b()}var e,r,o,m,h,q=!a.id||a.id===g||1>a.id.length||c("#"+I+"-"+a.id).length?H.nextid++:a.id,i=".qtip-"+q+"-create",n;a:{var A,y,d,v,G=c(this),C=c(document.body),J=this===document?C:G;y=G.metadata?G.metadata(a.metadata):x;v="html5"===a.metadata.type&&y?y[a.metadata.name]:x;var j=G.data(a.metadata.name||
+"qtipopts");try{j="string"===typeof j?(new Function("return "+j))():j}catch(w){ca("Unable to parse HTML5 attribute data: "+j)}v=c.extend(p,{},H.defaults,a,"object"===typeof j?U(j):x,U(v||y));y&&c.removeData(this,"metadata");y=v.position;v.id=q;if("boolean"===typeof v.content.text)if(d=G.attr(v.content.attr),v.content.attr!==g&&d)v.content.text=d;else{n=g;break a}y.container===g&&(y.container=C);y.target===g&&(y.target=J);v.show.target===g&&(v.show.target=J);v.show.solo===p&&(v.show.solo=C);v.hide.target===
+g&&(v.hide.target=J);v.position.viewport===p&&(v.position.viewport=y.container);y.at=new t.Corner(y.at);y.my=new t.Corner(y.my);if(c.data(this,"qtip"))if(v.overwrite)G.qtip("destroy");else if(v.overwrite===g){n=g;break a}c.attr(this,"title")&&(c.attr(this,O,c.attr(this,"title")),this.removeAttribute("title"));A=new aa(G,v,q,!!d);c.data(this,"qtip",A);G.bind("remove.qtip",function(){A.destroy()});n=A}if(n===g)return p;h=n.options;c.each(t,function(){"initialize"===this.initialize&&this(n)});o=h.show.target;
+m=h.hide.target;e=c.trim(""+h.show.event).replace(/ /g,i+" ")+i;r=c.trim(""+h.hide.event).replace(/ /g,i+" ")+i;/mouse(over|enter)/i.test(e)&&!/mouse(out|leave)/i.test(r)&&(r+=" mouseleave"+i);o.bind(e,f);(h.show.ready||h.prerender)&&f(b)})};t=H.plugins={Corner:function(a){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,"center").toLowerCase();this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase();this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase();
+this.precedance=-1<a.charAt(0).search(/^(t|b)/)?"y":"x";this.string=function(){return"y"===this.precedance?this.y+this.x:this.x+this.y};this.abbreviation=function(){var a=this.x.substr(0,1),c=this.y.substr(0,1);return a===c?a:"c"===a||"c"!==a&&"c"!==c?c+a:a+c}},offset:function(a,b,f){var a=a.offset(),e=b,g=0,o=document.body,m;if(e){do{if(e[0]===o)break;"static"!==e.css("position")&&(m=e.position(),a.left-=m.left+(parseInt(e.css("borderLeftWidth"),10)||0),a.top-=m.top+(parseInt(e.css("borderTopWidth"),
+10)||0),g++)}while(e=e.offsetParent());if(b[0]!==o||1<g)a.left+=1*b.scrollLeft(),a.top+=1*b.scrollTop();if(4.1>t.iOS&&3.1<t.iOS||!t.iOS&&f)b=c(C),a.left+=-1*b.scrollLeft(),a.top+=-1*b.scrollTop()}return a},iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,3})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_","."))||g,fn:{attr:function(a,b){if(this.length){var f=this[0],e=c.data(f,"qtip");if("title"===a){if(2>arguments.length)return c.attr(f,O);if("object"===
+typeof e)return e&&e.rendered&&"title"===e.options.content.attr&&e.cache.attr&&e.set("content.text",b),c.fn.attr_replacedByqTip.apply(this,arguments),c.attr(f,O,c.attr(f,"title")),this.removeAttr("title")}}},clone:function(a){c([]);return c.fn.clone_replacedByqTip.apply(this,arguments).filter("[oldtitle]").each(function(){c.attr(this,"title",c.attr(this,O));this.removeAttribute(O)}).end()},remove:c.ui?x:function(a,b){c(this).each(function(){b||(!a||c.filter(a,[this]).length)&&c("*",this).add(this).each(function(){c(this).triggerHandler("remove")})})}}};
+c.each(t.fn,function(a,b){if(!b)return p;var f=c.fn[a+"_replacedByqTip"]=c.fn[a];c.fn[a]=function(){return b.apply(this,arguments)||f.apply(this,arguments)}});c(document).bind("mousemove.qtip",function(a){Q={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}});H.version="nightly";H.nextid=0;H.inactiveEvents="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" ");H.zindex=15E3;H.defaults={prerender:g,id:g,overwrite:p,content:{text:p,attr:"title",title:{text:g,button:g}},position:{my:"top left",
+at:"bottom right",target:g,container:g,viewport:g,adjust:{x:0,y:0,mouse:p,resize:p,method:"flip flip"},effect:p},show:{target:g,event:"mouseenter",effect:p,delay:90,solo:g,ready:g},hide:{target:g,event:"mouseleave",effect:p,delay:0,fixed:g,inactive:g,leave:"window",distance:g},style:{classes:"",widget:g,width:g},events:{render:x,move:x,show:x,hide:x,toggle:x,focus:x,blur:x}};t.ajax=function(a){var b=a.plugins.ajax;return"object"===typeof b?b:a.plugins.ajax=new $(a)};t.ajax.initialize="render";t.ajax.sanitize=
+function(a){var b=a.content,c;b&&"ajax"in b&&(c=b.ajax,"object"!==typeof c&&(c=a.content.ajax={url:c}),"boolean"!==typeof c.once&&c.once&&(c.once=!!c.once))};c.extend(p,H.defaults,{content:{ajax:{loading:p,once:p}}});t.imagemap=function(a,b){var f=a.attr("shape").toLowerCase(),e=a.attr("coords").split(","),g=[],o=c('img[usemap="#'+a.parent("map").attr("name")+'"]'),m=o.offset(),h={width:0,height:0,offset:{top:1E10,right:0,bottom:0,left:1E10}},q=0,i=0;m.left+=Math.ceil((o.outerWidth()-o.width())/2);
+m.top+=Math.ceil((o.outerHeight()-o.height())/2);if("poly"===f)for(q=e.length;q--;)i=[parseInt(e[--q],10),parseInt(e[q+1],10)],i[0]>h.offset.right&&(h.offset.right=i[0]),i[0]<h.offset.left&&(h.offset.left=i[0]),i[1]>h.offset.bottom&&(h.offset.bottom=i[1]),i[1]<h.offset.top&&(h.offset.top=i[1]),g.push(i);else g=c.map(e,function(a){return parseInt(a,10)});switch(f){case "rect":h={width:Math.abs(g[2]-g[0]),height:Math.abs(g[3]-g[1]),offset:{left:g[0],top:g[1]}};break;case "circle":h={width:g[2]+2,height:g[2]+
+2,offset:{left:g[0],top:g[1]}};break;case "poly":c.extend(h,{width:Math.abs(h.offset.right-h.offset.left),height:Math.abs(h.offset.bottom-h.offset.top)});if("centercenter"===b.string())h.offset={left:h.offset.left+h.width/2,top:h.offset.top+h.height/2};else{for(var e=f=h,g=g.slice(),o=0,i=q=1,n=0,p=0,t=e.width,d=e.height;0<t&&0<d&&0<q&&0<i;){t=Math.floor(t/2);d=Math.floor(d/2);"left"===b.x?q=t:"right"===b.x?q=e.width-t:q+=Math.floor(t/2);"top"===b.y?i=d:"bottom"===b.y?i=e.height-d:i+=Math.floor(d/
+2);for(o=g.length;o--&&!(2>g.length);)n=g[o][0]-e.offset.left,p=g[o][1]-e.offset.top,("left"===b.x&&n>=q||"right"===b.x&&n<=q||"center"===b.x&&(n<q||n>e.width-q)||"top"===b.y&&p>=i||"bottom"===b.y&&p<=i||"center"===b.y&&(p<i||p>e.height-i))&&g.splice(o,1)}f.offset={left:g[0][0],top:g[0][1]}}h.width=h.height=0}h.offset.left+=m.left;h.offset.top+=m.top;return h};t.tip=function(a){var b=a.plugins.tip;return"object"===typeof b?b:a.plugins.tip=new Z(a)};t.tip.initialize="render";t.tip.sanitize=function(a){var b=
+a.style,c;b&&"tip"in b&&(c=a.style.tip,"object"!==typeof c&&(a.style.tip={corner:c}),/string|boolean/i.test(typeof c.corner)||(c.corner=p),"number"!==typeof c.width&&delete c.width,"number"!==typeof c.height&&delete c.height,"number"!==typeof c.border&&c.border!==p&&delete c.border,"number"!==typeof c.offset&&delete c.offset)};c.extend(p,H.defaults,{style:{tip:{corner:p,mimic:g,width:6,height:6,border:p,offset:0}}});t.svg=function(a){var b=c(document),f=a[0],a={width:0,height:0,offset:{top:1E10,left:1E10}},
+e,g,o;if(f.getBBox&&f.parentNode){e=f.getBBox();g=f.getScreenCTM();f=f.farthestViewportElement||f;if(!f.createSVGPoint)return a;f=f.createSVGPoint();f.x=e.x;f.y=e.y;o=f.matrixTransform(g);a.offset.left=o.x;a.offset.top=o.y;f.x+=e.width;f.y+=e.height;o=f.matrixTransform(g);a.width=o.x-a.offset.left;a.height=o.y-a.offset.top;a.offset.left+=b.scrollLeft();a.offset.top+=b.scrollTop()}return a};t.modal=function(a){var b=a.plugins.modal;return"object"===typeof b?b:a.plugins.modal=new Y(a)};t.modal.initialize=
+"render";t.modal.sanitize=function(a){a.show&&("object"!==typeof a.show.modal?a.show.modal={on:!!a.show.modal}:"undefined"===typeof a.show.modal.on&&(a.show.modal.on=p))};c.extend(p,H.defaults,{show:{modal:{on:g,effect:p,blur:p,escape:p}}});t.bgiframe=function(a){var b=c.browser,f=a.plugins.bgiframe;return 1>c("select, object").length||!b.msie||"6"!==b.version.charAt(0)?g:"object"===typeof f?f:a.plugins.bgiframe=new X(a)};t.bgiframe.initialize="render"})(jQuery,window); \ No newline at end of file
diff --git a/libgpl/querystring/querystring.js b/libgpl/querystring/querystring.js
new file mode 100644
index 0000000..c5d5b83
--- /dev/null
+++ b/libgpl/querystring/querystring.js
@@ -0,0 +1,34 @@
+function PageQuery(q) {
+ if(q.length > 1) this.q = q.substring(1, q.length);
+ else this.q = null;
+ this.keyValuePairs = new Array();
+ if(q) {
+ for(var i=0; i < this.q.split("&").length; i++) {
+ this.keyValuePairs[i] = this.q.split("&")[i];
+ }
+ }
+ this.getKeyValuePairs = function() { return this.keyValuePairs; }
+ this.getValue = function(s) {
+ for(var j=0; j < this.keyValuePairs.length; j++) {
+ if(this.keyValuePairs[j].split("=")[0] == s)
+ return this.keyValuePairs[j].split("=")[1];
+ }
+ return false;
+ }
+ this.getParameters = function() {
+ var a = new Array(this.getLength());
+ for(var j=0; j < this.keyValuePairs.length; j++) {
+ a[j] = this.keyValuePairs[j].split("=")[0];
+ }
+ return a;
+ }
+ this.getLength = function() { return this.keyValuePairs.length; }
+}
+function queryString(key){
+ var page = new PageQuery(window.location.search);
+ var query = page.getValue(key);
+ if(query !== false){
+ query = unescape(query);
+ }
+ return query;
+} \ No newline at end of file
diff --git a/libgpl/skins/classic/calendar.css b/libgpl/skins/classic/calendar.css
new file mode 100644
index 0000000..b9c3009
--- /dev/null
+++ b/libgpl/skins/classic/calendar.css
@@ -0,0 +1,4 @@
+.ui-dialog .ui-dialog-titlebar-close:hover { padding: 1px !important; }
+.ui-dialog .ui-dialog-titlebar-close { border: 1px solid #aaaaaa; background: #e6e6e7 url(images/ui-bg_highlight-hard_75_e6e6e7_1x100.png); height: 16px; width: 16px; }
+.ui-dialog .ui-dialog-title { min-width: 230px; }
+.ui-icon-closethick { background-position: -97px -129px; } \ No newline at end of file
diff --git a/libgpl/skins/classic/images/convert.png b/libgpl/skins/classic/images/convert.png
new file mode 100644
index 0000000..d57a19e
--- /dev/null
+++ b/libgpl/skins/classic/images/convert.png
Binary files differ
diff --git a/libgpl/skins/classic/images/delete.png b/libgpl/skins/classic/images/delete.png
new file mode 100644
index 0000000..af1ecaf
--- /dev/null
+++ b/libgpl/skins/classic/images/delete.png
Binary files differ
diff --git a/libgpl/skins/classic/images/door.png b/libgpl/skins/classic/images/door.png
new file mode 100644
index 0000000..369fc46
--- /dev/null
+++ b/libgpl/skins/classic/images/door.png
Binary files differ
diff --git a/libgpl/skins/classic/images/edit.png b/libgpl/skins/classic/images/edit.png
new file mode 100644
index 0000000..b93e776
--- /dev/null
+++ b/libgpl/skins/classic/images/edit.png
Binary files differ
diff --git a/libgpl/skins/classic/images/message.png b/libgpl/skins/classic/images/message.png
new file mode 100644
index 0000000..be1305e
--- /dev/null
+++ b/libgpl/skins/classic/images/message.png
Binary files differ
diff --git a/libgpl/skins/classic/images/note.png b/libgpl/skins/classic/images/note.png
new file mode 100644
index 0000000..6be00b6
--- /dev/null
+++ b/libgpl/skins/classic/images/note.png
Binary files differ
diff --git a/libgpl/skins/classic/images/task.png b/libgpl/skins/classic/images/task.png
new file mode 100644
index 0000000..2d0a5f8
--- /dev/null
+++ b/libgpl/skins/classic/images/task.png
Binary files differ
diff --git a/libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png b/libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png
new file mode 100644
index 0000000..e228645
--- /dev/null
+++ b/libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png
Binary files differ
diff --git a/libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.png b/libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.png
new file mode 100644
index 0000000..d0a127f
--- /dev/null
+++ b/libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.png
Binary files differ
diff --git a/libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png b/libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png
new file mode 100644
index 0000000..675c051
--- /dev/null
+++ b/libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png
Binary files differ
diff --git a/libgpl/skins/classic/images/ui-icons_004458_256x240.png b/libgpl/skins/classic/images/ui-icons_004458_256x240.png
new file mode 100644
index 0000000..083a564
--- /dev/null
+++ b/libgpl/skins/classic/images/ui-icons_004458_256x240.png
Binary files differ
diff --git a/libgpl/skins/classic/jquery.contextMenu.css b/libgpl/skins/classic/jquery.contextMenu.css
new file mode 100644
index 0000000..9512401
--- /dev/null
+++ b/libgpl/skins/classic/jquery.contextMenu.css
@@ -0,0 +1,141 @@
+/*!
+ * jQuery contextMenu - Plugin for simple contextMenu handling
+ *
+ * Version: git-master
+ *
+ * Authors: Rodney Rehm, Addy Osmani (patches for FF)
+ * Web: http://medialize.github.com/jQuery-contextMenu/
+ *
+ * Licensed under
+ * MIT License http://www.opensource.org/licenses/mit-license
+ * GPL v3 http://opensource.org/licenses/GPL-3.0
+ *
+ */
+
+.context-menu-list {
+ margin:0;
+ padding:0;
+
+ min-width: 120px;
+ max-width: 250px;
+ display: inline-block;
+ position: absolute;
+ list-style-type: none;
+
+ border: 1px solid #DDD;
+ background: #EEE;
+
+ -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -ms-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -o-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+}
+
+.context-menu-item {
+ padding: 2px 2px 2px 24px;
+ background-color: #EEE;
+ position: relative;
+ -webkit-user-select: none;
+ -moz-user-select: -moz-none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.context-menu-separator {
+ padding-bottom:0;
+ border-bottom: 1px solid #DDD;
+}
+
+.context-menu-item > label > input,
+.context-menu-item > label > textarea {
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+ user-select: text;
+}
+
+.context-menu-item.hover {
+ cursor: pointer;
+}
+
+.context-menu-item.disabled {
+ color: #666;
+}
+
+.context-menu-input.hover,
+.context-menu-item.disabled.hover {
+ cursor: default;
+ background-color: #EEE;
+}
+
+.context-menu-submenu:after {
+ content: ">";
+ color: #666;
+ position: absolute;
+ top: 0;
+ right: 3px;
+ z-index: 1;
+}
+
+/* icons
+ #protip:
+ In case you want to use sprites for icons (which I would suggest you do) have a look at
+ http://css-tricks.com/13224-pseudo-spriting/ to get an idea of how to implement
+ .context-menu-item.icon:before {}
+ */
+.context-menu-item.icon { min-height: 16px; background-repeat: no-repeat; background-position: 4px 2px; }
+.context-menu-item.icon-message { background-image: url(images/message.png); }
+.context-menu-item.icon-task { background-image: url(../../../tasklist/skins/classic/createfrommail.png); }
+.context-menu-item.icon-note { background-image: url(images/note.png); }
+.context-menu-item.icon-event { background-image: url(../../../calendar/skins/classic/images/calendars.png); background-position: 3px 0; }
+.context-menu-item.icon-edit { background-image: url(images/edit.png); }
+.context-menu-item.icon-delete { background-image: url(images/delete.png); }
+.context-menu-item.icon-convert { background-image: url(images/actions.png); }
+
+/* vertically align inside labels */
+.context-menu-input > label > * { vertical-align: top; }
+
+/* position checkboxes and radios as icons */
+.context-menu-input > label > input[type="checkbox"],
+.context-menu-input > label > input[type="radio"] {
+ margin-left: -17px;
+}
+.context-menu-input > label > span {
+ margin-left: 5px;
+}
+
+.context-menu-input > label,
+.context-menu-input > label > input[type="text"],
+.context-menu-input > label > textarea,
+.context-menu-input > label > select {
+ display: block;
+ width: 100%;
+
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ -o-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.context-menu-input > label > textarea {
+ height: 100px;
+}
+.context-menu-item > .context-menu-list {
+ display: none;
+ /* re-positioned by js */
+ right: -5px;
+ top: 5px;
+}
+
+.context-menu-item.hover > .context-menu-list {
+ display: block;
+}
+
+.context-menu-accesskey {
+ text-decoration: underline;
+}
diff --git a/libgpl/skins/classic/timepicker2.css b/libgpl/skins/classic/timepicker2.css
new file mode 100644
index 0000000..ee43c69
--- /dev/null
+++ b/libgpl/skins/classic/timepicker2.css
@@ -0,0 +1,10 @@
+/* css for timepicker */
+.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
+.ui-timepicker-div dl { text-align: left; }
+.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
+.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
+.ui-timepicker-div td { font-size: 90%; }
+.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
+.ui-timepicker-rtl{ direction: rtl; }
+.ui-timepicker-rtl dl { text-align: right; }
+.ui-timepicker-rtl dl dd { margin: 0 65px 10px 10px; } \ No newline at end of file
diff --git a/libgpl/skins/larry/calendar.css b/libgpl/skins/larry/calendar.css
new file mode 100644
index 0000000..65c1ff0
--- /dev/null
+++ b/libgpl/skins/larry/calendar.css
@@ -0,0 +1,6 @@
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: 10px; top: 10px; margin: 0; z-index: 99999; width: 18px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 0; background: url(images/ui-icons_004458_256x240.png) -79px -128px no-repeat; width: 18px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close, .ui-dialog .ui-dialog-titlebar-close:focus { border: 1px solid #cccccc; background: #f8f8f8 url(images/ui-bg_highlight-hard_75_f8f8f8_1x100.png) 50% 50% repeat-x; }
+.ui-dialog .ui-dialog-titlebar-close:hover { border: 1px solid #cccccc; background: #e4e4e4 url(images/ui-bg_highlight-soft_90_e4e4e4_1x100.png) 50% 50% repeat-x; }
+.ui-dialog .ui-dialog-title { min-width: 230px; }
+.fc-event { cursor: pointer !important; }
diff --git a/libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png b/libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png
new file mode 100644
index 0000000..e228645
--- /dev/null
+++ b/libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png
Binary files differ
diff --git a/libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png b/libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png
new file mode 100644
index 0000000..675c051
--- /dev/null
+++ b/libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png
Binary files differ
diff --git a/libgpl/skins/larry/images/ui-icons_004458_256x240.png b/libgpl/skins/larry/images/ui-icons_004458_256x240.png
new file mode 100644
index 0000000..083a564
--- /dev/null
+++ b/libgpl/skins/larry/images/ui-icons_004458_256x240.png
Binary files differ
diff --git a/libgpl/skins/larry/jquery.contextMenu.css b/libgpl/skins/larry/jquery.contextMenu.css
new file mode 100644
index 0000000..7eeb275
--- /dev/null
+++ b/libgpl/skins/larry/jquery.contextMenu.css
@@ -0,0 +1,154 @@
+/*!
+ * jQuery contextMenu - Plugin for simple contextMenu handling
+ *
+ * Version: git-master
+ *
+ * Authors: Rodney Rehm, Addy Osmani (patches for FF)
+ * Web: http://medialize.github.com/jQuery-contextMenu/
+ *
+ * Licensed under
+ * MIT License http://www.opensource.org/licenses/mit-license
+ * GPL v3 http://opensource.org/licenses/GPL-3.0
+ *
+ */
+
+.context-menu-list {
+ margin:0;
+ padding:0;
+
+ min-width: 120px;
+ max-width: 250px;
+ display: inline-block;
+ position: absolute;
+ list-style-type: none;
+
+ border: 1px solid #999;
+ border-radius: 4px;
+ background: #444;
+
+ -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -ms-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -o-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+
+ font-family: "Lucida Grande",Verdana,Arial,Helvetica,sans-serif;
+ color: #fff;
+ /*text-shadow: 0 1px 1px #333;*/
+ font-size: 11px;
+}
+
+.context-menu-item {
+ padding: 6px 6px 6px 30px;
+ height: 17px;
+ background-color: #444;
+ border-bottom: 1px solid #333;
+ border-top: 1px solid #5a5a5a;
+ position: relative;
+ -webkit-user-select: none;
+ -moz-user-select: -moz-none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.context-menu-item {
+ opacity: 0.2;
+ filter: alpha(opacity=20);
+}
+
+.context-menu-item:hover {
+ opacity: 0.94;
+ filter: alpha(opacity=94);
+ background-color: #008fc7;
+}
+
+.context-menu-separator {
+ padding-bottom:0;
+ border-bottom: 1px solid #DDD;
+}
+
+.context-menu-item > label > input,
+.context-menu-item > label > textarea {
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+ user-select: text;
+}
+
+.context-menu-item.hover {
+ cursor: pointer;
+}
+
+.context-menu-item.disabled {
+ color: #666;
+}
+
+.context-menu-input.hover,
+.context-menu-item.disabled.hover {
+ cursor: default;
+ background-color: #EEE;
+}
+
+.context-menu-submenu:after {
+ content: ">";
+ color: #666;
+ position: absolute;
+ top: 0;
+ right: 3px;
+ z-index: 1;
+}
+
+.context-menu-root { min-width: 135px; white-space: nowrap; overflow: hidden; }
+
+.context-menu-item.icon { padding-right: 5px; background-image: url(../../../../skins/larry/images/listicons.png?v=017c.29530); background-repeat: no-repeat; }
+.context-menu-item.icon-message { background-position: 5px -1291px; }
+.context-menu-item.icon-task { background-position: 5px -2124px; }
+.context-menu-item.icon-note { background-position: 5px -2124px; }
+.context-menu-item.icon-event { background-position: 5px -2124px; }
+.context-menu-item.icon-edit { background-image: url(../../../../skins/larry/images/listicons.png?v=017c.29530); background-repeat: no-repeat; background-position: 5px -1388px; }
+.context-menu-item.icon-delete { background-image: url(../../../contextmenu/skins/larry/images/contexticons.png); background-repeat: no-repeat; background-position: 5px -96px; }
+
+
+/* vertically align inside labels */
+.context-menu-input > label > * { vertical-align: top; }
+
+/* position checkboxes and radios as icons */
+.context-menu-input > label > input[type="checkbox"],
+.context-menu-input > label > input[type="radio"] {
+ margin-left: -17px;
+}
+.context-menu-input > label > span {
+ margin-left: 5px;
+}
+
+.context-menu-input > label,
+.context-menu-input > label > input[type="text"],
+.context-menu-input > label > textarea,
+.context-menu-input > label > select {
+ display: block;
+ width: 100%;
+
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ -o-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.context-menu-input > label > textarea {
+ height: 100px;
+}
+.context-menu-item > .context-menu-list {
+ display: none;
+ /* re-positioned by js */
+ right: -5px;
+ top: 5px;
+}
+
+.context-menu-item.hover > .context-menu-list {
+ display: block;
+}
+
+.context-menu-accesskey {
+ text-decoration: underline;
+}
diff --git a/libgpl/skins/larry/timepicker2.css b/libgpl/skins/larry/timepicker2.css
new file mode 100644
index 0000000..150c9f3
--- /dev/null
+++ b/libgpl/skins/larry/timepicker2.css
@@ -0,0 +1,13 @@
+/* css for timepicker */
+
+.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
+.ui-timepicker-div dl { text-align: left; }
+.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
+.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
+.ui-timepicker-div td { font-size: 90%; }
+.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
+.ui-timepicker-rtl{ direction: rtl; }
+.ui-timepicker-rtl dl { text-align: right; }
+.ui-timepicker-rtl dl dd { margin: 0 65px 10px 10px; }
+.ui-slider { border: 1px solid #AAA; background: white 50% 50% repeat-x; color: black; height: 10px; }
+.ui-timepicker-div dt { margin-left: 5px; }
diff --git a/libgpl/timepicker/jquery.timepicker.css b/libgpl/timepicker/jquery.timepicker.css
new file mode 100644
index 0000000..cd75f13
--- /dev/null
+++ b/libgpl/timepicker/jquery.timepicker.css
@@ -0,0 +1,72 @@
+.ui-timepicker-wrapper {
+ overflow-y: auto;
+ height: 150px;
+ width: 6.5em;
+ background: #fff;
+ border: 1px solid #ddd;
+ -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ outline: none;
+ z-index: 10001;
+ margin: 0;
+}
+
+.ui-timepicker-wrapper.ui-timepicker-with-duration {
+ width: 13em;
+}
+
+.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30,
+.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60 {
+ width: 11em;
+}
+
+.ui-timepicker-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.ui-timepicker-duration {
+ margin-left: 5px; color: #888;
+}
+
+.ui-timepicker-list:hover .ui-timepicker-duration {
+ color: #888;
+}
+
+.ui-timepicker-list li {
+ padding: 3px 0 3px 5px;
+ cursor: pointer;
+ white-space: nowrap;
+ color: #000;
+ list-style: none;
+ margin: 0;
+}
+
+.ui-timepicker-list:hover .ui-timepicker-selected {
+ background: #fff; color: #000;
+}
+
+li.ui-timepicker-selected,
+.ui-timepicker-list li:hover,
+.ui-timepicker-list .ui-timepicker-selected:hover {
+ background: #1980EC; color: #fff;
+}
+
+li.ui-timepicker-selected .ui-timepicker-duration,
+.ui-timepicker-list li:hover .ui-timepicker-duration {
+ color: #ccc;
+}
+
+.ui-timepicker-list li.ui-timepicker-disabled,
+.ui-timepicker-list li.ui-timepicker-disabled:hover,
+.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
+ color: #888;
+ cursor: default;
+}
+
+.ui-timepicker-list li.ui-timepicker-disabled:hover,
+.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
+ background: #f2f2f2;
+}
diff --git a/libgpl/timepicker/jquery.timepicker.js b/libgpl/timepicker/jquery.timepicker.js
new file mode 100644
index 0000000..462d8fe
--- /dev/null
+++ b/libgpl/timepicker/jquery.timepicker.js
@@ -0,0 +1,1149 @@
+/************************
+jquery-timepicker v1.4.10
+http://jonthornton.github.com/jquery-timepicker/
+
+requires jQuery 1.7+
+************************/
+
+
+(function (factory) {
+ if (typeof exports === "object" && exports &&
+ typeof module === "object" && module && module.exports === exports) {
+ // Browserify. Attach to jQuery module.
+ factory(require("jquery"));
+ } else if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function ($) {
+ var _baseDate = _generateBaseDate();
+ var _ONE_DAY = 86400;
+ var _lang = {
+ am: 'am',
+ pm: 'pm',
+ AM: 'AM',
+ PM: 'PM',
+ decimal: '.',
+ mins: 'mins',
+ hr: 'hr',
+ hrs: 'hrs'
+ };
+
+ var methods =
+ {
+ init: function(options)
+ {
+ return this.each(function()
+ {
+ var self = $(this);
+
+ // pick up settings from data attributes
+ var attributeOptions = [];
+ for (var key in $.fn.timepicker.defaults) {
+ if (self.data(key)) {
+ attributeOptions[key] = self.data(key);
+ }
+ }
+
+ var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options);
+
+ if (settings.lang) {
+ _lang = $.extend(_lang, settings.lang);
+ }
+
+ settings = _parseSettings(settings);
+ self.data('timepicker-settings', settings);
+ self.addClass('ui-timepicker-input');
+
+ if (settings.useSelect) {
+ _render(self);
+ } else {
+ self.prop('autocomplete', 'off');
+ self.on('click.timepicker focus.timepicker', methods.show);
+ self.on('change.timepicker', _formatValue);
+ self.on('keydown.timepicker', _keydownhandler);
+ self.on('keyup.timepicker', _keyuphandler);
+
+ _formatValue.call(self.get(0));
+ }
+ });
+ },
+
+ show: function(e)
+ {
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+
+ if (e) {
+ if (!settings.showOnFocus) {
+ return true;
+ }
+
+ e.preventDefault();
+ }
+
+ if (settings.useSelect) {
+ self.data('timepicker-list').focus();
+ return;
+ }
+
+ if (_hideKeyboard(self)) {
+ // block the keyboard on mobile devices
+ self.blur();
+ }
+
+ var list = self.data('timepicker-list');
+
+ // check if input is readonly
+ if (self.prop('readonly')) {
+ return;
+ }
+
+ // check if list needs to be rendered
+ if (!list || list.length === 0 || typeof settings.durationTime === 'function') {
+ _render(self);
+ list = self.data('timepicker-list');
+ }
+
+ if (_isVisible(list)) {
+ return;
+ }
+
+ // make sure other pickers are hidden
+ methods.hide();
+
+ // position the dropdown relative to the input
+ list.show();
+ var listOffset = {};
+
+ if (settings.orientation == 'rtl') {
+ // right-align the dropdown
+ listOffset.left = self.offset().left + self.outerWidth() - list.outerWidth() + parseInt(list.css('marginLeft').replace('px', ''), 10);
+ } else {
+ // left-align the dropdown
+ listOffset.left = self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10);
+ }
+
+ if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) {
+ // position the dropdown on top
+ listOffset.top = self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
+ } else {
+ // put it under the input
+ listOffset.top = self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
+ }
+
+ list.offset(listOffset);
+
+ // position scrolling
+ var selected = list.find('.ui-timepicker-selected');
+
+ if (!selected.length) {
+ if (_getTimeValue(self)) {
+ selected = _findRow(self, list, _time2int(_getTimeValue(self)));
+ } else if (settings.scrollDefault) {
+ selected = _findRow(self, list, settings.scrollDefault);
+ }
+ }
+
+ if (selected && selected.length) {
+ var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight();
+ list.scrollTop(topOffset);
+ } else {
+ list.scrollTop(0);
+ }
+
+ // attach close handlers
+ $(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler);
+ if (settings.closeOnWindowScroll) {
+ $(document).on('scroll.ui-timepicker', _closeHandler);
+ }
+
+ self.trigger('showTimepicker');
+
+ return this;
+ },
+
+ hide: function(e)
+ {
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+
+ if (settings && settings.useSelect) {
+ self.blur();
+ }
+
+ $('.ui-timepicker-wrapper').each(function() {
+ var list = $(this);
+ if (!_isVisible(list)) {
+ return;
+ }
+
+ var self = list.data('timepicker-input');
+ var settings = self.data('timepicker-settings');
+
+ if (settings && settings.selectOnBlur) {
+ _selectValue(self);
+ }
+
+ list.hide();
+ self.trigger('hideTimepicker');
+ });
+
+ return this;
+ },
+
+ option: function(key, value)
+ {
+ return this.each(function(){
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+ var list = self.data('timepicker-list');
+
+ if (typeof key == 'object') {
+ settings = $.extend(settings, key);
+
+ } else if (typeof key == 'string' && typeof value != 'undefined') {
+ settings[key] = value;
+
+ } else if (typeof key == 'string') {
+ return settings[key];
+ }
+
+ settings = _parseSettings(settings);
+
+ self.data('timepicker-settings', settings);
+
+ if (list) {
+ list.remove();
+ self.data('timepicker-list', false);
+ }
+
+ if (settings.useSelect) {
+ _render(self);
+ }
+ });
+ },
+
+ getSecondsFromMidnight: function()
+ {
+ return _time2int(_getTimeValue(this));
+ },
+
+ getTime: function(relative_date)
+ {
+ var self = this;
+
+ var time_string = _getTimeValue(self);
+ if (!time_string) {
+ return null;
+ }
+
+ if (!relative_date) {
+ relative_date = new Date();
+ }
+ var offset = _time2int(time_string);
+
+ // construct a Date with today's date, and offset's time
+ var time = new Date(relative_date);
+ time.setHours(offset / 3600);
+ time.setMinutes(offset % 3600 / 60);
+ time.setSeconds(offset % 60);
+ time.setMilliseconds(0);
+
+ return time;
+ },
+
+ setTime: function(value)
+ {
+ var self = this;
+ var settings = self.data('timepicker-settings');
+
+ if (settings.forceRoundTime) {
+ var prettyTime = _roundAndFormatTime(value, settings)
+ } else {
+ var prettyTime = _int2time(_time2int(value), settings.timeFormat);
+ }
+
+ _setTimeValue(self, prettyTime);
+ if (self.data('timepicker-list')) {
+ _setSelected(self, self.data('timepicker-list'));
+ }
+
+ return this;
+ },
+
+ remove: function()
+ {
+ var self = this;
+
+ // check if this element is a timepicker
+ if (!self.hasClass('ui-timepicker-input')) {
+ return;
+ }
+
+ var settings = self.data('timepicker-settings');
+ self.removeAttr('autocomplete', 'off');
+ self.removeClass('ui-timepicker-input');
+ self.removeData('timepicker-settings');
+ self.off('.timepicker');
+
+ // timepicker-list won't be present unless the user has interacted with this timepicker
+ if (self.data('timepicker-list')) {
+ self.data('timepicker-list').remove();
+ }
+
+ if (settings.useSelect) {
+ self.show();
+ }
+
+ self.removeData('timepicker-list');
+
+ return this;
+ }
+ };
+
+ // private methods
+
+ function _isVisible(elem)
+ {
+ var el = elem[0];
+ return el.offsetWidth > 0 && el.offsetHeight > 0;
+ }
+
+ function _parseSettings(settings)
+ {
+ if (settings.minTime) {
+ settings.minTime = _time2int(settings.minTime);
+ }
+
+ if (settings.maxTime) {
+ settings.maxTime = _time2int(settings.maxTime);
+ }
+
+ if (settings.durationTime && typeof settings.durationTime !== 'function') {
+ settings.durationTime = _time2int(settings.durationTime);
+ }
+
+ if (settings.scrollDefault == 'now') {
+ settings.scrollDefault = _time2int(new Date());
+ } else if (settings.scrollDefault) {
+ settings.scrollDefault = _time2int(settings.scrollDefault);
+ } else if (settings.minTime) {
+ settings.scrollDefault = settings.minTime;
+ }
+
+ if (settings.scrollDefault) {
+ settings.scrollDefault = _roundTime(settings.scrollDefault, settings);
+ }
+
+ if ($.type(settings.timeFormat) === "string" && settings.timeFormat.match(/[gh]/)) {
+ settings._twelveHourTime = true;
+ }
+
+ if (settings.disableTimeRanges.length > 0) {
+ // convert string times to integers
+ for (var i in settings.disableTimeRanges) {
+ settings.disableTimeRanges[i] = [
+ _time2int(settings.disableTimeRanges[i][0]),
+ _time2int(settings.disableTimeRanges[i][1])
+ ];
+ }
+
+ // sort by starting time
+ settings.disableTimeRanges = settings.disableTimeRanges.sort(function(a, b){
+ return a[0] - b[0];
+ });
+
+ // merge any overlapping ranges
+ for (var i = settings.disableTimeRanges.length-1; i > 0; i--) {
+ if (settings.disableTimeRanges[i][0] <= settings.disableTimeRanges[i-1][1]) {
+ settings.disableTimeRanges[i-1] = [
+ Math.min(settings.disableTimeRanges[i][0], settings.disableTimeRanges[i-1][0]),
+ Math.max(settings.disableTimeRanges[i][1], settings.disableTimeRanges[i-1][1])
+ ];
+ settings.disableTimeRanges.splice(i, 1);
+ }
+ }
+ }
+
+ return settings;
+ }
+
+ function _render(self)
+ {
+ var settings = self.data('timepicker-settings');
+ var list = self.data('timepicker-list');
+
+ if (list && list.length) {
+ list.remove();
+ self.data('timepicker-list', false);
+ }
+
+ if (settings.useSelect) {
+ list = $('<select />', { 'class': 'ui-timepicker-select' });
+ var wrapped_list = list;
+ } else {
+ list = $('<ul />', { 'class': 'ui-timepicker-list' });
+
+ var wrapped_list = $('<div />', { 'class': 'ui-timepicker-wrapper', 'tabindex': -1 });
+ wrapped_list.css({'display':'none', 'position': 'absolute' }).append(list);
+ }
+
+ if (settings.noneOption) {
+ if (settings.noneOption === true) {
+ settings.noneOption = (settings.useSelect) ? 'Time...' : 'None';
+ }
+
+ if ($.isArray(settings.noneOption)) {
+ for (var i in settings.noneOption) {
+ if (parseInt(i, 10) == i){
+ var noneElement = _generateNoneElement(settings.noneOption[i], settings.useSelect);
+ list.append(noneElement);
+ }
+ }
+ } else {
+ var noneElement = _generateNoneElement(settings.noneOption, settings.useSelect);
+ list.append(noneElement);
+ }
+ }
+
+ if (settings.className) {
+ wrapped_list.addClass(settings.className);
+ }
+
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
+ wrapped_list.addClass('ui-timepicker-with-duration');
+ wrapped_list.addClass('ui-timepicker-step-'+settings.step);
+ }
+
+ var durStart = settings.minTime;
+ if (typeof settings.durationTime === 'function') {
+ durStart = _time2int(settings.durationTime());
+ } else if (settings.durationTime !== null) {
+ durStart = settings.durationTime;
+ }
+ var start = (settings.minTime !== null) ? settings.minTime : 0;
+ var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1);
+
+ if (end <= start) {
+ // make sure the end time is greater than start time, otherwise there will be no list to show
+ end += _ONE_DAY;
+ }
+
+ if (end === _ONE_DAY-1 && $.type(settings.timeFormat) === "string" && settings.timeFormat.indexOf('H') !== -1) {
+ // show a 24:00 option when using military time
+ end = _ONE_DAY;
+ }
+
+ var dr = settings.disableTimeRanges;
+ var drCur = 0;
+ var drLen = dr.length;
+
+ for (var i=start; i <= end; i += settings.step*60) {
+ var timeInt = i;
+ var timeString = _int2time(timeInt, settings.timeFormat);
+
+ if (settings.useSelect) {
+ var row = $('<option />', { 'value': timeString });
+ row.text(timeString);
+ } else {
+ var row = $('<li />');
+ row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400));
+ row.text(timeString);
+ }
+
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
+ var durationString = _int2duration(i - durStart, settings.step);
+ if (settings.useSelect) {
+ row.text(row.text()+' ('+durationString+')');
+ } else {
+ var duration = $('<span />', { 'class': 'ui-timepicker-duration' });
+ duration.text(' ('+durationString+')');
+ row.append(duration);
+ }
+ }
+
+ if (drCur < drLen) {
+ if (timeInt >= dr[drCur][1]) {
+ drCur += 1;
+ }
+
+ if (dr[drCur] && timeInt >= dr[drCur][0] && timeInt < dr[drCur][1]) {
+ if (settings.useSelect) {
+ row.prop('disabled', true);
+ } else {
+ row.addClass('ui-timepicker-disabled');
+ }
+ }
+ }
+
+ list.append(row);
+ }
+
+ wrapped_list.data('timepicker-input', self);
+ self.data('timepicker-list', wrapped_list);
+
+ if (settings.useSelect) {
+ if (self.val()) {
+ list.val(_roundAndFormatTime(self.val(), settings));
+ }
+
+ list.on('focus', function(){
+ $(this).data('timepicker-input').trigger('showTimepicker');
+ });
+ list.on('blur', function(){
+ $(this).data('timepicker-input').trigger('hideTimepicker');
+ });
+ list.on('change', function(){
+ _setTimeValue(self, $(this).val(), 'select');
+ });
+
+ _setTimeValue(self, list.val());
+ self.hide().after(list);
+ } else {
+ var appendTo = settings.appendTo;
+ if (typeof appendTo === 'string') {
+ appendTo = $(appendTo);
+ } else if (typeof appendTo === 'function') {
+ appendTo = appendTo(self);
+ }
+ appendTo.append(wrapped_list);
+ _setSelected(self, list);
+
+ list.on('mousedown', 'li', function(e) {
+
+ // hack: temporarily disable the focus handler
+ // to deal with the fact that IE fires 'focus'
+ // events asynchronously
+ self.off('focus.timepicker');
+ self.on('focus.timepicker-ie-hack', function(){
+ self.off('focus.timepicker-ie-hack');
+ self.on('focus.timepicker', methods.show);
+ });
+
+ if (!_hideKeyboard(self)) {
+ self[0].focus();
+ }
+
+ // make sure only the clicked row is selected
+ list.find('li').removeClass('ui-timepicker-selected');
+ $(this).addClass('ui-timepicker-selected');
+
+ if (_selectValue(self)) {
+ self.trigger('hideTimepicker');
+ wrapped_list.hide();
+ }
+ });
+ }
+ }
+
+ function _generateNoneElement(optionValue, useSelect)
+ {
+ var label, className, value;
+
+ if (typeof optionValue == 'object') {
+ label = optionValue.label;
+ className = optionValue.className;
+ value = optionValue.value;
+ } else if (typeof optionValue == 'string') {
+ label = optionValue;
+ } else {
+ $.error('Invalid noneOption value');
+ }
+
+ if (useSelect) {
+ return $('<option />', {
+ 'value': value,
+ 'class': className,
+ 'text': label
+ });
+ } else {
+ return $('<li />', {
+ 'class': className,
+ 'text': label
+ }).data('time', value);
+ }
+ }
+
+ function _roundTime(seconds, settings)
+ {
+ if (!$.isNumeric(seconds)) {
+ seconds = _time2int(seconds);
+ }
+
+ if (seconds === null) {
+ return null;
+ } else {
+ var offset = seconds % (settings.step*60); // step is in minutes
+
+ if (offset >= settings.step*30) {
+ // if offset is larger than a half step, round up
+ seconds += (settings.step*60) - offset;
+ } else {
+ // round down
+ seconds -= offset;
+ }
+
+ return seconds;
+ }
+ }
+
+ function _roundAndFormatTime(seconds, settings)
+ {
+ seconds = _roundTime(seconds, settings);
+ if (seconds !== null) {
+ return _int2time(seconds, settings.timeFormat);
+ }
+ }
+
+ function _generateBaseDate()
+ {
+ return new Date(1970, 1, 1, 0, 0, 0);
+ }
+
+ // event handler to decide whether to close timepicker
+ function _closeHandler(e)
+ {
+ var target = $(e.target);
+ var input = target.closest('.ui-timepicker-input');
+ if (input.length === 0 && target.closest('.ui-timepicker-wrapper').length === 0) {
+ methods.hide();
+ $(document).unbind('.ui-timepicker');
+ }
+ }
+
+ function _hideKeyboard(self)
+ {
+ var settings = self.data('timepicker-settings');
+ return ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && settings.disableTouchKeyboard);
+ }
+
+ function _findRow(self, list, value)
+ {
+ if (!value && value !== 0) {
+ return false;
+ }
+
+ var settings = self.data('timepicker-settings');
+ var out = false;
+ var halfStep = settings.step*30;
+
+ // loop through the menu items
+ list.find('li').each(function(i, obj) {
+ var jObj = $(obj);
+ if (typeof jObj.data('time') != 'number') {
+ return;
+ }
+
+ var offset = jObj.data('time') - value;
+
+ // check if the value is less than half a step from each row
+ if (Math.abs(offset) < halfStep || offset == halfStep) {
+ out = jObj;
+ return false;
+ }
+ });
+
+ return out;
+ }
+
+ function _setSelected(self, list)
+ {
+ list.find('li').removeClass('ui-timepicker-selected');
+
+ var timeValue = _time2int(_getTimeValue(self), self.data('timepicker-settings'));
+ if (timeValue === null) {
+ return;
+ }
+
+ var selected = _findRow(self, list, timeValue);
+ if (selected) {
+
+ var topDelta = selected.offset().top - list.offset().top;
+
+ if (topDelta + selected.outerHeight() > list.outerHeight() || topDelta < 0) {
+ list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight());
+ }
+
+ selected.addClass('ui-timepicker-selected');
+ }
+ }
+
+
+ function _formatValue(e)
+ {
+ if (this.value === '') {
+ return;
+ }
+
+ var self = $(this);
+ var list = self.data('timepicker-list');
+
+ if (self.is(':focus') && (!e || e.type != 'change')) {
+ return;
+ }
+
+ var seconds = _time2int(this.value);
+
+ if (seconds === null) {
+ self.trigger('timeFormatError');
+ return;
+ }
+
+ var settings = self.data('timepicker-settings');
+ var rangeError = false;
+ // check that the time in within bounds
+ if (settings.minTime !== null && seconds < settings.minTime) {
+ rangeError = true;
+ } else if (settings.maxTime !== null && seconds > settings.maxTime) {
+ rangeError = true;
+ }
+
+ // check that time isn't within disabled time ranges
+ $.each(settings.disableTimeRanges, function(){
+ if (seconds >= this[0] && seconds < this[1]) {
+ rangeError = true;
+ return false;
+ }
+ });
+
+ if (settings.forceRoundTime) {
+ var offset = seconds % (settings.step*60); // step is in minutes
+
+ if (offset >= settings.step*30) {
+ // if offset is larger than a half step, round up
+ seconds += (settings.step*60) - offset;
+ } else {
+ // round down
+ seconds -= offset;
+ }
+ }
+
+ var prettyTime = _int2time(seconds, settings.timeFormat);
+
+ if (rangeError) {
+ if (_setTimeValue(self, prettyTime, 'error')) {
+ self.trigger('timeRangeError');
+ }
+ } else {
+ _setTimeValue(self, prettyTime);
+ }
+ }
+
+ function _getTimeValue(self)
+ {
+ if (self.is('input')) {
+ return self.val();
+ } else {
+ // use the element's data attributes to store values
+ return self.data('ui-timepicker-value');
+ }
+ }
+
+ function _setTimeValue(self, value, source)
+ {
+ if (self.is('input')) {
+ self.val(value);
+
+ var settings = self.data('timepicker-settings');
+ if (settings.useSelect) {
+ self.data('timepicker-list').val(_roundAndFormatTime(value, settings));
+ }
+ }
+
+ if (self.data('ui-timepicker-value') != value) {
+ self.data('ui-timepicker-value', value);
+ if (source == 'select') {
+ self.trigger('selectTime').trigger('changeTime').trigger('change');
+ } else if (source != 'error') {
+ self.trigger('changeTime');
+ }
+
+ return true;
+ } else {
+ self.trigger('selectTime');
+ return false;
+ }
+ }
+
+ /*
+ * Keyboard navigation via arrow keys
+ */
+ function _keydownhandler(e)
+ {
+ var self = $(this);
+ var list = self.data('timepicker-list');
+
+ if (!list || !_isVisible(list)) {
+ if (e.keyCode == 40) {
+ // show the list!
+ methods.show.call(self.get(0));
+ list = self.data('timepicker-list');
+ if (!_hideKeyboard(self)) {
+ self.focus();
+ }
+ } else {
+ return true;
+ }
+ }
+
+ switch (e.keyCode) {
+
+ case 13: // return
+ if (_selectValue(self)) {
+ methods.hide.apply(this);
+ }
+
+ e.preventDefault();
+ return false;
+
+ case 38: // up
+ var selected = list.find('.ui-timepicker-selected');
+
+ if (!selected.length) {
+ list.find('li').each(function(i, obj) {
+ if ($(obj).position().top > 0) {
+ selected = $(obj);
+ return false;
+ }
+ });
+ selected.addClass('ui-timepicker-selected');
+
+ } else if (!selected.is(':first-child')) {
+ selected.removeClass('ui-timepicker-selected');
+ selected.prev().addClass('ui-timepicker-selected');
+
+ if (selected.prev().position().top < selected.outerHeight()) {
+ list.scrollTop(list.scrollTop() - selected.outerHeight());
+ }
+ }
+
+ return false;
+
+ case 40: // down
+ selected = list.find('.ui-timepicker-selected');
+
+ if (selected.length === 0) {
+ list.find('li').each(function(i, obj) {
+ if ($(obj).position().top > 0) {
+ selected = $(obj);
+ return false;
+ }
+ });
+
+ selected.addClass('ui-timepicker-selected');
+ } else if (!selected.is(':last-child')) {
+ selected.removeClass('ui-timepicker-selected');
+ selected.next().addClass('ui-timepicker-selected');
+
+ if (selected.next().position().top + 2*selected.outerHeight() > list.outerHeight()) {
+ list.scrollTop(list.scrollTop() + selected.outerHeight());
+ }
+ }
+
+ return false;
+
+ case 27: // escape
+ list.find('li').removeClass('ui-timepicker-selected');
+ methods.hide();
+ break;
+
+ case 9: //tab
+ methods.hide();
+ break;
+
+ default:
+ return true;
+ }
+ }
+
+ /*
+ * Time typeahead
+ */
+ function _keyuphandler(e)
+ {
+ var self = $(this);
+ var list = self.data('timepicker-list');
+
+ if (!list || !_isVisible(list)) {
+ return true;
+ }
+
+ if (!self.data('timepicker-settings').typeaheadHighlight) {
+ list.find('li').removeClass('ui-timepicker-selected');
+ return true;
+ }
+
+ switch (e.keyCode) {
+
+ case 96: // numpad numerals
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 48: // numerals
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 65: // a
+ case 77: // m
+ case 80: // p
+ case 186: // colon
+ case 8: // backspace
+ case 46: // delete
+ _setSelected(self, list);
+ break;
+
+ default:
+ // list.find('li').removeClass('ui-timepicker-selected');
+ return;
+ }
+ }
+
+ function _selectValue(self)
+ {
+ var settings = self.data('timepicker-settings');
+ var list = self.data('timepicker-list');
+ var timeValue = null;
+
+ var cursor = list.find('.ui-timepicker-selected');
+
+ if (cursor.hasClass('ui-timepicker-disabled')) {
+ return false;
+ }
+
+ if (cursor.length) {
+ // selected value found
+ timeValue = cursor.data('time');
+ }
+
+ if (timeValue !== null) {
+ if (typeof timeValue == 'string') {
+ self.val(timeValue);
+ } else {
+ var timeString = _int2time(timeValue, settings.timeFormat);
+ _setTimeValue(self, timeString, 'select');
+ }
+ }
+
+ //self.trigger('change').trigger('selectTime');
+ return true;
+ }
+
+ function _int2duration(seconds, step)
+ {
+ seconds = Math.abs(seconds);
+ var minutes = Math.round(seconds/60),
+ duration = [],
+ hours, mins;
+
+ if (minutes < 60) {
+ // Only show (x mins) under 1 hour
+ duration = [minutes, _lang.mins];
+ } else {
+ hours = Math.floor(minutes/60);
+ mins = minutes%60;
+
+ // Show decimal notation (eg: 1.5 hrs) for 30 minute steps
+ if (step == 30 && mins == 30) {
+ hours += _lang.decimal + 5;
+ }
+
+ duration.push(hours);
+ duration.push(hours == 1 ? _lang.hr : _lang.hrs);
+
+ // Show remainder minutes notation (eg: 1 hr 15 mins) for non-30 minute steps
+ // and only if there are remainder minutes to show
+ if (step != 30 && mins) {
+ duration.push(mins);
+ duration.push(_lang.mins);
+ }
+ }
+
+ return duration.join(' ');
+ }
+
+ function _int2time(seconds, format)
+ {
+ if (seconds === null) {
+ return;
+ }
+
+ var time = new Date(_baseDate.valueOf() + (seconds*1000));
+
+ if (isNaN(time.getTime())) {
+ return;
+ }
+
+ if ($.type(format) === "function") {
+ return format(time);
+ }
+
+ var output = '';
+ var hour, code;
+ for (var i=0; i<format.length; i++) {
+
+ code = format.charAt(i);
+ switch (code) {
+
+ case 'a':
+ output += (time.getHours() > 11) ? _lang.pm : _lang.am;
+ break;
+
+ case 'A':
+ output += (time.getHours() > 11) ? _lang.pm.toUpperCase() : _lang.am.toUpperCase();
+ break;
+
+ case 'g':
+ hour = time.getHours() % 12;
+ output += (hour === 0) ? '12' : hour;
+ break;
+
+ case 'G':
+ output += time.getHours();
+ break;
+
+ case 'h':
+ hour = time.getHours() % 12;
+
+ if (hour !== 0 && hour < 10) {
+ hour = '0'+hour;
+ }
+
+ output += (hour === 0) ? '12' : hour;
+ break;
+
+ case 'H':
+ hour = time.getHours();
+ if (seconds === _ONE_DAY) hour = 24;
+ output += (hour > 9) ? hour : '0'+hour;
+ break;
+
+ case 'i':
+ var minutes = time.getMinutes();
+ output += (minutes > 9) ? minutes : '0'+minutes;
+ break;
+
+ case 's':
+ seconds = time.getSeconds();
+ output += (seconds > 9) ? seconds : '0'+seconds;
+ break;
+
+ case '\\':
+ // escape character; add the next character and skip ahead
+ i++;
+ output += format.charAt(i);
+ break;
+
+ default:
+ output += code;
+ }
+ }
+
+ return output;
+ }
+
+ function _time2int(timeString, settings)
+ {
+ if (timeString === '') return null;
+ if (!timeString || timeString+0 == timeString) return timeString;
+
+ if (typeof(timeString) == 'object') {
+ return timeString.getHours()*3600 + timeString.getMinutes()*60 + timeString.getSeconds();
+ }
+
+ timeString = timeString.toLowerCase();
+
+ // if the last character is an "a" or "p", add the "m"
+ if (timeString.slice(-1) == 'a' || timeString.slice(-1) == 'p') {
+ timeString += 'm';
+ }
+
+ // try to parse time input
+ var pattern = new RegExp('^([0-2]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?\\s*('+_lang.am+'|'+_lang.pm+')?$');
+ var time = timeString.match(pattern);
+ if (!time) {
+ return null;
+ }
+
+ var hour = parseInt(time[1]*1, 10);
+ var ampm = time[4];
+ var hours = hour;
+
+ if (hour <= 12 && ampm) {
+ if (hour == 12) {
+ hours = (time[4] == _lang.pm) ? 12 : 0;
+ } else {
+ hours = (hour + (time[4] == _lang.pm ? 12 : 0));
+ }
+ }
+
+ var minutes = ( time[2]*1 || 0 );
+ var seconds = ( time[3]*1 || 0 );
+ var timeInt = hours*3600 + minutes*60 + seconds;
+
+ // if no am/pm provided, intelligently guess based on the scrollDefault
+ if (!ampm && settings && settings._twelveHourTime && settings.scrollDefault) {
+ var delta = timeInt - settings.scrollDefault;
+ if (delta < 0 && delta >= _ONE_DAY / -2) {
+ timeInt = (timeInt + (_ONE_DAY / 2)) % _ONE_DAY;
+ }
+ }
+
+ return timeInt
+ }
+
+ function _pad2(n) {
+ return ("0" + n).slice(-2);
+ }
+
+ // Plugin entry
+ $.fn.timepicker = function(method)
+ {
+ if (!this.length) return this;
+ if (methods[method]) {
+ // check if this element is a timepicker
+ if (!this.hasClass('ui-timepicker-input')) {
+ return this;
+ }
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ }
+ else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
+ else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
+ };
+ // Global defaults
+ $.fn.timepicker.defaults = {
+ className: null,
+ minTime: null,
+ maxTime: null,
+ durationTime: null,
+ step: 30,
+ showDuration: false,
+ showOnFocus: true,
+ timeFormat: 'g:ia',
+ scrollDefault: null,
+ selectOnBlur: false,
+ disableTouchKeyboard: false,
+ forceRoundTime: false,
+ appendTo: 'body',
+ orientation: 'ltr',
+ disableTimeRanges: [],
+ closeOnWindowScroll: false,
+ typeaheadHighlight: true,
+ noneOption: false
+ };
+}));
diff --git a/libgpl/timepicker/jquery.timepicker.min.js b/libgpl/timepicker/jquery.timepicker.min.js
new file mode 100644
index 0000000..04daf60
--- /dev/null
+++ b/libgpl/timepicker/jquery.timepicker.min.js
@@ -0,0 +1,7 @@
+/*!
+ * jquery-timepicker v1.4.10 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.
+ * Copyright (c) 2014 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/
+ * License:
+ */
+
+!function(a){"object"==typeof exports&&exports&&"object"==typeof module&&module&&module.exports===exports?a(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){function b(a){var b=a[0];return b.offsetWidth>0&&b.offsetHeight>0}function c(b){if(b.minTime&&(b.minTime=u(b.minTime)),b.maxTime&&(b.maxTime=u(b.maxTime)),b.durationTime&&"function"!=typeof b.durationTime&&(b.durationTime=u(b.durationTime)),"now"==b.scrollDefault?b.scrollDefault=u(new Date):b.scrollDefault?b.scrollDefault=u(b.scrollDefault):b.minTime&&(b.scrollDefault=b.minTime),b.scrollDefault&&(b.scrollDefault=f(b.scrollDefault,b)),"string"===a.type(b.timeFormat)&&b.timeFormat.match(/[gh]/)&&(b._twelveHourTime=!0),b.disableTimeRanges.length>0){for(var c in b.disableTimeRanges)b.disableTimeRanges[c]=[u(b.disableTimeRanges[c][0]),u(b.disableTimeRanges[c][1])];b.disableTimeRanges=b.disableTimeRanges.sort(function(a,b){return a[0]-b[0]});for(var c=b.disableTimeRanges.length-1;c>0;c--)b.disableTimeRanges[c][0]<=b.disableTimeRanges[c-1][1]&&(b.disableTimeRanges[c-1]=[Math.min(b.disableTimeRanges[c][0],b.disableTimeRanges[c-1][0]),Math.max(b.disableTimeRanges[c][1],b.disableTimeRanges[c-1][1])],b.disableTimeRanges.splice(c,1))}return b}function d(b){var c=b.data("timepicker-settings"),d=b.data("timepicker-list");if(d&&d.length&&(d.remove(),b.data("timepicker-list",!1)),c.useSelect){d=a("<select />",{"class":"ui-timepicker-select"});var f=d}else{d=a("<ul />",{"class":"ui-timepicker-list"});var f=a("<div />",{"class":"ui-timepicker-wrapper",tabindex:-1});f.css({display:"none",position:"absolute"}).append(d)}if(c.noneOption)if(c.noneOption===!0&&(c.noneOption=c.useSelect?"Time...":"None"),a.isArray(c.noneOption)){for(var h in c.noneOption)if(parseInt(h,10)==h){var i=e(c.noneOption[h],c.useSelect);d.append(i)}}else{var i=e(c.noneOption,c.useSelect);d.append(i)}c.className&&f.addClass(c.className),null===c.minTime&&null===c.durationTime||!c.showDuration||(f.addClass("ui-timepicker-with-duration"),f.addClass("ui-timepicker-step-"+c.step));var k=c.minTime;"function"==typeof c.durationTime?k=u(c.durationTime()):null!==c.durationTime&&(k=c.durationTime);var m=null!==c.minTime?c.minTime:0,n=null!==c.maxTime?c.maxTime:m+w-1;m>=n&&(n+=w),n===w-1&&"string"===a.type(c.timeFormat)&&-1!==c.timeFormat.indexOf("H")&&(n=w);for(var p=c.disableTimeRanges,q=0,v=p.length,h=m;n>=h;h+=60*c.step){var x=h,z=t(x,c.timeFormat);if(c.useSelect){var A=a("<option />",{value:z});A.text(z)}else{var A=a("<li />");A.data("time",86400>=x?x:x%86400),A.text(z)}if((null!==c.minTime||null!==c.durationTime)&&c.showDuration){var B=s(h-k,c.step);if(c.useSelect)A.text(A.text()+" ("+B+")");else{var C=a("<span />",{"class":"ui-timepicker-duration"});C.text(" ("+B+")"),A.append(C)}}v>q&&(x>=p[q][1]&&(q+=1),p[q]&&x>=p[q][0]&&x<p[q][1]&&(c.useSelect?A.prop("disabled",!0):A.addClass("ui-timepicker-disabled"))),d.append(A)}if(f.data("timepicker-input",b),b.data("timepicker-list",f),c.useSelect)b.val()&&d.val(g(b.val(),c)),d.on("focus",function(){a(this).data("timepicker-input").trigger("showTimepicker")}),d.on("blur",function(){a(this).data("timepicker-input").trigger("hideTimepicker")}),d.on("change",function(){o(b,a(this).val(),"select")}),o(b,d.val()),b.hide().after(d);else{var D=c.appendTo;"string"==typeof D?D=a(D):"function"==typeof D&&(D=D(b)),D.append(f),l(b,d),d.on("mousedown","li",function(){b.off("focus.timepicker"),b.on("focus.timepicker-ie-hack",function(){b.off("focus.timepicker-ie-hack"),b.on("focus.timepicker",y.show)}),j(b)||b[0].focus(),d.find("li").removeClass("ui-timepicker-selected"),a(this).addClass("ui-timepicker-selected"),r(b)&&(b.trigger("hideTimepicker"),f.hide())})}}function e(b,c){var d,e,f;return"object"==typeof b?(d=b.label,e=b.className,f=b.value):"string"==typeof b?d=b:a.error("Invalid noneOption value"),c?a("<option />",{value:f,"class":e,text:d}):a("<li />",{"class":e,text:d}).data("time",f)}function f(b,c){if(a.isNumeric(b)||(b=u(b)),null===b)return null;var d=b%(60*c.step);return d>=30*c.step?b+=60*c.step-d:b-=d,b}function g(a,b){return a=f(a,b),null!==a?t(a,b.timeFormat):void 0}function h(){return new Date(1970,1,1,0,0,0)}function i(b){var c=a(b.target),d=c.closest(".ui-timepicker-input");0===d.length&&0===c.closest(".ui-timepicker-wrapper").length&&(y.hide(),a(document).unbind(".ui-timepicker"))}function j(a){var b=a.data("timepicker-settings");return(window.navigator.msMaxTouchPoints||"ontouchstart"in document)&&b.disableTouchKeyboard}function k(b,c,d){if(!d&&0!==d)return!1;var e=b.data("timepicker-settings"),f=!1,g=30*e.step;return c.find("li").each(function(b,c){var e=a(c);if("number"==typeof e.data("time")){var h=e.data("time")-d;return Math.abs(h)<g||h==g?(f=e,!1):void 0}}),f}function l(a,b){b.find("li").removeClass("ui-timepicker-selected");var c=u(n(a),a.data("timepicker-settings"));if(null!==c){var d=k(a,b,c);if(d){var e=d.offset().top-b.offset().top;(e+d.outerHeight()>b.outerHeight()||0>e)&&b.scrollTop(b.scrollTop()+d.position().top-d.outerHeight()),d.addClass("ui-timepicker-selected")}}}function m(b){if(""!==this.value){var c=a(this);if(c.data("timepicker-list"),!c.is(":focus")||b&&"change"==b.type){var d=u(this.value);if(null===d)return c.trigger("timeFormatError"),void 0;var e=c.data("timepicker-settings"),f=!1;if(null!==e.minTime&&d<e.minTime?f=!0:null!==e.maxTime&&d>e.maxTime&&(f=!0),a.each(e.disableTimeRanges,function(){return d>=this[0]&&d<this[1]?(f=!0,!1):void 0}),e.forceRoundTime){var g=d%(60*e.step);g>=30*e.step?d+=60*e.step-g:d-=g}var h=t(d,e.timeFormat);f?o(c,h,"error")&&c.trigger("timeRangeError"):o(c,h)}}}function n(a){return a.is("input")?a.val():a.data("ui-timepicker-value")}function o(a,b,c){if(a.is("input")){a.val(b);var d=a.data("timepicker-settings");d.useSelect&&a.data("timepicker-list").val(g(b,d))}return a.data("ui-timepicker-value")!=b?(a.data("ui-timepicker-value",b),"select"==c?a.trigger("selectTime").trigger("changeTime").trigger("change"):"error"!=c&&a.trigger("changeTime"),!0):(a.trigger("selectTime"),!1)}function p(c){var d=a(this),e=d.data("timepicker-list");if(!e||!b(e)){if(40!=c.keyCode)return!0;y.show.call(d.get(0)),e=d.data("timepicker-list"),j(d)||d.focus()}switch(c.keyCode){case 13:return r(d)&&y.hide.apply(this),c.preventDefault(),!1;case 38:var f=e.find(".ui-timepicker-selected");return f.length?f.is(":first-child")||(f.removeClass("ui-timepicker-selected"),f.prev().addClass("ui-timepicker-selected"),f.prev().position().top<f.outerHeight()&&e.scrollTop(e.scrollTop()-f.outerHeight())):(e.find("li").each(function(b,c){return a(c).position().top>0?(f=a(c),!1):void 0}),f.addClass("ui-timepicker-selected")),!1;case 40:return f=e.find(".ui-timepicker-selected"),0===f.length?(e.find("li").each(function(b,c){return a(c).position().top>0?(f=a(c),!1):void 0}),f.addClass("ui-timepicker-selected")):f.is(":last-child")||(f.removeClass("ui-timepicker-selected"),f.next().addClass("ui-timepicker-selected"),f.next().position().top+2*f.outerHeight()>e.outerHeight()&&e.scrollTop(e.scrollTop()+f.outerHeight())),!1;case 27:e.find("li").removeClass("ui-timepicker-selected"),y.hide();break;case 9:y.hide();break;default:return!0}}function q(c){var d=a(this),e=d.data("timepicker-list");if(!e||!b(e))return!0;if(!d.data("timepicker-settings").typeaheadHighlight)return e.find("li").removeClass("ui-timepicker-selected"),!0;switch(c.keyCode){case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 65:case 77:case 80:case 186:case 8:case 46:l(d,e);break;default:return}}function r(a){var b=a.data("timepicker-settings"),c=a.data("timepicker-list"),d=null,e=c.find(".ui-timepicker-selected");if(e.hasClass("ui-timepicker-disabled"))return!1;if(e.length&&(d=e.data("time")),null!==d)if("string"==typeof d)a.val(d);else{var f=t(d,b.timeFormat);o(a,f,"select")}return!0}function s(a,b){a=Math.abs(a);var c,d,e=Math.round(a/60),f=[];return 60>e?f=[e,x.mins]:(c=Math.floor(e/60),d=e%60,30==b&&30==d&&(c+=x.decimal+5),f.push(c),f.push(1==c?x.hr:x.hrs),30!=b&&d&&(f.push(d),f.push(x.mins))),f.join(" ")}function t(b,c){if(null!==b){var d=new Date(v.valueOf()+1e3*b);if(!isNaN(d.getTime())){if("function"===a.type(c))return c(d);for(var e,f,g="",h=0;h<c.length;h++)switch(f=c.charAt(h)){case"a":g+=d.getHours()>11?x.pm:x.am;break;case"A":g+=d.getHours()>11?x.pm.toUpperCase():x.am.toUpperCase();break;case"g":e=d.getHours()%12,g+=0===e?"12":e;break;case"G":g+=d.getHours();break;case"h":e=d.getHours()%12,0!==e&&10>e&&(e="0"+e),g+=0===e?"12":e;break;case"H":e=d.getHours(),b===w&&(e=24),g+=e>9?e:"0"+e;break;case"i":var i=d.getMinutes();g+=i>9?i:"0"+i;break;case"s":b=d.getSeconds(),g+=b>9?b:"0"+b;break;case"\\":h++,g+=c.charAt(h);break;default:g+=f}return g}}}function u(a,b){if(""===a)return null;if(!a||a+0==a)return a;if("object"==typeof a)return 3600*a.getHours()+60*a.getMinutes()+a.getSeconds();a=a.toLowerCase(),("a"==a.slice(-1)||"p"==a.slice(-1))&&(a+="m");var c=new RegExp("^([0-2]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?\\s*("+x.am+"|"+x.pm+")?$"),d=a.match(c);if(!d)return null;var e=parseInt(1*d[1],10),f=d[4],g=e;12>=e&&f&&(g=12==e?d[4]==x.pm?12:0:e+(d[4]==x.pm?12:0));var h=1*d[2]||0,i=1*d[3]||0,j=3600*g+60*h+i;if(!f&&b&&b._twelveHourTime&&b.scrollDefault){var k=j-b.scrollDefault;0>k&&k>=w/-2&&(j=(j+w/2)%w)}return j}var v=h(),w=86400,x={am:"am",pm:"pm",AM:"AM",PM:"PM",decimal:".",mins:"mins",hr:"hr",hrs:"hrs"},y={init:function(b){return this.each(function(){var e=a(this),f=[];for(var g in a.fn.timepicker.defaults)e.data(g)&&(f[g]=e.data(g));var h=a.extend({},a.fn.timepicker.defaults,f,b);h.lang&&(x=a.extend(x,h.lang)),h=c(h),e.data("timepicker-settings",h),e.addClass("ui-timepicker-input"),h.useSelect?d(e):(e.prop("autocomplete","off"),e.on("click.timepicker focus.timepicker",y.show),e.on("change.timepicker",m),e.on("keydown.timepicker",p),e.on("keyup.timepicker",q),m.call(e.get(0)))})},show:function(c){var e=a(this),f=e.data("timepicker-settings");if(c){if(!f.showOnFocus)return!0;c.preventDefault()}if(f.useSelect)return e.data("timepicker-list").focus(),void 0;j(e)&&e.blur();var g=e.data("timepicker-list");if(!e.prop("readonly")&&(g&&0!==g.length&&"function"!=typeof f.durationTime||(d(e),g=e.data("timepicker-list")),!b(g))){y.hide(),g.show();var h={};h.left="rtl"==f.orientation?e.offset().left+e.outerWidth()-g.outerWidth()+parseInt(g.css("marginLeft").replace("px",""),10):e.offset().left+parseInt(g.css("marginLeft").replace("px",""),10),h.top=e.offset().top+e.outerHeight(!0)+g.outerHeight()>a(window).height()+a(window).scrollTop()?e.offset().top-g.outerHeight()+parseInt(g.css("marginTop").replace("px",""),10):e.offset().top+e.outerHeight()+parseInt(g.css("marginTop").replace("px",""),10),g.offset(h);var l=g.find(".ui-timepicker-selected");if(l.length||(n(e)?l=k(e,g,u(n(e))):f.scrollDefault&&(l=k(e,g,f.scrollDefault))),l&&l.length){var m=g.scrollTop()+l.position().top-l.outerHeight();g.scrollTop(m)}else g.scrollTop(0);return a(document).on("touchstart.ui-timepicker mousedown.ui-timepicker",i),f.closeOnWindowScroll&&a(document).on("scroll.ui-timepicker",i),e.trigger("showTimepicker"),this}},hide:function(){var c=a(this),d=c.data("timepicker-settings");return d&&d.useSelect&&c.blur(),a(".ui-timepicker-wrapper").each(function(){var c=a(this);if(b(c)){var d=c.data("timepicker-input"),e=d.data("timepicker-settings");e&&e.selectOnBlur&&r(d),c.hide(),d.trigger("hideTimepicker")}}),this},option:function(b,e){return this.each(function(){var f=a(this),g=f.data("timepicker-settings"),h=f.data("timepicker-list");if("object"==typeof b)g=a.extend(g,b);else if("string"==typeof b&&"undefined"!=typeof e)g[b]=e;else if("string"==typeof b)return g[b];g=c(g),f.data("timepicker-settings",g),h&&(h.remove(),f.data("timepicker-list",!1)),g.useSelect&&d(f)})},getSecondsFromMidnight:function(){return u(n(this))},getTime:function(a){var b=this,c=n(b);if(!c)return null;a||(a=new Date);var d=u(c),e=new Date(a);return e.setHours(d/3600),e.setMinutes(d%3600/60),e.setSeconds(d%60),e.setMilliseconds(0),e},setTime:function(a){var b=this,c=b.data("timepicker-settings");if(c.forceRoundTime)var d=g(a,c);else var d=t(u(a),c.timeFormat);return o(b,d),b.data("timepicker-list")&&l(b,b.data("timepicker-list")),this},remove:function(){var a=this;if(a.hasClass("ui-timepicker-input")){var b=a.data("timepicker-settings");return a.removeAttr("autocomplete","off"),a.removeClass("ui-timepicker-input"),a.removeData("timepicker-settings"),a.off(".timepicker"),a.data("timepicker-list")&&a.data("timepicker-list").remove(),b.useSelect&&a.show(),a.removeData("timepicker-list"),this}}};a.fn.timepicker=function(b){return this.length?y[b]?this.hasClass("ui-timepicker-input")?y[b].apply(this,Array.prototype.slice.call(arguments,1)):this:"object"!=typeof b&&b?(a.error("Method "+b+" does not exist on jQuery.timepicker"),void 0):y.init.apply(this,arguments):this},a.fn.timepicker.defaults={className:null,minTime:null,maxTime:null,durationTime:null,step:30,showDuration:!1,showOnFocus:!0,timeFormat:"g:ia",scrollDefault:null,selectOnBlur:!1,disableTouchKeyboard:!1,forceRoundTime:!1,appendTo:"body",orientation:"ltr",disableTimeRanges:[],closeOnWindowScroll:!1,typeaheadHighlight:!0,noneOption:!1}}); \ No newline at end of file
diff --git a/libgpl/timepicker2/jquery.timepicker.js b/libgpl/timepicker2/jquery.timepicker.js
new file mode 100644
index 0000000..998d2f8
--- /dev/null
+++ b/libgpl/timepicker2/jquery.timepicker.js
@@ -0,0 +1,2223 @@
+/*! jQuery Timepicker Addon - v1.5.0 - 2014-09-01
+* http://trentrichardson.com/examples/timepicker
+* Copyright (c) 2014 Trent Richardson; Licensed MIT */
+(function ($) {
+
+ /*
+ * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
+ */
+ $.ui.timepicker = $.ui.timepicker || {};
+ if ($.ui.timepicker.version) {
+ return;
+ }
+
+ /*
+ * Extend jQueryUI, get it started with our version number
+ */
+ $.extend($.ui, {
+ timepicker: {
+ version: "1.5.0"
+ }
+ });
+
+ /*
+ * Timepicker manager.
+ * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
+ * Settings for (groups of) time pickers are maintained in an instance object,
+ * allowing multiple different settings on the same page.
+ */
+ var Timepicker = function () {
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[''] = { // Default regional settings
+ currentText: 'Now',
+ closeText: 'Done',
+ amNames: ['AM', 'A'],
+ pmNames: ['PM', 'P'],
+ timeFormat: 'HH:mm',
+ timeSuffix: '',
+ timeOnlyTitle: 'Choose Time',
+ timeText: 'Time',
+ hourText: 'Hour',
+ minuteText: 'Minute',
+ secondText: 'Second',
+ millisecText: 'Millisecond',
+ microsecText: 'Microsecond',
+ timezoneText: 'Time Zone',
+ isRTL: false
+ };
+ this._defaults = { // Global defaults for all the datetime picker instances
+ showButtonPanel: true,
+ timeOnly: false,
+ timeOnlyShowDate: false,
+ showHour: null,
+ showMinute: null,
+ showSecond: null,
+ showMillisec: null,
+ showMicrosec: null,
+ showTimezone: null,
+ showTime: true,
+ stepHour: 1,
+ stepMinute: 1,
+ stepSecond: 1,
+ stepMillisec: 1,
+ stepMicrosec: 1,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null,
+ hourMin: 0,
+ minuteMin: 0,
+ secondMin: 0,
+ millisecMin: 0,
+ microsecMin: 0,
+ hourMax: 23,
+ minuteMax: 59,
+ secondMax: 59,
+ millisecMax: 999,
+ microsecMax: 999,
+ minDateTime: null,
+ maxDateTime: null,
+ maxTime: null,
+ minTime: null,
+ onSelect: null,
+ hourGrid: 0,
+ minuteGrid: 0,
+ secondGrid: 0,
+ millisecGrid: 0,
+ microsecGrid: 0,
+ alwaysSetTime: true,
+ separator: ' ',
+ altFieldTimeOnly: true,
+ altTimeFormat: null,
+ altSeparator: null,
+ altTimeSuffix: null,
+ altRedirectFocus: true,
+ pickerTimeFormat: null,
+ pickerTimeSuffix: null,
+ showTimepicker: true,
+ timezoneList: null,
+ addSliderAccess: false,
+ sliderAccessArgs: null,
+ controlType: 'slider',
+ defaultValue: null,
+ parse: 'strict'
+ };
+ $.extend(this._defaults, this.regional['']);
+ };
+
+ $.extend(Timepicker.prototype, {
+ $input: null,
+ $altInput: null,
+ $timeObj: null,
+ inst: null,
+ hour_slider: null,
+ minute_slider: null,
+ second_slider: null,
+ millisec_slider: null,
+ microsec_slider: null,
+ timezone_select: null,
+ maxTime: null,
+ minTime: null,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null,
+ hourMinOriginal: null,
+ minuteMinOriginal: null,
+ secondMinOriginal: null,
+ millisecMinOriginal: null,
+ microsecMinOriginal: null,
+ hourMaxOriginal: null,
+ minuteMaxOriginal: null,
+ secondMaxOriginal: null,
+ millisecMaxOriginal: null,
+ microsecMaxOriginal: null,
+ ampm: '',
+ formattedDate: '',
+ formattedTime: '',
+ formattedDateTime: '',
+ timezoneList: null,
+ units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
+ support: {},
+ control: null,
+
+ /*
+ * Override the default settings for all instances of the time picker.
+ * @param {Object} settings object - the new settings to use as defaults (anonymous object)
+ * @return {Object} the manager object
+ */
+ setDefaults: function (settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /*
+ * Create a new Timepicker instance
+ */
+ _newInst: function ($input, opts) {
+ var tp_inst = new Timepicker(),
+ inlineSettings = {},
+ fns = {},
+ overrides, i;
+
+ for (var attrName in this._defaults) {
+ if (this._defaults.hasOwnProperty(attrName)) {
+ var attrValue = $input.attr('time:' + attrName);
+ if (attrValue) {
+ try {
+ inlineSettings[attrName] = eval(attrValue);
+ } catch (err) {
+ inlineSettings[attrName] = attrValue;
+ }
+ }
+ }
+ }
+
+ overrides = {
+ beforeShow: function (input, dp_inst) {
+ if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
+ return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
+ }
+ },
+ onChangeMonthYear: function (year, month, dp_inst) {
+ // Update the time as well : this prevents the time from disappearing from the $input field.
+ tp_inst._updateDateTime(dp_inst);
+ if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
+ tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
+ }
+ },
+ onClose: function (dateText, dp_inst) {
+ if (tp_inst.timeDefined === true && $input.val() !== '') {
+ tp_inst._updateDateTime(dp_inst);
+ }
+ if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
+ tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
+ }
+ }
+ };
+ for (i in overrides) {
+ if (overrides.hasOwnProperty(i)) {
+ fns[i] = opts[i] || null;
+ }
+ }
+
+ tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {
+ evnts: fns,
+ timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
+ });
+ tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {
+ return val.toUpperCase();
+ });
+ tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {
+ return val.toUpperCase();
+ });
+
+ // detect which units are supported
+ tp_inst.support = detectSupport(
+ tp_inst._defaults.timeFormat +
+ (tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +
+ (tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));
+
+ // controlType is string - key to our this._controls
+ if (typeof(tp_inst._defaults.controlType) === 'string') {
+ if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {
+ tp_inst._defaults.controlType = 'select';
+ }
+ tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
+ }
+ // controlType is an object and must implement create, options, value methods
+ else {
+ tp_inst.control = tp_inst._defaults.controlType;
+ }
+
+ // prep the timezone options
+ var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
+ 0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
+ if (tp_inst._defaults.timezoneList !== null) {
+ timezoneList = tp_inst._defaults.timezoneList;
+ }
+ var tzl = timezoneList.length, tzi = 0, tzv = null;
+ if (tzl > 0 && typeof timezoneList[0] !== 'object') {
+ for (; tzi < tzl; tzi++) {
+ tzv = timezoneList[tzi];
+ timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };
+ }
+ }
+ tp_inst._defaults.timezoneList = timezoneList;
+
+ // set the default units
+ tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :
+ ((new Date()).getTimezoneOffset() * -1);
+ tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :
+ tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
+ tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :
+ tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
+ tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :
+ tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;
+ tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :
+ tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
+ tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :
+ tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;
+ tp_inst.ampm = '';
+ tp_inst.$input = $input;
+
+ if (tp_inst._defaults.altField) {
+ tp_inst.$altInput = $(tp_inst._defaults.altField);
+ if (tp_inst._defaults.altRedirectFocus === true) {
+ tp_inst.$altInput.css({
+ cursor: 'pointer'
+ }).focus(function () {
+ $input.trigger("focus");
+ });
+ }
+ }
+
+ if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
+ tp_inst._defaults.minDate = new Date();
+ }
+ if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
+ tp_inst._defaults.maxDate = new Date();
+ }
+
+ // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
+ if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
+ tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
+ }
+ if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
+ tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
+ }
+ if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
+ tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
+ }
+ if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
+ tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
+ }
+ tp_inst.$input.bind('focus', function () {
+ tp_inst._onFocus();
+ });
+
+ return tp_inst;
+ },
+
+ /*
+ * add our sliders to the calendar
+ */
+ _addTimePicker: function (dp_inst) {
+ var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val();
+
+ this.timeDefined = this._parseTime(currDT);
+ this._limitMinMaxDateTime(dp_inst, false);
+ this._injectTimePicker();
+ },
+
+ /*
+ * parse the time string from input value or _setTime
+ */
+ _parseTime: function (timeString, withDate) {
+ if (!this.inst) {
+ this.inst = $.datepicker._getInst(this.$input[0]);
+ }
+
+ if (withDate || !this._defaults.timeOnly) {
+ var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
+ try {
+ var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
+ if (!parseRes.timeObj) {
+ return false;
+ }
+ $.extend(this, parseRes.timeObj);
+ } catch (err) {
+ $.timepicker.log("Error parsing the date/time string: " + err +
+ "\ndate/time string = " + timeString +
+ "\ntimeFormat = " + this._defaults.timeFormat +
+ "\ndateFormat = " + dp_dateFormat);
+ return false;
+ }
+ return true;
+ } else {
+ var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
+ if (!timeObj) {
+ return false;
+ }
+ $.extend(this, timeObj);
+ return true;
+ }
+ },
+
+ /*
+ * generate and inject html for timepicker into ui datepicker
+ */
+ _injectTimePicker: function () {
+ var $dp = this.inst.dpDiv,
+ o = this.inst.settings,
+ tp_inst = this,
+ litem = '',
+ uitem = '',
+ show = null,
+ max = {},
+ gridSize = {},
+ size = null,
+ i = 0,
+ l = 0;
+
+ // Prevent displaying twice
+ if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
+ var noDisplay = ' style="display:none;"',
+ html = '<div class="ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + '"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
+ '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>';
+
+ // Create the markup
+ for (i = 0, l = this.units.length; i < l; i++) {
+ litem = this.units[i];
+ uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
+ show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
+
+ // Added by Peter Medeiros:
+ // - Figure out what the hour/minute/second max should be based on the step values.
+ // - Example: if stepMinute is 15, then minMax is 45.
+ max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
+ gridSize[litem] = 0;
+
+ html += '<dt class="ui_tpicker_' + litem + '_label"' + (show ? '' : noDisplay) + '>' + o[litem + 'Text'] + '</dt>' +
+ '<dd class="ui_tpicker_' + litem + '"><div class="ui_tpicker_' + litem + '_slider"' + (show ? '' : noDisplay) + '></div>';
+
+ if (show && o[litem + 'Grid'] > 0) {
+ html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
+
+ if (litem === 'hour') {
+ for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
+ gridSize[litem]++;
+ var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
+ html += '<td data-for="' + litem + '">' + tmph + '</td>';
+ }
+ }
+ else {
+ for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
+ gridSize[litem]++;
+ html += '<td data-for="' + litem + '">' + ((m < 10) ? '0' : '') + m + '</td>';
+ }
+ }
+
+ html += '</tr></table></div>';
+ }
+ html += '</dd>';
+ }
+
+ // Timezone
+ var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;
+ html += '<dt class="ui_tpicker_timezone_label"' + (showTz ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
+ html += '<dd class="ui_tpicker_timezone" ' + (showTz ? '' : noDisplay) + '></dd>';
+
+ // Create the elements from string
+ html += '</dl></div>';
+ var $tp = $(html);
+
+ // if we only want time picker...
+ if (o.timeOnly === true) {
+ $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
+ $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
+ }
+
+ // add sliders, adjust grids, add events
+ for (i = 0, l = tp_inst.units.length; i < l; i++) {
+ litem = tp_inst.units[i];
+ uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
+ show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
+
+ // add the slider
+ tp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);
+
+ // adjust the grid and add click event
+ if (show && o[litem + 'Grid'] > 0) {
+ size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);
+ $tp.find('.ui_tpicker_' + litem + ' table').css({
+ width: size + "%",
+ marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + "%"),
+ marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + "%") : '0',
+ borderCollapse: 'collapse'
+ }).find("td").click(function (e) {
+ var $t = $(this),
+ h = $t.html(),
+ n = parseInt(h.replace(/[^0-9]/g), 10),
+ ap = h.replace(/[^apm]/ig),
+ f = $t.data('for'); // loses scope, so we use data-for
+
+ if (f === 'hour') {
+ if (ap.indexOf('p') !== -1 && n < 12) {
+ n += 12;
+ }
+ else {
+ if (ap.indexOf('a') !== -1 && n === 12) {
+ n = 0;
+ }
+ }
+ }
+
+ tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);
+
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ }).css({
+ cursor: 'pointer',
+ width: (100 / gridSize[litem]) + '%',
+ textAlign: 'center',
+ overflow: 'hidden'
+ });
+ } // end if grid > 0
+ } // end for loop
+
+ // Add timezone options
+ this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
+ $.fn.append.apply(this.timezone_select,
+ $.map(o.timezoneList, function (val, idx) {
+ return $("<option />").val(typeof val === "object" ? val.value : val).text(typeof val === "object" ? val.label : val);
+ }));
+ if (typeof(this.timezone) !== "undefined" && this.timezone !== null && this.timezone !== "") {
+ var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;
+ if (local_timezone === this.timezone) {
+ selectLocalTimezone(tp_inst);
+ } else {
+ this.timezone_select.val(this.timezone);
+ }
+ } else {
+ if (typeof(this.hour) !== "undefined" && this.hour !== null && this.hour !== "") {
+ this.timezone_select.val(o.timezone);
+ } else {
+ selectLocalTimezone(tp_inst);
+ }
+ }
+ this.timezone_select.change(function () {
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ });
+ // End timezone options
+
+ // inject timepicker into datepicker
+ var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
+ if ($buttonPanel.length) {
+ $buttonPanel.before($tp);
+ } else {
+ $dp.append($tp);
+ }
+
+ this.$timeObj = $tp.find('.ui_tpicker_time');
+
+ if (this.inst !== null) {
+ var timeDefined = this.timeDefined;
+ this._onTimeChange();
+ this.timeDefined = timeDefined;
+ }
+
+ // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
+ if (this._defaults.addSliderAccess) {
+ var sliderAccessArgs = this._defaults.sliderAccessArgs,
+ rtl = this._defaults.isRTL;
+ sliderAccessArgs.isRTL = rtl;
+
+ setTimeout(function () { // fix for inline mode
+ if ($tp.find('.ui-slider-access').length === 0) {
+ $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
+
+ // fix any grids since sliders are shorter
+ var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
+ if (sliderAccessWidth) {
+ $tp.find('table:visible').each(function () {
+ var $g = $(this),
+ oldWidth = $g.outerWidth(),
+ oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),
+ newWidth = oldWidth - sliderAccessWidth,
+ newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
+ css = { width: newWidth, marginRight: 0, marginLeft: 0 };
+ css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;
+ $g.css(css);
+ });
+ }
+ }
+ }, 10);
+ }
+ // end slideAccess integration
+
+ tp_inst._limitMinMaxDateTime(this.inst, true);
+ }
+ },
+
+ /*
+ * This function tries to limit the ability to go outside the
+ * min/max date range
+ */
+ _limitMinMaxDateTime: function (dp_inst, adjustSliders) {
+ var o = this._defaults,
+ dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
+
+ if (!this._defaults.showTimepicker) {
+ return;
+ } // No time so nothing to check here
+
+ if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
+ var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
+ minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
+
+ if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {
+ this.hourMinOriginal = o.hourMin;
+ this.minuteMinOriginal = o.minuteMin;
+ this.secondMinOriginal = o.secondMin;
+ this.millisecMinOriginal = o.millisecMin;
+ this.microsecMinOriginal = o.microsecMin;
+ }
+
+ if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {
+ this._defaults.hourMin = minDateTime.getHours();
+ if (this.hour <= this._defaults.hourMin) {
+ this.hour = this._defaults.hourMin;
+ this._defaults.minuteMin = minDateTime.getMinutes();
+ if (this.minute <= this._defaults.minuteMin) {
+ this.minute = this._defaults.minuteMin;
+ this._defaults.secondMin = minDateTime.getSeconds();
+ if (this.second <= this._defaults.secondMin) {
+ this.second = this._defaults.secondMin;
+ this._defaults.millisecMin = minDateTime.getMilliseconds();
+ if (this.millisec <= this._defaults.millisecMin) {
+ this.millisec = this._defaults.millisecMin;
+ this._defaults.microsecMin = minDateTime.getMicroseconds();
+ } else {
+ if (this.microsec < this._defaults.microsecMin) {
+ this.microsec = this._defaults.microsecMin;
+ }
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.hourMin = this.hourMinOriginal;
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ }
+
+ if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
+ var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
+ maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
+
+ if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {
+ this.hourMaxOriginal = o.hourMax;
+ this.minuteMaxOriginal = o.minuteMax;
+ this.secondMaxOriginal = o.secondMax;
+ this.millisecMaxOriginal = o.millisecMax;
+ this.microsecMaxOriginal = o.microsecMax;
+ }
+
+ if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {
+ this._defaults.hourMax = maxDateTime.getHours();
+ if (this.hour >= this._defaults.hourMax) {
+ this.hour = this._defaults.hourMax;
+ this._defaults.minuteMax = maxDateTime.getMinutes();
+ if (this.minute >= this._defaults.minuteMax) {
+ this.minute = this._defaults.minuteMax;
+ this._defaults.secondMax = maxDateTime.getSeconds();
+ if (this.second >= this._defaults.secondMax) {
+ this.second = this._defaults.secondMax;
+ this._defaults.millisecMax = maxDateTime.getMilliseconds();
+ if (this.millisec >= this._defaults.millisecMax) {
+ this.millisec = this._defaults.millisecMax;
+ this._defaults.microsecMax = maxDateTime.getMicroseconds();
+ } else {
+ if (this.microsec > this._defaults.microsecMax) {
+ this.microsec = this._defaults.microsecMax;
+ }
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.hourMax = this.hourMaxOriginal;
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ }
+
+ if (dp_inst.settings.minTime!==null) {
+ var tempMinTime=new Date("01/01/1970 " + dp_inst.settings.minTime);
+ if (this.hour<tempMinTime.getHours()) {
+ this.hour=this._defaults.hourMin=tempMinTime.getHours();
+ this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else if (this.hour===tempMinTime.getHours() && this.minute<tempMinTime.getMinutes()) {
+ this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else {
+ if (this._defaults.hourMin<tempMinTime.getHours()) {
+ this._defaults.hourMin=tempMinTime.getHours();
+ this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else if (this._defaults.hourMin===tempMinTime.getHours()===this.hour && this._defaults.minuteMin<tempMinTime.getMinutes()) {
+ this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else {
+ this._defaults.minuteMin=0;
+ }
+ }
+ }
+
+ if (dp_inst.settings.maxTime!==null) {
+ var tempMaxTime=new Date("01/01/1970 " + dp_inst.settings.maxTime);
+ if (this.hour>tempMaxTime.getHours()) {
+ this.hour=this._defaults.hourMax=tempMaxTime.getHours();
+ this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else if (this.hour===tempMaxTime.getHours() && this.minute>tempMaxTime.getMinutes()) {
+ this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else {
+ if (this._defaults.hourMax>tempMaxTime.getHours()) {
+ this._defaults.hourMax=tempMaxTime.getHours();
+ this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else if (this._defaults.hourMax===tempMaxTime.getHours()===this.hour && this._defaults.minuteMax>tempMaxTime.getMinutes()) {
+ this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else {
+ this._defaults.minuteMax=59;
+ }
+ }
+ }
+
+ if (adjustSliders !== undefined && adjustSliders === true) {
+ var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
+ minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
+ secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
+ millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),
+ microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);
+
+ if (this.hour_slider) {
+ this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax, step: this._defaults.stepHour });
+ this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
+ }
+ if (this.minute_slider) {
+ this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax, step: this._defaults.stepMinute });
+ this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
+ }
+ if (this.second_slider) {
+ this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax, step: this._defaults.stepSecond });
+ this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
+ }
+ if (this.millisec_slider) {
+ this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax, step: this._defaults.stepMillisec });
+ this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
+ }
+ if (this.microsec_slider) {
+ this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax, step: this._defaults.stepMicrosec });
+ this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));
+ }
+ }
+
+ },
+
+ /*
+ * when a slider moves, set the internal time...
+ * on time change is also called when the time is updated in the text field
+ */
+ _onTimeChange: function () {
+ if (!this._defaults.showTimepicker) {
+ return;
+ }
+ var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
+ minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
+ second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
+ millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
+ microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,
+ timezone = (this.timezone_select) ? this.timezone_select.val() : false,
+ o = this._defaults,
+ pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
+ pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
+
+ if (typeof(hour) === 'object') {
+ hour = false;
+ }
+ if (typeof(minute) === 'object') {
+ minute = false;
+ }
+ if (typeof(second) === 'object') {
+ second = false;
+ }
+ if (typeof(millisec) === 'object') {
+ millisec = false;
+ }
+ if (typeof(microsec) === 'object') {
+ microsec = false;
+ }
+ if (typeof(timezone) === 'object') {
+ timezone = false;
+ }
+
+ if (hour !== false) {
+ hour = parseInt(hour, 10);
+ }
+ if (minute !== false) {
+ minute = parseInt(minute, 10);
+ }
+ if (second !== false) {
+ second = parseInt(second, 10);
+ }
+ if (millisec !== false) {
+ millisec = parseInt(millisec, 10);
+ }
+ if (microsec !== false) {
+ microsec = parseInt(microsec, 10);
+ }
+ if (timezone !== false) {
+ timezone = timezone.toString();
+ }
+
+ var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
+
+ // If the update was done in the input field, the input field should not be updated.
+ // If the update was done using the sliders, update the input field.
+ var hasChanged = (
+ hour !== parseInt(this.hour,10) || // sliders should all be numeric
+ minute !== parseInt(this.minute,10) ||
+ second !== parseInt(this.second,10) ||
+ millisec !== parseInt(this.millisec,10) ||
+ microsec !== parseInt(this.microsec,10) ||
+ (this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) ||
+ (this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or "EST" format, so use toString()
+ );
+
+ if (hasChanged) {
+
+ if (hour !== false) {
+ this.hour = hour;
+ }
+ if (minute !== false) {
+ this.minute = minute;
+ }
+ if (second !== false) {
+ this.second = second;
+ }
+ if (millisec !== false) {
+ this.millisec = millisec;
+ }
+ if (microsec !== false) {
+ this.microsec = microsec;
+ }
+ if (timezone !== false) {
+ this.timezone = timezone;
+ }
+
+ if (!this.inst) {
+ this.inst = $.datepicker._getInst(this.$input[0]);
+ }
+
+ this._limitMinMaxDateTime(this.inst, true);
+ }
+ if (this.support.ampm) {
+ this.ampm = ampm;
+ }
+
+ // Updates the time within the timepicker
+ this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
+ if (this.$timeObj) {
+ if (pickerTimeFormat === o.timeFormat) {
+ this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
+ }
+ else {
+ this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
+ }
+ }
+
+ this.timeDefined = true;
+ if (hasChanged) {
+ this._updateDateTime();
+ //this.$input.focus(); // may automatically open the picker on setDate
+ }
+ },
+
+ /*
+ * call custom onSelect.
+ * bind to sliders slidestop, and grid click.
+ */
+ _onSelectHandler: function () {
+ var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
+ var inputEl = this.$input ? this.$input[0] : null;
+ if (onSelect && inputEl) {
+ onSelect.apply(inputEl, [this.formattedDateTime, this]);
+ }
+ },
+
+ /*
+ * update our input with the new date time..
+ */
+ _updateDateTime: function (dp_inst) {
+ dp_inst = this.inst || dp_inst;
+ var dtTmp = (dp_inst.currentYear > 0?
+ new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) :
+ new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
+ dt = $.datepicker._daylightSavingAdjust(dtTmp),
+ //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
+ //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
+ dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
+ formatCfg = $.datepicker._getFormatConfig(dp_inst),
+ timeAvailable = dt !== null && this.timeDefined;
+ this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
+ var formattedDateTime = this.formattedDate;
+
+ // if a slider was changed but datepicker doesn't have a value yet, set it
+ if (dp_inst.lastVal === "") {
+ dp_inst.currentYear = dp_inst.selectedYear;
+ dp_inst.currentMonth = dp_inst.selectedMonth;
+ dp_inst.currentDay = dp_inst.selectedDay;
+ }
+
+ /*
+ * remove following lines to force every changes in date picker to change the input value
+ * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
+ * If the user manually empty the value in the input field, the date picker will never change selected value.
+ */
+ //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
+ // return;
+ //}
+
+ if (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false) {
+ formattedDateTime = this.formattedTime;
+ } else if ((this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) || (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true)) {
+ formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
+ }
+
+ this.formattedDateTime = formattedDateTime;
+
+ if (!this._defaults.showTimepicker) {
+ this.$input.val(this.formattedDate);
+ } else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {
+ this.$altInput.val(this.formattedTime);
+ this.$input.val(this.formattedDate);
+ } else if (this.$altInput) {
+ this.$input.val(formattedDateTime);
+ var altFormattedDateTime = '',
+ altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator,
+ altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
+
+ if (!this._defaults.timeOnly) {
+ if (this._defaults.altFormat) {
+ altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
+ }
+ else {
+ altFormattedDateTime = this.formattedDate;
+ }
+
+ if (altFormattedDateTime) {
+ altFormattedDateTime += altSeparator;
+ }
+ }
+
+ if (this._defaults.altTimeFormat !== null) {
+ altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
+ }
+ else {
+ altFormattedDateTime += this.formattedTime + altTimeSuffix;
+ }
+ this.$altInput.val(altFormattedDateTime);
+ } else {
+ this.$input.val(formattedDateTime);
+ }
+
+ this.$input.trigger("change");
+ },
+
+ _onFocus: function () {
+ if (!this.$input.val() && this._defaults.defaultValue) {
+ this.$input.val(this._defaults.defaultValue);
+ var inst = $.datepicker._getInst(this.$input.get(0)),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+ if (tp_inst) {
+ if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
+ try {
+ $.datepicker._updateDatepicker(inst);
+ } catch (err) {
+ $.timepicker.log(err);
+ }
+ }
+ }
+ }
+ },
+
+ /*
+ * Small abstraction to control types
+ * We can add more, just be sure to follow the pattern: create, options, value
+ */
+ _controls: {
+ // slider methods
+ slider: {
+ create: function (tp_inst, obj, unit, val, min, max, step) {
+ var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
+ return obj.prop('slide', null).slider({
+ orientation: "horizontal",
+ value: rtl ? val * -1 : val,
+ min: rtl ? max * -1 : min,
+ max: rtl ? min * -1 : max,
+ step: step,
+ slide: function (event, ui) {
+ tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);
+ tp_inst._onTimeChange();
+ },
+ stop: function (event, ui) {
+ tp_inst._onSelectHandler();
+ }
+ });
+ },
+ options: function (tp_inst, obj, unit, opts, val) {
+ if (tp_inst._defaults.isRTL) {
+ if (typeof(opts) === 'string') {
+ if (opts === 'min' || opts === 'max') {
+ if (val !== undefined) {
+ return obj.slider(opts, val * -1);
+ }
+ return Math.abs(obj.slider(opts));
+ }
+ return obj.slider(opts);
+ }
+ var min = opts.min,
+ max = opts.max;
+ opts.min = opts.max = null;
+ if (min !== undefined) {
+ opts.max = min * -1;
+ }
+ if (max !== undefined) {
+ opts.min = max * -1;
+ }
+ return obj.slider(opts);
+ }
+ if (typeof(opts) === 'string' && val !== undefined) {
+ return obj.slider(opts, val);
+ }
+ return obj.slider(opts);
+ },
+ value: function (tp_inst, obj, unit, val) {
+ if (tp_inst._defaults.isRTL) {
+ if (val !== undefined) {
+ return obj.slider('value', val * -1);
+ }
+ return Math.abs(obj.slider('value'));
+ }
+ if (val !== undefined) {
+ return obj.slider('value', val);
+ }
+ return obj.slider('value');
+ }
+ },
+ // select methods
+ select: {
+ create: function (tp_inst, obj, unit, val, min, max, step) {
+ var sel = '<select class="ui-timepicker-select ui-state-default ui-corner-all" data-unit="' + unit + '" data-min="' + min + '" data-max="' + max + '" data-step="' + step + '">',
+ format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;
+
+ for (var i = min; i <= max; i += step) {
+ sel += '<option value="' + i + '"' + (i === val ? ' selected' : '') + '>';
+ if (unit === 'hour') {
+ sel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);
+ }
+ else if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }
+ else {sel += '0' + i.toString(); }
+ sel += '</option>';
+ }
+ sel += '</select>';
+
+ obj.children('select').remove();
+
+ $(sel).appendTo(obj).change(function (e) {
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ });
+
+ return obj;
+ },
+ options: function (tp_inst, obj, unit, opts, val) {
+ var o = {},
+ $t = obj.children('select');
+ if (typeof(opts) === 'string') {
+ if (val === undefined) {
+ return $t.data(opts);
+ }
+ o[opts] = val;
+ }
+ else { o = opts; }
+ return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
+ },
+ value: function (tp_inst, obj, unit, val) {
+ var $t = obj.children('select');
+ if (val !== undefined) {
+ return $t.val(val);
+ }
+ return $t.val();
+ }
+ }
+ } // end _controls
+
+ });
+
+ $.fn.extend({
+ /*
+ * shorthand just to use timepicker.
+ */
+ timepicker: function (o) {
+ o = o || {};
+ var tmp_args = Array.prototype.slice.call(arguments);
+
+ if (typeof o === 'object') {
+ tmp_args[0] = $.extend(o, {
+ timeOnly: true
+ });
+ }
+
+ return $(this).each(function () {
+ $.fn.datetimepicker.apply($(this), tmp_args);
+ });
+ },
+
+ /*
+ * extend timepicker to datepicker
+ */
+ datetimepicker: function (o) {
+ o = o || {};
+ var tmp_args = arguments;
+
+ if (typeof(o) === 'string') {
+ if (o === 'getDate' || (o === 'option' && tmp_args.length === 2 && typeof (tmp_args[1]) === 'string')) {
+ return $.fn.datepicker.apply($(this[0]), tmp_args);
+ } else {
+ return this.each(function () {
+ var $t = $(this);
+ $t.datepicker.apply($t, tmp_args);
+ });
+ }
+ } else {
+ return this.each(function () {
+ var $t = $(this);
+ $t.datepicker($.timepicker._newInst($t, o)._defaults);
+ });
+ }
+ }
+ });
+
+ /*
+ * Public Utility to parse date and time
+ */
+ $.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
+ var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
+ if (parseRes.timeObj) {
+ var t = parseRes.timeObj;
+ parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
+ parseRes.date.setMicroseconds(t.microsec);
+ }
+
+ return parseRes.date;
+ };
+
+ /*
+ * Public utility to parse time
+ */
+ $.datepicker.parseTime = function (timeFormat, timeString, options) {
+ var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),
+ iso8601 = (timeFormat.replace(/\'.*?\'/g, '').indexOf('Z') !== -1);
+
+ // Strict parse requires the timeString to match the timeFormat exactly
+ var strictParse = function (f, s, o) {
+
+ // pattern for standard and localized AM/PM markers
+ var getPatternAmpm = function (amNames, pmNames) {
+ var markers = [];
+ if (amNames) {
+ $.merge(markers, amNames);
+ }
+ if (pmNames) {
+ $.merge(markers, pmNames);
+ }
+ markers = $.map(markers, function (val) {
+ return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
+ });
+ return '(' + markers.join('|') + ')?';
+ };
+
+ // figure out position of time elements.. cause js cant do named captures
+ var getFormatPositions = function (timeFormat) {
+ var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),
+ orders = {
+ h: -1,
+ m: -1,
+ s: -1,
+ l: -1,
+ c: -1,
+ t: -1,
+ z: -1
+ };
+
+ if (finds) {
+ for (var i = 0; i < finds.length; i++) {
+ if (orders[finds[i].toString().charAt(0)] === -1) {
+ orders[finds[i].toString().charAt(0)] = i + 1;
+ }
+ }
+ }
+ return orders;
+ };
+
+ var regstr = '^' + f.toString()
+ .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
+ var ml = match.length;
+ switch (match.charAt(0).toLowerCase()) {
+ case 'h':
+ return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
+ case 'm':
+ return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
+ case 's':
+ return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
+ case 'l':
+ return '(\\d?\\d?\\d)';
+ case 'c':
+ return '(\\d?\\d?\\d)';
+ case 'z':
+ return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
+ case 't':
+ return getPatternAmpm(o.amNames, o.pmNames);
+ default: // literal escaped in quotes
+ return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
+ }
+ })
+ .replace(/\s/g, '\\s?') +
+ o.timeSuffix + '$',
+ order = getFormatPositions(f),
+ ampm = '',
+ treg;
+
+ treg = s.match(new RegExp(regstr, 'i'));
+
+ var resTime = {
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0
+ };
+
+ if (treg) {
+ if (order.t !== -1) {
+ if (treg[order.t] === undefined || treg[order.t].length === 0) {
+ ampm = '';
+ resTime.ampm = '';
+ } else {
+ ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM';
+ resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];
+ }
+ }
+
+ if (order.h !== -1) {
+ if (ampm === 'AM' && treg[order.h] === '12') {
+ resTime.hour = 0; // 12am = 0 hour
+ } else {
+ if (ampm === 'PM' && treg[order.h] !== '12') {
+ resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
+ } else {
+ resTime.hour = Number(treg[order.h]);
+ }
+ }
+ }
+
+ if (order.m !== -1) {
+ resTime.minute = Number(treg[order.m]);
+ }
+ if (order.s !== -1) {
+ resTime.second = Number(treg[order.s]);
+ }
+ if (order.l !== -1) {
+ resTime.millisec = Number(treg[order.l]);
+ }
+ if (order.c !== -1) {
+ resTime.microsec = Number(treg[order.c]);
+ }
+ if (order.z !== -1 && treg[order.z] !== undefined) {
+ resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);
+ }
+
+
+ return resTime;
+ }
+ return false;
+ };// end strictParse
+
+ // First try JS Date, if that fails, use strictParse
+ var looseParse = function (f, s, o) {
+ try {
+ var d = new Date('2012-01-01 ' + s);
+ if (isNaN(d.getTime())) {
+ d = new Date('2012-01-01T' + s);
+ if (isNaN(d.getTime())) {
+ d = new Date('01/01/2012 ' + s);
+ if (isNaN(d.getTime())) {
+ throw "Unable to parse time with native Date: " + s;
+ }
+ }
+ }
+
+ return {
+ hour: d.getHours(),
+ minute: d.getMinutes(),
+ second: d.getSeconds(),
+ millisec: d.getMilliseconds(),
+ microsec: d.getMicroseconds(),
+ timezone: d.getTimezoneOffset() * -1
+ };
+ }
+ catch (err) {
+ try {
+ return strictParse(f, s, o);
+ }
+ catch (err2) {
+ $.timepicker.log("Unable to parse \ntimeString: " + s + "\ntimeFormat: " + f);
+ }
+ }
+ return false;
+ }; // end looseParse
+
+ if (typeof o.parse === "function") {
+ return o.parse(timeFormat, timeString, o);
+ }
+ if (o.parse === 'loose') {
+ return looseParse(timeFormat, timeString, o);
+ }
+ return strictParse(timeFormat, timeString, o);
+ };
+
+ /**
+ * Public utility to format the time
+ * @param {string} format format of the time
+ * @param {Object} time Object not a Date for timezones
+ * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
+ * @returns {string} the formatted time
+ */
+ $.datepicker.formatTime = function (format, time, options) {
+ options = options || {};
+ options = $.extend({}, $.timepicker._defaults, options);
+ time = $.extend({
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null
+ }, time);
+
+ var tmptime = format,
+ ampmName = options.amNames[0],
+ hour = parseInt(time.hour, 10);
+
+ if (hour > 11) {
+ ampmName = options.pmNames[0];
+ }
+
+ tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
+ switch (match) {
+ case 'HH':
+ return ('0' + hour).slice(-2);
+ case 'H':
+ return hour;
+ case 'hh':
+ return ('0' + convert24to12(hour)).slice(-2);
+ case 'h':
+ return convert24to12(hour);
+ case 'mm':
+ return ('0' + time.minute).slice(-2);
+ case 'm':
+ return time.minute;
+ case 'ss':
+ return ('0' + time.second).slice(-2);
+ case 's':
+ return time.second;
+ case 'l':
+ return ('00' + time.millisec).slice(-3);
+ case 'c':
+ return ('00' + time.microsec).slice(-3);
+ case 'z':
+ return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);
+ case 'Z':
+ return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);
+ case 'T':
+ return ampmName.charAt(0).toUpperCase();
+ case 'TT':
+ return ampmName.toUpperCase();
+ case 't':
+ return ampmName.charAt(0).toLowerCase();
+ case 'tt':
+ return ampmName.toLowerCase();
+ default:
+ return match.replace(/'/g, "");
+ }
+ });
+
+ return tmptime;
+ };
+
+ /*
+ * the bad hack :/ override datepicker so it doesn't close on select
+ // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
+ */
+ $.datepicker._base_selectDate = $.datepicker._selectDate;
+ $.datepicker._selectDate = function (id, dateStr) {
+ var inst = this._getInst($(id)[0]),
+ tp_inst = this._get(inst, 'timepicker'),
+ was_inline;
+
+ if (tp_inst && inst.settings.showTimepicker) {
+ tp_inst._limitMinMaxDateTime(inst, true);
+ was_inline = inst.inline;
+ inst.inline = inst.stay_open = true;
+ //This way the onSelect handler called from calendarpicker get the full dateTime
+ this._base_selectDate(id, dateStr);
+ inst.inline = was_inline;
+ inst.stay_open = false;
+ this._notifyChange(inst);
+ this._updateDatepicker(inst);
+ } else {
+ this._base_selectDate(id, dateStr);
+ }
+ };
+
+ /*
+ * second bad hack :/ override datepicker so it triggers an event when changing the input field
+ * and does not redraw the datepicker on every selectDate event
+ */
+ $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
+ $.datepicker._updateDatepicker = function (inst) {
+
+ // don't popup the datepicker if there is another instance already opened
+ var input = inst.input[0];
+ if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {
+ return;
+ }
+
+ if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
+
+ this._base_updateDatepicker(inst);
+
+ // Reload the time control when changing something in the input text field.
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._addTimePicker(inst);
+ }
+ }
+ };
+
+ /*
+ * third bad hack :/ override datepicker so it allows spaces and colon in the input field
+ */
+ $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
+ $.datepicker._doKeyPress = function (event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if ($.datepicker._get(inst, 'constrainInput')) {
+ var ampm = tp_inst.support.ampm,
+ tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,
+ dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
+ datetimeChars = tp_inst._defaults.timeFormat.toString()
+ .replace(/[hms]/g, '')
+ .replace(/TT/g, ampm ? 'APM' : '')
+ .replace(/Tt/g, ampm ? 'AaPpMm' : '')
+ .replace(/tT/g, ampm ? 'AaPpMm' : '')
+ .replace(/T/g, ampm ? 'AP' : '')
+ .replace(/tt/g, ampm ? 'apm' : '')
+ .replace(/t/g, ampm ? 'ap' : '') +
+ " " + tp_inst._defaults.separator +
+ tp_inst._defaults.timeSuffix +
+ (tz ? tp_inst._defaults.timezoneList.join('') : '') +
+ (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
+ dateChars,
+ chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
+ return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
+ }
+ }
+
+ return $.datepicker._base_doKeyPress(event);
+ };
+
+ /*
+ * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
+ * Update any alternate field to synchronise with the main field.
+ */
+ $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
+ $.datepicker._updateAlternate = function (inst) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var altField = tp_inst._defaults.altField;
+ if (altField) { // update alternate field too
+ var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
+ date = this._getDate(inst),
+ formatCfg = $.datepicker._getFormatConfig(inst),
+ altFormattedDateTime = '',
+ altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
+ altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
+ altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
+
+ altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
+ if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {
+ if (tp_inst._defaults.altFormat) {
+ altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
+ }
+ else {
+ altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
+ }
+ }
+ $(altField).val( inst.input.val() ? altFormattedDateTime : "");
+ }
+ }
+ else {
+ $.datepicker._base_updateAlternate(inst);
+ }
+ };
+
+ /*
+ * Override key up event to sync manual input changes.
+ */
+ $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
+ $.datepicker._doKeyUp = function (event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
+ try {
+ $.datepicker._updateDatepicker(inst);
+ } catch (err) {
+ $.timepicker.log(err);
+ }
+ }
+ }
+
+ return $.datepicker._base_doKeyUp(event);
+ };
+
+ /*
+ * override "Today" button to also grab the time.
+ */
+ $.datepicker._base_gotoToday = $.datepicker._gotoToday;
+ $.datepicker._gotoToday = function (id) {
+ var inst = this._getInst($(id)[0]),
+ $dp = inst.dpDiv;
+ this._base_gotoToday(id);
+ var tp_inst = this._get(inst, 'timepicker');
+ selectLocalTimezone(tp_inst);
+ var now = new Date();
+ this._setTime(inst, now);
+ this._setDate(inst, now);
+ };
+
+ /*
+ * Disable & enable the Time in the datetimepicker
+ */
+ $.datepicker._disableTimepickerDatepicker = function (target) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+ if (tp_inst) {
+ inst.settings.showTimepicker = false;
+ tp_inst._defaults.showTimepicker = false;
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ $.datepicker._enableTimepickerDatepicker = function (target) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+ if (tp_inst) {
+ inst.settings.showTimepicker = true;
+ tp_inst._defaults.showTimepicker = true;
+ tp_inst._addTimePicker(inst); // Could be disabled on page load
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ /*
+ * Create our own set time function
+ */
+ $.datepicker._setTime = function (inst, date) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var defaults = tp_inst._defaults;
+
+ // calling _setTime with no date sets time to defaults
+ tp_inst.hour = date ? date.getHours() : defaults.hour;
+ tp_inst.minute = date ? date.getMinutes() : defaults.minute;
+ tp_inst.second = date ? date.getSeconds() : defaults.second;
+ tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
+ tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;
+
+ //check if within min/max times..
+ tp_inst._limitMinMaxDateTime(inst, true);
+
+ tp_inst._onTimeChange();
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ /*
+ * Create new public method to set only time, callable as $().datepicker('setTime', date)
+ */
+ $.datepicker._setTimeDatepicker = function (target, date, withDate) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ this._setDateFromField(inst);
+ var tp_date;
+ if (date) {
+ if (typeof date === "string") {
+ tp_inst._parseTime(date, withDate);
+ tp_date = new Date();
+ tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+ tp_date.setMicroseconds(tp_inst.microsec);
+ } else {
+ tp_date = new Date(date.getTime());
+ tp_date.setMicroseconds(date.getMicroseconds());
+ }
+ if (tp_date.toString() === 'Invalid Date') {
+ tp_date = undefined;
+ }
+ this._setTime(inst, tp_date);
+ }
+ }
+
+ };
+
+ /*
+ * override setDate() to allow setting time too within Date object
+ */
+ $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
+ $.datepicker._setDateDatepicker = function (target, _date) {
+ var inst = this._getInst(target);
+ var date = _date;
+ if (!inst) {
+ return;
+ }
+
+ if (typeof(_date) === 'string') {
+ date = new Date(_date);
+ if (!date.getTime()) {
+ this._base_setDateDatepicker.apply(this, arguments);
+ date = $(target).datepicker('getDate');
+ }
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ var tp_date;
+ if (date instanceof Date) {
+ tp_date = new Date(date.getTime());
+ tp_date.setMicroseconds(date.getMicroseconds());
+ } else {
+ tp_date = date;
+ }
+
+ // This is important if you are using the timezone option, javascript's Date
+ // object will only return the timezone offset for the current locale, so we
+ // adjust it accordingly. If not using timezone option this won't matter..
+ // If a timezone is different in tp, keep the timezone as is
+ if (tp_inst && tp_date) {
+ // look out for DST if tz wasn't specified
+ if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
+ tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
+ }
+ date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
+ tp_date = $.timepicker.timezoneAdjust(tp_date, tp_inst.timezone);
+ }
+
+ this._updateDatepicker(inst);
+ this._base_setDateDatepicker.apply(this, arguments);
+ this._setTimeDatepicker(target, tp_date, true);
+ };
+
+ /*
+ * override getDate() to allow getting time too within Date object
+ */
+ $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
+ $.datepicker._getDateDatepicker = function (target, noDefault) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ // if it hasn't yet been defined, grab from field
+ if (inst.lastVal === undefined) {
+ this._setDateFromField(inst, noDefault);
+ }
+
+ var date = this._getDate(inst);
+ if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
+ date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+ date.setMicroseconds(tp_inst.microsec);
+
+ // This is important if you are using the timezone option, javascript's Date
+ // object will only return the timezone offset for the current locale, so we
+ // adjust it accordingly. If not using timezone option this won't matter..
+ if (tp_inst.timezone != null) {
+ // look out for DST if tz wasn't specified
+ if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
+ tp_inst.timezone = date.getTimezoneOffset() * -1;
+ }
+ date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
+ }
+ }
+ return date;
+ }
+ return this._base_getDateDatepicker(target, noDefault);
+ };
+
+ /*
+ * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
+ * An option in datapicker to ignore extra format characters would be nicer.
+ */
+ $.datepicker._base_parseDate = $.datepicker.parseDate;
+ $.datepicker.parseDate = function (format, value, settings) {
+ var date;
+ try {
+ date = this._base_parseDate(format, value, settings);
+ } catch (err) {
+ // Hack! The error message ends with a colon, a space, and
+ // the "extra" characters. We rely on that instead of
+ // attempting to perfectly reproduce the parsing algorithm.
+ if (err.indexOf(":") >= 0) {
+ date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);
+ $.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
+ } else {
+ throw err;
+ }
+ }
+ return date;
+ };
+
+ /*
+ * override formatDate to set date with time to the input
+ */
+ $.datepicker._base_formatDate = $.datepicker._formatDate;
+ $.datepicker._formatDate = function (inst, day, month, year) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._updateDateTime(inst);
+ return tp_inst.$input.val();
+ }
+ return this._base_formatDate(inst);
+ };
+
+ /*
+ * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
+ */
+ $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
+ $.datepicker._optionDatepicker = function (target, name, value) {
+ var inst = this._getInst(target),
+ name_clone;
+ if (!inst) {
+ return null;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var min = null,
+ max = null,
+ onselect = null,
+ overrides = tp_inst._defaults.evnts,
+ fns = {},
+ prop,
+ ret,
+ oldVal,
+ $target;
+ if (typeof name === 'string') { // if min/max was set with the string
+ if (name === 'minDate' || name === 'minDateTime') {
+ min = value;
+ } else if (name === 'maxDate' || name === 'maxDateTime') {
+ max = value;
+ } else if (name === 'onSelect') {
+ onselect = value;
+ } else if (overrides.hasOwnProperty(name)) {
+ if (typeof (value) === 'undefined') {
+ return overrides[name];
+ }
+ fns[name] = value;
+ name_clone = {}; //empty results in exiting function after overrides updated
+ }
+ } else if (typeof name === 'object') { //if min/max was set with the JSON
+ if (name.minDate) {
+ min = name.minDate;
+ } else if (name.minDateTime) {
+ min = name.minDateTime;
+ } else if (name.maxDate) {
+ max = name.maxDate;
+ } else if (name.maxDateTime) {
+ max = name.maxDateTime;
+ }
+ for (prop in overrides) {
+ if (overrides.hasOwnProperty(prop) && name[prop]) {
+ fns[prop] = name[prop];
+ }
+ }
+ }
+ for (prop in fns) {
+ if (fns.hasOwnProperty(prop)) {
+ overrides[prop] = fns[prop];
+ if (!name_clone) { name_clone = $.extend({}, name); }
+ delete name_clone[prop];
+ }
+ }
+ if (name_clone && isEmptyObject(name_clone)) { return; }
+ if (min) { //if min was set
+ if (min === 0) {
+ min = new Date();
+ } else {
+ min = new Date(min);
+ }
+ tp_inst._defaults.minDate = min;
+ tp_inst._defaults.minDateTime = min;
+ } else if (max) { //if max was set
+ if (max === 0) {
+ max = new Date();
+ } else {
+ max = new Date(max);
+ }
+ tp_inst._defaults.maxDate = max;
+ tp_inst._defaults.maxDateTime = max;
+ } else if (onselect) {
+ tp_inst._defaults.onSelect = onselect;
+ }
+
+ // Datepicker will override our date when we call _base_optionDatepicker when
+ // calling minDate/maxDate, so we will first grab the value, call
+ // _base_optionDatepicker, then set our value back.
+ if(min || max){
+ $target = $(target);
+ oldVal = $target.datetimepicker('getDate');
+ ret = this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
+ $target.datetimepicker('setDate', oldVal);
+ return ret;
+ }
+ }
+ if (value === undefined) {
+ return this._base_optionDatepicker.call($.datepicker, target, name);
+ }
+ return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
+ };
+
+ /*
+ * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
+ * it will return false for all objects
+ */
+ var isEmptyObject = function (obj) {
+ var prop;
+ for (prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ /*
+ * jQuery extend now ignores nulls!
+ */
+ var extendRemove = function (target, props) {
+ $.extend(target, props);
+ for (var name in props) {
+ if (props[name] === null || props[name] === undefined) {
+ target[name] = props[name];
+ }
+ }
+ return target;
+ };
+
+ /*
+ * Determine by the time format which units are supported
+ * Returns an object of booleans for each unit
+ */
+ var detectSupport = function (timeFormat) {
+ var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals
+ isIn = function (f, t) { // does the format contain the token?
+ return f.indexOf(t) !== -1 ? true : false;
+ };
+ return {
+ hour: isIn(tf, 'h'),
+ minute: isIn(tf, 'm'),
+ second: isIn(tf, 's'),
+ millisec: isIn(tf, 'l'),
+ microsec: isIn(tf, 'c'),
+ timezone: isIn(tf, 'z'),
+ ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),
+ iso8601: isIn(timeFormat, 'Z')
+ };
+ };
+
+ /*
+ * Converts 24 hour format into 12 hour
+ * Returns 12 hour without leading 0
+ */
+ var convert24to12 = function (hour) {
+ hour %= 12;
+
+ if (hour === 0) {
+ hour = 12;
+ }
+
+ return String(hour);
+ };
+
+ var computeEffectiveSetting = function (settings, property) {
+ return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];
+ };
+
+ /*
+ * Splits datetime string into date and time substrings.
+ * Throws exception when date can't be parsed
+ * Returns {dateString: dateString, timeString: timeString}
+ */
+ var splitDateTime = function (dateTimeString, timeSettings) {
+ // The idea is to get the number separator occurrences in datetime and the time format requested (since time has
+ // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
+ var separator = computeEffectiveSetting(timeSettings, 'separator'),
+ format = computeEffectiveSetting(timeSettings, 'timeFormat'),
+ timeParts = format.split(separator), // how many occurrences of separator may be in our format?
+ timePartsLen = timeParts.length,
+ allParts = dateTimeString.split(separator),
+ allPartsLen = allParts.length;
+
+ if (allPartsLen > 1) {
+ return {
+ dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),
+ timeString: allParts.splice(0, timePartsLen).join(separator)
+ };
+ }
+
+ return {
+ dateString: dateTimeString,
+ timeString: ''
+ };
+ };
+
+ /*
+ * Internal function to parse datetime interval
+ * Returns: {date: Date, timeObj: Object}, where
+ * date - parsed date without time (type Date)
+ * timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
+ */
+ var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
+ var date,
+ parts,
+ parsedTime;
+
+ parts = splitDateTime(dateTimeString, timeSettings);
+ date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);
+
+ if (parts.timeString === '') {
+ return {
+ date: date
+ };
+ }
+
+ parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);
+
+ if (!parsedTime) {
+ throw 'Wrong time format';
+ }
+
+ return {
+ date: date,
+ timeObj: parsedTime
+ };
+ };
+
+ /*
+ * Internal function to set timezone_select to the local timezone
+ */
+ var selectLocalTimezone = function (tp_inst, date) {
+ if (tp_inst && tp_inst.timezone_select) {
+ var now = date || new Date();
+ tp_inst.timezone_select.val(-now.getTimezoneOffset());
+ }
+ };
+
+ /*
+ * Create a Singleton Instance
+ */
+ $.timepicker = new Timepicker();
+
+ /**
+ * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
+ * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
+ * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
+ * @return {string}
+ */
+ $.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {
+ if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {
+ return tzMinutes;
+ }
+
+ var off = tzMinutes,
+ minutes = off % 60,
+ hours = (off - minutes) / 60,
+ iso = iso8601 ? ':' : '',
+ tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);
+
+ if (tz === '+00:00') {
+ return 'Z';
+ }
+ return tz;
+ };
+
+ /**
+ * Get the number in minutes that represents a timezone string
+ * @param {string} tzString formatted like "+0500", "-1245", "Z"
+ * @return {number} the offset minutes or the original string if it doesn't match expectations
+ */
+ $.timepicker.timezoneOffsetNumber = function (tzString) {
+ var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with "+1245"
+
+ if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset
+ return 0;
+ }
+
+ if (!/^(\-|\+)\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back
+ return tzString;
+ }
+
+ return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus
+ ((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)
+ parseInt(normalized.substr(3, 2), 10))); // minutes
+ };
+
+ /**
+ * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
+ * @param {Date} date
+ * @param {string} toTimezone formatted like "+0500", "-1245"
+ * @return {Date}
+ */
+ $.timepicker.timezoneAdjust = function (date, toTimezone) {
+ var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);
+ if (!isNaN(toTz)) {
+ date.setMinutes(date.getMinutes() + -date.getTimezoneOffset() - toTz);
+ }
+ return date;
+ };
+
+ /**
+ * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * n.b. The input value must be correctly formatted (reformatting is not supported)
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the timepicker() call
+ * @return {jQuery}
+ */
+ $.timepicker.timeRange = function (startTime, endTime, options) {
+ return $.timepicker.handleRange('timepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @param {string} method Can be used to specify the type of picker to be added
+ * @return {jQuery}
+ */
+ $.timepicker.datetimeRange = function (startTime, endTime, options) {
+ $.timepicker.handleRange('datetimepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @return {jQuery}
+ */
+ $.timepicker.dateRange = function (startTime, endTime, options) {
+ $.timepicker.handleRange('datepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `method` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param {string} method Can be used to specify the type of picker to be added
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @return {jQuery}
+ */
+ $.timepicker.handleRange = function (method, startTime, endTime, options) {
+ options = $.extend({}, {
+ minInterval: 0, // min allowed interval in milliseconds
+ maxInterval: 0, // max allowed interval in milliseconds
+ start: {}, // options for start picker
+ end: {} // options for end picker
+ }, options);
+
+ // for the mean time this fixes an issue with calling getDate with timepicker()
+ var timeOnly = false;
+ if(method === 'timepicker'){
+ timeOnly = true;
+ method = 'datetimepicker';
+ }
+
+ function checkDates(changed, other) {
+ var startdt = startTime[method]('getDate'),
+ enddt = endTime[method]('getDate'),
+ changeddt = changed[method]('getDate');
+
+ if (startdt !== null) {
+ var minDate = new Date(startdt.getTime()),
+ maxDate = new Date(startdt.getTime());
+
+ minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);
+ maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);
+
+ if (options.minInterval > 0 && minDate > enddt) { // minInterval check
+ endTime[method]('setDate', minDate);
+ }
+ else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check
+ endTime[method]('setDate', maxDate);
+ }
+ else if (startdt > enddt) {
+ other[method]('setDate', changeddt);
+ }
+ }
+ }
+
+ function selected(changed, other, option) {
+ if (!changed.val()) {
+ return;
+ }
+ var date = changed[method].call(changed, 'getDate');
+ if (date !== null && options.minInterval > 0) {
+ if (option === 'minDate') {
+ date.setMilliseconds(date.getMilliseconds() + options.minInterval);
+ }
+ if (option === 'maxDate') {
+ date.setMilliseconds(date.getMilliseconds() - options.minInterval);
+ }
+ }
+
+ if (date.getTime) {
+ other[method].call(other, 'option', option, date);
+ }
+ }
+
+ $.fn[method].call(startTime, $.extend({
+ timeOnly: timeOnly,
+ onClose: function (dateText, inst) {
+ checkDates($(this), endTime);
+ },
+ onSelect: function (selectedDateTime) {
+ selected($(this), endTime, 'minDate');
+ }
+ }, options, options.start));
+ $.fn[method].call(endTime, $.extend({
+ timeOnly: timeOnly,
+ onClose: function (dateText, inst) {
+ checkDates($(this), startTime);
+ },
+ onSelect: function (selectedDateTime) {
+ selected($(this), startTime, 'maxDate');
+ }
+ }, options, options.end));
+
+ checkDates(startTime, endTime);
+
+ selected(startTime, endTime, 'minDate');
+ selected(endTime, startTime, 'maxDate');
+
+ return $([startTime.get(0), endTime.get(0)]);
+ };
+
+ /**
+ * Log error or data to the console during error or debugging
+ * @param {Object} err pass any type object to log to the console during error or debugging
+ * @return {void}
+ */
+ $.timepicker.log = function () {
+ if (window.console) {
+ window.console.log.apply(window.console, Array.prototype.slice.call(arguments));
+ }
+ };
+
+ /*
+ * Add util object to allow access to private methods for testability.
+ */
+ $.timepicker._util = {
+ _extendRemove: extendRemove,
+ _isEmptyObject: isEmptyObject,
+ _convert24to12: convert24to12,
+ _detectSupport: detectSupport,
+ _selectLocalTimezone: selectLocalTimezone,
+ _computeEffectiveSetting: computeEffectiveSetting,
+ _splitDateTime: splitDateTime,
+ _parseDateTimeInternal: parseDateTimeInternal
+ };
+
+ /*
+ * Microsecond support
+ */
+ if (!Date.prototype.getMicroseconds) {
+ Date.prototype.microseconds = 0;
+ Date.prototype.getMicroseconds = function () { return this.microseconds; };
+ Date.prototype.setMicroseconds = function (m) {
+ this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));
+ this.microseconds = m % 1000;
+ return this;
+ };
+ }
+
+ /*
+ * Keep up with the version
+ */
+ $.timepicker.version = "1.5.0";
+
+})(jQuery); \ No newline at end of file
diff --git a/listcommands b/listcommands
new file mode 160000
+Subproject 7b3ab01a0a7067185d5faf9d9442cc8bd003fba
diff --git a/markasjunk2 b/markasjunk2
new file mode 160000
+Subproject 5b412366afdcbe467705bfaabafc2d436c295f1
diff --git a/message_highlight b/message_highlight
new file mode 160000
+Subproject 15830735d061f8d6de0d4db46d01a5f96f128b5
diff --git a/myrc_branch/CHANGELOG b/myrc_branch/CHANGELOG
new file mode 100644
index 0000000..28819d0
--- /dev/null
+++ b/myrc_branch/CHANGELOG
@@ -0,0 +1,7 @@
+VERSION COMMENT
+---------------------------------------------------------------------------------
+1.0 - Roundcube 0.9.5
+2.0 - Roundcube 1.0.3
+3.0 - Roundcube 1.0.3 beta branch
+3.0.1 - Define a MyRoundcube plugins bundle version constant
+3.0.2 - Release Roundcube 1.0.4 beta branch as stable
diff --git a/myrc_branch/LICENSE b/myrc_branch/LICENSE
new file mode 100644
index 0000000..56c3b5b
--- /dev/null
+++ b/myrc_branch/LICENSE
@@ -0,0 +1,671 @@
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/myrc_branch/README b/myrc_branch/README
new file mode 100644
index 0000000..a294b84
--- /dev/null
+++ b/myrc_branch/README
@@ -0,0 +1,8 @@
+myrc_branch
+-----------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/
+
+
+MyRoundcube Dev Team
+www.myroundcube.com \ No newline at end of file
diff --git a/myrc_branch/localization/cs_CZ.inc b/myrc_branch/localization/cs_CZ.inc
new file mode 100644
index 0000000..be53fda
--- /dev/null
+++ b/myrc_branch/localization/cs_CZ.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/myrc_branch/localization/cs_CZ.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: tachec - 01/22/2015 08:03:27
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Větev MyRoundcube';
+$labels['plugindescription'] = 'Pomocný doplněk pro informaci ostatním doplňkům o větvi MyRoundcube.';
+
+?> \ No newline at end of file
diff --git a/myrc_branch/localization/en_US.inc b/myrc_branch/localization/en_US.inc
new file mode 100644
index 0000000..c86b116
--- /dev/null
+++ b/myrc_branch/localization/en_US.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/myrc_branch/localization/en_US.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 05/08/2013 03:47:20
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'MyRoundcube branch';
+$labels['plugindescription'] = 'A helper plugin to indicate other plugins the MyRoundcube branch.';
+
+?> \ No newline at end of file
diff --git a/myrc_branch/localization/es_ES.inc b/myrc_branch/localization/es_ES.inc
new file mode 100644
index 0000000..d2db0c7
--- /dev/null
+++ b/myrc_branch/localization/es_ES.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/myrc_branch/localization/es_ES.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 01/11/2015 17:51:55
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Rama de MyRoundcube';
+$labels['plugindescription'] = 'Un complemento auxiliar para indicar otros complementos la rama de MyRoundcube que se usa.';
+
+?> \ No newline at end of file
diff --git a/myrc_branch/localization/revision.inc.php b/myrc_branch/localization/revision.inc.php
new file mode 100644
index 0000000..ca0a7ba
--- /dev/null
+++ b/myrc_branch/localization/revision.inc.php
@@ -0,0 +1,11 @@
+<?php
+
+$ps_localization_update = serialize(
+ array(
+ 'translator' => 'tachec',
+ 'language ' => 'cs_CZ',
+ 'date' => '01/22/2015 08:03:27'
+ )
+);
+
+?> \ No newline at end of file
diff --git a/myrc_branch/myrc_branch.php b/myrc_branch/myrc_branch.php
new file mode 100644
index 0000000..8195933
--- /dev/null
+++ b/myrc_branch/myrc_branch.php
@@ -0,0 +1,65 @@
+<?php
+#
+# This file is part of MyRoundcube "myrc_branch" plugin.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2014 Roland 'Rosali' Liebl
+# dev-team [at] myroundcube [dot] com
+# http://myroundcube.com
+#
+class myrc_branch extends rcube_plugin
+{
+ /* unified plugin properties */
+ static private $plugin = 'myrc_branch';
+ static private $author = 'myroundcube@mail4us.net';
+ static private $authors_comments = '<a href="http://myroundcube.com/myroundcube-plugins/helper-plugin?myrc_branch" target="_blank">Documentation</a>';
+ static private $version = '3.0.2';
+ static private $date = '26-12-2014';
+ static private $licence = 'GPL';
+ static private $requirements = array(
+ 'Roundcube' => '1.0.3',
+ 'PHP' => '5.3'
+ );
+
+ function init(){
+ define('MYRC_BRANCH', 'stable');
+ define('MYRC_BUNDLE', self::$version);
+ }
+
+ static public function about($keys = false){
+ $requirements = self::$requirements;
+ foreach(array('required_', 'recommended_') as $prefix){
+ if(is_array($requirements[$prefix.'plugins'])){
+ foreach($requirements[$prefix.'plugins'] as $plugin => $method){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $class->about($keys),
+ );
+ }
+ else{
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $plugin,
+ );
+ }
+ }
+ }
+ }
+ return array(
+ 'plugin' => self::$plugin,
+ 'version' => self::$version,
+ 'date' => self::$date,
+ 'author' => self::$author,
+ 'comments' => self::$authors_comments,
+ 'licence' => self::$licence,
+ 'requirements' => $requirements,
+ );
+ }
+}
+?> \ No newline at end of file
diff --git a/myrc_branch/package.xml b/myrc_branch/package.xml
new file mode 100644
index 0000000..32da4b9
--- /dev/null
+++ b/myrc_branch/package.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+ http://pear.php.net/dtd/tasks-1.0.xsd
+ http://pear.php.net/dtd/package-2.0
+ http://pear.php.net/dtd/package-2.0.xsd">
+ <name>myrc_branch</name>
+ <lead>
+ <name>Myroundcube Dev Team</name>
+ <user>rosali</user>
+ <email>dev-team@myroundcube.com</email>
+ <active>yes</active>
+ </lead><date>2014-12-26</date>
+ <version>
+ <release>3.0.2</release>
+ <api>3.0.2</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.gnu.org/licenses/gpl.html">GNU GPLv3+</license>
+</package>
diff --git a/myrc_sprites/CHANGELOG b/myrc_sprites/CHANGELOG
new file mode 100644
index 0000000..e7f19b2
--- /dev/null
+++ b/myrc_sprites/CHANGELOG
@@ -0,0 +1,4 @@
+VERSION COMMENT
+---------------------------------------------------------------------------------
+1.0 - Initial release
+1.0.1 - 1.0.7 - Merged more images into sprites \ No newline at end of file
diff --git a/myrc_sprites/LICENSE b/myrc_sprites/LICENSE
new file mode 100644
index 0000000..56c3b5b
--- /dev/null
+++ b/myrc_sprites/LICENSE
@@ -0,0 +1,671 @@
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/myrc_sprites/README b/myrc_sprites/README
new file mode 100644
index 0000000..3461049
--- /dev/null
+++ b/myrc_sprites/README
@@ -0,0 +1,8 @@
+myrc_sprites
+------------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/
+
+
+MyRoundcube Dev Team
+www.myroundcube.com \ No newline at end of file
diff --git a/myrc_sprites/localization/cs_CZ.inc b/myrc_sprites/localization/cs_CZ.inc
new file mode 100644
index 0000000..e45b9b9
--- /dev/null
+++ b/myrc_sprites/localization/cs_CZ.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/myrc_sprites/localization/cs_CZ.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: tachec - 01/22/2015 08:06:54
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'MyRoundcube sprity';
+$labels['plugindescription'] = 'Pomocný doplněk, který obsahuje sprity a sdílené obrázky, které využívají ostatní doplňky.';
+
+?> \ No newline at end of file
diff --git a/myrc_sprites/localization/en_US.inc b/myrc_sprites/localization/en_US.inc
new file mode 100644
index 0000000..8913db6
--- /dev/null
+++ b/myrc_sprites/localization/en_US.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/myrc_sprites/localization/en_US.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 05/08/2013 03:47:20
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'MyRoundcube sprites';
+$labels['plugindescription'] = 'A helper plugin which holds sprites and shared images for other plugins.';
+
+?> \ No newline at end of file
diff --git a/myrc_sprites/localization/es_ES.inc b/myrc_sprites/localization/es_ES.inc
new file mode 100644
index 0000000..0c18658
--- /dev/null
+++ b/myrc_sprites/localization/es_ES.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/myrc_sprites/localization/es_ES.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 01/11/2015 17:54:50
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Imágenes MyRoundcube';
+$labels['plugindescription'] = 'Un complemento auxiliar que contiene imágenes compartidas para distintos complementos.';
+
+?> \ No newline at end of file
diff --git a/myrc_sprites/localization/fi_FI.inc b/myrc_sprites/localization/fi_FI.inc
new file mode 100644
index 0000000..b0299ff
--- /dev/null
+++ b/myrc_sprites/localization/fi_FI.inc
@@ -0,0 +1,18 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/myrc_sprites/localization/fi_FI.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Markku Virtanen - 01/15/2015 09:31:58
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'MyRoundcube sprites';
+$labels['plugindescription'] = 'Helper lisosa joka sisältää spritet ja jaetut kuvat muille lisäosille.';
+
+?> \ No newline at end of file
diff --git a/myrc_sprites/localization/revision.inc.php b/myrc_sprites/localization/revision.inc.php
new file mode 100644
index 0000000..08e57f0
--- /dev/null
+++ b/myrc_sprites/localization/revision.inc.php
@@ -0,0 +1,11 @@
+<?php
+
+$ps_localization_update = serialize(
+ array(
+ 'translator' => 'tachec',
+ 'language ' => 'cs_CZ',
+ 'date' => '01/22/2015 08:06:54'
+ )
+);
+
+?> \ No newline at end of file
diff --git a/myrc_sprites/myrc_sprites.php b/myrc_sprites/myrc_sprites.php
new file mode 100644
index 0000000..e153166
--- /dev/null
+++ b/myrc_sprites/myrc_sprites.php
@@ -0,0 +1,91 @@
+<?php
+#
+# This file is part of MyRoundcube "myrc_sprites" plugin.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2014 Roland 'Rosali' Liebl
+# dev-team [at] myroundcube [dot] com
+# http://myroundcube.com
+#
+class myrc_sprites extends rcube_plugin
+{
+ /* unified plugin properties */
+ static private $plugin = 'myrc_sprites';
+ static private $author = 'myroundcube@mail4us.net';
+ static private $authors_comments = '<a href="http://myroundcube.com/myroundcube-plugins/helper-plugin?myrc_sprite" target="_blank">Documentation</a>';
+ static private $version = '1.0.7';
+ static private $date = '18-01-2015';
+ static private $licence = 'GPL';
+ static private $requirements = array(
+ 'Roundcube' => '1.0.3',
+ 'PHP' => '5.3'
+ );
+
+ private $images = array(
+ 'myrc_sprites' => 'png',
+ 'myrc_loading' => 'gif',
+ 'myrc_loading_samll' => 'gif',
+ 'myrc_ajax_loading' => 'gif',
+ );
+
+ function init(){
+ $skin = rcube::get_instance()->config->get('skin', 'larry');
+ if(file_exists(INSTALL_PATH . 'plugins/myrc_sprites/skins/' . $skin . '/myrc_sprites.css')){
+ $this->include_stylesheet('skins/' . $skin . '/myrc_sprites.css');
+ }
+ $this->add_hook('render_page', array($this, 'render_page'));
+ }
+
+ static public function about($keys = false){
+ $requirements = self::$requirements;
+ foreach(array('required_', 'recommended_') as $prefix){
+ if(is_array($requirements[$prefix.'plugins'])){
+ foreach($requirements[$prefix.'plugins'] as $plugin => $method){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $class->about($keys),
+ );
+ }
+ else{
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $plugin,
+ );
+ }
+ }
+ }
+ }
+ return array(
+ 'plugin' => self::$plugin,
+ 'version' => self::$version,
+ 'date' => self::$date,
+ 'author' => self::$author,
+ 'comments' => self::$authors_comments,
+ 'licence' => self::$licence,
+ 'requirements' => $requirements,
+ );
+ }
+
+ function render_page($p){
+ $rcmail = rcube::get_instance();
+ if($p['template'] == 'login'){
+ $skin = $rcmail->config->get('skin', 'larry');
+ $rcmail->output->add_script('/***************************************************/', 'foot');
+ $rcmail->output->add_script('/* MyRoundcube myrc_sprites plugin images pre-load */', 'foot');
+ $rcmail->output->add_script('/***************************************************/', 'foot');
+ foreach($this->images as $name => $type){
+ if(file_exists(INSTALL_PATH . 'plugins/myrc_sprites/skins/' . $skin . '/images/' . $name . '.' . $type)){
+ $rcmail->output->add_script('var ' . $name . ' = new Image(); ' . $name . '.src = "./plugins/myrc_sprites/skins/' . $skin . '/images/' . $name . '.' . $type . '";', 'foot');
+ }
+ }
+ $rcmail->output->add_script('/***************************************************/', 'foot');
+ }
+ }
+}
+?> \ No newline at end of file
diff --git a/myrc_sprites/package.xml b/myrc_sprites/package.xml
new file mode 100644
index 0000000..b563a4e
--- /dev/null
+++ b/myrc_sprites/package.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+ http://pear.php.net/dtd/tasks-1.0.xsd
+ http://pear.php.net/dtd/package-2.0
+ http://pear.php.net/dtd/package-2.0.xsd">
+ <name>myrc_sprites</name>
+ <lead>
+ <name>Myroundcube Dev Team</name>
+ <user>rosali</user>
+ <email>dev-team@myroundcube.com</email>
+ <active>yes</active>
+ </lead><date>2015-01-18</date>
+ <version>
+ <release>1.0.7</release>
+ <api>1.0.7</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.gnu.org/licenses/gpl.html">GNU GPLv3+</license>
+</package>
diff --git a/myrc_sprites/skins/classic/images/myrc_watermark.png b/myrc_sprites/skins/classic/images/myrc_watermark.png
new file mode 100644
index 0000000..03e3155
--- /dev/null
+++ b/myrc_sprites/skins/classic/images/myrc_watermark.png
Binary files differ
diff --git a/myrc_sprites/skins/larry/images/myrc_ajax_loading.gif b/myrc_sprites/skins/larry/images/myrc_ajax_loading.gif
new file mode 100644
index 0000000..99dc4eb
--- /dev/null
+++ b/myrc_sprites/skins/larry/images/myrc_ajax_loading.gif
Binary files differ
diff --git a/myrc_sprites/skins/larry/images/myrc_linen_bg.jpg b/myrc_sprites/skins/larry/images/myrc_linen_bg.jpg
new file mode 100644
index 0000000..5b674c5
--- /dev/null
+++ b/myrc_sprites/skins/larry/images/myrc_linen_bg.jpg
Binary files differ
diff --git a/myrc_sprites/skins/larry/images/myrc_loading.gif b/myrc_sprites/skins/larry/images/myrc_loading.gif
new file mode 100644
index 0000000..86d3f4d
--- /dev/null
+++ b/myrc_sprites/skins/larry/images/myrc_loading.gif
Binary files differ
diff --git a/myrc_sprites/skins/larry/images/myrc_loading_small.gif b/myrc_sprites/skins/larry/images/myrc_loading_small.gif
new file mode 100644
index 0000000..07da747
--- /dev/null
+++ b/myrc_sprites/skins/larry/images/myrc_loading_small.gif
Binary files differ
diff --git a/myrc_sprites/skins/larry/images/myrc_login_shadow.png b/myrc_sprites/skins/larry/images/myrc_login_shadow.png
new file mode 100644
index 0000000..e640f59
--- /dev/null
+++ b/myrc_sprites/skins/larry/images/myrc_login_shadow.png
Binary files differ
diff --git a/myrc_sprites/skins/larry/images/myrc_sprites.png b/myrc_sprites/skins/larry/images/myrc_sprites.png
new file mode 100644
index 0000000..ab6ab47
--- /dev/null
+++ b/myrc_sprites/skins/larry/images/myrc_sprites.png
Binary files differ
diff --git a/myrc_sprites/skins/larry/images/myrc_watermark.png b/myrc_sprites/skins/larry/images/myrc_watermark.png
new file mode 100644
index 0000000..03e3155
--- /dev/null
+++ b/myrc_sprites/skins/larry/images/myrc_watermark.png
Binary files differ
diff --git a/myrc_sprites/skins/larry/images/offsets.txt b/myrc_sprites/skins/larry/images/offsets.txt
new file mode 100644
index 0000000..c5d52e2
--- /dev/null
+++ b/myrc_sprites/skins/larry/images/offsets.txt
@@ -0,0 +1,21 @@
+Plugin start (x/y px) grid (x/y px)
+-----------------------------------------------------
+planner 0016 x 0008 no fixed grid
+calendar 0016 x 0368 24 x 24
+sticky_notes 0016 x 0528 24 x 24
+compose_in_taskbar 0016 x 0720 24 x 24
+jappix4roundcube 0016 x 0816 24 x 24
+carddav 0016 x 0912
+taskbar 0016 x 0976
+settings 0016 x 1040 24 x 24
+markbuttons 0016 x 1136 16 x 16
+scheduled_sending 0016 x 1256
+hmail_rules 0016 x 1360 24 x 24
+hmail_signature 0016 x 1424 24 x 24
+rss_feed 0016 x 1488 16 x 16
+vcard_attachments 0016 x 1552
+vcard_send 0016 x 1648
+vkeyboard 0016 x 1720
+webmail_notifier 0016 x 1784
+keyboard_shortcuts 0016 x 1848
+contextmenu 0016 x 2080 16 x 16 \ No newline at end of file
diff --git a/myrc_sprites/skins/larry/myrc_sprites.css b/myrc_sprites/skins/larry/myrc_sprites.css
new file mode 100644
index 0000000..2ad306f
--- /dev/null
+++ b/myrc_sprites/skins/larry/myrc_sprites.css
@@ -0,0 +1,30 @@
+.myrc_sprites,
+#taskbar a.button-sticky_notes:before,
+#mailboxlist li.mailbox.notes > a,
+#messagelist .notessmall,
+#messagemenu li a.notesaddlink span.notesadd,
+#rcm_messagemenu li a.notesaddlink span.notesadd,
+#sections-table #rcmrowaccountlink td.section,
+#sections-table #rcmrowkeyboard_shortcuts td.section {
+ background-image: url(images/myrc_sprites.png?v=1.0.7) !important;
+ background-repeat: no-repeat;
+}
+
+.myrc_loading {
+ background-image: url(images/myrc_loading.gif?v=1.0.7) !important;
+ background-repeat: no-repeat;
+}
+
+.myrc_loading_small {
+ background-image: url(images/myrc_loading_small.gif?v=1.0.7) !important;
+ background-repeat: no-repeat;
+}
+
+.myrc_sprites_core_buttons {
+ background-image: url(../../../../skins/larry/images/buttons.png?v=3e15.39327);
+ background-repeat: no-repeat;
+}
+
+.myrc_sprites_core_buttons.deletebutton {
+ background-position: -7px -380px;
+} \ No newline at end of file
diff --git a/plugin_manager/CHANGELOG b/plugin_manager/CHANGELOG
new file mode 100644
index 0000000..fafe14d
--- /dev/null
+++ b/plugin_manager/CHANGELOG
@@ -0,0 +1,145 @@
+VERSION COMMENT
+-----------------------------------------------------------------------------------
+20.0 - Implemented GUI to enable/disable plugins by Plugin
+ Manager Administrators
+20.0.1 - 20.0.2 - Roundcube 0.9.2 release
+20.0.3 - GUI improvements
+21.0 - 21.0.4 - Add third party plugins by GUI
+ - Database versioning implemented into GUI (0.9 branch only)
+21.0.5 - Show recommended plugins in update page
+21.0.6 - Fix: PHP Warning: Invalid argument supplied for foreach()
+ in ./plugins/plugin_manager/plugin_manager.php on line 3016
+21.0.7 - 21.0.8 - Implemented skins binding
+21.0.9 - Enable/disable "About" link and MyRoundcube watermark
+21.0.10 - 21.0.13 - GUI improvements (indicate if a plugin is not configured)
+21.0.14 - Strip slashes before config code is passed to eval
+21.0.15 - 21.0.19 - Roundcube 0.9.3
+21.0.20 - 21.0.23 - HTML code editor improvements
+21.0.24 - Added sqlite3 to database map
+21.0.25 - HTML code editor improvements
+21.1 - 21.1.1 - Roundcube 0.9.4
+21.1.2 - Added jsdialogs plugin to defaults
+21.1.3 - Added jappix4roundcube to defaults
+21.1.4 - Removed scrollbar fix
+21.1.5 - 21.1.6 - Fixed register action error 'plugin.summary'
+21.1.7 - Jappix4Roundcube adjustments
+21.1.8 - 21.1.10 - Added tabbed plugin to defaults
+21.1.11 - Fixed navigation handler
+21.1.12 - 21.1.13 - Fixed logo click for tabbed plugin
+21.1.14 - 21.1.15 - Always use https to download plugins
+21.1.16 - Lock database configuration section properly for demo accounts
+21.1.17 - Fix bug in defaults override
+21.1.18 - Added compose_myroundcube to defaults
+21.1.19 - Added vcard_send to defaults
+21.1.20 - 21.1.22 - Adjustments regarding deprecated plugins
+21.2.23 - Submit server IP when downloading plugins to fight PayPal
+ Chargebacks - of course only if user has agreed
+22.0 - Require a Plugin Manager update
+22.0.1 - Don't hide checkboxes in update page on low screen resolution
+22.0.2 - Improved visitor IP detection
+22.0.3 - Added companyaddressbook to defaults
+22.0.4 - 22.0.5 - Added debug code
+22.0.6 - Skip companyaddressbook_plus (helper) in plugin configuration section
+22.0.7 - Prevent logging of 'Illegal string offset' warnings (PHP 5.4)
+22.0.8 - 22.0.9 - Backwards compatibility Roundcube 0.8 branch.
+22.0.10 - Inject MyRoundcube watermark into blank pages for identities and folders steps
+22.0.11 - 22.0.12 - Added mysqladmin to defaults
+22.0.13 - 22.0.14 - Implemented mysqladmin plugin
+22.0.15 - Added User-Agent header to cURL requests
+22.0.16 - Added hmail_publicfolder to defaults
+23.0 - Prepair to be ready for Roundcube 1.0
+23.0.1 - Bugfix: https://code.google.com/p/myroundcube/issues/detail?id=606
+23.0.2 - 23.0.3 - Bugfix: http://trac.roundcube.net/ticket/1489486
+23.0.4 - Added google_oauth2 plugin to defaults
+23.0.5 - Bugfix: Don't break frame when clicking on missing plugin link
+23.0.6 - Bugfix: Display plugin version even if plugin is not registered/loaded automatically
+24.0 - Separate branch for Roundcube 0.9
+25.0 - Roundcube 1.0 compatibility
+25.0.1 - Remove importmessages plugin from defaults
+25.0.2 - Use rcube_utils::remote_addr() for IP detection
+25.0.3 - Workaround for server or php specific escaped quotes when saving preferences
+ into database
+25.0.4 - Add remove_attachments to defaults
+25.0.5 - Roundcube compatibility check
+25.0.6 - Skip calendar_plus and carddav_plus in plugins selector
+25.0.7 - End injected javascript consequently by semicolon
+25.0.8 - Better layout for low resolutions screens
+25.0.9 - Close button for MyRoundcube messages
+25.0.10 - Add cookie_config to defaults
+25.0.11 - Add imap_threads to defaults
+25.0.12 - Bug fix: https://code.google.com/p/myroundcube/issues/detail?id=647
+25.0.13 - Add hmail_search to defaults
+25.0.14 - Hide hmail_* plugins if usage of hmail_* plugins is disabled
+25.0.15 - Configurable real-time translation account
+25.0.16 - Add serveral plugins to plugins settings combobox
+25.0.17 - Remove global_alias plugin
+25.0.18 - Remove globaladdressbook plugin from list of supported third party plugins
+25.0.19 - 25.0.20 - Attempt to fix not reproduceable issue that maintenance mode can't be disabled
+25.0.21 - Add sabredav_migrate to defaults
+25.0.22 - Remove sabredav_migrate from defaults
+25.0.23 - Add hmail_sabredav_sync to defaults
+25.0.24 - Add hmail_roundcube_sync to defaults
+25.0.25 - Roundcube 1.0.1 release
+25.0.26 - Bugfix: Plugins binding (hide checkboxes if plugin is intended to be binded
+ to a specific settings value)
+25.0.27 - Add limit_skins plugin to defaults
+25.0.28 - Added MSSQL support (third party contribution (https://asphostpage.com/)
+25.0.29 - Remove copymessage from defaults
+25.0.30 - Remove default Roundcube plugins from 'Third party plugins' section unless required
+ as a dependency by any MyRoundcube plugin
+25.0.31 - Update $nodocs property
+25.0.32 - Implement rcube_db::limitquery
+25.0.33 - Remove css .boxcontent overwrite (Larry)
+25.0.34 - Remove IF NOT EXISTS clause from PostgreSQL database script
+25.0.35 - Fix loop in 'Settings' section if a helper plugin is missing
+25.0.36 - Implement translation accounts for delegated administrators
+25.0.37 - Add custom_login_logout to defaults
+ - Remove newsletter subscription
+ - Add forum registration link
+25.0.38 - Adopt markbuttons plugin
+26.0 - Provide Roundcube Core Patches in a single download location
+26.0.1 - HTTPS and better wording for Core Patches downloads
+26.0.2 - 26.0.3 - Update notifications feature
+26.0.4 - Fix anchor link navigation (plugin selector) if anchor is out of viewport
+26.0.5 - Scroll up when tabs for plugins navigation are clicked
+26.0.6 - 26-0.7 - Compatibility with pwtools 3.1.x
+26.0.8 - Roundcube 1.0.3 release
+26.0.9 - Release new core patch version
+26.0.10 - 26.0.12 - New calendar plugin compatibility
+26.0.13 - Fix "Customer account" link in Plugin Manager Center
+26.0.14 - 26.0.15 - Added config option to use MyRoundcube splitter hosts
+26.0.16 - Check download branch according to installed myrc_branch plugin
+26.0.17 - Fix a hard coded label
+26.0.18 - Add custom_log plugin to defaults
+26.0.19 - Fix Roundcube date alignment bug in message list
+26.0.20 - 26.0.21 - Skip deprecated configuration key hint for unregistered register drivers
+26.0.22 - Add myrc_branch to required plugins
+26.0.23 - Remove globaladdressbook from defaults
+26.0.24 - 26.0.25 - Implement "closed branch"
+26.0.26 - Remove calendar_plus from defaults
+26.0.27 - Add myrc_sprites to required plugins
+26.0.28 - Remove nabble plugin from defaults
+26.0.29 - Display calendar_plus in "About" step
+27.0 - Force Plugin Manager update
+27.0.1 - 27.0.2 - Roundcube Core patch for Roundcube 1.0.4
+27.0.3 - Remove http_request plugin form required plugins
+27.0.4 - Remove jqueryui plugin from required plugins (loaded over libgpl)
+27.0.5 - Fix missing thired party plugins labels
+27.0.6 - CSS improvement, remove version history younger than 20.0 from CHANGELOG
+27.0.7 - CSS improvement
+27.0.8 - Remove qtip from required plugins (loaded over libgpl)
+27.0.9 - Remove http_request class
+27.0.10 - Fix tinymce configuration parse error
+27.0.11 - Add password_plus plugin to defaults
+27.0.12 - 27.0.15 - Improve customer account download options
+27.0.16 - Use watermark from myrc_sprites
+28.0 - Merge Plugin Manager beta branch with stable branch
+28.0.1 - Show localization updates for *_plus plugins
+28.0.2 - Remove debug code
+28.0.3 - Use admin account as sender for update notifcations
+28.0.4 - 28.0.6 - Update Plugin Manager Center consent page
+28.0.7 - Don't show PHPMyAdmin link if plugin is disabled
+28.0.8 - Updated load_splitter configuration link
+28.0.9 - 28.0.10 - Roundcube 1.0.5 release
+28.0.11 - 28.0.12 - Fix misspelling
+29.0 - Implement request tokens \ No newline at end of file
diff --git a/plugin_manager/COMMENTS b/plugin_manager/COMMENTS
new file mode 100644
index 0000000..c63eb17
--- /dev/null
+++ b/plugin_manager/COMMENTS
@@ -0,0 +1,8 @@
+plugin_manager
+==============
+
+Version 21.0
+------------
+
+Database adjustments are required. If adjustment script does not launch
+automatically then run ./plugins/plugin_manager/SQL/[...].20131209.sql. \ No newline at end of file
diff --git a/plugin_manager/CONFIGHEADER b/plugin_manager/CONFIGHEADER
new file mode 100644
index 0000000..9f7047f
--- /dev/null
+++ b/plugin_manager/CONFIGHEADER
@@ -0,0 +1,9 @@
+/******************************************************************************************************
+ * *
+ * Plugin Manager - file-based configuration *
+ * (c) 2012 - ##YEAR## - myroundcube.com *
+ * Documentation: http://myroundcube.com/myroundcube-plugins/plugin-manager/file-based-administration *
+ * Contact: dev-team [at] myroundcube [dot] com *
+ * *
+ ******************************************************************************************************/
+ \ No newline at end of file
diff --git a/plugin_manager/EXAMPLE b/plugin_manager/EXAMPLE
new file mode 100644
index 0000000..97a59f6
--- /dev/null
+++ b/plugin_manager/EXAMPLE
@@ -0,0 +1,36 @@
+/*************************
+ * *
+ * Full featured example *
+ * *
+ *************************/
+
+// 'myplugin' => array( /* the plugin name */
+// 'label_name' => 'markbuttons.pluginname', /* label for the plugin */
+// 'label_description' => 'markbuttons.plugindescription', // label for the plugin description
+// 'label_inject' => false, // see idle_timeout for a valid expample; possible sources: eval, string, config or session
+// 'unset' => array(), /* an array of configs which have to be wiped out of preferences,
+// if plugin is set to inactive by the user */
+// 'localization' => 'localization', /* localization folder relative to plugin root folder */
+// 'buttons' => false, /* false or an array with valid jquery selector -> inactive: $('validselector').show() */
+// 'domains' => false, /* array with email domains, true or false */
+// 'hosts' => false, /* an array with hosts, true or false */
+// 'config' => './?_task=settings&_action=edit-prefs&_section=folders&_framed=1', /* false or a link to plugin configuration */
+// 'section' => 'folders', /* false or Roundcube's configuration section */
+// 'reload' => false, /* Reload after saving */
+// 'browser' => '$test = $browser->mz || $browser->chrome;', /* false or PHP code based on Roundcube's rcube_browser class */
+// 'eval' => array('$this->register_action("plugin.summary", array($this, "plugin_manager_dummy"));'), /* false or an unindexed array with PHP code to execute */
+// 'uninstall' => array('hide_blockquote_limit'), /* give the user the choice to remove prefs from server permanently
+// false or missing: keep prefs
+// true: autodetect prefs if supported by plugin
+// or an unindexed array with pref keys */
+// 'uninstall_request' => array(
+// 'action' => 'plugin.hmail_autoresponder-uninstall',
+// 'method' => 'post',
+// ), /* a registered plugin action and the method of calling the request */
+// 'uninstall_force' => false, /* uninstall request must be exectuted */
+// 'skins' => false, /* false or an array with skins where the plugin should be active array('classic', 'larry') */
+// 'active' => false /* load plugin by default */
+// 'protected' => true, /* an array of domains where users are not allowed to overwrite plugin defaults or
+// true | false or
+// an associated config key */
+// ), \ No newline at end of file
diff --git a/plugin_manager/LICENSE b/plugin_manager/LICENSE
new file mode 100644
index 0000000..11b1f5e
--- /dev/null
+++ b/plugin_manager/LICENSE
@@ -0,0 +1,84 @@
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+
+
+
+TERMS AND CONDITIONS
+--------------------
+
+User Agreement
+
+MyRoundcube Developers provides MyRoundcube Plugins (code) shall provide ("MyRoundcube Plugins") to
+you ("User") under the terms and conditions of this User Agreement ("the Agreement"). USER UNDERSTANDS
+AND ACKNOWLEDGES THAT USER IS ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers AND NOT THE WEB
+SITE WITH WHOM ANYTHING HAS ASSOCIATED TO BRING YOU THIS CODE. BY USING ("MyRoundcube Plugins") OR ANY
+PART OF ITS CODE YOU ARE AGREEING TO BECOME A PARTY TO THIS AGREEMENT WITH MyRoundcube Developers AND
+TO THE TERMS AND CONDITIONS HEREIN AND ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND ANY APPLICABLE
+ASSOCIATE STATEMENT IN THIS DOCUMENT. ALL MyRoundcube Developers SERVICES ARE PROVIDED ONLINE. PERSONS
+UNDER 13 MAY NOT BE ELEGIBLE TO ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers OR PURCHASE OUR
+SERVICES AND CODE DOWNLOADS.
+
+Acceptable Use Policy
+
+The following policy governs the use of the MyRoundcube Developers code. User will comply with the terms
+and spirit of the Agreement.
+
+(a) User shall not use MyRoundcube Plugins (code) in a manner that violates any city, state, national
+or international law or regulation, or which fails to comply with accepted Internet protocol. User
+shall not attempt to interfere in any way with MyRoundcube Plugins networks or network security, or
+attempt to use the MyRoundcube Plugins code to gain unauthorized access to any other computer system.
+(b) User shall at all times provide MyRoundcube Developers with accurate information. User shall not
+interfere in any way with another User's use of, or MyRoundcube Developers provision of the MyRoundcube
+Plugins. User shall not resell, rent, lease, grant a security interest in, or make commercial use of
+the MyRoundcube Plugins without the express written consent of MyRoundcube Developers.
+(c) User agrees not to transfer MyRoundcube Plugins (code) for gain or otherwise. Transfer of such code
+will result in termination of contract with end user.
+
+Limitation of Liability
+
+UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, TORT, CONTRACT, OR OTHERWISE, SHALL MyRoundcube
+Developers OR ITS LICENSORS OR RESELLERS BE LIABLE TO USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL,
+INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES RESULTING
+FROM THE USE OF OR THE INABILITY TO USE THE MyRoundcube Plugins (code), THE PERFORMANCE OF MyRoundcube
+Plugins (code) SERVICE, OR DAMAGES FOR LOSS OF GOODWILL, BUSINESS PROFIT, BUSINESS STOPPAGE, LOSS OF
+DATA OR BUSINESS INFORMATION, COMPUTER DAMAGE, OR DAMAGES RESULTING FROM UNAUTHORIZED ACCESS TO OR
+CHANGES MADE TO USER'S TRANSMISSIONS OR DATA, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES.
+IN NO EVENT WILL MyRoundcube Developers BE LIABLE FOR ANY DAMAGES IN EXCESS OF WHAT ANYTHING MyRoundcube
+Developers RECEIVED FROM USER FOR THE MyRoundcube Plugins (code).
+
+Terms
+
+You (the User) are permitted to use the code on unlimited servers you may own, rented or leased, as
+long as you own, rent or lease the server in which MyRoundcube plugins code is hosted.
+Exclusive: You (the User) agree to use the code in one server at a time. Multiple server deployments
+(multiserver setup), clusters or any other form of deployment that simultaneously executes MyRoundcube
+plugins in a live environment must purchase a separate download per server or installation thereof.
+
+Warranties
+
+Our code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+Terms Modifications
+
+We reserve the right to change or modify our Terms and Conditions at any time without prior notice.
+For questions, please contact our team at dev-team [at] myroundcube [dot] com.
+
+Copyright (c) 2012 - 2014
+MyRoundcube.com - A Division of Informative Computing Consultants, LLC.
+All rights reserved
+
+Informative Computing Consultants, LLC.
+21741 NW 8th CT
+Pembroke Pines
+Florida, 33029
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
diff --git a/plugin_manager/README b/plugin_manager/README
new file mode 100644
index 0000000..5198c1c
--- /dev/null
+++ b/plugin_manager/README
@@ -0,0 +1,8 @@
+plugin_manager
+--------------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/plugin-manager
+
+
+MyRoundcube Dev Team
+www.myroundcube.com \ No newline at end of file
diff --git a/plugin_manager/SQL/mssql.20131209.sql b/plugin_manager/SQL/mssql.20131209.sql
new file mode 100644
index 0000000..19107fc
--- /dev/null
+++ b/plugin_manager/SQL/mssql.20131209.sql
@@ -0,0 +1,4 @@
+--az initben mar benne van
+
+UPDATE [system] SET [value]='initial|20131209' WHERE [name]='myrc_plugin_manager'
+GO
diff --git a/plugin_manager/SQL/mssql.initial.sql b/plugin_manager/SQL/mssql.initial.sql
new file mode 100644
index 0000000..f800588
--- /dev/null
+++ b/plugin_manager/SQL/mssql.initial.sql
@@ -0,0 +1,20 @@
+IF NOT EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'[dbo].[plugin_manager]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
+CREATE TABLE [plugin_manager] (
+ [id] int NOT NULL IDENTITY(1,1),
+ [conf] nvarchar(MAX) NOT NULL,
+ [value] nvarchar(MAX),
+ [type] nvarchar(MAX),
+ PRIMARY KEY ([id])
+)
+GO
+
+IF NOT EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'[dbo].[system]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
+CREATE TABLE [system] (
+ [name] nvarchar(64) NOT NULL,
+ [value] nvarchar(MAX),
+ PRIMARY KEY([name])
+)
+GO
+
+INSERT INTO [system] (name, value) VALUES ('myrc_plugin_manager', 'initial|20131209')
+GO \ No newline at end of file
diff --git a/plugin_manager/SQL/mysql.20131209.sql b/plugin_manager/SQL/mysql.20131209.sql
new file mode 100644
index 0000000..1afcbda
--- /dev/null
+++ b/plugin_manager/SQL/mysql.20131209.sql
@@ -0,0 +1,4 @@
+ALTER TABLE `plugin_manager` DROP FOREIGN KEY `user_id_fk_plugin_manager` ;
+ALTER TABLE `plugin_manager` DROP `user_id`;
+ALTER TABLE `plugin_manager` ENGINE=MyISAM;
+UPDATE `system` SET `value`='initial|20131209' WHERE `name`='myrc_plugin_manager'; \ No newline at end of file
diff --git a/plugin_manager/SQL/mysql.initial.sql b/plugin_manager/SQL/mysql.initial.sql
new file mode 100644
index 0000000..e7553d5
--- /dev/null
+++ b/plugin_manager/SQL/mysql.initial.sql
@@ -0,0 +1,21 @@
+CREATE TABLE IF NOT EXISTS `plugin_manager` (
+ `id` int(10) NOT NULL AUTO_INCREMENT,
+ `user_id` int(10) unsigned NOT NULL,
+ `conf` text NOT NULL,
+ `value` text,
+ `type` text,
+ PRIMARY KEY (`id`),
+ KEY `user_id` (`user_id`),
+ KEY `user_id_index` (`user_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
+
+CREATE TABLE IF NOT EXISTS `system` (
+ `name` varchar(64) NOT NULL,
+ `value` mediumtext,
+ PRIMARY KEY(`name`)
+);
+
+INSERT INTO `system` (name, value) VALUES ('myrc_plugin_manager', 'initial');
+
+ALTER TABLE `plugin_manager`
+ ADD CONSTRAINT `user_id_fk_plugin_manager` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/plugin_manager/SQL/pgsql.20131209.sql b/plugin_manager/SQL/pgsql.20131209.sql
new file mode 100644
index 0000000..2edd9bd
--- /dev/null
+++ b/plugin_manager/SQL/pgsql.20131209.sql
@@ -0,0 +1,3 @@
+ALTER TABLE plugin_manager DROP CONSTRAINT plugin_manager_user_id_fkey;
+ALTER TABLE plugin_manager DROP user_id;
+UPDATE "system" SET value='initial|20131209' WHERE name='myrc_plugin_manager'; \ No newline at end of file
diff --git a/plugin_manager/SQL/pgsql.initial.sql b/plugin_manager/SQL/pgsql.initial.sql
new file mode 100644
index 0000000..5fa498b
--- /dev/null
+++ b/plugin_manager/SQL/pgsql.initial.sql
@@ -0,0 +1,17 @@
+CREATE TABLE plugin_manager (
+ id serial NOT NULL,
+ user_id integer NOT NULL
+ REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE,
+ conf text NOT NULL,
+ value text,
+ type text,
+ PRIMARY KEY (id)
+);
+CREATE INDEX ix_plugin_manager_user_id ON users (user_id);
+
+CREATE TABLE IF NOT EXISTS "system" (
+ name varchar(64) NOT NULL PRIMARY KEY,
+ value text
+);
+
+INSERT INTO "system" (name, value) VALUES ('myrc_plugin_manager', 'initial'); \ No newline at end of file
diff --git a/plugin_manager/SQL/sqlite.20131209.sql b/plugin_manager/SQL/sqlite.20131209.sql
new file mode 100644
index 0000000..1fa9cd6
--- /dev/null
+++ b/plugin_manager/SQL/sqlite.20131209.sql
@@ -0,0 +1,48 @@
+CREATE TABLE 'plugin_manager_tmp' (
+ 'id' INTEGER NOT NULL PRIMARY KEY,
+ 'user_id' INT(10) NOT NULL,
+ 'conf' TEXT NOT NULL,
+ 'value' TEXT,
+ 'type' TEXT
+) ;
+
+INSERT INTO plugin_manager_tmp (
+ 'id',
+ 'user_id',
+ 'conf',
+ 'value',
+ 'type'
+)
+SELECT
+ 'id',
+ 'user_id',
+ 'conf',
+ 'value',
+ 'type'
+FROM plugin_manager;
+
+DROP TABLE plugin_manager;
+
+CREATE TABLE 'plugin_manager' (
+ 'id' INTEGER NOT NULL PRIMARY KEY,
+ 'conf' TEXT NOT NULL,
+ 'value' TEXT,
+ 'type' TEXT
+) ;
+
+INSERT INTO plugin_manager (
+ 'id',
+ 'conf',
+ 'value',
+ 'type'
+)
+SELECT
+ 'id',
+ 'conf',
+ 'value',
+ 'type'
+FROM plugin_manager_tmp;
+
+DROP TABLE plugin_manager_tmp;
+
+UPDATE 'system' SET value='initial|20131209' WHERE name='myrc_plugin_manager'; \ No newline at end of file
diff --git a/plugin_manager/SQL/sqlite.initial.sql b/plugin_manager/SQL/sqlite.initial.sql
new file mode 100644
index 0000000..c1b77a8
--- /dev/null
+++ b/plugin_manager/SQL/sqlite.initial.sql
@@ -0,0 +1,11 @@
+CREATE TABLE IF NOT EXISTS 'plugin_manager' ( 'id' integer NOT NULL PRIMARY KEY AUTOINCREMENT, 'user_id' INT(10) NOT NULL, 'conf' TEXT NOT NULL, 'value' TEXT, 'type' TEXT,
+ CONSTRAINT 'plugin_manager_ibfk_1' FOREIGN KEY ('user_id') REFERENCES 'users'
+ ('user_id') ON DELETE
+ CASCADE ON UPDATE CASCADE );
+
+CREATE TABLE IF NOT EXISTS 'system' (
+ name varchar(64) NOT NULL PRIMARY KEY,
+ value text NOT NULL
+);
+
+INSERT INTO system (name, value) VALUES ('myrc_plugin_manager', 'initial'); \ No newline at end of file
diff --git a/plugin_manager/defaults.inc.php b/plugin_manager/defaults.inc.php
new file mode 100644
index 0000000..9ade228
--- /dev/null
+++ b/plugin_manager/defaults.inc.php
@@ -0,0 +1,654 @@
+<?php
+$config['plugin_manager_third_party_plugins'] = array(
+ //'keyboard_shortcuts' => 'https://github.com/corbosman/keyboard_shortcuts',
+ //'listcommands' => 'https://github.com/corbosman/listcommands',
+ //'contextmenu' => 'https://github.com/JohnDoh/Roundcube-Plugin-Context-Menu',
+ //'markasjunk2' => 'https://github.com/JohnDoh/Roundcube-Plugin-Mark-as-Junk-2/',
+ 'jqueryui' => 'https://github.com/roundcube/roundcubemail/tree/release-1.0/plugins/jqueryui',
+ 'database_attachments' => 'https://github.com/roundcube/roundcubemail/tree/release-1.0/plugins/database_attachments',
+ 'password' => 'https://github.com/roundcube/roundcubemail/tree/release-1.0/plugins/password',
+);
+
+$config['plugin_manager_unauth'] = array(
+ 'vkeyboard' => true,
+ 'pwtools' => true,
+ 'webmail_notifier' => true,
+ 'checked_identities' => true,
+ 'detach_attachments' => true,
+ 'summary' => true,
+ 'jappix4roundcube' => true,
+);
+
+/* Full featured example */
+// 'myplugin' => array( /* the plugin name */
+// 'label_name' => 'markbuttons.pluginname', /* label for the plugin */
+// 'label_description' => 'markbuttons.plugindescription', // label for the plugin description
+// 'label_inject' => false, // see idle_timeout for a valid expample; possible sources: eval, string, config or session
+// 'unset' => array(), /* an array of configs which have to be wiped out of preferences,
+// if plugin is set to inactive by the user */
+// 'localization' => 'localization', /* localization folder relative to plugin root folder */
+// 'buttons' => false, /* false or an array with valid jquery selector -> inactive: $('validselector').show */
+// 'domains' => false, /* array with email domains, true or false */
+// 'hosts' => false, /* an array with hosts, true or false */
+// 'protected' => true, /* an array of domains where users are not allowed to overwrite or
+// true | false or
+// an associated config key */
+// 'config' => false, /* See archivefolder plugin for a valid example */
+// 'section' => false, /* See archivefolder plugin for a valid example */
+// 'reload' => false, /* Reload after saving */
+// 'browser' => false, /* See webmail_notifier config (below) for a valid example */
+// 'eval' => false, /* see summary config (below) for a valid example */
+// 'uninstall' => false, /* give the user the choice to remove prefs from server permanently
+// false or missing: keep prefs
+// true: autodetect prefs if supported by plugin or
+// unindexed array with pref keys */
+// 'uninstall_request' => false, /* hmail_autoresponder for a valid example */
+// 'uninstall_force' => false, /* force the uninstall request */
+// 'skins' => false, /* false or an array with skins where the plugin should be active array('classic', 'litecube-f') */
+// 'active' => false /* default */
+// ),
+/* End full featured example */
+
+$config['plugin_manager_defaults'] = array(
+ 'globalplugins' => array(
+ 'db_config' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'google_oauth2' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'custom_logo' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'custom_login_logout' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'jsdialogs' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'jscolor' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'helpui' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'summary' => array(
+ 'label_name' => 'summary.pluginname',
+ 'label_description' => 'summary.plugindescription',
+ 'unset' => 'nosummary',
+ //'eval' => array('$this->register_action("plugin.summary", array($this, "plugin_manager_dummy"));'),
+ //'uninstall' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'checkbox' => array(
+ 'label_name' => 'checkbox.pluginname',
+ 'label_description' => 'checkbox.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'disclaimer' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'google_analytics' => array(
+ 'label_name' => 'google_analytics.pluginname',
+ 'label_description' => 'google_analytics.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'domain_check' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'placeholder' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'sabredav' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'demologin' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'terms' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'register' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'lang_sel' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'limit_skins' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'rcguard' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'captcha' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'newuser' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'new_user_dialog' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'dnsbl' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'persistent_login' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'taskbar' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'impressum' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'contactus' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'crawler' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'checked_identities' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'identities_smtp' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'impersonate' => array(
+ 'defer' => true,
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'hmail_login' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'hmail_autoban' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'hmail_publicfolder' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'hmail_search' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'hmail_sabredav_sync' => array(
+ 'protected' => true,
+ 'active' => false,
+ ),
+ 'hmail_roundcube_sync' => array(
+ 'protected' => true,
+ 'active' => false,
+ ),
+ 'blockspamsending' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'dblog' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'mysqladmin' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ ),
+ 'performance' => array(
+ 'load_splitter' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'tabbed' => array(
+ 'protected' => true,
+ 'active' => false
+ ),
+ ),
+ 'uisettings' => array(
+ 'contextmenu' => array(
+ 'label_name' => 'contextmenu.pluginname',
+ 'label_description' => 'contextmenu.plugindescription',
+ 'defer' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'markbuttons' => array(
+ 'label_name' => 'markbuttons.pluginname',
+ 'label_description' => 'markbuttons.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'google_ads' => array(
+ 'label_name' => 'google_ads.pluginname',
+ 'label_description' => 'google_ads.plugindescription',
+ 'reload' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'vkeyboard' => array(
+ 'label_name' => 'vkeyboard.pluginname',
+ 'label_description' => 'vkeyboard.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'keyboard_shortcuts' => array(
+ 'label_name' => 'keyboard_shortcuts.keyboard_shortcuts',
+ 'label_description' => 'keyboard_shortcuts.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'folderbuttons' => array(
+ 'label_name' => 'folderbuttons.pluginname',
+ 'label_description' => 'folderbuttons.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ ),
+ 'messagescomposition' => array(
+ 'save_in_same_folder' => array(
+ 'label_name' => 'save_in_same_folder.pluginname',
+ 'label_description' => 'save_in_same_folder.plugindescription',
+ 'active' => false,
+ 'config_label' => 'replysamefolder',
+ 'protected' => 'reply_same_folder'
+ ),
+ 'compose_myroundcube' => array(
+ 'label_name' => 'compose_myroundcube.pluginname',
+ 'label_description' => 'compose_myroundcube.plugindescription',
+ 'active' => false,
+ 'config_label' => 'composeextwin',
+ 'protected' => 'compose_extwin'
+ ),
+ 'compose_in_taskbar' => array(
+ 'label_name' => 'compose_in_taskbar.pluginname',
+ 'label_description' => 'compose_in_taskbar.plugindescription',
+ 'reload' => true,
+ 'active' => false,
+ 'config_label' => 'composeextwin',
+ 'protected' => 'compose_extwin'
+ ),
+ 'detach_attachments' => array(
+ 'label_name' => 'detach_attachments.pluginname',
+ 'label_description' => 'detach_attachments.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'listcommands' => array(
+ 'label_name' => 'listcommands.pluginname',
+ 'label_description' => 'listcommands.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'scheduled_sending' => array(
+ 'label_name' => 'scheduled_sending.pluginname',
+ 'label_description' => 'scheduled_sending.plugindescription',
+ 'uninstall_request' => array( //Note: this will give the user the choice to remove all scheduled messages from sending queue.
+ 'action' => 'plugin.scheduled_sending_uninstall',
+ 'method' => 'post'
+ ),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'vcard_attach' => array(
+ 'label_name' => 'vcard_attach.pluginname',
+ 'label_description' => 'vcard_attach.plugindescription',
+ 'unset' => 'attach_vcard',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'vcard_send' => array(
+ 'label_name' => 'vcard_send.pluginname',
+ 'label_description' => 'vcard_send.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'embed_images' => array(
+ 'label_name' => 'embed_images.pluginname',
+ 'label_description' => 'embed_images.plugindescription',
+ 'protected' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ ),
+ 'messagesdisplaying' => array(
+ 'imap_threads' => array(
+ 'label_name' => 'imap_threads.pluginname',
+ 'label_description' => 'imap_threads.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'message_highlight' => array(
+ 'label_name' => 'message_highlight.mh_title',
+ 'label_description' => 'message_highlight.plugindescription',
+ 'config' => './?_task=settings&_action=edit-prefs&_section=mh_preferences&_framed=1',
+ 'section' => 'mh_preferences',
+ 'uninstall' => array('message_highlight'),
+ 'reload' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'hide_blockquote' => array(
+ 'label_name' => 'hide_blockquote.pluginname',
+ 'label_description' => 'hide_blockquote.plugindescription',
+ 'config' => './?_task=settings&_action=edit-prefs&_section=mailview&_framed=1',
+ 'section' => 'mailview',
+ 'uninstall' => array('hide_blockquote_limit'),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'vcard_attachments' => array(
+ 'label_name' => 'vcard_attachments.pluginname',
+ 'label_description' => 'vcard_attachments.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ ),
+ 'messagesmanagement' => array(
+ 'remove_attachments' => array(
+ 'label_name' => 'remove_attachments.pluginname',
+ 'label_description' => 'remove_attachments.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'jappix4roundcube' => array(
+ 'label_name' => 'jappix4roundcube.pluginname',
+ 'label_description' => 'jappix4roundcube.plugindescription',
+ 'reload' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'hmail_autoresponder' => array(
+ 'label_name' => 'hmail_autoresponder.pluginname',
+ 'label_description' => 'hmail_autoresponder.plugindescription',
+ 'config' => './?_task=settings&_action=plugin.hmail_autoresponder&_framed=1',
+ 'section' => 'accountlink',
+ 'uninstall_force' => true,
+ 'uninstall_request' => array(
+ 'action' => 'plugin.hmail_autoresponder-uninstall',
+ 'method' => 'post',
+ ),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'hmail_forwarding' => array(
+ 'label_name' => 'hmail_forwarding.pluginname',
+ 'label_description' => 'hmail_forwarding.plugindescription',
+ 'config' => './?_task=settings&_action=plugin.hmail_forwarding&_framed=1',
+ 'section' => 'accountlink',
+ 'uninstall_force' => true,
+ 'uninstall_request' => array(
+ 'action' => 'plugin.hmail_forwarding-uninstall',
+ 'method' => 'post',
+ ),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'hmail_signature' => array(
+ 'label_name' => 'hmail_signature.signature',
+ 'label_description' => 'hmail_signature.plugindescription',
+ 'config' => './?_task=settings&_action=plugin.hmail_signature&_framed=1',
+ 'section' => 'accountlink',
+ 'uninstall_force' => true,
+ 'uninstall_request' => array(
+ 'action' => 'plugin.hmail_signature-uninstall',
+ 'method' => 'post',
+ ),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'hmail_rules' => array(
+ 'label_name' => 'hmail_rules.pluginname',
+ 'label_description' => 'hmail_rules.plugindescription',
+ 'config' => './?_task=settings&_action=plugin.hmail_rules&_framed=1',
+ 'section' => 'accountlink',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'identities_imap' => array(
+ 'label_name' => 'identities_imap.pluginname',
+ 'label_description' => 'identities_imap.plugindescription',
+ 'uninstall_request' => array(
+ 'action' => 'plugin.identities_imap_uninstall',
+ 'method' => 'post',
+ ),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'hmail_pop3' => array(
+ 'label_name' => 'hmail_pop3.pluginname',
+ 'label_description' => 'hmail_pop3.plugindescription',
+ 'config' => './?_task=settings&_action=plugin.hmail_pop3&_framed=1',
+ 'section' => 'accountlink',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'archivefolder' => array(
+ 'label_name' => 'archivefolder.pluginname',
+ 'label_description' => 'archivefolder.plugindescription',
+ 'config' => './?_task=settings&_action=edit-prefs&_section=folders&_framed=1',
+ 'section' => 'folders',
+ 'uninstall' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'markasjunk2' => array(
+ 'label_name' => 'markasjunk2.pluginname',
+ 'label_description' => 'markasjunk2.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'zipdownload' => array(
+ 'label_name' => 'zipdownload.pluginname',
+ 'label_description' => 'zipdownload.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'newmail_notifier' => array(
+ 'label_name' => 'newmail_notifier.pluginname',
+ 'label_description' => 'newmail_notifier.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'webmail_notifier' => array(
+ 'label_name' => 'webmail_notifier.pluginname',
+ 'label_description' => 'webmail_notifier.plugindescription',
+ 'browser' => '$test = $browser->mz || $browser->chrome;',
+ 'uninstall' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ ),
+ 'addressbook' => array(
+ 'carddav' => array(
+ 'label_name' => 'carddav.pluginname',
+ 'label_description' => 'carddav.plugindescription',
+ 'reload' => true,
+ 'uninstall_request' => array(
+ 'action' => 'plugin.carddav_uninstall',
+ 'method' => 'post'
+ ),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'carddav_plus' => array(
+ 'active' => false,
+ 'protected' => true,
+ 'autoload' => true,
+ ),
+ 'plaxo_contacts' => array(
+ 'label_name' => 'plaxo_contacts.plaxocontacts',
+ 'label_description' => 'plaxo_contacts.plugindescription',
+ 'unset' => 'use_plaxo_abook',
+ 'config' => './?_task=settings&_action=edit-prefs&_section=addressbook&_framed=1',
+ 'section' => 'addressbook',
+ 'uninstall' => true,
+ 'uninstall_request' => array(
+ 'action' => 'plugin.plaxo_contacts_uninstall',
+ 'method' => 'post',
+ ),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'companyaddressbook' => array(
+ 'label_name' => 'companyaddressbook.pluginname',
+ 'label_description' => 'companyaddressbook.plugindescription',
+ 'protected' => true,
+ 'active' => false
+ ),
+ ),
+ 'settings' => array(
+ 'moreuserinfo' => array(
+ 'label_name' => 'moreuserinfo.pluginname',
+ 'label_description' => 'moreuserinfo.plugindescription',
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'cookie_config' => array(
+ 'label_name' => 'cookie_config.pluginname',
+ 'label_description' => 'cookie_config.plugindescription',
+ 'protected' => true,
+ 'active' => false
+ ),
+ ),
+ 'calendaring' => array(
+ 'planner' => array(
+ 'label_name' => 'planner.planner',
+ 'label_description' => 'planner.plugindescription',
+ 'buttons' => array('#planner_button'),
+ 'uninstall' => true,
+ 'uninstall_request' => array(
+ 'action' => 'plugin.planner_uninstall',
+ 'method' => 'post',
+ ),
+ 'reload' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'sticky_notes' => array(
+ 'label_name' => 'sticky_notes.pluginname',
+ 'label_description' => 'sticky_notes.plugindescription',
+ 'buttons' => array('#sticky_notes_button'),
+ 'reload' => true,
+ 'uninstall_request' => array(
+ 'action' => 'plugin.sticky_notes_unregister',
+ 'method' => 'post',
+ ),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'calendar' => array(
+ 'label_name' => 'calendar.pluginname',
+ 'label_description' => 'calendar.plugindescription',
+ 'buttons' => array('.button-calendar', '#rcmrowcalendar'),
+ 'reload' => true,
+ 'config' => './?_task=settings&_action=edit-prefs&_section=calendar&_framed=1',
+ 'section' => 'calendar',
+ 'active' => false,
+ 'protected' => true
+ ),
+ ),
+ //'backend' => array(
+ //),
+ 'misc' => array(
+ 'tinymce' => array(
+ 'label_name' => 'tinymce.pluginname',
+ 'label_description' => 'tinymce.plugindescription',
+ 'protected' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'password_plus' => array(
+ 'label_name' => 'password_plus.pluginname',
+ 'label_description' => 'password_plus.plugindescription',
+ 'protected' => true,
+ 'active' => false
+ ),
+ 'hmail_password' => array(
+ 'label_name' => 'hmail_password.changepasswd',
+ 'label_description' => 'hmail_password.plugindescription',
+ 'protected' => false,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'hmail_spamfilter' => array(
+ 'label_name' => 'hmail_spamfilter.spamfilter',
+ 'label_description' => 'hmail_spamfilter.plugindescription',
+ 'protected' => false,
+ 'config' => './?_task=settings&_action=plugin.hmail_spamfilter&_framed=1',
+ 'section' => 'accountlink',
+ 'uninstall' => true,
+ 'uninstall_force' => true,
+ 'uninstall_request' => array(
+ 'action' => 'plugin.hmail_spamfilter-uninstall',
+ 'method' => 'post',
+ ),
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'pwtools' => array(
+ 'label_name' => 'pwtools.passwordrecovery',
+ 'label_description' => 'pwtools.plugindescription',
+ 'unset' => array('pwtoolsaddress', 'pwtoolsquestion', 'pwtoolsanswer', 'pwtoolsenabled'),
+ 'config' => '.?_task=settings&_action=plugin.pwtools&_framed=1',
+ 'section' => 'accountlink',
+ 'uninstall' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'idle_timeout' => array(
+ 'label_name' => 'idle_timeout.pluginname',
+ 'label_description' => 'idle_timeout.plugindescription',
+ 'label_inject' => array('eval', '$s = $this->rcmail->config->get("idle_timeout_warning", 18) + $this->rcmail->config->get("idle_timeout_logout", 2);'),
+ 'reload' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'rss_feeds' => array(
+ 'label_name' => 'rss_feeds.rss_plugin_name',
+ 'label_description' => 'rss_feeds.plugindescription',
+ 'active' => false,
+ 'protected' => true
+ ),
+ 'wrapper' => array(
+ 'label_name' => 'wrapper.pluginname',
+ 'label_description' => 'wrapper.plugindescription',
+ 'reload' => true,
+ 'uninstall' => true,
+ 'active' => false,
+ 'protected' => true
+ ),
+ ),
+);
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/bg_BG.inc b/plugin_manager/localization/bg_BG.inc
new file mode 100644
index 0000000..bd0417e
--- /dev/null
+++ b/plugin_manager/localization/bg_BG.inc
@@ -0,0 +1,134 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/bg_BG.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Alkin Yusufov - 05/03/2013 23:01:23
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Управление на добавки';
+$labels['plugindescription'] = 'Управлението на добавки дава възможност за активиране и/или деактивиране на добавки за всеки потребителски профил поотделно, като същевременно дава възможност на администраторите да следят последните промени, актуалните добавки, поправки, централизирани изтегляния, документация и препоръки. Управлението на добавки не променя файловата система и не инсталира добавки автоматично.';
+$labels['plugin_manager_title'] = 'Управление на добавки';
+$labels['plugin_manager_center'] = 'Център за управление на добавки';
+$labels['updatepm'] = 'Налична е нова версия на Управление на добавки.';
+$labels['updatepmrequired'] = 'Необходима е актуализация на Управление на добавки.';
+$labels['downloadnow'] = 'Изтегли сега';
+$labels['calendaring'] = 'Календари';
+$labels['misc'] = 'Други';
+$labels['downloads'] = 'изтегляния';
+$labels['issue'] = 'Проблем';
+$labels['submitissue'] = 'Докладвай проблем.<br><br>Моля, проверете логовете си и предоставете уместна информация в съобщението.<br><br><b>ЗАБЕЛЕЖКА</b>: Изисква се профил в Google.';
+$labels['showall'] = 'Покажи всички добавки';
+$labels['hideuptodate'] = 'Покажи само актуализациите';
+$labels['connectionerror'] = 'Няма отговор от отдалечения сървър при опит за връзка.';
+$labels['trylater'] = 'Моля, опитайте по-късно ...';
+$labels['translate'] = 'Преведи на тази добавка';
+$labels['restoredefaults'] = 'Възстанови стандартните';
+$labels['checkall'] = 'Маркирай всички';
+$labels['uncheckall'] = 'Размаркирай всички';
+$labels['toggle'] = 'Превключи избора';
+$labels['status'] = 'Статус';
+$labels['globalplugins'] = 'Глобални добавки';
+$labels['backend'] = 'Сървърни добавки';
+$labels['messagesmanagement'] = 'Управление на съобщения';
+$labels['furtherconfig'] = 'Желаете ли да настроите тази добавка сега?';
+$labels['uninstall'] = 'Вие ще деактивирате тази добавка. Желаете ли да изтриете съхранените настройки?';
+$labels['uninstallconfirm'] = 'Вие ще деактивирате тази добавка. ПРЕДУПРЕЖДЕНИЕ: Изберете »ИЗКЛЮЧВАНЕ« за деактивиране на тази добавка, съхранявайки данните и настройките, записани на нашия сървър, ако смятате да ги използвате отново в бъдеще. Изберете »ПРЕМАХВАНЕ«, ако искате всички данни и настройки , управлявани от тази добавка, да бъдат изтрити от нашите бази данни. Обърнете внимание, че това действие е необратимо.';
+$labels['areyousure'] = 'Това действие е необратимо. Наистина ли сте сигурни?';
+$labels['successfullydeleted'] = 'Настройките бяха премахнати успешно.';
+$labels['successfullysaved'] = 'Успешен запис.';
+$labels['errorsaving'] = 'Възникна грешка при записване.';
+$labels['yes'] = 'Да';
+$labels['no'] = 'Не';
+$labels['disable'] = 'Изключване';
+$labels['remove'] = 'Премахване';
+$labels['savewarning'] = 'Желаете ли да запишете промените?';
+$labels['plugin_manager_update'] = 'Актуализирай добавките';
+$labels['authors_comments'] = 'Бележки на автора (без превод)';
+$labels['requiredby'] = 'Добавката се изисква от';
+$labels['requires'] = 'Добавката изисква';
+$labels['recommended'] = 'Препоръчани добавки';
+$labels['update_plugins'] = 'Изтегляне на добавки';
+$labels['ziparchive'] = 'Изтегли Zip-архив';
+$labels['demoaccount'] = 'Съжаляваме, няма изтегляне (Demo профил)';
+$labels['serverversion'] = 'Инсталирана версия';
+$labels['mirrorversion'] = 'Актуална версия';
+$labels['mirrorhost'] = 'Сървър за актуализация (host)';
+$labels['comments'] = 'Изисквания и Бележки за актуализация';
+$labels['update_error'] = 'Разлика във версиите';
+$labels['update_ok'] = 'Открита е последната версия. Не е нужна актуализация.';
+$labels['update_edit'] = 'Добавката трябва да се преконфигурира или изисква корекции в базата данни. Моля, прегледайте Бележките за актуализация.';
+$labels['servernewer'] = 'Инсталираната версия на добавката е по-нова от огледалната версия.';
+$labels['orhigher'] = 'или по-висока';
+$labels['rc_ok'] = 'Версията на Roundcube е актуална.';
+$labels['update_update'] = 'Добавката е неактуална. Моля, актуализирайте! Имайте предвид Бележките за актуализация.';
+$labels['noupdates'] = 'Няма избрани актуализации.';
+$labels['rc_update'] = 'Версията на Roundcube е неактуална. Моля, актуализирайте!';
+$labels['rc_uptodate'] = 'Версията на Roundcube е актуална.';
+$labels['rc_newer'] = 'Инсталираната версия на Roundcube е по-нова от огледалната версия.';
+$labels['nottested'] = 'Моля, използвайте добавките с повишено внимание. Ние не знаем дали хостваните допълнения работят с Roundcube версия %s.';
+$labels['justunzip'] = 'Просто разопаковайте архива като припокриете съществуващата инсталация.';
+$labels['guide'] = 'Прочети повече ...';
+$labels['thirdparty'] = 'Това не е добавка на MyRoundcube.';
+$labels['thirdpartywarning'] = 'Това е добавка на външен разработчик. Препоръчваме Ви да не го изтегляте от нашите сървъри. Най-добре я изтеглете от сайта на разработчика, за да сте сигурни, че имате последната версия, както и забележките и препоръките на автора.';
+$labels['develsite'] = 'Изтегляне';
+$labels['notinstalled'] = 'не е инсталиран';
+$labels['notregistered'] = 'не е регистриран';
+$labels['roundcubeurl'] = 'Изтегляне на Roundcube';
+$labels['languageupdate'] = 'Налична е актуализация на езиков пакет.';
+$labels['localizationfilesonly'] = 'Забележка: Изтеглянето съдържа само езикови пакети.';
+$labels['donotregister'] = 'Не регистрирайте това допълнение. Зарежда се автоматично.';
+$labels['register'] = 'Регистрирайте тази добавка в настройките на Plugin Manager или в ./config/config.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</small>.';
+$labels['customer_account'] = 'Клиентски профил';
+$labels['customer_id'] = 'Клиентски номер';
+$labels['invalid_customer_id'] = 'Невалиден клиентски номер';
+$labels['invalid_credits'] = 'Невалидни кредити';
+$labels['successfully_transferred'] = 'Кредитите бяха прехвърлени успешно';
+$labels['merge'] = 'Обединяване на кредити';
+$labels['credits'] = 'Кредити';
+$labels['creditsupdated'] = 'Има промяна в кредитите след последното опресняване на страницата';
+$labels['buynow'] = 'Купи кредити сега';
+$labels['history'] = 'История на профила';
+$labels['details'] = 'Подробности';
+$labels['receipt'] = 'Разписка';
+$labels['plugins'] = 'Допълнения';
+$labels['clickhere'] = 'Натисни тук';
+$labels['discardliabletopaycosts'] = 'Откажи платените изтегляния';
+$labels['unchecknotinstalledplugins'] = 'Откажи изтеглянията на добавките, които не са инсталирани';
+$labels['sum'] = 'Сума';
+$labels['show'] = 'Покажи';
+$labels['hide'] = 'Скрий';
+$labels['view'] = 'виж';
+$labels['expired'] = 'изтекъл';
+$labels['terms'] = 'Условия';
+$labels['pricelist'] = 'Изтегли цените';
+$labels['forthisdownload'] = 'за това изтегляне';
+$labels['remainingcredits'] = 'оставащи кредити';
+$labels['initialdownload'] = 'Първоначално изтегляне';
+$labels['keyfeatureaddition'] = 'Нова функционалност';
+$labels['codeimprovements'] = 'Подобрения на кода';
+$labels['servicenotavailable'] = 'Услугата не е достъпна в момента. Моля, опитайте по-късно!';
+$labels['myrcerror'] = 'Услугите на MyRoundcube не са достъпни в момента.';
+$labels['getnew'] = 'Заяви нов клиентски номер';
+$labels['getnew_hint'] = 'Препоръчваме Ви често да подновявате клиентския си номер. Ако забележите подозрителна активност в профила си, незабавно подновете клиентския си номер.';
+$labels['transfer'] = 'Прехвърляне на кредити';
+$labels['submenuprefix'] = ' » ';
+$labels['noplugindescription'] = 'Не е открито описание на допълнението.';
+$labels['markbuttons_pluginname'] = 'Бутони за маркиране на писмата';
+$labels['markbuttons_plugindescription'] = 'Добавя икони под списъка със съобщения за бързо маркиране на мейлите.';
+$labels['keyboard_shortcuts_pluginname'] = 'Клавиши за бърз достъп';
+$labels['keyboard_shortcuts_plugindescription'] = 'Изпълнение на команди с използване на клавишни комбинации.';
+$labels['message_highlight_pluginname'] = 'Оцветяване на съобщения';
+$labels['message_highlight_plugindescription'] = 'Оцветяване на съобщенията, които отговарят на определени критерии.';
+$labels['google_contacts_pluginname'] = 'Контакти от Google';
+$labels['google_contacts_plugindescription'] = 'Достъп до контактите Ви в Google.';
+$labels['contextmenu_pluginname'] = 'Контекстно меню';
+$labels['contextmenu_plugindescription'] = 'Добавяне на контекстно меню при кликване на десния бутон на мишката.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/cs_CZ.inc b/plugin_manager/localization/cs_CZ.inc
new file mode 100644
index 0000000..dc69aaf
--- /dev/null
+++ b/plugin_manager/localization/cs_CZ.inc
@@ -0,0 +1,346 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/cs_CZ.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: tachec - 01/20/2015 11:37:38
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Správce doplňků';
+$labels['plugindescription'] = 'Správce doplňků poskytuje uživatelům volby, které umožní povolit ​​nebo zakázat doplňky (na úrovni uživatelského účtu) a zároveň pomáhá administrátorům udržet doplňky v aktuálním stavu, opravu případných chyb, centralizované stahování, dokumentaci a doporučení. Správce doplňků neprovádí změny v souborovém systému ani automaticky neinstaluje doplňky.';
+$labels['plugin_manager_title'] = 'Správa doplňků';
+$labels['plugin_manager_center'] = 'Centrum Správce doplňků';
+$labels['updatepm'] = 'Je dostupná aktualizace pro Správce doplňků.';
+$labels['updatepmrequired'] = 'Je vyžadována aktualizace Správce doplňků.';
+$labels['downloadnow'] = 'Stáhnout nyní';
+$labels['homepage'] = 'Domovská stránka';
+$labels['calendaring'] = 'Kalendář';
+$labels['misc'] = 'Ostatní';
+$labels['downloads'] = 'staženo';
+$labels['issue'] = 'Problém';
+$labels['submitissue'] = 'Nahlásit problém. Zkontrolujte prosím logy a poskytněte relevantní informace v hlášení. Poznámka: je vyžadován účet Google.';
+$labels['showall'] = 'Zobrazit všechny doplňky';
+$labels['hideuptodate'] = 'Zobrazit pouze aktualizace';
+$labels['connectionerror'] = 'Vzdálený server neodpovídá na pokus o připojení.';
+$labels['trylater'] = 'Zkuste to prosím později...';
+$labels['translate'] = 'Přeložit tento doplněk';
+$labels['translationaccount'] = 'Účet pro překlad v reálném čase (uživatelské jméno)';
+$labels['translationserver'] = 'Účet pro překlad v reálném čase (IMAP server)';
+$labels['whatsthis'] = 'Co je to?';
+$labels['restoredefaults'] = 'Obnovit výchozí';
+$labels['checkall'] = 'Zaškrnout vše';
+$labels['uncheckall'] = 'Zrušit zaškrtnutí všech';
+$labels['toggle'] = 'Přepnout výběr';
+$labels['status'] = 'Stav';
+$labels['globalplugins'] = 'Globální doplňky';
+$labels['performance'] = 'Výkonnost';
+$labels['backend'] = 'Doplňky serveru';
+$labels['messagesmanagement'] = 'Obsluha zpráv';
+$labels['furtherconfig'] = 'Chtěli byste nastavit tento doplněk teď?';
+$labels['uninstall'] = 'Chystáte se vypnout tento doplněk. Chcete trvale odstranit i všechna jeho uložená nastavení? ';
+$labels['uninstallconfirm'] = 'Chystáte se vypnout tento doplněk. VAROVÁNÍ: Zvolte »Zakázat« pokud chcete tento doplněk zakázat, ale chcete pro něj ponechat veškerá nastavení pro pozdější použití. Zvolte »Odstranit« pokud chcete trvale odstranit z databáze veškerá nastavení a data související s tímto doplňkem. Tato akce je nevratná.';
+$labels['areyousure'] = 'Tuto akci nelze vrátit zpět. Jste si jistí?';
+$labels['successfullydeleted'] = 'Nastavení bylo úspěšně odstraněno.';
+$labels['successfullysaved'] = 'Úspěšně uloženo.';
+$labels['errorsaving'] = 'Při ukládání nastala chyba.';
+$labels['yes'] = 'Ano';
+$labels['no'] = 'Ne';
+$labels['disable'] = 'Zakázat';
+$labels['remove'] = 'Odstranit';
+$labels['savewarning'] = 'Chcete již uložit dané změny?';
+$labels['plugin_manager_update'] = 'Aktualizovat doplňky';
+$labels['authors_comments'] = 'Autorovy komentáře (bez překladu)';
+$labels['requiredby'] = 'Doplněk je vyžadován';
+$labels['requires'] = 'Doplněk vyžaduje';
+$labels['recommended'] = 'Doporučené doplňky';
+$labels['update_plugins'] = 'Stažení doplňků';
+$labels['ziparchive'] = 'Stáhnout ZIP archiv';
+$labels['demoaccount'] = 'Omlouváme se, ale tato akce je zakázána (demo účet)';
+$labels['serverversion'] = 'Verze na serveru';
+$labels['mirrorversion'] = 'Dostupná verze';
+$labels['mirrorhost'] = 'Dostupný server';
+$labels['comments'] = 'Požadavky a poznámky k aktualizaci';
+$labels['update_error'] = 'Verze nesouhlasí';
+$labels['update_ok'] = 'Zjištěna nejnovější verze. Žádná aktualizace není třeba.';
+$labels['update_edit'] = 'Doplněk musí být znovu nakonfigurován nebo vyžaduje úpravy databáze. Prohlédněte si prosím poznámky k aktualizaci.';
+$labels['servernewer'] = 'Registrovaný doplněk je novější než aktuálně dostupná verze.';
+$labels['orhigher'] = 'nebo vyšší';
+$labels['rc_ok'] = 'Jádro Roundcube je aktuální.';
+$labels['update_update'] = 'Doplněk je zastaralý. Prosím aktualizujte! Prohlédněte si poznámky k aktualizaci.';
+$labels['noupdates'] = 'Nejsou vybrány žádné aktualizace.';
+$labels['rc_update'] = 'Jádro Roundcube je zastaralé. Zaktualizujte jej prosím!';
+$labels['rc_uptodate'] = 'Jádro Roundcube je aktuální.';
+$labels['rc_newer'] = 'Jádro Roundcube je novější než aktuálně dostupná verze.';
+$labels['nottested'] = 'Prosím, použijte tento doplněk obezřetně! Nevíme, jestli tento hostovaný doplněk spolupracuje s Roundcube v%s.';
+$labels['justunzip'] = 'Stačí rozbalit archiv přes stávající instalaci.';
+$labels['guide'] = 'Čtěte více...';
+$labels['thirdparty'] = 'Toto není MyRoundcube doplněk.';
+$labels['thirdpartywarning'] = 'Toto je doplněk třetí strany. Doporučujeme nestahovat tento doplněk z našeho úložiště, ale stáhnout jej přímo ze stránek jeho tvůrce. Tím bude zajištěna jeho aktuálnost a případné poznámky a rady budete mít přímo od vývojáře tohoto doplňku.';
+$labels['develsite'] = 'Stáhnout';
+$labels['notinstalled'] = 'nenainstalován';
+$labels['notregistered'] = 'nezaregistrován';
+$labels['roundcubeurl'] = 'Stáhnout Roundcube';
+$labels['languageupdate'] = 'Je dostupná aktualizace lokalizačního souboru.';
+$labels['localizationfilesonly'] = 'Poznámka: stažení obsahuje pouze lokalizační soubory';
+$labels['donotregister'] = 'Neregistrujte tento doplněk. bude načten automaticky.';
+$labels['register'] = 'Zaregistrujte tento doplněk v konfiguraci Správce doplňků nebo v souboru ./config/config.inc.php [$config[\'plugins\'] = array("foo", "bar");].';
+$labels['customer_account'] = 'Zákaznický účet';
+$labels['customer_id'] = 'ID zákazníka';
+$labels['invalid_customer_id'] = 'Neplatné ID zákazníka';
+$labels['invalid_credits'] = 'Neplatné kredity';
+$labels['successfully_transferred'] = 'Kredity byly úspěšně převedeny';
+$labels['merge'] = 'Sloučit kredity';
+$labels['credits'] = 'Kredity';
+$labels['creditsupdated'] = 'Kredity se změnily od posledního obnovení stránky';
+$labels['buynow'] = 'Koupit kredity nyní';
+$labels['history'] = 'Historie účtu';
+$labels['details'] = 'Detaily';
+$labels['receipt'] = 'Příjmy';
+$labels['plugins'] = 'Doplňky';
+$labels['clickhere'] = 'Klikněte zde';
+$labels['discardliabletopaycosts'] = 'Vyřadit ze stažení doplňky, které jsou zpoplatněné';
+$labels['unchecknotinstalledplugins'] = 'Vyřadit ze stažení doplňky, které nejsou nainstalované';
+$labels['sum'] = 'Součet';
+$labels['show'] = 'Zobrazit';
+$labels['hide'] = 'Skrýt';
+$labels['view'] = 'zobrazeno';
+$labels['expired'] = 'expirováno';
+$labels['terms'] = 'Podmínky';
+$labels['pricelist'] = 'Stáhnout ceník';
+$labels['forthisdownload'] = 'pro toto stažení';
+$labels['remainingcredits'] = 'zbývající kredity';
+$labels['initialdownload'] = 'Počáteční stažení';
+$labels['keyfeatureaddition'] = 'Nová klíčová funkcionalita';
+$labels['codeimprovements'] = 'Zlepšení kódu';
+$labels['servicenotavailable'] = 'Služba je momentálně nedostupná. Zkuste to prosím později!';
+$labels['myrcerror'] = 'Služby MyRoundcube jsou momentálně nedostupné.';
+$labels['getnew'] = 'Vyžaduje nové ID zákazníka';
+$labels['getnew_hint'] = 'Doporučujeme abyste často obnovovali své ID zákazníka. Pokud si všimnete jakékoliv podezřelé aktivity v detailech vašeho účtu, obnovte okamžitě své zákaznické ID.';
+$labels['transfer'] = 'Přenos kreditů';
+$labels['submenuprefix'] = '»';
+$labels['printdetails'] = 'Vytisknout detaily účtu ';
+$labels['noplugindescription'] = 'Nezjištěn žádný popisek doplňku.';
+$labels['welcome_to_plugin_manager'] = 'Vítejte ve Správci doplňků';
+$labels['about_to_create_account'] = 'Správce doplňků se chystá vytvořit výsadní administrátorský účet.';
+$labels['create_account_proceed'] = 'Chcete-li pokračovat, musíte potvrdit, že jste správce této služby.';
+$labels['please_create'] = 'Vytvořte prosím následující soubor v kořenovém adresáři vaší instalace Roundcube:';
+$labels['thank_you'] = 'Děkuji!';
+$labels['done'] = 'Hotovo';
+$labels['manage_admins'] = 'Administrátoři';
+$labels['plugin_manager_admins'] = 'Administrátoři Správce doplňků';
+$labels['allow_plugins_configuration'] = 'Udělit oprávnění pro konfiguraci doplňků';
+$labels['share_credits'] = 'Sdílet MyRC$ kredity';
+$labels['add'] = 'Přidat';
+$labels['accountnotexists'] = 'Účet neexistuje';
+$labels['sharedby'] = 'Zákaznický účet sdílí';
+$labels['switch'] = 'Přepnout';
+$labels['ownaccount'] = 'vlastníkovi účtu';
+$labels['shareinvitation'] = 'sdílenému účtu';
+$labels['enable_notifications'] = 'Povolit upozornění na novou verzi doplňků';
+$labels['enable_notifications_note'] = 'Poznámka: Správce doplňků dotazuje MyRoundcube servery pro zjištění dostupných aktualizací pouze jednou denně.';
+$labels['notifications_cc'] = 'CC adresa pro upozornění';
+$labels['notifications_cc_note'] = 'Poznámka: oznámení o nových aktualizacích se pošle všem administrátorům Správce doplňků. Pomocí tohoto pole můžete přidat další příjemce, např: jan.novak@gmail.com nebo distribuční seznam e-mailových adres.';
+$labels['serverconfiguration'] = 'Konfigurace serveru';
+$labels['pluginsconfiguration'] = 'Konfigurace doplňků';
+$labels['use_ssl'] = 'Vytvořit zabezpečené SSL připojení k serverům MyRoundcube';
+$labels['use_hmail'] = 'Použít hMailserver kompatibilní doplňky';
+$labels['load_splitter'] = 'Rozdělení zátěže pro statické soubory';
+$labels['show_myrc_messages'] = 'Zobrazit oznamovací zprávy ze serverů MyRoundcube';
+$labels['maintenance_mode'] = 'Režim údržby';
+$labels['maintenance_mode_hint'] = 'Dočasně zakáže všechny aktivní doplňky. Používá se k aktualizaci doplňků na novější hlavní verze. Správce doplňků zakáže všechny aktivní doplňky, ale umožní vám i nadále přístup ke stažení nejnovějších aktualizací doplňků z našich serverů.';
+$labels['running_in_maintenance_mode'] = 'Webmail běží v režimu údržby';
+$labels['serverwide'] = 'konfigurace na straně serveru';
+$labels['file_based_config'] = 'Povolit konfiguraci Správce doplňků pomocí souborů';
+$labels['advanced_admins'] = 'vhodné pouze pro pokročilé správce';
+$labels['compress_html'] = 'Zmenšit HTML výstup';
+$labels['show_config'] = 'Zobrazit aktuální konfiguraci';
+$labels['systemadmin'] = 'Systémový administrátor';
+$labels['admin'] = 'Administrátor';
+$labels['configuredby'] = 'nakonfigurováno';
+$labels['enabled'] = 'Povolen (výchozí)';
+$labels['protected'] = 'Chráněn';
+$labels['skins'] = 'Skiny';
+$labels['loads_always'] = 'Povinný';
+$labels['loads_never'] = 'Doplněk je zakázán';
+$labels['loads_by_user'] = 'Uživatel si může určit jeho využití';
+$labels['loads_linked'] = 'Vázán na';
+$labels['unbind'] = 'odvázat';
+$labels['bind'] = 'přivázat';
+$labels['addplugin'] = 'Přidat doplněk';
+$labels['removeplugin'] = 'Odstranit doplněk';
+$labels['errorplugin'] = 'Chyba: Požadovaný doplněk chybí';
+$labels['errorrcversion'] = 'Chyba: doplněk vyžaduje Roundcube';
+$labels['errorphpversion'] = 'Chyba: doplněk vyžaduje PHP';
+$labels['errorphpcurl'] = 'Chyba: není nainstalována podpora cURL';
+$labels['errorphpfinfo'] = 'Chyba: není nainstalována podpora finfo';
+$labels['errordb'] = 'Je vyžadována úprava databáze. Povolte prosím doplněk pro spuštění databázových úloh.';
+$labels['errordb8'] = 'Je vyžadována úprava databáze.';
+$labels['syntaxerror'] = 'Chyba PHP syntaxe';
+$labels['notconfigured'] = 'Doplněk není nakonfigurován';
+$labels['editconfig'] = 'Upravit konfiguraci';
+$labels['instructions'] = 'Pokyny';
+$labels['dbautomatically'] = 'Zahájení úprav.';
+$labels['dbmanually'] = 'Postupujte prosím podle následujících pokynů.';
+$labels['ornewer'] = 'nebo novější';
+$labels['official_releases'] = 'Podporujeme pouze oficiální verze Roundcube';
+$labels['localizationmissing'] = 'Nenalezeny žádné popisky pro jméno a popis doplňku';
+$labels['documentation'] = 'Dokumentace';
+$labels['select_plugin'] = 'Vybrat doplněk';
+$labels['legend'] = 'Legenda';
+$labels['plugindisabledbydefault'] = 'Doplněk je ve výchozím nastavení zakázán - uživatel si může určit jeho použití';
+$labels['pluginenabledbydefault'] = 'Doplněk je ve výchozím nastavení povolen - uživatel si může určit jeho použití';
+$labels['pluginmandatory'] = 'Povinný - doplněk je povolen, uživatelé nemohou tento doplněk povolit/zakázat';
+$labels['show_about_link'] = 'Zobrazit odkaz "O programu"';
+$labels['show_support_link'] = 'Zobrazit odkaz "Podpora"';
+$labels['use_myroundcube_watermark'] = 'Použít vodoznak "MyRoundcube"';
+$labels['remove_watermark'] = 'Nezobrazovat vůbec vodoznak';
+$labels['database'] = 'Databáze';
+$labels['account_details_compressed'] = 'Detaily účtu zkomprimovány';
+$labels['credits_transferred'] = 'Kredity převedeny';
+$labels['customer_id_changed'] = 'ID zákazníka změněno';
+$labels['myrcd_bought'] = 'MyRC$ koupeno - děkujeme!';
+$labels['myrcd_refunded'] = 'MyRC$ vráceno';
+$labels['PHPMyAdmin'] = 'PHPMyAdmin';
+$labels['ipmismatch'] = 'Stažení z IP adresy %s není možné (IP adresa klienta neodpovídá). Použijte %s nebo navštivte %s z IP adresy %s.';
+$labels['emoticons_pluginname'] = 'Náhrada smajlíků';
+$labels['emoticons_plugindescription'] = 'Nahradí zkratku pro smajlík obrázkem';
+$labels['markbuttons_pluginname'] = 'Tlačítko pro označení zpráv';
+$labels['markbuttons_plugindescription'] = 'Přidá ovládací ikony pod oddělovač seznamu zpráv, které umožní rychle označit zprávy.';
+$labels['keyboard_shortcuts_pluginname'] = 'Klávesové zkratky';
+$labels['keyboard_shortcuts_plugindescription'] = 'Spouští příkazy na základě klávesových zkratek.';
+$labels['message_highlight_pluginname'] = 'Zvýrazňování zpráv';
+$labels['message_highlight_plugindescription'] = 'Zvýrazní zprávy na základě filtrovacích pravidel.';
+$labels['google_contacts_pluginname'] = 'Kontakty Google';
+$labels['google_contacts_plugindescription'] = 'Umožní přístup do vašich kontaktů Google.';
+$labels['contextmenu_pluginname'] = 'Kontextové menu';
+$labels['contextmenu_plugindescription'] = 'Kontextové menu na pravé tlačítko myši.';
+$labels['newmail_notifier_pluginname'] = 'Oznámení příchozí zprávy';
+$labels['newmail_notifier_plugindescription'] = 'Oznámí nově příchozí zprávu.';
+$labels['listcommands_pluginname'] = 'Odpovědět do e-mailové konference';
+$labels['listcommands_plugindescription'] = 'Různé možnosti pro odpovědi na zprávy odeslané z e-mailových konferencí.';
+$labels['copymessage_pluginname'] = 'Kopírování zpráv';
+$labels['copymessage_plugindescription'] = 'Kopírování zpráv do jiné IMAP složky .';
+$labels['vcard_attachments_pluginname'] = 'Přílohy ve formátu vCard';
+$labels['vcard_attachments_plugindescription'] = 'Přidá prvek do zpráv, které mají přílohu ve formátu vcard a umožní tak importovat kontakty přímo do adresáře.';
+$labels['zipdownload_pluginname'] = 'Export zpráv';
+$labels['zipdownload_plugindescription'] = 'Exportuje zprávy jako zip soubor.';
+$labels['markasjunk2_pluginname'] = 'Označ zprávy jako SPAM';
+$labels['markasjunk2_plugindescription'] = 'Označí zprávu jako SPAM nebo jako validní zprávu.';
+$labels['markasjunk_pluginname'] = 'Označ zprávy jako SPAM';
+$labels['markasjunk_plugindescription'] = 'Označí zprávu jako SPAM nebo jako validní zprávu.';
+$labels['google_analytics_pluginname'] = 'Analýza Google';
+$labels['google_analytics_plugindescription'] = 'Vloží analýzu Google';
+$labels['globaladdressbook_pluginname'] = 'Globální adresář';
+$labels['globaladdressbook_plugindescription'] = 'Adresář (pouze pro čtení), který je poskytován správcem systému.';
+$labels['blockspamsending_pluginname'] = 'Ochrana proti rozesílání spamu';
+$labels['blockspamsending_plugindescription'] = 'Povolí zasílání pouze určitého množství zpráv se stejným předmětem v průběhu jednoho sezení.';
+$labels['global_config_pluginname'] = 'Správa konfigurace';
+$labels['global_config_plugindescription'] = 'Toto je doplněk pro správu konfigurace. Optimalizuje váš server centralizací konfiguračních souborů jednotlivých doplňků. Zjednodušuje vaše administrační úkoly tím, že umožňuje použít pouze jeden konfigurační soubor pro všechny doplňky.';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Javascriptová knihovna Jqueryui';
+$labels['hide_blockquote_pluginname'] = 'Skrýt citace';
+$labels['hide_blockquote_plugindescription'] = 'Skrýt citace, když je počet řádků větší než zadaný.';
+$labels['crawler_pluginname'] = 'Crawler';
+$labels['crawler_plugindescription'] = 'Falešná stránka pro prohledávací systémy.';
+$labels['archive_pluginname'] = 'Archiv';
+$labels['archive_plugindescription'] = 'Archivuje zprávy v archivní složce.';
+$labels['autologon_pluginname'] = 'Automatické přihlášení';
+$labels['autologon_plugindescription'] = 'Automatické přihlášení uživatele.';
+$labels['openpgpjs_pluginname'] = 'OpenPGPjs';
+$labels['openpgpjs_plugindescription'] = 'PGP pro Roundcube.';
+$labels['dblog_pluginname'] = 'Logu do databáze ';
+$labels['dblog_plugindescription'] = 'Zapisuje události do databáze namísto logovacího souboru.';
+$labels['gibberish_pluginname'] = 'Gibberish šifrování';
+$labels['gibberish_plugindescription'] = 'Pomocný doplněk pro šifrování Gibberish AES.';
+$labels['http_request_pluginname'] = 'HTTP požadavek';
+$labels['http_request_plugindescription'] = 'Pomocný doplněk pro provádění HTTP požadavků přes cURL nebo fsockopen.';
+$labels['http_auth_pluginname'] = 'HTTP autentizace';
+$labels['http_auth_plugindescription'] = 'Pomocný doplněk pro podporu HTTP autentizace pro ostatní doplňky. Poznámka: Tento doplněk je odlišný od výchozího doplňku http_authentication pro Roundcube.';
+$labels['http_authentication_pluginname'] = 'HTTP autentizace (výchozí)';
+$labels['http_authentication_plugindescription'] = 'Využívá aktuální HTTP autentizaci a provádí přihlášení se stávajícím pověřením uživatele.';
+$labels['jscolor_pluginname'] = 'Výběr barvy';
+$labels['jscolor_plugindescription'] = 'Pomocný doplněk sloužící k zobrazení dialogu pro výběr barvy.';
+$labels['tinymce_pluginname'] = 'TinyMCE - HTML editor';
+$labels['tinymce_plugindescription'] = 'Tento doplněk implementuje TinyMCE PHP Kompresor (http://www.tinymce.com/wiki.php/Compressors:PHP). Kromě toho přidává možnost konfigurovat nastavení TinyMCE bez nutnosti úprav v základních souborech RoundCube.';
+$labels['lang_sel_pluginname'] = 'Výběr jazyka.';
+$labels['lang_sel_plugindescription'] = 'Umožňuje výběr jazyka při přihlášení.';
+$labels['newuser_pluginname'] = 'Nový uživatel';
+$labels['newuser_plugindescription'] = 'Informuje správce, když se nový uživatel registruje přes rozhraní webmailu a umožňuje odeslat uvítací zprávu novému uživatele při prvním přihlášení.';
+$labels['placeholder_pluginname'] = 'Přídavné atributy';
+$labels['placeholder_plugindescription'] = 'Přidá přídavné atributy ke vstupním textovým polím a polím pro vstup hesla.';
+$labels['qtip_pluginname'] = 'Místní nápověda jQueryUI';
+$labels['qtip_plugindescription'] = 'Pomocný doplněk pro využití místní nápovědy - jQueryUI qtip.';
+$labels['sabredav_pluginname'] = 'SabreDAV';
+$labels['sabredav_plugindescription'] = 'Vytváří SabreDAV účty pro přístup k CalDAV kalendáři při vytváření nových uživatelů v RoundCube a přidružuje hesla, pokud byla změněna.';
+$labels['savepassword_pluginname'] = 'Ulož hesla';
+$labels['savepassword_plugindescription'] = 'Jedná se o pomocný doplněk, který využívají některé další doplňky.';
+$labels['database_attachments_pluginname'] = 'Přílohy v databázi';
+$labels['database_attachments_plugindescription'] = 'Pomocný doplněk pro správu příloh v databázi.';
+$labels['help_pluginname'] = 'Nápověda';
+$labels['help_plugindescription'] = 'Nápověda k webmailu';
+$labels['new_user_dialog_pluginname'] = 'Dialog pro nového uživatele';
+$labels['new_user_dialog_plugindescription'] = 'Poskytuje dialogové okno pro nastavení identity pro nové uživatele. Když je vytvořen nový uživatel, tento doplněk kontroluje výchozí identitu a nastaví příznak v případě, že je identita nekompletní. Na obrazovce uživatele se objeví okno, které překryje veškerý obsah dokud uživatel nedoplní svoji identitu.';
+$labels['rcguard_pluginname'] = 'ReCAPTCHA';
+$labels['rcguard_plugindescription'] = 'Vynutí CAPTCHA ověření po určitém počtu neúspěšných pokusů o přihlášení.';
+$labels['domain_check_pluginname'] = 'Kontrola domény';
+$labels['domain_check_plugindescription'] = 'Omezuje přihlášení do konkrétních domén.';
+$labels['tasklist_pluginname'] = 'Seznam úkolů';
+$labels['tasklist_plugindescription'] = 'Umožňuje vytvářet úkoly a seznamy dílčích úkolů s připomenutím.';
+$labels['virtuser_query_pluginname'] = 'Dotaz na virtuálního uživatele';
+$labels['virtuser_query_plugindescription'] = 'Databázové vyhledávání spojení uživatel-email a email-uživatel.';
+$labels['virtuser_file_pluginname'] = 'Dotaz na virtuálního uživatele';
+$labels['virtuser_file_plugindescription'] = 'Databázové vyhledávání spojení uživatel-email a email-uživatel.';
+$labels['userinfo_pluginname'] = 'Uživatelské informace';
+$labels['userinfo_plugindescription'] = 'Zobrazí informace o aktuálním uživateli.';
+$labels['subscriptions_option_pluginname'] = 'Odebírání/přidávání IMAP složek';
+$labels['subscriptions_option_plugindescription'] = 'Slouží ke správě odebírání/přidávání IMAP složek.';
+$labels['filters_pluginname'] = 'Filtry';
+$labels['filters_plugindescription'] = 'Správa filtrů na straně klienta.';
+$labels['forgot_password_pluginname'] = 'Zapomenuté heslo';
+$labels['forgot_password_plugindescription'] = 'Požadavek na obnovu hesla.';
+$labels['sieverules_pluginname'] = 'Sieve filtry';
+$labels['sieverules_plugindescription'] = 'Správa Sieve filtrů.';
+$labels['managesieve_pluginname'] = 'Sieve filtry';
+$labels['managesieve_plugindescription'] = 'Správa Sieve filtrů.';
+$labels['acl_pluginname'] = 'Přístupová práva';
+$labels['acl_plugindescription'] = 'Správa přístupových práv na složkách.';
+$labels['vacation_pluginname'] = 'Zpráva v nepřítomnosti';
+$labels['vacation_plugindescription'] = 'Nastavení zprávy v nepřítomnosti (oznámení o dovolené).';
+$labels['password_pluginname'] = 'Změna hesla';
+$labels['password_plugindescription'] = 'Povoluje uživatelům změnit si své heslo.';
+$labels['redundant_attachments_pluginname'] = 'Záložní přílohy';
+$labels['redundant_attachments_plugindescription'] = 'Tento doplněk poskytuje redundantní úložiště pro dočasně nahrané soubory příloh. Přílohy jsou uloženy v databázi a současně i na lokálním souborovém systému.';
+$labels['example_addressbook_pluginname'] = 'Ukázkový adresář';
+$labels['example_addressbook_plugindescription'] = 'Ukázkový kód pro přidání dalšího adresáře.';
+$labels['debug_logger_pluginname'] = 'Rozšířené logování záznamů';
+$labels['debug_logger_plugindescription'] = 'Umožňuje rozšířené logování záznamů pro účely testování.';
+$labels['show_additional_headers_pluginname'] = 'Zobrazit další hlavičky zprávy';
+$labels['show_additional_headers_plugindescription'] = 'Doplněk, který stáhne další hlavičky a zobrazí je v detailu zprávy.';
+$labels['additional_message_headers_pluginname'] = 'Další hlavičky zprávy';
+$labels['additional_message_headers_plugindescription'] = 'Velmi jednoduchý doplněk, který do odchozích zpráv přidá další hlavičky nebo je naopak odstraní.';
+$labels['new_user_identity_pluginname'] = 'Identita nového uživatele';
+$labels['new_user_identity_plugindescription'] = 'Tento doplněk vyplní výchozí identitu nového uživatele z LDAPu při jeho první návštěvě.';
+$labels['squirrelmail_usercopy_pluginname'] = 'Migruje uživatele ze Squirrelmailu';
+$labels['squirrelmail_usercopy_plugindescription'] = 'Pro nového uživatele nakopíruje identitu uživatele a jeho nastavení ze Squirrelmailu.';
+$labels['yubikey_authentication_pluginname'] = 'Autentizace Yubikey od firmy Yubico';
+$labels['yubikey_authentication_plugindescription'] = 'Doplněk pro využití autentizace do Roundcube pomocí Yubikey od firmy Yubico ';
+$labels['sauserprefs_pluginname'] = 'Uživatelské nastavení pro Spamassassin';
+$labels['sauserprefs_plugindescription'] = 'Přidá záložku \'Spam\' do uživatelského nastavení pomocí níž si uživatel může měnit nastavení Spamassassinu.';
+$labels['dkimstatus_pluginname'] = 'DKIM stav';
+$labels['dkimstatus_plugindescription'] = 'Zobrazuje stav DKIM podpisu pro každý e-mail.';
+$labels['roundcube_openpgp_pluginname'] = 'Roundcube OpenPGP';
+$labels['roundcube_openpgp_plugindescription'] = 'Implementace OpenPGP pro Roundcube. Pomáhá generovat, spravovat a používat šifrovací klíče.';
+$labels['automatic_addressbook_pluginname'] = 'Automatický adresář';
+$labels['automatic_addressbook_plugindescription'] = 'Vytvoří adresář a automaticky do něj vkládá získané e-mailové adresy. Eliminuje potřebu ručně přidávat každý kontakt.';
+$labels['calendar_pluginname'] = 'Kalendář';
+$labels['calendar_plugindescription'] = 'Umožňuje správu událostí za pomocí Webmail kalendáře.';
+$labels['attachment_reminder_pluginname'] = 'Připomenutí na přílohu';
+$labels['attachment_reminder_plugindescription'] = 'Připomene uživatelům přiložit soubor přílohy před odesláním zprávy.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/de_CH.inc b/plugin_manager/localization/de_CH.inc
new file mode 100644
index 0000000..f3a1daf
--- /dev/null
+++ b/plugin_manager/localization/de_CH.inc
@@ -0,0 +1,244 @@
+<?php
+/*
++-----------------------------------------------------------------------+
+| ./plugins/plugin_manager/localization/de_CH.inc
+|
+| Language file of MyRoundcube Plugins Bundle
+| Copyright (C) 2010-2012, Roland 'rosali' Liebl
+| Licensed under the GNU GPL
+|
++-----------------------------------------------------------------------+
+| Author: myroundcube@mail4us.net - 03/21/2012 18:05:31
++-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Plugin Manager';
+$labels['plugindescription'] = 'Plugin Manager gibt Benutzern die Möglichkeit einzelne Erweiterungen zu aktivieren oder zu deaktivieren und hilft Administratoren Erweiterungen aktuell zu halten. Plugin Manager verändert weder das Filesystem, noch werden Erweiterungen automatisch installiert.';
+$labels['plugin_manager_title'] = 'Erweiterungen verwalten';
+$labels['plugin_manager_center'] = 'Plugin Manager Center';
+$labels['updatepm'] = 'Plugin Manager Update verfügbar.';
+$labels['updatepmrequired'] = 'Plugin Manager Update erforderlich.';
+$labels['downloadnow'] = 'Jetzt herunterladen';
+$labels['calendaring'] = 'Aufgaben und Termine verwalten';
+$labels['misc'] = 'Verschiedenes';
+$labels['downloads'] = 'Downloads';
+$labels['issue'] = 'Problem';
+$labels['submitissue'] = 'Melden Sie ein Problem.<br /><br />Bitte überprüfen Sie Ihre Logs und stellen Sie relevante Informationen im Ticket zur Verfügung.<br /><br /><b>BEACHTE</b>: Sie benötigen einen Google-Account.';
+$labels['showall'] = 'Alle verfügbaren Erweiterungen anzeigen.';
+$labels['hideuptodate'] = 'Nur Erweiterungen anzeigen, für die ein Update vorliegt.';
+$labels['connectionerror'] = 'Der Server hat nicht geantwortet.';
+$labels['trylater'] = 'Bitte versuchen Sie es später nochmal.';
+$labels['translate'] = 'Diese Erweiterung übersetzen ';
+$labels['restoredefaults'] = 'Grundeinstellung wiederherstellen';
+$labels['checkall'] = 'Alle auswählen';
+$labels['uncheckall'] = 'Alle abwählen';
+$labels['toggle'] = 'Auswahl umkehren';
+$labels['status'] = 'Status';
+$labels['globalplugins'] = 'Globale Erweiterungen';
+$labels['backend'] = 'Server-Erweiterungen';
+$labels['messagesmanagement'] = 'Nachrichtenverwaltung';
+$labels['furtherconfig'] = 'Diese Erweiterung erfordert weitere Einstellungen. Möchen Sie die Einstellungen jetzt vornehmen?';
+$labels['uninstall'] = 'Möchten Sie alle gespeicherten Einstellungen löschen?';
+$labels['uninstallconfirm'] = 'Möchten Sie Ihre persönlichen Einstellungen dieser Erweiterung behalten oder entfernen? Wenn Si...';
+$labels['areyousure'] = 'Sie können diese Aktion nicht rückgängig machen. Sind Sie wirklich sicher?';
+$labels['successfullydeleted'] = 'Einstellungen wurden erfolgreich entfernt.';
+$labels['successfullysaved'] = 'Erfolgreich gespeichert.';
+$labels['errorsaving'] = 'Beim Speichern ist ein Fehler aufgetreten.';
+$labels['yes'] = 'Ja';
+$labels['no'] = 'Nein';
+$labels['disable'] = 'Behalten';
+$labels['remove'] = 'Entfernen';
+$labels['savewarning'] = 'Möchten Sie Ihre Änderungen jetzt speichern?';
+$labels['plugin_manager_update'] = 'Erweiterungen erneuern';
+$labels['authors_comments'] = 'Anmerkungen des Autors (nicht übersetzt)';
+$labels['requiredby'] = 'Erweiterung wird benötigt von';
+$labels['requires'] = 'Benötigte Erweiterung(en)';
+$labels['recommended'] = 'Empfohlene Erweiterung(en)';
+$labels['update_plugins'] = 'Nach Updates suchen';
+$labels['ziparchive'] = 'Zip-Archiv herunterladen';
+$labels['demoaccount'] = 'Aktion ist nicht möglich (Demo-Konto)';
+$labels['serverversion'] = 'Server-Version';
+$labels['mirrorversion'] = 'Mirror-Version';
+$labels['mirrorhost'] = 'Mirror-Server';
+$labels['comments'] = 'Voraussetzungen und Amerkungen';
+$labels['update_error'] = 'Versionskonflikt';
+$labels['update_ok'] = 'Die Erweiterung ist aktuell. Es ist kein Update erforderlich.';
+$labels['update_edit'] = 'Die Erweiterung muss neu konfiguriert werden und/oder es sind Datenbankanpassungen vorzunehmen. B...';
+$labels['servernewer'] = 'Die registrierte Version der Erweiterung ist neuer als die des Mirror-Servers.';
+$labels['orhigher'] = 'oder höher';
+$labels['rc_ok'] = 'Roundcube Core ist aktuell.';
+$labels['update_update'] = 'Die Erweiterung ist veraltet. Bitte erneuern Sie die Erweiterung unter Berücksichtigung der nebe...';
+$labels['noupdates'] = 'Es wurden keine Updates ausgewählt.';
+$labels['rc_update'] = 'Roundcube Core veraltet. Bitte erneuern Sie Roundcube Core!';
+$labels['rc_uptodate'] = 'Roundcube Core ist aktuell.';
+$labels['rc_newer'] = 'Roundcube Core ist neuer als die Mirror-Version!';
+$labels['nottested'] = 'Bitte benutzen Sie die Erweiterungen mit Vorsicht! Möglicherweise arbeiten die Erweiterungen mit...';
+$labels['justunzip'] = 'Entpacken Sie das Archiv über die bestehende Installation.';
+$labels['guide'] = 'Anleitung';
+$labels['thirdparty'] = 'Das ist keine MyRoundcube-Erweiterung.';
+$labels['thirdpartywarning'] = 'Das ist keine MyRoundcube-Erweiterung. Damit Sie die aktuellste Version erhalten und eventuelle H...';
+$labels['develsite'] = 'Herunterladen';
+$labels['notinstalled'] = 'nicht installiert';
+$labels['notregistered'] = 'nicht registriert';
+$labels['roundcubeurl'] = 'Roundcube herunterladen';
+$labels['languageupdate'] = 'Übsetzungen wurden überarbeitet.';
+$labels['localizationfilesonly'] = 'Download beinhaltet nur Sprachdateien';
+$labels['donotregister'] = 'Diese Erweiterung braucht nicht registriert zu werden. Sie wird automatisch geladen.';
+$labels['register'] = 'Registrieren Sie diese Erweiterung in ./config/config.inc.php <small>[$config[\'plugins\'] = a...</small>';
+$labels['customer_account'] = 'Kundenkonto';
+$labels['customer_id'] = 'Kundennummer';
+$labels['invalid_customer_id'] = 'Ungültige Kundennummer';
+$labels['successfully_transferred'] = 'Credits wurde übertragen';
+$labels['merge'] = 'Credits zusammenfassen';
+$labels['credits'] = 'Credits';
+$labels['creditsupdated'] = 'Credits hat sich seit dem letzten Laden der Seite geändert';
+$labels['buynow'] = 'Credits aufladen';
+$labels['history'] = 'Kontoauszug';
+$labels['details'] = 'Details';
+$labels['receipt'] = 'Quittung';
+$labels['plugins'] = 'Erweiterungen';
+$labels['clickhere'] = 'Hier klicken';
+$labels['discardliabletopaycosts'] = 'Kostenpflichtige Downloads abwählen';
+$labels['unchecknotinstalledplugins'] = 'Nicht installierte Erweiterungen abwählen';
+$labels['sum'] = 'Summe';
+$labels['show'] = 'Anzeigen';
+$labels['hide'] = 'Verbergen';
+$labels['view'] = 'Ansehen';
+$labels['expired'] = 'verfallen';
+$labels['terms'] = 'Bedingungen';
+$labels['pricelist'] = 'Preisliste';
+$labels['forthisdownload'] = 'für diesen Download';
+$labels['remainingcredits'] = 'verbleibende Credits';
+$labels['initialdownload'] = 'Erstmaliger Download';
+$labels['keyfeatureaddition'] = 'Neue Schlüsselfunktionalität';
+$labels['codeimprovements'] = 'Code-Verbesserungen';
+$labels['servicenotavailable'] = 'Der Service ist gerade nicht verfügbar. Versuchen Sie es bitte später nocheinmal.';
+$labels['myrcerror'] = 'MyRoundcube Services sind zur Zeit nicht verfügbar.';
+$labels['getnew'] = 'Neue Kundennummer anfordern';
+$labels['getnew_hint'] = 'Wir empfehlen, die Kundennummer regelmäßig zu erneuern. Wenn Sie verdächtige Aktivitäten in Ihrem Kundenkonto bemerken, dann erneuern Sie die Kundennummer bitte umgehend.';
+$labels['transfer'] = 'Guthaben übertragen';
+$labels['submenuprefix'] = '» ';
+$labels['noplugindescription'] = 'Es konnte keine Beschreibung der Erweiterung gefunden werden.';
+$labels['emoticons_pluginname'] = 'Emotion-Shortcuts';
+$labels['emoticons_plugindescription'] = 'Emotion-Shortcuts mit Smiley-Grafiken ersetzen';
+$labels['markbuttons_pluginname'] = 'Nachrichten markieren';
+$labels['markbuttons_plugindescription'] = 'Ein Menue zum gleichzeitigen markieren mehrer Nachrichten hinzufügen.';
+$labels['keyboard_shortcuts_pluginname'] = 'Tastatureingaben';
+$labels['keyboard_shortcuts_plugindescription'] = 'Die Webmail-Oberfläche über Tastaturbefehle steuern.';
+$labels['message_highlight_pluginname'] = 'Nachrichtenhervorhebung';
+$labels['message_highlight_plugindescription'] = 'Nachrichten in der Nachrichtenliste nach bestimmten Filterkriterien hervorheben.';
+$labels['google_contacts_pluginname'] = 'Google-Adressen';
+$labels['google_contacts_plugindescription'] = 'Machen Sie Ihre Google-Kontakte verfügbar.';
+$labels['contextmenu_pluginname'] = 'Rechter Mausklick';
+$labels['contextmenu_plugindescription'] = 'Erledigen Sie viele Sachen einfach mit einem rechten Mausklick.';
+$labels['newmail_notifier_pluginname'] = 'Benachrichtigung bei neuen Nachrichten';
+$labels['newmail_notifier_plugindescription'] = 'Benachrichtigung bei neuen Nachrichten anzeigen.';
+$labels['listcommands_pluginname'] = 'Beantwortung von Mailing-Lists';
+$labels['listcommands_plugindescription'] = 'Verschiedene Optionen zur Beantwortung von Nachrichten, die an eine Mailing-List versandt werden.';
+$labels['copymessage_pluginname'] = 'Nachrichten kopieren';
+$labels['copymessage_plugindescription'] = 'Eine oder mehrer Nachrichten in einen anderen IMAP-Ordner kopieren.';
+$labels['vcard_attachments_pluginname'] = 'vCard-Anhänge';
+$labels['vcard_attachments_plugindescription'] = 'vCard-Anhänge direkt in das Adressbuch importieren.';
+$labels['importmessages_pluginname'] = 'Nachrichten importieren';
+$labels['importmessages_plugindescription'] = 'Nachrichten von einer eml- oder zip-Quelle importieren.';
+$labels['zipdownload_pluginname'] = 'Nachrichten exportieren';
+$labels['zipdownload_plugindescription'] = 'Nachrichten als zip-Datei exportieren.';
+$labels['markasjunk2_pluginname'] = 'Nachrichten als Spam kennzeichnen';
+$labels['markasjunk2_plugindescription'] = 'Nachrichten als Spam kennzeichnen oder die Spamkennzeichnung von legitimen Nachrichten entfernen.';
+$labels['markasjunk_pluginname'] = 'Nachrichten als Spam kennzeichnen';
+$labels['markasjunk_plugindescription'] = 'Nachrichten als Spam kennzeichnen oder die Spamkennzeichnung von legitimen Nachrichten entfernen.';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Google Analytics erlauben.';
+$labels['globaladdressbook_pluginname'] = 'Globales Adressbuch';
+$labels['globaladdressbook_plugindescription'] = 'Dieses Adressbuch enthält Adressen, die von Ihrem Administrator zur Verfügung gestellt werden.';
+$labels['blockspamsending_pluginname'] = 'Spamversand vermeiden';
+$labels['blockspamsending_plugindescription'] = 'Limitieren Sie den Versand von Nachrichrichten gleichen Inhalts während einer Sitzung.';
+$labels['global_config_pluginname'] = 'Konfigurations-Manager';
+$labels['global_config_plugindescription'] = 'Optimieren Sie die Performance Ihres Servers durch Zusammenfassung der einzelnen Erweiterungskonf...';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Jqueryui Javascript-Bibliothek';
+$labels['hide_blockquote_pluginname'] = 'Zitate abkürzen';
+$labels['hide_blockquote_plugindescription'] = 'Verbergen Sie längere Zitate.';
+$labels['crawler_pluginname'] = 'Crawler';
+$labels['crawler_plugindescription'] = 'Für Crawler einen alternativen Seiteninhalt ausgeben.';
+$labels['archive_pluginname'] = 'Archiv';
+$labels['archive_plugindescription'] = 'Meldungen in Archiv Ordner archivieren.';
+$labels['autologon_pluginname'] = 'Autologin';
+$labels['autologon_plugindescription'] = 'Automatisch anmelden';
+$labels['dblog_pluginname'] = 'Datenbanklogging';
+$labels['dblog_plugindescription'] = 'Logs in die Datenbank anstatt in eine Datei schreiben.';
+$labels['http_auth_pluginname'] = 'HTTP Authentifizierung';
+$labels['jscolor_pluginname'] = 'Color Picker';
+$labels['jscolor_plugindescription'] = 'Farben mittels eines Color Pickers selektieren (Hilfserweiterung).';
+$labels['tinymce_pluginname'] = 'TinyMCE - HTML Editor';
+$labels['tinymce_plugindescription'] = 'Diese Erweiterung implementiert TinyMCE PHP Compressor (http://www.tinymce.com/wiki.php/Compressors:PHP). Zusätzlich schafft diese Erweiterung die Möglichkeit, TinyMCE ohne Änderung des Roundcube-Quellcodes zu konfigurieren.';
+$labels['database_attachments_pluginname'] = 'Datenbank Dateianhänge';
+$labels['database_attachments_plugindescription'] = 'Dateianhänge über die Datenbank anstatt über das File-System verarbeiten (Hilfserweiterung).';
+$labels['help_pluginname'] = 'Hilfe';
+$labels['help_plugindescription'] = 'Webmailhilfe';
+$labels['thank_you'] = 'Herzlichen Dank!';
+$labels['done'] = 'Erledigt';
+$labels['manage_admins'] = 'Administratoren';
+$labels['plugin_manager_admins'] = 'Plugin Manager Administratoren';
+$labels['allow_plugins_configuration'] = 'Berechtigung zur Konfiguration von Erweiterungen';
+$labels['share_credits'] = 'Zugriff auf MyRC$-Credits erlauben';
+$labels['add'] = 'Hinzufügen';
+$labels['accountnotexists'] = 'Diese Konto existiert nicht';
+$labels['sharedby'] = 'Zugriff auf Kundenkonto gewährt von';
+$labels['switch'] = 'Wechseln';
+$labels['ownaccount'] = 'zum eigenen Kundenkonto';
+$labels['shareinvitation'] = 'zum Kundenkonto von';
+$labels['use_ssl'] = 'Verbindungen zu MyRoundcube-Server über SSL';
+$labels['use_hmail'] = 'hMailserver kompatible Erweiterungen nutzen';
+$labels['show_myrc_messages'] = 'Benachrichtigungen von MyRoundcube anzeigen';
+$labels['file_based_config'] = 'File-basierte Konfiguration aktivieren';
+$labels['advanced_admins'] = 'nur für fortgeschrittene Administratoren';
+$labels['compress_html'] = 'HTML-Ausgabe komprimieren';
+$labels['show_config'] = 'Aktuelle Konfiguration anzeigen';
+$labels['systemadmin'] = 'Systemadministrator';
+$labels['admin'] = 'Administrator';
+$labels['configuredby'] = 'konfiguriert durch';
+$labels['enabled'] = 'aktiviert<br />(standardmäßig)';
+$labels['protected'] = 'geschützt';
+$labels['loads_always'] = 'obligatorisch';
+$labels['loads_never'] = 'Erweiterung ist deaktiviert';
+$labels['loads_by_user'] = 'der Benutzer entscheidet';
+$labels['loads_linked'] = 'Verknüpft mit';
+$labels['unbind'] = 'Verknüpfung aufheben';
+$labels['bind'] = 'Verknüpfung herstellen';
+$labels['addplugin'] = 'Erweiterung hinzufügen';
+$labels['removeplugin'] = 'Erweiterung entfernen';
+$labels['errorplugin'] = 'Fehler: Erforderliche Erweiterung fehlt';
+$labels['errorrcversion'] = 'Fehler: Erweiterung erfordert Roundcube';
+$labels['errorphpversion'] = 'Fehler: Erweiterung erfordert PHP';
+$labels['errorphpcurl'] = 'Fehler: cURL ist nicht installiert';
+$labels['errorphpfinfo'] = 'Fehler: finfo ist nicht installiert';
+$labels['errordb'] = 'Datenbankanpassungen sind erforderlich.<br />Bitte aktivieren Sie die Erweiterung, um die Anpassungen zu starten.';
+$labels['errordb8'] = 'Datenbankanpassungen sind erforderlich.';
+$labels['syntaxerror'] = 'PHP-Syntaxerror';
+$labels['notconfigured'] = 'Erweiterung ist nicht konfiguriert';
+$labels['editconfig'] = 'Konfiguration bearbeiten';
+$labels['instructions'] = 'Anweisungen';
+$labels['dbautomatically'] = 'Anpassungen starten.';
+$labels['dbmanually'] = 'Bitte folgen Sie diesen Anweisungen.';
+$labels['ornewer'] = 'oder neuer';
+$labels['official_releases'] = 'nur offizielle Roundcube Versionen werden unterstützt';
+$labels['localizationmissing'] = 'Keine Übersetzung für Namen und Beschreibung der Erweiterung vorhanden';
+$labels['documentation'] = 'Dokumentation';
+$labels['select_plugin'] = 'Erweiterung auswählen';
+$labels['legend'] = 'Legende';
+$labels['plugindisabledbydefault'] = 'Erweiterung ist standardmäßig deaktiviert - der Benutzer kann die Erweiterung aktivieren';
+$labels['pluginenabledbydefault'] = 'Erweiterung ist standardmäßig aktiviert - der Benutzer kann die Erweiterung deaktivieren';
+$labels['pluginmandatory'] = 'Verpflichtend laden - Erweiterung ist aktiviert; der Benutzer kann die Einstellung nicht ändern';
+$labels['show_about_link'] = '"Über"-Link anzeigen';
+$labels['show_support_link'] = '"Support"-Link anzeigen';
+$labels['use_myroundcube_watermark'] = '"MyRoundcube"-Wasserzeichen benutzen';
+$labels['remove_watermark'] = 'Wasserzeichen nicht anzeigen';
+$labels['database'] = 'Datenbank';
+$labels['account_details_compressed'] = 'Buchungen wurden komprimiert';
+$labels['credits_transferred'] = 'Credits wurden übertragen';
+$labels['customer_id_changed'] = 'Kundennummer wurde geändert';
+$labels['myrcd_bought'] = 'Es wurden MyRC$ gekauft - Danke!';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/de_DE.inc b/plugin_manager/localization/de_DE.inc
new file mode 100644
index 0000000..35542cd
--- /dev/null
+++ b/plugin_manager/localization/de_DE.inc
@@ -0,0 +1,346 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/de_DE.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: myroundcube@mail4us.net - 01/13/2015 15:48:44
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Plugin Manager';
+$labels['plugindescription'] = 'Plugin Manager gibt Benutzern die Möglichkeit einzelne Erweiterungen zu aktivieren oder zu deaktivieren und hilft Administratoren Erweiterungen aktuell zu halten. Plugin Manager verändert weder das Filesystem, noch werden Erweiterungen automatisch installiert.';
+$labels['plugin_manager_title'] = 'Erweiterungen verwalten';
+$labels['plugin_manager_center'] = 'Plugin Manager Center';
+$labels['updatepm'] = 'Plugin Manager Update verfügbar.';
+$labels['updatepmrequired'] = 'Plugin Manager Update erforderlich.';
+$labels['downloadnow'] = 'Jetzt herunterladen';
+$labels['homepage'] = 'Homepage';
+$labels['calendaring'] = 'Aufgaben und Termine verwalten';
+$labels['misc'] = 'Verschiedenes';
+$labels['downloads'] = 'Downloads';
+$labels['issue'] = 'Problem';
+$labels['submitissue'] = 'Melden Sie ein Problem.<br /><br />Bitte überprüfen Sie Ihre Logs und stellen Sie relevante Informationen im Ticket zur Verfügung.<br /><br /><b>BEACHTE</b>: Sie benötigen einen Google-Account.';
+$labels['showall'] = 'Alle verfügbaren Erweiterungen anzeigen.';
+$labels['hideuptodate'] = 'Nur Erweiterungen anzeigen, für die ein Update vorliegt.';
+$labels['connectionerror'] = 'Der Server hat nicht geantwortet.';
+$labels['trylater'] = 'Bitte versuchen Sie es später nocheinmal.';
+$labels['translate'] = 'Diese Erweiterung übersetzen ';
+$labels['translationaccount'] = 'Echtzeit Übersetzeraccount (Benutzername)';
+$labels['translationserver'] = 'Echtzeit Übersetzeraccout (IMAP Server)';
+$labels['whatsthis'] = 'Was ist das?';
+$labels['restoredefaults'] = 'Grundeinstellung wiederherstellen';
+$labels['checkall'] = 'Alle auswählen';
+$labels['uncheckall'] = 'Alle abwählen';
+$labels['toggle'] = 'Auswahl umkehren';
+$labels['status'] = 'Status';
+$labels['globalplugins'] = 'Globale Erweiterungen';
+$labels['performance'] = 'Leistung';
+$labels['backend'] = 'Server-Erweiterungen';
+$labels['messagesmanagement'] = 'Nachrichtenverwaltung';
+$labels['furtherconfig'] = 'Diese Erweiterung erfordert weitere Einstellungen. Möchen Sie die Einstellungen jetzt vornehmen?';
+$labels['uninstall'] = 'Möchten Sie alle gespeicherten Einstellungen löschen?';
+$labels['uninstallconfirm'] = 'Möchten Sie Ihre persönlichen Einstellungen dieser Erweiterung behalten oder entfernen? Wenn Sie die Einstellungen entfernen, dann müssen Sie die Erweiterung bei einer späteren Aktivierung erneut konfigurieren.';
+$labels['areyousure'] = 'Sie können diese Aktion nicht rückgängig machen. Sind Sie wirklich sicher?';
+$labels['successfullydeleted'] = 'Einstellungen wurden erfolgreich entfernt.';
+$labels['successfullysaved'] = 'Erfolgreich gespeichert.';
+$labels['errorsaving'] = 'Beim Speichern ist ein Fehler aufgetreten.';
+$labels['yes'] = 'Ja';
+$labels['no'] = 'Nein';
+$labels['disable'] = 'Behalten';
+$labels['remove'] = 'Entfernen';
+$labels['savewarning'] = 'Möchten Sie Ihre Änderungen jetzt speichern?';
+$labels['plugin_manager_update'] = 'Erweiterungen erneuern';
+$labels['authors_comments'] = 'Anmerkungen des Autors (nicht übersetzt)';
+$labels['requiredby'] = 'Erweiterung wird benötigt von';
+$labels['requires'] = 'Benötigte Erweiterung(en)';
+$labels['recommended'] = 'Empfohlene Erweiterung(en)';
+$labels['update_plugins'] = 'Updates herunterladen';
+$labels['ziparchive'] = 'Zip-Archiv herunterladen';
+$labels['demoaccount'] = 'Aktion ist nicht möglich (Demo-Konto)';
+$labels['serverversion'] = 'Server-Version';
+$labels['mirrorversion'] = 'Mirror-Version';
+$labels['mirrorhost'] = 'Mirror-Server';
+$labels['comments'] = 'Voraussetzungen und Amerkungen';
+$labels['update_error'] = 'Versionskonflikt';
+$labels['update_ok'] = 'Die Erweiterung ist aktuell. Es ist kein Update erforderlich.';
+$labels['update_edit'] = 'Die Erweiterung ist veraltet. Bitte berücksichtigen Sie die nebenstehenden Hinweise.';
+$labels['servernewer'] = 'Die registrierte Version der Erweiterung ist neuer als die des Mirror-Servers.';
+$labels['orhigher'] = 'oder höher';
+$labels['rc_ok'] = 'Roundcube Core ist aktuell.';
+$labels['update_update'] = 'Die Erweiterung ist veraltet. Bitte erneuern Sie die Erweiterung unter Berücksichtigung der nebenstehenden Hinweise.';
+$labels['noupdates'] = 'Es wurden keine Updates ausgewählt.';
+$labels['rc_update'] = 'Roundcube Core veraltet. Bitte erneuern Sie Roundcube Core!';
+$labels['rc_uptodate'] = 'Roundcube Core ist aktuell.';
+$labels['rc_newer'] = 'Roundcube Core ist neuer als die Mirror-Version!';
+$labels['nottested'] = 'Bitte benutzen Sie die Erweiterungen mit Vorsicht! Möglicherweise arbeiten die Erweiterungen mit Roundcube v%s nicht oder nicht korrekt.';
+$labels['justunzip'] = 'Entpacken Sie das Archiv über die bestehende Installation.';
+$labels['guide'] = 'Anleitung';
+$labels['thirdparty'] = 'Das ist keine MyRoundcube-Erweiterung.';
+$labels['thirdpartywarning'] = 'Das ist keine MyRoundcube-Erweiterung. Damit Sie die aktuellste Version erhalten und eventuelle Hinweise des Entwicklers beachten können, wird empfohlen, diese Erweiterung nicht von diesem Mirror, sondern von der Seite des Entwicklers herunterzuladen.';
+$labels['develsite'] = 'Herunterladen';
+$labels['notinstalled'] = 'nicht installiert';
+$labels['notregistered'] = 'nicht registriert';
+$labels['roundcubeurl'] = 'Roundcube herunterladen';
+$labels['languageupdate'] = 'Übersetzungen wurden überarbeitet.';
+$labels['localizationfilesonly'] = 'Download beinhaltet nur Sprachdateien';
+$labels['donotregister'] = 'Diese Erweiterung braucht nicht registriert zu werden. Sie wird automatisch geladen.';
+$labels['register'] = 'Registrieren Sie diese Erweiterung in der Plugin Manager Konfiguration oder in ./config/main.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</small>.';
+$labels['customer_account'] = 'Kundenkonto';
+$labels['customer_id'] = 'Kundennummer';
+$labels['invalid_customer_id'] = 'Ungültige Kundennummer';
+$labels['invalid_credits'] = 'Eingabe ist ungültig';
+$labels['successfully_transferred'] = 'Guthaben wurde übertragen';
+$labels['merge'] = 'Guthaben zusammenfassen';
+$labels['credits'] = 'Guthaben';
+$labels['creditsupdated'] = 'Guthaben hat sich seit dem letzten Laden der Seite geändert';
+$labels['buynow'] = 'Guthaben aufladen';
+$labels['history'] = 'Kontoauszug';
+$labels['details'] = 'Details';
+$labels['receipt'] = 'Quittung';
+$labels['plugins'] = 'Erweiterungen';
+$labels['clickhere'] = 'Hier klicken';
+$labels['discardliabletopaycosts'] = 'Kostenpflichtige Downloads abwählen';
+$labels['unchecknotinstalledplugins'] = 'Nicht installierte Erweiterungen abwählen';
+$labels['sum'] = 'Summe';
+$labels['show'] = 'Anzeigen';
+$labels['hide'] = 'Verbergen';
+$labels['view'] = 'Ansehen';
+$labels['expired'] = 'verfallen';
+$labels['terms'] = 'Bedingungen';
+$labels['pricelist'] = 'Preisliste';
+$labels['forthisdownload'] = 'für diesen Download';
+$labels['remainingcredits'] = 'verbleibendes Guthaben';
+$labels['initialdownload'] = 'Erstmaliger Download';
+$labels['keyfeatureaddition'] = 'Neue Schlüsselfunktionalität';
+$labels['codeimprovements'] = 'Code-Verbesserungen';
+$labels['servicenotavailable'] = 'Der Service ist gerade nicht verfügbar. Versuchen Sie es bitte später nocheinmal.';
+$labels['myrcerror'] = 'MyRoundcube Services sind zur Zeit nicht verfügbar.';
+$labels['getnew'] = 'Neue Kundennummer anfordern';
+$labels['getnew_hint'] = 'Wir empfehlen, die Kundennummer regelmäßig zu erneuern. Wenn Sie verdächtige Aktivitäten in Ihrem Kundenkonto bemerken, dann erneuern Sie die Kundennummer bitte umgehend.';
+$labels['transfer'] = 'Guthaben übertragen';
+$labels['submenuprefix'] = '» ';
+$labels['printdetails'] = 'Drucken';
+$labels['noplugindescription'] = 'Es konnte keine Beschreibung der Erweiterung gefunden werden.';
+$labels['welcome_to_plugin_manager'] = 'Plugin Manager - Herzlich willkommen!';
+$labels['about_to_create_account'] = 'Plugin Manager wird nun ein priviligiertes Administrationskonto einrichten.';
+$labels['create_account_proceed'] = 'Dazu muss sichergestellt sein, dass Sie der Server-Administrator sind.';
+$labels['please_create'] = 'Bitte erstellen Sie im Wurzelverzeichnis Ihrer Roundcube-Installation die folgende Datei:';
+$labels['thank_you'] = 'Herzlichen Dank!';
+$labels['done'] = 'Erledigt';
+$labels['manage_admins'] = 'Administratoren';
+$labels['plugin_manager_admins'] = 'Plugin Manager Administratoren';
+$labels['allow_plugins_configuration'] = 'Berechtigung zur Konfiguration von Erweiterungen';
+$labels['share_credits'] = 'Zugriff auf MyRC$-Guthaben erlauben';
+$labels['add'] = 'Hinzufügen';
+$labels['accountnotexists'] = 'Diese Konto existiert nicht';
+$labels['sharedby'] = 'Zugriff auf Kundenkonto gewährt von';
+$labels['switch'] = 'Wechseln';
+$labels['ownaccount'] = 'zum eigenen Kundenkonto';
+$labels['shareinvitation'] = 'zum Kundenkonto von';
+$labels['enable_notifications'] = 'Update-Benachrichtigungen aktivieren';
+$labels['enable_notifications_note'] = 'Beachte: Plugin Manager kontaktiert MyRoundcube-Mirror-Servers zur Abfrage verfügbarer Updates einmal täglich.';
+$labels['notifications_cc'] = 'Benachrichtigungen zusätzlich senden (CC) an';
+$labels['notifications_cc_note'] = 'Beachte: Update-Benachrichtigungen werden an alle Plugin Manager Administratoren versendet. Bestimmen Sie in diesem Feld einen zusätzlichen Empfänger, z.B. user@gmail.com oder eine Mailingliste.';
+$labels['serverconfiguration'] = 'Server-Konfiguration';
+$labels['pluginsconfiguration'] = 'Plugin-Konfiguration';
+$labels['use_ssl'] = 'Verbindungen zu MyRoundcube-Server über SSL';
+$labels['use_hmail'] = 'hMailserver kompatible Erweiterungen nutzen';
+$labels['load_splitter'] = 'Statische Dateien durch alternative bedienen';
+$labels['show_myrc_messages'] = 'Benachrichtigungen von MyRoundcube anzeigen';
+$labels['maintenance_mode'] = 'Wartungsmodus';
+$labels['maintenance_mode_hint'] = 'Deaktiviert temporär alle Plugins. Wird benutzt, um Plugins für größere Neuerungen zu aktualisieren. Der Plugin Manager deaktiviert alle aktiven Plugins und erlaubt, trotzdem auf das Plugin Center zuzugreifen, um die aktuelleren Plugins von unseren Servern herunterzuladen.';
+$labels['running_in_maintenance_mode'] = 'Webmail läuft im Wartungsmodus.';
+$labels['serverwide'] = 'Serverebene';
+$labels['file_based_config'] = 'File-basierte Konfiguration aktivieren';
+$labels['advanced_admins'] = 'nur für fortgeschrittene Administratoren';
+$labels['compress_html'] = 'HTML-Ausgabe komprimieren';
+$labels['show_config'] = 'Gegenwärtige Konfiguration anzeigen';
+$labels['systemadmin'] = 'Systemadministrator';
+$labels['admin'] = 'Administrator';
+$labels['configuredby'] = 'konfiguriert durch';
+$labels['enabled'] = 'aktiviert<br />(standardmäßig)';
+$labels['protected'] = 'geschützt';
+$labels['skins'] = 'Benutzeroberflächen';
+$labels['loads_always'] = 'verpflichtend laden';
+$labels['loads_never'] = 'Erweiterung ist deaktiviert';
+$labels['loads_by_user'] = 'der Benutzer entscheidet';
+$labels['loads_linked'] = 'Verknüpft mit';
+$labels['unbind'] = 'Verknüpfung aufheben';
+$labels['bind'] = 'Verknüpfung herstellen';
+$labels['addplugin'] = 'Erweiterung hinzufügen';
+$labels['removeplugin'] = 'Erweiterung entfernen';
+$labels['errorplugin'] = 'Error: Erforderliche Erweiterung fehlt';
+$labels['errorrcversion'] = 'Error: Erweiterung erfordert Roundcube';
+$labels['errorphpversion'] = 'Error: Erweiterung erfordert PHP';
+$labels['errorphpcurl'] = 'Error: cURL ist nicht installiert';
+$labels['errorphpfinfo'] = 'Error: finfo ist nicht installiert';
+$labels['errordb'] = 'Datenbankanpassungen sind erforderlich.<br />Bitte aktivieren Sie die Erweiterung, um die Anpassungen zu starten.';
+$labels['errordb8'] = 'Datenbankanpassungen sind erforderlich.';
+$labels['syntaxerror'] = 'PHP-Syntaxerror';
+$labels['notconfigured'] = 'Erweiterung ist nicht konfiguriert';
+$labels['editconfig'] = 'Konfiguration bearbeiten';
+$labels['instructions'] = 'Anleitung';
+$labels['dbautomatically'] = 'Anpassungen starten.';
+$labels['dbmanually'] = 'Bitte folgen Sie diesen Anweisungen.';
+$labels['ornewer'] = 'oder neuer';
+$labels['official_releases'] = 'nur offizielle Roundcubeversionen werden unterstützt';
+$labels['localizationmissing'] = 'Keine Übersetzung für Namen und Beschreibung der Erweiterung vorhanden';
+$labels['documentation'] = 'Dokumentation';
+$labels['select_plugin'] = 'Erweiterung auswählen';
+$labels['legend'] = 'Legende';
+$labels['plugindisabledbydefault'] = 'Erweiterung ist standardmäßig deaktiviert - der Benutzer kann die Erweiterung aktivieren';
+$labels['pluginenabledbydefault'] = 'Erweiterung ist standardmäßig aktiviert - der Benutzer kann die Erweiterung deaktivieren';
+$labels['pluginmandatory'] = 'Verpflichtend laden - Erweiterung ist aktiviert; der Benutzer kann die Einstellung nicht ändern';
+$labels['show_about_link'] = '"Über"-Link anzeigen';
+$labels['show_support_link'] = '"Support"-Link anzeigen';
+$labels['use_myroundcube_watermark'] = '"MyRoundcube"-Wasserzeichen benutzen';
+$labels['remove_watermark'] = 'Wasserzeichen nicht anzeigen';
+$labels['database'] = 'Datenbank';
+$labels['account_details_compressed'] = 'Buchungen wurden komprimiert';
+$labels['credits_transferred'] = 'Credits wurden übertragen';
+$labels['customer_id_changed'] = 'Kundennummer wurde geändert';
+$labels['myrcd_bought'] = 'Es wurden MyRC$ gekauft - Danke!';
+$labels['myrcd_refunded'] = 'Es wurden MyRC$ erstattet';
+$labels['PHPMyAdmin'] = 'PHPMyAdmin';
+$labels['ipmismatch'] = 'Download von IP %s nicht möglich (Client-IP stimmt nicht überein).<br />Benutzen Sie % oder navigieren Sie zu %s von IP %s aus.';
+$labels['emoticons_pluginname'] = 'Emotion-Shortcuts';
+$labels['emoticons_plugindescription'] = 'Emotion-Shortcuts mit Smiley-Grafiken ersetzen';
+$labels['markbuttons_pluginname'] = 'Nachrichten markieren';
+$labels['markbuttons_plugindescription'] = 'Ein Menue zum gleichzeitigen markieren mehrer Nachrichten hinzufügen.';
+$labels['keyboard_shortcuts_pluginname'] = 'Tastatureingaben';
+$labels['keyboard_shortcuts_plugindescription'] = 'Die Webmail-Oberfläche über Tastaturbefehle steuern.';
+$labels['message_highlight_pluginname'] = 'Nachrichten hervorheben';
+$labels['message_highlight_plugindescription'] = 'Nachrichten in der Nachrichtenliste nach bestimmten Filterkriterien hervorheben.';
+$labels['google_contacts_pluginname'] = 'Google-Adressen';
+$labels['google_contacts_plugindescription'] = 'Machen Sie Ihre Google-Kontakte verfügbar.';
+$labels['contextmenu_pluginname'] = 'Rechter Mausklick';
+$labels['contextmenu_plugindescription'] = 'Erledigen Sie viele Sachen einfach mit einem rechten Mausklick.';
+$labels['newmail_notifier_pluginname'] = 'Benachrichtigung bei neuen Nachrichten';
+$labels['newmail_notifier_plugindescription'] = 'Benachrichtigung bei neuen Nachrichten anzeigen.';
+$labels['listcommands_pluginname'] = 'Beantwortung von Mailing-Lists';
+$labels['listcommands_plugindescription'] = 'Verschiedene Optionen zur Beantwortung von Nachrichten, die an eine Mailing-List versandt werden.';
+$labels['copymessage_pluginname'] = 'Nachrichten kopieren';
+$labels['copymessage_plugindescription'] = 'Eine oder mehrer Nachrichten in einen anderen IMAP-Ordner kopieren.';
+$labels['vcard_attachments_pluginname'] = 'vCard-Anhänge';
+$labels['vcard_attachments_plugindescription'] = 'vCard-Anhänge direkt in das Adressbuch importieren.';
+$labels['zipdownload_pluginname'] = 'Nachrichten exportieren';
+$labels['zipdownload_plugindescription'] = 'Nachrichten als zip-Datei exportieren.';
+$labels['markasjunk2_pluginname'] = 'Nachrichten als Spam kennzeichnen';
+$labels['markasjunk2_plugindescription'] = 'Nachrichten als Spam kennzeichnen oder die Spamkennzeichnung von legitimen Nachrichten entfernen.';
+$labels['markasjunk_pluginname'] = 'Nachrichten als Spam kennzeichnen';
+$labels['markasjunk_plugindescription'] = 'Nachrichten als Spam kennzeichnen oder die Spamkennzeichnung von legitimen Nachrichten entfernen.';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Google Analytics erlauben.';
+$labels['globaladdressbook_pluginname'] = 'Globales Adressbuch';
+$labels['globaladdressbook_plugindescription'] = 'Dieses Adressbuch enthält Adressen, die von Ihrem Administrator zur Verfügung gestellt werden.';
+$labels['blockspamsending_pluginname'] = 'Spamversand vermeiden';
+$labels['blockspamsending_plugindescription'] = 'Limitieren Sie den Versand von Nachrichrichten gleichen Inhalts während einer Sitzung.';
+$labels['global_config_pluginname'] = 'Konfigurations-Manager';
+$labels['global_config_plugindescription'] = 'Optimieren Sie die Performance Ihres Servers durch Zusammenfassung der einzelnen Erweiterungskonfigurationen in einer zentralen Konfiguration.';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Jqueryui Javascript-Bibliothek';
+$labels['hide_blockquote_pluginname'] = 'Zitate abkürzen';
+$labels['hide_blockquote_plugindescription'] = 'Verbergen Sie längere Zitate.';
+$labels['crawler_pluginname'] = 'Crawler';
+$labels['crawler_plugindescription'] = 'Für Crawler einen alternativen Seiteninhalt ausgeben.';
+$labels['archive_pluginname'] = 'Archiv';
+$labels['archive_plugindescription'] = 'Archiviere Nachricht in Archiv Ordner';
+$labels['autologon_pluginname'] = 'Automatische Anmeldung';
+$labels['autologon_plugindescription'] = 'Automatisch einloggen';
+$labels['openpgpjs_pluginname'] = 'OpenPGPjs';
+$labels['openpgpjs_plugindescription'] = 'Des PGP in Roundcube';
+$labels['dblog_pluginname'] = 'Logging';
+$labels['dblog_plugindescription'] = 'Logs in die Datenbank anstatt einer Datei schreiben.';
+$labels['gibberish_pluginname'] = 'Gibberish Encryption';
+$labels['gibberish_plugindescription'] = 'Hilfserweiterung zur Implentierung von Gibberish-AES-Verschlüsselung.';
+$labels['http_request_pluginname'] = 'HTTP Request';
+$labels['http_request_plugindescription'] = 'Hilfserweiterung zur Implementierung von HTTP-Requests via cURL oder fsockopen.';
+$labels['http_auth_pluginname'] = 'HTTP Authentifizierung';
+$labels['http_auth_plugindescription'] = 'HTTP Authentifizierung (Hilfserweiterung)';
+$labels['http_authentication_pluginname'] = 'HTTP-Authentifizierung (Standard)';
+$labels['http_authentication_plugindescription'] = 'Falls eine HTTP-Authentifizierung besteht, dann automatisch mit den entsprechenden Zugangsdaten einloggen.';
+$labels['jscolor_pluginname'] = 'Color Picker';
+$labels['jscolor_plugindescription'] = 'Farben mittels eines Color Pickers eingeben (Hilfserweiterung).';
+$labels['tinymce_pluginname'] = 'TinyMCE - HTML Editor';
+$labels['tinymce_plugindescription'] = 'Diese Erweiterung implementiert TinyMCE PHP Compressor (http://www.tinymce.com/wiki.php/Compressors:PHP). Zusätzlich schafft diese Erweiterung die Möglichkeit, TinyMCE ohne Änderung des Roundcube-Quellcodes zu konfigurieren.';
+$labels['lang_sel_pluginname'] = 'Sprachauswahl';
+$labels['lang_sel_plugindescription'] = 'Sprache beim Login auswählen.';
+$labels['newuser_pluginname'] = 'Neuer Benutzer';
+$labels['newuser_plugindescription'] = 'Informen Sie den Administrator wenn sich ein neuer Benutzer registriert und senden Sie eine Willkommens-Nachricht an den neuen Benutzer.';
+$labels['placeholder_pluginname'] = 'Placeholder Attribute';
+$labels['placeholder_plugindescription'] = 'Placeholder Attribute zu HTML-Input-Elementen (text/password) hinzufügen.';
+$labels['qtip_pluginname'] = 'jQueryUI Tool Tips';
+$labels['qtip_plugindescription'] = 'jQueryUI tool tips (Hilfserweiterung).';
+$labels['sabredav_pluginname'] = 'SabreDAV';
+$labels['sabredav_plugindescription'] = 'Diese Erweiterung erstellt Konten auf SabreDAV-Servern und synchronisiert Passwörter.';
+$labels['savepassword_pluginname'] = 'Passwörter speichern';
+$labels['savepassword_plugindescription'] = 'Diese Erweiterung wird von anderen Erweiterungen benötigt, die auf das IMAP-Passwort zurückgreifen müssen (Hilfserweiterung).';
+$labels['database_attachments_pluginname'] = 'Database Attachments';
+$labels['database_attachments_plugindescription'] = 'Dateianhänge über die Datenbank anstatt über das File-System verarbeiten (Hilfserweiterung).';
+$labels['help_pluginname'] = 'Hilfe';
+$labels['help_plugindescription'] = 'Webmailhilfe';
+$labels['new_user_dialog_pluginname'] = 'Eingabe der Identität erzwingen';
+$labels['new_user_dialog_plugindescription'] = 'Fordern Sie neue Benutzer mittels eines Dialogs zur Eingabe der Identitätseinstellungen auf.';
+$labels['rcguard_pluginname'] = 'ReCAPTCHA';
+$labels['rcguard_plugindescription'] = 'Mittels ReCAPTCHA ungültige Login-Versuche limitieren.';
+$labels['domain_check_pluginname'] = 'Domain überprüfen';
+$labels['domain_check_plugindescription'] = 'Zugang zum Webmail nur für bestimmte Domains erlauben.';
+$labels['tasklist_pluginname'] = 'Aufgaben';
+$labels['tasklist_plugindescription'] = 'Erstelle Aufgaben und Unteraufgaben mit Erinnerungen.';
+$labels['virtuser_query_pluginname'] = 'Virtuelle Benutzer (datenbankbasiert)';
+$labels['virtuser_query_plugindescription'] = 'Datenbankbasierte User-to-Email und Email-to-User Auflösung';
+$labels['virtuser_file_pluginname'] = 'Virtuelle Benutzer (filebasiert)';
+$labels['virtuser_file_plugindescription'] = 'Filebasierte User-to-Email und Email-to-User Auflösung';
+$labels['userinfo_pluginname'] = 'Benutzerinformation';
+$labels['userinfo_plugindescription'] = 'Zeigen diverse Informationen über den aktuellen Benutzer an.';
+$labels['subscriptions_option_pluginname'] = 'IMAP Einträge';
+$labels['subscriptions_option_plugindescription'] = 'Verwalte IMAP Einträge';
+$labels['filters_pluginname'] = 'Filter';
+$labels['filters_plugindescription'] = 'Webmailseitige Filter verwalten.';
+$labels['forgot_password_pluginname'] = 'Passwort vergessen';
+$labels['forgot_password_plugindescription'] = 'Passwort Anfragen zurücksetzen.';
+$labels['sieverules_pluginname'] = 'Sieve-Filter';
+$labels['sieverules_plugindescription'] = 'Sieve_Filter verwalten.';
+$labels['managesieve_pluginname'] = 'Sieve-Filter';
+$labels['managesieve_plugindescription'] = 'Sieve-Filter verwalten.';
+$labels['acl_pluginname'] = 'Access-Control-Listen (ACL)';
+$labels['acl_plugindescription'] = 'Access-Control-Listen (ACL) verwalten.';
+$labels['vacation_pluginname'] = 'Abwesenheitsnachricht';
+$labels['vacation_plugindescription'] = 'Abwesenheitsnachricht einstellen.';
+$labels['password_pluginname'] = 'Passwort ändern';
+$labels['password_plugindescription'] = 'Benutzer erlauben Passwort zu ändern.';
+$labels['redundant_attachments_pluginname'] = 'Redundante Anhänge';
+$labels['redundant_attachments_plugindescription'] = 'Das Plugin Redundante Anhänge speicher temporär hochgeladene Anhänge doppelt. Sie werden je in der Datenbank und im lokalen Dateisystem abgelegt.';
+$labels['example_addressbook_pluginname'] = 'Beispiel Adressbuch';
+$labels['example_addressbook_plugindescription'] = 'Beispiel Code um ein zusätzliches Adressbuch einzufügen.';
+$labels['debug_logger_pluginname'] = 'Debug Logger';
+$labels['debug_logger_plugindescription'] = 'Debug Logger aktiviert erweitertes Logging für Debug Zwecke.';
+$labels['show_additional_headers_pluginname'] = 'Zeige zusätzliche Nachrichten Headers';
+$labels['show_additional_headers_plugindescription'] = 'Proof-of-Concept Erweiterung welche zusätzliche Headers in der Nachrichtenansicht anzeigt.';
+$labels['additional_message_headers_pluginname'] = 'Zusätzliche Headers';
+$labels['additional_message_headers_plugindescription'] = 'Sehr einfache Erweiterung welche zusätzliche Headers zu ausgehenden Nachrichten hinzufügt oder entfernt.';
+$labels['new_user_identity_pluginname'] = 'Neue Benutzeridentität';
+$labels['new_user_identity_plugindescription'] = 'Neue Nutzeridentität synchronisiert die Standardidentität eines neuen Nutzers bei der Erstanmeldung mit einem LDAP-Verzeichnis.';
+$labels['squirrelmail_usercopy_pluginname'] = 'Übertrage Squirrelmail Nutzer';
+$labels['squirrelmail_usercopy_plugindescription'] = 'Übernehme Einstellungen einer alten Squirrelmail Installation.';
+$labels['yubikey_authentication_pluginname'] = 'Yubico\'s Yubikey Authentifizierung';
+$labels['yubikey_authentication_plugindescription'] = 'Erweiterung zur Implementierung von Yubico\'s Yubikey Authentifizierung.';
+$labels['sauserprefs_pluginname'] = 'Spamassassin\'s Benutzereinstellungen';
+$labels['sauserprefs_plugindescription'] = 'Fügt einen \'Spam\' Tab zu den \'Persönlichen Einstellungen\' hinzu und erlaubt dem Benutzer, seine SpamAssassin-Einstellungen zu verändern.';
+$labels['dkimstatus_pluginname'] = 'DKIM-Status';
+$labels['dkimstatus_plugindescription'] = 'DKIMSTATUTS zeigt den Status der Überprüfung der DKIM-Signature beim Lesen einer Nachricht an.';
+$labels['roundcube_openpgp_pluginname'] = 'Roundcube OpenPGP';
+$labels['roundcube_openpgp_plugindescription'] = 'Mit dieser Erweiterung können Sie OpenPGP in Roundcube verwenden. Es hilft Ihnen Schlüssel zu erzeugen, zu verwalten und bei der Emailabwicklung zu verwenden.';
+$labels['automatic_addressbook_pluginname'] = 'Automatisches Adressbuch';
+$labels['automatic_addressbook_plugindescription'] = 'Erzeugt ein Adressbuch und fügt automatisch die gesammelten Mailadressen dort ein. So muss nicht jeder Kontakt manuell hinzugefügt werden.';
+$labels['calendar_pluginname'] = 'Kalender';
+$labels['calendar_plugindescription'] = 'Verwalten Sie ihre Termine mit einem Webmail-Kalender';
+$labels['attachment_reminder_pluginname'] = 'Attachment Reminder';
+$labels['attachment_reminder_plugindescription'] = 'Benutzer erinnern, Anhänge anzuheften.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/el_GR.inc b/plugin_manager/localization/el_GR.inc
new file mode 100644
index 0000000..807c630
--- /dev/null
+++ b/plugin_manager/localization/el_GR.inc
@@ -0,0 +1,74 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| language/el_GR/labels.inc |
+| |
+| Language file of the RoundCube Webmail client |
+| Copyright (C) 2008-2012, RoundQube Dev. - Switzerland |
+| |
++-----------------------------------------------------------------------+
+| Author: |
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Διαχειριστής Προσθέτων';
+$labels['plugin_manager_title'] = 'Διαχείριση Προσθέτων';
+$labels['downloadnow'] = 'Μεταφόρτωση τώρα';
+$labels['misc'] = 'Διάφορα';
+$labels['downloads'] = 'μεταφορτώσεις';
+$labels['showall'] = 'Προβολή όλων των Προσθέτων';
+$labels['hideuptodate'] = 'Προβολή μόνο αναβαθμίσεων';
+$labels['trylater'] = 'Παρακαλώ προσπαθήστε αργότερα...';
+$labels['translate'] = 'Μεταφράστε αυτό το Πρόσθετο';
+$labels['restoredefaults'] = 'Επαναφορά Προεπιλογών';
+$labels['checkall'] = 'Επιλογή Όλων';
+$labels['uncheckall'] = 'Αποεπιλογή Όλων';
+$labels['status'] = 'Κατάσταση';
+$labels['backend'] = 'Πρόσθετα Διακομιστή';
+$labels['messagesmanagement'] = 'Διαχείριση Μηνυμάτων';
+$labels['furtherconfig'] = 'Θέλετε να ρυθμίσετε αυτό το πρόσθετο τώρα?';
+$labels['uninstall'] = 'Πρόκειται να απενεργοποιήσετε αυτό το πρόσθετο. Θέλετε να αφαιρέσετε όλες τις αποθηκευμένες ρυθμίσεις μόνιμα;';
+$labels['successfullydeleted'] = 'Οι ρυθμίσεις αφαιρέθηκαν επιτυχώς.';
+$labels['successfullysaved'] = 'Αποθηκεύτηκε επιτυχώς.';
+$labels['errorsaving'] = 'Προέκυψε σφάλμα κατά την αποθήκευση.';
+$labels['yes'] = 'Ναι';
+$labels['no'] = 'Όχι';
+$labels['disable'] = 'Απενεργοποίηση';
+$labels['remove'] = 'Αφαίρεση';
+$labels['plugin_manager_update'] = 'Αναβάθμιση Προσθέτων';
+$labels['recommended'] = 'Προτεινόμενα Πρόσθετα';
+$labels['serverversion'] = 'Έκδοση Διακομιστή';
+$labels['orhigher'] = 'ή μεγαλύτερο';
+$labels['noupdates'] = 'Δεν επιλέχθηκαν Ενημερώσεις.';
+$labels['guide'] = 'Διαβάστε περισσότερα...';
+$labels['thirdparty'] = 'Αυτό δεν είναι πρόσθετο του MyRoundcube.';
+$labels['develsite'] = 'Μεταφόρτωση';
+$labels['notinstalled'] = 'μη εγκατεστημένο';
+$labels['roundcubeurl'] = 'Μεταφόρτωση Roundcube';
+$labels['customer_account'] = 'Λογαριασμός Πελάτη';
+$labels['history'] = 'Ιστορικό Λογαριασμού';
+$labels['details'] = 'Λεπτομέρειες';
+$labels['receipt'] = 'Απόδειξη';
+$labels['plugins'] = 'Πρόσθετα';
+$labels['sum'] = 'Σύνολο';
+$labels['show'] = 'Προβολή';
+$labels['hide'] = 'Απόκρυψη';
+$labels['view'] = 'προβολή';
+$labels['terms'] = 'Όροι';
+$labels['codeimprovements'] = 'Βελτιώσεις κώδικα';
+$labels['google_contacts_pluginname'] = 'Επαφές Google';
+$labels['newmail_notifier_plugindescription'] = 'Ειδοποίηση σε νέα μηνύματα.';
+$labels['importmessages_pluginname'] = 'Εισαγωγή Μηνυμάτων';
+$labels['importmessages_plugindescription'] = 'Εισαγωγή μηνυματων από αρχείο zip ή πηγή eml.';
+$labels['zipdownload_pluginname'] = 'Εξαγωγή Μηνυμάτων';
+$labels['markasjunk2_pluginname'] = 'Σημείωση Μηνυμάτων ως Ανεπιθύμητα';
+$labels['google_ads_pluginname'] = 'Διαφημίσεις Google';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['lang_sel_pluginname'] = 'Επιλογή Γλώσσας';
+$labels['lang_sel_plugindescription'] = 'Επιλογή γλώσσας στη σελίδα εισόδου.';
+$labels['newuser_pluginname'] = 'Νέος Χρήστης';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/en_GB.inc b/plugin_manager/localization/en_GB.inc
new file mode 100644
index 0000000..b841d10
--- /dev/null
+++ b/plugin_manager/localization/en_GB.inc
@@ -0,0 +1,139 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| ./plugins/plugin_manager/localization/en_GB.inc
+|
+| Language file of MyRoundcube Plugins Bundle
+| Copyright (C) 2010-2012, Roland 'rosali' Liebl
+| Licensed under the GNU GPL
+|
++-----------------------------------------------------------------------+
+| Author: myroundcube@mail4us.net - 03/20/2012 09:34:44
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Plugin Manager';
+$labels['plugindescription'] = 'Plugin Manager gives users the option to enable or disable plugins (at the user account level), while it helps admins to stay current with plugin updates, bug fixes, centralized downloads, documentation and recommendations. Plugin Manager does not modify your file system, nor it will install plugins automatically.';
+$labels['plugin_manager_title'] = 'Manage Plugins';
+$labels['plugin_manager_center'] = 'Plugin Manager Centre';
+$labels['updatepm'] = 'Plugin Manager update available.';
+$labels['updatepmrequired'] = 'Plugin Manager update required.';
+$labels['downloadnow'] = 'Download now';
+$labels['homepage'] = 'Home page';
+$labels['calendaring'] = 'Calendaring';
+$labels['misc'] = 'Miscellaneous';
+$labels['downloads'] = 'downloads';
+$labels['issue'] = 'Issue';
+$labels['submitissue'] = 'Report an issue.<br /><br />Please check your logs and provide relevant information in the ticket.<br /><br /><b>NOTE</b>: a Google Account is required.';
+$labels['showall'] = 'Show All Plugins';
+$labels['hideuptodate'] = 'Show Updates Only';
+$labels['connectionerror'] = 'The remote server did not respond to a connection attempt.';
+$labels['trylater'] = 'Please try later...';
+$labels['translate'] = 'Translate this plugin';
+$labels['translationaccount'] = 'Realtime translation account (username)';
+$labels['translationserver'] = 'Realtime translation account (IMAP server)';
+$labels['whatsthis'] = 'What\'s this?';
+$labels['restoredefaults'] = 'Restore Defaults';
+$labels['checkall'] = 'Check All';
+$labels['uncheckall'] = 'Uncheck All';
+$labels['toggle'] = 'Toggle Selection';
+$labels['status'] = 'Status';
+$labels['globalplugins'] = 'Global Plugins';
+$labels['performance'] = 'Performance';
+$labels['backend'] = 'Server Plugins';
+$labels['messagesmanagement'] = 'Message Management';
+$labels['furtherconfig'] = 'Do you want to configure this plugin now?';
+$labels['uninstall'] = 'You are about to disable this plugin. Do you want to remove all saved settings permanently?';
+$labels['uninstallconfirm'] = 'You are about to disable this plugin. WARNING: Select »DISABLE« to disable this plugin while keeping your current data and configuration stored in our server. Select »REMOVE« if you want all data and configuration managed by this plugin to be removed permanently from our databases. NOTE: this action cannot be undone.';
+$labels['areyousure'] = 'You can\'t undo this action. Are you really sure?';
+$labels['successfullydeleted'] = 'Settings have been removed successfully.';
+$labels['successfullysaved'] = 'Successfully saved.';
+$labels['errorsaving'] = 'An error occured while saving.';
+$labels['yes'] = 'Yes';
+$labels['no'] = 'No';
+$labels['disable'] = 'Disable';
+$labels['remove'] = 'Remove';
+$labels['savewarning'] = 'Do you want to save your changes now?';
+$labels['plugin_manager_update'] = 'Update Plugins';
+$labels['authors_comments'] = 'Author\'s Comments (not translated)';
+$labels['requiredby'] = 'Plugin is required by';
+$labels['requires'] = 'Plugin requires';
+$labels['recommended'] = 'Recommended Plugins';
+$labels['update_plugins'] = 'Plugin Downloads';
+$labels['ziparchive'] = 'Download Zip Archive';
+$labels['demoaccount'] = 'Sorry, action is disabled (Demo Account)';
+$labels['serverversion'] = 'Server Version';
+$labels['mirrorversion'] = 'Mirror Version';
+$labels['mirrorhost'] = 'Mirror Server';
+$labels['comments'] = 'Requirements and Update Notes';
+$labels['update_error'] = 'Version mismatch';
+$labels['update_ok'] = 'Most recent has been detected. No update is necessary.';
+$labels['update_edit'] = 'Plugin must be re-configured or requires database adjustments. Please consider Update Notes.';
+$labels['servernewer'] = 'Registered plugin is newer than mirror version.';
+$labels['orhigher'] = 'or higher';
+$labels['rc_ok'] = 'Roundcube Core is up to date.';
+$labels['update_update'] = 'Plugin is outdated, please update! Consider update notes.';
+$labels['noupdates'] = 'No updates selected.';
+$labels['rc_update'] = 'Roundcube core is outdated, please update!';
+$labels['rc_uptodate'] = 'Roundcube core is up to date.';
+$labels['rc_newer'] = 'Roundcube core is newer than mirror version!';
+$labels['nottested'] = 'Please use plugins with care! We don\'t know if hosted plugins work with Roundcube v%s.';
+$labels['justunzip'] = 'Just unzip the archive over your existing installation.';
+$labels['guide'] = 'Read more...';
+$labels['thirdparty'] = 'This is not a MyRoundcube plugin.';
+$labels['thirdpartywarning'] = 'This is a third party plugin. We recommend not to download the plugin from this mirror server and instead download it from the developer\'s site, to ensure you get the latest version as well as notes and advice from its developer.';
+$labels['develsite'] = 'Download';
+$labels['notinstalled'] = 'not installed';
+$labels['notregistered'] = 'not registered';
+$labels['roundcubeurl'] = 'Download Roundcube';
+$labels['languageupdate'] = 'Localization update is available.';
+$labels['localizationfilesonly'] = 'Note: Download contains only localisation files';
+$labels['donotregister'] = 'Don\'t register this plugin. It is loaded automatically.';
+$labels['register'] = 'Register this plugin in Plugin Manager\'s configuration or in ./config/config.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</small>.';
+$labels['customer_account'] = 'Customer Account';
+$labels['customer_id'] = 'Customer ID';
+$labels['invalid_customer_id'] = 'Invalid Customer ID';
+$labels['invalid_credits'] = 'Invalid credits';
+$labels['successfully_transferred'] = 'Credits successfully transferred';
+$labels['noplugindescription'] = 'No plugin description detected.';
+$labels['markbuttons_pluginname'] = 'Mark Message Buttons';
+$labels['markbuttons_plugindescription'] = 'Add control icons under message list separator to quickly mark messages.';
+$labels['keyboard_shortcuts_pluginname'] = 'Keyboard Shortcuts';
+$labels['keyboard_shortcuts_plugindescription'] = 'Enter commands using keyboard shortcuts.';
+$labels['message_highlight_pluginname'] = 'Highlight Messages';
+$labels['message_highlight_plugindescription'] = 'Highlight messages which matches your filter options.';
+$labels['google_contacts_pluginname'] = 'Google Contacts';
+$labels['google_contacts_plugindescription'] = 'Access your Google Contacts.';
+$labels['contextmenu_pluginname'] = 'Context Menu';
+$labels['contextmenu_plugindescription'] = 'Enable right click context menu functionality.';
+$labels['newmail_notifier_pluginname'] = 'New Mail Notifier';
+$labels['newmail_notifier_plugindescription'] = 'Notify on new messages.';
+$labels['listcommands_pluginname'] = 'Reply Mailing Lists';
+$labels['listcommands_plugindescription'] = 'Various options to reply to messages sent from mailing lists.';
+$labels['copymessage_pluginname'] = 'Copy Message(s)';
+$labels['copymessage_plugindescription'] = 'Copy message(s) into another IMAP folder.';
+$labels['vcard_attachments_pluginname'] = 'vCard Attachments';
+$labels['vcard_attachments_plugindescription'] = 'Add a box to messages which have a vcard attachment to import the contact directly into the addre...';
+$labels['zipdownload_pluginname'] = 'Export Messages';
+$labels['zipdownload_plugindescription'] = 'Export messages as a zip file.';
+$labels['markasjunk2_pluginname'] = 'Mark Messages as Spam';
+$labels['markasjunk2_plugindescription'] = 'Mark Messages as spam or not spam.';
+$labels['markasjunk_pluginname'] = 'Mark Messages as Spam';
+$labels['markasjunk_plugindescription'] = 'Mark Messages as spam or not spam.';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Include Google Analytics.';
+$labels['globaladdressbook_pluginname'] = 'Global Addressbook';
+$labels['globaladdressbook_plugindescription'] = 'This is a readonly addressbook provided by your administrator.';
+$labels['blockspamsending_pluginname'] = 'Prevent Sending Spam';
+$labels['blockspamsending_plugindescription'] = 'Allow sending out only a specific amount of messages with same body during one session.';
+$labels['global_config_pluginname'] = 'Configuration Manager';
+$labels['global_config_plugindescription'] = 'This is a configuration manager plugin. It optimizes your server by centralizing plugin configura...';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Jqueryui javascript library';
+$labels['automatic_addressbook_pluginname'] = 'Automatic Addressbook';
+$labels['automatic_addressbook_plugindescription'] = 'Creates an addressbook and automatically inserts the collected email addresses there. This eliminates the need to manually add each contact.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/en_US.inc b/plugin_manager/localization/en_US.inc
new file mode 100644
index 0000000..288e5d9
--- /dev/null
+++ b/plugin_manager/localization/en_US.inc
@@ -0,0 +1,346 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/en_US.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 01/16/2015 03:54:10
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Plugin Manager';
+$labels['plugindescription'] = 'Plugin Manager gives users the options to enable and/or disable plugins (at the user account level) while it helps admins to stay current with updates, up-to-date plugins, bug fixes, centralized downloads, documentation and recommendations. Plugin Manager does not modify your file system nor it will install plugins automatically.';
+$labels['plugin_manager_title'] = 'Manage Plugins';
+$labels['plugin_manager_center'] = 'Plugin Manager Center';
+$labels['updatepm'] = 'Plugin Manager update available.';
+$labels['updatepmrequired'] = 'Plugin Manager update required.';
+$labels['downloadnow'] = 'Download now';
+$labels['homepage'] = 'Homepage';
+$labels['calendaring'] = 'Calendaring';
+$labels['misc'] = 'Miscellaneous';
+$labels['downloads'] = 'downloads';
+$labels['issue'] = 'Issue';
+$labels['submitissue'] = 'Report issue.<br /><br />Please check errors logs and provide relevant information in the ticket.<br /><br /><b>NOTE</b>: Google Account is required.';
+$labels['showall'] = 'Show all Plugins';
+$labels['hideuptodate'] = 'Show Updates only';
+$labels['connectionerror'] = 'The remote server did not respond to a connection attempt.';
+$labels['trylater'] = 'Please try later...';
+$labels['translate'] = 'Translate this plugin';
+$labels['translationaccount'] = 'Realtime translation account (username)';
+$labels['translationserver'] = 'Realtime translation account (IMAP server)';
+$labels['whatsthis'] = 'What\'s this?';
+$labels['restoredefaults'] = 'Restore defaults';
+$labels['checkall'] = 'Check all';
+$labels['uncheckall'] = 'Uncheck all';
+$labels['toggle'] = 'Toggle Selection';
+$labels['status'] = 'Status';
+$labels['globalplugins'] = 'Global Plugins';
+$labels['performance'] = 'Performance';
+$labels['backend'] = 'Server Plugins';
+$labels['messagesmanagement'] = 'Messages Management';
+$labels['furtherconfig'] = 'Would you like to configure this plugin now?';
+$labels['uninstall'] = 'You are about to disable this plugin. Do you want to remove all saved settings permanently?';
+$labels['uninstallconfirm'] = 'You are about to disable this plugin. WARNING: Select »DISABLE« to disable this plugin while keeping your current data and configuration stored in our server if you plan to use it again later. Select »REMOVE« if you want all data and configuration managed by this plugin to be removed permanently from our databases. Note this action cannot be undone.';
+$labels['areyousure'] = 'You can\'t undo this action. Are you really sure?';
+$labels['successfullydeleted'] = 'Settings have been removed successfully.';
+$labels['successfullysaved'] = 'Successfully saved.';
+$labels['errorsaving'] = 'An error occured while saving.';
+$labels['yes'] = 'Yes';
+$labels['no'] = 'No';
+$labels['disable'] = 'Disable';
+$labels['remove'] = 'Remove';
+$labels['savewarning'] = 'Do you want to save your changes already?';
+$labels['plugin_manager_update'] = 'Update Plugins';
+$labels['authors_comments'] = 'Author\'s Comments (not translated)';
+$labels['requiredby'] = 'Plugin is required by';
+$labels['requires'] = 'Plugin requires';
+$labels['recommended'] = 'Recommended Plugins';
+$labels['update_plugins'] = 'Plugins downloads';
+$labels['ziparchive'] = 'Download Zip-Archive';
+$labels['demoaccount'] = 'Sorry, action is disabled (Demo Account)';
+$labels['serverversion'] = 'Server Version';
+$labels['mirrorversion'] = 'Mirror Version';
+$labels['mirrorhost'] = 'Mirror Server';
+$labels['comments'] = 'Requirements and Update Notes';
+$labels['update_error'] = 'Version mismatch';
+$labels['update_ok'] = 'Most recent has been detected. No update necessary.';
+$labels['update_edit'] = 'Plugin has to be re-configured or requires database adjustments. Please consider Update Notes.';
+$labels['servernewer'] = 'Registered Plugin is newer than Mirror Version.';
+$labels['orhigher'] = 'or higher';
+$labels['rc_ok'] = 'Roundcube Core is up to date.';
+$labels['update_update'] = 'Plugin is outdated. Please update! Consider Update Notes.';
+$labels['noupdates'] = 'No Updates selected.';
+$labels['rc_update'] = 'Roundcube Core is outdated. Please update!';
+$labels['rc_uptodate'] = 'Roundcube Core is up to date.';
+$labels['rc_newer'] = 'Roundcube Core is newer than Mirror version!';
+$labels['nottested'] = 'Please use Plugins with care! We don\'t know if hosted Plugins work with Roundcube v%s.';
+$labels['justunzip'] = 'Just unzip the Archive over your existing Installation.';
+$labels['guide'] = 'Read more...';
+$labels['thirdparty'] = 'This is not a MyRoundcube Plugin.';
+$labels['thirdpartywarning'] = 'This is a third party plugin. It is recommended not to download the plugin from our mirror. Instead, download it from the developer\'s site to ensure you get the latest version, as well as notes and advices of its developer.';
+$labels['develsite'] = 'Download';
+$labels['notinstalled'] = 'not installed';
+$labels['notregistered'] = 'not registered';
+$labels['roundcubeurl'] = 'Download Roundcube';
+$labels['languageupdate'] = 'Localization Update is available.';
+$labels['localizationfilesonly'] = 'Note: Download contains only localization files';
+$labels['donotregister'] = 'Don\'t register this plugin. It is loaded automatically.';
+$labels['register'] = 'Register this plugin in Plugin Manager\'s configuration or in ./config/config.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</small>.';
+$labels['customer_account'] = 'Customer Account';
+$labels['customer_id'] = 'Customer ID';
+$labels['invalid_customer_id'] = 'Invalid Customer ID';
+$labels['invalid_credits'] = 'Invalid credits';
+$labels['successfully_transferred'] = 'Credits successfully transferred';
+$labels['merge'] = 'Merge Credits';
+$labels['credits'] = 'Credits';
+$labels['creditsupdated'] = 'Credits have changed since last page refresh';
+$labels['buynow'] = 'Buy credits now';
+$labels['history'] = 'Account History';
+$labels['details'] = 'Details';
+$labels['receipt'] = 'Receipt';
+$labels['plugins'] = 'Plugins';
+$labels['clickhere'] = 'Click here';
+$labels['discardliabletopaycosts'] = 'Discard incurring costs downloads';
+$labels['unchecknotinstalledplugins'] = 'Discard not installed plugins downloads';
+$labels['sum'] = 'Sum';
+$labels['show'] = 'Show';
+$labels['hide'] = 'Hide';
+$labels['view'] = 'view';
+$labels['expired'] = 'expired';
+$labels['terms'] = 'Terms';
+$labels['pricelist'] = 'Downloads prices chart';
+$labels['forthisdownload'] = 'for this download';
+$labels['remainingcredits'] = 'remaining credits';
+$labels['initialdownload'] = 'Initial download';
+$labels['keyfeatureaddition'] = 'New key feature';
+$labels['codeimprovements'] = 'Code improvements';
+$labels['servicenotavailable'] = 'Service is currently not available. Please try later!';
+$labels['myrcerror'] = 'MyRoundcube services are currently not available.';
+$labels['getnew'] = 'Require a new Customer ID';
+$labels['getnew_hint'] = 'We recommend to renew your Customer ID frequently. If you notice any suspicious activity in your account details, renew your Customer ID immediately.';
+$labels['transfer'] = 'Transfer credits';
+$labels['submenuprefix'] = '» ';
+$labels['printdetails'] = 'Print account details';
+$labels['noplugindescription'] = 'No plugin description detected.';
+$labels['welcome_to_plugin_manager'] = 'Welcome to Plugin Manager';
+$labels['about_to_create_account'] = 'Plugin Manager is about to create a privileged administration account.';
+$labels['create_account_proceed'] = 'To proceed, you need to confirm that you are the service administrator.';
+$labels['please_create'] = 'Please, create the following file in the root folder of your Roundcube installation:';
+$labels['thank_you'] = 'Thank you!';
+$labels['done'] = 'Done';
+$labels['manage_admins'] = 'Administrators';
+$labels['plugin_manager_admins'] = 'Plugin Manager Administrators';
+$labels['allow_plugins_configuration'] = 'Grant plugins configuration permissions';
+$labels['share_credits'] = 'Share MyRC$ credits';
+$labels['add'] = 'Add';
+$labels['accountnotexists'] = 'Account does not exist';
+$labels['sharedby'] = 'Customer account shared by';
+$labels['switch'] = 'Switch';
+$labels['ownaccount'] = 'to own account';
+$labels['shareinvitation'] = 'to shared account';
+$labels['enable_notifications'] = 'Enable plugins update notifications';
+$labels['enable_notifications_note'] = 'Note: Plugin Manager queries MyRoundcube mirror servers for available updates once a day only.';
+$labels['notifications_cc'] = 'Cc for notifications';
+$labels['notifications_cc_note'] = 'Note: Update notifications are sent to all Plugin Manager administrators. Use this field to notify an additional recipient. E.g: john.doh@gmail.com or a distribution list email address.';
+$labels['serverconfiguration'] = 'Server Configuration';
+$labels['pluginsconfiguration'] = 'Plugins Configuration';
+$labels['use_ssl'] = 'Establish secure SSL connections to MyRoundcube servers';
+$labels['use_hmail'] = 'Use hMailserver compatible plugins';
+$labels['load_splitter'] = 'Offload static files';
+$labels['show_myrc_messages'] = 'Display notification messages from MyRoundcube servers';
+$labels['maintenance_mode'] = 'Maintenance mode';
+$labels['maintenance_mode_hint'] = 'Temporarily disable all active plugins. Used to upgrade plugins during major releases. Plugin Manager disables all active plugins, allowing you to still access Plugin Manager Center to download the latest plugins updates from our mirror servers.';
+$labels['running_in_maintenance_mode'] = 'Webmail is running in maintenance mode.';
+$labels['serverwide'] = 'server wide configuration';
+$labels['file_based_config'] = 'Enable Plugin Manager file-based configuration';
+$labels['advanced_admins'] = 'recommended for advanced administrators only';
+$labels['compress_html'] = 'Shrink HTML output';
+$labels['show_config'] = 'Show current configuration';
+$labels['systemadmin'] = 'System Administrator';
+$labels['admin'] = 'Administrator';
+$labels['configuredby'] = 'configured by';
+$labels['enabled'] = 'Enabled<br />(default)';
+$labels['protected'] = 'Protected';
+$labels['skins'] = 'Skins';
+$labels['loads_always'] = 'Mandatory';
+$labels['loads_never'] = 'Plugin is disabled';
+$labels['loads_by_user'] = 'User can determine its usage';
+$labels['loads_linked'] = 'Bound to';
+$labels['unbind'] = 'unbind';
+$labels['bind'] = 'bind';
+$labels['addplugin'] = 'Add plugin';
+$labels['removeplugin'] = 'Remove plugin';
+$labels['errorplugin'] = 'Error: Required plugins are missing';
+$labels['errorrcversion'] = 'Error: Plugin requires Roundcube';
+$labels['errorphpversion'] = 'Error: Plugin requires PHP';
+$labels['errorphpcurl'] = 'Error: cURL is not installed';
+$labels['errorphpfinfo'] = 'Error: finfo is not installed';
+$labels['errordb'] = 'Database adjustments required.<br />Please enable plugin to start database tasks.';
+$labels['errordb8'] = 'Database adjustments required.';
+$labels['syntaxerror'] = 'PHP Syntax Error';
+$labels['notconfigured'] = 'Plugin is not configured';
+$labels['editconfig'] = 'Edit configuration';
+$labels['instructions'] = 'Instructions';
+$labels['dbautomatically'] = 'Start adjustments.';
+$labels['dbmanually'] = 'Please follow these instructions.';
+$labels['ornewer'] = 'or newer';
+$labels['official_releases'] = 'we support official Roundcube releases only';
+$labels['localizationmissing'] = 'No labels for Plugin name and Plugin description detected';
+$labels['documentation'] = 'Documentation';
+$labels['select_plugin'] = 'Select plugin';
+$labels['legend'] = 'Legend';
+$labels['plugindisabledbydefault'] = 'Plugin is disabled by default - User can determine its usage';
+$labels['pluginenabledbydefault'] = 'Plugin is enabled by default - User can determine its usage';
+$labels['pluginmandatory'] = 'Mandatory - Plugin is enabled, users can\'t enable/disable plugin';
+$labels['show_about_link'] = 'Show "About" link';
+$labels['show_support_link'] = 'Show "Support" link';
+$labels['use_myroundcube_watermark'] = 'Use "MyRoundcube" watermark';
+$labels['remove_watermark'] = 'Do not display watermark at all';
+$labels['database'] = 'Database';
+$labels['account_details_compressed'] = 'Account details compressed';
+$labels['credits_transferred'] = 'Credits transferred';
+$labels['customer_id_changed'] = 'Customer ID changed';
+$labels['myrcd_bought'] = 'MyRC$ bought - Thank you!';
+$labels['myrcd_refunded'] = 'MyRC$ refunded';
+$labels['PHPMyAdmin'] = 'PHPMyAdmin';
+$labels['ipmismatch'] = 'No download possible from IP %s <small>(Client IP does not match)</small>.<br />Use %s or browse to %s from IP %s.';
+$labels['emoticons_pluginname'] = 'Emoticon shortcuts';
+$labels['emoticons_plugindescription'] = 'Replace emoticon shortcuts by Smiley images';
+$labels['markbuttons_pluginname'] = 'Mark Message buttons';
+$labels['markbuttons_plugindescription'] = 'Add control icons to the message list separator to quickly mark messages.';
+$labels['keyboard_shortcuts_pluginname'] = 'Keyboard Shortcuts';
+$labels['keyboard_shortcuts_plugindescription'] = 'Enter commands using keyboard shortcuts.';
+$labels['message_highlight_pluginname'] = 'Highlight Messages';
+$labels['message_highlight_plugindescription'] = 'Highlight messages which matches your filter options.';
+$labels['google_contacts_pluginname'] = 'Google Contacts';
+$labels['google_contacts_plugindescription'] = 'Access your Google Contacts.';
+$labels['contextmenu_pluginname'] = 'Context Menu';
+$labels['contextmenu_plugindescription'] = 'Enable right-click contextual menu functionality in webmail.';
+$labels['newmail_notifier_pluginname'] = 'New Mail Notifier';
+$labels['newmail_notifier_plugindescription'] = 'Notify on new messages.';
+$labels['listcommands_pluginname'] = 'Reply Mailing Lists';
+$labels['listcommands_plugindescription'] = 'Various options to reply to messages sent from mailing lists.';
+$labels['copymessage_pluginname'] = 'Copy Message(s)';
+$labels['copymessage_plugindescription'] = 'Copy message(s) into another IMAP folder.';
+$labels['vcard_attachments_pluginname'] = 'vCard Attachments';
+$labels['vcard_attachments_plugindescription'] = 'Add a box to messages which have a vcard attachment to import the contact directly into the addressbook.';
+$labels['zipdownload_pluginname'] = 'Export Messages';
+$labels['zipdownload_plugindescription'] = 'Download selected messages (.eml) or complete folders, as a zip file.';
+$labels['markasjunk2_pluginname'] = 'Mark Messages as Spam';
+$labels['markasjunk2_plugindescription'] = 'Mark Messages as spam or not spam.';
+$labels['markasjunk_pluginname'] = 'Mark Messages as Spam';
+$labels['markasjunk_plugindescription'] = 'Mark Messages as spam or not spam.';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Include Google Analytics.';
+$labels['globaladdressbook_pluginname'] = 'Global Addressbook';
+$labels['globaladdressbook_plugindescription'] = 'This is a readonly addressbook provided by your administrator.';
+$labels['blockspamsending_pluginname'] = 'Prevent Sending Spam';
+$labels['blockspamsending_plugindescription'] = 'Allow sending out only a specific amount of messages with same body during one session.';
+$labels['global_config_pluginname'] = 'Configuration Manager';
+$labels['global_config_plugindescription'] = 'This is a configuration manager plugin. It optimizes your server by centralizing plugin configuration files. It also makes administrative tasks easier by enabling the use of a single configuration file for all your plugins.';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Jqueryui javascript library';
+$labels['hide_blockquote_pluginname'] = 'Hide blockquote';
+$labels['hide_blockquote_plugindescription'] = 'Hide citation when the count of lines is greater than the specified value.';
+$labels['crawler_pluginname'] = 'Crawler';
+$labels['crawler_plugindescription'] = 'Fake page content for crawlers.';
+$labels['archive_pluginname'] = 'Archive';
+$labels['archive_plugindescription'] = 'Archive messages in an archive folder.';
+$labels['autologon_pluginname'] = 'Autologon';
+$labels['autologon_plugindescription'] = 'Logon automatically.';
+$labels['openpgpjs_pluginname'] = 'OpenPGPjs';
+$labels['openpgpjs_plugindescription'] = 'Des PGP in Roundcube.';
+$labels['dblog_pluginname'] = 'Log to database';
+$labels['dblog_plugindescription'] = 'Log events to database instead of logging to file.';
+$labels['gibberish_pluginname'] = 'Gibberish Encryption';
+$labels['gibberish_plugindescription'] = 'A helper plugin for Gibberish AES encryption.';
+$labels['http_request_pluginname'] = 'HTTP Request';
+$labels['http_request_plugindescription'] = 'A helper plugin to perform HTTP requests via cURL or fsockopen.';
+$labels['http_auth_pluginname'] = 'HTTP Authentication';
+$labels['http_auth_plugindescription'] = 'A helper plugin to support HTTP Authentication for other plugins. Note: This plugin is different from default Roundcube http_authentication plugin.';
+$labels['http_authentication_pluginname'] = 'HTTP Authentication (default)';
+$labels['http_authentication_plugindescription'] = 'Make use of an existing HTTP authentication and perform login with the existing user credentials.';
+$labels['jscolor_pluginname'] = 'Color Picker';
+$labels['jscolor_plugindescription'] = 'A helper plugin to display a color picker.';
+$labels['tinymce_pluginname'] = 'TinyMCE - HTML Editor';
+$labels['tinymce_plugindescription'] = 'This plugin implements TinyMCE PHP Compressor (http://www.tinymce.com/wiki.php/Compressors:PHP). Additionally, it adds the ability to configure TinyMCE settings without editing Roundcube\'s core files.';
+$labels['lang_sel_pluginname'] = 'Select Language';
+$labels['lang_sel_plugindescription'] = 'Select language on login page.';
+$labels['newuser_pluginname'] = 'New User';
+$labels['newuser_plugindescription'] = 'Inform administrators when a new user is registered via webmail interface and send a welcome message to the new user on the first login.';
+$labels['placeholder_pluginname'] = 'Placeholder Attributes';
+$labels['placeholder_plugindescription'] = 'Add placeholder attributes to text and password input elements.';
+$labels['qtip_pluginname'] = 'jQueryUI Tool Tips';
+$labels['qtip_plugindescription'] = 'A helper plugin to use jQueryUI qtips.';
+$labels['sabredav_pluginname'] = 'SabreDAV';
+$labels['sabredav_plugindescription'] = 'Creates SabreDAV accounts for CalDAV calendar access when new users in Roundcube are created and associates passwords if they have been changed.';
+$labels['savepassword_pluginname'] = 'Save Passwords';
+$labels['savepassword_plugindescription'] = 'This is a helper plugin which is required by other plugins.';
+$labels['database_attachments_pluginname'] = 'Database Attachments';
+$labels['database_attachments_plugindescription'] = 'Helper Plugin to manage attachments in database.';
+$labels['help_pluginname'] = 'Help';
+$labels['help_plugindescription'] = 'Webmail help';
+$labels['new_user_dialog_pluginname'] = 'New User Dialog';
+$labels['new_user_dialog_plugindescription'] = 'Present identity settings dialog box to new users. When a new user is created, this plugin checks the default identity and sets a session flag in case it is incomplete. An overlay box will appear on the screen until the user has reviewed and completed her/his identity.';
+$labels['rcguard_pluginname'] = 'ReCAPTCHA';
+$labels['rcguard_plugindescription'] = 'Force CAPTCHA challenge after a number of failed login attempts.';
+$labels['domain_check_pluginname'] = 'Check Domain';
+$labels['domain_check_plugindescription'] = 'Restrict webmail login to specific domains.';
+$labels['tasklist_pluginname'] = 'Tasklist';
+$labels['tasklist_plugindescription'] = 'Manager your tasks with the Webmail Tasklist.';
+$labels['virtuser_query_pluginname'] = 'Virtual user query';
+$labels['virtuser_query_plugindescription'] = 'Database based User-to-Email and Email-to-User lookup.';
+$labels['virtuser_file_pluginname'] = 'Virtual user query';
+$labels['virtuser_file_plugindescription'] = 'File based User-to-Email and Email-to-User lookup.';
+$labels['userinfo_pluginname'] = 'User information';
+$labels['userinfo_plugindescription'] = 'Display some information about the current user.';
+$labels['subscriptions_option_pluginname'] = 'IMAP subscriptions';
+$labels['subscriptions_option_plugindescription'] = 'Manage IMAP subscriptions.';
+$labels['filters_pluginname'] = 'Filters';
+$labels['filters_plugindescription'] = 'Manage client side filters.';
+$labels['forgot_password_pluginname'] = 'Forgot Password';
+$labels['forgot_password_plugindescription'] = 'Reset Password requests.';
+$labels['sieverules_pluginname'] = 'Sieve Filters';
+$labels['sieverules_plugindescription'] = 'Manage Sieve filters.';
+$labels['managesieve_pluginname'] = 'Sieve Filters';
+$labels['managesieve_plugindescription'] = 'Manage Sieve filters.';
+$labels['acl_pluginname'] = 'Access Control Lists';
+$labels['acl_plugindescription'] = 'Folders Access Control Lists Management.';
+$labels['vacation_pluginname'] = 'Away Message';
+$labels['vacation_plugindescription'] = 'Manage Away Message (vacation notification).';
+$labels['password_pluginname'] = 'Change Password';
+$labels['password_plugindescription'] = 'Allow users to change their password.';
+$labels['redundant_attachments_pluginname'] = 'Redundant Attachments';
+$labels['redundant_attachments_plugindescription'] = 'Redundant attachments plugin provides a redundant storage for temporary uploaded attachment files. They are stored in both the database backend as well as on the local file system.';
+$labels['example_addressbook_pluginname'] = 'Example Address Book';
+$labels['example_addressbook_plugindescription'] = 'Sample code to add an additional address book.';
+$labels['debug_logger_pluginname'] = 'Debug Logger';
+$labels['debug_logger_plugindescription'] = 'Debug logger enables enhanced logging for debugging purposes.';
+$labels['show_additional_headers_pluginname'] = 'Show additional message headers';
+$labels['show_additional_headers_plugindescription'] = 'Proof-of-concept plugin which will fetch additional headers and display them in the message view.';
+$labels['additional_message_headers_pluginname'] = 'Additional Message Headers';
+$labels['additional_message_headers_plugindescription'] = 'Very simple plugin which will add additional headers to or remove them from outgoing messages.';
+$labels['new_user_identity_pluginname'] = 'New User Identity';
+$labels['new_user_identity_plugindescription'] = 'New User Identity populates a new user\'s default identity from LDAP on their first visit.';
+$labels['squirrelmail_usercopy_pluginname'] = 'Migrate Squirrelmail Users';
+$labels['squirrelmail_usercopy_plugindescription'] = 'Copy a new users identity and settings from a nearby Squirrelmail installation.';
+$labels['yubikey_authentication_pluginname'] = 'Yubico\'s Yubikey authentication';
+$labels['yubikey_authentication_plugindescription'] = 'Plugin to use Yubico\'s YubiKey to authentication on Roundcube webmail.';
+$labels['sauserprefs_pluginname'] = 'Spamassassin user preferences';
+$labels['sauserprefs_plugindescription'] = 'Adds a \'Spam\' tab to the \'Personal Settings\' to allow the user to change their SpamAssassin preferences.';
+$labels['dkimstatus_pluginname'] = 'DKIM status';
+$labels['dkimstatus_plugindescription'] = 'DKIMSTATUS displays the status of the DKIM Signature of each email your read in Roundcube.';
+$labels['roundcube_openpgp_pluginname'] = 'Roundcube OpenPGP';
+$labels['roundcube_openpgp_plugindescription'] = 'This extension implements OpenPGP in Roundcube. It helps to generate, manage and use encryption keys.';
+$labels['automatic_addressbook_pluginname'] = 'Automatic Addressbook';
+$labels['automatic_addressbook_plugindescription'] = 'Creates an addressbook and automatically inserts the collected email addresses there. This eliminates the need to manually add each contact.';
+$labels['calendar_pluginname'] = 'Calendar';
+$labels['calendar_plugindescription'] = 'Manage your events with the Webmail Calendar.';
+$labels['attachment_reminder_pluginname'] = 'Attachment Reminder';
+$labels['attachment_reminder_plugindescription'] = 'Remind users to attach a file before sending a message.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/es_ES.inc b/plugin_manager/localization/es_ES.inc
new file mode 100644
index 0000000..d0ec284
--- /dev/null
+++ b/plugin_manager/localization/es_ES.inc
@@ -0,0 +1,346 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/es_ES.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 01/16/2015 03:54:51
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Administrador de complementos';
+$labels['plugindescription'] = 'El administrador de complementos brinda a los usuarios la opcion de habilitar y/o deshabilitar complementos (a nivel de la cuenta del usuario) mientras ayuda a los administradores a estar al día con las actualizaciones, complementos actualizados, solucionar problemas, realiza descargas centralizadas, documentacion y recomendaciones. El administrador de complementos no modifica su sistema de archivos, ni instalará complementos automáticamente';
+$labels['plugin_manager_title'] = 'Administrar complementos';
+$labels['plugin_manager_center'] = 'Centro de administración de complementos';
+$labels['updatepm'] = 'Actualización de Administrador de Complementos disponible.';
+$labels['updatepmrequired'] = 'Actualización de Administrador de Complementos requerida.';
+$labels['downloadnow'] = 'Descargar ahora';
+$labels['homepage'] = 'Página principal';
+$labels['calendaring'] = 'Calendarios';
+$labels['misc'] = 'Misceláneo';
+$labels['downloads'] = 'descargas';
+$labels['issue'] = 'Problema';
+$labels['submitissue'] = 'Reportar un problema.<br><br>Por favor, compruebe los registros y proporcione información relevante de su problema.<br><br>NOTA: Se requiere cuenta de Google';
+$labels['showall'] = 'Mostrar todos los complementos';
+$labels['hideuptodate'] = 'Mostrar sólo actualizaciones ';
+$labels['connectionerror'] = 'El servidor remoto no respondió al intento de conexión.';
+$labels['trylater'] = 'Por favor, intente más tarde...';
+$labels['translate'] = 'Traducir este complemento';
+$labels['translationaccount'] = 'Cuenta de traducción en tiempo real (usuario)';
+$labels['translationserver'] = 'Cuenta de traducción en tiempo real (servidor IMAP)';
+$labels['whatsthis'] = '¿Qué es esto?';
+$labels['restoredefaults'] = 'Restaurar Predeterminados';
+$labels['checkall'] = 'Seleccionar Todos';
+$labels['uncheckall'] = 'Deseleccionar Todos';
+$labels['toggle'] = 'Alternar Selección';
+$labels['status'] = 'Estado';
+$labels['globalplugins'] = 'Globales';
+$labels['performance'] = 'Rendimiento';
+$labels['backend'] = 'Plugins de Servidor';
+$labels['messagesmanagement'] = 'Administración de Mensaje';
+$labels['furtherconfig'] = '¿Quiere configurar este complemento ahora?';
+$labels['uninstall'] = 'Está a punto de desactivar este complemento. ¿Desea eliminar todas las configuraciones guardadas de forma permanente?';
+$labels['uninstallconfirm'] = 'Está a punto de desactivar este complemento. ADVERTENCIA: Seleccione »DESACTIVAR« para desactivar este plugin, manteniendo los datos actuales y su configuración almacenados en nuestro servidor si quiere poder utilizarlos más adelante. Seleccione »REMOVER« si desea que todos los datos y la configuración que gestiona este plugin sean removidos permanentemente de nuestra base de datos. Tenga en cuenta que esta acción no se puede deshacer.';
+$labels['areyousure'] = 'No podrá deshacer esta acción. ¿Está realmente seguro?';
+$labels['successfullydeleted'] = 'Configuraciones eliminadas exitosamente.';
+$labels['successfullysaved'] = 'Guardado exitosamente.';
+$labels['errorsaving'] = 'Ha ocurrido un error mientras se guardaba.';
+$labels['yes'] = 'Sí';
+$labels['no'] = 'No';
+$labels['disable'] = 'Desactivar';
+$labels['remove'] = 'Remover';
+$labels['savewarning'] = '¿Desea guardar los cambios ya?';
+$labels['plugin_manager_update'] = 'Actualizar Complementos';
+$labels['authors_comments'] = 'Comentarios de autor (no traducido)';
+$labels['requiredby'] = 'Complemento requerido por';
+$labels['requires'] = 'Complemento requiere';
+$labels['recommended'] = 'Complementos Recomendados';
+$labels['update_plugins'] = 'Actualizar complementos';
+$labels['ziparchive'] = 'Descargar Zip-Archivo';
+$labels['demoaccount'] = 'Descarga no disponible. (Cuenta Demo)';
+$labels['serverversion'] = 'Versión en Servidor';
+$labels['mirrorversion'] = 'Versión en Proveedor';
+$labels['mirrorhost'] = 'Servidor Proveedor';
+$labels['comments'] = 'Notas de actualización';
+$labels['update_error'] = 'Versión no coincide';
+$labels['update_ok'] = 'Lo más reciente ha sido detectado. No es necesario actualizar.';
+$labels['update_edit'] = 'Complemento debe ser reconfigurado o requiere de ajustes de bases de datos. Por favor, considere las Notas de Actualización.';
+$labels['servernewer'] = 'Complemento registrado es más reciente que la versión del proveedor.';
+$labels['orhigher'] = 'o superior';
+$labels['rc_ok'] = 'Versión de Roundcube en fecha.';
+$labels['update_update'] = 'Complemento no actualizado. Por favor, actualice! Considere las Notas de Actualización.';
+$labels['noupdates'] = 'No hay actualizaciones seleccionadas.';
+$labels['rc_update'] = 'Versión de Roundcube desactualizada. Por favor, actualice!';
+$labels['rc_uptodate'] = 'Versión de Roundcube en fecha.';
+$labels['rc_newer'] = 'Versión de Roundcube es más reciente que la versión del proveedor!';
+$labels['nottested'] = 'Por favor, use estos complementos con cuidado! No sabemos si complementos externos trabajan con Roundcube v%s.';
+$labels['justunzip'] = 'Simplemente descomprima el archivo sobre la instalación existente.';
+$labels['guide'] = 'Leer más...';
+$labels['thirdparty'] = 'Este no es un complemento de MyRoundcube.';
+$labels['thirdpartywarning'] = 'Este es un plugin de terceros. Se recomienda no descargar el plugin desde nuestro servidor proveedor. En vez, descárguelo desde el sitio de su programador para asegurarse de obtener la versión más reciente, así como notas y consejos de su programador.';
+$labels['develsite'] = 'Descarga';
+$labels['notinstalled'] = 'No instalado';
+$labels['notregistered'] = 'No registrado';
+$labels['roundcubeurl'] = 'Descargar Roundcube';
+$labels['languageupdate'] = 'Actualización de Idioma disponible.';
+$labels['localizationfilesonly'] = 'Nota: Descarga contiene sólo archivos de localización';
+$labels['donotregister'] = 'No registre este complemento. Se carga automáticamente.';
+$labels['register'] = 'Registre este complemento en ./config/config.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</i></small>';
+$labels['customer_account'] = 'Cuenta de Cliente';
+$labels['customer_id'] = 'ID de Cliente';
+$labels['invalid_customer_id'] = 'ID de cliente inválido';
+$labels['invalid_credits'] = 'Créditos inválidos';
+$labels['successfully_transferred'] = 'Créditos transferidos éxitosamente';
+$labels['merge'] = 'Combinar Créditos';
+$labels['credits'] = 'Créditos';
+$labels['creditsupdated'] = 'Sus créditos han variado desde la última actualización de página';
+$labels['buynow'] = 'Comprar créditos ahora';
+$labels['history'] = 'Historial de Cuenta';
+$labels['details'] = 'Detalles';
+$labels['receipt'] = 'Recibo';
+$labels['plugins'] = 'Complementos';
+$labels['clickhere'] = 'Haga clic aquí';
+$labels['discardliabletopaycosts'] = 'Descartar descargas que incurren gastos';
+$labels['unchecknotinstalledplugins'] = 'Descartar descargas de complementos no instalados';
+$labels['sum'] = 'Suma';
+$labels['show'] = 'Mostrar';
+$labels['hide'] = 'Ocultar';
+$labels['view'] = 'ver';
+$labels['expired'] = 'expirado';
+$labels['terms'] = 'Condiciones';
+$labels['pricelist'] = 'Lista de Precios de Descargas';
+$labels['forthisdownload'] = 'por esta descarga';
+$labels['remainingcredits'] = 'créditos restantes';
+$labels['initialdownload'] = 'descarga inicial';
+$labels['keyfeatureaddition'] = 'Nueva característica clave';
+$labels['codeimprovements'] = 'Mejoras de Código';
+$labels['servicenotavailable'] = 'El servicio no está disponible actualmente. Por favor, inténte más tarde!';
+$labels['myrcerror'] = 'MyRoundcube servicios no están actualmente disponibles.';
+$labels['getnew'] = 'Solicitar un ID de Cliente nuevo';
+$labels['getnew_hint'] = 'Se recomienda renovar su ID de Cliente frecuentemente. Si usted nota cualquier actividad sospechosa en los detalles de su cuenta, renueve su ID de Cliente inmediatamente.';
+$labels['transfer'] = 'Transferir Créditos';
+$labels['submenuprefix'] = '» ';
+$labels['printdetails'] = 'Imprimir detalles de cuenta ';
+$labels['noplugindescription'] = 'Descripción de complemento no detectada.';
+$labels['welcome_to_plugin_manager'] = 'Bienvenido al Administrador de Complementos';
+$labels['about_to_create_account'] = 'El Administrador de Complementos está a punto de crear una cuenta de administración privilegiada.';
+$labels['create_account_proceed'] = 'Para continuar, debe confirmar que usted es el administrador del servicio.';
+$labels['please_create'] = 'Por favor, cree el siguiente archivo en la carpeta raíz de la instalación de Roundcube:';
+$labels['thank_you'] = '¡Gracias!';
+$labels['done'] = 'Listo';
+$labels['manage_admins'] = 'Administradores';
+$labels['plugin_manager_admins'] = 'Cuentas adicionales como Administrador de Complementos';
+$labels['allow_plugins_configuration'] = 'Conceder permisos de configuración de complementos';
+$labels['share_credits'] = 'Compartir MyRC$ créditos';
+$labels['add'] = 'Añadir';
+$labels['accountnotexists'] = 'Cuenta no existe';
+$labels['sharedby'] = 'Cuenta de cliente compartida por';
+$labels['switch'] = 'Cambiar a';
+$labels['ownaccount'] = 'cuenta propia';
+$labels['shareinvitation'] = 'a cuenta compartida';
+$labels['enable_notifications'] = 'Habilitar notificaciones de actualización';
+$labels['enable_notifications_note'] = 'Nota: El Administrador de Complementos consulta los servidores MyRoundcube para actualizaciones disponibles una sola vez al día.';
+$labels['notifications_cc'] = 'Cc de notificaciones';
+$labels['notifications_cc_note'] = 'Nota: Las notificaciones de actualización se envían a todos los administradores de complementos. Utilice este campo para notificar a un receptor adicional. Por ejemplo: john.doh@gmail.com o una dirección de correo electrónico de lista de distribución.';
+$labels['serverconfiguration'] = 'Configuración de Servidor';
+$labels['pluginsconfiguration'] = 'Configuración de Complementos';
+$labels['use_ssl'] = 'Establecer conexiones seguras SSL con los servidores MyRoundcube';
+$labels['use_hmail'] = 'Usar complementos compatibles de hmailserver';
+$labels['load_splitter'] = 'Externalizar archivos estáticos';
+$labels['show_myrc_messages'] = 'Mostrar mensajes de notificación de los servidores MyRoundcube';
+$labels['maintenance_mode'] = 'Modo de mantenimiento';
+$labels['maintenance_mode_hint'] = 'Se utiliza para actualizar complementos durante versiones principales. El Administrador de Complementos desactiva todos los complementos activos y le permite seguir teniendo acceso al Centro de Descargas de Complementos para obtener las más recientes actualizaciones en los servidores de distribución.';
+$labels['running_in_maintenance_mode'] = 'El webmail está funcionando en modo de mantenimiento.';
+$labels['serverwide'] = 'configuración de servidor';
+$labels['file_based_config'] = 'Habilitar configuración del Administrador de Complementos basada en archivos';
+$labels['advanced_admins'] = 'recomendado para administradores avanzados solamente';
+$labels['compress_html'] = 'Comprimir HTML';
+$labels['show_config'] = 'Mostrar configuración actual';
+$labels['systemadmin'] = 'Administrador del Sistema';
+$labels['admin'] = 'Administrador';
+$labels['configuredby'] = 'configurado por';
+$labels['enabled'] = 'Activado<br />(por defecto)';
+$labels['protected'] = 'Protegido';
+$labels['skins'] = 'Temas';
+$labels['loads_always'] = 'Obligatorio';
+$labels['loads_never'] = 'Complemento desactivado';
+$labels['loads_by_user'] = 'El usuario puede determinar su uso';
+$labels['loads_linked'] = 'Enlazado a';
+$labels['unbind'] = 'desenlazar';
+$labels['bind'] = 'enlazar';
+$labels['addplugin'] = 'Añadir complemento';
+$labels['removeplugin'] = 'Eliminar complemento';
+$labels['errorplugin'] = 'Error: complementos necesarios no están disponibles';
+$labels['errorrcversion'] = 'Error: Complemento requiere Roundcube';
+$labels['errorphpversion'] = 'Error: Complemento requiere PHP';
+$labels['errorphpcurl'] = 'Error: cURL no está instalado';
+$labels['errorphpfinfo'] = 'Error: finfo no está instalado';
+$labels['errordb'] = 'Ajustes de base de datos requerido.<br />Por favor, active el complemento para iniciar ajustes.';
+$labels['errordb8'] = 'Ajustes de base de datos requerido.';
+$labels['syntaxerror'] = 'Error de sintaxis PHP';
+$labels['notconfigured'] = 'Complemento no está configurado';
+$labels['editconfig'] = 'Editar configuración';
+$labels['instructions'] = 'Instrucciones';
+$labels['dbautomatically'] = 'Iniciar ajustes.';
+$labels['dbmanually'] = 'Por favor, siga estas instrucciones.';
+$labels['ornewer'] = 'o más reciente';
+$labels['official_releases'] = 'sólo soportamos versiones oficiales de Roundcube';
+$labels['localizationmissing'] = 'Etiquetas para el nombre y la descripción del complemento no detectados';
+$labels['documentation'] = 'Documentación';
+$labels['select_plugin'] = 'Seleccione complemento';
+$labels['legend'] = 'Leyenda';
+$labels['plugindisabledbydefault'] = 'Complemento desactivado por defecto - El usuario puede determinar su uso';
+$labels['pluginenabledbydefault'] = 'Complemento activado por defecto - El usuario puede determinar su uso';
+$labels['pluginmandatory'] = 'Obligatorio - Complemento activado. Usuarios no pueden activar/desactivar el complemento';
+$labels['show_about_link'] = 'Mostrar enlace "Acerca de"';
+$labels['show_support_link'] = 'Mostrar enlace "Soporte"';
+$labels['use_myroundcube_watermark'] = 'Utilizar sello digital "MyRoundcube"';
+$labels['remove_watermark'] = 'No mostrar sello digital';
+$labels['database'] = 'Base de datos';
+$labels['account_details_compressed'] = 'Detalles de la cuenta comprimidos';
+$labels['credits_transferred'] = 'Créditos transferidos';
+$labels['customer_id_changed'] = 'ID de cliente modificado';
+$labels['myrcd_bought'] = 'MyRC$ comprado - ¡Gracias!';
+$labels['myrcd_refunded'] = 'MyRC$ reembolsados';
+$labels['PHPMyAdmin'] = 'PHPMyAdmin';
+$labels['ipmismatch'] = 'Ninguna descarga posible de IP %s <small> (IP del cliente no coincide) </small>.<br /> Utilice %s o navegue a %s de IP %s.';
+$labels['emoticons_pluginname'] = 'Atajos de Emoticono';
+$labels['emoticons_plugindescription'] = 'Reemplace atajos de Emoticono por imágenes';
+$labels['markbuttons_pluginname'] = 'Botones \'Marcar Mensaje\'';
+$labels['markbuttons_plugindescription'] = 'Agregar íconos de control al separador de la lista de mensajes para aplicar acciones rápidamente.';
+$labels['keyboard_shortcuts_pluginname'] = 'Métodos Abreviados de Teclado';
+$labels['keyboard_shortcuts_plugindescription'] = 'Ejecutar comandos utilizando métodos abreviados de teclado.';
+$labels['message_highlight_pluginname'] = 'Resaltar Mensajes';
+$labels['message_highlight_plugindescription'] = 'Resaltar mensajes que coincidan con sus opciones de filtro.';
+$labels['google_contacts_pluginname'] = 'Google Contacts';
+$labels['google_contacts_plugindescription'] = 'Accede a tus contactos de Google.';
+$labels['contextmenu_pluginname'] = 'Menú Contextual';
+$labels['contextmenu_plugindescription'] = 'Habilitar la funcionalidad de menú contextual al hacer clic derecho en webmail.';
+$labels['newmail_notifier_pluginname'] = 'Notificador de Mensaje';
+$labels['newmail_notifier_plugindescription'] = 'Notificación de nuevos mensajes.';
+$labels['listcommands_pluginname'] = 'Responder Listas de Correo';
+$labels['listcommands_plugindescription'] = 'Varias opciones para responder a los mensajes enviados desde listas de correo.';
+$labels['copymessage_pluginname'] = 'Copiar Mensaje(s)';
+$labels['copymessage_plugindescription'] = 'Copiar mensaje(s) hacia otra carpeta IMAP.';
+$labels['vcard_attachments_pluginname'] = 'vCard Adjuntos';
+$labels['vcard_attachments_plugindescription'] = 'Agregar casilla a mensajes que tienen un vCard adjunto para importar el contacto directamente hacia el libro de direcciones.';
+$labels['zipdownload_pluginname'] = 'Exportar Mensajes';
+$labels['zipdownload_plugindescription'] = 'Descargar mensajes seleccionados (.eml) o carpetas completas, como un archivo zip.';
+$labels['markasjunk2_pluginname'] = 'Marcar como Spam';
+$labels['markasjunk2_plugindescription'] = 'Marcar mensajes como spam o no spam.';
+$labels['markasjunk_pluginname'] = 'Marcar como Spam';
+$labels['markasjunk_plugindescription'] = 'Marcar mensajes como spam o no spam.';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Incluir Google Analytics.';
+$labels['globaladdressbook_pluginname'] = 'Libro Global de Direcciones';
+$labels['globaladdressbook_plugindescription'] = 'Libreta de direcciones de sólo lectura proporcionada por el administrador.';
+$labels['blockspamsending_pluginname'] = 'Impedir el envío de Spam';
+$labels['blockspamsending_plugindescription'] = 'Permitir el envío de una cantidad específica de mensajes con el mismo texto durante una sesión.';
+$labels['global_config_pluginname'] = 'Administrador de Configuración';
+$labels['global_config_plugindescription'] = 'Este es un complemento de administración de configuración. Se optimiza el servidor mediante la centralización de la configuración de estos complementos. También hace más fácil las tareas administrativas, permitiendo el uso de un solo archivo de configuración para todos los complementos.';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Librería de Jqueryui javascript';
+$labels['hide_blockquote_pluginname'] = 'Ocultar bloque entrecomillado';
+$labels['hide_blockquote_plugindescription'] = 'Ocultar citación cuando el recuento de líneas es mayor que el valor especificado.';
+$labels['crawler_pluginname'] = 'Crawler';
+$labels['crawler_plugindescription'] = 'Contenido de página falso para los rastreadores.';
+$labels['archive_pluginname'] = 'Archive';
+$labels['archive_plugindescription'] = 'Archivar mensajes en una carpeta de archivo.';
+$labels['autologon_pluginname'] = 'Autologon';
+$labels['autologon_plugindescription'] = 'Iniciar sesión automáticamente.';
+$labels['openpgpjs_pluginname'] = 'OpenPGPjs';
+$labels['openpgpjs_plugindescription'] = 'Des PGP en Roundcube.';
+$labels['dblog_pluginname'] = 'Registrar en base de datos';
+$labels['dblog_plugindescription'] = 'Registrar eventos en base de datos en vez de registrarlos en archivos.';
+$labels['gibberish_pluginname'] = 'Gibberish Encryption';
+$labels['gibberish_plugindescription'] = 'Complemtento para ayudar en la codificación Gibberish AES.';
+$labels['http_request_pluginname'] = 'HTTP Request';
+$labels['http_request_plugindescription'] = 'Complemento para ayudar a realizar peticiones HTTP vía cURL o fsockopen.';
+$labels['http_auth_pluginname'] = 'Autentificación HTTP';
+$labels['http_auth_plugindescription'] = 'Un complemento de ayuda para soportar autentificación HTTP.';
+$labels['http_authentication_pluginname'] = 'Autenticación HTTP (por defecto)';
+$labels['http_authentication_plugindescription'] = 'Hacer uso de una autenticación HTTP existente e iniciar sesión con las credenciales del mismo usuario.';
+$labels['jscolor_pluginname'] = 'Selector de Color';
+$labels['jscolor_plugindescription'] = 'Un complemento de ayuda para mostrar un selector de color.';
+$labels['tinymce_pluginname'] = 'TinyMCE - Editor HTML';
+$labels['tinymce_plugindescription'] = 'Reemplazar el editor HTML predeterminado TinyMCE por TinyMCE jQuery. (Incluye Compresor PHP TinyMCE - http://www.tinymce.com/wiki.php/Compressors:PHP)';
+$labels['lang_sel_pluginname'] = 'Seleccionar Idioma';
+$labels['lang_sel_plugindescription'] = 'Seleccionar idioma en la página de inicio de sesión';
+$labels['newuser_pluginname'] = 'Nuevo usuario';
+$labels['newuser_plugindescription'] = 'Informar al los administradores cuando un nuevo usuario es registrado por medio de la interfaz Web del correo y envía un mensaje de bienvenida al nuevo usuario en el primer inicio de sesión.';
+$labels['placeholder_pluginname'] = 'Atributos de marcador de posición';
+$labels['placeholder_plugindescription'] = 'Agregar atributos de marcador de posición para los elementos de entrada de texto y contraseña.';
+$labels['qtip_pluginname'] = 'Información sobre herramientas con jQueryUI';
+$labels['qtip_plugindescription'] = 'Un complemento de ayuda para utilizar qtips de jQueryUI.';
+$labels['sabredav_pluginname'] = 'SabreDAV (Soporte para WebDav sobre PHP)';
+$labels['sabredav_plugindescription'] = 'Crea cuentas SabreDav para accesos a calendarios CalDAV cuando se crean nuevos usuarios en Roundcube y asocia contraseñas si estas han sido modificadas.';
+$labels['savepassword_pluginname'] = 'Guardar contraseñas';
+$labels['savepassword_plugindescription'] = 'Éste es un complemente auxiliar requerido por otros complementos.';
+$labels['database_attachments_pluginname'] = 'Adjuntos en base de datos';
+$labels['database_attachments_plugindescription'] = 'Complemento auxiliar para administrar adjuntos en base de datos';
+$labels['help_pluginname'] = 'Ayuda';
+$labels['help_plugindescription'] = 'Ayuda Webmail';
+$labels['new_user_dialog_pluginname'] = 'diálogo de nuevo usuario';
+$labels['new_user_dialog_plugindescription'] = 'Muestra el diálogo de configuración de datos personales a los nuevos usuarios. Cuando un usuario es creado, el complemento verifica la Identidad Predeterminada y establece un límite de sesión en caso de que se encuentre incompleta. Un cuadro emergente aparece en pantalla hasta que el usuario lo revise y complete su información.';
+$labels['rcguard_pluginname'] = 'ReCaptcha';
+$labels['rcguard_plugindescription'] = 'Enforzar un desafío CAPTCHA después de varios intentos de inicio de sesión fallidos.';
+$labels['domain_check_pluginname'] = 'Verifica Dominio';
+$labels['domain_check_plugindescription'] = 'Restringir el inicio de sesión de webmail a dominios específicos.';
+$labels['tasklist_pluginname'] = 'Lista de Tareas';
+$labels['tasklist_plugindescription'] = 'Crear tareas y listas de subtareas con recordatorios.';
+$labels['virtuser_query_pluginname'] = 'Consulta de Usuario Virtual';
+$labels['virtuser_query_plugindescription'] = 'Búsqueda en base de datos de \'Usuario a Correo electrónico\' y viceversa.';
+$labels['virtuser_file_pluginname'] = 'Consulta de Usuario Virtual';
+$labels['virtuser_file_plugindescription'] = 'Búsqueda en archivos de \'Usuario a Correo electrónico\' y viceversa.';
+$labels['userinfo_pluginname'] = 'Información del usuario';
+$labels['userinfo_plugindescription'] = 'Mostrar información sobre el usuario actual.';
+$labels['subscriptions_option_pluginname'] = 'Suscripciones IMAP';
+$labels['subscriptions_option_plugindescription'] = 'Administrar suscripciones IMAP.';
+$labels['filters_pluginname'] = 'Filtros';
+$labels['filters_plugindescription'] = 'Gestionar filtros de mensajes definidos por el usuario.';
+$labels['forgot_password_pluginname'] = 'Forgot Password';
+$labels['forgot_password_plugindescription'] = 'Peticiones de restablecimiento de contraseña.';
+$labels['sieverules_pluginname'] = 'Filtros Sieve';
+$labels['sieverules_plugindescription'] = 'Administrar Filtros Sieve.';
+$labels['managesieve_pluginname'] = 'Filtros Sieve';
+$labels['managesieve_plugindescription'] = 'Administrar Filtros Sieve.';
+$labels['acl_pluginname'] = 'Listas de Control de Acceso';
+$labels['acl_plugindescription'] = 'Administración de Lista de Control de Acceso a Carpetas.';
+$labels['vacation_pluginname'] = 'Respuesta Automática';
+$labels['vacation_plugindescription'] = 'Administrar Respuestas Automáticas (notificación de vacaciones).';
+$labels['password_pluginname'] = 'Cambiar Contraseña';
+$labels['password_plugindescription'] = 'Permite al usuario cambiar su contraseña.';
+$labels['redundant_attachments_pluginname'] = 'Adjuntos Redundantes';
+$labels['redundant_attachments_plugindescription'] = 'Proporciona un almacenamiento redundante para archivos adjuntos cargados temporales. Se almacenan tanto en la base de datos así como en el sistema de archivos local.';
+$labels['example_addressbook_pluginname'] = 'Libreta de direcciones de ejemplo ';
+$labels['example_addressbook_plugindescription'] = 'Código de ejemplo para agregar una libreta de direcciones adicional.';
+$labels['debug_logger_pluginname'] = 'Registros de Depuración';
+$labels['debug_logger_plugindescription'] = 'Permite registros mejorados para fines de depuración.';
+$labels['show_additional_headers_pluginname'] = 'Mostrar encabezados de mensajes adicionales';
+$labels['show_additional_headers_plugindescription'] = 'Complemento de concepto-de-prueba para que se capturen cabeceras adicionales y sean mostradas en la vista de mensajes.';
+$labels['additional_message_headers_pluginname'] = 'Encabezados de Mensajes Adicionales';
+$labels['additional_message_headers_plugindescription'] = 'Complemento sencillo que agrega encabezados adicionales o los elimina de mensajes salientes.';
+$labels['new_user_identity_pluginname'] = 'Nueva Identidad de Usuario';
+$labels['new_user_identity_plugindescription'] = 'Autocompleta identidad predeterminada de un nuevo usuario de LDAP en su primera visita.';
+$labels['squirrelmail_usercopy_pluginname'] = 'Migrar Usuarios Squirrelmail';
+$labels['squirrelmail_usercopy_plugindescription'] = 'Copia la identidad de un nuevo usuario y la configuración de una instalación Squirrelmail cercana.';
+$labels['yubikey_authentication_pluginname'] = 'Autenticación Yubikey de Yubico';
+$labels['yubikey_authentication_plugindescription'] = 'Complemento para utilizar la autenticación YubiKey de Yubico en Roundcube webmail.';
+$labels['sauserprefs_pluginname'] = 'Preferencias de Usuario para Spamassassin';
+$labels['sauserprefs_plugindescription'] = 'Añade una pestaña de \'spam\' a los \'Ajustes personales\' para permitir al usuario cambiar sus preferencias de SpamAssassin.';
+$labels['dkimstatus_pluginname'] = 'DKIM status';
+$labels['dkimstatus_plugindescription'] = 'DKIMSTATUS muestra el estado de la firma DKIM en cada correo que lee en Roundcube.';
+$labels['roundcube_openpgp_pluginname'] = 'Roundcube OpenPGP';
+$labels['roundcube_openpgp_plugindescription'] = 'Esta extensión implementa OpenPGP en Roundcube. Ayuda a generar, administrar y utilizar claves de cifrado.';
+$labels['automatic_addressbook_pluginname'] = 'Libreta de Direcciones Automática';
+$labels['automatic_addressbook_plugindescription'] = 'Crea una libreta de direcciones e inserta automáticamente las direcciones de correos electrónicos contactados. Esto elimina la necesidad de añadir manualmente cada contacto.';
+$labels['calendar_pluginname'] = 'Calendario';
+$labels['calendar_plugindescription'] = 'Administre sus eventos con el Calendario Webmail.';
+$labels['attachment_reminder_pluginname'] = 'Recordatorio de adjuntos';
+$labels['attachment_reminder_plugindescription'] = 'Recordar a usuarios adjuntar un archivo antes de enviar mensajes.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/fi_FI.inc b/plugin_manager/localization/fi_FI.inc
new file mode 100644
index 0000000..09f4205
--- /dev/null
+++ b/plugin_manager/localization/fi_FI.inc
@@ -0,0 +1,252 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/fi_FI.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Markku Virtanen - 01/13/2015 11:52:45
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Liitännäisten hallinta';
+$labels['plugindescription'] = 'Liitännäisten hallinta antaa käyttäjille mahdollisuuden liitännäisten aktivointiin ja/tai päältä pois ottamiseen (käyttäjätasolla). Webmailin hallintatunnuksilla saa tietoa päivityksistä, ajantasalla olevista liitännäisistä, bugikorjauksista, keskitetyt lataukset, ohjeet ja suosituksista. Liitännäinen...';
+$labels['plugin_manager_title'] = 'Hallinnoi liitännäisiä';
+$labels['plugin_manager_center'] = 'Liitännäisten hallintaportaali';
+$labels['updatepm'] = 'Liitännäisten hallintaan on päivitys olemassa.';
+$labels['updatepmrequired'] = 'Päivitys liitännäisten hallintaan tarvitaan.';
+$labels['downloadnow'] = 'Lataa nyt';
+$labels['homepage'] = 'Kotisivu';
+$labels['calendaring'] = 'Kalenteri';
+$labels['misc'] = 'Sekalaiset';
+$labels['downloads'] = 'lataukset';
+$labels['issue'] = 'Ongelma';
+$labels['submitissue'] = 'Raportoi ongelma.<br><br>Tarkista lokitiedostot ja anna tarvittavat tiedot tikettiin.<br><br><b>HUOMIO</b>: Google tili tarvitaan.';
+$labels['showall'] = 'Näytä kaikki liitännäiset';
+$labels['hideuptodate'] = 'Näyt vain päivitykset';
+$labels['connectionerror'] = 'Etäpalvelin ei vastannut yhdistämisyritykseen.';
+$labels['trylater'] = 'Ole hyvä ja yritä myöhemmin uudestaan...';
+$labels['translate'] = 'Käännä tämä liitännäinen';
+$labels['translationaccount'] = 'Reaaliaikaisen kääntämisen tili (käyttäjänimi)';
+$labels['translationserver'] = 'Reaaliaikaisen kääntämisen tili (IMAP palvelin)';
+$labels['whatsthis'] = 'Mikä tämä on?';
+$labels['restoredefaults'] = 'Palauta oletukset';
+$labels['checkall'] = 'Ruksaa kaikki';
+$labels['uncheckall'] = 'Ruksi pois kaikista';
+$labels['toggle'] = 'Käännä valinnat';
+$labels['status'] = 'Tila';
+$labels['globalplugins'] = 'Globaalit liitännäiset';
+$labels['performance'] = 'Suorituskyky';
+$labels['backend'] = 'Palvelin liitännäiset';
+$labels['messagesmanagement'] = 'Viestien hallinta';
+$labels['furtherconfig'] = 'Haluatko muuttaa tämän liitännäisen asetuksia nyt?';
+$labels['uninstall'] = 'Olet ottamassa tämän liitännäisen pois päältä. Haluatko pysyvästi poistaa kaikki tallennetut asetukset?';
+$labels['uninstallconfirm'] = 'Olet poistamassa tämän liitännäisen pois käytöstä. VAROITUS: Valitse »POIS PÄÄLTÄ« ottaaksesi liitännäisen pois päältä mutta säilyttäen tämänhetkiset tiedot ja asetukset palvelimella jos haluat käyttää niitä uudestaan. Valitse »POISTA« poistaaksesi myös tiedot ja asetukset';
+$labels['areyousure'] = 'Et voi peruuttaa tätä. Oletko aivan varma?';
+$labels['successfullydeleted'] = 'Asetukset poistettu.';
+$labels['successfullysaved'] = 'Tallennus onnistui.';
+$labels['errorsaving'] = 'Tapahtui virhe tallentaessa.';
+$labels['yes'] = 'Kyllä';
+$labels['no'] = 'Ei';
+$labels['disable'] = 'Pois päältä';
+$labels['remove'] = 'Poista';
+$labels['savewarning'] = 'Haluatko jo nyt tallentaa muutokset?';
+$labels['plugin_manager_update'] = 'Pävitä liitännäiset';
+$labels['authors_comments'] = 'Tekijän kommentit (ei käännetty)';
+$labels['requiredby'] = 'Liitännäinen vaatii liitännäisen';
+$labels['requires'] = 'Liitännäinen vaatii';
+$labels['recommended'] = 'Suositellut liitännäiset';
+$labels['update_plugins'] = 'Liitännäisten lataus';
+$labels['ziparchive'] = 'Lataa ZIP-paketti';
+$labels['demoaccount'] = 'Sori, et voi tehdä tätä (Esittely tili)';
+$labels['serverversion'] = 'Palvelinversio';
+$labels['mirrorversion'] = 'Mirror versio';
+$labels['mirrorhost'] = 'Mirror palvelin';
+$labels['comments'] = 'Vaatimukset ja päivitystiedot';
+$labels['update_error'] = 'Versiot eivät täsmänneet';
+$labels['update_ok'] = 'Uusin löydetty. Ei tarvetta päivitykselle.';
+$labels['update_edit'] = 'Liitännäisen asetukset pitää tehdä uudestaan tai vaatii tietokantamuutoksia. Katso päivitystiedot.';
+$labels['servernewer'] = 'Rekisteröity liitännäinen on uudempi kuin mirror versio.';
+$labels['orhigher'] = 'tai uudempi';
+$labels['rc_ok'] = 'Roundcube Core on ajan tasalla.';
+$labels['update_update'] = 'Liitännäinen on vanhentunut. Ole hyvä ja päivitä! Katso myös päivitystiedot.';
+$labels['noupdates'] = 'Ei valittuja päivityksiä.';
+$labels['rc_update'] = 'Roundcube Core ei ole ajan tasalla. Ole hyvä ja päivitä!';
+$labels['rc_uptodate'] = 'Roundcube Core on ajan tasalla.';
+$labels['rc_newer'] = 'Roundcube Core on uudempi kuin mirror versio.';
+$labels['nottested'] = 'Käytä liitännäisiä varoen! Emme tiedä toimivatko kyseiset liitännäiset Roundcube v%s.';
+$labels['justunzip'] = 'Pura tiedosto olemassaolevaan asennukseen.';
+$labels['guide'] = 'Lue lisää...';
+$labels['thirdparty'] = 'Tämä ei ole MyRoundcube liitännäinen';
+$labels['thirdpartywarning'] = 'Tämä on kolmannen osapuolen liitännäinen. Ei ole suositeltavaa ladata tätä liitännäistä peilauspalvelimeltamme. Lataa tiedosto mieluummin kehittäjän sivustolta jotta saat varmasti uusimman version ohjeiden ja avun kera.';
+$labels['develsite'] = 'Lataa';
+$labels['notinstalled'] = 'ei asennettu';
+$labels['notregistered'] = 'ei rekisteröity';
+$labels['roundcubeurl'] = 'Lataa Roundcube';
+$labels['languageupdate'] = 'Kielikäännös päivitys saatavilla.';
+$labels['localizationfilesonly'] = 'Huomio: Lataus sisältää vain kielitiedostot';
+$labels['donotregister'] = 'Älä rekisteröi tätä liitännäistä. Se on ladattu automaattisesti.';
+$labels['register'] = 'Rekisteröi tämä liitännäinen liitännäisten hallinnasta tai ./config/config.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</small>.';
+$labels['customer_account'] = 'Asiakastili';
+$labels['customer_id'] = 'Asiakasnumero';
+$labels['invalid_customer_id'] = 'Väärä asiakasnumero';
+$labels['invalid_credits'] = 'Väärät krediitit';
+$labels['successfully_transferred'] = 'Krediittien siirto onnistui';
+$labels['merge'] = 'Yhdistä krediittejä';
+$labels['credits'] = 'Krediitit';
+$labels['creditsupdated'] = 'Krediitit ovat muuttuneet sitten viime sivupäivityksen';
+$labels['buynow'] = 'Osta krediittejä nyt';
+$labels['history'] = 'Tilihistoria';
+$labels['details'] = 'Tiedot';
+$labels['receipt'] = 'Kuitti';
+$labels['plugins'] = 'Liitännäiset';
+$labels['clickhere'] = 'Klikkaa tästä';
+$labels['discardliabletopaycosts'] = 'Älä ota huomioon maksullisia latauksia';
+$labels['unchecknotinstalledplugins'] = 'Älä ota huomioon asennettuja liitännäisiä';
+$labels['sum'] = 'Summa';
+$labels['show'] = 'Näytä';
+$labels['hide'] = 'Piilota';
+$labels['view'] = 'näytä';
+$labels['expired'] = 'ei ole voimassa';
+$labels['terms'] = 'Ehdot';
+$labels['pricelist'] = 'Lataus hinnasto';
+$labels['forthisdownload'] = 'tälle lataukselle';
+$labels['remainingcredits'] = 'jäljellä olevat krediitit';
+$labels['initialdownload'] = 'Ensilataus';
+$labels['keyfeatureaddition'] = 'Uusi keskeinen piirre';
+$labels['codeimprovements'] = 'Koodin parannukset';
+$labels['servicenotavailable'] = 'Palvelu ei ole tällä hetkellä käytössä. Kokeile myöhemmin uudelleen!';
+$labels['myrcerror'] = 'MyRoundcube palvelut eivät tällä hetkellä ole käytössä.';
+$labels['getnew'] = 'Hanki uusi asiakasnumero';
+$labels['getnew_hint'] = 'Suosittellemme uusimaan asiakasnumeronne usein. Jos huomaatte epäilyttävää toimintaa tilin tiedoissa, uusikaa asiakasnumero välittömästi.';
+$labels['transfer'] = 'Siirrä krediittejä';
+$labels['submenuprefix'] = '» ';
+$labels['printdetails'] = 'Tulosta tilin tiedot';
+$labels['noplugindescription'] = 'Liitännäiseltä ei löytynyt lisätietoja';
+$labels['welcome_to_plugin_manager'] = 'Tervetuloa liitännäisten hallinnointiin';
+$labels['about_to_create_account'] = 'Liitännäisten hallinnointi on luomassa ylläpitotilin.';
+$labels['create_account_proceed'] = 'Jatkaaksesi sinun täytyy varmistaa että olet palvelun ylläpitäjä';
+$labels['please_create'] = 'Ole hyvä ja luo seuraava tiedosto Roundcube asennuksen juureen:';
+$labels['thank_you'] = 'Kiitos!';
+$labels['done'] = 'Valmis';
+$labels['manage_admins'] = 'Ylläpitäjät';
+$labels['plugin_manager_admins'] = 'Liitännäisten hallinnoinnin ylläpitäjät';
+$labels['allow_plugins_configuration'] = 'Anna liitännäisten konfigurointiin oikeuksia';
+$labels['share_credits'] = 'Jaa MyRC$ krediittejä';
+$labels['add'] = 'Lisää';
+$labels['accountnotexists'] = 'Tiliä ei ole olemassa';
+$labels['sharedby'] = 'Asiakastilin jakoi ';
+$labels['switch'] = 'Vaihda';
+$labels['ownaccount'] = 'omaan tiliin';
+$labels['shareinvitation'] = 'jaettuun tiliin';
+$labels['enable_notifications'] = 'Laita päälle liitännäisten päivitysilmoitukset';
+$labels['enable_notifications_note'] = 'Huomio: Liitännäisten hallinnointi kyselee MyRoundcube palvelimilta saatavilla olevia päivityksiä kerran päivässä.';
+$labels['notifications_cc'] = 'Kopio ilmoituksista';
+$labels['notifications_cc_note'] = 'Huomio: Päivitysten ilmoitukset lähetetään kaikille liitännäisten hallinta ylläpitäjille. Käytä tätä kenttää lähettääksesi ulkopuolisille ilmoituksia päivityksistä. Esim. johd.doh@gmail.com tai postistuslistaosoite.';
+$labels['serverconfiguration'] = 'Palvelinasetukset';
+$labels['pluginsconfiguration'] = 'Liitännäisten asetukset';
+$labels['use_ssl'] = 'Käytä salattuja SSL yhteyksiä MyRoundcube palvelimilla';
+$labels['use_hmail'] = 'Käytä hMailserver yhteensopivia liitännäisiä';
+$labels['load_splitter'] = 'Lataa staattiset tiedostot toisaalla';
+$labels['show_myrc_messages'] = 'Näytä ilmoitusviestit MyRoundcube palvelimilta';
+$labels['maintenance_mode'] = 'Huoltokatko';
+$labels['maintenance_mode_hint'] = 'Väliaikaikaisesti otetaan kaikki aktiiviset liitännäiset pois päältä. Käytetään liitännäisten päivitykseen isojen päivitysten kanssa. Liitännäisten hallinta ottaa pois päältä kaikki aktiiviset liitännäiset, mutta antaa sinulle pääsyn liitännäisten hallintaportaaliin jotta voit ladata viimeisimmät pävitykset peilauspalvelimiltamme.';
+$labels['running_in_maintenance_mode'] = 'Webmailissa on huoltokatko';
+$labels['serverwide'] = 'koko palvelimen asetukset';
+$labels['file_based_config'] = 'Ota käyttöön tiedostopohjainen liitännäisten hallinnointi';
+$labels['advanced_admins'] = 'suositellaan vain edistyneille ylläpitäjille';
+$labels['compress_html'] = 'Pienennä HTML ulostulo';
+$labels['show_config'] = 'Näytä tämänhetkiset asetukset';
+$labels['systemadmin'] = 'Järjestelmän ylläpitäjä';
+$labels['admin'] = 'Ylläpitäjä';
+$labels['configuredby'] = 'asetukset tehnyt';
+$labels['enabled'] = 'Päällä (oletus)';
+$labels['protected'] = 'Suojattu';
+$labels['skins'] = 'Skinit';
+$labels['loads_always'] = 'Pakollinen';
+$labels['loads_never'] = 'Liitännäinen on pois päältä';
+$labels['loads_by_user'] = 'Käyttäjä voi päättää sen käytöstä';
+$labels['loads_linked'] = 'Liitetty';
+$labels['unbind'] = 'irrota';
+$labels['bind'] = 'liitä';
+$labels['addplugin'] = 'Lisää liitännäinen';
+$labels['removeplugin'] = 'Poista liitännäinen';
+$labels['errorplugin'] = 'Virhe: Vaadittuja liitännäisiä ei löytynyt';
+$labels['errorrcversion'] = 'Virhe: Liitännäinen vaatii Roundcuben';
+$labels['errorphpversion'] = 'Virhe: Liitännäinen vaatii PHP:n';
+$labels['errorphpcurl'] = 'Virhe: cURL ei ole asennettu';
+$labels['errorphpfinfo'] = 'Virhe: finfo ei ole asennettu';
+$labels['errordb'] = 'Tietokantamuutokset vaaditaan. Ole hyvä ja ota liitännäinen käyttöön aloittaaksesi tietokantamuutokset.';
+$labels['errordb8'] = 'Tietokantamuutokset vaaditaan.';
+$labels['syntaxerror'] = 'PHP syntaksivirhe';
+$labels['notconfigured'] = 'Liitännäistä ei ole konfiguroitu';
+$labels['editconfig'] = 'Muokkaa konfiguraatiota';
+$labels['instructions'] = 'Ohjeet';
+$labels['dbautomatically'] = 'Aloita toimet';
+$labels['dbmanually'] = 'Noudata näitä ohjeita.';
+$labels['ornewer'] = 'tai uudemppi';
+$labels['official_releases'] = 'tuemme vain virallisia Roundcube julkasuja';
+$labels['localizationmissing'] = 'Ei löytynyt liitännäisen nimeä tai liitännäisen lisätietoja';
+$labels['documentation'] = 'Dokumentaatio';
+$labels['select_plugin'] = 'Valitse liitännäinen';
+$labels['legend'] = 'Selitys';
+$labels['plugindisabledbydefault'] = 'Liitännäinen on pois käytöstä oletuksena - Käyttäjä voi määrittää sen käytöstä';
+$labels['pluginenabledbydefault'] = 'Liitännäinen on päällä oletuksena - Käyttäjä voi määrittää sen käytöstä';
+$labels['pluginmandatory'] = 'Pakollinen - Liitännäinen on päällä, käyttäjä ei voi kytkeä päälle tai poistaa käytöstä liitännäistä';
+$labels['show_about_link'] = 'Näytä "Tietoa" linkki';
+$labels['show_support_link'] = 'Näytä "Tuki" linkki';
+$labels['use_myroundcube_watermark'] = 'Käytä "MyRoundcube" vesileimaa';
+$labels['remove_watermark'] = 'Älä näytä vesileimaa ollenkaan';
+$labels['database'] = 'Tietokanta';
+$labels['account_details_compressed'] = 'Tilin tiedot pakattuna';
+$labels['credits_transferred'] = 'Krediittejä siirretty';
+$labels['customer_id_changed'] = 'Asiakasnumero muutettu';
+$labels['myrcd_bought'] = 'MyRC$ ostettu - Kiitos!';
+$labels['myrcd_refunded'] = 'MyRC$ takaisinmaksettu';
+$labels['PHPMyAdmin'] = 'PHPMyAdmin';
+$labels['ipmismatch'] = 'Lataus ei mahdollista IP osoitteesta %s <small>(IP ei täsmää)</small>.<br>Käytä %s tai selaa %s IP osoitteista %s.';
+$labels['emoticons_pluginname'] = 'Emoticon lyhenteet';
+$labels['emoticons_plugindescription'] = 'Vaihda emoticon lyhenteet hymiökuvilla';
+$labels['markbuttons_pluginname'] = 'Merkkaa viestit painikkeet';
+$labels['markbuttons_plugindescription'] = 'Lisää kuvakkeet viestilistan erottimeen jotta voit nopeasti merkata viestejä.';
+$labels['keyboard_shortcuts_pluginname'] = 'Pikanäppäimet';
+$labels['keyboard_shortcuts_plugindescription'] = 'Syötä komentoja käyttäen pikanäppäimiä';
+$labels['message_highlight_pluginname'] = 'Korosta viestejä';
+$labels['message_highlight_plugindescription'] = 'Korosta viestit jotka täsmäävät suotimiisi.';
+$labels['google_contacts_pluginname'] = 'Google Kontaktit';
+$labels['google_contacts_plugindescription'] = 'Pääsy Google kontakteihin';
+$labels['contextmenu_pluginname'] = 'Pikavalikko';
+$labels['contextmenu_plugindescription'] = 'Aseta päälle oikean hiiren klikkauksen pikavalikko toiminnot.';
+$labels['newmail_notifier_pluginname'] = 'Uusi viesti muistuttaja';
+$labels['newmail_notifier_plugindescription'] = 'Muistuta uusista viesteisteistä';
+$labels['listcommands_pluginname'] = 'Vastaa postituslistoihin';
+$labels['listcommands_plugindescription'] = 'Erinäisiä valintoja vastata viesteihin jotka ovat tulleet postituslistoilta.';
+$labels['copymessage_pluginname'] = 'Kopioi viesti(t)';
+$labels['copymessage_plugindescription'] = 'Kopioi viesti(t) toiseen IMAP kansioon.';
+$labels['vcard_attachments_pluginname'] = 'vCard liitteet';
+$labels['vcard_attachments_plugindescription'] = 'Lisää laatikko viesteihin joissa on vcard-liite lisätäksesi sen suoraan osoitekirjaan.';
+$labels['zipdownload_pluginname'] = 'Vie viestejä';
+$labels['zipdownload_plugindescription'] = 'Vie viestejä .zip tiedostossa.';
+$labels['markasjunk2_pluginname'] = 'Merkkaa roskapostiviestit';
+$labels['markasjunk2_plugindescription'] = 'Merkkaa viestit roskaposteiksi.';
+$labels['markasjunk_pluginname'] = 'Merkkaa roskapostiviestit';
+$labels['markasjunk_plugindescription'] = 'Merkkaa viestit roskaposteiksi.';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Lisää Google Analytics';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Jqueryui javascript kirjasto';
+$labels['autologon_pluginname'] = 'Autologon';
+$labels['autologon_plugindescription'] = 'Kirjaudu automaattisesti';
+$labels['dblog_pluginname'] = 'Lokita tietokantaan';
+$labels['dblog_plugindescription'] = 'Kirjoittaa lokit tietokantaan tiedoston sijaan';
+$labels['http_request_pluginname'] = 'HTTP Request';
+$labels['http_request_plugindescription'] = 'Helper lisäosa jolla voidaan tehdä HTTP pyyntöjä cURLin tai fsockopenin avulla';
+$labels['http_auth_pluginname'] = 'HTTP autentikointi';
+$labels['http_auth_plugindescription'] = 'Helper lisäosa tuki HTTP autentikoinnille käytettäväksi muissa lisäosissa. Huom: tämä lisäosa on eri kuin Roundcuben http_authentication lisäosa.';
+$labels['jscolor_pluginname'] = 'Värivalitsin';
+$labels['jscolor_plugindescription'] = 'Helper lisäosa jolla näytetään värivalitsin';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/fr_FR.inc b/plugin_manager/localization/fr_FR.inc
new file mode 100644
index 0000000..b795890
--- /dev/null
+++ b/plugin_manager/localization/fr_FR.inc
@@ -0,0 +1,346 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/fr_FR.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Olivier Zolli - 01/20/2015 18:23:27
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Gestionnaire de plugins';
+$labels['plugindescription'] = 'Le gestionnaire de plugins fournit aux utilisateurs des options pour activer ou désactiver les plugins (au niveau du compte utilisateur) tandis qu\'il aide les administrateurs à maintenir leur système à jour avec des mises à jour de plugins, des corrections de bugs, des téléchargements et documentations centralisés. Le gestionnaire de plugins ne modifie pas votre système de fichiers et n\'installe pas les plugins automatiquement';
+$labels['plugin_manager_title'] = 'Gestionnaire de Plugins';
+$labels['plugin_manager_center'] = 'Centre de gestion des plugins';
+$labels['updatepm'] = 'Une mise à jour du Plugin_Manager est disponible';
+$labels['updatepmrequired'] = 'La mise à jour de Plugin_manager est nécessaire';
+$labels['downloadnow'] = 'Téléchargez maintenant';
+$labels['homepage'] = 'Accueil';
+$labels['calendaring'] = 'Gestion de calendrier';
+$labels['misc'] = 'Divers';
+$labels['downloads'] = 'Traduire ce plugin';
+$labels['issue'] = 'Problème';
+$labels['submitissue'] = 'Rapporter un problème.<br /><br />Merci de vérifier vos logs et fournir des informations pertinentes dans le billet.<br /><br /><b>NOTE</b>: Un compte google est requis.';
+$labels['showall'] = 'Montrer tous les plugins';
+$labels['hideuptodate'] = 'Ne montrer que les mises à jour';
+$labels['connectionerror'] = 'Le serveur distant n\'a pas répondu à une tentative de connexion.';
+$labels['trylater'] = 'Merci de réessayer plus tard...';
+$labels['translate'] = 'Traduire ce plugin';
+$labels['translationaccount'] = 'Traduction en temps réel (Nom d\'utilisateur)';
+$labels['translationserver'] = 'Traduction en temps réel (Serveur IMAP)';
+$labels['whatsthis'] = 'Plus d\'info...';
+$labels['restoredefaults'] = 'Paramètres par défaut';
+$labels['checkall'] = 'Tout cocher';
+$labels['uncheckall'] = 'Tout décocher';
+$labels['toggle'] = 'Inverser la sélection';
+$labels['status'] = 'Status';
+$labels['globalplugins'] = 'Plugins génériques';
+$labels['performance'] = 'Performance';
+$labels['backend'] = 'Plugins serveur';
+$labels['messagesmanagement'] = 'Gestion des messages';
+$labels['furtherconfig'] = 'Voulez-vous configurer le plugin maintenant?';
+$labels['uninstall'] = 'Vous êtes sur le point de désactiver ce plugin. Voulez-vous supprimer tous les paramètres enregistrés de façon permanente?';
+$labels['uninstallconfirm'] = 'Vous êtes sur le point de désactiver ce plugin. AVERTISSEMENT: Sélectionner »DÉSACTIVER« pour désactiver ce plugin tout en gardant vos données actuelles et la configuration stockée sur notre serveur si vous prévoyez de l\'utiliser à nouveau plus tard. Sélectionnez »SUPPRIMER« si vous voulez que toutes les données de configuration gérés par ce plugin soient définitivement supprimées de nos bases de données. Notez que cette action ne peut pas est irréversible.';
+$labels['areyousure'] = 'Vous ne pouvez pas annuler cette action. Etes-vous vraiment sûr?';
+$labels['successfullydeleted'] = 'Les paramètres ont été supprimés avec succès.';
+$labels['successfullysaved'] = 'Enregistré avec succès.';
+$labels['errorsaving'] = 'Une erreur est survenue lors de l\'enregistrement.';
+$labels['yes'] = 'Oui';
+$labels['no'] = 'Non';
+$labels['disable'] = 'Désactiver';
+$labels['remove'] = 'Supprimer';
+$labels['savewarning'] = 'Voulez-vous enregistrer vos modifications?';
+$labels['plugin_manager_update'] = 'Mise à jour des plugins';
+$labels['authors_comments'] = 'Commentaires de l\'auteur (non traduit)';
+$labels['requiredby'] = 'Le plugin est requis par';
+$labels['requires'] = 'Plugin requis';
+$labels['recommended'] = 'Plugin recommandé';
+$labels['update_plugins'] = 'Mise à jour du plugin';
+$labels['ziparchive'] = 'Télécharger une archive ZIP';
+$labels['demoaccount'] = 'Désolé, pas de téléchargements (Compte de démonstration)';
+$labels['serverversion'] = 'Version serveur';
+$labels['mirrorversion'] = 'Version distante';
+$labels['mirrorhost'] = 'Serveur distant';
+$labels['comments'] = 'Pré-requis et notes de mise à jour';
+$labels['update_error'] = 'Différence de version';
+$labels['update_ok'] = 'Version la plus récente a été détectée. Pas de mise à jour nécessaire.';
+$labels['update_edit'] = 'Le plugin doit être re-configuré ou nécessite des ajustements de base de données. S\'il vous plaît tenez compte des notes de mise à jour.';
+$labels['servernewer'] = 'Le plugin enregistré est plus récente que la version distante.';
+$labels['orhigher'] = 'ou supérieure';
+$labels['rc_ok'] = 'Roundcube est à jour.';
+$labels['update_update'] = 'Le plugin est obsolète. Mettez à jour s\'il vous plait! Tenez compte des notes de mise à jour.';
+$labels['noupdates'] = 'Aucune mise à jour sélectionnée.';
+$labels['rc_update'] = 'Roundcube n\'est pas à jour. Mettez le à jour s\'il vous plait!';
+$labels['rc_uptodate'] = 'Roundcube est à jour.';
+$labels['rc_newer'] = 'Votre version de roundcude est plus récente que la version distante!';
+$labels['nottested'] = 'S\'il vous plaît utilisez les plugins avec prudence! Nous ne savons pas si Plugins hébergés fonctionnent avec Roundcube v%s.';
+$labels['justunzip'] = 'Il suffit de décompresser l\'archive sur votre installation existante.';
+$labels['guide'] = 'En savoir plus...';
+$labels['thirdparty'] = 'Ce n\'est pas un plugin MyRoundcube.';
+$labels['thirdpartywarning'] = 'Ceci est un plugin tiers. Nous vous recommandons de ne pas télécharger le plugin à partir de ce serveur distant. Téléchargez-le à partir du site du développeur pour être sûr d\'avoir la version la plus récente et prenez en compte les conseils du développeur.';
+$labels['develsite'] = 'Téléchargement';
+$labels['notinstalled'] = 'pas installé';
+$labels['notregistered'] = 'pas enregistré';
+$labels['roundcubeurl'] = 'Télécharger Roundcube';
+$labels['languageupdate'] = 'Une mise à jour de la traduction est disponible.';
+$labels['localizationfilesonly'] = 'Note: Le téléchargement ne contient que les traductions';
+$labels['donotregister'] = 'N\'enregistrez pas ce plugin. Il sera chargé automatiquement.';
+$labels['register'] = 'Enregistrez ce plugin dans ./config/config.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</small>.';
+$labels['customer_account'] = 'Compte client';
+$labels['customer_id'] = 'Numéro de client';
+$labels['invalid_customer_id'] = 'Mauvais identifiant Customer_ID';
+$labels['invalid_credits'] = 'Pas assez de crédits';
+$labels['successfully_transferred'] = 'Crédits transférés avec succès';
+$labels['merge'] = 'Fusionner les crédits';
+$labels['credits'] = 'Crédits';
+$labels['creditsupdated'] = 'Les crédits ont changé depuis le dernier rafraichissement de la page';
+$labels['buynow'] = 'Acheter des crédits maintenant';
+$labels['history'] = 'Historique du compte';
+$labels['details'] = 'Détails';
+$labels['receipt'] = 'Reçu';
+$labels['plugins'] = 'Plugins';
+$labels['clickhere'] = 'Cliquez ici';
+$labels['discardliabletopaycosts'] = 'Enlever les téléchargements payants';
+$labels['unchecknotinstalledplugins'] = 'Abandonnez le téléchargement des plugins non installés ';
+$labels['sum'] = 'Résumé';
+$labels['show'] = 'Montrer';
+$labels['hide'] = 'Cacher';
+$labels['view'] = 'Voir';
+$labels['expired'] = 'Expiré';
+$labels['terms'] = 'Conditions';
+$labels['pricelist'] = 'Coûts des téléchargements';
+$labels['forthisdownload'] = 'Pour ce téléchargement';
+$labels['remainingcredits'] = 'Crédits restants';
+$labels['initialdownload'] = 'Premier téléchargement';
+$labels['keyfeatureaddition'] = 'Nouvelle fonctionnalité clée';
+$labels['codeimprovements'] = 'Amélioration de code';
+$labels['servicenotavailable'] = 'Le service est actuellement indisponible. Merci de rééssayer ultérieurement';
+$labels['myrcerror'] = 'Le service MyRoundcube est actuellement indisponible';
+$labels['getnew'] = 'Demander un nouveau numéro de client';
+$labels['getnew_hint'] = 'Nous vous recommandons de renouveler votre numéro de client fréquemment. Si vous détéctez une activité suspecte le détail de votre compte, renouvelez votre numéro de client immédiatement.';
+$labels['transfer'] = 'Transférer des crédits';
+$labels['submenuprefix'] = ' » ';
+$labels['printdetails'] = 'Imprimer les détails du compte';
+$labels['noplugindescription'] = 'Aucune description n\'est disponible pour ce plugin.';
+$labels['welcome_to_plugin_manager'] = 'Bienvenue dans le Plugin_Manager';
+$labels['about_to_create_account'] = 'Le Plugin_Manager va créer un compte d\'administrateur';
+$labels['create_account_proceed'] = 'Veuillez confirmer que vous êtes bien l\'administrateur';
+$labels['please_create'] = 'Veuillez SVP créer un fichier vide avec ce nom dans le répertoire racine de votre installation RoundCube';
+$labels['thank_you'] = 'Merci !';
+$labels['done'] = 'Terminé';
+$labels['manage_admins'] = 'Administrateurs';
+$labels['plugin_manager_admins'] = 'Administrateurs du Plugin_Manager';
+$labels['allow_plugins_configuration'] = 'Accorder les permissions de configuration du Plugin_Manager';
+$labels['share_credits'] = 'Partager les crédits MyRC$';
+$labels['add'] = 'Ajouter';
+$labels['accountnotexists'] = 'Compte inexistant';
+$labels['sharedby'] = 'compte client partagé pars';
+$labels['switch'] = 'Changer';
+$labels['ownaccount'] = 'vers son propre compte';
+$labels['shareinvitation'] = 'vers un compte partagé';
+$labels['enable_notifications'] = 'Activer les notifications de mise à jour des plugins';
+$labels['enable_notifications_note'] = 'Note : Le gestionnaire de plugins ne cherche les mises à jour sur les serveurs miroir MyRoundcube qu\'une fois par jour.';
+$labels['notifications_cc'] = 'Cc pour les notifications';
+$labels['notifications_cc_note'] = 'Note : Les notifications de mise à jour sont envoyées à tous les administrateurs du gestionnaire de plugins. Utilisez ce champ pour notifier un destinataire supplémentaire. Par exemple john.doh@gmail.com ou une adresse de mailing list.';
+$labels['serverconfiguration'] = 'Configuration du serveur';
+$labels['pluginsconfiguration'] = 'Configuration des plugins';
+$labels['use_ssl'] = 'Etablir une connexion sécurisée SSL vers les serveurs MyRoundCube';
+$labels['use_hmail'] = 'Utiliser les plugins HMailserver';
+$labels['load_splitter'] = 'Décharge les fichiers statiques';
+$labels['show_myrc_messages'] = 'Afficher les notifications en provenance des serveurs MyRoundCube';
+$labels['maintenance_mode'] = 'Mode maintenance';
+$labels['maintenance_mode_hint'] = 'Désactive temporairement l\'ensemble des plugins. Utilisé lors d\'une mise à jour majeure. Plugin Manager désactive tous les plugins actifs, vous permettant de toujours accéder au centre de gestion des plugins pour télécharger les dernières versions depuis nos miroirs.';
+$labels['running_in_maintenance_mode'] = 'Le webmail est exécuté en mode maintenance.';
+$labels['serverwide'] = 'configuration sur le serveur';
+$labels['file_based_config'] = 'Activer la configuration du Plugin_manager via le fichier de config';
+$labels['advanced_admins'] = 'recommandé pour les administrateurs expérimentés';
+$labels['compress_html'] = 'Compresser l\'export HTML';
+$labels['show_config'] = 'Montrer Afficher la configuration par défaut';
+$labels['systemadmin'] = 'Administrateur système';
+$labels['admin'] = 'Administrateur';
+$labels['configuredby'] = 'configuré par';
+$labels['enabled'] = 'Activé (defaut)';
+$labels['protected'] = 'Protégé';
+$labels['skins'] = 'Skins';
+$labels['loads_always'] = 'Obligatoire';
+$labels['loads_never'] = 'Plugin désactivé';
+$labels['loads_by_user'] = 'L\'utilisateur peut déterminer son usage';
+$labels['loads_linked'] = 'Lié à';
+$labels['unbind'] = 'non lié';
+$labels['bind'] = 'lié';
+$labels['addplugin'] = 'Ajouter un plugin';
+$labels['removeplugin'] = 'Enlever un plugin';
+$labels['errorplugin'] = 'Erreur: plugins obligatoires manquants ';
+$labels['errorrcversion'] = 'Erreur: plugin nécessite Roundcube';
+$labels['errorphpversion'] = 'Erreur: plugin nécessite PHP';
+$labels['errorphpcurl'] = 'Erreur: cURL n\'est pas installé';
+$labels['errorphpfinfo'] = 'Erreur: finfo n\'est pas installé';
+$labels['errordb'] = 'Mise à jour de la DB requise. Veuillez activer le plugin pour démarrer cet ajustement.';
+$labels['errordb8'] = 'Mise à jour de la DB requise';
+$labels['syntaxerror'] = 'Erreur de syntaxe PHP';
+$labels['notconfigured'] = 'Plugin n\'est pas configuré';
+$labels['editconfig'] = 'Editer la configuration';
+$labels['instructions'] = 'Instructions';
+$labels['dbautomatically'] = 'Démarrer la mise à jour';
+$labels['dbmanually'] = 'Veuillez suivre les instructions';
+$labels['ornewer'] = 'ou plus récent';
+$labels['official_releases'] = 'nous supportons les versions officielles Roundcube uniquement';
+$labels['localizationmissing'] = 'Pas détail pour le nom ou la description du plugin détéctés';
+$labels['documentation'] = 'Documentation';
+$labels['select_plugin'] = 'Choisir un plugin';
+$labels['legend'] = 'Légende';
+$labels['plugindisabledbydefault'] = 'Le plugin est désactivé par défaut - L\'utilisateur peut déterminer son usage';
+$labels['pluginenabledbydefault'] = 'Le plugin est sactivé par défaut - L\'utilisateur peut déterminer son usage';
+$labels['pluginmandatory'] = 'Obligatoire - Le plugin est activé, l\'utilisateur ne peut activer ou désactiver le plugin';
+$labels['show_about_link'] = 'Montrer le lien "A propos"';
+$labels['show_support_link'] = 'Montrer le lien "Support"';
+$labels['use_myroundcube_watermark'] = 'Utilisez le watermak "MyRoundCube"';
+$labels['remove_watermark'] = 'Ne pas afficher de watermark';
+$labels['database'] = 'Database';
+$labels['account_details_compressed'] = 'Détails du compte comprimé';
+$labels['credits_transferred'] = 'Crédits transférés';
+$labels['customer_id_changed'] = 'ID client modifié';
+$labels['myrcd_bought'] = 'MyRC$ acheté - merci !';
+$labels['myrcd_refunded'] = 'Remboursement de MyRC$';
+$labels['PHPMyAdmin'] = 'PHPMyAdmin';
+$labels['ipmismatch'] = 'Pas de téléchargement possible depuis l\'IP %s (l\'IP du client ne correspond pas). Utilisez %s ou naviguez vers %s depuis l\'IP %s.';
+$labels['emoticons_pluginname'] = 'Raccourcis des émoticons';
+$labels['emoticons_plugindescription'] = 'Remplacer les raccourcis des émoticons par des images';
+$labels['markbuttons_pluginname'] = 'Boutons de sélection des messages';
+$labels['markbuttons_plugindescription'] = 'Ajoute une icône de contrôle sous la liste des séparateurs de message pour sélectionner rapidement les messages.';
+$labels['keyboard_shortcuts_pluginname'] = 'Raccourcis claviers';
+$labels['keyboard_shortcuts_plugindescription'] = 'Ajoute des contrôles utilisant les raccourcis clavier.';
+$labels['message_highlight_pluginname'] = 'Mise en valeur des messages';
+$labels['message_highlight_plugindescription'] = 'Mets en valeur les messages qui correspondent à vos options de filtrage.';
+$labels['google_contacts_pluginname'] = 'Google contacts';
+$labels['google_contacts_plugindescription'] = 'Permet l\'accès à vos contacts google.';
+$labels['contextmenu_pluginname'] = 'Menu contextuel';
+$labels['contextmenu_plugindescription'] = 'Active l\'affichage d\'un menu contextuel lors d\'un clic droit.';
+$labels['newmail_notifier_pluginname'] = 'Notification de nouveaux messages';
+$labels['newmail_notifier_plugindescription'] = 'Notification lors de la réceptions de nouveaux messages';
+$labels['listcommands_pluginname'] = 'Réponse aux listes de diffusion';
+$labels['listcommands_plugindescription'] = 'Options variées permettant de répondre aux messages en provenance de listes de diffusions.';
+$labels['copymessage_pluginname'] = 'Copie de message(s)';
+$labels['copymessage_plugindescription'] = 'Copie de message(s) dans un autre dossier IMAP.';
+$labels['vcard_attachments_pluginname'] = 'vCard en pièce jointe';
+$labels['vcard_attachments_plugindescription'] = 'Ajouter une boîte aux messages qui ont une pièce jointe vCard pour importer directement le contact dans le carnet d\'adresse.';
+$labels['zipdownload_pluginname'] = 'Exportation des messages';
+$labels['zipdownload_plugindescription'] = 'Exporte les messages en format zip';
+$labels['markasjunk2_pluginname'] = 'Marquer les messages comme étant du spam';
+$labels['markasjunk2_plugindescription'] = 'Marque les message comme étant du spam ou inversement.';
+$labels['markasjunk_pluginname'] = 'Marquer les messages comme étant du spam';
+$labels['markasjunk_plugindescription'] = 'Marque les message comme étant du spam ou inversement.';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Inclure Google Analytics.';
+$labels['globaladdressbook_pluginname'] = 'Carnet d\'adresse global';
+$labels['globaladdressbook_plugindescription'] = 'Ceci est un carnet d\'adresse en lecture seule fourni par votre administrateur.';
+$labels['blockspamsending_pluginname'] = 'Empêcher l\'envoi de spam';
+$labels['blockspamsending_plugindescription'] = 'Permet l\'envoi d\'une quantité définie de messages avec même destinataire pendant une session.';
+$labels['global_config_pluginname'] = 'Gestionnaire de configuration';
+$labels['global_config_plugindescription'] = 'Ceci est un plugin gestionnaire de configuration. Il optimise votre serveur en centralisant les fichiers de configuration du plugin. Il rend aussi les tâches administratives plus simple en permettant l\'utilisation d\'un fichier de configuration unique pour tous vos plugins';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Librairie javascript Jqueryui';
+$labels['hide_blockquote_pluginname'] = 'Masquer la citation';
+$labels['hide_blockquote_plugindescription'] = 'Masquer la citation lorsque le nombre de lignes est supérieur au nombre de lignes spécifiées.';
+$labels['crawler_pluginname'] = 'Crawler';
+$labels['crawler_plugindescription'] = 'Leurre les moteurs de recherche ';
+$labels['archive_pluginname'] = 'Archive';
+$labels['archive_plugindescription'] = 'Archiver les messages dans un dossier d\'archives.';
+$labels['autologon_pluginname'] = 'Connexion automatique.';
+$labels['autologon_plugindescription'] = 'Se connecter automatiquement.';
+$labels['openpgpjs_pluginname'] = 'OpenPGPjs';
+$labels['openpgpjs_plugindescription'] = 'PGP DES dans RoundCube.';
+$labels['dblog_pluginname'] = 'Log dans une database';
+$labels['dblog_plugindescription'] = 'Enregistrer les logs dans une Database au lieu d\'un fichier';
+$labels['gibberish_pluginname'] = 'Chiffrement Gibberish';
+$labels['gibberish_plugindescription'] = 'Une aide pour le chiffrement Gibberish AES.';
+$labels['http_request_pluginname'] = 'Requête HTTP';
+$labels['http_request_plugindescription'] = 'Un plugin pour exécuter des requêtes HTTP via cURL ou fsockopen.';
+$labels['http_auth_pluginname'] = 'Authentification HTTP';
+$labels['http_auth_plugindescription'] = 'Plug in pour supporter l\'authentification HTTP';
+$labels['http_authentication_pluginname'] = 'Authentification HTTP (defaut)';
+$labels['http_authentication_plugindescription'] = 'Utiliser l\'authentification HTTP existante par défaut et utiliser les données de l\'utilisateur';
+$labels['jscolor_pluginname'] = 'Sélecteur de couleur';
+$labels['jscolor_plugindescription'] = 'Plugin pour choisir une couleur';
+$labels['tinymce_pluginname'] = 'TinyMCE - Editeur HTML';
+$labels['tinymce_plugindescription'] = 'Remplacer le TinuMCE par défaut pas TinyMCE jquery (inclu TinyMCE php compressor http://www.tinymce.com/wiki.php/Compressors:PHP).';
+$labels['lang_sel_pluginname'] = 'Séléctionner le language';
+$labels['lang_sel_plugindescription'] = 'Séléctionner le language sur la page d\'authentification';
+$labels['newuser_pluginname'] = 'Nouvel utilisateur';
+$labels['newuser_plugindescription'] = 'informe les administrateurs quand un nouvel utilisateur s\'enregistre via l\'interface du webmail et envoie un message de bienvenue à cet utilisateur lors de la première connexion.';
+$labels['placeholder_pluginname'] = 'Attributs de marqueur de position';
+$labels['placeholder_plugindescription'] = 'Ajouter des attributs de marqueur de position pour les éléments d\'entrée utilisateur et mot de passe.';
+$labels['qtip_pluginname'] = 'Outils jQueryUI';
+$labels['qtip_plugindescription'] = 'Un plugin d\'aide à l\'utilisation des outils jQueryUI';
+$labels['sabredav_pluginname'] = 'SabreDAV (support pour WebDAV avec PHP)';
+$labels['sabredav_plugindescription'] = 'Crée des comptes SabreDAV pour l\'accès aux calendriers CalDAV lorsque de nouveaux utilisateurs sont créés dans Roundcube et leur associe leur mot de passe s\'il a été changé';
+$labels['savepassword_pluginname'] = 'Sauvegarde les mots de passe';
+$labels['savepassword_plugindescription'] = 'Un plugin d\'aide qui est requis par d\'autres plugins';
+$labels['database_attachments_pluginname'] = 'Pièce jointe en base de données';
+$labels['database_attachments_plugindescription'] = 'Un plugin d\'aide à la gestion des pièces jointe en base de données';
+$labels['help_pluginname'] = 'aide';
+$labels['help_plugindescription'] = 'Aide Webmail';
+$labels['new_user_dialog_pluginname'] = 'Nouvel utilisateur';
+$labels['new_user_dialog_plugindescription'] = 'Présente une zone de dialogue avec les paramètres d\'identité aux nouveaux utilisateurs. Lorsqu\'un utilisateur est créé, ce plugin vérifie l\'identité par défaut et met un flag si elle est incomplète. Un message d\'avertissement apparait sur l\'écran jusqu\'à que l\'utilisateur ait compléter ses données personnelles';
+$labels['rcguard_pluginname'] = 'ReCAPTCHA';
+$labels['rcguard_plugindescription'] = 'Force l\'utilisateur à utililser les captcha après un certain nombre d\'échec lors de l\'authentification';
+$labels['domain_check_pluginname'] = 'Vérification de domaine';
+$labels['domain_check_plugindescription'] = 'Restreint l\'identification au webmail à des domaines spécifiques';
+$labels['tasklist_pluginname'] = 'Liste de tâches';
+$labels['tasklist_plugindescription'] = 'Créer des tâches et des sous-tâches avec rappels.';
+$labels['virtuser_query_pluginname'] = 'Requête utilisateur virtuel';
+$labels['virtuser_query_plugindescription'] = 'Recherche utilisateur -> email ou email -> utilisateur avec base de donnée.';
+$labels['virtuser_file_pluginname'] = 'Requête utilisateur virtuel';
+$labels['virtuser_file_plugindescription'] = 'Recherche utilisateur -> email ou email -> utilisateur avec fichier.';
+$labels['userinfo_pluginname'] = 'Informations utilisateur.';
+$labels['userinfo_plugindescription'] = 'Affiche quelques informations à propos de l\'utilisateur courant.';
+$labels['subscriptions_option_pluginname'] = 'Abonnements IMAP';
+$labels['subscriptions_option_plugindescription'] = 'Gérer les abonnements IMAP';
+$labels['filters_pluginname'] = 'Filtres';
+$labels['filters_plugindescription'] = 'Gérer les filtres clients.';
+$labels['forgot_password_pluginname'] = 'Mot de passe perdu';
+$labels['forgot_password_plugindescription'] = 'Requêtes de changement de mot de passe.';
+$labels['sieverules_pluginname'] = 'Filtres Sieve';
+$labels['sieverules_plugindescription'] = 'Gérer les filtres Sieve.';
+$labels['managesieve_pluginname'] = 'Filtres Sieve';
+$labels['managesieve_plugindescription'] = 'Gérer les filtres Sieve.';
+$labels['acl_pluginname'] = 'Listes de contrôle d\'accès (ACL)';
+$labels['acl_plugindescription'] = 'Gestion des dossiers de liste de contrôle d\'accès (ACL).';
+$labels['vacation_pluginname'] = 'Message automatiques';
+$labels['vacation_plugindescription'] = 'Gérer les messages automatiques (signalement de vacances)';
+$labels['password_pluginname'] = 'Modifier le mot de passe';
+$labels['password_plugindescription'] = 'Permet aux utilisateurs de changer de mot de passe.';
+$labels['redundant_attachments_pluginname'] = 'Pièces jointes redondantes.';
+$labels['redundant_attachments_plugindescription'] = 'Le plugin de pièces jointes redondantes permet de stocker les fichiers temporaires en double. Elles sont attachées à la fois dans la base de données et sur le système de fichier.';
+$labels['example_addressbook_pluginname'] = 'Carnet d\'adresse d\'exemple.';
+$labels['example_addressbook_plugindescription'] = 'Exemple de code pour ajouter un carnet d\'adresse supplémentaire.';
+$labels['debug_logger_pluginname'] = 'Enregistreur de données de débogage';
+$labels['debug_logger_plugindescription'] = 'L\'enregistreur de données de débogage active l\'enregistrement étendu de données pour le débogage.';
+$labels['show_additional_headers_pluginname'] = 'Visualiser les entêtes supplémentaires.';
+$labels['show_additional_headers_plugindescription'] = 'Concept de plugin permettant de visualiser les entêtes supplémentaires dans la vue message.';
+$labels['additional_message_headers_pluginname'] = 'Entêtes de messages supplémentaires';
+$labels['additional_message_headers_plugindescription'] = 'Plugin simple permettant d\'ajouter ou supprimer des entêtes sur les messages envoyés.';
+$labels['new_user_identity_pluginname'] = 'Visite d\'un nouvel utiisateur';
+$labels['new_user_identity_plugindescription'] = 'Le plugin de visite d\'un nouvel utilisateur peuple l\'identité d\'un nouvel utilisateur depuis ses informations LDAP à sa première connexion.';
+$labels['squirrelmail_usercopy_pluginname'] = 'Migration des utilisateurs Squirrelmail';
+$labels['squirrelmail_usercopy_plugindescription'] = 'Copie les identités des utilisateurs depuis une installation de Squirrelmail.';
+$labels['yubikey_authentication_pluginname'] = 'Authentification Yubikey de Yubico';
+$labels['yubikey_authentication_plugindescription'] = 'Plugin pour utiliser l\'authentification Yubikey de Yubico sur RoundCube.';
+$labels['sauserprefs_pluginname'] = 'Préférences utilisateurs Spamassassin';
+$labels['sauserprefs_plugindescription'] = 'Ajoute un onglet \'Spam\' à l\'onglet \'Paramètres personnels\' pour modifier leurs préférences Spamassassin';
+$labels['dkimstatus_pluginname'] = 'Statut DKIM';
+$labels['dkimstatus_plugindescription'] = 'DKIMSTATUS affiche le statut de la signature DKIM de chaque mail que l\'utilisateur lit dans Roundcube.';
+$labels['roundcube_openpgp_pluginname'] = 'RoundCube OpenPGP';
+$labels['roundcube_openpgp_plugindescription'] = 'Cette extension implémente OpenPGP dans RoundCube. Il génère, gère et utilise des clés de cryptage.';
+$labels['automatic_addressbook_pluginname'] = 'Carnet d\'adresses automatique';
+$labels['automatic_addressbook_plugindescription'] = 'Créé un carnet d\'adresses et y insère automatiquement les adresses email collectées. Cela élimine le besoin de le faire manuellement.';
+$labels['calendar_pluginname'] = 'Agenda';
+$labels['calendar_plugindescription'] = 'Gérez vos rendez-vous dans l\'agenda webmail.';
+$labels['attachment_reminder_pluginname'] = 'Rappel de pièce jointe';
+$labels['attachment_reminder_plugindescription'] = 'Rappelle aux utilisateurs de joindre un fichier avant d\'envoyer un message.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/hu_HU.inc b/plugin_manager/localization/hu_HU.inc
new file mode 100644
index 0000000..15ec191
--- /dev/null
+++ b/plugin_manager/localization/hu_HU.inc
@@ -0,0 +1,154 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/hu_HU.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Mihaly Vukovics - 09/18/2013 14:09:15
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Beépülőmodul kezelő';
+$labels['plugindescription'] = 'A beépülőmodul kezelő lehetőséget ad a beépülőmodulok felhasználói szintű engedélyezésére, tiltására. Emelett segíti a rendszgazdákat a beépülők telepítésében és frissen tartásában. A modul nem végez módosításokat a fáljrendszeren, illetve nem telepít semmit automatikusan.';
+$labels['plugin_manager_title'] = 'Beépülő modulok kezelése';
+$labels['plugin_manager_center'] = 'Beépülőmodul kezelő központ';
+$labels['updatepm'] = 'Beépülőmodul kezelőhöz frissítés érhető el';
+$labels['updatepmrequired'] = 'A beépülőmodul kezelőt frissíteni kell.';
+$labels['downloadnow'] = 'Letöltés';
+$labels['misc'] = 'Egyebek';
+$labels['downloads'] = 'letöltések';
+$labels['issue'] = 'Hibajelentés';
+$labels['submitissue'] = 'Hibajelentés. Kérlük ellenőrizze a hibanaplót és a relevéns információkat írja a jegybe. Megjegyzés: Google Account szükséges.';
+$labels['showall'] = 'Összes beépülőmodul megjelenítése';
+$labels['hideuptodate'] = 'Csak a frissítések megjelenítése';
+$labels['connectionerror'] = 'A távoli szerver nem válaszolt a csatlakozési kérésre.';
+$labels['trylater'] = 'Próbálkozzon később...';
+$labels['translate'] = 'Beépüélőmodul nyelvének fordítása';
+$labels['restoredefaults'] = 'Alapbeállítások visszaállítása';
+$labels['checkall'] = 'Mindegyik';
+$labels['uncheckall'] = 'Semelyik';
+$labels['toggle'] = 'Kijelölés megfordítása';
+$labels['status'] = 'Státusz';
+$labels['globalplugins'] = 'Globális beépülők';
+$labels['backend'] = 'Server beépülők';
+$labels['messagesmanagement'] = 'Üzenetkezelés';
+$labels['furtherconfig'] = 'Most szeretné konfigurálni a beépülőt?';
+$labels['uninstall'] = 'A modul kikapcsolása a hozzá kapcsolodó összes beállítást véglegesen törli. Ennek tudatában is kikapcsolod?';
+$labels['areyousure'] = 'Ez a lépés nem visszaállítható, biztos, hogy folytatja?';
+$labels['successfullydeleted'] = 'A beállítások sikeresen eltávolításra kerültek.';
+$labels['successfullysaved'] = 'Sikeresen elmentve.';
+$labels['errorsaving'] = 'Hiba lépett fel a mentés közben.';
+$labels['yes'] = 'Igen';
+$labels['no'] = 'Nem';
+$labels['disable'] = 'Letiltva';
+$labels['remove'] = 'Eltávaolítás';
+$labels['savewarning'] = 'El akarok menteni a változásokat?';
+$labels['authors_comments'] = 'A szerző megjegyzései (nincs lefordítva)';
+$labels['requiredby'] = 'Erre a beépülőre az alábbiaknak van szüksége:';
+$labels['requires'] = 'Ez a beépülő a következőket igényli:';
+$labels['recommended'] = 'Ajánlott beépülők';
+$labels['update_plugins'] = 'Beépülő letöltések';
+$labels['ziparchive'] = 'ZIP letöltése';
+$labels['demoaccount'] = 'Sajnálhu, de ez a funkció nem elérhető (Demó hozzáférés)';
+$labels['serverversion'] = 'Telepített verzió';
+$labels['mirrorversion'] = 'Elérhető legújabb verzió';
+$labels['mirrorhost'] = 'Tükör szerver';
+$labels['comments'] = 'Követelmények és frissítési megjegyzések';
+$labels['update_error'] = 'Verzió eltérés';
+$labels['update_ok'] = 'A legújabb verziók vannak telepítve, nincs szükség frissítésre.';
+$labels['update_edit'] = 'A beépülőt újra kell konfigurálni vagy adatbázis frissítést igényel. Kérjük olvassa el a frissítéssel kapcsolatos megjegyzéseket.';
+$labels['servernewer'] = 'A regisztrált beépülő újabb, mint a tükörszerveren található.';
+$labels['orhigher'] = 'vagy magasabb';
+$labels['rc_ok'] = 'A Roundcube verzió aktuális.';
+$labels['update_update'] = 'A beépülő elavult, frissítse, olvassa el a frissítési megjegyzéseket.';
+$labels['noupdates'] = 'Nincs frissítés kiválasztva.';
+$labels['rc_update'] = 'A Rouncube elavult, kérjük frissítse.';
+$labels['rc_uptodate'] = 'A Rouncube verziója aktuális.';
+$labels['rc_newer'] = 'A Roundcube verziója frissebb, mint a tükör szerveren lévő!';
+$labels['justunzip'] = 'Csak tömörítse ki a ZIP fáljt a meglévő Roundcube könyvtárába.';
+$labels['guide'] = 'További információk...';
+$labels['thirdparty'] = 'Ez a beépülő harmadik féltől származik.';
+$labels['thirdpartywarning'] = 'Ez a beépülőmodul harmadik féltől származik. Javasoljuk, hogy ne innen töltse le, hanem egyenesen a fejlesztő oldaláról, hogy biztosan a legfrissebb verziót és az aktuális dokumentációt kapja.';
+$labels['develsite'] = 'Letöltés';
+$labels['notinstalled'] = 'nincs telepítve';
+$labels['notregistered'] = 'nincs regisztrálva';
+$labels['roundcubeurl'] = 'Roundcube letöltése';
+$labels['languageupdate'] = 'Nyelvi frissítés előrhető.';
+$labels['localizationfilesonly'] = 'Megjegyzés: a letöltés csak nyelvi frissítést tartalmaz.';
+$labels['donotregister'] = 'Ne regisztrálja a beépülőt, mert automatikusan betöltődik.';
+$labels['register'] = 'Regisztrálja a beépülőt a Beépülő kezelőben vagy a Rouncube konfigurációs fájljában: ./config/config.inc.php [$config[\'plugins\'] = array("foo", "bar");].';
+$labels['customer_account'] = 'Felhasználói fiók';
+$labels['customer_id'] = 'Ügyfélazonosító';
+$labels['invalid_customer_id'] = 'Hibás ügyfélazonosító';
+$labels['invalid_credits'] = 'Hibás kreditek';
+$labels['successfully_transferred'] = 'Kreditek sikeresen átadva';
+$labels['merge'] = 'Kreditek összevonása';
+$labels['credits'] = 'Kreditek';
+$labels['creditsupdated'] = 'A kreditek változtak az oldal utolsó betöltése óta';
+$labels['buynow'] = 'Kredit vásárlása';
+$labels['history'] = 'Felhasználó fiók történet';
+$labels['details'] = 'Részletek';
+$labels['receipt'] = 'Számla';
+$labels['plugins'] = 'Beépülő modulok';
+$labels['clickhere'] = 'Kattintson ide';
+$labels['discardliabletopaycosts'] = 'Fizetős letöltések figyelmen kivül hagyása';
+$labels['unchecknotinstalledplugins'] = 'Nem telepített beépülő modulok figyelmen kívül hagyása';
+$labels['sum'] = 'Összesen';
+$labels['show'] = 'Mutat';
+$labels['hide'] = 'Elrejt';
+$labels['view'] = 'nézet';
+$labels['expired'] = 'lejárt';
+$labels['terms'] = 'Feltételek';
+$labels['pricelist'] = 'Árlista letöltése';
+$labels['forthisdownload'] = 'ezért a letöltésért';
+$labels['remainingcredits'] = 'megmaradt kreditek';
+$labels['initialdownload'] = 'Első letöltés';
+$labels['keyfeatureaddition'] = 'Új fontosabb képesség';
+$labels['codeimprovements'] = 'Kód fejlesztése';
+$labels['servicenotavailable'] = 'A szolgáltatás jelenleg nem elérhető, próbálja később';
+$labels['myrcerror'] = 'A MyRoundcube szolgáltatás jelenleg nem elérhető';
+$labels['getnew'] = 'Új felhasználói azonosító igénylése';
+$labels['getnew_hint'] = 'Javasoljuk, hogy rendszeresen újjítsa meg a felhasználói azonosítóját. Ha bármilyen gyanús változást lát a felhasználói fiók adatai körül, azonnal ujjítsa meg!';
+$labels['transfer'] = 'Kreditek átadása';
+$labels['message_highlight_pluginname'] = 'Üzenetek kiemelése';
+$labels['message_highlight_plugindescription'] = 'Üzenetek kiemelése egy megadott feltétel alapján';
+$labels['google_contacts_pluginname'] = 'Google Névjegyek';
+$labels['contextmenu_pluginname'] = 'Környezetérzékeny menü';
+$labels['contextmenu_plugindescription'] = 'Környezettől függő, jobb egérgombra felbukkanó menü engedélyezése.';
+$labels['globaladdressbook_pluginname'] = 'Google Címjegyzék';
+$labels['manage_admins'] = 'Adminisztrátorok';
+$labels['plugin_manager_admins'] = 'Beépülő modul kezelő adminisztrátorok';
+$labels['allow_plugins_configuration'] = 'Beépölő beállítási jogkör delegálása';
+$labels['share_credits'] = 'Kreditek megosztása';
+$labels['add'] = 'Hozzáadás';
+$labels['accountnotexists'] = 'A fiók nem létezik';
+$labels['sharedby'] = 'A felhasználói fiók megosztva';
+$labels['switch'] = 'Váltás';
+$labels['ownaccount'] = 'a saját fiókhoz';
+$labels['shareinvitation'] = 'a megosztott fikóhoz';
+$labels['use_ssl'] = 'Használjon SSL titkosítást a MyRouncube szerverekhez való csatlakozáskor';
+$labels['use_hmail'] = 'hMeilserver kompatibilis beépülők használata';
+$labels['show_myrc_messages'] = 'MyRoundcube-tól érkező értesítések megjelenítése';
+$labels['serverwide'] = 'Server szintű konfiguráció';
+$labels['file_based_config'] = 'Fálj alapú, globális konfiguráció engedélyezése';
+$labels['advanced_admins'] = 'Csak gyarkolott rendszergazdáknak';
+$labels['compress_html'] = 'HTML kimenet tömörítése';
+$labels['enabled'] = 'Engedélyezve (alapértelmezett)';
+$labels['protected'] = 'Védett';
+$labels['skins'] = 'Bőrök';
+$labels['loads_always'] = 'Elengedhetetlen';
+$labels['loads_never'] = 'Beépülő letiltva';
+$labels['documentation'] = 'Dokumentáció';
+$labels['select_plugin'] = 'Válasszon beépülőt';
+$labels['legend'] = 'Jelmagyarázat';
+$labels['show_about_link'] = 'Névjegy link megjelenítése';
+$labels['show_support_link'] = 'Támogatás link megjelenítése';
+$labels['use_myroundcube_watermark'] = '"MyRoundcube" vízjel használata';
+$labels['remove_watermark'] = 'Ne legyen semmilyen vízjel';
+$labels['database'] = 'Adatbázis';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/it_IT.inc b/plugin_manager/localization/it_IT.inc
new file mode 100644
index 0000000..60b8224
--- /dev/null
+++ b/plugin_manager/localization/it_IT.inc
@@ -0,0 +1,170 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/it_IT.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2012, Roland 'rosali' Liebl
+ | Licensed under the GNU GPL
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Roberto - 11/05/2012 14:56:52
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Gestore Plugin';
+$labels['plugindescription'] = 'Gestore plugin permette agli utenti di abilitare e/o disabilitare i plugin (a livello di account utente) e aiuta gli amministratori a mantenere aggiornato il sistema per ciò che riguarda plugins, bug di sistema, downloads centralizzati, documentazioni e suggerimenti.';
+$labels['plugin_manager_title'] = 'Gestisci i Plugin';
+$labels['plugin_manager_center'] = 'Pannello gestione Plugin';
+$labels['calendaring'] = 'Calendario';
+$labels['misc'] = 'Varie';
+$labels['downloads'] = 'Downloads';
+$labels['issue'] = 'Problemi';
+$labels['submitissue'] = 'Notifica un problema';
+$labels['showall'] = 'Mostra tutti i Plugins';
+$labels['hideuptodate'] = 'Mostra solo gli aggiornamenti';
+$labels['connectionerror'] = 'Il server remoto non risponde al tentativo di connessione';
+$labels['trylater'] = 'Per favore, riprova più tardi...';
+$labels['translate'] = 'Traduci questo Plugin';
+$labels['restoredefaults'] = 'Impostazioni iniziali';
+$labels['checkall'] = 'Seleziona tutti';
+$labels['uncheckall'] = 'Rimuovi tutti';
+$labels['toggle'] = 'Inverti la selezione';
+$labels['status'] = 'Stato';
+$labels['globalplugins'] = 'Plugin globale';
+$labels['backend'] = 'Server di Plugin';
+$labels['messagesmanagement'] = 'Gestione Messaggi';
+$labels['furtherconfig'] = 'Vuoi configurare il plugin adesso?';
+$labels['uninstall'] = 'Stai per disabilitare il plugin. Vuoi rimuovere definitivamente le configurazioni salvate?';
+$labels['uninstallconfirm'] = 'Stai per disabilitare il plugin. ATTENZIONE: Seleziona »DISABILITA« per disabilitare questo plugin e mantenere dati e configurazioni nel nostro server se intendi usare ancora il plugin nel futuro. Seleziona »RIMUOVI« per cancellare definitivamente dati e configurazioni di questo plugin dal nostro database. Quest\'ultima azione non può essere annullata.';
+$labels['areyousure'] = 'Non puoi intraprendere questa azione. Sei veramente sicuro?';
+$labels['successfullydeleted'] = 'Le configurazioni sono state rimosse con successo.';
+$labels['successfullysaved'] = 'Salvato con successo.';
+$labels['errorsaving'] = 'Errore durante il salvataggio.';
+$labels['yes'] = 'Si';
+$labels['no'] = 'No';
+$labels['disable'] = 'Disabilita';
+$labels['remove'] = 'Rimuovi';
+$labels['savewarning'] = 'Vuoi salvare i cambiamenti?';
+$labels['plugin_manager_update'] = 'Aggiorna il gestore di Plugin';
+$labels['authors_comments'] = 'Commento dell\'Autore (non tradotto)';
+$labels['requiredby'] = 'Plugin richiesto da';
+$labels['requires'] = 'Il Plugin richiede';
+$labels['recommended'] = 'Plugin raccomandati';
+$labels['update_plugins'] = 'Aggiorna i Plugin';
+$labels['ziparchive'] = 'Scarica l\'archivio compresso';
+$labels['demoaccount'] = 'Spiacente, download non disponibile (Account Demo)';
+$labels['serverversion'] = 'Versione del Server';
+$labels['mirrorversion'] = 'Versione del Mirror';
+$labels['mirrorhost'] = 'Server di Mirror';
+$labels['comments'] = 'Requisiti e Note di Aggiornamento';
+$labels['update_error'] = 'Versione non corrispondente';
+$labels['update_ok'] = 'È stata rilevata la versione più recente. Nessun aggiornamento necessario.';
+$labels['update_edit'] = 'Il Plugin deve essere riconfigurato o richiede cambiamenti nel database. Per favore leggi le Note di Aggiornamento.';
+$labels['servernewer'] = 'Il Plugin registrato è più nuovo della versione nel Server Mirror.';
+$labels['orhigher'] = 'o successiva';
+$labels['rc_ok'] = 'Il Core di Roundcube è aggiornato.';
+$labels['update_update'] = 'Il Plugin è obsoleto. Per favore aggiornalo! Leggi le Note di Aggiornamento.';
+$labels['noupdates'] = 'Nessun aggiornamento selezionato.';
+$labels['rc_update'] = 'Il Core di Roundcube è obsoleto. Per favore aggiornalo!';
+$labels['rc_uptodate'] = 'Il Core di Roundcube è aggiornato.';
+$labels['rc_newer'] = 'Il Core di Roundcube è più nuovo della versione nel server Mirror!';
+$labels['nottested'] = 'Per favore usa i Plugin con attenzione! Non sappiamo se i Plugin a disposizione funzionano con Roundcube v%s.';
+$labels['justunzip'] = 'Scompatta semplicemente l\'Archivio e sostituisci all\'installazione esistente.';
+$labels['guide'] = 'Ulteriori informazioni...';
+$labels['thirdparty'] = 'Questo non è un Plugin myRoundcube.';
+$labels['thirdpartywarning'] = 'Questo è un Plugin di terze parti. Consigliamo di non scaricare il plugin da questo Server Mirror. Scaricalo dal sito dello sviluppatore per essere sicuro di avere la versione più aggiornata facendo attenzione alle note dello sviluppatore.';
+$labels['develsite'] = 'Scarica';
+$labels['notinstalled'] = 'non installato';
+$labels['notregistered'] = 'non registrato';
+$labels['roundcubeurl'] = 'Scarica Roundcube';
+$labels['languageupdate'] = 'L\'aggiornamento della lingua è disponibile';
+$labels['donotregister'] = 'Non attivare questo Plugin. Viene caricato automaticamente.';
+$labels['register'] = 'Attiva il Plugin in ./config/config.inc.php [$config[\'plugins\'] = array("foo", "bar");].';
+$labels['customer_id'] = 'Customer ID';
+$labels['noplugindescription'] = 'Nessuna descrizione del plugin rilevata.';
+$labels['markbuttons_pluginname'] = 'Bottoni di Contrassegno dei Messaggi';
+$labels['markbuttons_plugindescription'] = 'Aggiunge delle icone di controllo sotto la lista dei messaggi per contrassegnare rapidamente i messaggi.';
+$labels['automatic_addressbook_pluginname'] = 'Rubrica automatica';
+$labels['automatic_addressbook_plugindescription'] = 'Raccogli gli indirizzi di posta di tutti i destinatari in una rubrica separata.';
+$labels['keyboard_shortcuts_pluginname'] = 'Scorciatoie da tastiera';
+$labels['keyboard_shortcuts_plugindescription'] = 'Inserisci i comandi utilizzando le scorciatoie da tastiera.';
+$labels['message_highlight_pluginname'] = 'Evidenzia Messaggi';
+$labels['message_highlight_plugindescription'] = 'Evidenzia i messaggi in corrispondenza delle opzioni dei filtri.';
+$labels['fixTHEAD_pluginname'] = 'Fissa Intestazione Lista Messaggi';
+$labels['fixTHEAD_plugindescription'] = 'Fissa l\'intestazione della Lista Messaggi';
+$labels['compose_addressbook_pluginname'] = 'Seleziona Indirizzi';
+$labels['compose_addressbook_plugindescription'] = 'Seleziona indirizzi durante la composizione dei messaggi.';
+$labels['google_contacts_pluginname'] = 'Contatti Google';
+$labels['google_contacts_plugindescription'] = 'Accedi ai tuoi contatti Google';
+$labels['contextmenu_pluginname'] = 'Menu contestuale';
+$labels['contextmenu_plugindescription'] = 'Abilita la funzionalità pulsante destro del mouse nel menu contestuale.';
+$labels['newmail_notifier_pluginname'] = 'Notifica Nuovo Messaggio';
+$labels['newmail_notifier_plugindescription'] = 'Notifica all\'arrivo di un nuovo messaggio.';
+$labels['listcommands_pluginname'] = 'Rispondi alle Liste';
+$labels['listcommands_plugindescription'] = 'Varie opzioni per rispondere ai messaggi inviati dalle liste di discussione.';
+$labels['copymessage_pluginname'] = 'Copia messaggi(o)';
+$labels['copymessage_plugindescription'] = 'Copia messaggi(o) in un\'altra cartella IMAP.';
+$labels['forwardattachment_pluginname'] = 'Inoltra come Allegato';
+$labels['forwardattachment_plugindescription'] = 'Inoltra messaggi multipli come allegati.';
+$labels['vcard_attachments_pluginname'] = 'Allega vCard';
+$labels['vcard_attachments_plugindescription'] = 'Aggiunge in allegato una vCard ai messaggi inviati per permettere ai destinatari l\'archiviazione del proprio contatto nella loro rubrica.';
+$labels['importmessages_pluginname'] = 'Importa Messaggi';
+$labels['importmessages_plugindescription'] = 'Importa messaggi da un file compresso .zip o da una sorgente eml.';
+$labels['zipdownload_pluginname'] = 'Esporta Messaggi';
+$labels['zipdownload_plugindescription'] = 'Esporta i messaggi in un file compresso .zip';
+$labels['markasjunk2_pluginname'] = 'Marca i Messaggi come Posta Indesiderata';
+$labels['markasjunk2_plugindescription'] = 'Marca i Messaggi come Posta Indesiderata e come Posta Non indesiderata';
+$labels['markasjunk_pluginname'] = 'Marca i Messaggi come Posta Indesiderata';
+$labels['markasjunk_plugindescription'] = 'Marca i Messaggi come Posta Indesiderata e come Posta Non indesiderata';
+$labels['google_ads_pluginname'] = 'Annunci Google';
+$labels['google_ads_plugindescription'] = 'Mostra gli Annunci di Google';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Includi Google Analytics';
+$labels['globaladdressbook_pluginname'] = 'Rubrica globale';
+$labels['globaladdressbook_plugindescription'] = 'Questa è una rubrica in sola lettura fornita dall\'Amministratore';
+$labels['blockspamsending_pluginname'] = 'Impedisci l\'Invio di Posta Indesiderata';
+$labels['blockspamsending_plugindescription'] = 'Permette l\'invio solo di una quantità definita di messaggi con lo stesso contenuto durante una sessione.';
+$labels['global_config_pluginname'] = 'Gestore Configurazioni';
+$labels['global_config_plugindescription'] = 'Questo è plugin di gestione di configurazioni. Ottimizza il tuo server centralizzando i file di configurazione dei plugin. Rende anche le attività di amministrazione più facili abilitando l\'utilizzo di un solo file di configurazione per tutti i plugin.';
+$labels['jqueryui_pluginname'] = 'jQuery UI';
+$labels['jqueryui_plugindescription'] = 'Libreria javascript jQuery UI';
+$labels['hide_blockquote_pluginname'] = 'Nascondi le citazioni';
+$labels['hide_blockquote_plugindescription'] = 'Nascondi le citazioni when il numero delle linee è maggiore di quello specificato';
+$labels['crawler_pluginname'] = 'Crawler';
+$labels['crawler_plugindescription'] = 'Pagina di contenuto "Fake" per i crawlers';
+$labels['dblog_pluginname'] = 'Log su database';
+$labels['dblog_plugindescription'] = 'Registra i log su un database anziché su un file';
+$labels['http_auth_pluginname'] = 'HTTP Authentication ';
+$labels['http_auth_plugindescription'] = 'Plugin che attiva il supporto all\'autenticazione HTTP';
+$labels['impersonate_pluginname'] = 'Impersonate';
+$labels['impersonate_plugindescription'] = 'Tool per amministratori che permettere di eseguire login nei vari accounts attraverso una "master password"';
+$labels['jscolor_pluginname'] = 'Cattura colori';
+$labels['jscolor_plugindescription'] = 'Un plugin che visualizza un "Cattura colori"';
+$labels['tinymce_pluginname'] = 'TinyMCE - HTML Editor';
+$labels['tinymce_plugindescription'] = 'Questo plugin implementa TinyMCE PHP Compressor (http://www.tinymce.com/wiki.php/Compressors:PHP). Inoltre aggiunge la possibilità di configrare TinyMCE senza modificare i file di Roundcube';
+$labels['embed_images_pluginname'] = 'Embed external Images';
+$labels['embed_images_plugindescription'] = 'Incolla immagini esterne nel corpo di un messaggio';
+$labels['lang_sel_pluginname'] = 'Select Language';
+$labels['lang_sel_plugindescription'] = 'Scegli la lingua nella pagina di login';
+$labels['newuser_pluginname'] = 'New User';
+$labels['newuser_plugindescription'] = 'Informa gli amministratori quando un nuovo utente si è registrato attraverso l\'interfaccia webmail e manda un messaggio di benvenuto al nuovo utente al primo login';
+$labels['placeholder_pluginname'] = 'Placeholder Attributes';
+$labels['placeholder_plugindescription'] = 'Aggiungi attributi segnaposto agli elementi input testo e password';
+$labels['qtip_pluginname'] = 'jQueryUI Tool Tips';
+$labels['qtip_plugindescription'] = 'Plugin di supporto per usare jQueryUI';
+$labels['sabredav_pluginname'] = 'SabreDAV';
+$labels['sabredav_plugindescription'] = 'Crea SabreDAV accounts per l\'accesso a un calendario CalDAV quando in Roundcube viene creato un nuovo utente e aggiorna la password associata se viene cambiata';
+$labels['savepassword_pluginname'] = 'Save Passwords';
+$labels['savepassword_plugindescription'] = 'Plugin richiesto da altri plugin';
+$labels['database_attachments_pluginname'] = 'Database Attachments';
+$labels['database_attachments_plugindescription'] = 'Plugin di supporto per gestire gli allegati tramite database';
+$labels['new_user_dialog_pluginname'] = 'New user Dialog';
+$labels['new_user_dialog_plugindescription'] = 'Mostra la finestra gestione identità ai nuovi utenti. Quando un nuovo utente viene creato, questo plugin controlla l\'identità di default e imposta un flag di sessione se questa è incompleta. Un box in sovrimpressione apparirà sullo schermo fino a quando l\'utente non abbia completato l\'inserimento delle informazioni';
+$labels['rcguard_pluginname'] = 'ReCAPTCHA';
+$labels['rcguard_plugindescription'] = 'Forca l\'inseirmento di un CAPTCHA dopo un certo numero di tentativi di login falliti';
+$labels['domain_check_pluginname'] = 'Check Domain';
+$labels['domain_check_plugindescription'] = 'Limita l\'accesso alla Webmail ai domini specificati.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/nl_NL.inc b/plugin_manager/localization/nl_NL.inc
new file mode 100644
index 0000000..b9562f5
--- /dev/null
+++ b/plugin_manager/localization/nl_NL.inc
@@ -0,0 +1,201 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| language/nl_NL/labels.inc |
+| |
+| Language file of the RoundCube Webmail client |
+| Copyright (C) 2008-2012, RoundQube Dev. - Switzerland |
+| |
++-----------------------------------------------------------------------+
+| Author: |
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Plugin beheerder';
+$labels['plugindescription'] = 'Hiermee kunnen gebruikers plugins makkelijk activeren of uitschakelen, beheerders kunnen makkelijk de plugins onderhouden. ';
+$labels['plugin_manager_title'] = 'Beheer plugins';
+$labels['plugin_manager_center'] = 'Centrale plaats voor plugins';
+$labels['calendaring'] = 'Kalendering';
+$labels['misc'] = 'Diversen';
+$labels['downloads'] = 'downloads';
+$labels['issue'] = 'Probleem';
+$labels['submitissue'] = 'Rapporteer een probleem.<br /><br />Controleer de logbestanden en plaats deze informatie in de ticket.<br /><br /><b>Notitie</b>: Google account is noodzakelijk.';
+$labels['showall'] = 'Maak alle plugins zichtbaar';
+$labels['hideuptodate'] = 'Laat alleen nieuwe plugins zichtbaar';
+$labels['connectionerror'] = 'De externe server heeft geen antwoord gegeven.';
+$labels['trylater'] = 'Probeer AUB later';
+$labels['translate'] = 'Vertaal deze plugin';
+$labels['restoredefaults'] = 'Herstel standaard waardes';
+$labels['checkall'] = 'Selecteer alles';
+$labels['uncheckall'] = 'Alles deselecteren';
+$labels['toggle'] = 'Wissel selectie';
+$labels['status'] = 'Status';
+$labels['globalplugins'] = 'Algemene plugins';
+$labels['backend'] = 'Server plugins';
+$labels['messagesmanagement'] = 'Bericht beheer';
+$labels['furtherconfig'] = 'Wilt u deze plugin nu configureren?';
+$labels['uninstall'] = 'U staat op het punt om deze plugin uit te schakelen. Wilt u de opgeslagen instellingen definitief verwijderen?';
+$labels['uninstallconfirm'] = 'U staat op het punt om deze plugin uit te schakelen. LET OP: Selecteer >>UITSCHAKELEN<< om deze plugin uit te schakelen en alle data en configuraties te bewaren. Selecteer >>VERWIJDEREN<< als u alle data en configuraties wenst te verwijderen. Deze actie kan niet ongedaan worden gemaakt!';
+$labels['areyousure'] = 'Deze instelling kan niet ongedaan worden gemaakt, weet u het zeker?';
+$labels['successfullydeleted'] = 'Instellingen zijn succesvol verwijderd.';
+$labels['successfullysaved'] = 'Succesvol opgeslagen';
+$labels['errorsaving'] = 'Er is een probleem opgetreden tijdens het opslaan.';
+$labels['yes'] = 'Ja';
+$labels['no'] = 'Nee';
+$labels['disable'] = 'Uitschakelen';
+$labels['remove'] = 'Verwijderen';
+$labels['savewarning'] = 'Wenst u de aanpassingen op te slaan?';
+$labels['plugin_manager_update'] = 'Update Plugins';
+$labels['authors_comments'] = 'Commentaar van de auteur (Niet vertaald)';
+$labels['requiredby'] = 'Plugin word vereist door';
+$labels['requires'] = 'Plugin vereist';
+$labels['recommended'] = 'Aanbevolen plugins';
+$labels['update_plugins'] = 'Plugin downloads';
+$labels['ziparchive'] = 'Download Zip-Archief';
+$labels['demoaccount'] = 'Sorry, donwloaden is niet mogelijk (Demo Account)';
+$labels['serverversion'] = 'Server versie';
+$labels['mirrorversion'] = 'Versie op de bronserver';
+$labels['mirrorhost'] = 'Bronserver';
+$labels['comments'] = 'Benodigdheden en notities van de bijgewerkte versie';
+$labels['update_error'] = 'Versie verschil';
+$labels['update_ok'] = 'Meest actuele versie gedetecteerd. Geen aanpassingen noodzakelijk.';
+$labels['update_edit'] = 'Plugin dient opnieuw te worden ingesteld of vraagt een database aanpassing. Lees de bijsluiter van de update.';
+$labels['servernewer'] = 'Aanwezige plugin is nieuwer dan die van de bronserver.';
+$labels['orhigher'] = 'of hoger';
+$labels['rc_ok'] = 'Roudcube versie is up-to-date';
+$labels['update_update'] = 'Plugin is verouderd. Het is verstandig om deze bij te werken. Lees de bijsluiter van de update.';
+$labels['noupdates'] = 'Geen bijgewerkte versie geselecteerd.';
+$labels['rc_update'] = 'Roundcube versie is verouderd. Het is verstandig om deze bij te werken!';
+$labels['rc_uptodate'] = 'Roundcube versie is up-to-date';
+$labels['rc_newer'] = 'Roundcube versie is nieuwer dan die die van de bronserver.';
+$labels['nottested'] = 'Voorzichtigheid bij het gebruik van deze plugin is geboden! Het is niet bekend of de plugins goed functioneren met Roundcube v%s.';
+$labels['justunzip'] = 'Archief bestand uitpakken over de bestaande installatie.';
+$labels['guide'] = 'Lees meer...';
+$labels['thirdparty'] = 'Dit is geen plugin van MyRoundcube';
+$labels['thirdpartywarning'] = 'Dit betreft een plugin van een derde partij. Het is niet aan te raden deze vanaf onze bronserver te downloaden maar rechtstreeks vanuit de ontwikkelaar. Zo weet u zeker dat u de laatste versie heeft en heeft u tevens de beschikking over eventuele adviezen en bijsluiters van de maker.';
+$labels['develsite'] = 'Downloaden';
+$labels['notinstalled'] = 'niet geinstalleerd';
+$labels['notregistered'] = 'niet geregistreerd';
+$labels['roundcubeurl'] = 'Roundcube downloaden';
+$labels['languageupdate'] = 'Bijgewerkte versies van vertalingen zijn beschikbaar.';
+$labels['donotregister'] = 'Deze plugin wordt automatisch geladen en hoeft niet geregisteerd te worden.';
+$labels['register'] = 'Voeg deze plugin toe bij de Plugin Beheerder configuratie of in ./config/config.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</small>.';
+$labels['customer_account'] = 'Klant account';
+$labels['customer_id'] = 'Klant ID';
+$labels['invalid_customer_id'] = 'Ongeldig Klant ID';
+$labels['invalid_credits'] = 'Ongeldige credits';
+$labels['successfully_transferred'] = 'Credits zijn succesvol overgeschreven';
+$labels['merge'] = 'Credits samenvoegen';
+$labels['credits'] = 'Credits';
+$labels['creditsupdated'] = 'De hoogte van het aantal credits is aangepast sinds de laatste verversing van de pagina';
+$labels['buynow'] = 'Credits kopen';
+$labels['history'] = 'Account geschiedenis';
+$labels['details'] = 'Details ';
+$labels['receipt'] = 'Ontvangstbewijs';
+$labels['plugins'] = 'Plugins';
+$labels['clickhere'] = 'Klik hier';
+$labels['discardliabletopaycosts'] = 'Discard incurring costs downloads';
+$labels['sum'] = 'Som';
+$labels['show'] = 'Toon';
+$labels['hide'] = 'Verberg';
+$labels['view'] = 'bekijken';
+$labels['expired'] = 'verlopen';
+$labels['terms'] = 'Termijnen';
+$labels['pricelist'] = 'Download prijslijst';
+$labels['forthisdownload'] = 'voor deze download';
+$labels['remainingcredits'] = 'te behouden credits';
+$labels['initialdownload'] = 'Initieer download';
+$labels['keyfeatureaddition'] = 'Nieuwe sleutel optie';
+$labels['codeimprovements'] = 'Verbeteringen in de code';
+$labels['servicenotavailable'] = 'Dienst is momenteel niet beschikbaar. Probeer het later nog eens!';
+$labels['getnew'] = 'Genereer een nieuw Klant ID';
+$labels['getnew_hint'] = 'Wij raden het aan om uw klant ID frequent te verversen. Als u een vreemde actie in uw account details aantreft dient u uw Klant ID onmiddellijk te verversen.';
+$labels['transfer'] = 'Credits overschrijven';
+$labels['noplugindescription'] = 'Geen omschrijving van de plugin aanwezig.';
+$labels['markbuttons_pluginname'] = 'Selecteer bericht knoppen.';
+$labels['markbuttons_plugindescription'] = 'Voegt onder de berichtenlijst controle iconen toe om snel berichten te selecteren.';
+$labels['automatic_addressbook_pluginname'] = 'Automatische adressenboek';
+$labels['automatic_addressbook_plugindescription'] = 'Verzameld email adressen van alle ontvangers in een apart adressenboek.';
+$labels['keyboard_shortcuts_pluginname'] = 'Toetsenbord snelkoppeling';
+$labels['keyboard_shortcuts_plugindescription'] = 'Commando toevoegen op basis van toetsenbord snelkoppelingen.';
+$labels['message_highlight_pluginname'] = 'Berichten markeren ';
+$labels['message_highlight_plugindescription'] = 'Berichten markeren op basis van de aangemaakte selectie.';
+$labels['fixTHEAD_pluginname'] = 'Herstel de header van de berichten lijst';
+$labels['fixTHEAD_plugindescription'] = 'Herstel de header van de berichten lijst.';
+$labels['compose_addressbook_pluginname'] = 'Adressenboek in schrijfvenster';
+$labels['compose_addressbook_plugindescription'] = 'Geeft u de mogelijkheid om het adressenboek in het schrijfvenster weer te geven om zo eenvoudig naar het adres van de ontvanger te zoeken.';
+$labels['google_contacts_pluginname'] = 'Google contactpersonen';
+$labels['google_contacts_plugindescription'] = 'Benader u Google Contacten';
+$labels['contextmenu_pluginname'] = 'Keuze menu';
+$labels['contextmenu_plugindescription'] = 'Bied u een keuze menu door te klikken met de rechter muis knop.';
+$labels['newmail_notifier_pluginname'] = 'Nieuwe berichten melder';
+$labels['newmail_notifier_plugindescription'] = 'Geeft een melding als er nieuwe berichten zijn.';
+$labels['listcommands_pluginname'] = 'Beantwoord berichtenlijst';
+$labels['listcommands_plugindescription'] = 'Verschillende opties om te reageren op een bericht wat is verzonden via een mailing lijst.';
+$labels['copymessage_pluginname'] = 'Kopieer bericht(en)';
+$labels['copymessage_plugindescription'] = 'Kopieer bericht(en) naareen andere IMAP map.';
+$labels['forwardattachment_pluginname'] = 'Doorsturen als bijlage';
+$labels['forwardattachment_plugindescription'] = 'Meerdere berichten doorsturen als bijlage';
+$labels['vcard_attachments_pluginname'] = 'vCard bijlage';
+$labels['vcard_attachments_plugindescription'] = 'Laat u zien als een bericht voorzien is van een vcard en geeft u de mogelijkheid deze direct in te voegen tot het adressenboek.';
+$labels['importmessages_pluginname'] = 'Importeer berichten';
+$labels['importmessages_plugindescription'] = 'Importeer berichten van een zip- of emlbestand';
+$labels['zipdownload_pluginname'] = 'Exporteer berichten';
+$labels['zipdownload_plugindescription'] = 'Exporteer nerichten naar een zip bestand';
+$labels['markasjunk2_pluginname'] = 'Markeer berichten als spam';
+$labels['markasjunk2_plugindescription'] = 'Markeer berichten als spam of als geen spam';
+$labels['markasjunk_pluginname'] = 'Markeer berichten als spam';
+$labels['markasjunk_plugindescription'] = 'Markeer berichten als spam of als geen spam';
+$labels['google_ads_pluginname'] = 'Google advertenties';
+$labels['google_ads_plugindescription'] = 'Laat google advertenties zien';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Voeg Google Analytics toe';
+$labels['globaladdressbook_pluginname'] = 'Algemene adressenboek';
+$labels['globaladdressbook_plugindescription'] = 'Dit adressenboek kunt u niet aanpassen en wordt aangeboden door de beheerder.';
+$labels['blockspamsending_pluginname'] = 'Voorkom het versturen van SPAM';
+$labels['blockspamsending_plugindescription'] = 'Sta toe om slechts een specifiek aantal berichten met dezelfde indeling tijdens n sessie te verzenden.';
+$labels['global_config_pluginname'] = 'Configuratie beheerder';
+$labels['global_config_plugindescription'] = 'Dit is een plugin om configuraties te beheren. Het optimaliseert uw server door configuratie bestanden te centraliseren. Het is maakt beheerders taken tevens eenvoudiger door gebruik van slechts n configuratie bestand voor al uw plugins.';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Jqueryui javascript Bibliotheek';
+$labels['hide_blockquote_pluginname'] = 'Verberg blockquote';
+$labels['hide_blockquote_plugindescription'] = 'Verberg citaten wanneer het aantal regels groter is dan een specifiek aangegeven aantal regels.';
+$labels['crawler_pluginname'] = 'Zoekmachine';
+$labels['crawler_plugindescription'] = 'Nep pagina voor zoekmachines.';
+$labels['dblog_pluginname'] = 'Logboek opslaan in een database';
+$labels['dblog_plugindescription'] = 'Logboek opslaan in een database inplaats van opslaan in een bestand.';
+$labels['http_auth_pluginname'] = 'HTTP Authenticatie';
+$labels['http_auth_plugindescription'] = 'Een hulpvaardige plugin om HTTP authentificatie te ondersteunen. ';
+$labels['impersonate_pluginname'] = 'Imiteren';
+$labels['impersonate_plugindescription'] = 'Een administratieve tool om in te loggen tot een account met behulp van een master wachtwoord.';
+$labels['jscolor_pluginname'] = 'Kleuren selectieprogramma';
+$labels['jscolor_plugindescription'] = 'Een hulpvaardige plugin om een kleuren kiezer te tonen.';
+$labels['tinymce_pluginname'] = 'TinyMCE - HTML editor';
+$labels['tinymce_plugindescription'] = 'Deze plugin implanteert TinyMCE PHP Compressor (http://www.tinymce.com/wiki.php/Compressors:PHP). Tevens voegt het een mogelijkheid toe om TinyMCE instellingen te beheren zonder de Roundcube bron bestanden aan te hoeven passen.';
+$labels['embed_images_pluginname'] = 'Externe afbeeldingen insluiten';
+$labels['embed_images_plugindescription'] = 'Externe afbeeldingen insluiten in de bron van het bericht.';
+$labels['lang_sel_pluginname'] = 'Selecteer taal';
+$labels['lang_sel_plugindescription'] = 'Selecteer taal tijdens het aanmelden';
+$labels['newuser_pluginname'] = 'Nieuwe gebruiker';
+$labels['newuser_plugindescription'] = 'Informeert beheerders wanneer een nieuwe gebruiker zich via het webmail interface aanmeld en zend bij de eerste login een welkomstbericht aan de nieuwe gebruiker.';
+$labels['placeholder_pluginname'] = 'Placeholder Attributen';
+$labels['placeholder_plugindescription'] = 'Voeg een placeholder attribuut toe aan text en password invoer elementen.';
+$labels['qtip_pluginname'] = 'jQueryUI Tool Tips';
+$labels['qtip_plugindescription'] = 'Een hulpvaardige plugin om jQueryUI qtips te gebruiken.';
+$labels['sabredav_pluginname'] = 'SabreDAV';
+$labels['sabredav_plugindescription'] = 'Maakt SabreDAV accounts voor CalDAV kalender wanneer een nieuwe gebruiker in Roundcube worden aangemaakt. Past tevens wachtwoorden aan wanneer deze worden aangepast.';
+$labels['savepassword_pluginname'] = 'Wachtwoorden opslaan';
+$labels['savepassword_plugindescription'] = 'Dit is een plugin welke word vereist door bepaalde andere plugins.';
+$labels['database_attachments_pluginname'] = 'Database bijlage';
+$labels['database_attachments_plugindescription'] = 'Hulp plugin om bijlages in de database te beheren.';
+$labels['new_user_dialog_pluginname'] = 'Nieuwe gebruiker dialoog';
+$labels['new_user_dialog_plugindescription'] = 'Zorgt ervoor dat nieuwe gebruikers bij de eerste keer dat zij inloggen een popup scherm krijgen te zien waarbij de identiteit kan worden ingesteld. ';
+$labels['rcguard_pluginname'] = 'HerCAPTCHA';
+$labels['rcguard_plugindescription'] = 'Activeer CAPTCHA na een aantal mislukte aanmeld pogingen';
+$labels['domain_check_pluginname'] = 'Controleer domein';
+$labels['domain_check_plugindescription'] = 'Beperk het inloggen alleen voor gespecificeerde domeinen';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/pl_PL.inc b/plugin_manager/localization/pl_PL.inc
new file mode 100644
index 0000000..15161bc
--- /dev/null
+++ b/plugin_manager/localization/pl_PL.inc
@@ -0,0 +1,275 @@
+<?php
+/*
++-----------------------------------------------------------------------+
+| ./plugins/plugin_manager/localization/pl_PL.inc
+|
+| Language file of MyRoundcube Plugins Bundle
+| Copyright (C) 2010-2013, Roland 'rosali' Liebl
+|
++-----------------------------------------------------------------------+
+| Author: Tomasz - 08/25/2013 13:22:04
++-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Menedżer Wtyczek';
+$labels['plugindescription'] = 'Menedżer Wtyczek daje użytkownikom opcje aby włączać i wyłączać wtyczki ( z poziomu użytkownika) podczas gdy pomaga administratorom aktualizować, poprawiać błędu, tworzyć dokumentacje i zalecenia. Menadżer Wtyczek nie modyfikuje plików systemowych ani nie będzie instalować samodzielnie wtyczek.';
+$labels['plugin_manager_title'] = 'Zarządzanie wtyczkami';
+$labels['plugin_manager_center'] = 'Centrum zarządzania wtyczkami';
+$labels['updatepm'] = 'Dostępna aktualizacja Menedżera Wtyczek';
+$labels['updatepmrequired'] = 'Wymagana aktualizacja Menedżera Wtyczek';
+$labels['downloadnow'] = 'Pobierz teraz';
+$labels['calendaring'] = 'Kalendarzowe';
+$labels['misc'] = 'Różne';
+$labels['downloads'] = 'pobrania';
+$labels['issue'] = 'Problem';
+$labels['submitissue'] = 'Zgłaszanie problemu.<br /><br />Sprawdź dzienniki zdarzeń, a następnie dołącz istotne informacje w zgłoszeniu.<br /><br /><b>UWAGA</b>: Wymagane konto Google.';
+$labels['showall'] = 'Pokaż wszystkie wtyczki';
+$labels['hideuptodate'] = 'Pokaż tylko uaktualnienia';
+$labels['connectionerror'] = 'Zdalny serwer nie odpowiedział na próbę połączenia.';
+$labels['trylater'] = 'Proszę spróbować później...';
+$labels['translate'] = 'Lokalizuj tą wtyczkę';
+$labels['whatsthis'] = 'Co to jest?';
+$labels['restoredefaults'] = 'Przywróć domyślne';
+$labels['checkall'] = 'Zaznacz wszystko';
+$labels['uncheckall'] = 'Odznacz wszystko';
+$labels['toggle'] = 'Odwróć zaznaczenie';
+$labels['status'] = 'Status';
+$labels['globalplugins'] = 'Wtyczki globalne';
+$labels['performance'] = 'Wydajność';
+$labels['backend'] = 'Wtyczki serwerowe';
+$labels['messagesmanagement'] = 'Zarządzanie komunikatami';
+$labels['furtherconfig'] = 'Czy chciałbyś teraz skonfigurować tą wtyczkę?';
+$labels['uninstall'] = 'Jesteś bliski wyłączenia tej wtyczki. Czy chcesz, aby wszystkie zachowane ustawienia zostały trwale usunięte?';
+$labels['uninstallconfirm'] = 'Jesteś bliski wyłączenia tej wtyczki. OSTRZEŻENIE: Wybór <WYŁĄCZ> spowoduje wyłączenie tej wtyczki, a Twoje aktualne dane i ustawienia pozostaną zachowane w celu późniejszego wykorzystania. Wybór <USUŃ> spowoduje trwałe usunięcie wszystkich danych i konfiguracji wykorzystywanych przez tą wtyczkę. Miej na uwadze, że tej czynności nie można cofnąć.';
+$labels['areyousure'] = 'Nie będziesz mógł cofnąć tej czynności. Naprawdę jesteś pewien?';
+$labels['successfullydeleted'] = 'Ustawienia zostały usunięte.';
+$labels['successfullysaved'] = 'Zapis powiódł się.';
+$labels['errorsaving'] = 'Wystąpił błąd poczas zapisu.';
+$labels['yes'] = 'Tak';
+$labels['no'] = 'Nie';
+$labels['disable'] = 'Wyłącz';
+$labels['remove'] = 'Usuń';
+$labels['savewarning'] = 'Czy chcesz już zachować zmiany?';
+$labels['plugin_manager_update'] = 'Uaktualnij wtyczki';
+$labels['authors_comments'] = 'Komentarze autora (nie przetłumaczone)';
+$labels['requiredby'] = 'Wtyczka wymagana przez';
+$labels['requires'] = 'Wtyczka wymaga';
+$labels['recommended'] = 'Zalecane wtyczki';
+$labels['update_plugins'] = 'Uaktualnij wtyczki';
+$labels['ziparchive'] = 'Pobierz archiwum ZIP';
+$labels['demoaccount'] = 'Pobieranie niemożliwe (konto Demo)';
+$labels['serverversion'] = 'Używana wersja';
+$labels['mirrorversion'] = 'Wersja uaktualnienia';
+$labels['mirrorhost'] = 'Serwer z aktualnieniem';
+$labels['comments'] = 'Wymagania i informacje związane z uaktualnieniem';
+$labels['update_error'] = 'Niezgodność wersji';
+$labels['update_ok'] = 'Wykryto najnowszą wersję. Uaktualnienie nie jest potrzebne.';
+$labels['update_edit'] = 'Wtyczka musi zostać ponownie skonfigurowana lub wymaga zmiany ustawień bazy danych. Zapoznaj się z informacjami związanymi z uaktualnieniem.';
+$labels['servernewer'] = 'Wersja używanej wtyczki jest nowsza od wersji uaktualnionej.';
+$labels['orhigher'] = 'lub wyższa';
+$labels['rc_ok'] = 'Roundcube Core jest aktualny.';
+$labels['update_update'] = 'Wtyczka zdeaktualizowana. Proszę uaktualnić! Zapoznaj się z informacjami związanymi z uaktualnieniem.';
+$labels['noupdates'] = 'Nie wybrano uaktualnienia.';
+$labels['rc_update'] = 'Roundcube Core jest nie aktualny. Proszę uaktualnić!';
+$labels['rc_uptodate'] = 'Roundcube Core jest aktualny.';
+$labels['rc_newer'] = 'Używany Roundcube Core jest nowszy od uaktualnienia!';
+$labels['nottested'] = 'Zachowaj ostrożność wykorzystując wtyczki! Nie wiadomo czy te wtyczki działają z Roundcube v%s.';
+$labels['justunzip'] = 'Rozpakuj archiwum w miejscu istniejącej instalacji.';
+$labels['guide'] = 'Czytaj więcej...';
+$labels['thirdparty'] = 'To nie jest wtyczka MyRoundcube.';
+$labels['thirdpartywarning'] = 'Wtyczka autorstwa osoby trzeciej. Zalecamy nie pobierać wtyczki z naszego serwera.<br />Zamiast tego proponujemy jej pobranie z witryny projektanta wtyczki.<br />Dzięki temu uzyskasz pewność, że pobrałeś najnowszą wersję oraz będziesz mógł<br />zapoznać się z informacji i poradami przygotowanymi przez jej projektanta.';
+$labels['develsite'] = 'Pobierz';
+$labels['notinstalled'] = 'nie zainstalowana';
+$labels['notregistered'] = 'nie używana';
+$labels['roundcubeurl'] = 'Pobierz Roundcube';
+$labels['languageupdate'] = 'Dostępna aktualizacja lokalizacji.';
+$labels['localizationfilesonly'] = 'Uwaga: Plik zawiera tylko pliki z tłumaczeniem.';
+$labels['donotregister'] = 'Nie uaktywniaj tej wtyczki, gdyż jest ona ładowana automatycznie.';
+$labels['register'] = 'Uaktywnij tą wtyczkę w ./config/config.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</small>.';
+$labels['customer_account'] = 'Konto Klienta';
+$labels['customer_id'] = 'ID Klienta';
+$labels['invalid_customer_id'] = 'Nieprawidłowy ID klienta';
+$labels['invalid_credits'] = 'Nieprawidłowy stan środków';
+$labels['successfully_transferred'] = 'Środki przeniesione poprawnie';
+$labels['merge'] = 'Połącz środki';
+$labels['credits'] = 'Środki';
+$labels['creditsupdated'] = 'Stan środków został zmieniony podczas ostatniego odświeżenia strony';
+$labels['buynow'] = 'Kup środki teraz';
+$labels['history'] = 'Historia Konta';
+$labels['details'] = 'Szczegóły';
+$labels['receipt'] = 'Rachunek';
+$labels['plugins'] = 'Wtyczki';
+$labels['clickhere'] = 'Klinij tutaj';
+$labels['discardliabletopaycosts'] = 'Usuń ponoszone koszty pobrań';
+$labels['unchecknotinstalledplugins'] = 'Usuń nie zainstalowane pobrania wtyczek';
+$labels['sum'] = 'Suma';
+$labels['show'] = 'Pokaż';
+$labels['hide'] = 'Ukryj';
+$labels['view'] = 'widok';
+$labels['expired'] = 'przerminowane';
+$labels['terms'] = 'Warunki';
+$labels['pricelist'] = 'Koszty pobrań';
+$labels['forthisdownload'] = 'dla tego pobrania';
+$labels['remainingcredits'] = 'pozostałe środki';
+$labels['initialdownload'] = 'Początkowe pobranie';
+$labels['keyfeatureaddition'] = 'Nowa ważna funkcja';
+$labels['codeimprovements'] = 'Usprawnienie kodu';
+$labels['servicenotavailable'] = 'Usługa aktualnie niedostępna. Spróbuj ponownie później!';
+$labels['myrcerror'] = 'Usługi MyRoundcube są aktualnie niedostępne.';
+$labels['getnew'] = 'Wymagany ID Klienta';
+$labels['getnew_hint'] = 'Zalecamy aby odnawiać ID Klienta regularnie. Jeżeli zauważysz podejrzane zachowanie na koncie, natychmiast odnów swoje ID klienta.';
+$labels['transfer'] = 'Przekaż środki';
+$labels['submenuprefix'] = '» ';
+$labels['noplugindescription'] = 'Nie wykryto opisu wtyczki.';
+$labels['welcome_to_plugin_manager'] = 'Witamy w Menedżerze Wtyczek';
+$labels['about_to_create_account'] = 'Menedżer Wtyczek jest w trakcie tworzenia uprzywilejowanego konta administracyjnego.';
+$labels['create_account_proceed'] = 'Żeby wykonać tą czynność, potrzebne będzie potwierdzenie, że jesteś administratorem systemu.';
+$labels['please_create'] = 'Proszę, utwórz poniższy plik w katalogu głównym Twojej instalacji Roundcube:';
+$labels['thank_you'] = 'Dziękujemy!';
+$labels['done'] = 'Zrobione';
+$labels['manage_admins'] = 'Administratorzy';
+$labels['plugin_manager_admins'] = 'Administratorzy Menedżera Wtyczek';
+$labels['allow_plugins_configuration'] = 'Nadaj uprawnienia konfiguracji wtyczek';
+$labels['share_credits'] = 'Współdziel środki MyRC$';
+$labels['add'] = 'Dodaj';
+$labels['accountnotexists'] = 'Konto nie istnieje';
+$labels['sharedby'] = 'Konto klienckie współdzielone przez';
+$labels['switch'] = 'Przełącz';
+$labels['ownaccount'] = 'na konto własne';
+$labels['shareinvitation'] = 'na konto współdzielone';
+$labels['serverconfiguration'] = 'Konfiguracja serwera';
+$labels['pluginsconfiguration'] = 'Konfiguracja wtyczek';
+$labels['use_ssl'] = 'Ustanawiaj bezpieczne połączenia SSL z serwerami MyRoundcube';
+$labels['use_hmail'] = 'Używaj wtyczek zgodnych z hMailserver';
+$labels['show_myrc_messages'] = 'Wyświetlaj komunikaty powiadomień pochodzące z serwerów MyRoundcube';
+$labels['maintenance_mode'] = 'Tryb obsługi';
+$labels['serverwide'] = 'globalna konfiguracja serwera';
+$labels['file_based_config'] = 'Włącz konfigurację Menedżera Wtyczek przechowywaną w pliku';
+$labels['advanced_admins'] = 'zalecane tylko dla zaawansowanych administratorów';
+$labels['show_config'] = 'Pokaż aktualną konfigurację';
+$labels['systemadmin'] = 'Administrator Systemu';
+$labels['admin'] = 'Administrator';
+$labels['configuredby'] = 'skonfigurowane przez';
+$labels['enabled'] = 'Włączone (domyślnie)';
+$labels['protected'] = 'Zabezpieczone';
+$labels['skins'] = 'Skórki';
+$labels['loads_always'] = 'Obowiązkowe';
+$labels['loads_never'] = 'Wtyczka jest wyłączona';
+$labels['loads_by_user'] = 'Użytkownik może samodzielnie decydować o jej użyciu';
+$labels['loads_linked'] = 'Powiązane z';
+$labels['unbind'] = 'odwiąż';
+$labels['bind'] = 'powiąż';
+$labels['addplugin'] = 'Dodaj wtyczkę';
+$labels['removeplugin'] = 'Usuń wtyczkę';
+$labels['errorplugin'] = 'Błąd: Nie znaleziono wymaganych wtyczek';
+$labels['errorrcversion'] = 'Błąd: Wtyczka wymaga Roundcube';
+$labels['errorphpversion'] = 'Błąd: Wtyczka wymaga PHP';
+$labels['errorphpcurl'] = 'Błąd: Nie zainstalowano cURL';
+$labels['errorphpfinfo'] = 'Błąd: Nie zainstalowano finfo';
+$labels['errordb'] = 'Wymagane dostosowanie bazy danych. Włącz wtyczkę, aby rozpocząć tą operację.';
+$labels['errordb8'] = 'Wymagane dostosowanie bazy danych.';
+$labels['syntaxerror'] = 'Błąd składni PHP';
+$labels['notconfigured'] = 'Wtyczka nie skonfigurowana';
+$labels['editconfig'] = 'Edycja konfiguracji';
+$labels['instructions'] = 'Instrukcje';
+$labels['dbautomatically'] = 'Rozpocznij dostosowanie.';
+$labels['dbmanually'] = 'Proszę postępować zgodnie z instrukcją.';
+$labels['ornewer'] = 'lub nowsze';
+$labels['official_releases'] = 'Wspieramy wyłącznie oficjalne wydania Roundcube';
+$labels['localizationmissing'] = 'Nie wykryto plików językowych';
+$labels['documentation'] = 'Dokumentacja';
+$labels['select_plugin'] = 'Wybierz wtyczkę';
+$labels['legend'] = 'Opis';
+$labels['plugindisabledbydefault'] = 'Wtyczka jest domyślnie wyłączona - Użytkownik może samodzielnie decydować o jej użyciu';
+$labels['pluginenabledbydefault'] = 'Wtyczka jest domyślnie włączona - Użytkownik może samodzielnie decydować o jej użyciu';
+$labels['pluginmandatory'] = 'Obowiązkowe - wtyczka jest włączona, użytkownicy nie mogą włączać/wyłączać wtyczki';
+$labels['show_about_link'] = 'Pokazuj odsyłacz "O MyRoundcube"';
+$labels['show_support_link'] = 'Pokazuj odsyłacz "Wsparcie"';
+$labels['use_myroundcube_watermark'] = 'Używaj znaku wodnego "MyRoundcube"';
+$labels['remove_watermark'] = 'Nie wyświetlaj w ogóle znaku wodnego';
+$labels['database'] = 'Baza danych';
+$labels['credits_transferred'] = 'Środki przeniesiono';
+$labels['customer_id_changed'] = 'Zmieniono ID klienta';
+$labels['myrcd_bought'] = 'Zakupiono MyRC$ - dziękujemy!';
+$labels['PHPMyAdmin'] = 'PHPMyAdmin';
+$labels['markbuttons_pluginname'] = 'Przyciski Oznaczania Wiadomości';
+$labels['markbuttons_plugindescription'] = 'Dodaj ikony oznaczania wiadomości.';
+$labels['keyboard_shortcuts_pluginname'] = 'Skróty klawiszowe';
+$labels['keyboard_shortcuts_plugindescription'] = 'Wpisuj polecenia używając skrótów klawiszowych.';
+$labels['message_highlight_pluginname'] = 'Podświetlanie Wiadomości';
+$labels['message_highlight_plugindescription'] = 'Podświetlanie wiadomości pasujących do filtra.';
+$labels['google_contacts_pluginname'] = 'Kontakty Google';
+$labels['google_contacts_plugindescription'] = 'Dostęp do kontaktów Google';
+$labels['contextmenu_pluginname'] = 'Menu Kontekstowe';
+$labels['contextmenu_plugindescription'] = 'Pozwala na dostęp do menu uruchamianego prawym przyciskiem myszy.';
+$labels['newmail_notifier_pluginname'] = 'Informacja o nowej wiadomości';
+$labels['newmail_notifier_plugindescription'] = 'Powiadamiaj o nowych wiadomościach';
+$labels['listcommands_pluginname'] = 'Odpowiedzi dla List mailigowych';
+$labels['listcommands_plugindescription'] = 'Pozwala na różne odpowiedzi na wiadomości z list mailingowych';
+$labels['copymessage_pluginname'] = 'Kopuj Wiadomości';
+$labels['copymessage_plugindescription'] = 'Pozwala na kopiowanie wiadomości do inych folderów IMAP';
+$labels['vcard_attachments_pluginname'] = 'Załączniki vCard';
+$labels['vcard_attachments_plugindescription'] = 'Dodaje przycisk do automatycznego dodania wizytówki do książki adresowej';
+$labels['zipdownload_pluginname'] = 'Eksport Wiadomości';
+$labels['zipdownload_plugindescription'] = 'Eksport wiadomości jako .zip';
+$labels['markasjunk2_pluginname'] = 'Zaznacz Wiadomości jako SPAM';
+$labels['markasjunk2_plugindescription'] = 'Zaznaczanie wiadomości jako SPAM i nie SPAM';
+$labels['markasjunk_pluginname'] = 'Zaznacz Wiadomości jako SPAM';
+$labels['markasjunk_plugindescription'] = 'Zaznaczanie wiadomości jako SPAM i nie SPAM';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Dołącz google Analytics';
+$labels['globaladdressbook_pluginname'] = 'Globalna Książka adresowa';
+$labels['globaladdressbook_plugindescription'] = 'Globalna książka adresowa przygotowana przez Administratora.';
+$labels['blockspamsending_pluginname'] = 'Blokada Wysyłania SPAMu';
+$labels['blockspamsending_plugindescription'] = 'Pozwala na ograniczenie wysyłania zbyt dużych ilości wiadmości o takiej samej treści podczas jednej sesji.';
+$labels['global_config_pluginname'] = 'Manadżer Konfiguracji';
+$labels['global_config_plugindescription'] = 'To jest wtyczka menadżera konfiguracji. Optymalizuje twój serwer poprzez centralizacje konfiguracji wtyczek. Pozwala też na zarządzanie wtyczkami z jednego pliku konfiguracyjnego.';
+$labels['jqueryui_pluginname'] = 'Jquertyui';
+$labels['jqueryui_plugindescription'] = 'Biblioteka javascript Jqueryui';
+$labels['hide_blockquote_pluginname'] = 'Ukryj cytaty';
+$labels['hide_blockquote_plugindescription'] = 'Urywa cytaty jezeli liczba lini jest wieksza niż ustwiona ilość lini cytowanego tekstu.';
+$labels['crawler_pluginname'] = 'Roboty';
+$labels['crawler_plugindescription'] = 'Strona dla robotów i web crawlerów.';
+$labels['archive_pluginname'] = 'Archiwum';
+$labels['autologon_pluginname'] = 'Auto-logowanie';
+$labels['autologon_plugindescription'] = 'Zaloguj automatycznie';
+$labels['dblog_pluginname'] = 'Loguj do bazy';
+$labels['dblog_plugindescription'] = 'Logowanie zdarzeń do bazy danych zamiast do pliku.';
+$labels['gibberish_pluginname'] = 'Szyfrowanie Gibberish';
+$labels['http_request_pluginname'] = 'Żądanie HTTP';
+$labels['http_auth_pluginname'] = 'HTTP Autentykacja';
+$labels['http_auth_plugindescription'] = 'Wtyczka wspierająca autentykacje HTTP';
+$labels['http_authentication_pluginname'] = 'Autentukacja HTTP (default)';
+$labels['jscolor_pluginname'] = 'Wybór Kolorów';
+$labels['jscolor_plugindescription'] = 'Wtyczka pozawalająca wybrać kolory';
+$labels['tinymce_pluginname'] = 'TinyMCE - Edytor HTML';
+$labels['tinymce_plugindescription'] = 'Wtyczka implementująca edytor TinyMCE';
+$labels['lang_sel_pluginname'] = 'Wybierz język';
+$labels['lang_sel_plugindescription'] = 'Wybierz język na stronie logowania.';
+$labels['newuser_pluginname'] = 'Nowy użytkownik';
+$labels['newuser_plugindescription'] = 'Poinformuj administratora o rejestracji nowego uzytkonika poprzez interfejs webmail oraz wyślij wiadomość powitalną przy pierwszym logowaniu.';
+$labels['placeholder_pluginname'] = 'Atrybuty pól';
+$labels['placeholder_plugindescription'] = 'Dodaje atrybuty do pól tekstu i hasla';
+$labels['qtip_pluginname'] = 'jQueryUI Dymki Wskazówek';
+$labels['qtip_plugindescription'] = 'Wtyczka dodająca dymki ze wskazówkami';
+$labels['sabredav_pluginname'] = 'SabreDAV';
+$labels['sabredav_plugindescription'] = 'Tworzy konta SabreDAV dla kalendarza CalDAV kiedy nowy użytkownik zostaje dodany do Rouncube i tworzy połączenia pomiędzy Roundcubre-SabreDAV.';
+$labels['savepassword_pluginname'] = 'Zapisz Hasła';
+$labels['savepassword_plugindescription'] = 'Wtyczka pomocnicza dla innych wtyczek';
+$labels['database_attachments_pluginname'] = 'Załączniki bazodanowe';
+$labels['database_attachments_plugindescription'] = 'Wtyczka pomocnicza do zarządzaniem załączników w bazie';
+$labels['help_pluginname'] = 'Pomoc';
+$labels['new_user_dialog_pluginname'] = 'Informacja dla nowych użytkowników';
+$labels['new_user_dialog_plugindescription'] = 'Pokazuje ustawienia tożsamości dla nowych użytkowników. Wtyczka sprawdza czy nowy uzytkownik ma stworzoną poprawnie tożsamość i pomaga zakonczenie procesu rejestracji tożsamości.';
+$labels['rcguard_pluginname'] = 'ReCAPTCHA';
+$labels['rcguard_plugindescription'] = 'Zmusza wprowadzenie CAPTCHA po kilku nieudanych próbach logowania.';
+$labels['domain_check_pluginname'] = 'Sprawdzenie Domeny';
+$labels['domain_check_plugindescription'] = 'Ograniczenie logowania tylko dla niektórych domen';
+$labels['tasklist_pluginname'] = 'Lista zadań';
+$labels['userinfo_pluginname'] = 'Informacja o użytkowniku';
+$labels['filters_pluginname'] = 'Filtry';
+$labels['password_pluginname'] = 'Zmiana hasła';
+$labels['example_addressbook_pluginname'] = 'Przykładowa książka adresowa';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/pt_BR.inc b/plugin_manager/localization/pt_BR.inc
new file mode 100644
index 0000000..0b1e781
--- /dev/null
+++ b/plugin_manager/localization/pt_BR.inc
@@ -0,0 +1,182 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/pt_BR.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: filhocf - 01/03/2013 18:46:35
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Plugin Manager';
+$labels['plugindescription'] = 'O Plugin Manager dá ao usuário as opções de ativar e/ou desativar plugins (ao nível de conta de usuário) enquanto ele ajuda os administradores a manter atualizado com os plugins, correções de erros, descarga centralizada, documentação e recomendações. O Plugin Manager não faz modificações no seu sistema de arquivo ou não instalará plugins automaticamente.';
+$labels['plugin_manager_title'] = 'Gerenciar Plugins';
+$labels['plugin_manager_center'] = 'Centro de Gerenciamento de Plugin';
+$labels['calendaring'] = 'Calendário';
+$labels['misc'] = 'Diversos';
+$labels['downloads'] = 'Descargas';
+$labels['issue'] = 'problema';
+$labels['submitissue'] = 'Reporte um problema.Por favor, verifique seus registros e forneça informações relevantes no bilhete...';
+$labels['showall'] = 'Mostrar todos os Plugins';
+$labels['hideuptodate'] = 'Mostrar atualizações somente';
+$labels['connectionerror'] = 'O servidor remoto não respondeu a solicitação de conexão.';
+$labels['trylater'] = 'Por favor, tente mais tarde...';
+$labels['translate'] = 'Traduzir este plugin';
+$labels['restoredefaults'] = 'Restaurar padrões';
+$labels['checkall'] = 'Marcar todos';
+$labels['uncheckall'] = 'Desmarcar todos';
+$labels['toggle'] = 'Alternar seleção';
+$labels['status'] = 'Status';
+$labels['globalplugins'] = 'Plugins globais';
+$labels['backend'] = 'Plugins do servidor';
+$labels['messagesmanagement'] = 'Gerenciamento de mensagens';
+$labels['furtherconfig'] = 'Você deseja configurar este plugin agora?';
+$labels['uninstall'] = 'Você está prestes a desativar este plugin. Você deseja remover todas as configurações salvas permanentemente?';
+$labels['uninstallconfirm'] = 'Você está prestes a desativar este plugin. ATENÇÃO: Selecione »DESATIVAR« para desativar este plugin enquanto mantém seus dados atuais e configurações armazenadas no seu servidor se você planeja usar eles novamente. Selecione »REMOVER« se você deseja que todos seus dados e configurações gerenciadas por este plugin sejam removidos permanentemente de seus bancos de dados. Note que esta ação não pode ser desfeita.';
+$labels['areyousure'] = 'Você não pode desfazer esta ação. Você está certo disto?';
+$labels['successfullydeleted'] = 'Configuracões foram removidos com sucesso.';
+$labels['successfullysaved'] = 'Salvo com sucesso.';
+$labels['errorsaving'] = 'Ocorreu um erro ao salvar.';
+$labels['yes'] = 'Sim';
+$labels['no'] = 'Não';
+$labels['disable'] = 'Desativar';
+$labels['remove'] = 'Remover';
+$labels['savewarning'] = 'Você ainda deseja salvar suas mudanças?';
+$labels['plugin_manager_update'] = 'Atualizar Plugins';
+$labels['authors_comments'] = 'Comentários do Autor (não traduzido)';
+$labels['requiredby'] = 'O Plugin é requerido por';
+$labels['requires'] = 'O Plugin requer';
+$labels['recommended'] = 'Plugins recomendados';
+$labels['update_plugins'] = 'Atualizar Plugins';
+$labels['ziparchive'] = 'Baixar arquivo ZIP';
+$labels['demoaccount'] = 'Desculpe, sem descargas (Conta de demonstração)';
+$labels['serverversion'] = 'Versão do servidor';
+$labels['mirrorversion'] = 'Versão do espelho';
+$labels['mirrorhost'] = 'Servidor espelho';
+$labels['comments'] = 'Requerimentos e Notas de Atualização';
+$labels['update_error'] = 'Incompatibilidade de versão';
+$labels['update_ok'] = 'A versão mais recente foi detectada. Não é necessária atualização.';
+$labels['update_edit'] = 'O Plugin teve que ser reconfigurado ou requer ajustes de banco de dados. Por favor, considere as Notas de Atualização.';
+$labels['servernewer'] = 'Plugins registrados são mais novos que a versão do espelho.';
+$labels['orhigher'] = 'ou maior';
+$labels['rc_ok'] = 'O número do RoundCube está atualizado.';
+$labels['update_update'] = 'O Plugin está desatualizado. Por favor, atualize! Considere as Notas de Atualização.';
+$labels['noupdates'] = 'Nenhuma Atualização selecionada.';
+$labels['rc_update'] = 'O núcleo do Roundcube está desatualizado. Por favor, atualize!';
+$labels['rc_uptodate'] = 'O número do RoundCube está atualizado.';
+$labels['rc_newer'] = 'O núcleo do Roundcube é mais novo que a versão do espelho!';
+$labels['nottested'] = 'Por favor, use os Plugins com cuidado! Nós não sabemos se os Plugins trabalham com o Roundcube x%s.';
+$labels['justunzip'] = 'Somente descompacte o arquivo sobre sua instalação existe.';
+$labels['guide'] = 'Leia mais...';
+$labels['thirdparty'] = 'Este não é um Plugin do MyRoundcube.';
+$labels['thirdpartywarning'] = 'Este é um plugin de terceiros. Nós recomendamosnão baixar o plugin deste Servidor Espelho.';
+$labels['develsite'] = 'Baixar';
+$labels['notinstalled'] = 'Não instalado';
+$labels['notregistered'] = 'não registrado';
+$labels['roundcubeurl'] = 'Baixe o Roundcube';
+$labels['languageupdate'] = 'Uma atualização de idioma está disponível.';
+$labels['donotregister'] = 'Não registre este plugin. Ele é lido automaticamente.';
+$labels['register'] = 'Registre este plugin em ./config/config.inc.php [$config[\'plugins\'] = array("foo", "bar");';
+$labels['customer_account'] = 'Conta de Cliente';
+$labels['customer_id'] = 'ID do Cliente';
+$labels['invalid_customer_id'] = 'ID do Cliente Inválido';
+$labels['invalid_credits'] = 'Créditos inválidos';
+$labels['successfully_transferred'] = 'Créditos transferidos com sucesso';
+$labels['merge'] = 'Fundir Créditos';
+$labels['credits'] = 'Créditos';
+$labels['creditsupdated'] = 'Créditos foram modificados desde a última atualização da página';
+$labels['buynow'] = 'Comprar créditos agora';
+$labels['history'] = 'Histórico da Conta';
+$labels['details'] = 'Detalhes';
+$labels['receipt'] = 'Recibo';
+$labels['plugins'] = 'Plugins';
+$labels['clickhere'] = 'Clique aqui';
+$labels['discardliabletopaycosts'] = 'Descartar descargas que incorram em custos';
+$labels['sum'] = 'Soma';
+$labels['show'] = 'Mostrar';
+$labels['hide'] = 'Ocultar';
+$labels['view'] = 'exibir';
+$labels['expired'] = 'expirado';
+$labels['terms'] = 'Termos';
+$labels['pricelist'] = 'Preços de descarga';
+$labels['forthisdownload'] = 'para esta descarga';
+$labels['remainingcredits'] = 'créditos remanescentes';
+$labels['initialdownload'] = 'Descarga inicial';
+$labels['keyfeatureaddition'] = 'Nova funcionalidade chave';
+$labels['codeimprovements'] = 'Melhorias de código';
+$labels['servicenotavailable'] = 'O serviço está atualmente indisponível. Por favor, tente mais tarde!';
+$labels['getnew'] = 'Querer um novo ID de Cliente';
+$labels['getnew_hint'] = 'Nós recomendamos renovar seu ID de Cliente frequentemente. Se você notar qualquer atividade suspeita nos seus detalhes da conta, renove seu ID de cliente imediatamente.';
+$labels['transfer'] = 'Transferir créditos';
+$labels['noplugindescription'] = 'Não foi detectado descrição do plugin.';
+$labels['markbuttons_pluginname'] = 'Botões de marcação de mensagem';
+$labels['markbuttons_plugindescription'] = 'Adicionar ícones de controle no separador de lista de mensagens para marcação rápida de mensagens.';
+$labels['automatic_addressbook_pluginname'] = 'Catálogo de endereços automático';
+$labels['automatic_addressbook_plugindescription'] = 'Coletar endereços de e-mail dos recipientes em um catálogo de endereços separado.';
+$labels['keyboard_shortcuts_pluginname'] = 'Atalhos de teclado';
+$labels['keyboard_shortcuts_plugindescription'] = 'Digite os comandos usando atalhos de teclado.';
+$labels['message_highlight_pluginname'] = 'Mensagens destacadas';
+$labels['message_highlight_plugindescription'] = 'Mensagens destacadas que combinam com suas opções de filtro.';
+$labels['fixTHEAD_pluginname'] = 'Corrigir o cabeçalho da lista de mensagens';
+$labels['fixTHEAD_plugindescription'] = 'Corrigir o cabeçalho da lista de mensagens.';
+$labels['compose_addressbook_pluginname'] = 'Pegar endereços';
+$labels['compose_addressbook_plugindescription'] = 'Pegar os endereços ao compor uma mensagem.';
+$labels['google_contacts_pluginname'] = 'Contatos do Google';
+$labels['google_contacts_plugindescription'] = 'Acessar seus contatos do Google.';
+$labels['contextmenu_pluginname'] = 'Menu de contexto';
+$labels['contextmenu_plugindescription'] = 'Ativar a funcionalidade de menu de contexto com o clique direito.';
+$labels['newmail_notifier_pluginname'] = 'Novo Notificador de E-mail';
+$labels['newmail_notifier_plugindescription'] = 'Notificar sobre novas mensagens.';
+$labels['listcommands_pluginname'] = 'Responder para lista de discussão';
+$labels['listcommands_plugindescription'] = 'Varias opções de resposta para mensagens enviadas das listas de discussão.';
+$labels['copymessage_pluginname'] = 'Copiar mensagem(ns)';
+$labels['copymessage_plugindescription'] = 'Copiar mensagem(ns) para outra pasta IMAP.';
+$labels['forwardattachment_pluginname'] = 'Encaminhar como Anexo';
+$labels['forwardattachment_plugindescription'] = 'Encaminhar múltiplas mensagens como anexos.';
+$labels['vcard_attachments_pluginname'] = 'Anexos vCard';
+$labels['vcard_attachments_plugindescription'] = 'Adicionar uma caixa para mensagens que tenham um anexo vcard para importar o contato diretamente para o catálogo de endereço.';
+$labels['importmessages_pluginname'] = 'Importar mensagens';
+$labels['importmessages_plugindescription'] = 'Importar mensagens de uma fonte zip ou eml.';
+$labels['zipdownload_pluginname'] = 'Exportar mensagens';
+$labels['zipdownload_plugindescription'] = 'Exportar mensagens como um arquivo zip.';
+$labels['markasjunk2_pluginname'] = 'Marcar mensagens como spam';
+$labels['markasjunk2_plugindescription'] = 'Marcar mensagens como spam ou não spam.';
+$labels['markasjunk_pluginname'] = 'Marcar mensagens como spam';
+$labels['markasjunk_pluginname'] = 'Google Ads';
+$labels['google_ads_plugindescription'] = 'Mostrar anúncios do Google.';
+$labels['google_analytics_pluginname'] = 'Google Analytics';
+$labels['google_analytics_plugindescription'] = 'Incluir Google Analytics.';
+$labels['globaladdressbook_pluginname'] = 'Catálogo de endereços global';
+$labels['globaladdressbook_plugindescription'] = 'Este é um catálogo de endereço somente leitura provido pelo seu administrador.';
+$labels['blockspamsending_pluginname'] = 'Previne envio de spam';
+$labels['blockspamsending_plugindescription'] = 'Permite enviar somente um grupo de mensagens específicas com mesmo corpo durante uma sessão.';
+$labels['global_config_pluginname'] = 'Gerente de Configuração';
+$labels['global_config_plugindescription'] = 'Esta é um plugin de gerenciamento de configuração. Ele otimiza seu servidor pela centralização dos arquivos de configurações dos plugins. Ele também faz as tarefas administrativas mais fáceis pela ativação do uso de um arquivo simples de configuração para todos os plugins.';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Biblioteca javascript Jqueryui';
+$labels['hide_blockquote_pluginname'] = 'Ocultar bloco de citação (blockquote)';
+$labels['hide_blockquote_plugindescription'] = 'Oculta a citação quando o contador de linhas é maior que um contador de linhas especificado.';
+$labels['crawler_pluginname'] = 'Rastreador (Crawler)';
+$labels['crawler_plugindescription'] = 'Página de conteúdo falto para rastreadores (crawler).';
+$labels['dblog_pluginname'] = 'Registrar no banco de dados';
+$labels['dblog_plugindescription'] = 'Registrar no banco de dados invés de em arquivo.';
+$labels['http_auth_pluginname'] = 'Autenticação HTTP';
+$labels['http_auth_plugindescription'] = 'Um plugin auxiliar para suporte à Autenticação HTTP.';
+$labels['impersonate_pluginname'] = 'Impersonate';
+$labels['impersonate_plugindescription'] = 'Uma ferramenta administrativa para conectar nas contas através de uma senha mestra.';
+$labels['jscolor_pluginname'] = 'Seletor de Cores';
+$labels['jscolor_plugindescription'] = 'Um plugin auxiliar que mostra um seletor de cores.';
+$labels['tinymce_pluginname'] = 'TinyMCE - Editor HTML';
+$labels['tinymce_plugindescription'] = 'Substitui o TinyMCE padrão pelo TinyMCE jQuery (incluindo o Compressor PHP TinyMCE http://www.tinymce.com/wiki.php/Compressors:PHP).';
+$labels['embed_images_pluginname'] = 'Imagens externas embarcadas';
+$labels['embed_images_plugindescription'] = 'Imagens externas embarcadas na mensagem fonte.';
+$labels['lang_sel_pluginname'] = 'Selecione o idioma';
+$labels['lang_sel_plugindescription'] = 'Selecione o idioma na página de acesso.';
+$labels['newuser_pluginname'] = 'Novo Usuário';
+$labels['newuser_plugindescription'] = 'Informe os administradores quando um novo usuário é registrado via interface webmail e envie uma mensagem de boas vindas para o novo usuário no seu primeiro acesso.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/pt_PT.inc b/plugin_manager/localization/pt_PT.inc
new file mode 100644
index 0000000..44444c2
--- /dev/null
+++ b/plugin_manager/localization/pt_PT.inc
@@ -0,0 +1,116 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/pt_PT.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: RuiSMoura - 01/25/2013 17:57:49
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Gestor de Plugins';
+$labels['plugin_manager_title'] = 'Gerir Plugins';
+$labels['plugin_manager_center'] = 'Gestor de Plugins';
+$labels['calendaring'] = 'Elementos de Calendário';
+$labels['misc'] = 'Vários';
+$labels['downloads'] = 'Transferências';
+$labels['issue'] = 'problema';
+$labels['showall'] = 'Mostrar todos os Plugins';
+$labels['hideuptodate'] = 'Mostrar apenas actualizações';
+$labels['connectionerror'] = 'O servidor não respondeu à tentativa de ligação.';
+$labels['trylater'] = 'Por favor tente mais tarde...';
+$labels['translate'] = 'Traduzir Plugin';
+$labels['restoredefaults'] = 'Restaurar Definições';
+$labels['checkall'] = 'Selecionar Todos';
+$labels['uncheckall'] = 'Desmarcar Todos';
+$labels['toggle'] = 'Inverter Seleção';
+$labels['status'] = 'Estado';
+$labels['globalplugins'] = 'Plugins Globais';
+$labels['backend'] = 'Plugins do Servidor';
+$labels['messagesmanagement'] = 'Gestão de Mensagens';
+$labels['furtherconfig'] = 'Quer configurar este plugin agora?';
+$labels['uninstall'] = 'Este plugin será desativado. Quer remover definitivamente todas as definições gravadas?';
+$labels['areyousure'] = 'Não pode desfazer esta ação. Tem a certeza?';
+$labels['successfullydeleted'] = 'As definições foram removidas com sucesso.';
+$labels['successfullysaved'] = 'Gravado com sucesso.';
+$labels['errorsaving'] = 'Ocorreu um erro ao gravar.';
+$labels['yes'] = 'Sim';
+$labels['no'] = 'Não';
+$labels['disable'] = 'Desativar';
+$labels['remove'] = 'Remover';
+$labels['savewarning'] = 'Pertende gravar as suas alterações já?';
+$labels['plugin_manager_update'] = 'Atualizar Plugins';
+$labels['authors_comments'] = 'Comentários do Autor (não traduzido)';
+$labels['requiredby'] = 'O plugin é requerido pelo';
+$labels['requires'] = 'O plugin requer';
+$labels['recommended'] = 'Plugins recomendados';
+$labels['update_plugins'] = 'Transferir Plugins';
+$labels['ziparchive'] = 'Transferir Arquivo-Zip ';
+$labels['demoaccount'] = 'Desculpe, download desactivado (Conta de Demonstração)';
+$labels['serverversion'] = 'Versão no Servidor';
+$labels['mirrorversion'] = 'Versão no Servidor-Espelho';
+$labels['mirrorhost'] = 'Servidor-Espelho';
+$labels['comments'] = 'Requisitos e Notas de Atualização';
+$labels['update_error'] = 'Versão não coincide';
+$labels['update_ok'] = 'Versão mais actual detetada, Não é necessária atualização';
+$labels['update_edit'] = 'O Plugin precisa de ser reconfigurado ou requer ajustes na base de dados. Por favor tenha em considerção as Notas de Actualização ';
+$labels['servernewer'] = 'O Plugin é mais recente do que o da versão do servidor-espelho.';
+$labels['orhigher'] = 'ou superior';
+$labels['rc_ok'] = 'O Roundcube está atualizado.';
+$labels['update_update'] = 'Plugin desatualizado. Por favor atualize! Tenha em Consideração as Notas de Atualização.';
+$labels['noupdates'] = 'Nenhuma atualização detetada.';
+$labels['rc_update'] = 'O Roundcube está desatualizado. Por favor atualize!';
+$labels['rc_uptodate'] = 'O Roundcube está atualizado.';
+$labels['nottested'] = 'Por favor use os Plugins com precaução! Não sabemos se os Plugins alojados funcionam com o Roundcube v%s.';
+$labels['justunzip'] = 'Apenas descompacte o arquivo para a instalação existente.';
+$labels['guide'] = 'Leia mais...';
+$labels['thirdparty'] = 'Isto não é um Plugin do MyRoundcube';
+$labels['thirdpartywarning'] = 'Este é um plugin de terceiros. Recomendamos que não faça o download do nosso servidor. Em vez disso faça o download diretamente do site do autor para assim obter a última versão assim como todas as notas e conselhos do seu autor.';
+$labels['develsite'] = 'Transferir';
+$labels['notinstalled'] = 'não instalado';
+$labels['notregistered'] = 'não registado';
+$labels['roundcubeurl'] = 'Transferir o Roundcube ';
+$labels['languageupdate'] = 'Está disponível uma atualização de linguagem.';
+$labels['noplugindescription'] = 'Nenhuma descrição encontrada para este plugin.';
+$labels['markbuttons_pluginname'] = 'Botões para Sinalização de Mensagens';
+$labels['markbuttons_plugindescription'] = 'Acrescenta icons sob a lista de mensagens para rapidamente sinalizar mensagens.';
+$labels['automatic_addressbook_pluginname'] = 'Livro de endereços Automático';
+$labels['automatic_addressbook_plugindescription'] = 'Captar endereços de email não existentes para um livro de endereços em separado.';
+$labels['keyboard_shortcuts_pluginname'] = 'Atalhos de teclado';
+$labels['message_highlight_pluginname'] = 'Destacar Mensagens';
+$labels['message_highlight_plugindescription'] = 'Destacar mensagens de acordo com as opções de filtro.';
+$labels['compose_addressbook_pluginname'] = 'Livro de Endereços na Janela de Composição.';
+$labels['google_contacts_pluginname'] = 'Contactos Google';
+$labels['google_contacts_plugindescription'] = 'Tenha acesso aos seus contactos do Google.';
+$labels['contextmenu_pluginname'] = 'Menu de Contexto';
+$labels['contextmenu_plugindescription'] = 'Activar a funcionalidade menu de contexto.';
+$labels['newmail_notifier_pluginname'] = 'Novo Notificador de Email';
+$labels['newmail_notifier_plugindescription'] = 'Receba um alterta de nova mensagem.';
+$labels['copymessage_pluginname'] = 'Copiar Mensagem(s)';
+$labels['copymessage_plugindescription'] = 'Copia mensagem(s) para outra pasta IMAP.';
+$labels['forwardattachment_pluginname'] = 'Reencaminhar como anexo';
+$labels['forwardattachment_plugindescription'] = 'Reencaminha várias mensagens como anexos.';
+$labels['vcard_attachments_pluginname'] = 'Anexos vCard';
+$labels['vcard_attachments_plugindescription'] = 'Adiciona uma caixa às mensagens que tenham em anexo um vcard, para importar diretamente para o livro de endereços.';
+$labels['importmessages_pluginname'] = 'Importar Mensagens';
+$labels['importmessages_plugindescription'] = 'Importa mensagens de uma fonte zip ou eml.';
+$labels['zipdownload_pluginname'] = 'Exportar Mensagens';
+$labels['zipdownload_plugindescription'] = 'Exportar mensagens num ficheiro zip.';
+$labels['markasjunk2_pluginname'] = 'Marcar Mensagem como Spam';
+$labels['markasjunk2_plugindescription'] = 'Marca as Mensagens como sendo spam ou não.';
+$labels['markasjunk_pluginname'] = 'Marcar Mensagem como Spam';
+$labels['markasjunk_plugindescription'] = 'Marca as Mensagens como sendo spam ou não.';
+$labels['google_ads_pluginname'] = 'Anúncios Google';
+$labels['google_ads_plugindescription'] = 'Mostra Publicidade do Google.';
+$labels['globaladdressbook_pluginname'] = 'Livro de Endereços Global';
+$labels['blockspamsending_pluginname'] = 'Previne Enviar Spam';
+$labels['impersonate_pluginname'] = 'Personificar';
+$labels['impersonate_plugindescription'] = 'Uma ferramenta de administração que permite iniciar sessão nas contas de email dos utilizadores com uma palvra-passe mestre.';
+$labels['jscolor_pluginname'] = 'Palete de cores';
+$labels['jscolor_plugindescription'] = 'Um plugin de ajuda que mostra uma palete de cores.';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/revision.inc.php b/plugin_manager/localization/revision.inc.php
new file mode 100644
index 0000000..db75626
--- /dev/null
+++ b/plugin_manager/localization/revision.inc.php
@@ -0,0 +1,11 @@
+<?php
+
+$ps_localization_update = serialize(
+ array(
+ 'translator' => 'Olivier Zolli',
+ 'language ' => 'fr_FR',
+ 'date' => '01/20/2015 18:23:27'
+ )
+);
+
+?> \ No newline at end of file
diff --git a/plugin_manager/localization/ru_RU.inc b/plugin_manager/localization/ru_RU.inc
new file mode 100644
index 0000000..4869c7d
--- /dev/null
+++ b/plugin_manager/localization/ru_RU.inc
@@ -0,0 +1,205 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/plugin_manager/localization/ru_RU.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Pavel - 02/11/2013 17:48:12
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Менеджер расширений';
+$labels['plugindescription'] = 'Менеджер расширений дает возможность пользователям включать или отключать плагины на уровне пользователя. Менеджер расширений не изменяет вашу файловую систему, он предназначен только для автоматической установки расширений. Админимстраторам систем Менеджер расширений позволяет быть в курсе последних обновлений системы и самих расширений, документации, рекомендаций. Включает в себя централизованную загрузку';
+$labels['plugin_manager_title'] = 'Управление расширениями';
+$labels['plugin_manager_center'] = 'Центр управления расширениями';
+$labels['updatepm'] = 'Доступны обновления Менеджера Расширений';
+$labels['updatepmrequired'] = 'Необходимо обновление Менеджера Расширений';
+$labels['downloadnow'] = 'Загрузить сейчас';
+$labels['calendaring'] = 'Календарь';
+$labels['misc'] = 'Остальное';
+$labels['downloads'] = 'Загрузки';
+$labels['issue'] = 'Версии';
+$labels['submitissue'] = 'Сообщить о проблеме. <br /><br />Пожалуйста, проверьте журналы событий и предоставлять соответствующую информацию в поддрежку.<br /><br /><b>NOTE</b>: Требуется аккаунт Google.';
+$labels['showall'] = 'Показать все расширения';
+$labels['hideuptodate'] = 'Показать только обновления';
+$labels['connectionerror'] = 'Удаленный Сервер не реагирует на попытку соединения.';
+$labels['trylater'] = 'Пожалуйста, попробуйте позже...';
+$labels['translate'] = 'Перевести это расширение';
+$labels['restoredefaults'] = 'Восстановить значения по умолчанию';
+$labels['checkall'] = 'Выделить все';
+$labels['uncheckall'] = 'Снять выбор';
+$labels['toggle'] = 'Изменить выбор';
+$labels['status'] = 'Статус';
+$labels['globalplugins'] = 'Глобальные расширения';
+$labels['backend'] = 'Серверные расширения';
+$labels['messagesmanagement'] = 'Управление сообщениями';
+$labels['furtherconfig'] = 'Хотели бы вы, чтобы настроить это расширение сейчас?';
+$labels['uninstall'] = 'Вы собираетесь отключить этот плагин. Вы хотите, удалить все сохраненные настройки навсегда?';
+$labels['uninstallconfirm'] = 'Вы собираетесь отключить этот плагин. Внимание: Выбрав пункт "ОТКЛЮЧИТЬ" это расширение сохранит ваши данные и настройки на сервере (если вы планируете использовать его позже выберете "ОТКЛЮЧТЬ".). Выберите пункт "УДАЛИТЬ", если вы хотите, чтобы все данные и настройки, управляемых этим расширением, были удаленны. Обратите внимание, это действие НЕ может быть ОТМЕНЕННО.';
+$labels['areyousure'] = 'Вы не можете отменить это действие. Вы действительно уверены?';
+$labels['successfullydeleted'] = 'Настройки были успешно удалены.';
+$labels['successfullysaved'] = 'Успешно сохранены.';
+$labels['errorsaving'] = 'Произошла ошибка при сохранении.';
+$labels['yes'] = 'Да';
+$labels['no'] = 'Нет';
+$labels['disable'] = 'Отключить';
+$labels['remove'] = 'Удалить';
+$labels['savewarning'] = 'Вы хотите сохранить изменения?';
+$labels['plugin_manager_update'] = 'Обновить расширения';
+$labels['authors_comments'] = 'Комментарии авторов';
+$labels['requiredby'] = 'Расширение требуется ';
+$labels['requires'] = 'Расширению требуется';
+$labels['recommended'] = 'Рекомендованные расширения';
+$labels['update_plugins'] = 'Обновить расширения';
+$labels['ziparchive'] = 'Скачать архив (ZIP)';
+$labels['demoaccount'] = 'Извините, скачать невозможно (демо - аккаунт)';
+$labels['serverversion'] = 'Сервер версия';
+$labels['mirrorversion'] = 'Зеркало версия';
+$labels['mirrorhost'] = 'Зеркало';
+$labels['comments'] = 'Примечания и требования к обновлению';
+$labels['update_error'] = 'Несоответствие версий';
+$labels['update_ok'] = 'Последняя версия. Обновление не требуется.';
+$labels['update_edit'] = 'Расширение должно быть повторно настроено илии требует корректировки базы данных. Обратите внимание на примечание к обновлению.';
+$labels['servernewer'] = 'Версия расширения новее версии на зеркале. ';
+$labels['orhigher'] = 'или выше';
+$labels['rc_ok'] = 'Версия Roundcube актуальна. ';
+$labels['update_update'] = 'Расширение является устаревшей. Обновите, пожалуйста! ';
+$labels['noupdates'] = 'Ни одного обновления не выбрано.';
+$labels['rc_update'] = 'Версия Roundcube устарела. Пожалуйста, обновите!';
+$labels['rc_uptodate'] = 'Roundcube обновлен!';
+$labels['rc_newer'] = 'Версия Roundcube новее версии на зеркале!';
+$labels['nottested'] = 'Пожалуйста, используйте расширения с осторожностью! Расширения могут повредить Roundcube v%s.';
+$labels['justunzip'] = 'Просто распакуйте архив поверх вашей существующей установки.';
+$labels['guide'] = 'Читать полностью...';
+$labels['thirdparty'] = 'Это не MyRoundcube расширение.';
+$labels['thirdpartywarning'] = 'Этот плагин написан сторонним разработчиком. Мы рекомендуем вам скачать его с сайта разработчика а не с нашего зеркала. На сайте разработчика вы так же найдете его более свежую версию, и замечания и советы по установке';
+$labels['develsite'] = 'Скачать';
+$labels['notinstalled'] = 'Не установлен';
+$labels['notregistered'] = 'Расширение не зарегистрировано в файле конфигурации';
+$labels['roundcubeurl'] = 'Скачать Roundcube';
+$labels['languageupdate'] = 'Доступно обновление локализации.';
+$labels['localizationfilesonly'] = 'Загрузка будет содержать только файлы локализации. Изменений в коде плагина нет';
+$labels['donotregister'] = 'Не регистрируйте это расширение, оно будет скаченно автоматически.';
+$labels['register'] = 'Зарегистрировать этот плагин в ./config/config.inc.php <small>[$config[\'plugins\'] = array("<i>foo</i>", "<i>bar</i>");]</small>.';
+$labels['customer_account'] = 'Аккаунт клиента';
+$labels['customer_id'] = 'Номер клиента';
+$labels['invalid_customer_id'] = 'Неправильный номер клиента';
+$labels['invalid_credits'] = 'Неправильные кредиты';
+$labels['successfully_transferred'] = 'Кредиты успешно перенесены';
+$labels['merge'] = 'Принять кредиты';
+$labels['credits'] = 'Кредиты';
+$labels['creditsupdated'] = 'Кредиты были изменены с момента последнего обновления страницы';
+$labels['buynow'] = 'Приобрести кредиты';
+$labels['history'] = 'История операций по аккаунту';
+$labels['details'] = 'Подробно';
+$labels['receipt'] = 'выписка';
+$labels['plugins'] = 'Плагины';
+$labels['clickhere'] = 'Нажмите здесь';
+$labels['discardliabletopaycosts'] = 'Отказаться от оплаты';
+$labels['unchecknotinstalledplugins'] = 'Отменить загрузку ';
+$labels['sum'] = 'Сумма';
+$labels['show'] = 'Показать';
+$labels['hide'] = 'Убрать';
+$labels['view'] = 'просмотреть';
+$labels['expired'] = 'просрочен';
+$labels['terms'] = 'Правила';
+$labels['pricelist'] = 'Загрузить цены';
+$labels['forthisdownload'] = 'для этой загрузки';
+$labels['remainingcredits'] = 'Осталось кредитов';
+$labels['initialdownload'] = 'Начальная загрузка';
+$labels['keyfeatureaddition'] = 'Новая ключевая особенность';
+$labels['codeimprovements'] = 'Улучшения кода';
+$labels['servicenotavailable'] = 'Сервис недоступен. Попробуйте позже!';
+$labels['myrcerror'] = 'Службы MyRoundcube в настоящий момент недоступны';
+$labels['getnew'] = 'Запросить новый номер клиента';
+$labels['getnew_hint'] = 'Мы рекомендуем вам чаще обновлять обновлять свой номер клиента. Если вы уведомлены о подозрительной активности на вашем счете, обновите свой номер клиента как можно скорее';
+$labels['transfer'] = 'Перенести кредиты';
+$labels['noplugindescription'] = 'Описание расширение не найдено.';
+$labels['markbuttons_pluginname'] = 'Отметить кнопки сообщений';
+$labels['markbuttons_plugindescription'] = 'Добавить "множественный выбор".';
+$labels['automatic_addressbook_pluginname'] = 'Автоматический сборщик арессов';
+$labels['automatic_addressbook_plugindescription'] = 'Собирает адреса электронной почты всех получателей в отдельную книгу.';
+$labels['keyboard_shortcuts_pluginname'] = 'Сочетания клавиш';
+$labels['keyboard_shortcuts_plugindescription'] = 'Ввод команд при помощи сочетаний клавиш.';
+$labels['message_highlight_pluginname'] = 'Подсветка сообщений';
+$labels['message_highlight_plugindescription'] = 'Подсветка сообщений в соответствии с фильтром.';
+$labels['fixTHEAD_pluginname'] = 'Fix Header of Message List';
+$labels['fixTHEAD_plugindescription'] = 'Исправление заголовка списка сообщений.';
+$labels['compose_addressbook_pluginname'] = 'Адресная книга в окне создания сообщения';
+$labels['compose_addressbook_plugindescription'] = 'Добавляет адресную книгу в окно создания сообщения для удобного поиска получателей.';
+$labels['google_contacts_pluginname'] = 'Контакты Google';
+$labels['google_contacts_plugindescription'] = 'Доступ к контактам вашего Google аккаунта. ';
+$labels['contextmenu_pluginname'] = 'Контекстное меню';
+$labels['contextmenu_plugindescription'] = 'Добавляет открытие меню по правому клику мыши.';
+$labels['newmail_notifier_pluginname'] = 'New Mail Notifier';
+$labels['newmail_notifier_plugindescription'] = 'Уведомление о новых сообщениях.';
+$labels['listcommands_pluginname'] = 'Reply Mailing Lists';
+$labels['listcommands_plugindescription'] = 'Различные варианты ответа на сообщения, отправленные из списков рассылки.';
+$labels['copymessage_pluginname'] = 'Копирование сообщения(ий)';
+$labels['copymessage_plugindescription'] = 'Копирование сообщения(ий) в другую IMAP папку.';
+$labels['forwardattachment_pluginname'] = 'Пересылка вложением';
+$labels['forwardattachment_plugindescription'] = 'Пересылка нескольких сообщений как вложения.';
+$labels['vcard_attachments_pluginname'] = 'vCard вложения';
+$labels['vcard_attachments_plugindescription'] = 'Добавляет возможность импорта файла vCard напрямую в адресную книгу.';
+$labels['importmessages_pluginname'] = 'Импорт сообщений';
+$labels['importmessages_plugindescription'] = 'Импортирует сообщения из *.zip архива или *.eml файла.';
+$labels['zipdownload_pluginname'] = 'Экспорт сообщений';
+$labels['zipdownload_plugindescription'] = 'Экспортирует сообщения в zip архив.';
+$labels['markasjunk2_pluginname'] = 'Отметить как спам';
+$labels['markasjunk2_plugindescription'] = 'Отмечает сообщения как спам.';
+$labels['markasjunk_pluginname'] = 'Отметить как спам';
+$labels['markasjunk_plugindescription'] = 'Отмечает сообщения как спам.';
+$labels['google_ads_pluginname'] = 'Google реклама';
+$labels['google_ads_plugindescription'] = 'Показ Google рекламы.';
+$labels['google_analytics_pluginname'] = 'Google аналитика';
+$labels['google_analytics_plugindescription'] = 'Добавляет Google аналитику.';
+$labels['globaladdressbook_pluginname'] = 'Глобальная адресная книга';
+$labels['globaladdressbook_plugindescription'] = 'Глобальная адресная книга видна всем пользователям, но пользователь не имеет прав на редактирование, редактирование и заполнение ведется заранее назначенным администратором.';
+$labels['blockspamsending_pluginname'] = 'Предотвращение рассылки спама';
+$labels['blockspamsending_plugindescription'] = 'Позволяет посылать, только определенное количество сообщений с одного тела в течение одной сессии.';
+$labels['global_config_pluginname'] = 'Конфигуратор';
+$labels['global_config_plugindescription'] = 'Единая конфигурация для всех расширений.';
+$labels['jqueryui_pluginname'] = 'Jqueryui';
+$labels['jqueryui_plugindescription'] = 'Jqueryui ява библиотека.';
+$labels['hide_blockquote_pluginname'] = 'Скрыть цитату';
+$labels['hide_blockquote_plugindescription'] = 'Hide citation when lines count is greater than a specified count of lines.';
+$labels['crawler_pluginname'] = 'Crawler';
+$labels['crawler_plugindescription'] = 'Поддельные содержание страницы для поисковых роботов.';
+$labels['dblog_pluginname'] = 'Журнал в базе';
+$labels['dblog_plugindescription'] = 'Ведение журнала в БД вместо файла.';
+$labels['http_auth_pluginname'] = 'HTTP авторизация';
+$labels['http_auth_plugindescription'] = 'Добавляет поддержку HTTP авторизации.';
+$labels['impersonate_pluginname'] = 'Impersonate';
+$labels['impersonate_plugindescription'] = 'Инструмент для входа в учетные записи по мастер-паролю.';
+$labels['jscolor_pluginname'] = 'Палитра цветов';
+$labels['jscolor_plugindescription'] = 'Добавляет палитру цветов.';
+$labels['tinymce_pluginname'] = 'TinyMCE - HTML редактор';
+$labels['tinymce_plugindescription'] = 'Замена стандартного редактора TinyMCE на редактор TinyMCE jQuery (включает TinyMCE PHP Compressor http://www.tinymce.com/wiki.php/Compressors:PHP).';
+$labels['embed_images_pluginname'] = 'Внедрить внешний рисунок';
+$labels['embed_images_plugindescription'] = 'Внедрить внешний рисунок в источник сообщения';
+$labels['lang_sel_pluginname'] = 'Выбрать язык';
+$labels['lang_sel_plugindescription'] = 'Выбрать язык на странице входа в систему';
+$labels['newuser_pluginname'] = 'Новый пользователь';
+$labels['newuser_plugindescription'] = 'Уведомлять администратора в случае когда через веб-интерфейс зарегистрирован новый пользователь, и высылать приветственное письмо новому пользователю на первый логин';
+$labels['placeholder_pluginname'] = 'Атрибуты заполнителя';
+$labels['placeholder_plugindescription'] = 'Добавить атрибуты заполнителя для текстовых полей и полей ввода пароля';
+$labels['qtip_pluginname'] = 'Подсказки jQueryUI';
+$labels['qtip_plugindescription'] = 'Плагин помощи для использования jQueryUI подсказок';
+$labels['sabredav_pluginname'] = 'SabreDAV';
+$labels['sabredav_plugindescription'] = 'Создавать аккаунты доступа SabreDAV для календарей CalDAV, когда новый пользователь Roundcube создает и объединяет пароли, если они были изменены';
+$labels['savepassword_pluginname'] = 'Сохранить пароли';
+$labels['savepassword_plugindescription'] = 'Этот плагин помощи используется другими плагинами';
+$labels['database_attachments_pluginname'] = 'Вложения в БД';
+$labels['database_attachments_plugindescription'] = 'Плагин помощи для управления вложениями в базе данных';
+$labels['new_user_dialog_pluginname'] = 'Новый диалог пользователя';
+$labels['new_user_dialog_plugindescription'] = 'Настройки идентификации диалогового окна создания новых пользователей. Когда создается новый пользователь, плагин проверяет настройки и устанавливает флаг незавершенной сессии. При этом на экране появляется всплывающее окно для просмотра и ввода идентификационных данных пользователя';
+$labels['rcguard_pluginname'] = 'ReCAPTCHA';
+$labels['rcguard_plugindescription'] = 'Усилить CAPTCHA после некоторого количества безуспешных попыток входа';
+$labels['domain_check_pluginname'] = 'Проверить Домен';
+$labels['domain_check_plugindescription'] = 'Ограничить вход в webmail до специально указываемых адресов';
+
+?> \ No newline at end of file
diff --git a/plugin_manager/package.xml b/plugin_manager/package.xml
new file mode 100644
index 0000000..3c65785
--- /dev/null
+++ b/plugin_manager/package.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+ http://pear.php.net/dtd/tasks-1.0.xsd
+ http://pear.php.net/dtd/package-2.0
+ http://pear.php.net/dtd/package-2.0.xsd">
+ <name>plugin_manager</name>
+ <lead>
+ <name>Myroundcube Dev Team</name>
+ <user>rosali</user>
+ <email>dev-team@myroundcube.com</email>
+ <active>yes</active>
+ </lead>
+ <uri>http://myroundcube.com/myroundcube-plugins/plugin-manager</uri>
+ <date>2015-02-14</date>
+ <version>
+ <release>28.0.12</release>
+ <api>28.0.12</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://dev.myroundcube.com/index.php?_action=plugin.plugin_server_license&amp;_plugin=plugin_manager">All Rights reserved</license>
+</package>
diff --git a/plugin_manager/plugin_manager.js b/plugin_manager/plugin_manager.js
new file mode 100644
index 0000000..e043d03
--- /dev/null
+++ b/plugin_manager/plugin_manager.js
@@ -0,0 +1,372 @@
+function pm_get_credits(){
+ rcmail.http_post(
+ 'plugin.plugin_manager_getcredits', ''
+ );
+}
+
+function pm_update_credits(response){
+ if(response){
+ if($('#cdlcredits').get(0) && parseInt(response) && (parseInt(response) != parseInt($('#cdlcredits').text()))){
+ var newcredits = parseInt(response) - parseInt($('#cdlcredits').text());
+ var color = newcredits > 0 ? 'green' : 'red';
+ var html = $('#accountdetails').html();
+ $('#accountdetails > tbody:last').append('<tr><td colspan="4" style="border: 1px solid lightgrey;">MyRC$ ' + rcmail.gettext('creditsupdated','plugin_manager') + '</td><td align="right" style="border: 1px solid lightgrey; color: ' + color + ';">' + (newcredits > 0 ? '+' : '') + newcredits + '</td><td style="border: 1px solid lightgrey;">&nbsp;</td></tr>');
+ $('#cdlcredits').text(response);
+ rcmail.display_message('MyRC$ ' + newcredits + ' ' + rcmail.gettext('creditsupdated','plugin_manager'), 'confirmation');
+ }
+ }
+ window.setTimeout('pm_get_credits()', 1000 * 30);
+}
+
+function plugin_manager_save_prefs(){
+ $('.mainaction').hide();
+ var prefs = $('input[name*="man"]').serialize();
+ rcmail.http_post('plugin.plugin_manager_save', prefs);
+}
+
+$(document).ready(function(){
+ // update credtis
+ if(rcmail.env.framed){
+ window.setTimeout('pm_get_credits()', 1 * 1000);
+ }
+ // hide qtips
+ $('.about-link').click(function(){
+ $('.ui-tooltip').hide();
+ });
+ // add event listeners
+ rcmail.addEventListener('init', function(evt){
+ rcmail.addEventListener('plugin.plugin_manager_getcredits', pm_update_credits);
+ });
+ rcmail.addEventListener('plugin.plugin_manager_save_config', function(response) {
+ var msg = response[0];
+ var type = response[1];
+ rcmail.display_message(msg, type);
+ $('#source').html(msg + '&nbsp;');
+ });
+ rcmail.addEventListener('plugin.plugin_manager_success', function(response) {
+ rcmail.pm_stat = $('input[name*="man"]').serialize();
+ rcmail.display_message(rcmail.gettext('successfullydeleted', 'plugin_manager'), 'confirmation');
+ if(response){
+ eval(response);
+ plugin_manager_save_prefs();
+ }
+ else{
+ plugin_manager_save_prefs();
+ }
+ });
+ rcmail.addEventListener('plugin.plugin_manager_saved', function(response) {
+ rcmail.pm_stat = $('input[name*="man"]').serialize();
+ rcmail.display_message(rcmail.gettext('successfullysaved', 'plugin_manager'), 'confirmation');
+ if(response){
+ eval(response);
+ }
+ });
+ rcmail.addEventListener('plugin.plugin_manager_error', function(response) {
+ rcmail.display_message(rcmail.gettext('errorsaving', 'plugin_manager'), 'error');
+ $('.mainaction').hide();
+ $(':checkbox').each(function(){
+ $(this).prop('disabled', true);
+ });
+ window.setTimeout("parent.location.href='./?_task=settings&_action=plugin.plugin_manager'", 3000);
+ });
+ rcmail.addEventListener('init', function(){
+ function float_fieldsets(){
+ if(document.location.search.indexOf('&_section=plugin_manager&') < 0){
+ return;
+ }
+ $('td.title').remove();
+ rcmail.pm_mh = 0;
+ rcmail.pm_mh2 = new Array();
+ rcmail.pm_mw = 0;
+ rcmail.pm_top = 0;
+ rcmail.pm_row = -1;
+ $('.pm_section').each(function(){
+ if($(this).width() > rcmail.pm_mw)
+ rcmail.pm_mw = $(this).width();
+ if($(this).height() > rcmail.pm_mh)
+ rcmail.pm_mh = $(this).height();
+ });
+ $('.pm_section').each(function(){
+ $(this).width(rcmail.pm_mw);
+ $(this).height(rcmail.pm_mh);
+ });
+ $('.pm_fieldset').each(function(){
+ if($(this).offset().top > rcmail.pm_top){
+ rcmail.pm_row ++;
+ rcmail.pm_top = $(this).offset().top;
+ if(!rcmail.pm_mh2[rcmail.pm_row])
+ rcmail.pm_mh2[rcmail.pm_row] = $(this).height();
+ }
+ if($(this).height() > rcmail.pm_mh2[rcmail.pm_row]){
+ rcmail.pm_mh2[rcmail.pm_row] = $(this).height();
+ }
+ });
+ rcmail.pm_top = 0;
+ rcmail.pm_row = -1;
+ rcmail.pm_heights = new Array();
+ rcmail.pm_sections = -1;
+ $('.pm_fieldset').each(function(){
+ $(this).width(rcmail.pm_mw - 20);
+ if($(this).offset().top > rcmail.pm_top){
+ rcmail.pm_row ++;
+ rcmail.pm_top = $(this).offset().top;
+ }
+ rcmail.pm_sections ++;
+ rcmail.pm_heights[rcmail.pm_sections] = rcmail.pm_mh2[rcmail.pm_row];
+ $(this).height(rcmail.pm_mh2[rcmail.pm_row] - 20);
+ });
+ rcmail.pm_sections = -1;
+ $('.pm_section').each(function(){
+ rcmail.pm_sections ++;
+ $(this).height(rcmail.pm_heights[rcmail.pm_sections]);
+ });
+ }
+ float_fieldsets();
+ $(window).resize(function(){
+ $('.pm_section').each(function(){
+ $(this).attr('style', '');
+ });
+ $('.pm_fieldset').each(function(){
+ $(this).attr('style', '');
+ });
+ float_fieldsets();
+ });
+ $('.plugin_manager_li').click(function(){
+ $('#pm_restore_defaults').prop('checked', false);
+ $('#pm_check_all').prop('checked', false);
+ $('#pm_uncheck_all').prop('checked', false);
+ });
+ $('#pm_restore_defaults').click(function(){
+ $('#pm_check_all').prop('checked', false);
+ $('#pm_uncheck_all').prop('checked', false);
+ for(var i in rcmail.env.pm_restore){
+ $('#pm_chbox_' + rcmail.env.pm_restore[i][0]).prop('checked', rcmail.env.pm_restore[i][1]);
+ }
+ });
+ $('#pm_check_all').click(function(){
+ $('#pm_uncheck_all').prop('checked', false);
+ $('#pm_restore_defaults').prop('checked', false);
+ for(var i in rcmail.env.pm_restore){
+ $('#pm_chbox_' + rcmail.env.pm_restore[i][0]).prop('checked', true);
+ }
+ });
+ $('#pm_uncheck_all').click(function(){
+ $('#pm_check_all').prop('checked', false);
+ $('#pm_restore_defaults').prop('checked', false);
+ for(var i in rcmail.env.pm_restore){
+ $('#pm_chbox_' + rcmail.env.pm_restore[i][0]).prop('checked', false);
+ }
+ });
+ $('#pm_update_plugins').click(function(){
+ document.location.href = './?_task=settings&_framed=1&_action=plugin.plugin_manager_update&_warning=1';
+ });
+ rcmail.pm_stat = $('input[name*="man"]').serialize();
+ $('.mainaction').hide();
+ $('.mainaction').prop('disabled', true);
+ $('input:checkbox').click(function(){
+ if(rcmail.pm_stat != $('input[name*="man"]').serialize()){
+ $('.mainaction').prop('disabled', false);
+ $('.mainaction').show();
+ }
+ else{
+ $('.mainaction').prop('disabled', true);
+ $('.mainaction').hide();
+ }
+ });
+ $('.fsavedialog').click(function(){
+ var plugin = $(this).attr('name').replace('_plugin_manager_','');
+ var label = rcmail.gettext(plugin + '.plugindescription');
+ if(label.substr(0,1) != '[' && label.substr(label.length - 1, 1) != ']'){
+ if($('.mainaction').prop('disabled') == false){
+ if($(this).prop('checked') && !$(this).hasClass('fconfig')){
+ plugin_manager_save_prefs();
+ }
+ else{
+ if(!$(this).hasClass('funinstall') && !$(this).hasClass('frequest') && !$(this).hasClass('frequestforce')){
+ plugin_manager_save_prefs();
+ }
+ }
+ }
+ }
+ });
+ $('.fconfig').click(function(){
+ if($(this).prop('checked')){
+ var plugin = $(this).attr('name').replace('_plugin_manager_','');
+ var label = rcmail.gettext(plugin + '.plugindescription');
+ if(label.substr(0,1) != '[' && label.substr(label.length - 1, 1) != ']'){
+ if($('.mainaction').prop('disabled') == false){
+ $('.mainaction').hide();
+ var buttons = {};
+ buttons[rcmail.gettext('plugin_manager.yes')] = function(){
+ $('#plugin_manager_config_plugin').val(plugin);
+ document.forms.form.submit();
+ $('#jqdialog').dialog("close");
+ };
+ buttons[rcmail.gettext('plugin_manager.no')] = function(){
+ plugin_manager_save_prefs();
+ $('#jqdialog').dialog("close");
+ };
+ $('#jqdialog').html(label + '<hr /><p>' + rcmail.gettext('plugin_manager.furtherconfig') + '</p>');
+ $('#jqdialog').dialog({
+ 'title': rcmail.gettext(plugin + '.pluginname'),
+ 'buttons': buttons,
+ 'position': [$(this).offset().left + 20, $(this).offset().top + 20],
+ 'zIndex': 99999,
+ 'close': function(){
+ $('#plugin_manager_config_plugin').val('');
+ }
+ });
+ }
+ }
+ }
+ else{
+ if(!$(this).hasClass('funinstall') && !$(this).hasClass('frequest') && !$(this).hasClass('frequestforce')){
+ plugin_manager_save_prefs();
+ }
+ }
+ });
+ $('.funinstall').click(function(){
+ if(!$(this).prop('checked')){
+ var plugin = $(this).attr('name').replace('_plugin_manager_','');
+ var label = rcmail.gettext(plugin + '.plugindescription');
+ if(label.substr(0,1) != '[' && label.substr(label.length - 1, 1) != ']'){
+ if($('.mainaction').prop('disabled') == false){
+ $('.mainaction').hide();
+ var buttons = {};
+ buttons[rcmail.gettext('plugin_manager.yes')] = function(){
+ $('.mainaction').prop('disabled', true);
+ rcmail.http_post('plugin.plugin_manager_uninstall', '_uninstall=' + plugin);
+ $('#jqdialog').dialog("close");
+ };
+ buttons[rcmail.gettext('plugin_manager.no')] = function(){
+ plugin_manager_save_prefs();
+ $('#jqdialog').dialog("close");
+ };
+ $('#jqdialog').html(label + '<hr /><p>' + rcmail.gettext('plugin_manager.uninstall') + '</p>');
+ $('#jqdialog').dialog({
+ 'title': rcmail.gettext(plugin + '.pluginname'),
+ 'buttons': buttons,
+ 'position': [$(this).offset().left + 20, $(this).offset().top + 20],
+ 'zIndex': 99999,
+ 'close': function(){
+ }
+ });
+ }
+ }
+ }
+ });
+ $('.frequest').click(function(){
+ if(!$(this).prop('checked')){
+ $(this).prop('checked', true)
+ var plugin = $(this).attr('name').replace('_plugin_manager_','');
+ var label = rcmail.gettext(plugin + '.plugindescription');
+ if(label.substr(0,1) != '[' && label.substr(label.length - 1, 1) != ']'){
+ if($('.mainaction').prop('disabled') == false){
+ $('.mainaction').hide();
+ var buttons = {};
+ buttons[rcmail.gettext('plugin_manager.disable')] = function(){
+ $('#pm_chbox_' + plugin).prop('checked', false);
+ plugin_manager_save_prefs();
+ $('#jqdialog').dialog("close");
+ };
+ buttons[rcmail.gettext('plugin_manager.remove')] = function(){
+ $('.mainaction').prop('disabled', true);
+ $('#pm_chbox_' + plugin).prop('checked', false);
+ if(confirm(rcmail.gettext('plugin_manager.areyousure')))
+ rcmail.http_post('plugin.plugin_manager_uninstall', '_uninstall=' + plugin);
+ else
+ plugin_manager_save_prefs();
+ $('#jqdialog').dialog("close");
+ };
+ $('#jqdialog').html(label + '<hr /><p>' + rcmail.gettext('plugin_manager.uninstallconfirm') + '</p>');
+ $('#jqdialog').dialog({
+ 'title': rcmail.gettext(plugin + '.pluginname'),
+ 'buttons': buttons,
+ 'position': [$(this).offset().left + 20, $(this).offset().top + 20],
+ 'zIndex': 99999,
+ 'close': function(){
+ }
+ });
+ }
+ }
+ }
+ });
+ $('.frequestforce').click(function(){
+ if(!$(this).prop('checked')){
+ $(this).prop('checked', true)
+ var plugin = $(this).attr('name').replace('_plugin_manager_','');
+ var label = rcmail.gettext(plugin + '.plugindescription');
+ if(label.substr(0,1) != '[' && label.substr(label.length - 1, 1) != ']'){
+ if($('.mainaction').prop('disabled') == false){
+ var buttons = {};
+ buttons[rcmail.gettext('plugin_manager.remove')] = function(){
+ $('.mainaction').prop('disabled', true);
+ $('#pm_chbox_' + plugin).prop('checked', false);
+ rcmail.http_post('plugin.plugin_manager_uninstall', '_uninstall=' + plugin);
+ $('#jqdialog').dialog("close");
+ };
+ $('#jqdialog').html(label + '<hr /><p>' + rcmail.gettext('plugin_manager.uninstall') + '</p>');
+ $('#jqdialog').dialog({
+ 'title': rcmail.gettext(plugin + '.pluginname'),
+ 'buttons': buttons,
+ 'position': [$(this).offset().left + 20, $(this).offset().top + 20],
+ 'zIndex': 99999,
+ 'close': function(){
+ }
+ });
+ }
+ }
+ }
+ });
+ $('.plugin_manager_ul > li').each(function(){
+ var plugin = $(this).attr('id');
+ var temparr = plugin.split('pmid_');
+ plugin = temparr[1];
+ if(rcmail.env['pm_plugin_' + plugin] != 1){
+ if(rcmail.env['pm_buttons_' + plugin]){
+ for(var i in rcmail.env['pm_buttons_' + plugin]){
+ if(parent.$(rcmail.env['pm_buttons_' + plugin][i]).get(0)){
+ parent.$(rcmail.env['pm_buttons_' + plugin][i]).hide();
+ }
+ else{
+ if(parent.$(rcmail.env['pm_buttons_' + plugin][i]).get(0)){
+ parent.$(rcmail.env['pm_buttons_' + plugin][i]).show();
+ }
+ }
+ }
+ }
+ }
+ else{
+ if(rcmail.env['pm_buttons_' + plugin]){
+ console.log(rcmail.env['pm_buttons_' + plugin][0]);
+ if(!parent.$(rcmail.env['pm_buttons_' + plugin][0]).get(0)){
+ parent.location.href='./?_task=settings&_action=plugin.plugin_manager';
+ }
+ }
+ }
+ var label = rcmail.gettext(plugin + '.plugindescription');
+ if(label.indexOf('.plugindescription') == -1){
+ if(label.substr(0,1) != '[' && label.substr(label.length - 1, 1) != ']'){
+ $(this).qtip({
+ content: {
+ title: $(this).text().replace("\n",""),
+ text: label
+ },
+ position: {
+ my: "top left",
+ at: "left bottom",
+ target: $(this),
+ viewport: $(window)
+ },
+ hide: {
+ effect: function () { $(this).slideUp(5, function(){ $(this).dequeue(); }); }
+ },
+ style: {
+ classes: "ui-tooltip-light"
+ }
+ });
+ }
+ }
+ });
+ });
+}); \ No newline at end of file
diff --git a/plugin_manager/plugin_manager.php b/plugin_manager/plugin_manager.php
new file mode 100644
index 0000000..65850a1
--- /dev/null
+++ b/plugin_manager/plugin_manager.php
@@ -0,0 +1,4554 @@
+<?php
+#
+# This file is part of MyRoundcube "plugin_manager" plugin.
+#
+# Your are not allowed to distribute this file or parts of it.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl - all rights reserved.
+# dev-team [at] myroundcube [dot] com
+# http://myroundcube.com
+#
+class plugin_manager extends rcube_plugin
+{
+
+ private $debug = false;
+ static private $version = '29.0';
+ static private $date = '22-02-2015';
+
+ private $core_patches = array(
+ 'version' => 'Roundcube 1.0.5',
+ 'count' => 0,
+ 'date' => '2015-02-08 06:00:00',
+ 'comments' => 'Download required core files PATCHES for Roundcube 1.0.5 from <a href="https://mirror.myroundcube.com/dl/1.0.5/roundcube.zip">here</a>. Unzip the package over your Roundcube installation. For DETAILS about the additions these files provide, download a revision copy (*.PATCH) from <a href="https://mirror.myroundcube.com/dl/1.0.5/roundcube.patch" target="_blank">here</a>.',
+ 'PHP' => '5.3',
+ 'lc' => false,
+ );
+
+ public $allowed_prefs = array('plugin_manager_hmail');
+
+ private $rcmail;
+ private $log = false;
+ private $template;
+ private $admins = array();
+ private $noremote = false;
+ private $host;
+ private $domain;
+ private $config;
+ private $lables;
+ private $plugins;
+ private $mirror = 'http://mirror.myroundcube.com';
+ private $svn = 'http://dev.myroundcube.com';
+ private $beta = 'http://beta.myroundcube.com';
+ private $stable = '0.9.5';
+ private $dev = '1.0.5';
+ private $dev_beta = '1.0.5';
+ private $rcurl = 'http://roundcube.net';
+ private $guide = 'http://myroundcube.com/myroundcube-plugins/plugins-installation';
+ private $replyto = 'dev-team@myroundcube.com';
+ private $vlength = 5;
+ private $billingurl = 'http://billing.myroundcube.com/?_task=billing&_action=buycredits';
+ private $dlurl = 'https://billing.myroundcube.com/pm/';
+ private $delay = 8000;
+ private $out;
+ private $defaults = array();
+ private $unauth = array();
+ private $thirdparty = array();
+ private $use_ssl = false;
+ private $use_hmail = false;
+ private $load_splitter = false;
+ private $maintenance_mode = false;
+ private $compress_html = false;
+ private $file_based_config = false;
+ private $config_permissions = false;
+ private $dontlist = array('plugin_server', 'global_config');
+ private $skip = array('plugin_manager', 'plugin_server', 'companyaddressbook_plus', 'calendar_plus', 'carddav_plus', 'codemirror_ui', 'db_version', 'global_config', 'http_auth', 'jqueryui', 'filesystem_attachments', 'fancybox', 'package_xml', 'sabredav_migrate', 'savepassword', 'timepicker', 'jsdialogs', 'jappix4roundcube', 'db_config', 'tabbed');
+ private $noselect = array('plugin_manager', 'plugin_server', 'companyaddressbook_plus', 'calendar_plus', 'carddav_plus', 'codemirror_ui', 'global_config', 'http_auth', 'jqueryui', 'filesystem_attachments', 'fancybox', 'package_xml', 'sabredav_migrate', 'savepassword','timepicker');
+ private $rctasks = array('settings', 'mail', 'addressbook', 'settings', 'dummy', 'logout', 'login');
+ private $db_map = array(
+ 'sqlite' => 'sqlite',
+ 'sqlite2' => 'sqlite',
+ 'sqlite3' => 'sqlite',
+ 'sybase' => 'mssql',
+ 'dblib' => 'mssql',
+ 'sqlsrv' => 'mssql',
+ 'mssql' => 'mssql',
+ 'mysql' => 'mysql',
+ 'mysqli' => 'mysql',
+ 'pgsql' => 'pgsql',
+ 'postgresql' => 'pgsql',
+ );
+ private $nodocs = array(
+
+ );
+ private $docsmap = array(
+ //'rcguard' => 'captcha-plugin#rcguard',
+ );
+
+ /* unified plugin properties */
+ static private $plugin = 'plugin_manager';
+ static private $author = 'myroundcube@mail4us.net';
+ static private $authors_comments = '<a onclick="alert(\'Roundcube Core Patches are recommended in order to show all installed plugins in <i>About</i> popup.\')" href="#pmu_Roundcube_Core_Patches"><font color="red">IMPORTANT</font></a><br /><a href="http://trac.roundcube.net/ticket/1488871" target="_blank">Related Ticket</a><br /><a href="http://myroundcube.com/myroundcube-plugins/plugin-manager" target="_blank">Documentation</a>';
+ static private $download = 'http://myroundcube.com';
+ static private $licence = 'All Rights reserved';
+ static private $requirements = array(
+ 'Roundcube' => '1.0',
+ 'PHP' => '5.3',
+ 'extra' => 'PHP cURL and OpenSSL are recommended',
+ 'required_plugins' => array(
+ 'settings' => 'require_plugin',
+ 'libgpl' => 'require_plugin',
+ 'codemirror_ui' => 'require_plugin',
+ 'db_version' => 'require_plugin',
+ 'myrc_branch' => 'require_plugin',
+ 'myrc_sprites' => 'require_plugin',
+ ),
+ );
+ static private $prefs = array(
+ 'plugin_manager_active',
+ 'plugin_manager_hash',
+ );
+ static private $tables = array('plugin_manager');
+ static private $db_version = array(
+ 'initial',
+ '20131209'
+ );
+
+ function init(){
+
+ $this->require_plugin('libgpl');
+
+ /* PHP 5.4: suppress illegal string offset warnings */
+ if(version_compare(PHP_VERSION, '5.4.0', '>=') && strpos($_SERVER['HTTP_HOST'], 'myroundcube.com') === false){
+ if((E_ALL & ~E_NOTICE & ~E_STRICT & ~E_WARNING & ~E_USER_WARNING) != filter_var(ini_get('error_reporting'), FILTER_VALIDATE_INT)){
+ @ini_set('error_reporting', E_ALL & ~E_NOTICE & ~E_STRICT & ~E_WARNING & ~E_USER_WARNING);
+ if((E_ALL & ~E_NOTICE & ~E_STRICT & ~E_WARNING & ~E_USER_WARNING) != filter_var(ini_get('error_reporting'), FILTER_VALIDATE_INT)){
+ write_log('errors', 'MyRoundcube Plugin Manager: Please set error_reporting to E_ALL & ~E_NOTICE & ~E_STRICT & ~E_WARNING & ~E_USER_WARNING (php.ini or .htaccess).');
+ }
+ }
+ }
+
+ /* DB versioning */
+ if(is_dir(INSTALL_PATH . 'plugins/db_version')){
+ $this->require_plugin('db_version');
+ if(!$load = db_version::exec(self::$plugin, self::$tables, self::$db_version)){
+ return;
+ }
+ }
+
+ $this->rcmail = rcmail::get_instance();
+
+ $required = self::$requirements['required_plugins'];
+ foreach($required as $plugin => $load){
+ if(!file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/' . $plugin . '.php')){
+ if(get_input_value('_framed', RCUBE_INPUT_GPC)){
+ $this->rcmail->output->add_script('parent.location.href="./";', 'foot');
+ }
+ else{
+ if(MYRC_BRANCH == 'stable'){
+ $server = $this->svn;
+ }
+ else if(MYRC_BRANCH == 'frozen'){
+ $server = $this->mirror;
+ }
+ else{
+ $server = $this->beta;
+ }
+ $this->out = html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -200px; width: 400px;'),
+ html::tag('h3', null, 'Missing plugin: "' . html::tag('a', array('href' => 'http://myroundcube.com/myroundcube-plugins#' . $plugin, 'target' => '_blank'), $plugin) . '"<br />' . html::tag('span', array('style' => 'font-weight: normal; font-size: 9px'), '(' . INSTALL_PATH . $plugin . ')')) .
+ html::tag('span', null, 'Please ' .
+ html::tag('a', array('href' => $server . '/?_action=plugin.plugin_server_get_pm'), 'download') .
+ ' Plugin Manager package again and upload the entire package to your Roundcube\'s plugin folder.') . html::tag('br') . html::tag('br') .
+ html::tag('div', array('style' => 'display: inline; float: left'),
+ html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => 'document.location.href=\'./\''), $this->gettext('done'))
+ )
+ );
+ $this->register_handler('plugin.body', array($this, 'sqlerror'));
+ $this->rcmail->output->send('plugin');
+ }
+ }
+ }
+
+ $this->require_plugin('myrc_sprites');
+
+ $rcversion = current(explode('-', RCMAIL_VERSION));
+ $pmversion = self::$requirements['Roundcube'];
+
+ if(version_compare($rcversion, $pmversion, '<')){
+ $this->out = html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -200px; width: 400px;'),
+ html::tag('h3', null, 'Plugin Manager is incompatible with your Roundcube installation (' . RCMAIL_VERSION . ')') .
+ html::tag('span', null, 'Please ' .
+ html::tag('a', array('href' => 'http://myroundcube.com/myroundcube-plugins/plugin-manager', 'target' => '_blank'), 'download') .
+ ' Plugin Manager package again and upload the entire package to your Roundcube\'s plugin folder.') . html::tag('br') . html::tag('br') .
+ html::tag('div', array('style' => 'display: inline; float: left'),
+ html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => 'document.location.href=\'./\''), $this->gettext('done'))
+ )
+ );
+ $this->register_handler('plugin.body', array($this, 'sqlerror'));
+ $this->rcmail->output->send('plugin');
+ }
+
+ $this->add_hook('login_after', array($this, 'login_after'));
+
+ if($this->rcmail->task == 'mail' && $this->rcmail->action == 'plugin.dla'){
+ if(file_exists(INSTALL_PATH . 'plugins/detach_attachments/detach_attachments.php')){
+ $this->require_plugin('detach_attachments');
+ }
+ }
+
+ if($this->rcmail->task == 'settings' && $this->rcmail->action == 'save-pref' && get_input_value('_name', RCUBE_INPUT_POST)){
+ $sql = 'DELETE FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $this->rcmail->db->query($sql, '_plugin_manager_hmail');
+ $save = get_input_value('_value', RCUBE_INPUT_POST);
+ $sql = 'INSERT INTO ' . get_table_name('plugin_manager') . ' (conf, value, type) VALUES (?, ?, ?)';
+ $this->rcmail->db->query($sql, '_plugin_manager_hmail', $save ? 1: 0, 'bool');
+ $this->rcmail->session->remove('plugin_manager_settings');
+ }
+
+ if(!isset($_SESSION['plugin_manager_settings'])){
+ $sql = 'SELECT * FROM ' . get_table_name('system') . ' WHERE ' . $this->q('name') . '=?';
+ $res = $this->rcmail->db->query($sql, 'myrc_plugin_manager');
+ $res = $this->rcmail->db->fetch_assoc($res);
+ if(is_array($res)){
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . ' LIKE ?';
+ $res = $this->rcmail->db->query($sql, '_plugin_manager_%');
+ if($res){
+ while($conf = $this->rcmail->db->fetch_assoc($res)){
+ $this->rcmail->config->set(substr($conf['conf'], 1), $conf['value']);
+ $_SESSION['plugin_manager_settings'][substr($conf['conf'], 1)] = $conf['value'];
+ }
+ }
+ }
+ }
+ else{
+ foreach($_SESSION['plugin_manager_settings'] as $key => $value){
+ $this->rcmail->config->set($key, $value);
+ }
+ }
+
+ $this->use_ssl = $this->rcmail->config->get('plugin_manager_use_ssl');
+ $this->use_hmail = $this->rcmail->config->get('plugin_manager_hmail');
+ $this->load_splitter = $this->rcmail->config->get('plugin_manager_load_splitter');
+ if($this->load_splitter && file_exists(INSTALL_PATH . 'plugins/load_splitter/load_splitter.php')){
+ $this->require_plugin('load_splitter');
+ }
+ else{
+ $this->load_splitter = false;
+ }
+ $this->maintenance_mode = $this->rcmail->config->get('plugin_manager_maintenance_mode');
+ $this->compress_html = $this->rcmail->config->get('plugin_manager_compress_html');
+ $this->file_based_config = $this->rcmail->config->get('plugin_manager_file_based_config');
+ $svn = parse_url($this->svn);
+ if($this->file_based_config || $_SERVER['HTTP_HOST'] == $svn['host']){
+ $this->file_based_config = true;
+ if(!in_array('global_config', $this->rcmail->config->get('plugins'))){
+ $this->load_config();
+ $this->require_plugin('settings');
+ }
+ $this->defaults = $this->rcmail->config->get('plugin_manager_defaults', array());
+ $this->unauth = $this->rcmail->config->get('plugin_manager_unauth', array());
+ $this->thirdparty = $this->rcmail->config->get('plugin_manager_third_party_plugins', array());
+ }
+ else{
+ $this->build_defaults();
+ if(!in_array('global_config', $this->rcmail->config->get('plugins'))){
+ $this->require_plugin('settings');
+ }
+ }
+ if($this->rcmail->config->get('plugin_manager_use_ssl', false) && defined('OPENSSL_VERSION_TEXT')){
+ $this->mirror = str_replace('http://', 'https://', $this->mirror);
+ $this->svn = str_replace('http://', 'https://', $this->svn);
+ $this->beta = str_replace('http://', 'https://', $this->beta);
+ $this->billingurl = str_replace('http://', 'https://', $this->billingurl);
+ }
+
+ if($hash = $this->rcmail->config->get('plugin_manager_hash')){
+ if(file_exists(INSTALL_PATH . $hash . '.myrc')){
+ $this->config_permissions = true;
+ }
+ }
+ $fileadmins = $this->rcmail->config->get('plugin_manager_admins');
+ if($this->rcmail->task == 'settings' && $_SESSION['plugin_manager_admins']){
+ $this->admins = $_SESSION['plugin_manager_admins'];
+ }
+ else if($this->rcmail->task == 'settings' && !isset($_GET['_remote'])){
+ $this->admins = array();
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'admins');
+ if($res){
+ $admins = $this->rcmail->db->fetch_assoc($res);
+ if($admins = unserialize($admins['value'])){
+ $this->rcmail->config->set('plugin_manager_admins', $admins);
+ $this->admins = array_flip($admins);
+ $_SESSION['plugin_manager_admins'] = $this->admins;
+ }
+ }
+ if(count($this->admins) < 1 && strtolower($this->get_demo($_SESSION['username'])) != strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ if($this->rcmail->task == 'settings' && !isset($_GET['_remote'])){
+ if(!$hash = $this->rcmail->config->get('plugin_manager_hash')){
+ $hash = session_id();
+ $this->rcmail->user->save_prefs(array('plugin_manager_hash' => $hash));
+ }
+ else{
+ if(!file_exists(INSTALL_PATH . $hash . '.myrc') && !isset($_GET['_framed'])){
+ $this->register_handler('plugin.body', array($this, 'authenticate'));
+ $this->rcmail->output->send('plugin');
+ }
+ else{
+ $query = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($query, 0, 1, 'admins');
+ $res = $this->rcmail->db->fetch_assoc($res);
+ if(is_array($res)){
+ $admins = unserialize($res['value']);
+ }
+ else{
+ $query = 'INSERT INTO ' . get_table_name('plugin_manager') . ' (' .
+ $this->q('conf') . ', ' .
+ $this->q('value') . ', ' .
+ $this->q('type') .
+ ') VALUES (?, ?, ?)';
+ $superadmin = array($this->rcmail->user->data['username']);
+ $this->rcmail->db->query($query, 'admins', serialize($superadmin), 'array');
+ $this->rcmail->config->set('plugin_manager_admins', $superadmin);
+ $this->admins = array_flip($superadmin);
+ $_SESSION['plugin_manager_admins'] = $this->admins;
+ }
+ }
+ }
+ }
+ }
+ else if($this->rcmail->task != 'logout' && strtolower($this->get_demo($_SESSION['username'])) != strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $admins = $this->rcmail->config->get('plugin_manager_admins', array());
+ if($admins[0] == strtolower($this->rcmail->user->data['username'])){
+ if(!$hash = $this->rcmail->config->get('plugin_manager_hash')){
+ $hash = session_id();
+ $this->rcmail->user->save_prefs(array('plugin_manager_hash' => $hash));
+ }
+ else{
+ if(!file_exists(INSTALL_PATH . $hash . '.myrc') && !isset($_GET['_framed'])){
+ $this->register_handler('plugin.body', array($this, 'authenticate'));
+ $this->rcmail->output->send('plugin');
+ }
+ }
+ }
+ }
+ $hash = $this->rcmail->config->get('plugin_manager_hash');
+ if(is_array($fileadmins) && file_exists(INSTALL_PATH . $hash . '.myrc')){
+ $this->rcmail->session->remove('plugin_manager_admins');
+ $sql = 'UPDATE ' . get_table_name('plugin_manager') . ' SET ' . $this->q('value') . '=? WHERE ' . $this->q('conf') . '=?';
+ $this->rcmail->db->query($sql, serialize($fileadmins), 'admins');
+ $this->out = html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -200px; width: 400px;'),
+ html::tag('h3', null, 'Plugin Manager detected a misconfiguration') .
+ html::tag('span', null, 'Please remove ' . '$config[\'plugin_manager_admins\'] from your configuration file.') . html::tag('br') . html::tag('br') .
+ html::tag('pre', null, print_r($fileadmins, true)) .
+ html::tag('div', array('style' => 'display: inline; float: right'),
+ html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => 'document.location.href=\'./?_task=settings\''), $this->gettext('done'))
+ )
+ );
+ $this->register_handler('plugin.body', array($this, 'sqlerror'));
+ $this->rcmail->output->send('plugin');
+ }
+ }
+
+ if($this->rcmail->action != 'jappix.loadmini'){
+ $this->add_texts('localization/', false);
+
+ $this->add_hook('render_page', array($this, 'render_page'));
+ $this->add_hook('send_page', array($this, 'send_page'));
+ $this->add_hook('preferences_sections_list', array($this, 'settings_link'));
+ $this->add_hook('preferences_list', array($this, 'settings'));
+ $this->add_hook('preferences_save', array($this, 'saveprefs'));
+ $this->add_hook('plugins_installed', array($this, 'plugins_installed'));
+
+ $this->register_action('plugin.plugin_manager', array($this, 'navigation'));
+ $this->register_action('plugin.plugin_manager_save', array($this, 'save'));
+ $this->register_action('plugin.plugin_manager_uninstall', array($this, 'uninstall'));
+ $this->register_action('plugin.plugin_manager_update', array($this, 'update'));
+ $this->register_action('plugin.plugin_manager_bind', array($this, 'bind'));
+ $this->register_action('plugin.plugin_manager_unbind', array($this, 'unbind'));
+ $this->register_action('plugin.plugin_manager_getnew', array($this, 'getnew'));
+ $this->register_action('plugin.plugin_manager_deny', array($this, 'deny'));
+ $this->register_action('plugin.plugin_manager_show_config', array($this, 'show'));
+ $this->register_action('plugin.plugin_manager_save_config', array($this, 'save_config'));
+ $this->register_action('plugin.plugin_manager_edit_config', array($this, 'edit_config'));
+ $this->register_action('plugin.plugin_manager_restore_config', array($this, 'restore_config'));
+ $this->register_action('plugin.plugin_manager_accept', array($this, 'accept'));
+ $this->register_action('plugin.plugin_manager_transfer', array($this, 'transfer'));
+ $this->register_action('plugin.plugin_manager_getcredits', array($this, 'getcredits'));
+ $this->register_action('plugin.plugin_manager_buycredits', array($this, 'buycredits'));
+ //$this->register_action('plugin.plugin_manager_compress', array($this, 'compress'));
+ $this->register_action('plugin.plugin_manager_update_notifier', array($this, 'update_notifier'));
+
+ $this->include_script('plugin_manager_fixes.js');
+ if(!$_SESSION['pm_cache']['pm_version'] || $_SESSION['pm_cache']['pm_version']['time'] < time() - 3600){
+ if(isset($this->admins[$this->rcmail->user->data['username']])){
+ $skin = $this->rcmail->config->get('skin');
+ if(!file_exists($this->home . '/skins/' . $skin . '/plugin_manager_update.css')){
+ $skin = 'classic';
+ }
+ $httpConfig['method'] = 'GET';
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_pmversion';
+ $httpConfig['timeout'] = '30';
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ if($http->error){
+ $this->mirror = str_replace('https://', 'http://', $this->mirror);
+ $this->svn = str_replace('https://', 'http://', $this->svn);
+ $this->beta = str_replace('https://', 'http://', $this->beta);
+ $this->billingurl = str_replace('https://', 'http://', $this->billingurl);
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_pmversion';
+ $http->initialize($httpConfig);
+ $http->execute();
+ if($http->error){
+ $this->mirror = str_replace('.com', '.net', $this->mirror);
+ $this->svn = str_replace('.com', '.net', $this->svn);
+ $this->beta = str_replace('.com', '.net', $this->beta);
+ $this->billingurl = str_replace('.com', '.net', $this->billingurl);
+ $this->guide = str_replace('.com', '.net', $this->guide);
+ $this->dlurl = str_replace('.com', '.net', $this->dlurl);
+ // find me: remove when myroundcube.net SSL is available
+ $this->dlurl = str_replace('https://', 'http://', $this->dlurl);
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_pmversion';
+ $http->initialize($httpConfig);
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ }
+ }
+ if(!preg_match('/^[0-9\.|]+$/', trim($http->result)) || count(explode('|', $http->result)) != 2){
+ $this->mirror = str_replace('https://', 'http://', $this->mirror);
+ $this->svn = str_replace('https://', 'http://', $this->svn);
+ $this->beta = str_replace('https://', 'http://', $this->beta);
+ $this->billingurl = str_replace('https://', 'http://', $this->billingurl);
+ // find me: remove when myroundcube.net SSL is available
+ $this->dlurl = str_replace('https://', 'http://', $this->dlurl);
+ $this->mirror = str_replace('.com', '.net', $this->mirror);
+ $this->svn = str_replace('.com', '.net', $this->svn);
+ $this->beta = str_replace('.com', '.net', $this->beta);
+ $this->billingurl = str_replace('.com', '.net', $this->billingurl);
+ $this->guide = str_replace('.com', '.net', $this->guide);
+ $this->dlurl = str_replace('.com', '.net', $this->dlurl);
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_pmversion';
+ $http->initialize($httpConfig);
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ }
+ if($this->debug){
+ write_log('plugin_manager', $httpConfig);
+ write_log('plugin_manager', $_SERVER['SERVER_ADDR']);
+ write_log('plugin_manager', self::$version);
+ write_log('plugin_manager', $http);
+ }
+ if(!preg_match('/^[0-9\.|]+$/', trim($http->result)) || count(explode('|', $http->result)) != 2){
+ $this->noremote = true;
+ $http->result = 'error';
+ }
+ $response = $http->result;
+ $_SESSION['pm_cache']['pm_version'] = array(
+ 'error' => $http->error,
+ 'response' => $http->result,
+ 'urls' => array(
+ 'mirror' => $this->mirror,
+ 'svn' => $this->svn,
+ 'beta' => $this->beta,
+ 'billingurl' => $this->billingurl,
+ 'dlurl' => $this->dlurl,
+ 'guide' => $this->guide,
+ ),
+ 'time' => time(),
+ );
+ if(is_array($_SESSION['pm_cache']['pm_version']['urls'])){
+ foreach($_SESSION['pm_cache']['pm_version']['urls'] as $key => $url){
+ $this->$key = $url;
+ }
+ }
+ if(isset($_SESSION['pm_cache']) && !$_SESSION['pm_cache']['pm_version']['error']){
+ $temp = explode('|', $_SESSION['pm_cache']['pm_version']['response'], 2);
+ if($response == 'error'){
+ $this->noremote = true;
+ if(!get_input_value('_remote', RCUBE_INPUT_GPC) && !get_input_value('_framed', RCUBE_INPUT_GPC)){
+ $this->include_stylesheet('skins/' . $skin . '/plugin_manager_update.css');
+ $this->api->output->add_footer(html::tag('div', array('class' => 'myrcerror myrcmessage'), html::tag('span', null, $this->gettext('myrcerror'))));
+ }
+ }
+ else if(self::$version != $temp[0]){
+ if(self::$version < $temp[1]){
+ $this->rcmail->session->remove('pm_update_message');
+ }
+ if((!$_SESSION['pm_update_message']) && !get_input_value('_framed', RCUBE_INPUT_GPC) && $this->rcmail->action != 'about'){
+ if(version_compare(self::$version, $temp[1], '<')){
+ $this->noremote = true;
+ $this->delay = 500000;
+ $_SESSION['pm_update_message'] = true;
+ if(!get_input_value('_remote', RCUBE_INPUT_GPC)){
+ $this->include_stylesheet('skins/' . $skin . '/plugin_manager_update.css');
+ $this->api->output->add_footer(html::tag('div', array('class' => 'updatepmrequired myrcmessage', 'onclick' => 'document.location.href="' . slashify($this->svn) . '?_action=plugin.plugin_server_get_pm"; $(this).hide("slow");'),
+ html::tag('span', null, $this->gettext('updatepmrequired')) .
+ ((strpos($skin, 'litecube') !== false) ? '&nbsp;' : html::tag('br')) .
+ html::tag('span', array('style' => 'text-decoration:underline;'), $this->gettext('downloadnow'))
+ ));
+ }
+ }
+ else if(version_compare(self::$version, $temp[0], '<')){
+ $this->delay = 30000;
+ //$_SESSION['pm_update_message'] = true;
+ if(!get_input_value('_remote', RCUBE_INPUT_GPC)){
+ $this->include_stylesheet('skins/' . $skin . '/plugin_manager_update.css');
+ $this->api->output->add_footer(html::tag('div', array('class' => 'updatepm myrcmessage', 'onclick' => 'document.location.href="' . slashify($this->svn) . '?_action=plugin.plugin_server_get_pm"; $(this).hide("slow");'),
+ html::tag('span', null, $this->gettext('updatepm')) .
+ ((strpos($skin, 'litecube') !== false) ? '&nbsp;' : html::tag('br')) .
+ html::tag('span', array('style' => 'text-decoration:underline;'), $this->gettext('downloadnow'))
+ ));
+ }
+ }
+ }
+ }
+ }
+ else if(isset($_SESSION['pm_cache']) && $_SESSION['pm_cache']['pm_version']['error']){
+ $this->delay = 8000;
+ $this->noremote = true;
+ if(!get_input_value('_remote', RCUBE_INPUT_GPC) && !get_input_value('_framed', RCUBE_INPUT_GPC)){
+ $this->include_stylesheet('skins/' . $skin . '/plugin_manager_update.css');
+ $this->api->output->add_footer(html::tag('div', array('class' => 'myrcerror myrcmessage'), html::tag('span', null, $this->gettext('myrcerror'))));
+ }
+ }
+ $httpConfig['method'] = 'GET';
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_branches';
+ $httpConfig['timeout'] = '30';
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ $http->execute();
+ if($http->error){
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_branches';
+ $http->initialize($httpConfig);
+ $http->execute();
+ }
+ if(!$http->error){
+ if($branches = unserialize($http->result)){
+ $this->dev = $branches['dev'];
+ $this->stable = $branches['stable'];
+ }
+ }
+ $map = array(
+ 'frozen' => 'mirror',
+ 'stable' => 'svn',
+ 'beta' => 'beta'
+ );
+ foreach($map as $host => $map){
+ if($host = $branches['branches'][$host]){
+ $temp1 = parse_url($this->$map);
+ $temp2 = explode('.', $temp1['host']);
+ $temp3 = parse_url($host);
+ $subdomain = current(explode('.', $temp3['host']));
+ $this->$map = $temp1['scheme'] . '://' . $subdomain . '.' . $temp2[1] . '.' . $temp2[2];
+ }
+ else{
+ $this->$map = false;
+ }
+ }
+ if(!$_SESSION['pm_update_message'] && $_SESSION['user_id'] && $this->rcmail->task != 'logout' && !get_input_value('_framed', RCUBE_INPUT_GPC) && $this->rcmail->config->get('plugin_manager_show_myrc_messages', false)){
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_motd';
+ $http->initialize($httpConfig);
+ $http->execute();
+ if($http->error){
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_motd';
+ $http->initialize($httpConfig);
+ $http->execute();
+ }
+ if(!$http->error){
+ if($http->result != ''){
+ $this->delay = 30000;
+ $_SESSION['pm_update_message'] = true;
+ if(!get_input_value('_remote', RCUBE_INPUT_GPC)){
+ $this->include_stylesheet('skins/' . $skin . '/plugin_manager_update.css');
+ $this->api->output->add_footer(html::tag('div', array('class' => 'motd myrcmessage'),
+ html::tag('span', null, html::tag('div', array('style' => 'float: right'), html::tag('small', null, '[' . html::tag('a', array('href' => '#', 'onclick' => '$(".myrcmessage").hide()', 'title' => $this->gettext('close')), 'x') .']')) . $http->result)
+ ));
+ }
+ }
+ }
+ }
+ }
+ if(count($this->admins) == 0 &&
+ ($_SERVER['QUERY_STRING'] == '_task=settings&_action=edit-prefs&_section=plugin_manager_update&_framed=1' ||$_SERVER['QUERY_STRING'] == '_task=settings&_action=edit-prefs&_section=plugin_manager_customer&_framed=1')
+ ){
+ $this->rcmail->output->add_script('parent.location.href="./?_task=settings"', 'docready');
+ }
+ }
+
+ /* uninstall requests */
+ /* google_contacts */
+ $this->register_action('plugin.google_contacts_uninstall', array($this, 'google_contacts_uninstall'));
+ /* automatic_addressbook */
+ $this->register_action('plugin.automatic_addressbook_uninstall', array($this, 'automatic_addressbook_uninstall'));
+ }
+
+ $this->plugins = $this->rcmail->config->get('plugins', array());
+
+ $this->host = strtolower($_SERVER['HTTP_HOST']);
+ $temparr = explode('@', $_SESSION['username']);
+ $this->domain = strtolower($temparr[1]);
+ if($this->domain == ''){
+ $host = $this->rcmail->user->data['mail_host'];
+ if($host == 'localhost'){
+ $host = $_SERVER['HTTP_HOST'];
+ }
+ $this->domain = $host;
+ }
+ $this->merge_config();
+ $deferred = array();
+ foreach($this->config as $sections => $section){
+ foreach($section as $plugin => $props){
+ if(isset($this->config[$sections][$plugin])){
+ if($props['active']){
+ $load = true;
+ if(is_array($props['hosts']) && count($props['hosts'] > 0)){
+ $load = false;
+ foreach($props['hosts'] as $host){
+ if($this->host == strtolower($host)){
+ $load = true;
+ break;
+ }
+ }
+ }
+ if($this->domain){
+ if($props['domain'] === true){
+ $load = true;
+ }
+ else if(is_array($props['domains']) && count($props['domains'] > 0)){
+ $load = false;
+ foreach($props['domains'] as $domain){
+ if($this->domain == strtolower($domain)){
+ $load = true;
+ break;
+ }
+ }
+ }
+ }
+ if(is_array($props['skins'])){
+ $props['skins'] = array_flip($props['skins']);
+ if(!isset($props['skins'][$this->rcmail->config->get('skin', 'classic')])){
+ $load = false;
+ }
+ }
+ if($load){
+ if($file = @file_get_contents(INSTALL_PATH . '/plugins/' . $plugin . '/' . $plugin . '.php')){
+ $file = str_replace(' ', '', $file);
+ $file = current(explode('functioninit(', $file, 2));
+ $task = explode('$task', $file, 2);
+ $task = explode('=', $task[1], 2);
+ $task = explode(';', $task[1], 2);
+ $task = str_replace(array('"', "'"), array('', ''), trim($task[0]));
+ $noajax = explode('$noajax', $file, 2);
+ $noajax = explode('=', $noajax[1], 2);
+ $noajax = explode(';', $noajax[1], 2);
+ $noajax = str_replace(array('"', "'"), array('', ''), trim($noajax[0]));
+ $noframe = explode('$noframe', $file, 2);
+ $noframe = explode('=', $noframe[1], 2);
+ $noframe = explode(';', $noframe[1], 2);
+ $noframe = str_replace(array('"', "'"), array('', ''), trim($noajax[0]));
+ if($task){
+ if(!preg_match('/^(' . $task . ')$/i', $this->rcmail->task)){
+ $noajax = false;
+ $noframe = false;
+ $load = false;
+ }
+ }
+ if($noajax && ($noajax == 'true' || $noajax == '1')){
+ if(isset($_REQUEST['_remote'])){
+ $noframe = false;
+ $load = false;
+ }
+ }
+ if($noframe && ($noframe == 'true' || $noframe == '1')){
+ if(isset($_REQUEST['_framed'])){
+ $load = false;
+ }
+ }
+ }
+ }
+ if($load && !$this->maintenance_mode){
+ if($props['browser']){
+ if(!$browser)
+ $browser = new rcube_browser();
+ eval($props['browser']);
+ if($test){
+ if($props['defer']){
+ $deferred[] = $plugin;
+ }
+ else{
+ if($plugin != 'load_splitter'){
+ $this->require_plugin($plugin);
+ }
+ }
+ }
+ }
+ else if($props['defer']){
+ $deferred[] = $plugin;
+ }
+ else{
+ if($plugin != 'load_splitter'){
+ $this->require_plugin($plugin);
+ }
+ }
+ }
+ }
+ else{
+ if($props['eval']){
+ if(!is_array($props['eval'])){
+ $eval = array($props['eval']);
+ }
+ else{
+ $eval = $props['eval'];
+ }
+ foreach($eval as $code){
+ eval($code);
+ }
+ }
+ }
+ }
+ }
+ }
+ if(!$this->maintenance_mode){
+ foreach($deferred as $plugin){
+ $this->require_plugin($plugin);
+ }
+ }
+ }
+
+ static public function about($keys = false){
+ $requirements = self::$requirements;
+ foreach(array('required_', 'recommended_') as $prefix){
+ if(is_array($requirements[$prefix.'plugins'])){
+ foreach($requirements[$prefix.'plugins'] as $plugin => $method){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $class->about($keys),
+ );
+ }
+ else{
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $plugin,
+ );
+ }
+ }
+ }
+ }
+ $config = array();
+ $ret = array(
+ 'plugin' => self::$plugin,
+ 'version' => self::$version,
+ 'db_version' => self::$db_version,
+ 'date' => self::$date,
+ 'author' => self::$author,
+ 'comments' => self::$authors_comments,
+ 'licence' => self::$licence,
+ 'download' => self::$download,
+ 'requirements' => $requirements,
+ );
+ if(is_array(self::$prefs))
+ $ret['config'] = array_merge($config, array_flip(self::$prefs));
+ else
+ $ret['config'] = $config;
+ if(is_array($keys)){
+ $return = array('plugin' => self::$plugin);
+ foreach($keys as $key){
+ $return[$key] = $ret[$key];
+ }
+ return $return;
+ }
+ else{
+ return $ret;
+ }
+ }
+
+ function update_notifier(){
+ $_SESSION['plugin_manager_update_notifier'] = true;
+ $server = array();
+ $updates = array();
+ $dir = scandir(INSTALL_PATH . 'plugins');
+ foreach($dir as $dirname){
+ if($dirname != '.' && $dirname != '..' && is_dir(INSTALL_PATH . 'plugins/' . $dirname) && file_exists(INSTALL_PATH . 'plugins/' . $dirname . '/' . $dirname . '.php')){
+ $server[$dirname] = 1;
+ }
+ }
+ if(!empty($server)){
+ $params = array();
+ $httpConfig['method'] = 'GET';
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_update_notifier';
+ $httpConfig['timeout'] = '30';
+ $httpConfig['params'] = $params;
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ if($http->error){
+ $response = false;
+ }
+ else{
+ $response = $http->result;
+ }
+ if($mirror = json_decode($response, true)){
+ if(is_array($mirror)){
+ $sql = 'SELECT value FROM ' . get_table_name('system') . ' WHERE name=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'myrc_plugin_manager_updates_hash');
+ $value = $this->rcmail->db->fetch_assoc($res);
+ if(is_array($value)){
+ $value = current($value);
+ }
+ else{
+ $value = '';
+ }
+ if($value != md5($response)){
+ $sql = 'DELETE FROM ' . get_table_name('system') . ' WHERE name=?';
+ $this->rcmail->db->query($sql, 'myrc_plugin_manager_updates_hash');
+ $sql = 'INSERT INTO ' . get_table_name('system') . '(name, value) VALUES (?, ?)';
+ $this->rcmail->db->query($sql, 'myrc_plugin_manager_updates_hash', md5($response));
+ $sql = 'DELETE FROM ' . get_table_name('system') . ' WHERE name=?';
+ $this->rcmail->db->query($sql, 'myrc_plugin_manager_updates_last');
+ $sql = 'INSERT INTO ' . get_table_name('system') . '(name, value) VALUES (?, ?)';
+ $this->rcmail->db->query($sql, 'myrc_plugin_manager_updates_last', date('Y-m-d H:i:s'));
+ foreach($server as $plugin => $null){
+ if(isset($mirror[$plugin])){
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/' . $plugin . '.php')){
+ $this->require_plugin($plugin);
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $props = $class->about('version', 'date');
+ if(version_compare($props['version'], $mirror[$plugin]['version'], '<')){
+ $updates[$plugin] = array('server' => $props['version'], 'mirror' => $mirror[$plugin]['version']);
+ }
+ }
+ }
+ }
+ }
+ }
+ $rows = html::tag('tr', null, html::tag('th', array('align' => 'left', 'style' => 'border: 1px solid grey'), 'Plugin') . html::tag('th', array('align' => 'right', 'style' => 'border: 1px solid grey'), 'Locale Version') . html::tag('th', array('align' => 'right', 'style' => 'border: 1px solid grey'), 'Remote Version') . html::tag('th', array('align' => 'right', 'style' => 'border: 1px solid grey'), '&nbsp;'));
+ if(!empty($updates)){
+ foreach($updates as $plugin => $props){
+ $rows .= html::tag('tr', null, html::tag('td', array('style' => 'border: 1px solid grey'), $plugin) . html::tag('td', array('align' => 'right', 'style' => 'border: 1px solid grey'), $props['server']) . html::tag('td', array('align' => 'right', 'style' => 'border: 1px solid grey'), $props['mirror']) . html::tag('td', array('align' => 'right', 'style' => 'border: 1px solid grey'), html::tag('a', array('href' => 'https://myroundcube.com/myroundcube-plugins/show-changelog?_plugin=' . $plugin), 'CHANGELOG')));
+ }
+ $table = html::tag('table', array('cellpadding' => 4, 'cellspacing' => 0, 'style' => 'border: 1px solid grey'), $rows);
+ $body = 'Hello,<br /><br />There are plugins updates available for your Roundcube installation at <i>' . $this->gethost() . '</i>, <i>' . INSTALL_PATH . '</i>:<br /><br />' . $table . '<br /><br />Greetings,<br />MyRoundcube Support<br />(c) ';
+ $body .= html::tag('a', array('href' => 'http://myroundcube.com'), 'MyRoundcube.com') . ' 2012-' . date('Y') . '<br /><br />';
+ $body .= html::tag('div', array('style' => 'text-align:justify;'), 'You are receiving this email notification from Plugin Manager. If you no longer wish to receive updates notifications, please disable the <i>Update Notifications</i> option in your Roundcube installation <i>(Settings&nbsp;&raquo;&nbsp;Manage&nbsp;Plugins&nbsp;&raquo;&nbsp;Settings)</i>.');
+ $body = html::tag('div', array('style' => 'width: 580px'), $body);
+ $sql = 'SELECT value FROM ' . get_table_name('plugin_manager') . ' WHERE conf=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'admins');
+ $admins = $this->rcmail->db->fetch_assoc($res);
+ if(is_array($admins)){
+ $admins = unserialize(current($admins));
+ if(is_array($admins)){
+ $subject = 'MyRoundcube Plugins Updates available';
+ $cc = $this->rcmail->config->get('plugin_manager_update_notifications_cc');
+ /*
+ $from = rcube_user::user2email($this->rcmail->user->data['username'], false, true);
+ if(!$from){
+ $from = $this->rcmail->user->data['username'];
+ }
+ */
+ foreach($admins as $admin){
+ $to = rcube_user::user2email($admin, false, true);
+ if(!$to){
+ $to = $admin;
+ }
+ $this->sendmail($to, $to, false, $subject, $body);
+ }
+ if($cc){
+ $this->sendmail($to, false, $cc, $subject, $body);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ function plugins_installed($plugins){
+ unset($plugins['abort']);
+ $conf = $this->defaults;
+ foreach($conf as $section){
+ foreach($section as $plugin => $props){
+ if($props['protected']){
+ if($props['active']){
+ $plugins[] = $plugin;
+ }
+ }
+ else{
+ $plugins[] = $plugin;
+ }
+ }
+ }
+ if(file_exists(INSTALL_PATH . 'plugins/calendar_plus/calendar_plus.php') && in_array('calendar', $plugins)){
+ $plugins = array_merge($plugins, array('calendar_plus'));
+ }
+ $plugs = $plugins;
+ foreach($plugins as $key => $plugin){
+ $this->require_plugin($plugin);
+ if(method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $about = $class->about();
+ $requirements = (array) $about['requirements'];
+ foreach($requirements as $requirement => $props){
+ if($requirement == 'required_plugins'){
+ foreach($props as $plugin => $method){
+ if($method['method'] == 'require_plugin'){
+ $plugs[] = $plugin;
+ }
+ }
+ }
+ }
+ }
+ }
+ return $plugs;
+ }
+
+ function build_defaults(){
+ if($_SESSION['plugin_manager_defaults'] && !isset($_SESSION['plugin_manager_admins'][strtolower($this->rcmail->user->data['username'])])){
+ $this->defaults = $_SESSION['plugin_manager_defaults'];
+ $this->unauth = $_SESSION['plugin_manager_unauth'];
+ return;
+ }
+ include INSTALL_PATH . 'plugins/plugin_manager/defaults.inc.php';
+ $defaults = $config['plugin_manager_defaults'];
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'defaults_overwrite');
+ $overwrite = $this->rcmail->db->fetch_assoc($res);
+ if(is_array($overwrite)){
+ if($overwrite = unserialize($overwrite['value'])){
+ $depricate = false;
+ foreach($overwrite as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ if(isset($defaults[$section][$plugin]['deprecated'])){
+ if(RCMAIL_VERSION > $defaults[$section][$plugin]['deprecated']){
+ unset($overwrite[$section][$plugin]);
+ $deprecate = true;
+ }
+ }
+ foreach($props as $prop => $value){
+ $defaults[$section][$plugin][$prop] = $value;
+ }
+ }
+ }
+ if($deprecate){
+ $sql = 'UPDATE ' . get_table_name('plugin_manager') . ' SET ' . $this->q('value') . '=? WHERE ' . $this->q('conf') . '=?';
+ $this->rcmail->db->query($sql, serialize($overwrite), 'defaults_overwrite');
+ }
+ }
+ }
+ foreach($defaults as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ if(!file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/' . $plugin . '.php')){
+ unset($defaults[$section][$plugin]);
+ }
+ else if(substr($plugin, 0, strlen('hmail_')) == 'hmail_' && !$this->use_hmail){
+ unset($defaults[$section][$plugin]);
+ }
+ else{
+ if(isset($config['plugin_manager_unauth'][$plugin])){
+ $this->unauth[$plugin] = true;
+ }
+ }
+ }
+ }
+ $sql = 'SELECT ' . $this->q('value') . ' FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'defaults');
+ $overwrite = $this->rcmail->db->fetch_assoc($res);
+ if(is_array($overwrite)){
+ if($overwrite = unserialize($overwrite['value'])){
+ foreach($overwrite as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ foreach($props as $prop => $value){
+ if(isset($defaults[$section][$plugin])){
+ $true = true;
+ if(is_bool($defaults[$section][$plugin][$prop])){
+ $defaults[$section][$plugin][$prop] = $value ? true : false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ foreach($defaults as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ if(isset($defaults[$section][$plugin]['deprecated'])){
+ if(RCMAIL_VERSION > $defaults[$section][$plugin]['deprecated']){
+ unset($defaults[$section][$plugin]);
+ }
+ }
+ }
+ }
+ $this->defaults = $defaults;
+ $_SESSION['plugin_manager_defaults'] = $defaults;
+ $_SESSION['plugin_manager_unauth'] = $this->unauth;
+ $this->thirdparty = $config['plugin_manager_third_party_plugins'];
+ }
+
+ function sqlerror($p){
+ return $this->out;
+ }
+
+ function authenticate($p){
+ $rcmail = rcmail::get_instance();
+ $this->add_texts('localization/');
+ $hash = $this->rcmail->config->get('plugin_manager_hash');
+ $out = html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -225px; width: 450px;'),
+ html::tag('h3', null, $this->gettext('welcome_to_plugin_manager')) .
+ $this->gettext('about_to_create_account') . ' ' .
+ $this->gettext('create_account_proceed') . ' ' .
+ $this->gettext('please_create') . html::tag('br') . html::tag('br') .
+ html::tag('b', null, html::tag('center', null, $hash . '.myrc')) . html::tag('br') . html::tag('br') .
+ html::tag('div', array('style' => 'display: block; float: left;'), $this->gettext('thank_you')) .
+ html::tag('div', array('style' => 'display: block; float: right;'), html::tag('a', array('href' => './?_task=settings'), $this->gettext('done'))) . html::tag('br') .
+ html::tag('hr') .
+ html::tag('div', array('style' => 'font-size: 10px;'), '&copy;&nbsp;2012 - ' . date('Y') . '&nbsp;MyRoundcube.com. All rights reserved.')
+ );
+ $this->rcmail->output->add_script('$(".button-settings").attr("onclick", "document.location.href=\'./?_task=settings\'")', 'docready');
+ return $out;
+ }
+
+ function login_after($args){
+ $active = $this->rcmail->config->get('plugin_manager_active', array());
+ if(!$active){
+ $this->build_defaults();
+ foreach($this->defaults as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ if($props['active']){
+ $active[$plugin] = 1;
+ }
+ else{
+ $active[$plugin] = 0;
+ }
+ }
+ }
+ $this->rcmail->user->save_prefs(array('plugin_manager_active' => $active));
+ }
+ return $args;
+ }
+
+ function render_page($p){
+ $this->template = $p['template'];
+ if($this->template == 'settings'){
+ if($next = get_input_value('_next', RCUBE_INPUT_GET)){
+ $this->rcmail->output->add_script('window.setTimeout(\'$("#rcmrow' . $next . '").trigger("mousedown").trigger("mouseup")\', 500);', 'docready');
+ }
+ }
+ else if($this->template == 'mail'){
+ if($this->rcmail->config->get('plugin_manager_update_notifications')){
+ if(!isset($_SESSION['plugin_manager_update_notifier'])){
+ $sql = 'SELECT value FROM ' . get_table_name('system') . ' WHERE name=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'myrc_plugin_manager_updates_last');
+ $last = $this->rcmail->db->fetch_assoc($res);
+ if(is_array($last)){
+ $last = strtotime(current($last));
+ }
+ else{
+ $last = 0;
+ }
+ if($last + 86400 < time()){
+ $this->rcmail->output->add_script("rcmail.http_request('plugin.plugin_manager_update_notifier');", 'docready');
+ }
+ }
+ }
+ }
+ if(!get_input_value('_framed', RCUBE_INPUT_GET)){
+ if($this->maintenance_mode){
+ $this->rcmail->output->show_message($this->gettext('running_in_maintenance_mode'), 'warning');
+ }
+ if(!$this->rcmail->config->get('plugin_manager_about_link', true)){
+ $this->rcmail->output->add_script('$(".about-link").hide();', 'foot');
+ }
+ if(!$this->rcmail->config->get('plugin_manager_support_link', true)){
+ if($this->rcmail->action != 'jappix.loadmini'){
+ $this->rcmail->output->add_script('$(".support-link").hide();', 'docready');
+ }
+ }
+ if($section = get_input_value('_plugin_manager_settings_section', RCUBE_INPUT_GET)){
+ $this->rcmail->output->set_env('section', $section);
+ $src = './?_task=settings&_action=edit-prefs&_section=plugin_manager_settings&_framed=1&_expand=' . get_input_value('_expand', RCUBE_INPUT_GET);
+ if($this->rcmail->config->get('skin', 'classic') != 'classic'){
+ $this->rcmail->output->add_script("$('#rcmrowplugin_manager_settings').addClass('selected focused'); $('#preferences-frame').attr('src', '" . $src . "');", 'docready');
+ }
+ else{
+ $this->rcmail->output->add_script("$('#rcmrowplugin_manager_settings').addClass('selected focused'); $('#prefs-frame').attr('src', '" . $src . "');", 'docready');
+ }
+ }
+ if(!class_exists('tabbed')){
+ $this->rcmail->output->add_script('window.setTimeout("$(\'.myrcmessage\').hide(\'slow\');", ' . $this->delay . ');', 'docready');
+ }
+ else{
+ $this->rcmail->output->set_env('pm_message_delay', $this->delay);
+ }
+ if($this->rcmail->config->get('plugin_manager_myroundcube_watermark', true) || $this->rcmail->config->get('plugin_manager_remove_watermark', false)){
+ if(strtolower($this->rcmail->user->data['username']) != $this->rcmail->config->get('mysql_admin') || !class_exists('mysqladmin')){
+ $repl = 'myroundcube.html';
+ if($this->rcmail->config->get('plugin_manager_remove_watermark', false)){
+ $repl = 'blank.html';
+ }
+ switch($p['template']){
+ case 'settings':
+ case 'addressbook':
+ case 'identities':
+ case 'folders':
+ case 'mail':
+ $p['content'] = str_replace('skins/' . $this->rcmail->config->get('skin', 'classic') . '/watermark.html', 'plugins/plugin_manager/skins/' . $this->rcmail->config->get('skin', 'classic') . '/' . $repl, $p['content']);
+ $this->rcmail->output->set_env('blankpage', 'plugins/plugin_manager/skins/' . $this->rcmail->config->get('skin', 'classic') . '/' . $repl);
+ }
+ }
+ }
+ }
+ return $p;
+ }
+
+ function send_page($p){
+ if($this->compress_html){
+ $p = $this->html_compress($p);
+ }
+ else{
+ $temp = explode('.', $this->template);
+ $plugin = $temp[0];
+ if(count($temp == 2)){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $about = $class->about(array('version', 'date'));
+ if($temp[0] && $temp[1]){
+ $comment = '<!-- Plugin: ' . $temp[0] . ', Version: ' . $about['version'] . ' - ' . date('Y-m-d', strtotime($about['date'])) . ', Template: ' . $temp[1] . '.html -->';
+ $temp = explode('<head', $p['content'], 2);
+ $p['content'] = $temp[0] . $comment . "\r\n<head" . $temp[1];
+ }
+ }
+ }
+ }
+ return $p;
+ }
+
+ function navigation(){
+ if($section = get_input_value('_section', RCUBE_INPUT_GPC)){
+ $this->rcmail->output->add_script("$(document).ready(function(){ rcmail.addEventListener('init', function(){ rcmail.sections_list.select('" . $section . "') }); })", 'foot');
+ }
+ }
+
+ function merge_config(){
+ $this->config = $this->defaults;
+ if($this->rcmail->user->ID && $this->rcmail->task != 'logout'){
+ $active = $this->rcmail->config->get('plugin_manager_active', array());
+ }
+ else{
+ $active = $this->unauth;
+ }
+ foreach($this->config as $sections => $section){
+ foreach($section as $plugin => $props){
+ if(in_array($plugin, $this->plugins)){
+ $branch = $this->mirror;
+ if(RCMAIL_VERSION > '0.7')
+ $branch = $this->svn;
+ $error = html::tag('h3', array('align' => 'center'), 'ERROR<hr />- Plugin Manager Center -<br />Branch: ' . $branch . '<br />(Roundcube v' . RCMAIL_VERSION . ')<hr />') .
+ html::tag('p', null, 'Misconfiguration: Unregister <b>' . $plugin . '</b> in ./config/main.inc.php.') .
+ html::tag('p', null, 'You can\'t register a plugin in main.inc.php which is configured to be loaded by Plugin Manager.<hr /><center>[<a href="javascript:void(0)" onclick="document.location.reload()">Done</a>]</center>');
+ $this->out = $error;
+ $this->register_handler('plugin.body', array($this, 'sqlerror'));
+ $this->rcmail->output->send('plugin_manager.error');
+ }
+ if(isset($active[$plugin])){
+ $overwrite = $active[$plugin];
+ }
+ else{
+ $overwrite = $props['active'];
+ }
+ if($props['protected']){
+ $overwrite = $props['active'];
+ if(is_array($props['protected'])){
+ foreach($props['protected'] as $domain){
+ if($domain == $this->domain){
+ $overwrite = $props['active'];
+ break;
+ }
+ else{
+ $overwrite = $active[$plugin];
+ }
+ }
+ }
+ else if(is_string($props['protected'])){
+ $overwrite = $this->rcmail->config->get($props['protected']);
+ }
+ }
+ $this->config[$sections][$plugin]['active'] = $overwrite;
+ }
+ }
+ }
+
+ function google_contacts_uninstall(){
+ if($this->rcmail->user->ID){
+ $db_table = get_table_name('google_contacts');
+ $query = "DELETE FROM $db_table WHERE user_id=?";
+ $this->rcmail->db->query($query, $this->rcmail->user->ID);
+ }
+ }
+
+ function automatic_addressbook_uninstall(){
+ if($this->rcmail->user->ID){
+ $db_table = get_table_name('collected_contacts');
+ $query = "DELETE FROM $db_table WHERE user_id=?";
+ $this->rcmail->db->query($query, $this->rcmail->user->ID);
+ }
+ }
+
+ function uninstall(){
+ $uninstall = get_input_value('_uninstall', RCUBE_INPUT_POST);
+ $config = unserialize($this->rcmail->user->data['preferences']);
+ $response = '';
+ foreach($this->config as $sections => $section){
+ foreach($section as $plugin => $props){
+ if($plugin == $uninstall){
+ if($props['uninstall_request']){
+ if(is_array($props['uninstall_request'])){
+ if(strtolower($props['uninstall_request']['method']) == 'post'){
+ $response = 'rcmail.http_post(';
+ }
+ else{
+ $response = 'rcmail.http_request(';
+ }
+ $params = '';
+ if($props['uninstall_request']['params'])
+ $params = $props['uninstall_request']['params'];
+ $response .= '"' . $props['uninstall_request']['action'] . '", "' . $params .'");';
+ }
+ }
+ if(is_array($props['uninstall'])){
+ foreach($props['uninstall'] as $prop){
+ if(is_string($prop)){
+ unset($config[$prop]);
+ }
+ }
+ }
+ else if($props['uninstall'] === true){
+ if(method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $about = $class->about();
+ if(is_array($about['config'])){
+ foreach($about['config'] as $prop => $val){
+ if(is_string($prop)){
+ unset($config[$prop]);
+ }
+ }
+ }
+ }
+ }
+ $a_user_prefs = $config;
+ $config = serialize($config);
+ $this->rcmail->db->query(
+ "UPDATE ".get_table_name('users').
+ " SET preferences = ?".
+ ", language = ?".
+ " WHERE user_id = ?",
+ $config,
+ $_SESSION['language'],
+ $this->rcmail->user->ID
+ );
+ if($this->rcmail->db->affected_rows() !== false){
+ $this->rcmail->config->set_user_prefs($a_user_prefs);
+ $this->rcmail->data['preferences'] = $config;
+ if(isset($_SESSION['preferences'])){
+ $this->rcmail->session->remove('preferences');
+ $this->rcmail->session->remove('preferences_time');
+ }
+ }
+ break;
+ }
+ }
+ }
+ $this->rcmail->output->command('plugin.plugin_manager_success', $response);
+ }
+
+ function transfer(){
+ $this->register_handler('plugin.body', array($this, 'transfer_html'));
+ $user = $_SESSION['username'];
+ $admins = $this->admins;
+ if(isset($admins[strtolower($user)]) || strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $this->rcmail->output->send('plugin_manager.transfer');
+ }
+ }
+
+ function transfer_html(){
+ $customer_id = $this->rcmail->config->get('customer_id');
+ if(isset($_POST['_from']) && isset($_POST['_to']) && isset($_POST['_amount'])){
+ $dest = get_input_value('_to', RCUBE_INPUT_POST);
+ $amount = get_input_value('_amount', RCUBE_INPUT_POST);
+ $alphanum = 'a-z0-9';
+ $alpha = '0-9';
+ if(strlen($dest) < 32){
+ $this->rcmail->output->show_message($this->gettext('invalid_customer_id'), 'error');
+ }
+ else if(strlen($dest) != preg_replace("/[^$alphanum]/i", '', strlen($dest))){
+ $this->rcmail->output->show_message($this->gettext('invalid_customer_id'), 'error');
+ }
+ else if(strlen($amount) != preg_replace("/[^$alpha]/", '', strlen($amount))){
+ $this->rcmail->output->show_message($this->gettext('invalid_credits'), 'error');
+ }
+ else{
+ $httpConfig['method'] = 'POST';
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_transfer';
+ $httpConfig['timeout'] = '30';
+ $httpConfig['params'] = array('_customer_id' => $customer_id, '_to' => $dest, '_amount' => $amount, '_ip' => $this->getVisitorIP());
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ if($http->error){
+ $this->rcmail->output->show_message($this->gettext('errorsaving'), 'error');
+ }
+ $response = $http->result;
+ if($response == 'ok'){
+ $this->rcmail->output->show_message($this->gettext('successfully_transferred'), 'confirmation');
+ }
+ else{
+ $this->rcmail->output->show_message($this->gettext('errorsaving'), 'error');
+ }
+ }
+ }
+ $credits = $this->getcredits(false);
+ $row = html::tag('td', array('class' => 'title'), $this->gettext('from') . ':') . html::tag('td', null, html::tag('td', null, html::tag('input', array('name' => '_from', 'size' => 32, 'readonly' => 'readonly', 'value' => $customer_id)) . html::tag('td', array('class' => 'title'), '(' . $this->gettext('customer_id') . ')')));
+ $rows = html::tag('tr', null, $row);
+ $row = html::tag('td', array('class' => 'title'), $this->gettext('to') . ':') . html::tag('td', null, html::tag('td', null, html::tag('input', array('name' => '_to', 'size' => 32, 'value' => $dest ? $dest : '')) . html::tag('td', array('class' => 'title'), '(' . $this->gettext('customer_id') . ')')));
+ $rows .= html::tag('tr', null, $row);
+ $row = html::tag('td', array('class' => 'title'), 'MyRC$:') . html::tag('td', null, html::tag('td', null, html::tag('input', array('name' => '_amount', 'size' => 3, 'value' => $credits)) . html::tag('td', array('class' => 'title'), '(' . 'MyRC$&nbsp;' . html::tag('span', array('id' =>'cdl'), $credits) . '&nbsp;' . $this->gettext('credits') . ')')));
+ $rows .= html::tag('tr', null, $row);
+ $content = html::tag('table', null, $rows);
+ $content .= html::tag('br') . html::tag('input', array('type' => 'submit', 'value' => $this->gettext('transfer'), 'class' => 'button mainaction'));
+ $content .= '&nbsp;' . html::tag('input', array('type' => 'button', 'value' => $this->gettext('cancel'), 'class' => 'button', 'onclick' => 'document.location.href="./?_task=settings&_action=edit-prefs&_section=plugin_manager_customer&_framed=1"'));
+ $fieldset = html::tag('fieldset', null, html::tag('legend', null, $this->gettext('transfer')) . $content);
+ $out = html::tag('form', array('action' => './?_task=settings&_action=plugin.plugin_manager_transfer&_framed=1', 'method' => 'post'), $fieldset);
+ return $out;
+ }
+
+ function update(){
+ $user = $_SESSION['username'];
+ $admins = $this->admins;
+ if(isset($admins[strtolower($user)]) || strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $this->register_handler('plugin.body', array($this, 'update_html'));
+ $this->rcmail->output->add_script('pm_resize();', 'docready');
+ $this->rcmail->output->send('plugin');
+ }
+ }
+
+ function update_html(){
+ $hl = get_input_value('_hl', RCUBE_INPUT_GET);
+ $branch = get_input_value('_branch', RCUBE_INPUT_GET);
+ if(strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ if(RCMAIL_VERSION > $this->stable){
+ $branch = 'dev';
+ }
+ }
+ if($branch == 'dev'){
+ $this->mirror = $this->svn;
+ }
+ else if($branch == 'beta'){
+ $this->mirror = $this->beta;
+ }
+ if($hl && $hl != $_SESSION['language']){
+ $this->rcmail->load_language($hl);
+ $this->add_texts('localization', false);
+ }
+ $this->include_script('plugin_manager_update.js');
+ $this->rcmail->output->add_label(
+ 'plugin_manager.noupdates',
+ 'plugin_manager.showall',
+ 'plugin_manager.hideuptodate'
+ );
+ $skin = $this->rcmail->config->get('skin');
+ if(!file_exists($this->home . '/skins/' . $skin . '/plugin_manager.css')) {
+ $skin = "larry";
+ }
+ $this->include_stylesheet('skins/' . $skin . '/plugin_manager.css');
+ $plugins = array_flip($this->rcmail->config->get('plugins', array()));
+ $dtp = $this->thirdparty;
+ $sections = $this->defaults;
+ foreach($sections as $section => $plugs){
+ foreach($plugs as $plug => $props){
+ $plugins[$plug] = $props;
+ }
+ }
+ $scope = array();
+ foreach($plugins as $plugin => $props){
+ if(!class_exists($plugin)){
+ $this->require_plugin($plugin);
+ }
+ if(method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $p = $class->about();
+ $p_sav = $p;
+ //$p = $plugin::about();
+ $scope[$plugin] = array('version' => $p['version'], 'date'=> $p ['date']);
+ if(is_array($p['requirements']['required_plugins'])){
+ foreach($p['requirements']['required_plugins'] as $required => $val){
+ $this->require_plugin($required);
+ $p = $val['plugin'];
+ if(method_exists($required, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $required(false);
+ $p = $class->about();
+ }
+ if(is_array($p)){
+ $scope[$required] = array('version'=>$p['version'], 'date'=>$p['date']);
+ }
+ else{
+ if($dtp[$required]){
+ $scope[$required] = $dtp[$plugin];
+ }
+ else{
+ $scope[$required] = 'unknown';
+ }
+ }
+ }
+ }
+ $p = $p_sav;
+ if(is_array($p['requirements']['recommended_plugins'])){
+ foreach($p['requirements']['recommended_plugins'] as $recommended => $val){
+ if(file_exists(INSTALL_PATH . 'plugins/' . $recommended . '/' . $recommended . '.php')){
+ $this->require_plugin($recommended);
+ $p = $val['plugin'];
+ if(method_exists($recommended, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $recommended(false);
+ $p = $class->about();
+ }
+ if(is_array($p)){
+ $scope[$recommended] = array('version'=>$p['version'], 'date'=>$p['date']);
+ }
+ else{
+ if($dtp[$recommended]){
+ $scope[$recommended] = $dtp[$plugin];
+ }
+ else{
+ $scope[$recommended] = 'unknown';
+ }
+ }
+ }
+ }
+ }
+ }
+ else{
+ if($dtp[$plugin]){
+ $scope[$plugin] = $dtp[$plugin];
+ }
+ else{
+ $scope[$plugin] = 'unknown';
+ }
+ }
+ }
+ $user = $_SESSION['username'];
+ $temparr = explode('@', $user);
+ if(count($temparr) == 1){
+ $host = $this->rcmail->user->data['mail_host'];
+ if($host == 'localhost'){
+ $host = $_SERVER['HTTP_HOST'];
+ }
+ $user = $user . '@' . $host;
+ }
+ if(get_input_value('_warning', RCUBE_INPUT_GET)){
+ if(MYRC_BRANCH == 'beta'){
+ $betachecked = 'checked';
+ $devchecked = '';
+ $stablechecked = '';
+ $host = $this->beta;
+ }
+ else if(MYRC_BRANCH == 'stable'){
+ $betachecked = '';
+ $devchecked = 'checked';
+ $stablechecked = '';
+ $host = $this->svn;
+ }
+ else{
+ $betachecked = '';
+ $devchecked = '';
+ $stablechecked = 'checked';
+ $host = $this->mirror;
+ }
+ $warning = html::tag('h3', null, 'We respect your privacy!') . html::tag('div', array('style' => 'text-align:justify'), 'If you proceed the following data will be submitted to our mirror servers and saved in our databases. While we consider this data as a whole not to be an invasion to your privacy, you may want to share a different email address with us. See ' . html::tag('a', array('target' => '_blank', 'href' => 'https://myroundcube.com/myroundcube-plugins/plugin-manager/administration#plugin-manager-administrators'), 'here') . ' how to add an additional administrative account to use a different email address.');
+ $form = html::tag('ul', null,
+ html::tag('li', null, '_admin: ' . $user) .
+ html::tag('li', null, '_hl: ' . $_SESSION['language']) .
+ html::tag('li', null, '_customer_id: ' . $this->rcmail->config->get('customer_id')) .
+ html::tag('li', null, '_plugins:')
+ );
+ $EMAIL_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[^&@"\'.][^@&"\']*\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))';
+ $display = 'none';
+ if(preg_match('/' . $EMAIL_PATTERN . '/i', $user)){
+ $display = 'block';
+ }
+ $out = '<br />' . html::tag('div',
+ array('style' => 'opacity: 0.85;text-align: center; margin-left: auto; margin-left: auto; margin-right: auto; width: 600px; padding: 15px; background-color: #F7FDCB; border: 1px solid #C2D071;'),
+ $warning . html::tag('div', array('style' => "display:$display"),
+ html::tag('div', array('style' => 'text-align: right; margin-right: 80px;'),
+ //html::tag('span', null, 'Yes, please send me MyRoundcube Newsletters') . '&nbsp;' . html::tag('input', array('type' => 'checkbox', 'name' => '_newsletter', 'id' => 'newsletter', 'value' => 1)) . html::tag('br') .
+ html::tag('br') . html::tag('div', array('style' => 'display:inline;margin-right:22px'), 'Don\'t miss out ' . html::tag('a', array('href' => 'https://forum.myroundcube.com/index.php?app=core&module=global&section=register', 'target' => '_blank'), 'on joining') . ' at MyRoundcube\'s community forum.') . html::tag('br') .
+ ($this->svn ? ('<br />' . html::tag('span', null, 'Download <b>stable versions</b> of plugins for Roundcube <b>' . $this->dev) . '</b>&nbsp;' . html::tag('input', array('class' => 'branch', 'onclick' =>'$("#mirrorhost").html("' . $this->svn . '")', 'type' => 'radio', 'checked' => $devchecked, 'name' => '_branch', 'id' => 'devbranch', 'value' => 'dev'))) : '') .
+ ($this->beta ? ('<br />' . html::tag('span', null, 'Download <b>beta versions</b> of plugins for Roundcube <b>' . $this->dev_beta) . '</b>&nbsp;(developement in progress)&nbsp;' . html::tag('input', array('class' => 'branch', 'onclick' =>'$("#mirrorhost").html("' . $this->beta . '")', 'type' => 'radio', 'checked' => $betachecked, 'name' => '_branch', 'id' => 'betabranch', 'value' => 'beta'))) : '').
+ ($this->mirror ? ('<br />' . html::tag('span', null, 'Download <b>stable plugins</b> for Roundcube <b>' . $this->stable) . '</b>&nbsp;(developemnet frozen)&nbsp;' . html::tag('input', array('class' => 'branch', 'onclick' =>'$("#mirrorhost").html("' . $this->mirror . '")', 'type' => 'radio', 'checked' => $stablechecked, 'name' => '_branch', 'id' => 'stablebranch', 'value' => 'stable'))) : '')
+ ) .
+ html::tag('div', array('style' => 'display:none;', 'id' => 'newletterdetails'), '<br />' . html::tag('span', null, 'First Name:&nbsp;') . html::tag('input', array('type' => 'text', 'name' => '_firstname', 'id' => 'firstname', 'maxlength' => 30)) . '<br /><br />' .
+ html::tag('span', null, 'Last Name:&nbsp;') . html::tag('input', array('type' => 'text', 'name' => '_lastnamename', 'id' => 'lastname', 'maxlength' => 30)))) .
+ '<br /><br />' . html::tag('a', array('href' => './?_task=settings&_framed=1&_action=plugin.plugin_manager_update', 'onclick' => 'return backup(this);', 'target' => '_self'), 'I agree') . '&nbsp;|&nbsp;' .
+ html::tag('a', array('href' => '#', 'onclick' => 'document.location.href="plugins/plugin_manager/skins/larry/myroundcube.html";parent.$("#rcmrowplugin_manager_update").remove()'), "I disagree")
+ );
+ $out .= html::tag('div', array('style' => 'margin-left: auto; margin-right: auto; width: 600px; padding: 15px;'), $form);
+ ksort($scope);
+ $out .= html::tag('div', array('style' => 'margin-left: auto; margin-right: auto; width: 900px;'), html::tag('center', null, html::tag('textarea', array('cols' => 90, 'rows' => 20, 'disabled' => true), print_r($scope, true))));
+ $this->rcmail->output->add_script('$(document).ready(function(){$("#tabsbar").hide()});');
+ return $out;
+ }
+ if(get_input_value('_newsletter', RCUBE_INPUT_GET) == 1 && strtolower($this->get_demo($_SESSION['username'])) != strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $params = array('_hl' => $_SESSION['language'], '_admin' => $user, '_plugins' => serialize($scope), '_newsletter' => get_input_value('_newsletter', RCUBE_INPUT_GET), '_firstname' => get_input_value('_firstname', RCUBE_INPUT_GET), '_lastname' => get_input_value('_lastname', RCUBE_INPUT_GET));
+ }
+ else{
+ $params = array('_hl' => $_SESSION['language'], '_admin' => $user, '_plugins' => serialize($scope));
+ }
+ $branch = get_input_value('_branch', RCUBE_INPUT_GET);
+ if($branch == 'dev'){
+ $host = $this->svn;
+ }
+ else if($branch == 'stable'){
+ $host = $this->mirror;
+ }
+ else{
+ $host = $this->beta;
+ }
+ $httpConfig['method'] = 'POST';
+ $httpConfig['target'] = $host . '?_action=plugin.plugin_server_mirror';
+ $httpConfig['timeout'] = '30';
+ $httpConfig['params'] = array_merge($params, array('_customer_id' => $this->rcmail->config->get('customer_id')));
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ if($http->error){
+ return html::tag('div',
+ array('style' => 'opacity: 0.85; text-align: center; margin-left: auto; margin-right: auto; width: 600px; padding: 8px 10px 8px 46px; background: url(./skins/classic/images/display/icons.png) 6px -97px no-repeat; background-color: #EF9398; border: 1px solid #DC5757;'),
+ $this->gettext('connectionerror') . '<br /><br />' . html::tag('a', array('href' => './?_task=settings&_framed=1&_action=plugin.plugin_manager_update', 'target' => '_self'), $this->gettext('trylater')));
+ }
+ $response = $http->result;
+ if(!$server = unserialize($response)){
+ return html::tag('div',
+ array('style' => 'opacity: 0.85; text-align: center; margin-left: auto; margin-right: auto; width: 600px; padding: 8px 10px 8px 46px; background: url(./skins/classic/images/display/icons.png) 6px -97px no-repeat; background-color: #EF9398; border: 1px solid #DC5757;'),
+ $this->gettext('connectionerror') . '<br /><br />' . html::tag('a', array('href' => './?_task=settings&_framed=1&_action=plugin.plugin_manager_update', 'target' => '_self'), $this->gettext('trylater')));
+ }
+ $mirror_rc = $server['roundcube'];
+ $mirror = $server['scope'];
+ if(!isset($mirror['Branch is currently closed'])){
+ $merge = array();
+ foreach($dtp as $plugin => $props){
+ if(!isset($mirror[$plugin])){
+ $merge[$plugin] = $dtp[$plugin];
+ }
+ }
+ ksort($merge);
+ $mirror = array_merge($mirror, $merge);
+ }
+ $temp = $mirror;
+ unset($mirror['plugin_manager']);
+ if(!isset($mirror['Branch is currently closed'])){
+ $ret = array();
+ $ret['Roundcube Core Patches'] = $this->core_patches;
+ $ret['plugin_manager'] = $temp['plugin_manager'];
+ foreach($mirror as $plugin => $props){
+ $ret[$plugin] = $mirror[$plugin];
+ }
+ $mirror = $ret;
+ }
+ $update = array();
+ if(is_array($mirror)){
+ foreach($mirror as $plugin => $props){
+ if(is_array($props)){
+ if($scope[$plugin] && $props['version']){
+ if($props['version'] > $scope[$plugin]['version']){
+ $update[$plugin] = $scope[$plugin];
+ if(is_array($update[$plugin])){
+ $update[$plugin]['notinstalled'] = false;
+ }
+ }
+ }
+ else{
+ $update[$plugin] = $props;
+ if(is_array($update[$plugin])){
+ $update[$plugin]['notinstalled'] = true;
+ }
+ }
+ }
+ else{
+ $update[$plugin] = $scope[$plugin];
+ if(is_array($update[$plugin])){
+ $update[$plugin]['notinstalled'] = false;
+ }
+ }
+ }
+ }
+ $checked = false;
+ foreach($update as $plugin => $props){
+ if(is_array($props)){
+ $checked = true;
+ break;
+ }
+ }
+ include './program/localization/index.inc';
+ $options = '';
+ ksort($rcube_languages);
+ foreach($rcube_languages as $abbr => $lang){
+ $options .= html::tag('option', array('title' => $lang, 'selected' => ($_SESSION['language'] == $abbr)?true:false, 'value' => $abbr), $abbr);
+ }
+ $select = html::tag('select', array('onchange' => 'document.location.href="./?_task=settings&_framed=1&_action=plugin.plugin_manager_update&_branch=dev&_hl=" + this.value'), $options);
+ $thead = html::tag('tr', null,
+ html::tag('th', array('width' => '220px'), $this->gettext('plugin')) .
+ html::tag('th', array('width' => '100px'), $this->gettext('mirrorversion')) .
+ html::tag('th', array('width' => '100px'), $this->gettext('serverversion')) .
+ html::tag('th', array('width' => '90px', 'title' => $this->gettext('language')), $select) .
+ html::tag('th', array('width' => '90px'), html::tag('a', array('href' => 'http://code.google.com/p/myroundcube/issues/list', 'target' => '_blank'), $this->gettext('issue'))) .
+ html::tag('th', array('width' => '30px', 'title' => $this->gettext('hideuptodate')), html::tag('input', array('type' => 'checkbox', 'id' => 'updatetoggle'))) .
+ html::tag('th', array('width' => '30px'), html::tag('input', array('id' => 'toggle', 'title' => $this->gettext('toggle'), 'type' => 'checkbox', 'checked' => $checked))) .
+ html::tag('th', null, $this->gettext('comments'))
+ );
+ $tbody1 = '';
+ $tbody2 = '';
+ $cdlcredits = $server['credits'];
+ $cdlprice = 0;
+ foreach($mirror as $plugin => $props){
+ if(in_array($plugin, $this->dontlist)){
+ continue;
+ }
+ if(substr($plugin, 0, 6) == 'hmail_'){
+ if(!$this->use_hmail){
+ continue;
+ }
+ }
+ $nr = false;
+ if(is_array($props) && $props['version']){
+ $stat = 'ok';
+ $comment = '';
+ $append = '';
+ if($update[$plugin]){
+ $stat = 'update';
+ }
+ if($props['lr']){
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/localization/revision.inc.php')){
+ $ps_localization_update = false;
+ $A = false;
+ include INSTALL_PATH . 'plugins/' . $plugin . '/localization/revision.inc.php';
+ if(!$ps_localization_update){
+ $ps_localization_update = $A;
+ }
+ if($ps_localization_update != $props['lr'] && $props['version'] == $scope[$plugin]['version']){
+ $stat = 'update';
+ $comment .= $this->gettext('languageupdate') . "<br /><font color='red'>" . $this->gettext('localizationfilesonly') . "</font>\r\n";
+ }
+ }
+ }
+ if($props['roundcube']){
+ if($props['roundcube'] > RCMAIL_VERSION){
+ $stat = 'error';
+ }
+ }
+ if($props['license']){
+ $license = $this->gettext('terms') . ": " . html::tag('a', array('href' => $this->svn . '?_action=plugin.plugin_server_license&_plugin=' . $plugin, 'target' => '_blank', 'title' => $this->gettext('view')), $props['license']);
+ }
+ else{
+ $license = false;
+ }
+ if($props['comments']){
+ $props['comments'] = $this->gettext('authors_comments') . ': ' . $this->comment2ul($props['comments']);
+ }
+ $comment .= nl2br($props['comments']);
+ $pmsv = $scope[$plugin]['version'];
+ $t = explode('-', $pmsv);
+ $pmsv = $t[0];
+ $pmcv = $props['version'];
+ $t = explode('-', $pmsc);
+ $pmsc = $t[0];
+ $tmsv = explode('.', $pmsv);
+ $tmcv = explode('.', $pmcv);
+ foreach($tmsv as $tmsvk => $tmsvp){
+ while(strlen($tmsvp) < $this->vlength){
+ $tmsvp = '0'. $tmsvp;
+ }
+ $tmsv[$tmsvk] = $tmsvp;
+ }
+ foreach($tmcv as $tmcvk => $tmcvp){
+ while(strlen($tmcvp) < $this->vlength){
+ $tmcvp = '0'. $tmcvp;
+ }
+ $tmcv[$tmcvk] = $tmcvp;
+ }
+ $s = implode('.', $tmsv);
+ $p = implode('.', $tmcv);
+ if($p < $s && is_numeric(substr($scope[$plugin]['version'], 0, 1))){
+ $stat = 'error';
+ $comment = $this->gettext('servernewer');
+ }
+ else if(!is_numeric(substr($scope[$plugin]['version'],0, 1))){
+ if(is_dir(INSTALL_PATH . 'plugins/' . $plugin) && $plugin != 'dblog' && $this->require_plugin($plugin)){
+ if(method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $arr = $class->about(array('version', 'date'));
+ $scope[$plugin] = $arr;
+ $update[$plugin] = $scope[$plugin];
+ $update[$plugin]['notinstalled'] = false;
+ $pmsv = $scope[$plugin]['version'];
+ $t = explode('-', $pmsv);
+ $pmsv = $t[0];
+ $tmsv = explode('.', $pmsv);
+ foreach($tmsv as $tmsvk => $tmsvp){
+ while(strlen($tmsvp) < $this->vlength){
+ $tmsvp = '0'. $tmsvp;
+ }
+ $tmsv[$tmsvk] = $tmsvp;
+ }
+ $s = implode('.', $tmsv);
+ if($p == $s){
+ $nr = true;
+ }
+ else{
+ $nr = false;
+ }
+ if($p < $s && is_numeric(substr($scope[$plugin]['version'],0,1))){
+ $stat = 'error';
+ $comment = $this->gettext('servernewer');
+ }
+ }
+ else{
+ $scope[$plugin]['version'] = 'unknown';
+ }
+ }
+ else{
+ $scope[$plugin]['version'] = 'unknown';
+ }
+ if($comment != '' && $stat != 'error'){
+ $stat = 'edit';
+ }
+ else if($stat != 'error'){
+ $stat = 'update';
+ }
+ }
+ else if($p > $s && $comment != ''){
+ $stat = 'edit';
+ }
+ else if($p > $s){
+ $stat = 'update';
+ }
+ else if (is_array($update[$plugin]) && $stat != 'error'){
+ $comment = $this->gettext('justunzip') . '<br />' . html::tag('a', array('href' => $this->guide, 'target' => '_blank'), $this->gettext('guide'));;
+ }
+ $roundcube = '';
+ if($props['roundcube']){
+ $roundcube = 'Roundcube Version: ' . $props['roundcube'] . ' ' . $this->gettext('orhigher') . "\r\n";
+ }
+ $php = '';
+ if($props['PHP']){
+ $php = 'PHP: ' . $props['PHP'] . "\r\n";
+ $phpversion = phpversion();
+ $temparr = explode('-', $phpversion);
+ if($props['PHP'] >= $temparr[0]){
+ $stat = 'error';
+ }
+ }
+ $required_plugins = '';
+ if(is_array($props['requires'])){
+ $required_plugins = $this->gettext('requires') . ':<br />';
+ foreach($props['requires'] as $key => $val){
+ $method = '&sup2';
+ if($val['method'] && $val['method'] == 'require_plugin'){
+ $method = '&sup1';
+ }
+ $required_plugins .= '-&nbsp;'.html::tag('a', array('href' => '#' . $key, 'class' => 'anchorLink'), $key) . $method . '<br />';
+ }
+ $required_plugins = substr($required_plugins, 0, strlen($required_plugins) - 2) . "\r\n";
+ }
+ $recommended_plugins = '';
+ if(is_array($props['recommended'])){
+ $recommended_plugins = $this->gettext('recommended') . ':<br />';
+ foreach($props['recommended'] as $key => $val){
+ $recommended_plugins .= '-&nbsp;'.html::tag('a', array('href' => '#' . $key, 'class' => 'anchorLink'), $key) . '&sup2<br />';
+ }
+ $recommended_plugins = substr($recommended_plugins, 0, strlen($recommended_plugins) - 2) . "\r\n";
+ }
+ if(is_array($props['required'])){
+ $requiredby = '';
+ foreach($props['required'] as $key){
+ $requiredby .= '-&nbsp;'.html::tag('a', array('href' => '#' . $key, 'class' => 'anchorLink'), $key) . '<br />';
+ }
+ $requiredby = substr($requiredby, 0, strlen($requiredby) - 2) . "\r\n";
+ $comment = $this->gettext('requiredby') . ':<br />' . $requiredby . "\r\n" . $comment;
+ }
+ $temparr = explode("\r\n", $roundcube . $php . $required_plugins . $recommended_plugins . $comment);
+ $comments = '';
+ foreach($temparr as $r){
+ if($r)
+ $comments .= html::tag('li', null, $r);
+ }
+ if($comments != '' && $plugin != 'Roundcube Core Patches' && $plugin != 'Branch is currently closed'){
+ $changelog = html::tag('li', null, html::tag('a', array('href' => $this->svn . '?_action=plugin.plugin_server_changelog&_plugin=' . $plugin, 'target' => '_blank', 'title' => $this->gettext('view')), 'CHANGELOG'));
+ $comment = html::tag('ul', array('class' =>'pm_update'), ($license ? html::tag('li', null, $license) : '') . $changelog . $comments);
+ }
+ if($update[$plugin]['notinstalled']){
+ if(is_dir('./plugins/' . $plugin)){
+ $serverversion = html::tag('td', null, $this->gettext('notregistered'));
+ }
+ else{
+ if($plugin == 'Roundcube Core Patches'){
+ if($content = @file_get_contents(INSTALL_PATH . '.myrc.patch_version')){
+ $content = explode('|', trim($content));
+ $serverversion = html::tag('td', null, $content[0] . html::tag('br') . html::tag('small', null, '(' . date($this->rcmail->config->get('date_format', 'm-d-Y'), strtotime($content[1])) . ')'));
+ if($mirror[$plugin]['version'] . $mirror[$plugin]['date'] != $content[0] . $content[1]){
+ $stat = 'edit';
+ }
+ else{
+ $stat = 'ok';
+ }
+ }
+ else{
+ $serverversion = html::tag('td', null, $this->gettext('notinstalled'));
+ }
+ }
+ else if($plugin == 'Branch is currently closed'){
+ $stat = 'ok';
+ $serverversion = html::tag('td', null, '--');
+ }
+ else{
+ $serverversion = html::tag('td', null, $this->gettext('notinstalled'));
+ }
+ }
+ }
+ else{
+ $content = ($update[$plugin]?$update[$plugin]['version']:$scope[$plugin]['version']) . '<br />' . html::tag('small', null, '(' . ($update[$plugin] ? date($this->rcmail->config->get('date_format', 'm-d-Y'), strtotime($scope[$plugin]['date'])):date($this->rcmail->config->get('date_format', 'm-d-Y'), strtotime($scope[$plugin]['date']))) . ')');
+ if(substr($content, 0, 1) == 'u'){
+ $serverversion = html::tag('td', null, $this->gettext('unknown'));
+ }
+ else{
+ $serverversion = html::tag('td', null, $content);
+ }
+ }
+ $translation = html::tag('td', array('align' => 'center'), '--');
+ $user = $this->rcmail->config->get('plugin_manager_translation_account') ? $this->rcmail->config->get('plugin_manager_translation_account') : $_SESSION['username'];
+ if($mirror[$plugin]['lc'] !== false){
+ $host = $_SESSION['storage_host'];
+ if($host == 'localhost')
+ $host = $_SERVER['SERVER_ADDR'];
+ if(!$host)
+ $host = $_SERVER['HTTP_HOST'];
+ $host = ($_SESSION['storage_ssl'] ? 'ssl://' : '') . $host . ':' . $_SESSION['storage_port'];
+ $port = $_SESSION['storage_port'] ? $_SESSION['storage_port'] : $this->rcmail->config->get('default_port');
+ if($host = $this->rcmail->config->get('plugin_manager_translation_server')){
+ $temp = parse_url($host);
+ $port = $temp['port'] ? $temp['port'] : $port;
+ }
+ $translation = html::tag('td', array('align' => 'right', 'title' => $plugin . ' :: ' . $this->gettext('translate') . '...'), html::tag('a', array('target' => '_blank', 'href' => $this->mirror . '?_action=plugin.plugin_server_translate&_hl=' . $_SESSION['language'] . '&_plugin=' . $plugin . '&_translator=' . $user . '&_host=' . $host . '&_port=' . $port), ($mirror[$plugin]['lc'] * 100)) . ' %');
+ }
+ $db = $this->rcmail->config->get('db_dsnw');
+ $db = parse_url($db);
+ $db = $db['scheme'];
+ $onclick = '';
+ if(strtolower($this->get_demo($user)) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $onclick = 'return false';
+ }
+ $dlprice = 0;
+ if($p > $s || substr($s, 0, 5) == '0000u'){
+ $dlprice = $mirror[$plugin]['prices'][0];
+ $background = 'lightgreen';
+ if(is_dir(INSTALL_PATH . 'plugins/' . $plugin)){
+ if($plugin == 'dblog'){
+ $dlprice = $mirror[$plugin]['prices'][1];
+ $v = explode('.', $scope[$plugin]['version']);
+ $mv = explode('.', $mirror[$plugin]['version']);
+ if(($v[1] == 0 && count($mv) == 2) || $v[0] < $mv[0]){
+ $dlprice = $mirror[$plugin]['prices'][1];
+ $background = 'lightblue';
+ }
+ else if($v[0] == $mv[0] && $v[1] < $mv[1]){
+ $dlprice = $mirror[$plugin]['prices'][2];
+ $background = 'yellow';
+ }
+ else{
+ $dlprice = 0;
+ $background = 'none';
+ }
+ }
+ else if($this->require_plugin($plugin)){
+ $dlprice = $mirror[$plugin]['prices'][1];
+ $v = explode('.', $scope[$plugin]['version']);
+ $mv = explode('.', $mirror[$plugin]['version']);
+ if(($v[1] == 0 && count($mv) == 2) || $v[0] < $mv[0]){
+ $dlprice = $mirror[$plugin]['prices'][1];
+ $background = 'lightblue';
+ }
+ else if($v[0] == $mv[0] && $v[1] < $mv[1]){
+ $dlprice = $mirror[$plugin]['prices'][2];
+ $background = 'yellow';
+ }
+ else{
+ if(method_exists($plugin, 'about')){
+ $dlprice = 0;
+ $background = 'none';
+ }
+ }
+ }
+ }
+ }
+ if(!$dlprice){
+ $background = 'none';
+ }
+ if($nr){// && $scope[$plugin]['version']
+ $stat = 'ok';
+ }
+ $cdlprice = $cdlprice + $dlprice;
+ $prices = html::tag('td', array('style' => "background: lightgreen", 'title' => $this->gettext('initialdownload')), $mirror[$plugin]['prices'][0]);
+ $prices .= html::tag('td', array('style' => "background: lightblue", 'title' => $this->gettext('keyfeatureaddition')), $mirror[$plugin]['prices'][1]);
+ $prices .= html::tag('td', array('style' => "background: yellow", 'title' => $this->gettext('codeimprovements')), $mirror[$plugin]['prices'][2]);
+ $prices .= html::tag('td', null, '&rArr;');
+ $prices .= html::tag('td', array('style' => "background: " . $background, 'title' => 'MyRC$ ' . $dlprice), 'MyRC$&nbsp;' . html::tag('span', array('id' => 'pmdlp_' . $plugin), $dlprice));
+ $checked = ((is_array($update[$plugin]) && !$update[$plugin]['notinstalled'] && $stat != 'error' || $stat == 'edit' || $stat == 'update') && $stat != 'ok')?true:false;
+ $notinstalled = '';
+ if(substr($scope[$plugin]['version'], 0, 1) == 'u'){
+ $notinstalled = 'notinstalled ';
+ }
+ if($plugin == 'Roundcube Core Patches' || $plugin == 'Branch is currently closed'){
+ $submitissue = html::tag('td', array('align' => 'center'), '--');
+ $checkbox = html::tag('td', null, '&nbsp;');
+ }
+ else{
+ $submitissue = html::tag('td', array('align' => 'center', 'title' => $plugin . ' :: ' . $this->gettext('submitissue')), html::tag('a', array('onclick' => $onclick, 'href' => 'http://code.google.com/p/myroundcube/issues/entry?summary=[' . $plugin . '] - Enter one-line summary&comment=Token:%20' . $server['token'] . "%20(Don't modify this token!)%0AVersion:%20" . $scope[$plugin]['version'] . " (" . $scope[$plugin]['date'] . ")%0APHP:%20" . phpversion() . '%0ARCMAIL:%20' . RCMAIL_VERSION . '%0ADatabase:%20' . $db . '%0ASERVER:%20' . $_SERVER['SERVER_SOFTWARE'] . '%0A----%0AI.%20%20Issue%20Description:%0A%0AII.%20Steps to reproduce the Issue:%0A1.%0A2.%0A3.', 'target' => '_blank'), $this->gettext('issue')));
+ $checkbox = html::tag('td', array('align' => 'center'), html::tag('input', array('class' => 'chbox ' . $notinstalled . ($dlprice ? 'costs' : 'free'), 'value' => $plugin . '|' . ($scope[$plugin]['version'] ? $scope[$plugin]['version'] : '0') . '|' . $mirror[$plugin]['token'], 'type' => 'checkbox', 'checked'=> $checked, 'disabled' => ($stat != 'ok' && (is_array($update[$plugin]) && $stat != 'error' || $stat == 'edit' || $stat == 'update'))?false:true, 'name' => '_plugins[]', 'id' => 'chbox_' . asciiwords($plugin, false, '_'), null)));
+ }
+ $tbody1 .= html::tag('tr', null,
+ html::tag('td', array('id' => 'pmu_' . asciiwords($plugin, false, '_'), 'title' => $mirror[$plugin]['description']), html::tag('a', array('name' => '#' . $plugin, 'class' => 'anchorLink'), '&nbsp;') . $plugin . ($mirror[$plugin]['count'] ? ('<br />&nbsp;' . html::tag('small', array('title' => $mirror[$plugin]['count'] . ' ' . $this->gettext('downloads')), '(' . $mirror[$plugin]['count'] . ')')) : '') . ($dlprice ? '<br />' . html::tag('table', null, html::tag('tr', null, html::tag('td', null, 'MyRC$') . $prices)) : '')) .
+ html::tag('td', array('style' => 'background:' . $background), $props['version'] . '<br />' . html::tag('small', null, '(' . date($this->rcmail->config->get('date_format', 'm-d-Y'), strtotime($props['date'])) . ')')) .
+ $serverversion .
+ $translation .
+ $submitissue .
+ html::tag('td', array('class' => $stat, 'title' => $plugin . ' :: ' . $this->gettext('update_' . $stat)), '&nbsp;') .
+ $checkbox .
+ html::tag('td', array('title' => $comment?($plugin . ' :: ' . $comment):''), $comment . $append)
+ );
+ }
+ else{
+ if(is_array($mirror[$plugin])){
+ if(is_array($mirror[$plugin]['required'])){
+ $comments = '';
+ if($mirror[$plugin]['comments']){
+ $comments = html::tag('li', null, $mirror[$plugin]['comments']);
+ }
+ $requiredby = '';
+ foreach($mirror[$plugin]['required'] as $key){
+ $requiredby .= '-&nbsp;'.html::tag('a', array('href' => '#' . $key, 'class' => 'anchorLink'), $key) . '<br />';
+ }
+ $requiredby = substr($requiredby, 0, strlen($requiredby) - 2) . "\r\n";
+ $mirror[$plugin]['comments'] = html::tag('ul', array('class' =>'pm_update'), $comments . html::tag('li', null, $this->gettext('requiredby') . ':<br />' . $requiredby));
+ }
+ $tbody2 .= html::tag('tr', null,
+ html::tag('td', array('id' => 'pmu_' . $plugin, 'title' => $mirror[$plugin]['description']), html::tag('a', array('name' => '#' . $plugin), '&nbsp;') . $plugin) .
+ html::tag('td', array('title' => $plugin . ' :: ' . html::tag('a', array('href' => $mirror[$plugin]['download'], 'target' => '_blank'), $this->gettext('develsite')), 'colspan' => 2), ($mirror[$plugin] != 'unknown')?html::tag('a', array('href' => $mirror[$plugin]['download'], 'target' => '_blank'), $this->gettext('homepage')):$this->gettext($mirror[$plugin])) .
+ html::tag('td', array('align' => 'center'), '--') .
+ html::tag('td', array('align' => 'center'), '--') .
+ html::tag('td', array('align' => 'center', 'class' => 'thirdparty'), '--') .
+ html::tag('td', array('align' => 'center'), html::tag('input', array('title' => $plugin . ' :: ' . $this->gettext('thirdpartywarning'), 'class' => 'chbox', 'name' => '_plugins[]', 'value' => $plugin, 'type' => 'checkbox', 'checked'=> false))) .
+ html::tag('td', array('title' => $mirror[$plugin]['comments']?($plugin . ' :: ' . $mirror[$plugin]['comments']):''), $mirror[$plugin]['comments'])
+ );
+ }
+ else{
+ // ToDo: if link is missing: http://www.google.de/search?q=roundcube+fileapi_attachments
+ $tbody2 .= html::tag('tr', null,
+ html::tag('td', array('id' => 'pmu_' . $plugin), '&nbsp;' . $plugin) .
+ html::tag('td', array('colspan' => 2), ($mirror[$plugin] != 'unknown')?html::tag('a', array('href' => $mirror[$plugin], 'target' => '_blank', 'title' => $mirror[$plugin]), $mirror[$plugin]):$this->gettext($mirror[$plugin])) .
+ html::tag('td', array('align' => 'center'), '--') .
+ html::tag('td', array('align' => 'center'), '--') .
+ html::tag('td', array('align' => 'center'), '--') .
+ html::tag('td', array('align' => 'center'), html::tag('input', array('title' => $plugin . ' :: ' . $this->gettext('thirdpartywarning'), 'class' => 'chbox', 'value' => $plugin, 'type' => 'checkbox', 'checked'=> false))) .
+ html::tag('td', null,'&nbsp;')
+ );
+ }
+ }
+ }
+ $boxtitle = html::tag('div', array('id' => 'prefs-title-right'), $this->gettext('plugin_manager_center'));
+ $rctitle = 'rc_ok';
+ $rcclass = 'rcok';
+ $append = html::tag('span', array('class' => 'vmatch'), '&nbsp;'.$this->gettext('rc_uptodate').'&nbsp;');
+ if($mirror_rc > RCMAIL_VERSION){
+ $rctitle = 'rc_update';
+ $rcclass = 'rcupdate';
+ $append = html::tag('span', array('class' => 'vupdate'), '&nbsp;'.$this->gettext('rc_update').'&nbsp;') . '&nbsp;&raquo;&nbsp;' . html::tag('a', array('href' => $this->rcurl, 'target' => '_blank'), $this->gettext('roundcubeurl')) . '&nbsp;';
+ }
+ else if($mirror_rc < RCMAIL_VERSION){
+ $rctitle = 'rc_newer';
+ $rcclass = 'rcerror';
+ $append = html::tag('span', array('class' => 'vmismatch'), '&nbsp;'.sprintf($this->gettext('nottested'), RCMAIL_VERSION).'&nbsp;');
+ }
+ if($branch == 'beta'){
+ $append .= html::tag('span', null, '<br />&nbsp;<div style="float:right; margin-right:10px;">SECTION: MyRoundcube plugins <b>beta</b> branch</div>');
+ }
+ else if($branch == 'dev'){
+ $append .= html::tag('span', null, '<br />&nbsp;<div style="float:right; margin-right:10px;">SECTION: MyRoundcube plugins <b>stable</b> branch</div>');
+ }
+ else if($branch == 'stable'){
+ $append .= html::tag('span', null, '<br />&nbsp;<div style="float:right; margin-right:10px;">SECTION: MyRoundcube plugins <b>frozen</b> branch</div>');
+ }
+ $rctitle = $this->gettext($rctitle);
+ $mirrorh = parse_url($this->mirror);
+ $db = $this->rcmail->config->get('db_dsnw');
+ $db = parse_url($db);
+ $db = $db['scheme'];
+ $web = 'http' . ($_SERVER['HTTPS']?'s':'') . '://'. $_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
+ $user = $_SESSION['username'];
+ if(is_numeric($cdlcredits) && is_numeric($cdlprice)){
+ $remaining = $cdlcredits - $cdlprice;
+ }
+ else{
+ $remaining = 0;
+ }
+ $link = html::tag('a', array('onclick' => 'parent.location.href="./?_task=settings&_action=preferences&_buynow=1"', 'href' => '#'), $this->gettext('customer_account'));
+ $hmchecked = '';
+ $otherchecked = 'checked';
+ if($this->use_hmail){
+ $hmchecked = 'checked';
+ $otherchecked = '';
+ }
+ if($this->admins[$this->rcmail->user->data['username']] == 0){
+ $hmail = html::tag('span', null, 'IMAP-Server:&nbsp;') .
+ html::tag('input', array('type' => 'radio', 'name' => 'hmailbackend', 'id' => 'yhmail', 'checked' => $hmchecked, 'onclick' => 'pm_hmail(false)')) . html::tag('span', null, html::tag('a', array('href' => 'http://www.hmailserver.com/', 'target' => '_blank'), 'hMailserver') . '&nbsp;') .
+ html::tag('input', array('type' => 'radio', 'name' => 'hmailbackend', 'id' => 'nhmail', 'checked' => $otherchecked, 'onclick' => 'pm_hmail(true)')) . html::tag('span', null, 'other') . '&nbsp;&rArr;&nbsp;';
+ }
+ else{
+ $hmail = '';
+ }
+ $credits = html::tag('div', array('style' => 'display:block; border:1px solid lightgrey; background:lightyellow; padding:2px 2px 2px 2px; width:99%;'), '&nbsp;' . $hmail . 'MyRC$ ' .
+ html::tag('span', array('id' => 'cdlcredits'), ($cdlcredits ? $cdlcredits : 0)) . ' (' . $this->gettext('credits') . ') &minus; MyRC$ ' . html::tag('span', array('id' => 'cdlprice'), $cdlprice) . '&nbsp(' . $this->gettext('forthisdownload') . ') = ' . 'MyRC$ ' . html::tag('span', array('id' => 'cdlremaining'), $remaining) . ($remaining > 0 ? '&nbsp;(' . $this->gettext('remainingcredits') . ')' : '&nbsp;(' . $link . ')')
+ );
+ $controls = html::tag('div', array('style' => 'display: inline; float: right; margin-right: 5px;'), html::tag('a', array('id' => 'buycreditslink', 'href' => './?_task=settings&_action=plugin.plugin_manager_buycredits', 'target' => '_blank'), $this->gettext('buynow'))) .
+ html::tag('div', array('style' => 'display: inline; float: right;'), html::tag('a', array('href' => '#', 'onclick' => 'pm_discard()'), $this->gettext('discardliabletopaycosts')) . '&nbsp;|&nbsp;' . html::tag('a', array('href' => '#', 'onclick' => 'pm_notinstalled()'), $this->gettext('unchecknotinstalledplugins')) . '&nbsp;|&nbsp;');
+ $zipbutton = $credits . html::tag('br') . html::tag('input', array('type' => 'submit', 'class' => 'button mainaction', 'value' => $this->gettext('ziparchive'))) . $controls;
+ /*$paypalbutton = html::tag('form', array('action' => "https://www.paypal.com/cgi-bin/webscr", 'method' => "post", 'target' => '_blank'),
+ html::tag('input', array('type' => "hidden", 'name' => "cmd", 'value' => "_s-xclick")) .
+ html::tag('input', array('type' => "hidden", 'name' => "hosted_button_id", 'value' => "37WMD9TBQXRNG")) .
+ html::tag('input', array('type' => "image", 'src' => "https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif", 'border' => "0", 'name' => "submit", 'alt' => "PayPal - The safer, easier way to pay online!")) .
+ html::tag('img', array('alt' => "", 'border' => "0", 'src' => "https://www.paypalobjects.com/en_US/i/scr/pixel.gif", 'width' => "1", 'height' => "1"))
+ );*/
+ if(strtolower($this->get_demo($user)) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $zipbutton = $zipbutton = html::tag('input', array('type' => 'button', 'class' => 'button mainaction', 'value' => $this->gettext('demoaccount')));;
+ }
+ $formcontent = html::tag('div', array('id' => 'rcheader'), '<br />Roundcube:&nbsp;' . $this->gettext('serverversion') . '&nbsp;' . RCMAIL_VERSION . '&nbsp;&raquo;&nbsp;' . $this->gettext('mirrorversion') . '&nbsp;' . $mirror_rc . '&nbsp;&raquo;&nbsp;' . $append . '<hr />');
+ $formcontent .= html::tag('p', null);
+ $formcontent .= html::tag('div', array('id' => 'table-container', 'style' => 'height:0px; overflow:auto; margin-right:10px;'), html::tag('table', array('id' => 'table', 'border' => 0, 'cellspacing' => 0, 'cellpadding' => 0), html::tag('thead', null, $thead) . html::tag('tbody', null, $tbody1 . $tbody2)));
+ $formcontent .= html::tag('div', array('id' => 'update_footer'), html::tag('p', null, null) .
+ $zipbutton .
+ html::tag('input', array('type' => 'button', 'onclick' => 'document.location.href="./?_task=settings&_framed=1&_action=plugin.plugin_manager_update&_warning=1"', 'class' => 'button', 'value' => $this->gettext('cancel'))) .
+ html::tag('br') . html::tag('div', array('class' => 'asterix'), '&sup1;' . $this->gettext('donotregister') . '<br />&sup2;' . $this->gettext('register')) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_price', 'id' => 'pm_price', 'value' => '##placeholder##')) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_customer_id', 'value' => $this->rcmail->config->get('customer_id'))) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_admin', 'value' => $user)) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_serveradmin', 'value' => $_SERVER['SERVER_ADMIN'])) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_newsletter', 'value' => get_input_value('_newsletter', RCUBE_INPUT_GPC))) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_branch', 'value' => get_input_value('_branch', RCUBE_INPUT_GPC))) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_firstname', 'value' => urldecode(get_input_value('_firstname', RCUBE_INPUT_GPC)))) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_lastname', 'value' => urldecode(get_input_value('_lastname', RCUBE_INPUT_GPC)))) .
+ /*html::tag('input', array('type' => 'hidden', 'name' => '_pm_self', 'value' => $web)) .*/
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_serverip', 'value' => $server['ip'])) .
+ /*html::tag('input', array('type' => 'hidden', 'name' => '_pm_servername', 'value' => $_SERVER['SERVER_NAME'])) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_serverport', 'value' => $_SERVER['SERVER_PORT'])) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_serverprotocol', 'value' => $_SERVER['SERVER_PROTOCOL'])) .*/
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_serversoftware', 'value' => $_SERVER['SERVER_SOFTWARE'])) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_rcmail', 'value' => RCMAIL_VERSION)) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_version', 'value' => self::$version)) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_db', 'value' => $db)) .
+ html::tag('input', array('type' => 'hidden', 'name' => '_pm_php', 'value' => phpversion())) .
+ html::tag('p', null, null)
+ );
+ $formfooter = html::tag('div', array('id' => 'formfooter'), html::tag('div', array('class' => 'footerleft'), html::tag('form', array('name' => 'form', 'onsubmit' => 'return pmf();', 'method' => 'post', 'action' => str_ireplace('http:', 'https:', $this->mirror) . '?_action=plugin.plugin_server_request&_hl=' . $_SESSION['language']), $formcontent)));
+ $formfooter .= html::tag('script', array('type' => 'text/javascript'), '$("body").hide();');
+ $this->rcmail->output->add_label(
+ 'plugin_manager.creditsupdated'
+ );
+ $paypalbutton = html::tag('a', array('href' => 'http://myroundcube.com/#contact', 'target' => '_blank'), 'MyRoundcube ' . $this->gettext('support'));
+ $this->rcmail->output->add_script('if(screen.width < 1300){$(".pm_update").html("..."); $("#settings-sections").hide();$("#pluginbody").css("left", "5px")}', 'docready');
+ return html::tag('div', array('id' =>'prefs-box', 'style' => 'width: 100%; overflow: auto;'), $boxtitle . $formfooter) . html::tag('div', array('id' => 'paypalcontainer'), html::tag('div', array('id' => 'paypal'), $paypalbutton));
+ }
+
+ function getcredits($ajax = true){
+ $params = array('_customer_id' => $this->rcmail->config->get('customer_id'));
+ $httpConfig['method'] = 'POST';
+ $httpConfig['target'] = str_replace('buycredits', 'getcredits', $this->billingurl);
+ $httpConfig['timeout'] = '30';
+ $httpConfig['params'] = $params;
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ if($http->error){
+ $response = false;
+ }
+ else{
+ $response = $http->result;
+ }
+ if($response == '-0'){
+ unset($httpConfig['params']);
+ $httpConfig['method'] = 'GET';
+ $httpConfig['target'] .= '&_customer_id=' . $this->rcmail->config->get('customer_id');
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ if($http->error){
+ $response = false;
+ }
+ else{
+ $response = $http->result;
+ }
+ }
+ if($ajax)
+ $this->rcmail->output->command('plugin.plugin_manager_getcredits', $response);
+ else
+ return $response;
+ }
+
+ function buycredits(){
+ $params = array(
+ '_customer_id' => $this->rcmail->config->get('customer_id'),
+ '_clientip' => $_SERVER['REMOTE_ADDR'],
+ '_serverip' => $_SERVER['SERVER_ADDR']
+ );
+ $httpConfig['method'] = 'POST';
+ $httpConfig['target'] = $this->billingurl;
+ $httpConfig['timeout'] = '30';
+ $httpConfig['params'] = $params;
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ if($http->error){
+ $this->rcmail->output->send('plugin_manager.error');
+ }
+ else{
+ $url = explode('?', $this->billingurl, 2);
+ $url = slashify($url[0]);
+ $page = $http->result;
+ $page = str_replace('href="plugins/', 'href="' . $url . 'plugins/', $page);
+ $page = str_replace('src="skins/', 'src="' . $url . 'skins/', $page);
+ $page = str_replace('<img src="plugins/', '<img src="' . $url . 'plugins/', $page);
+ $page = str_replace('<script type="text/javascript" src="plugins/', '<script type="text/javascript" src="' . $url . 'plugins/', $page);
+ send_nocacheing_headers();
+ echo $page;
+ }
+ exit;
+ }
+
+ function getnew(){
+ $params = array('_customer_id' => $this->rcmail->config->get('customer_id'), '_ip' => $this->getVisitorIP());
+ $httpConfig['method'] = 'POST';
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_customer_id_new';
+ $httpConfig['timeout'] = '30';
+ $httpConfig['params'] = $params;
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ if($http->error){
+ $response = false;
+ }
+ else{
+ $response = $http->result;
+ }
+ if(is_string($response) && strlen($response) == 32){
+ $a_prefs['customer_id'] = $response;
+ $a_prefs['own_customer_id'] = $response;
+ $this->rcmail->user->save_prefs($a_prefs);
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'admins');
+ $admins = $this->rcmail->db->fetch_assoc($res);
+ if($admins = unserialize($admins['value'])){
+ if($admins[0] == $this->rcmail->user->data['username']){
+ foreach($admins as $idx => $admin){
+ if($idx == 0) continue;
+ $sql = 'SELECT ' . $this->q('preferences') . ' FROM ' . get_table_name('users') . ' WHERE ' . $this->q('username') . '=? AND ' . $this->q('mail_host') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, $admin, $_SESSION['storage_host']);
+ $prefs = $this->rcmail->db->fetch_assoc($res);
+ if($prefs = unserialize($prefs['preferences'])){
+ if($prefs['customer_id'] == $prefs['shared_customer_id']){
+ $prefs['customer_id'] = $reponse;
+ }
+ $prefs['shared_customer_id'] = $response;
+ $prefs = serialize($prefs);
+ $sql = 'UPDATE ' . get_table_name('users') . ' SET ' . $this->q('preferences') . '=? WHERE ' . $this->q('username') . '=? AND ' . $this->q('mail_host') . '=?';
+ $this->rcmail->db->query($sql, $prefs, $admin, $_SESSION['storage_host']);
+ }
+ }
+ }
+ }
+ }
+ else{
+ unset($httpConfig['params']);
+ $httpConfig['method'] = 'GET';
+ $httpConfig['target'] .= '&_customer_id=' . $this->rcmail->config->get('customer_id') . '&_ip=' . $this->getVisitorIP();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ if($http->error){
+ $response = false;
+ }
+ else{
+ $response = $http->result;
+ }
+ if(is_string($response) && strlen($response) == 32){
+ $a_prefs['customer_id'] = $response;
+ $a_prefs['own_customer_id'] = $response;
+ $this->rcmail->user->save_prefs($a_prefs);
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'admins');
+ $admins = $this->rcmail->db->fetch_assoc($res);
+ if($admins = unserialize($admins['value'])){
+ if($admins[0] == $this->rcmail->user->data['username']){
+ foreach($admins as $idx => $admin){
+ if($idx == 0) continue;
+ $sql = 'SELECT ' . $this->q('preferences') . ' FROM ' . get_table_name('users') . ' WHERE ' . $this->q('username') . '=? AND ' . $this->q('mail_host') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, $admin, $_SESSION['storage_host']);
+ $prefs = $this->rcmail->db->fetch_assoc($res);
+ if($prefs = unserialize($prefs['preferences'])){
+ if($prefs['customer_id'] == $prefs['shared_customer_id']){
+ $prefs['customer_id'] = $reponse;
+ }
+ $prefs['shared_customer_id'] = $response;
+ $prefs = serialize($prefs);
+ $sql = 'UPDATE ' . get_table_name('users') . ' SET ' . $this->q('preferences') . '=? WHERE ' . $this->q('username') . '=? AND ' . $this->q('mail_host') . '=?';
+ $this->rcmail->db->query($sql, $prefs, $admin, $_SESSION['storage_host']);
+ }
+ }
+ }
+ }
+ }
+ }
+ header('Location: ./?_task=settings&_action=edit-prefs&_section=plugin_manager_customer&_framed=1');
+ exit;
+ }
+
+ function restore_config(){
+ if($this->config_permissions){
+ $plugin = get_input_value('_plugin', RCUBE_INPUT_GPC);
+ $this->show('./plugins/' . $plugin . '/config.inc.php.dist', 'restore');
+ }
+ }
+
+ function edit_config(){
+ if($this->config_permissions){
+ if($plugin = get_input_value('_plugin', RCUBE_INPUT_GPC)){
+ $admin = false;
+ $sql = 'SELECT * FROM ' . get_table_name('db_config') . ' WHERE ' . $this->q('env') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, $plugin);
+ $conf = $this->rcmail->db->fetch_assoc($res);
+ if($conf['conf']){
+ $conf['conf'] = str_replace('$rcmail_config', '$config', $conf['conf']);
+ $source = 'database';
+ $admin = $conf['admin'];
+ include INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php.dist';
+ $skip_deprecated = false;
+ if($plugin == 'register'){
+ if(isset($conf['conf'])){
+ eval($conf['conf']);
+ }
+ if($driver = $config['register_driver']){
+ include INSTALL_PATH . 'plugins/register/drivers/' . $driver . '/driver.php';
+ }
+ else{
+ $skip_deprecated = true;
+ }
+ }
+ if(is_array($rcmail_config)){
+ $config = $rcmail_config;
+ $sconfig = $rcmail_config;
+ $defaults = $sconfig;
+ $scomments = $rcmail_config_comments;
+ $rcmail_config = false;
+ }
+ else{
+ $sconfig = $config;
+ $defaults = $sconfig;
+ $scomments = $config_comments;
+ }
+ $config = array();
+ eval($conf['conf']);
+ if(is_array($rcmail_config)){
+ $config = $rcmail_config;
+ $rcmail_config = false;
+ }
+ foreach($config as $key => $val){
+ unset($sconfig[$key]);
+ }
+ foreach($config as $key => $val){
+ if(!isset($defaults[$key]) && !$skip_deprecated){
+ if($dist = @file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php.dist')){
+ if(strpos($dist, '$config[\'' . $key . '\']') === false){
+ if(strpos($conf['conf'], "/* The following configuration parameter is deprecated - please remove */\n" . '$config[\'' . $key . '\']') === false){
+ $conf['conf'] = str_replace('$config[\'' . $key . '\']', "/* The following configuration parameter is deprecated - please remove */\r\n" . '$config[\'' . $key . '\']', $conf['conf']);
+ }
+ }
+ }
+ }
+ }
+ $prepend = '';
+ if(count($sconfig > 0)){
+ $code = '';
+ foreach($sconfig as $key => $val){
+ if(strpos($conf['conf'], '$config[\'' . $key . '\']') === false){
+ if($comment = $scomments[$key]){
+ $code .= "\r\n" . '/* ' . $comment . ' */' . "\r\n";
+ }
+ $code .= '$config[\'' . $key . '\'] = ' . var_export($val, true) .';' . "\r\n";
+ }
+ }
+ if($code){
+ $prepend = '/*---- New configuration parameters since last saving ----*/' . "\r\n\r\n" .
+ $code . "\r\n" .
+ '/*----------------------------------------------------------*/' . "\r\n\r\n" .
+ '/* Begin currently saved parameters */' . "\r\n\r\n";
+ }
+ }
+ $_POST['_save_config'] = "<?php\r\n\r\n" . $prepend . $conf['conf'] . "\r\n\r\n?>";
+ }
+ else{
+ if(file_exists(INSTALL_PATH . 'plugins/global_config/config.inc.php')){
+ include INSTALL_PATH . 'plugins/global_config/config.inc.php';
+ if(is_array($rcmail_config)){
+ $global_config = $rcmail_config;
+ $rcmail_config = array();
+ }
+ else{
+ $global_config = $config;
+ $config = array();
+ }
+ }
+ $source = './plugins/' . $plugin . '/config.inc.php.dist';
+ $conf = file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php.dist');
+ if($plugin == 'register'){
+ if($driver = $this->rcmail->config->get('register_driver')){
+ if(file_exists(INSTALL_PATH . 'plugins/register/drivers/' . $driver . '/config.inc.php.dist')){
+ $source = ', ./plugins/' . $plugin . 'drivers/' . $driver . '/config.inc.php.dist';
+ $conf .= file_get_contents(INSTALL_PATH . 'plugins/register/drivers/' . $driver . '/config.inc.php.dist');
+ $conf = str_replace('?><?php', '/* ' . INSTALL_PATH . 'plugins/regster/drivers/' . $driver . '/config.inc.php */', $conf);
+ }
+ }
+ }
+ $conf = str_replace('$rcmail_config', '$config', $conf);
+ include INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php.dist';
+ if(is_array($rcmail_config)){
+ $config = $rcmail_config;
+ }
+ $rcmail_config = array();
+ $config = array();
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php')){
+ $source = './plugins/' . $plugin . '/config.inc.php';
+ include INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php';
+ }
+ if($plugins == 'register'){
+ if($driver = $this->rcmail->config->get('register_driver')){
+ if(file_exists(INSTALL_PATH . 'plugins/register/drivers/' . $driver . '/config.inc.php')){
+ $source = ', ./plugins/' . $plugin . 'drivers/' . $driver . '/config.inc.php';
+ include INSTALL_PATH . 'plugins/register/drivers/' . $driver . '/config.inc.php';
+ }
+ }
+ }
+ if(file_exists(INSTALL_PATH . 'plugins/global_config/config.inc.php')){
+ include INSTALL_PATH . 'plugins/global_config/config.inc.php';
+ }
+ foreach($config as $key => $val){
+ if(isset($global_config[$key])){
+ $source = './plugins/global_config/config.inc.php';
+ }
+ $conf = preg_replace('/\n\$config\[\'' . $key . '\'\] = \$/s', "\n" . '//***$config[' . "'" . $key . "'" . '] = $', $conf);
+ if(isset($config[$key])){
+ $conf = preg_replace('/\n\$config\[\'' . $key . '\'\](.+?);(\r|\n)/s', "\n" . '$config[' . "'" . $key . "'" . '] = ' . var_export($config[$key], true) . ';', $conf);
+ }
+ }
+ $conf = str_replace("\n" . '//***$config[', "\n" . '$config[', $conf);
+ $_POST['_save_config'] = $conf;
+ }
+ }
+ $this->show($source, 'edit', $admin);
+ }
+ }
+
+ function check_syntax($conf = false){
+ $test = "if(0){\n" . $conf . "\n}";
+ @ini_set('log_errors', false);
+ @ini_set('display_errors', true);
+ ob_start();
+ eval($test);
+ $error = str_replace(': eval()\'d code ', '', strip_tags(ob_get_clean()));
+ ob_end_clean();
+ return $error;
+ }
+
+ function save_config(){
+ if($this->config_permissions){
+ $plugin = get_input_value('_plugin', RCUBE_INPUT_POST);
+ $source = get_input_value('_source', RCUBE_INPUT_POST);
+ $conf = trim($_POST['_save_config']);
+ $conf = str_replace('+', '__plus__', $conf);
+ $conf = urldecode($conf);
+ $conf = str_replace('__plus__', '+', $conf);
+ $conf = str_replace('/*---- New configuration parameters since last saving ----*/' . "\n\n", '', $conf);
+ $conf = str_replace('/*----------------------------------------------------------*/' . "\n\n", '', $conf);
+ $conf = str_replace('/* Begin currently saved parameters */' . "\n\n", '', $conf);
+ $conf = explode("\n", $conf);
+ if(strtolower(trim($conf[count($conf) -1])) == '?>'){
+ unset($conf[count($conf) -1]);
+ }
+ if(strtolower(trim($conf[0])) == '<?php'){
+ unset($conf[0]);
+ }
+ $conf = trim(stripslashes(implode("\n", $conf)));
+ $error = $this->check_syntax($conf);
+ if($error){
+ $conf = str_replace("\\'", '"', $conf);
+ $error = $this->check_syntax($conf);
+ }
+ if(!$error){
+ $sql = 'DELETE FROM ' . get_table_name('db_config') . ' WHERE ' . $this->q('env') . '=?';
+ $this->rcmail->db->query($sql, $plugin);
+ $sql = 'INSERT INTO ' . get_table_name('db_config') . '(' . $this->q('env') . ', ' . $this->q('conf') . ', ' . $this->q('admin') . ') VALUES (?, ?, ?)';
+ $this->rcmail->db->query($sql, $plugin, $conf, $this->rcmail->user->data['username']);
+ $this->rcmail->output->command('plugin.plugin_manager_save_config', array($this->gettext('successfullysaved'), 'confirmation'));
+ }
+ else{
+ $this->rcmail->output->command('plugin.plugin_manager_save_config', array($error, 'error'));
+ }
+ }
+ else{
+ $this->rcmail->output->command('plugin.plugin_manager_save_config', array($this->gettext('errorsaving'), 'error'));
+ }
+ }
+
+ function show($source = false, $mode = 'edit', $admin = false){
+ $plugin = get_input_value('_plugin', RCUBE_INPUT_GPC);
+ if(!$source){
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php.dist')){
+ $source = './plugins/' . $plugin . '/config.inc.php.dist';
+ }
+ }
+ if(strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $this->out = html::tag('h3', null, '&nbsp;&nbsp;Access denied (Demo Account)') .
+ html::tag('div', array('style' => 'float: left;'), '&nbsp;&nbsp;[' . html::tag('a', array('href' => './?_task=settings&_action=edit-prefs&_section=plugin_manager_settings&_framed=1&_expand=' . $plugin), $this->gettext('back')) . ']');
+ }
+ else if($plugin){
+ $GLOBALS['codemirror'] = array(
+ 'mode' => 'PHP',
+ 'elem' => 'code',
+ 'readonly' => false,
+ 'buttons' => '["save", "undo", "redo", "jump", "search"]',
+ 'save' => 'function(){document.getElementById("code").value = editor.mirror.getValue(); rcmail.http_post("plugin.plugin_manager_save_config", "_plugin=' . $plugin . '&_save_config=" + urlencode($("#code").val()));}',
+ );
+ $this->require_plugin('codemirror_ui');
+ if(isset($_POST['_save_config'])){
+ $content = trim($_POST['_save_config']);
+ }
+ else{
+ $content = file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php.dist');
+ if($plugin == 'register'){
+ if($driver = $this->rcmail->config->get('register_driver')){
+ if(file_exists(INSTALL_PATH . 'plugins/register/drivers/' . $driver . '/config.inc.php.dist')){
+ $content .= file_get_contents(INSTALL_PATH . 'plugins/register/drivers/' . $driver . '/config.inc.php.dist');
+ $content = str_replace('?><?php', '', $content);
+ }
+ }
+ }
+ }
+ if($mode == 'edit'){
+ $action = '&nbsp;[' . html::tag('a', array('href' => './?_task=settings&_action=plugin.plugin_manager_restore_config&_framed=1&_plugin=' . $plugin), $this->gettext('restoredefaults')) . ']';
+ }
+ else{
+ $action = '&nbsp;[' . html::tag('a', array('href' => './?_action=plugin.plugin_manager_edit_config&_framed=1&_plugin=' . $plugin), $this->gettext('edit')) . ']';
+ }
+ if(in_array($plugin, $this->nodocs)){
+ $instructions = html::tag('div', array('style' => 'float: left;'),
+ '&nbsp;[' . html::tag('a', array('target' => '_blank', 'href' => 'http://myroundcube.com/myroundcube-plugins#' . $plugin), $this->gettext('instructions')) . ']');
+
+ }
+ else if(isset($this->docsmap[$plugin])){
+ $instructions = html::tag('div', array('style' => 'float: left;'),
+ '&nbsp;[' . html::tag('a', array('target' => '_blank', 'href' => 'http://myroundcube.com/myroundcube-plugins/' . $this->docsmap[$plugin]), $this->gettext('instructions')) . ']');
+ }
+ else{
+ $instructions = html::tag('div', array('style' => 'float: left;'),
+ '&nbsp;[' . html::tag('a', array('target' => '_blank', 'href' => 'http://myroundcube.com/myroundcube-plugins/' . $plugin . '-plugin'), $this->gettext('instructions')) . ']');
+ }
+ $this->include_script('plugin_manager.js');
+ $this->out = html::tag('form', array('method' => 'post', 'name' => 'form', 'action' => './?_task=settings&_action=plugin.plugin_manager_save_config&_framed=1'),
+ html::tag('div', array('style' => 'position:absolute; top: 20px; bottom: 20px; left: 20px; right: 20px;'),
+ html::tag('div', array('style' => 'float: left;'), $this->gettext('plugin') . ':&nbsp;' . $plugin) .
+ html::tag('div', array('style' => 'float: right;', 'id' => 'source'), ($source ? ($this->gettext('source') . ':&nbsp;') : '') . ($source == 'database' ? $this->gettext('database') : $source) . ($admin ? html::tag('small', null, html::tag('span', null, '&nbsp;(' . $this->gettext('configuredby') . '&nbsp;' . $admin . ')')) : '')) .
+ html::tag('input', array('name' => '_plugin', 'type' => 'hidden', 'value' => $plugin)) .
+ html::tag('input', array('name' => '_source', 'type' => 'hidden', 'value' => $source)) .
+ html::tag('br') .
+ html::tag('textarea', array('style' => 'width: 100%; height: 95%', 'name' => '_save_config', 'id' => 'code'),
+ $content
+ ) .
+ html::tag('br') .
+ html::tag('div', array('style' => 'float: left;'),
+ $instructions .
+ $action .
+ '&nbsp;[' . html::tag('a', array('href' => './?_task=settings&_action=edit-prefs&_section=plugin_manager_settings&_framed=1&_expand=' . $plugin), $this->gettext('back')) . ']')
+ )
+ );
+ }
+ else{
+ $GLOBALS['codemirror'] = array(
+ 'mode' => 'PHP',
+ 'elem' => 'code',
+ 'readonly' => true,
+ 'buttons' => '["jump", "search"]',
+ 'save' => 'function(){}',
+ );
+ $this->require_plugin('codemirror_ui');
+ $header = str_replace('##YEAR##', date('Y'), file_get_contents(INSTALL_PATH . 'plugins/plugin_manager/CONFIGHEADER'));
+ $example = file_get_contents(INSTALL_PATH . 'plugins/plugin_manager/EXAMPLE');
+ $this->out = html::tag('div', array('style' => 'position:absolute; top: 20px; bottom: 20px; left: 20px; right: 20px;'),
+ html::tag('textarea', array('readonly' => true, 'style' => 'width: 100%; height: 95%', 'id' => 'code'),
+ "<?php\r\n" .
+ $header . "\r\n" .
+ $example . "\r\n\r\n" .
+ '/* Configuration */' . "\r\n\r\n" .
+ '/* Plugins which have to be loaded in not authenticated state even if disabled by user */' . "\r\n" .
+ '$config[\'plugin_manager_unauth\'] = ' .
+ var_export($this->unauth, true) . ";\r\n\r\n" .
+ '/* Defaults */' . "\r\n" .
+ '$config[\'plugin_manager_defaults\'] = ' .
+ var_export($this->defaults, true) . ";\r\n?>"
+ ) .
+ html::tag('div', array('style' => 'float: right;'), '[' . html::tag('a', array('href' => './?_task=settings&_action=edit-prefs&_section=plugin_manager_settings&_framed=1'), $this->gettext('back')) . ']')
+ );
+ }
+ $this->register_handler('plugin.body', array($this, 'sqlerror'));
+ $this->rcmail->output->send('plugin_manager.config');
+ }
+
+ function deny(){
+ $customer_id = $this->rcmail->config->get('customer_id');
+ $own_customer_id = $this->rcmail->config->get('own_customer_id');
+ $a_prefs = array();
+ $a_prefs['customer_id'] = $own_customer_id;
+ $a_prefs['shared_customer_id'] = $customer_id;
+ $this->rcmail->user->save_prefs($a_prefs);
+ header('Location: ./?_task=settings&_action=edit-prefs&_section=plugin_manager_customer&_framed=1');
+ exit;
+ }
+
+ function accept(){
+ $customer_id = $this->rcmail->config->get('shared_customer_id');
+ $a_prefs = array();
+ $a_prefs['customer_id'] = $customer_id;
+ $this->rcmail->user->save_prefs($a_prefs);
+ header('Location: ./?_task=settings&_action=edit-prefs&_section=plugin_manager_customer&_framed=1');
+ exit;
+ }
+
+ function settings_link($args){
+ $args['list']['plugin_manager'] = array(
+ 'id' => 'plugin_manager',
+ 'section' => $this->gettext('plugin_manager_title')
+ );
+ $user = $_SESSION['username'];
+ $admins = $this->admins;
+ if(strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ if($this->rcmail->config->get('demo_target_group', 'admins') == 'admins'){
+ $demo = true;
+ }
+ }
+ if((isset($admins[strtolower($user)]) && $admins[strtolower($user)] == 0 && file_exists(INSTALL_PATH . $this->rcmail->config->get('plugin_manager_hash') . '.myrc')) || $demo){
+ $args['list']['plugin_manager_admins'] = array(
+ 'id' => 'plugin_manager_admins',
+ 'section' => $this->gettext('submenuprefix') . $this->gettext('manage_admins')
+ );
+ }
+ if((isset($admins[strtolower($user)]) && file_exists(INSTALL_PATH . $this->rcmail->config->get('plugin_manager_hash') . '.myrc')) || $demo){
+ $args['list']['plugin_manager_settings'] = array(
+ 'id' => 'plugin_manager_settings',
+ 'section' => $this->gettext('submenuprefix') . $this->gettext('settings')
+ );
+ }
+ if(!$this->noremote && isset($admins[strtolower($user)]) || $demo){
+ $args['list']['plugin_manager_update'] = array(
+ 'id' => 'plugin_manager_update',
+ 'section' => $this->gettext('submenuprefix') . $this->gettext('update_plugins')
+ );
+ if(!$demo){
+ $args['list']['plugin_manager_customer'] = array(
+ 'id' => 'plugin_manager_customer',
+ 'section' => $this->gettext('submenuprefix') . $this->gettext('customer_account')
+ );
+ if(!$this->rcmail->config->get('customer_id')){
+ $customer_id = $this->getCustomerID();
+ if(is_string($customer_id) && strlen($customer_id) == 32){
+ $a_prefs['customer_id'] = $customer_id;
+ $this->rcmail->user->save_prefs($a_prefs);
+ }
+ }
+ $customer_id = $this->rcmail->config->get('customer_id');
+ if($_GET['_buynow'] || !$customer_id){
+ if(!$customer_id){
+ $customer_id = $this->getCustomerID();
+ $arr['customer_id'] = $customer_id;
+ $this->rcmail->user->save_prefs($arr);
+ $this->rcmail->output->add_script('rcmail.display_message("' . $this->gettext('getnew') . '", "notice");', 'docready');
+ }
+ $this->rcmail->output->add_script('rcmail.sections_list.select("plugin_manager_customer");', 'docready');
+ }
+ }
+ }
+ return $args;
+ }
+
+ function bind(){
+ if(isset($this->admins[strtolower($_SESSION['username'])]) && file_exists(INSTALL_PATH . $this->rcmail->config->get('plugin_manager_hash') . '.myrc')){
+ $target = get_input_value('_target', RCUBE_INPUT_GET);
+ $section = get_input_value('_section', RCUBE_INPUT_GET);
+ if($section && $target){
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'defaults_overwrite');
+ $overwrite = $this->rcmail->db->fetch_assoc($res);
+ if(is_array($overwrite)){
+ $defaults = unserialize($overwrite['value']);
+ if(is_array($defaults)){
+ include INSTALL_PATH . 'plugins/plugin_manager/defaults.inc.php';
+ $defaults[$section][$target]['protected'] = $config['plugin_manager_defaults'][$section][$target]['protected'];
+ $sql = 'UPDATE ' . get_table_name('plugin_manager') . ' SET ' . $this->q('value') . '=?, ' . $this->q('type') . '=? WHERE ' . $this->q('conf') . '=?';
+ $this->rcmail->db->query($sql, serialize($defaults), 'array', 'defaults_overwrite');
+ $this->rcmail->session->remove('plugin_manager_defaults');
+ }
+ }
+ header('Location: ./?_task=settings&_action=edit-prefs&_section=plugin_manager_settings&_framed=1');
+ exit;
+ }
+ }
+ }
+
+ function unbind(){
+ if(isset($this->admins[strtolower($_SESSION['username'])]) && file_exists(INSTALL_PATH . $this->rcmail->config->get('plugin_manager_hash') . '.myrc')){
+ $target = get_input_value('_target', RCUBE_INPUT_GET);
+ $section = get_input_value('_section', RCUBE_INPUT_GET);
+ if($section && $target){
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'defaults_overwrite');
+ $overwrite = $this->rcmail->db->fetch_assoc($res);
+ if(!is_array($overwrite)){
+ include INSTALL_PATH . 'plugins/plugin_manager/defaults.inc.php';
+ $overwrite = $config['plugin_manager_defaults'];
+ }
+ else{
+ $overwrite = unserialize($overwrite['value']);
+ if(!is_array($overwrite)){
+ include INSTALL_PATH . 'plugins/plugin_manager/defaults.inc.php';
+ $overwrite = $config['plugin_manager_defaults'];
+ }
+ }
+ $overwrite[$section][$target]['protected'] = false;
+ $sql = 'DELETE FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $this->rcmail->db->query($sql, 'defaults_overwrite');
+ $sql = 'INSERT INTO ' . get_table_name('plugin_manager') . ' (' . $this->q('conf') . ', ' . $this->q('value') . ', ' . $this->q('type') . ') VALUES(?, ?, ?)';
+ $this->rcmail->db->query($sql, 'defaults_overwrite', serialize($overwrite), 'array');
+ $this->rcmail->session->remove('plugin_manager_defaults');
+ header('Location: ./?_task=settings&_action=edit-prefs&_section=plugin_manager_settings&_framed=1');
+ exit;
+ }
+ }
+ }
+
+ function settings($args){
+ // Do not run the section just for building the settings section link
+ if(!get_input_value('_framed', RCUBE_INPUT_GPC)){
+ if($args['section'] == 'plugin_manager'){
+ $skin = $this->rcmail->config->get('skin');
+ if(!file_exists($this->home . '/skins/' . $skin . '/plugin_manager.css')) {
+ $skin = "classic";
+ }
+ $this->include_stylesheet('skins/' . $skin . '/plugin_manager.css');
+ }
+ if(substr($args['section'], 0, strlen('plugin_manager')) == 'plugin_manager'){
+ if($args['section'] != 'plugin_manager'){
+ $args['blocks'][$args['section']]['options'] = array(
+ 'title' => '',
+ 'content' => html::tag('div', array('id' => 'pm_dummy'), '')
+ );
+ return $args;
+ }
+ }
+ }
+ if($args['section'] == 'plugin_manager'){
+ $this->include_script('plugin_manager.js');
+ $skin = $this->rcmail->config->get('skin');
+ if(!file_exists($this->home . '/skins/' . $skin . '/plugin_manager.css')) {
+ $skin = "classic";
+ }
+ $this->include_stylesheet('skins/' . $skin . '/plugin_manager.css');
+ $args['blocks']['plugin_manager'] = array(
+ 'options' => array(),
+ 'name' => ''
+ );
+ $this->merge_config();
+ $content = '';
+ $restore = array();
+ $display_section = array();
+ foreach($this->config as $section => $props) {
+ if(count($props) > 0){
+ $li = array();
+ foreach($props as $plugin => $prop){
+ $show = true;
+ if($this->domain){
+ if(is_array($prop['domains']) && count($prop['domains'] > 0)){
+ $show = false;
+ foreach($prop['domains'] as $domain){
+ if($this->domain == $domain){
+ $show = true;
+ break;
+ }
+ }
+ }
+ if(is_array($prop['hosts']) && count($prop['hosts'] > 0)){
+ $show = false;
+ foreach($prop['hosts'] as $host){
+ if($this->host == strtolower($host)){
+ $show = true;
+ break;
+ }
+ }
+ }
+ if($prop['browser']){
+ $show = false;
+ if(!$browser)
+ $browser = new rcube_browser();
+ eval($prop['browser']);
+ if($test){
+ if($prop['active']){
+ $show = true;
+ }
+ }
+ }
+ if($prop['autoload']){
+ $show = false;
+ }
+ if($prop['protected']){
+ if($prop['protected'] === true){
+ $show = false;
+ }
+ else if(is_string($prop['protected'])){
+ $show = false;
+ }
+ else if(is_array($prop['protected']) && count($prop['protected']) > 0){
+ foreach($prop['protected'] as $domain){
+ if($this->domain == strtolower($domain)){
+ $show = false;
+ break;
+ }
+ }
+ }
+ }
+ if(is_array($prop['skins'])){
+ $prop['skins'] = array_flip($prop['skins']);
+ if(!isset($prop['skins'][$this->rcmail->config->get('skin', 'classic')])){
+ $show = false;
+
+ }
+ }
+ }
+ if($show){
+ $display_section[$section] = true;
+ $defaults = $this->defaults;
+ $restore[$plugin] = array($plugin, $defaults[$section][$plugin]['active']);
+ if($user[$section][$plugin]){
+ $prop = $user[$section][$plugin];
+ }
+ if(is_array($prop['buttons'])){
+ $this->rcmail->output->set_env('pm_buttons_' . $plugin, $prop['buttons']);
+ $this->rcmail->output->set_env('pm_plugin_' . $plugin, $prop['active']);
+ }
+ $fconfig = 'fsavedialog';
+ if($prop['config']){
+ $fconfig = 'fconfig';
+ }
+ $funinstall = '';
+ if($prop['uninstall']){
+ $funinstall = 'funinstall';
+ }
+ $frequest = '';
+ if($prop['uninstall_request']){
+ if($prop['uninstall_force']){
+ $frequest = 'frequestforce';
+ }
+ else{
+ $frequest = 'frequest';
+ }
+ }
+
+ $input = new html_checkbox(array('style' => 'vertical-align: middle;', 'name' => '_plugin_manager_' . $plugin, 'class' => trim($fconfig . ' ' . $funinstall . ' ' . $frequest), 'value' => 1, 'id' => 'pm_chbox_' . $plugin));
+ if(substr($this->labels($prop['label_name']), 0, 1) == '[' && substr($this->labels($prop['label_name']), strlen($this->labels($prop['label_name'])) - 1) == ']'){
+ if(!is_dir('./plugins/' . $plugin)){
+ $li[$plugin].= html::tag('li', array('class' => '_plugin_manager_li', 'id' => 'pmid_' . html::tag('i', null, $plugin)), html::tag('input', array('style' => 'vertical-align: middle;', 'type' => 'checkbox', 'disabled' => 'true')) . html::tag('span', array('style' => 'vertical-align: middle;'), '&nbsp;' . html::tag('i', null, $plugin) . '&nbsp;' . html::tag('font', array('color' => 'red'), '(' . $this->gettext('notinstalled') . ')')));
+ }
+ }
+ else{
+ $li[$this->labels($prop['label_name'])].= html::tag('li', array('class' => 'plugin_manager_li', 'style' => 'white-space: nowrap', 'id' => 'pmid_' . $plugin), $input->show($prop['active']?1:0) . html::tag('span', array('style' => 'vertical-align: middle;'), '&nbsp;' . str_replace(' ', '&nbsp;', $this->labels($prop['label_name']))));
+ }
+ if($prop['label_name']){
+ $this->rcmail->output->add_script('rcmail.add_label({"' . $plugin . '.pluginname":"' . $this->labels($prop['label_name']) . '"});');
+ }
+ if($prop['label_description']){
+ $s = '';
+ if(is_array($prop['label_inject'])){
+ switch($prop['label_inject'][0]){
+ case 'string':
+ $s = $prop['label_inject'][1];
+ break;
+ case 'config':
+ $s = $this->rcmail->config->get($prop['label_inject'][1]);
+ break;
+ case 'session':
+ $s = $_SESSION($prop['label_inject'][1]);
+ break;
+ case 'eval':
+ eval($prop['label_inject'][1]);
+ break;
+ }
+ }
+ $this->rcmail->output->add_script('rcmail.add_label({"' . $prop['label_description'] . '":"' . $this->labels($prop['label_description'], $s) . '"});');
+ }
+ }
+ else{
+ $input = new html_hiddenfield(array('name' => '_plugin_manager_' . $plugin, 'id' => 'pm_chbox_' . $plugin, 'value' => $prop['active']?1:0));
+ $li[$this->labels($prop['label_name'])].= $input->show();
+ }
+ }
+ if($display_section[$section] && count($li) > 0 && $section != 'globalplugins' && $section != 'performance'){
+ ksort($li);
+ $li = implode('', $li);
+ $content .= html::tag('div', array('id' => 'pm_section_' . $section, 'class' => 'pm_section'), html::tag('fieldset', array('class' => 'pm_fieldset'), html::tag('legend', array('class' => 'title'), str_replace(' ', '&nbsp;', $this->labels($section))) . html::tag('ul', array('id' => 'pm_' . $section, 'class' => 'plugin_manager_ul'), $li)));
+ }
+ }
+ }
+ if($content != ''){
+ $args['blocks']['plugin_manager']['options'][0] = array(
+ 'title' => '',
+ 'content' => html::tag('div', array('id' => 'pm_div'), $content)
+ );
+ $input_restore = new html_checkbox(array('id' => 'pm_restore_defaults'));
+ $input_checkall = new html_checkbox(array('id' => 'pm_check_all'));
+ $input_uncheckall = new html_checkbox(array('id' => 'pm_uncheck_all'));
+ $input_config = new html_hiddenfield(array('name' => '_config_plugin', 'id' => 'plugin_manager_config_plugin'));
+ $update = '';
+ $admins = $this->admins;
+ $user = $_SESSION['username'];
+ if(isset($admins[strtolower($user)]) || strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $input_update = new html_checkbox(array('id' => 'pm_update_plugins'));
+ $update = '&nbsp;&nbsp;' . $this->gettext('update_plugins') . '&nbsp;' . html::tag('span', array('class' => 'pm_control'), $input_update->show(0));
+ }
+ $args['blocks']['plugin_manager']['options'][2] = array(
+ 'title' => '',
+ 'content' => $this->gettext('restoredefaults') . '&nbsp;' . html::tag('span', array('class' => 'pm_control'), $input_restore->show(0)) .
+ '&nbsp;&nbsp;' . $this->gettext('checkall') . '&nbsp;' . html::tag('span', array('class' => 'pm_control'), $input_checkall->show(0)) .
+ '&nbsp;&nbsp;' . $this->gettext('uncheckall') . '&nbsp;' . html::tag('span', array('class' => 'pm_control'), $input_uncheckall->show(0)) .
+ $input_config->show() .
+ $update .
+ html::tag('div', array('id' => 'jqdialog', 'style' => 'display: none;'))
+ );
+ $this->rcmail->output->set_env('pm_restore', $restore);
+ $this->rcmail->output->add_label(
+ 'plugin_manager.furtherconfig',
+ 'plugin_manager.successfullydeleted',
+ 'plugin_manager.successfullysaved',
+ 'plugin_manager.errorsaving',
+ 'plugin_manager.uninstall',
+ 'plugin_manager.uninstallconfirm',
+ 'plugin_manager.savewarning',
+ 'plugin_manager.areyousure',
+ 'plugin_manager.yes',
+ 'plugin_manager.no',
+ 'plugin_manager.disable',
+ 'plugin_manager.remove'
+ );
+ }
+ else{
+ $user = $_SESSION['username'];
+ $admins = $this->admins;
+ if(isset($admins[strtolower($user)])){
+ $input_update = new html_checkbox(array('id' => 'pm_update_plugins'));
+ $args['blocks']['plugin_manager']['options'][1] = array(
+ 'title' => '',
+ 'content' => $this->gettext('update_plugins') . '&nbsp;' . $input_update->show(0)
+ );
+ }
+ }
+ }
+ else if($args['section'] == 'plugin_manager_update'){
+ $warning = '&_warning=1';
+ if(strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $warning = '';
+ }
+ $args['blocks']['plugin_manager_update']['options'][0] = array(
+ 'title' => html::tag('script', array('type' => 'text/javascript'), '$("body").hide(); document.location.href="./?_task=settings&_framed=1&_action=plugin.plugin_manager_update' . $warning . '"'),
+ 'content' => ''
+ );
+ }
+ else if($args['section'] == 'plugin_manager_settings'){
+ if($label = get_input_value('_pmmsg', RCUBE_INPUT_GET)){
+ $this->rcmail->output->show_message($this->gettext($label), 'confirmation');
+ }
+ $args['blocks']['plugin_manager']['name'] = $this->gettext('settings');
+ $checked = false;
+ $readonly = true;
+ if($this->admins[$this->rcmail->user->data['username']] == 0){
+ $readonly = false;
+ }
+ if($this->file_based_config){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('file_based_config') . $append,
+ 'content' => ($readonly ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_file_based_config', 'name' => '_plugin_manager_file_based_config', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ($readonly ? '' : '&nbsp; - ' . html::tag('a', array('href' => 'http://myroundcube.com/myroundcube-plugins/plugin-manager/file-based-administration', 'target' => '_blank'), $this->gettext('advanced_admins'))) . '&nbsp;-&nbsp;' . html::tag('a', array('href' => './?_action=plugin.plugin_manager_show_config&_framed=1'), $this->gettext('show_config')) . ')')
+ );
+ $checked = false;
+ if($this->use_ssl){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('use_ssl'),
+ 'content' => ($readonly ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_use_ssl', 'name' => '_plugin_manager_use_ssl', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ $checked = false;
+ if($this->use_hmail){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('use_hmail'),
+ 'content' => ($readonly ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_use_hmail', 'name' => '_plugin_manager_hmail', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ $checked = false;
+ if($this->load_splitter){
+ $checked = true;
+ }
+ if(!file_exists(INSTALL_PATH . 'plugins/load_splitter/load_splitter.php')){
+ $append = '&nbsp;&minus;&nbsp;' . html::tag('font', array('color' => 'red'), html::tag('a', array('href' => '#', 'onclick' => 'document.location.href="./?_task=settings&_framed=1&_action=plugin.plugin_manager_update&_warning=1"'), 'load_splitter') . '&nbsp;' . $this->gettext('notinstalled'));
+ $disabled = true;
+ }
+ else{
+ $append = '';
+ $disabled = false;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('load_splitter') . '&nbsp;' . html::tag('small', null, html::tag('a', array('href' => '#', 'onclick' => '$("#pluginselector").val("performance").change();$("html, body").animate({ scrollTop: $("#row_load_splitter").offset().top - 40 }, 500)'), '[load_splitter]')) . '&nbsp;' . $append,
+ 'content' => (($readonly || $disabled) ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_load_splitter', 'name' => '_plugin_manager_load_splitter', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')') . '&nbsp;' . html::tag('a', array('href' => 'https://myroundcube.com/myroundcube-plugins/load_splitter-plugin/load-splitter-service', 'target' => '_blank'), html::tag('small', null, 'MyRoundcube Load Splitter Service'))
+ );
+
+ $checked = false;
+ if($this->compress_html){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('compress_html'),
+ 'content' => ($readonly ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_compress_html', 'name' => '_plugin_manager_compress_html', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ $checked = false;
+ if($this->rcmail->config->get('plugin_manager_about_link', true)){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('show_about_link'),
+ 'content' => ($readonly ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); if($(this).prop("checked")){parent.$(".about-link").show()}else{parent.$(".about-link").hide()}; document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_about_link', 'name' => '_plugin_manager_about_link', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ if($this->rcmail->config->get('support_url')){
+ $checked = false;
+ if($this->rcmail->config->get('plugin_manager_support_link', true)){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('show_support_link'),
+ 'content' => ($readonly ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); if($(this).prop("checked")){parent.$(".support-link").show()}else{parent.$(".support-link").hide()}; document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_support_link', 'name' => '_plugin_manager_support_link', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ }
+ $checked = false;
+ if($this->rcmail->config->get('plugin_manager_myroundcube_watermark', true)){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('use_myroundcube_watermark'),
+ 'content' => ($readonly ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_myroundcube_watermark', 'name' => '_plugin_manager_myroundcube_watermark', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ $checked = false;
+ if($this->rcmail->config->get('plugin_manager_remove_watermark', false)){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('remove_watermark'),
+ 'content' => ($readonly ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_remove_watermark', 'name' => '_plugin_manager_remove_watermark', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ $checked = false;
+ if($this->rcmail->config->get('plugin_manager_show_myrc_messages')){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('show_myrc_messages'),
+ 'content' => html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_show_myrc_messages', 'name' => '_plugin_manager_show_myrc_messages', 'value' => 1))
+ );
+ $checked = false;
+ if($this->rcmail->config->get('plugin_manager_maintenance_mode')){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('maintenance_mode') . ':' . html::tag('br') . html::tag('small', null, $this->gettext('maintenance_mode_hint')),
+ 'content' => html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_maintenanceMode', 'name' => '_plugin_manager_maintenance_mode', 'value' => 1)) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ $readonly = true;
+ if($this->admins[$this->rcmail->user->data['username']] == 0){
+ $readonly = false;
+ }
+ $checked = false;
+ if($this->rcmail->config->get('plugin_manager_update_notifications')){
+ $checked = true;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('enable_notifications') . ':' . html::tag('br') . html::tag('small', null, $this->gettext('enable_notifications_note')),
+ 'content' => ($readonly ? html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => $checked)) : html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()', 'type' => 'checkbox', 'checked' => $checked, 'id' => 'pm_update_notifications', 'name' => '_plugin_manager_update_notifications', 'value' => 1))) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ $readonly = true;
+ if($this->admins[$this->rcmail->user->data['username']] == 0){
+ $readonly = false;
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('notifications_cc') . ':' . html::tag('br') . html::tag('small', null, $this->gettext('notifications_cc_note')),
+ 'content' => ($readonly ? html::tag('input', array('type' => 'text', 'disabled' => true, 'value' => $this->rcmail->config->get('plugin_manager_update_notifications_cc'))) : html::tag('input', array('placeholder' => 'john.doh@gmail.com', 'size' => '30', 'type' => 'text', 'id' => 'pm_update_notifications_cc', 'name' => '_plugin_manager_update_notifications_cc', 'value' => $this->rcmail->config->get('plugin_manager_update_notifications_cc'))) .
+ '&nbsp;' . html::tag('small', null, '[' . html::tag('a', array('href' => '#', 'onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()'), $this->gettext('save')) . ']')) .
+ html::tag('small', null, '&nbsp;(' . $this->gettext('serverwide') . ')')
+ );
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('translationaccount'),
+ 'content' => html::tag('input', array('type' => 'text', 'size' => 30, 'placeholder' => 'john.doh@gmail.com', 'id' => 'pm_translation_account', 'name' => '_plugin_manager_translation_account', 'value' => $this->rcmail->config->get('plugin_manager_translation_account'))) .
+ '&nbsp;' . html::tag('small', null, '[' . html::tag('a', array('href' => '#', 'onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()'), $this->gettext('save')) . ']' . '&nbsp;' . html::tag('a', array('href' => 'http://myroundcube.com/myroundcube-plugins/real-time-translation', 'target' => '_blank'), $this->gettext('whatsthis'))
+ )
+ );
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('translationserver'),
+ 'content' => html::tag('input', array('type' => 'text', 'placeholder' => 'ssl://imap.gmail.com:993', 'size' => 30, 'id' => 'pm_translation_server', 'name' => '_plugin_manager_translation_server', 'value' => $this->rcmail->config->get('plugin_manager_translation_server'))) .
+ '&nbsp;' . html::tag('small', null, '[' . html::tag('a', array('href' => '#', 'onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.submit()'), $this->gettext('save')) . ']')
+ );
+ if(!$this->file_based_config){
+ $options = html::tag('option', null, '--');
+ $plugins_sorted = array();
+ foreach($this->defaults as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ $plugins_sorted[$plugin] = $section;
+ }
+ }
+ ksort($plugins_sorted);
+ foreach($plugins_sorted as $plugin => $section){
+ if(!in_array($plugin, $this->noselect)){
+ $options .= html::tag('option', array('value' => $section, 'id' => 'option_' . $plugin), $plugin);
+ }
+ }
+ $selector = html::tag('select', array('id' => 'pluginselector', 'onchange' => '$(".row").attr("style", ""); if(!$("#" + $(this).val()).is(":visible")){ $("#tab" + $(this).val()).trigger("click") }; $("#row_" + ($(this).find(":selected").text())).attr("style", "border-left: 7px solid #000000;"); $("html, body").animate({ scrollTop: $("#row_" + $(this).find(":selected").text()).offset().top - 40 }, 500);'), $options);
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $this->gettext('select_plugin'),
+ 'content' => $selector
+ );
+ $tabs = '';
+ $divs = '';
+ include INSTALL_PATH . 'plugins/plugin_manager/defaults.inc.php';
+ $defaults = $config['plugin_manager_defaults'];
+ $release_defaults = $defaults;
+ $conf = array();
+ foreach($defaults as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ $conf[$plugin] = 1;
+ }
+ }
+ $options = array();
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'defaults');
+ $overwrite = $this->rcmail->db->fetch_assoc($res);
+ if($overwrite['value']){
+ $overwrite = unserialize($overwrite['value']);
+ if(is_array($overwrite)){
+ $defaults = array_merge($defaults, $overwrite);
+ }
+ }
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'defaults_overwrite');
+ $overwrite = $this->rcmail->db->fetch_assoc($res);
+ if($overwrite['value']){
+ $overwrite = unserialize($overwrite['value']);
+ if(is_array($overwrite)){
+ foreach($overwrite as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ foreach($props as $key => $val){
+ $defaults[$section][$plugin][$key] = $val;
+ }
+ }
+ }
+ }
+ }
+ foreach($defaults as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ $options[$plugin] = 1;
+ }
+ }
+ foreach($this->rcmail->config->get('plugins', array()) as $plugin){
+ $options[$plugin] = 1;
+ }
+ $scope = scandir(INSTALL_PATH . 'plugins');
+ $select = array();
+ foreach($scope as $dir){
+ if(file_exists(INSTALL_PATH . 'plugins/' . $dir . '/' . $dir . '.php')){
+ if(!isset($options[$dir])){
+ if(!in_array($dir, $this->skip)){
+ $select[$dir] = 1;
+ }
+ }
+ else if(!isset($conf[$dir])){
+ if(!in_array($dir, $this->skip)){
+ $select[$dir] = -1;
+ }
+ }
+ }
+ }
+ $sel_add = html::tag('option', null, '--');
+ ksort($options);
+ foreach($select as $plugin => $available){
+ if($available == 1){
+ $sel_add .= html::tag('option', array('value' => $plugin), $plugin);
+ }
+ }
+ foreach($this->defaults as $section => $plugins){
+ foreach($select as $plugin => $available){
+ if($available == -1 && isset($plugins[$plugin])){
+ $sel_remove[$section] .= html::tag('option', array('value' => $plugin), $plugin);
+ }
+ }
+ if(function_exists('mb_substr')){
+ $truncate = mb_substr($this->gettext($section), 0, 9);
+ }
+ else{
+ $truncate = substr($this->gettext($section), 0, 9);
+ }
+ $tabs .= html::tag('li', array('onclick' => 'window.location.href="#pm_translation_server"'),
+ html::tag('a', array('href' => '#' . $section, 'onclick' => 'parent.rcmail.env.section="' . $section . '"', 'id' => 'tab' . $section, 'title' => $this->gettext($section)), strlen($this->gettext($section)) > 12 ? $truncate . '...' : $this->gettext($section))
+ );
+ $legend = html::tag('div', array('style' => 'float: left; width: 300px;'), html::tag('span', array('style' => 'font-size: 11px; font-weight: normal;'), '&nbsp;' . $this->gettext('legend') . ':') .
+ html::tag('table', null,
+ html::tag('tr', null,
+ html::tag('td', array('nowrap' => true, 'class' => 'pm_legend'), html::tag('input', array('type' => 'checkbox', 'disabled' => true)) . html::tag('input', array('type' => 'checkbox', 'disabled' => true))) .
+ html::tag('td', array('nowrap' => true, 'class' => 'pm_legend', 'style' => 'font-size: 9px; font-weight: normal; color: #188c18;'), $this->gettext('plugindisabledbydefault'))
+ ) .
+ html::tag('tr', null,
+ html::tag('td', array('class' => 'pm_legend'), html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => true)) . html::tag('input', array('type' => 'checkbox', 'disabled' => true))) .
+ html::tag('td', array('class' => 'pm_legend', 'nowrap' => true, 'style' => 'font-size: 9px; font-weight: normal; color: #188c18;'), $this->gettext('pluginenabledbydefault'))
+ ) .
+ html::tag('tr', null,
+ html::tag('td', array('class' => 'pm_legend'), html::tag('input', array('type' => 'checkbox', 'disabled' => true)) . html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => true))) .
+ html::tag('td', array('nowrap' => true, 'class' => 'pm_legend', 'style' => 'font-size: 9px; font-weight: normal; color: #8a8a8a;'), $this->gettext('loads_never'))
+ ) .
+ html::tag('tr', null,
+ html::tag('td', array('class' => 'pm_legend'), html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => true)) . html::tag('input', array('type' => 'checkbox', 'disabled' => true, 'checked' => true))) .
+ html::tag('td', array('nowrap' => true, 'class' => 'pm_legend', 'style' => 'font-size: 9px; font-weight: normal; color: #ff1b1b;'), $this->gettext('pluginmandatory'))
+ )
+ )
+ );
+ $rows = array();
+ $skins = array();
+ $files = scandir(INSTALL_PATH . 'skins');
+ foreach($files as $file){
+ if(is_dir(INSTALL_PATH . 'skins/' . $file) && $file != '.' && $file != '..'){
+ $skins[] = $file;
+ }
+ }
+ $skinoptions = html::tag('option', array('value' => 'all'), $this->gettext('all'));
+ $combinations = '';
+ foreach($skins as $skin){
+ if($combinations){
+ $combinations .= '|';
+ }
+ $combinations .= $skin;
+ if($combinations != implode('|', $skins)){
+ $skinoptions .= html::tag('option', array('value' => $combinations), $combinations);
+ }
+ }
+ foreach($plugins as $plugin => $props){
+ if($props['autoload']){
+ continue;
+ }
+ $labels = array();
+ $name = $this->gettext($plugin . '.pluginname');
+ $title = $this->gettext($plugin . '.plugindescription');
+ if(substr($name, 0, 1) == '['){
+ $name = $this->gettext($plugin . '_pluginname');
+ $title = $this->gettext($plugin . '_plugindescription');
+ }
+ if(substr($name, 0, 1) == '['){
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/localization/en_US.inc')){
+ include INSTALL_PATH . 'plugins/' . $plugin . '/localization/en_US.inc';
+ $en_us_labels = $labels;
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/localization/' . $_SESSION['language'] . '.inc')){
+ include INSTALL_PATH . 'plugins/' . $plugin . '/localization/' . $_SESSION['language'] . '.inc';
+ $labels = array_merge($en_us_labels, $labels);
+ }
+ if(isset($labels['pluginname'])){
+ $name = $labels['pluginname'];
+ }
+ if(isset($labels['plugindescription'])){
+ $title = $labels['plugindescription'];
+ }
+ else{
+ $title = '';
+ }
+ }
+ else{
+ $title = '';
+ }
+ }
+ $docs = false;
+ if(substr($name, 0, 1) == '['){
+ $name = $plugin . '&nbsp;' . html::tag('small', null, html::tag('span', null, '[') . html::tag('a', array('href' =>
+ "mailto:dev-team@myroundcube.com?subject=Third party plugin localization (" . $plugin . ")&body=Please add localization labels to the next Plugin Manager localization update.%0D%0A%0D%0APlugin: " . $plugin . "%0D%0A%0D%0ALanguage: en_US (English please)%0D%0APlugin name:%0D%0APlugin description:"
+ ),
+ html::tag('span', array('style' => 'color: #ff1b1b;'), $this->gettext('localizationmissing'))) . html::tag('span', null, ']')
+ );
+ }
+ if(is_array($release_defaults[$section][$plugin])){
+ $docs = true;
+ }
+ $isactive = $props['active'] ? true : false;
+ $isprotected = $props['protected'] ? true : false;
+ if(is_string($props['protected'])){
+ $isprotected = $props['protected'];
+ }
+ if($disable = get_input_value('_plugin', RCUBE_INPUT_GET)){
+ if($disable == $plugin){
+ $isactive = false;
+ $isprotected = true;
+ if(is_array($props['protected'])){
+ $isprotected = $props['protected'];
+ }
+ }
+ }
+ $status = false;
+ $bind = '';
+ $unbind = '';
+ $linked = '';
+ $error = '';
+ if(class_exists('db_config') && $this->defaults['globalplugins']['db_config']['active'] && RCMAIL_VERSION > '0.8.6'){
+ $isconfigured = true;
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php.dist')){
+ $sql = 'SELECT * FROM ' . get_table_name('db_config') . ' WHERE ' . $this->q('env') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, $plugin);
+ if(!is_array($this->rcmail->db->fetch_assoc($res))){
+ if($plugin != 'global_config' && file_exists(INSTALL_PATH . 'plugins/global_config/config.inc.php')){
+ if(!file_exists(INSTALL_PATH . 'plugins/' . $plugin . 'config.inc.php')){
+ $config = array();
+ $rcmail_config = array();
+ include INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php.dist';
+ if(is_array($rcmail_config)){
+ $config = $rcmail_config;
+ $rcmail_config = array();
+ }
+ $defconf = $config;
+ $config = array();
+ include INSTALL_PATH . 'plugins/global_config/config.inc.php';
+ if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php')){
+ include INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php';
+ if(is_array($rcmail_config)){
+ $config = $rcmail_config;
+ }
+ }
+ foreach($defconf as $key => $value){
+ if(isset($config[$key])){
+ $isconfigured = true;
+ break;
+ }
+ else{
+ $isconfigured = false;
+ }
+ }
+ }
+ }
+ }
+ $democlick = '';
+ if(strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $democlick = 'rcmail.display_message("' . $this->gettext('demoaccount') . '", "error"); return false';
+ }
+ if(!$isconfigured){
+ $error .= '&nbsp;' . html::tag('small', array('style' => 'color: #ff1b1b;'), '[' . html::tag('a', array('style' => 'color: #ff1b1b;', 'onclick' => $democlick, 'href' => './?_action=plugin.plugin_manager_show_config&_framed=1&_plugin=' . $plugin), $this->gettext('notconfigured')) . ']');
+ }
+ else if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/config.inc.php.dist')){
+ $error .= '&nbsp;' . html::tag('small', array('style' => 'color: #188c18;'), '[' . html::tag('a', array('style' => 'color: #188c18;', 'onclick' => $democlick, 'href' => './?_action=plugin.plugin_manager_edit_config&_framed=1&_plugin=' . $plugin), $this->gettext('editconfig')) . ']');
+ }
+ }
+ }
+ if($this->defaults['globalplugins']['mysqladmin']['active'] && class_exists('mysqladmin') && class_exists($plugin) && method_exists($plugin, 'about') && strtolower($this->rcmail->config->get('mysql_admin')) == strtolower($this->rcmail->user->data['username'])){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $sqladmin = $class->about(array('sqladmin'));
+ if($sqladmin['sqladmin']){
+ $sqladmin = $sqladmin['sqladmin'];
+ $error .= '&nbsp;' . html::tag('small', array('style' => 'color: #188c18;'), '[' . html::tag('a', array('style' => 'color: #188c18;', 'onclick' => 'var temp = document.location.href.split(\'&_expand\'); rcmail.set_cookie(\'PMA_referrer\', temp[0] + \'&_expand=' . $plugin . '\');', 'href' => './?_action=plugin.mysqladmin&pma_login=1&db=' . $sqladmin[0] . '&dbt=' . $sqladmin[1]), $this->gettext('PHPMyAdmin')) . ']');
+ }
+ }
+ if(class_exists($plugin) && !method_exists($plugin, 'about')){
+ $error .= '&nbsp;' . html::tag('small', array('style' => 'color: #8a8a8a;'), '[' . html::tag('i', null, str_replace('.', '', $this->gettext('thirdparty'))) . ']');
+ }
+ if($plugin == 'load_splitter'){
+ $isactive = $this->load_splitter;
+ $disabled = true;
+ }
+ else{
+ $disabled = false;
+ }
+ $active = html::tag('td', array('align' => 'center'), html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.action = document.forms.form.action + "?_plugin=' . $plugin . '"; document.forms.form.submit()', 'name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][active]', 'value' => 1, 'checked' => $isactive ? true : false, 'style' => 'display:' . ($disabled ? 'none' : 'block'), 'type' => 'checkbox')));
+ if(is_string($release_defaults[$section][$plugin]['protected']) && !is_string($props['protected'])){
+ if(substr($this->gettext($release_defaults[$section][$plugin]['config_label']), 0, 1) != '['){
+ $bind = '&nbsp;' . html::tag('small', null, '[' . html::tag('a', array('title' => $this->gettext('loads_linked') . ': ' . $this->gettext($release_defaults[$section][$plugin]['config_label']), 'href' => './?_task=settings&_action=plugin.plugin_manager_bind&_section=' . $section . '&_target=' . $plugin), $this->gettext('bind')) . ']');
+ $active = html::tag('td');
+ }
+ }
+ if(is_string($props['protected'])){
+ $linked = $this->gettext('loads_linked') . ':' . html::tag('br') . $this->gettext($section) . html::tag('br') . '-&nbsp';
+ $status = $props['config_label'] ? $props['config_label'] : $props['protected'];
+ if(substr($this->gettext($status), 0, 1) == '['){
+ $this->rcmail->output->add_script('document.location.href="./?_task=settings&_action=plugin.plugin_manager_unbind&_section=' . $section . '&_target=' . $plugin . '";', 'docready');
+ }
+ $unbind = '&nbsp;' . html::tag('small', null, '[' . html::tag('a', array('href' => './?_task=settings&_action=plugin.plugin_manager_unbind&_section=' . $section . '&_target=' . $plugin), $this->gettext('unbind')) . ']');
+ $color = '#188c18';
+ $active = html::tag('td', array('align' => 'center'), html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][active]', 'value' => 0, 'type' => 'hidden')));
+ }
+ else if($isactive && $isprotected){
+ $status = 'loads_always';
+ $color = '#ff1b1b';
+ }
+ else if((!$isactive && $isprotected) || (($section == 'globalplugins' || $section == 'performance') && !$isactiv && !$isprotected)){
+ $status = 'loads_never';
+ $color = '#8a8a8a';
+ }
+ else{
+ $status = 'loads_by_user';
+ $color = '#188c18';
+ }
+ if($section == 'globalplugins' || $section == 'performance' || $bind){
+ if($bind){
+ $protected = html::tag('td');
+ }
+ else{
+ $protected = html::tag('td', array('align' => 'center'), html::tag('input', array('disabled' => true, 'checked' => true, 'type' => 'checkbox')));
+ }
+ $protected .= html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => 1, 'type' => 'hidden'));
+ }
+ else{
+ if(is_string($isprotected)){
+ $protected = html::tag('td', array('align' => 'center'), html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => $isprotected, 'type' => 'hidden')));
+ }
+ else{
+ $protected = html::tag('td', array('align' => 'center'), html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.action = document.forms.form.action + "?_plugin=' . $plugin . '"; document.forms.form.submit()', 'name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => 1, 'checked' => $isprotected ? true : false, 'type' => 'checkbox')));
+ }
+ }
+ if(!class_exists($plugin)){
+ $this->require_plugin($plugin);
+ }
+ if(method_exists($plugin, 'about')){
+ $class = new $plugin(false);
+ $requirements = $class->about();
+ $required = $requirements['db_version'];
+ if(is_array($required)){
+ $required = implode('|', $required);
+ $sql = 'SELECT * FROM ' . get_table_name('system') . ' WHERE ' . $this->q('name') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'myrc_' . $plugin);
+ $db = $this->rcmail->db->fetch_assoc($res);
+ $db = $db['value'];
+ if($db != $required && strtolower($this->get_demo($_SESSION['username'])) != strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ if(!$isactive && !$isprotected){
+ $isprotected = true;
+ if(is_string($isprotected)){
+ $protected = html::tag('td', array('align' => 'center'), html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => 1, 'type' => 'hidden')));
+ }
+ else{
+ $protected = html::tag('td', array('align' => 'center'), html::tag('input', array('onclick' => '$("#plugin_manager_overlay").show(); document.forms.form.action = document.forms.form.action + "?_plugin=' . $plugin . '"; document.forms.form.submit()', 'name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => 1, 'checked' => true, 'type' => 'checkbox')));
+ }
+ $this->rcmail->output->add_script('$("#plugin_manager_overlay").show(); document.forms.form.submit();', 'docready');
+ }
+ $status = 'errordb';
+ $color = '#ff1b1b';
+ $temp = explode('.', RCMAIL_VERSION);
+ if(($temp[0] == 0 && $temp[1] > 8) || $temp[0] > 0){
+ if($isactive && $isprotected){
+ if($class->task){
+ foreach($this->rctasks as $task){
+ if(preg_match('/^('.$class->task.')$/i', $task)){
+ $link = './?_task=' . $task . '&_plugin_manager_settings_section=' . $section;
+ break;
+ }
+ }
+ }
+ else{
+ $link = './?_task=settings&_plugin_manager_settings_section=' . $section;
+ }
+ $_SESSION['db_version_lock'] = true;
+ $status = 'errordb8';
+ $error = html::tag('br') . html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => 'window.setTimeout(\'parent.location.href="' . $link . '"\', 500);'), $this->gettext('dbautomatically'));
+ $this->rcmail->output->show_message('plugin_manager.dbautomatically', 'notice');
+ }
+ }
+ else{
+ $status = 'errordb8';
+ $error = html::tag('br') . html::tag('a', array('href' => 'http://myroundcube.com/myroundcube-plugins/faqs/myroundcube-plugins-database-versioning-support', 'target' => '_blank'), $this->gettext('dbmanually'));
+ }
+ }
+ }
+ $required = $requirements['requirements']['required_plugins'];
+ if(is_array($required)){
+ $missing = array();
+ foreach($required as $key => $val){
+ if(!file_exists(INSTALL_PATH . 'plugins/' . $key . '/' . $key . '.php')){
+ $missing[] = $key;
+ }
+ }
+ if(count($missing) > 0){
+ $active = html::tag('td', null, '&nbsp;');
+ $protected = html::tag('td', null, '&nbsp;');
+ $status = 'errorplugin';
+ $color = '#ff1b1b';
+ if(RCMAIL_VERSION > $this->stable){
+ $branch = 'dev';
+ }
+ else{
+ $branch = 'stable';
+ }
+ $error = '&nbsp;(' . html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => 'document.location.href="./?_task=settings&_action=plugin.plugin_manager_update&_framed=1&_branch=' . $branch . '"'), implode(', ', $missing)) . ')';
+ }
+ }
+ $required = $requirements['requirements']['Roundcube'];
+ if(isset($required)){
+ if(RCMAIL_VERSION < $required){
+ $active = html::tag('td', null, html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][active]', 'value' => 0, 'type' => 'hidden')));
+ $protected = html::tag('td', null, html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => 1, 'type' => 'hidden')));
+ $status = 'errorrcversion';
+ $color = '#ff1b1b';
+ $error = '&nbsp;v' . $required . '&nbsp;' . $this->gettext('ornewer') . html::tag('br') . html::tag('small', array('style' => 'color: #000000;'), '[' . html::tag('a', array('href' => 'http://roundcube.net/download', 'target' => '_blank'), $this->gettext('official_releases')) . ']');
+ if($isactive || !$isprotected){
+ $this->rcmail->output->add_script('$("#plugin_manager_overlay").show(); document.forms.form.submit();', 'docready');
+ }
+ }
+ }
+ $required = $requirements['requirements']['PHP'];
+ if(isset($required)){
+ $temp = explode('+', $required);
+ $module = trim($temp[1]);
+ if(strtolower($module) == 'curl'){
+ if(!function_exists('curl_init')){
+ $active = html::tag('td', null, html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][active]', 'value' => 0, 'type' => 'hidden')));
+ $protected = html::tag('td', null, html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => 1, 'type' => 'hidden')));
+ $status = 'errorphpcurl';
+ $color = '#ff1b1b';
+ $error = '&nbsp;' . html::tag('small', array('style' => 'color: #000000;'), '[' . html::tag('a', array('href' => 'http://php.net/manual/en/book.curl.php', 'target' => '_blank'), 'PHP cURL') . ']');
+ if($isactive || !$isprotected){
+ $this->rcmail->output->add_script('$("#plugin_manager_overlay").show(); document.forms.form.submit();', 'docready');
+ }
+ }
+ }
+ if(strtolower($module) == 'finfo'){
+ if(!function_exists('finfo_open')){
+ $active = html::tag('td', null, html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][active]', 'value' => 0, 'type' => 'hidden')));
+ $protected = html::tag('td', null, html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => 1, 'type' => 'hidden')));
+ $status = 'errorphpcurl';
+ $status = 'errorphpfinfo';
+ $color = '#ff1b1b';
+ $error = '&nbsp;' . html::tag('small', array('style' => 'color: #000000;'), '[' . html::tag('a', array('href' => 'http://php.net/manual/en/book.fileinfo.php', 'target' => '_blank'), 'PHP finfo') . ']');
+ if($isactive || !$isprotected){
+ $this->rcmail->output->add_script('$("#plugin_manager_overlay").show(); document.forms.form.submit();', 'docready');
+ }
+ }
+ }
+ $php = trim($temp[0]);
+ if(PHP_VERSION < $php){
+ $active = html::tag('td', null, html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][active]', 'value' => 0, 'type' => 'hidden')));
+ $protected = html::tag('td', null, html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => 1, 'type' => 'hidden')));
+ $status = 'errorphpversion';
+ $color = '#ff1b1b';
+ $error = '&nbsp;v' . $required;
+ if($isactive || !$isprotected){
+ $this->rcmail->output->add_script('$("#plugin_manager_overlay").show(); document.forms.form.submit();', 'docready');
+ }
+ }
+ }
+ }
+ $skins = html::tag('td', null, html::tag('select', array('id' => 'skin_sel_' . $plugin , 'name' => '_skins[' . $section . '][' . $plugin . ']', 'onchange' => 'document.forms.form.submit()'), $skinoptions));
+ if(is_array($props['skins'])){
+ $skins .= html::tag('script', array('type' => 'text/javascript'), '$("#skin_sel_' . $plugin . '").val("' . implode('|', $props['skins']) . '");');
+ }
+ if($plugin == 'db_config'){
+ $skey = '_03';
+ if($this->admins[$this->rcmail->user->data['username']] != 0){
+ $active = html::tag('td', array('align' => 'center', 'colspan' => 3),
+ html::tag('span', array('style' => 'font-weight: normal; color: #8a8a8a;'), $this->gettext('systemadmin') . '&nbsp;(' . $this->gettext('serverwide') . ')') .
+ html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][active]', 'value' => $this->defaults['globalplugins']['db_config']['active'], 'type' => 'hidden')) .
+ html::tag('input', array('name' => '_plugin_manager_defaults[' . $section . '][' . $plugin . '][protected]', 'value' => 1, 'type' => 'hidden'))
+ );
+ $protected = '';
+ $skins = '';
+ if($isactive && $isprotected){
+ $status = 'loads_always';
+ $color = '#ff1b1b';
+ }
+ else if((!$isactive && $isprotected)){
+ $status = 'loads_never';
+ $color = '#8a8a8a';
+ }
+ }
+ }
+ else if(substr($this->gettext($plugin . '.pluginname'), 0, 1) != '['){
+ $skey = $this->gettext($plugin . '.pluginname');
+ }
+ else if(substr($this->gettext('plugin_manager.' . $plugin . '_pluginname'), 0, 1) != '['){
+ $skey = $this->gettext('plugin_manager.' . $plugin . '_pluginname');
+ }
+ else{
+ $skey = $plugin;
+ }
+ $rows[strtolower($skey)] = html::tag('a', array('name' => $plugin), '') . html::tag('tr', array('id' => 'row_' . $plugin, 'class' => 'row'),
+ html::tag('td', array('style' => 'font-weight: normal;', 'class' => 'pm_config'), html::tag('span', array('title' => $title), $name) . ' ' . ($docs ? html::tag('small', null, '[' . html::tag('a', array('href' => 'http://myroundcube.com/myroundcube-plugins#'. $plugin, 'target' => '_blank', 'title' => $this->gettext('documentation')), $plugin) . ']') : '')) .
+ $active .
+ $protected .
+ $skins .
+ html::tag('td', array('style' => 'font-weight: normal; color: ' . $color), ($status ? ($linked . $this->gettext($status) . $unbind . $bind . $error) : '&nbsp;'))
+ );
+ }
+ $rows['_0'] = html::tag('tr', array('id' => 'row_new_plugin_' . $section, 'class' => 'row'),
+ html::tag('td', array('width' => '20%'), html::tag('select', array('onchange' => 'document.forms.form.submit()', 'name' => '_new_plugin_name[' . $section . ']'), $sel_add)) .
+ html::tag('td', array('width' => '30%', 'colspan' => 3, 'align' => 'center', 'style' => 'font-weight: normal; color: #8a8a8a;'), $this->gettext('addplugin')) .
+ html::tag('td', array('width' => '50%'), '&nbsp;')
+ );
+ if($sel_remove[$section]){
+ $sel_remove[$section] = html::tag('option', null, '--') . $sel_remove[$section];
+ $rows['_1'] = html::tag('tr', array('id' => 'row_remove_plugin_' . $section, 'class' => 'row'),
+ html::tag('td', array('width' => '20%'), html::tag('select', array('onchange' => 'document.forms.form.submit()', 'name' => '_remove_plugin_name[' . $section . ']'), $sel_remove[$section])) .
+ html::tag('td', array('width' => '30%', 'colspan' => 3, 'align' => 'center', 'style' => 'font-weight: normal; color: #8a8a8a;'), $this->gettext('removeplugin')) .
+ html::tag('td', array('width' => '50%'), '&nbsp;')
+ );
+ }
+ ksort($rows);
+ $divs .= html::tag('div', array('id' => $section),
+ html::tag('table', array('class' => 'propform', 'width' => '100%'),
+ html::tag('tr', null,
+ html::tag('th', array('width' => '20%', 'style' =>'font-weight: normal;'), $this->gettext('plugin')) .
+ html::tag('th', array('width' => '10%', 'style' =>'font-weight: normal;'), $this->gettext('enabled')) .
+ html::tag('th', array('width' => '10%', 'style' =>'font-weight: normal;'), $this->gettext('protected')) .
+ html::tag('th', array('width' => '10%', 'align' => 'left', 'style' => 'font-weight: normal;'), '&nbsp;&nbsp;' . $this->gettext('skins')) .
+ html::tag('th', array('width' => '50%', 'align' => 'left', 'style' => 'font-weight: normal;'), '&nbsp;&nbsp;' . $this->gettext('status'))
+ ) . implode('', $rows)
+ ) . $legend
+ );
+ }
+ $html = html::tag('div', array('id' => 'plugin_manager_defaults', 'style' => 'display: none;'),
+ html::tag('ul', null,
+ html::tag('style', array('type' => 'text/css'), '.ui-tabs .ui-tabs-nav li a { font-size: 11px; } table.propform td.title { white-space: normal; }') . $tabs . $divs
+ )
+ );
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => $html,
+ 'content' => html::tag('span', array('id' => 'remove'))
+ );
+ $skin = $this->rcmail->config->get('skin');
+ if(!file_exists($this->home . '/skins/' . $skin . '/plugin_manager.css')) {
+ $skin = "classic";
+ }
+ $this->include_stylesheet('skins/' . $skin . '/plugin_manager.css');
+ $this->api->output->add_footer(html::tag('div', array('id' => 'plugin_manager_overlay')));
+ }
+ $admins = array_flip($this->admins);
+ $systemadmin = '$(".boxtitle").html($(".boxtitle").html() + "&nbsp;&raquo;&nbsp;' . $this->gettext('systemadmin') . ':&nbsp;' . $admins[0];
+ if($admins[0] != $this->rcmail->user->data['username']){
+ $systemadmin .= '&nbsp;&raquo;&nbsp;' . $this->gettext('admin') . ':&nbsp;' . $admins[0];
+ }
+ $systemadmin .= '&nbsp;&raquo;&nbsp;<a href=\'javascript:window.scrollTo(0, 0)\'>' . $this->gettext('serverconfiguration') . '</a>&nbsp;|&nbsp;<a onclick=\'return pluginsconfiguration()\' href=\'#pm_translation_server\'>' . $this->gettext('pluginsconfiguration') . '</a>';
+ $systemadmin .= '")';
+ $this->rcmail->output->add_script(
+ 'function pluginsconfiguration(){
+ if($("#plugin_manager_defaults").tabs("option", "selected") == -1){
+ $("#tabglobalplugins").trigger("click");
+ return true;
+ }
+ }
+ $(".mainaction").hide();
+ $("#remove").parent().remove();
+ $("#plugin_manager_defaults").parent().attr("colspan", 2);
+ $("#plugin_manager_defaults").tabs({ collapsible: true, active: false });
+ if(parent.rcmail.env.section){
+ $("#tab" + parent.rcmail.env.section).trigger("click");
+ }
+ $("#plugin_manager_defaults").show();
+ $("td.title").css("width", "300px");
+ ' . $systemadmin,
+ 'foot'
+ );
+ if($plugin = get_input_value('_plugin', RCUBE_INPUT_GET)){
+ if(strtolower($this->get_demo($_SESSION['username'])) != strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $this->rcmail->output->add_script('document.forms.form.action = document.forms.form.action + "?_plugin=' . $plugin . '"; document.forms.form.submit();', 'docready');
+ }
+ }
+ if($plugin = get_input_value('_expand', RCUBE_INPUT_GET)){
+ $this->rcmail->output->add_script('$("#option_' . $plugin . '").prop("selected", true); $("#pluginselector").change();', 'docready');
+ }
+ }
+ else if($args['section'] == 'plugin_manager_admins'){
+ $this->admins = array();
+ $args['blocks']['plugin_manager']['name'] = $this->gettext('plugin_manager_admins');
+ $content = '';
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => '',
+ 'content' => html::tag('div', array('id' => 'pm_div_0'), html::tag('input', array('type' => 'hidden', 'size' => 35, 'id' => 'pma_label_0', 'name' => '_plugin_manager_admins[]', 'value' => ''))) .
+ '&nbsp;' . html::tag('small', null, html::tag('a', array('href' => 'javascript:var user = prompt("' . $this->gettext('username') . '", $("#pma_label_0").val()); if(user) {$("#pma_label_0").val(user); document.forms.form.submit()}'), $this->gettext('add')))
+ );
+ $sql = 'SELECT ' . $this->q('value') . ' FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'admins');
+ if($res){
+ $admins = $this->rcmail->db->fetch_assoc($res);
+ if($admins = unserialize($admins['value'])){
+ $this->admins = array_flip($admins);
+ }
+ }
+ foreach($this->admins as $admin => $val){
+ if($val == 0) continue;
+ $isadmin = false;
+ $isshared = false;
+ $sql = 'SELECT ' . $this->q('preferences') . ' FROM ' . get_table_name('users') . ' WHERE ' . $this->q('username') . '=? AND ' . $this->q('mail_host') . '=?';
+ if($res = $this->rcmail->db->limitquery($sql, 0, 1, $admin, $_SESSION['storage_host'])){
+ $prefs = $this->rcmail->db->fetch_assoc($res);
+ if($prefs = unserialize($prefs['preferences'])){
+ if($prefs['plugin_manager_hash'] && $prefs['plugin_manager_hash'] == $this->rcmail->config->get('plugin_manager_hash')){
+ $isadmin = true;
+ }
+ if($prefs['customer_id'] && $prefs['customer_id'] == $this->rcmail->config->get('customer_id')){
+ $isshared = true;
+ }
+ else if($prefs['shared_customer_id'] && ($prefs['customer_id'] != $prefs['shared_customer_id']) && ($prefs['shared_customer_id'] == $this->rcmail->config->get('customer_id'))){
+ $isshared = true;
+ }
+ }
+ }
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => html::tag('label', array('for' => 'pma_label_' . $val), html::tag('b', null, html::tag('i', null, $admin))),
+ 'content' => html::tag('div', array('id' => 'pm_div_' . $val), html::tag('input', array('type' => 'hidden', 'size' => 35, 'id' => 'pma_label_' . $val, 'name' => '_plugin_manager_admins[]', 'value' => $admin))) .
+ '&nbsp;' . html::tag('small', null, html::tag('a', array('href' => 'javascript:$("#pma_label_' . $val . '").val("");document.forms.form.submit()'), $this->gettext('delete')) . '&nbsp;|&nbsp;' .
+ html::tag('a', array('href' => 'javascript:var user = prompt("' . $this->gettext('username') . '", $("#pma_label_' . $val . '").val()); if(user) {$("#pma_label_' . $val . '").val(user); document.forms.form.submit()}'), $this->gettext('edit')))
+ );
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => html::tag('label', array('for' => 'pmc_label_' . $val), $this->gettext('submenuprefix') . '&nbsp;' . $this->gettext('allow_plugins_configuration')),
+ 'content' => html::tag('div', array('id' => 'pm_div_config_' . $val), html::tag('input', array('checked' => $isadmin, 'onclick' => 'document.forms.form.submit()', 'id' => 'pmc_label_' . $val, 'type' => 'checkbox', 'name' => '_plugin_manager_config[' . $admin . ']', 'value' => 1)))
+ );
+ $args['blocks']['plugin_manager']['options'][] = array(
+ 'title' => html::tag('label', array('for' => 'pmi_label_' . $val), $this->gettext('submenuprefix') . '&nbsp;' . $this->gettext('share_credits')),
+ 'content' => html::tag('div', array('id' => 'pm_div_customer_' . $val), html::tag('input', array('checked' => $isshared, 'onclick' => 'document.forms.form.submit()', 'id' => 'pmi_label_' . $val, 'type' => 'checkbox', 'name' => '_plugin_manager_customer[' . $admin . ']', 'value' => 1)))
+ );
+ }
+ $this->rcmail->output->add_script('$(".mainaction").hide(); $(".boxtitle").html($(".boxtitle").html() + "&nbsp;&raquo;&nbsp;' . $this->gettext('systemadmin') . ':&nbsp;' . $this->rcmail->user->data['username'] . '")', 'docready');
+ }
+ else if($args['section'] == 'plugin_manager_customer'){
+ $this->include_script('plugin_manager.js');
+ $this->rcmail->output->add_label(
+ 'plugin_manager.creditsupdated'
+ );
+ $customer_id = $this->rcmail->config->get('customer_id');
+ if(!$customer_id){
+ $customer_id = $this->getCustomerID();
+ if(is_string($customer_id) && strlen($customer_id) == 32){
+ $a_prefs['customer_id'] = $customer_id;
+ $this->rcmail->user->save_prefs($a_prefs);
+ }
+ else{
+ $args['blocks']['plugin_manager_customer']['options'][0] = array(
+ 'title' => $this->gettext('servicenotavailable'),
+ 'content' => ''
+ );
+ $this->rcmail->output->add_script('if(self.location.href != parent.location.href){$(".mainaction").remove()}', 'docready');
+ }
+ }
+ if($_GET['_framed']){
+ $params = array('_customer_id' => $this->rcmail->config->get('customer_id'));
+ $httpConfig['method'] = 'POST';
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_account';
+ $httpConfig['timeout'] = '30';
+ $httpConfig['params'] = $params;
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ if(($shared = $this->rcmail->config->get('plugin_manager_shared')) && $this->rcmail->config->get('customer_id') != $this->rcmail->config->get('own_customer_id')){
+ $content = html::tag('input', array('name' => '_customer_id', 'id' => 'customer_id', 'type' => 'hidden', 'value' => $customer_id)) .
+ html::tag('input', array('name' => '_clientip', 'id' => 'clientip', 'type' => 'hidden', 'value' => $_SERVER['REMOTE_ADDR'])) .
+ html::tag('input', array('name' => '_serverip', 'id' => 'serverip', 'type' => 'hidden', 'value' => $_SERVER['SERVER_ADDR'])) .
+ html::tag('span', array('style' => 'font-weight: normal; font-size: 13px'), $this->gettext('sharedby') . '&nbsp;' . html::tag('b', null, $shared)) . html::tag('br') .
+ html::tag('small', array('style' => 'font-weight: normal'), '&raquo;&nbsp;' .
+ html::tag('a', array('href' => './?_action=plugin.plugin_manager_deny'), $this->gettext('switch')) . '&nbsp;' . $this->gettext('ownaccount') . '&nbsp;' . $this->rcmail->user->data['username']
+ ) .
+ html::tag('br') . html::tag('br') .
+ html::tag('input', array('name' => '_home', 'id' => 'home', 'type' => 'hidden', 'value' => ''));
+ }
+ else{
+ $accept = '';
+ if($this->rcmail->config->get('shared_customer_id')){
+ $accept = html::tag('br') .
+ html::tag('small', array('style' => 'font-weight: normal'), '&raquo;&nbsp;' . html::tag('a', array('href' => './?_action=plugin.plugin_manager_accept'), $this->gettext('switch')) . ' ' .
+ $this->gettext('shareinvitation') . ' ' . $this->rcmail->config->get('plugin_manager_shared'));
+ }
+ $content = $this->gettext('customer_id') . ': ' . html::tag('input', array('name' => '_customer_id', 'id' => 'customer_id', 'size' => 32, 'readonly' => 'readonly', 'value' => $customer_id)) .
+ html::tag('input', array('name' => '_clientip', 'id' => 'clientip', 'type' => 'hidden', 'value' => $_SERVER['REMOTE_ADDR'])) .
+ html::tag('input', array('name' => '_serverip', 'id' => 'serverip', 'type' => 'hidden', 'value' => $_SERVER['SERVER_ADDR'])) .
+ '&nbsp;' . html::tag('a', array('href' => './?_task=settings&_action=plugin.plugin_manager_getnew', 'style' => 'font-size:11px;', 'title' => $this->gettext('getnew_hint')), $this->gettext('getnew')) .
+ $accept .
+ html::tag('br') . html::tag('br') .
+ html::tag('input', array('name' => '_home', 'id' => 'home', 'type' => 'hidden', 'value' => ''));
+ }
+ $this->rcmail->output->add_script('if(document.getElementById("home")){ $("#home").val(document.location.href) };', 'docready');
+ if($http->error){
+ $content .= html::tag('span', array('style' => 'font-weight: normal; font-size: 11px'), $this->gettext('trylater'));
+ }
+ else{
+ $response = $http->result;
+ $account = unserialize($response);
+ if(is_array($account) && !$account['credits'] == '-0'){
+ unset($httpConfig['params']);
+ $httpConfig['method'] = 'GET';
+ $httpConfig['target'] .= '&_customer_id=' . $this->rcmail->config->get('customer_id');
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $response = $http->result;
+ $account = unserialize($response);
+ }
+ if(is_array($account)){
+ $rows = '';
+ $sum = 0;
+ if(is_array($account['history'])){
+ $head = html::tag('tr', array('style' => 'font-weight: bold; font-size: 12px;'),
+ html::tag('td', array('style' => 'border: 2px solid lightgrey;'), $this->gettext('date')) .
+ html::tag('td', array('style' => 'border: 2px solid lightgrey;'), 'IPs') .
+ html::tag('td', array('style' => 'border: 2px solid lightgrey;', 'align' => 'center'), $this->gettext('download')) .
+ html::tag('td', array('style' => 'border: 2px solid lightgrey;', 'align' => 'center'), $this->gettext('receipt')) .
+ html::tag('td', array('style' => 'border: 2px solid lightgrey;'), 'MyRC$') .
+ html::tag('td', array('style' => 'border: 2px solid lightgrey;', 'align' => 'center'), $this->gettext('plugins'))
+ );
+ foreach($account['history'] as $entry){
+ $list = '';
+ $plugins = unserialize($entry['plugins']);
+ if(is_array($plugins)){
+ foreach($plugins as $plugin){
+ $list .= html::tag('li', null, $plugin[0] . '&nbsp;(' . $plugin[1] . ')');
+ }
+ }
+ if($entry['action'] == 'd'){
+ if($_SERVER['REMOTE_ADDR'] == $entry['clientip'] || $_SERVER['HTTP_X_FORWARDED_FOR'] == $entry['clientip'] || $_SERVER['HTTP_X_REAL_IP'] == $entry['clientip']){
+ $dllink = $this->dlurl . 'index.php?_hash=' . md5($_SERVER['REMOTE_ADDR']) . '&_dl=' . $entry['dl'];
+ $dllabel = $this->gettext('clickhere');
+ }
+ else{
+ $dllink = '#';
+ $dllabel = sprintf($this->gettext('ipmismatch'), $_SERVER['REMOTE_ADDR'], html::tag('input', array('readonly' => 'readonly', 'onclick' => 'this.select()', 'style' => 'font-size:9px', 'value' => 'wget --no-check-certificate -O plugins.zip "' . $this->dlurl . 'index.php?_hash=' . md5($entry['serverip']) . '&_dl=' . $entry['dl'] . '"')), html::tag('input', array('readonly' => 'readonly', 'onclick' => 'this.select()', 'style' => 'font-size:9px', 'value' => $this->dlurl . 'index.php?_hash=' . md5($entry['serverip']) . '&_dl=' . $entry['dl'])), $entry['serverip']);
+ }
+ if(substr($entry['dl'], 0, 1) == '_'){
+ $dllink = '#';
+ $dllabel = $this->gettext('expired');
+ }
+ $rows .= html::tag('tr', null,
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), str_replace(' ', '&nbsp;', date($this->rcmail->config->get('date_format', 'Y-m-d') . ' ' . $this->rcmail->config->get('time_format', 'H:i:s') . ':s', strtotime($entry['date'])))) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), $entry['serverip'] ? ($entry['serverip'] . '&nbsp;(Server)<br />' . $entry['clientip'] . '&nbsp;(Client)') : ($entry['ip'] . '&nbsp;(Client)')) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'center'), $dllink == '#' ? $dllabel : html::tag('a', array('href' => $dllink), $dllabel)) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'),
+ html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => '$(".' . $entry['dl'] . '").show()'), $this->gettext('show')) . '&nbsp;|&nbsp;' .
+ html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => '$(".' . $entry['dl'] . '").hide()'), $this->gettext('hide')) . '&nbsp;|&nbsp;' .
+ html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => 'var win = window.open(); win.document.write("<pre>" + $(".' . $entry['dl'] . '").html() + "</pre>"); win.print(); win.close()'), $this->gettext('print')) .
+ html::tag('pre', array('class' => 'expand ' . $entry['dl'], 'style' => 'display: none;'), base64_decode($entry['receipt']))) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey; color: red;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'right'), $entry['myrcd']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), html::tag('ul', null, $list))
+ );
+ $sum = $sum + $entry['myrcd'];
+ }
+ else if($entry['action'] == 'b'){
+ $rows .= html::tag('tr', null,
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), str_replace(' ', '&nbsp;', date($this->rcmail->config->get('date_format', 'Y-m-d') . ' ' . $this->rcmail->config->get('time_format', 'H:i:s') . ':s', strtotime($entry['date'])))) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), $entry['serverip'] ? ($entry['serverip'] . '&nbsp;(Server)<br />' . $entry['clientip'] . '&nbsp;(Client)<br />via ' . $entry['ip']) : $entry['ip']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'center', 'colspan' => 2), $this->gettext('myrcd_bought')) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey; color: green;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'right'), '+' . $entry['myrcd']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), '&nbsp;')
+ );
+ $sum = $sum + $entry['myrcd'];
+ }
+ else if($entry['action'] == 'r'){
+ $rows .= html::tag('tr', null,
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), str_replace(' ', '&nbsp;', date($this->rcmail->config->get('date_format', 'Y-m-d') . ' ' . $this->rcmail->config->get('time_format', 'H:i:s') . ':s', strtotime($entry['date'])))) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), $entry['serverip'] ? ($entry['serverip'] . '&nbsp;(Server)<br />' . $entry['clientip'] . '&nbsp;(Client)<br />via ' . $entry['ip']) : $entry['ip']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'center', 'colspan' => 2), $this->gettext('myrcd_refunded')) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey; color: red;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'right'), $entry['myrcd']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), '&nbsp;')
+ );
+ $sum = $sum + $entry['myrcd'];
+ }
+ else if($entry['action'] == 'c'){
+ $rows .= html::tag('tr', null,
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), str_replace(' ', '&nbsp;', date($this->rcmail->config->get('date_format', 'Y-m-d') . ' ' . $this->rcmail->config->get('time_format', 'H:i:s') . ':s', strtotime($entry['date'])))) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), $entry['ip']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'center', 'colspan' => 2), $this->gettext('customer_id_changed')) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), '&nbsp;') .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), '&nbsp;')
+ );
+ }
+ else if($entry['action'] == 't'){
+ $rows .= html::tag('tr', null,
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), str_replace(' ', '&nbsp;', date($this->rcmail->config->get('date_format', 'Y-m-d') . ' ' . $this->rcmail->config->get('time_format', 'H:i:s') . ':s', strtotime($entry['date'])))) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), $entry['ip']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'center', 'colspan' => 2), $this->gettext('credits_transferred')) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey; color:' . ($entry['myrcd'] > 0 ? ' green;' : ' red;'), 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'right'), ($entry['myrcd'] > 0 ? '+' : '') . $entry['myrcd']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), '&nbsp;')
+ );
+ $sum = $sum + $entry['myrcd'];
+ }
+ else if($entry['action'] == 'a'){
+ $color = $entry['myrcd'] > 0 ? 'green' : 'red';
+ $rows .= html::tag('tr', null,
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), str_replace(' ', '&nbsp;', date($this->rcmail->config->get('date_format', 'Y-m-d') . ' ' . $this->rcmail->config->get('time_format', 'H:i:s') . ':s', strtotime($entry['date'])))) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), $entry['ip']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'center', 'colspan' => 2), $this->gettext('account_details_compressed')) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey; color: ' . $color . ';', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'right'), ($entry['myrcd'] > 0 ? '+' : '') . $entry['myrcd']) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), '&nbsp;')
+ );
+ $sum = $sum + $entry['myrcd'];
+ }
+ }
+ }
+ $free = '';
+ if($account['credits'] > $sum){
+ $free = html::tag('tr', null,
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'center'), '--') .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'colspan' => 3), 'Free&nbsp;MyRC$&nbsp;granted&nbsp;-&nbsp;Enjoy!') .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey; color: green;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'right'), '+'. ($account['credits'] - $sum)) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top'), '&nbsp;')
+ );
+ }
+ $rows .= html::tag('tr', null,
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'colspan' => 4), 'MyRC$ (' . $this->gettext('credits') . ')') .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey; font-weight: bold; color: ' . ($account['credits'] > 0 ? 'green' : 'red'), 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'right'), ($account['credits'] > 0 ? '+' : '') . html::tag('span', null, $account['credits'])) .
+ html::tag('td', array('style' => 'border: 1px solid lightgrey;', 'nowrap' => 'nowrap', 'valign' => 'top', 'align' => 'right'), html::tag('a', array('href' => 'javascript:document.forms.form.target="_blank";document.forms.form.action="' . $this->billingurl .'";document.forms.form.submit()', 'style' => 'font-weight:normal; font-size: 11px'), str_replace(' ', '&nbsp;', $this->gettext('buynow'))))
+ );
+ $print = '$(".expand").show(); $("a").hide(); var content = $("#accountdetails").html(); while(content.indexOf("|") > -1){content = content.replace("|", "")}; ' .
+ 'var win = window.open(); win.document.write("<html><head><title>MyRoundcube ' . $this->gettext('customer_account') . ' - ' . $this->gettext('print') . '</title></head><body><table>" + content + "</table></body></html>"); ' .
+ '$("a").show(); $(".expand").hide(); win.print(); win.close();';// document.location.href="./?_task=settings&_action=plugin.plugin_manager_compress";';
+ if($this->rcmail->config->get('plugin_manager_shared')){
+ $priviledged = '';
+ $printdetails = '';
+ }
+ else{
+ $priviledged = html::tag('li', null, html::tag('a', array('href' => './?_task=settings&_action=plugin.plugin_manager_transfer&_framed=1', 'style' => 'font-weight:normal; font-size: 12px'), str_replace(' ', '&nbsp;', $this->gettext('transfer')))) .
+ html::tag('li', null, html::tag('a', array('href' => 'javascript:document.forms.form.target="_blank";document.forms.form.action="' . str_replace('buycredits', 'mergecredits', $this->billingurl) .'";document.forms.form.submit()', 'style' => 'font-weight:normal; font-size: 12px'), str_replace(' ', '&nbsp;', $this->gettext('merge'))));
+ $printdetails = html::tag('div', array('style' => 'float:right;padding:3px;'), html::tag('a', array('href' => '#', 'onclick' => $print, 'style' => 'font-size:11px;'), $this->gettext('printdetails')) . '&nbsp;');
+ }
+ $content .= html::tag('fieldset', array('style' => 'border: 1px solid lightgrey; padding: 5px; margin-left: 0'),
+ html::tag('legend', array('style' => 'font-weight: normal; padding-bottom: 0;'), $this->gettext('details')) .
+ html::tag('ul', null,
+ html::tag('li', null, html::tag('a', array('href' => 'javascript:document.forms.form.target="_blank";document.forms.form.action="' . $this->billingurl .'";document.forms.form.submit()', 'style' => 'font-weight:normal; font-size: 12px'), str_replace(' ', '&nbsp;', $this->gettext('buynow')))) .
+ $priviledged .
+ html::tag('li', null, html::tag('span', array('style' => 'font-weight: bold; font-size: 12px;'), 'MyRC$ ' . ' ' . html::tag('span', array('id' => 'cdlcredits'), $account['credits']) . ' ' . html::tag('span', array('style' => 'font-weight: normal;'), '(' . $this->gettext('credits') . ')'))) .
+ html::tag('li', null, html::tag('span', array('style' => 'font-size: 12px;'), $this->gettext('history'))) . html::tag('br') .
+ html::tag('div', array('style' => 'float:left;padding:3px;'), html::tag('a', array('href' => '#', 'onclick' => 'document.location.href=document.location.href + "&_ts=' . time() . '"', 'style' => 'font-size:11px;'), $this->gettext('refresh'))) .
+ html::tag('div', array('style' => 'float:right;padding:3px;'), html::tag('a', array('href' => '#', 'onclick' => 'window.open("' . str_replace('?_task=billing&_action=buycredits', 'plugins/billing/prices.php?_ts=' . time(), $this->billingurl) . '")', 'style' => 'font-size:11px;'), $this->gettext('pricelist'))) .
+ $printdetails .
+ html::tag('table', array('id' => 'accountdetails', 'style' => 'font-weight: normal; font-size: 11px; border: 1px solid lightgrey;', 'border' => '0', 'cellpadding' => '0', 'cellspacing' => '0', 'width' => '100%'), $head . $free . $rows)
+ )
+ );
+ }
+ else{
+ $content .= html::tag('span', array('style' => 'font-weight: normal; font-size: 11px'), $this->gettext('trylater'));
+ }
+ }
+ }
+ else{
+ $content = '';
+ }
+ $args['blocks']['plugin_manager_customer']['options'][0] = array(
+ 'title' => $content,
+ 'content' => ''
+ );
+ $this->rcmail->output->add_script('if(self.location.href != parent.location.href){$(".mainaction").remove(); $("td").css("width", "1px");}', 'docready');
+ }
+ return $args;
+ }
+
+ function compress(){
+ $params = array('_customer_id' => $this->rcmail->config->get('customer_id'), '_ip' => $this->getVisitorIP());
+ $httpConfig['method'] = 'POST';
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_compress';
+ $httpConfig['timeout'] = '30';
+ $httpConfig['params'] = $params;
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ header('Location: ./?_task=settings&_action=edit-prefs&_section=plugin_manager_customer&_framed=1');
+ exit;
+ }
+
+ function getCustomerID(){
+ $params = array();
+ $httpConfig['method'] = 'GET';
+ $httpConfig['target'] = $this->svn . '?_action=plugin.plugin_server_customer_id';
+ $httpConfig['timeout'] = '30';
+ $httpConfig['params'] = $params;
+ $httpConfig['user_agent'] = 'MyRoundcube PHP/5.0';
+ $http = new MyRCHttp();
+ $http->initialize($httpConfig);
+ if(ini_get('safe_mode') || ini_get('open_basedir')){
+ $http->useCurl(false);
+ }
+ $http->execute();
+ $this->_log($httpConfig, $http);
+ if($http->error){
+ $response = false;
+ }
+ else{
+ $response = $http->result;
+ }
+ return $response;
+ }
+
+ function save(){
+ $ret = $this->saveprefs(array('section' => 'plugin_manager'));
+ if(class_exists('cookie_config')){
+ cookie_config::plugin_manager_save($ret);
+ }
+ $saved = $this->rcmail->user->save_prefs($ret['prefs']);
+ $response = '';
+ if($saved){
+ if($ret['script'])
+ $response = $ret['script'];
+ $this->rcmail->output->command('plugin.plugin_manager_saved', $response);
+ }
+ else{
+ $this->rcmail->output->command('plugin.plugin_manager_error', $response);
+ }
+ }
+
+ function saveprefs($args){
+ if($args['section'] == 'plugin_manager_settings'){
+ if(strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $this->rcmail->output->show_message($this->gettext('demoaccount'), 'error');
+ return $args;
+ }
+ $this->rcmail->session->remove('plugin_manager_settings');
+ $defaults = get_input_value('_plugin_manager_defaults', RCUBE_INPUT_POST);
+ $newplugin = (array) get_input_value('_new_plugin_name', RCUBE_INPUT_POST);
+ $removeplugin = (array) get_input_value('_remove_plugin_name', RCUBE_INPUT_POST);
+ $skins = (array) get_input_value('_skins', RCUBE_INPUT_POST);
+ include INSTALL_PATH . 'plugins/plugin_manager/defaults.inc.php';
+ $overwrite = $config['plugin_manager_defaults'];
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'defaults_overwrite');
+ $overwrite = $this->rcmail->db->fetch_assoc($res);
+ if(is_array($overwrite)){
+ $overwrite = unserialize($overwrite['value']);
+ if(!is_array($overwrite)){
+ $overwrite = $config['plugin_manager_defaults'];
+ }
+ }
+ else{
+ $overwrite = $config['plugin_manager_defaults'];
+ }
+ foreach($skins as $section => $plugins){
+ foreach($plugins as $plugin => $skin){
+ if($skin != 'all'){
+ $overwrite[$section][$plugin]['skins'] = explode('|', $skin);
+ }
+ else{
+ unset($overwrite[$section][$plugin]['skins']);
+ }
+ }
+ }
+ $sql = 'UPDATE ' . get_table_name('plugin_manager') . ' SET ' . $this->q('value') . '=? WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->query($sql, serialize($overwrite), 'defaults_overwrite');
+ if(!$this->rcmail->db->affected_rows($res)){
+ $sql = 'INSERT INTO ' . get_table_name('plugin_manager') . ' (' . $this->q('conf') . ', ' . $this->q('value') . ', ' . $this->q('type') . ') VALUES (?, ?, ?)';
+ $this->rcmail->db->query($sql, 'defaults_overwrite', serialize($overwrite), 'array');
+ }
+ foreach($removeplugin as $section => $plugin){
+ if($plugin && file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/' . $plugin . '.php')){
+ unset($overwrite[$section][$plugin]);
+ $sql = 'UPDATE ' . get_table_name('plugin_manager') . ' SET ' . $this->q('value') . '=? WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->query($sql, serialize($overwrite), 'defaults_overwrite');
+ break;
+ }
+ }
+ foreach($newplugin as $section => $plugin){
+ if($plugin && file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/' . $plugin . '.php')){
+ $overwrite[$section][$plugin] = array(
+ 'active' => false,
+ 'protected' => true,
+ 'label_name' => $plugin . '.pluginname',
+ 'label_description' => $plugin . '.plugindescription'
+ );
+ $sql = 'UPDATE ' . get_table_name('plugin_manager') . ' SET ' . $this->q('value') . '=? WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->query($sql, serialize($overwrite), 'defaults_overwrite');
+ break;
+ }
+ }
+ if(is_array($defaults)){
+ foreach($this->defaults as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ foreach($props as $prop => $value){
+ if($prop == 'active' || $prop == 'protected'){
+ if(!isset($defaults[$section][$plugin][$prop])){
+ $defaults[$section][$plugin][$prop] = false;
+ }
+ }
+ }
+ }
+ }
+ $defaults = serialize($defaults);
+ $sql = 'DELETE FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $this->rcmail->db->query($sql, 'defaults');
+ $sql = 'INSERT INTO ' . get_table_name('plugin_manager') . '(' . $this->q('conf') . ', ' . $this->q('value') . ', ' . $this->q('type') . ') VALUES (?, ?, ?)';
+ $this->rcmail->db->query($sql, 'defaults', $defaults, 'array');
+ $this->rcmail->session->remove('plugin_manager_defaults');
+ $defaults = unserialize($defaults);
+ if($defaults['globalplugins']['sabredav']['active'] == 1){
+ $this->require_plugin('sabredav');
+ }
+ }
+ if($this->admins[$this->rcmail->user->data['username']] == 0){
+ $this->rcmail->user->save_prefs(
+ array(
+ 'plugin_manager_show_myrc_messages' => get_input_value('_plugin_manager_show_myrc_messages', RCUBE_INPUT_POST),
+ 'plugin_manager_translation_account' => trim(get_input_value('_plugin_manager_translation_account', RCUBE_INPUT_POST)),
+ 'plugin_manager_translation_server' => trim(get_input_value('_plugin_manager_translation_server', RCUBE_INPUT_POST)),
+ )
+ );
+ $sql = 'DELETE FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . ' LIKE ?';
+ $this->rcmail->db->query($sql, '_plugin_manager_%');
+ $keys = array('_plugin_manager_update_notifications', '_plugin_manager_update_notifications_cc', '_plugin_manager_maintenance_mode', '_plugin_manager_file_based_config', '_plugin_manager_use_ssl', '_plugin_manager_hmail', '_plugin_manager_load_splitter', '_plugin_manager_compress_html', '_plugin_manager_about_link', '_plugin_manager_myroundcube_watermark', '_plugin_manager_remove_watermark', '_plugin_manager_support_link');
+ foreach($keys as $key){
+ $save = get_input_value($key, RCUBE_INPUT_POST);
+ $sql = 'INSERT INTO ' . get_table_name('plugin_manager') . ' (conf, value, type) VALUES (?, ?, ?)';
+ if(is_null($save) || is_numeric($save)){
+ $this->rcmail->db->query($sql, $key, $save ? 1: 0, 'bool');
+ }
+ else if(is_array($save)){
+ $this->rcmail->db->query($sql, $key, serialize($save), 'array');
+ }
+ else if(is_string($save)){
+ $this->rcmail->db->query($sql, $key, trim($save), 'string');
+ }
+ }
+ }
+ else{
+ $keys = array('_plugin_manager_maintenance_mode');
+ foreach($keys as $key){
+ $sql = 'DELETE FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . ' LIKE ?';
+ $this->rcmail->db->query($sql, $key);
+ $save = get_input_value($key, RCUBE_INPUT_POST);
+ $sql = 'INSERT INTO ' . get_table_name('plugin_manager') . ' (conf, value, type) VALUES (?, ?, ?)';
+ $this->rcmail->db->query($sql, $key, $save ? 1: 0, 'bool');
+ }
+ $this->rcmail->user->save_prefs(
+ array(
+ 'plugin_manager_show_myrc_messages' => get_input_value('_plugin_manager_show_myrc_messages', RCUBE_INPUT_POST),
+ 'plugin_manager_translation_account' => trim(get_input_value('_plugin_manager_translation_account', RCUBE_INPUT_POST)),
+ 'plugin_manager_translation_server' => trim(get_input_value('_plugin_manager_translation_server', RCUBE_INPUT_POST))
+ )
+ );
+ }
+ if($plugin = get_input_value('_plugin', RCUBE_INPUT_GET)){
+ $append = '&_expand='. $plugin;
+ }
+ else{
+ $append = '';
+ }
+ if(get_input_value('_plugin_manager_maintenance_mode', RCUBE_INPUT_POST)){
+ $prefix = '';
+ if(class_exists('tabbed')){
+ $prefix = 'parent.';
+ }
+ $this->rcmail->output->add_script($prefix . "parent.location.href='./?_task=settings&_next=plugin_manager_settings';", 'docready');
+ return $args;
+ }
+ else{
+ header('Location: ./?_task=settings&_action=edit-prefs&_section=plugin_manager_settings&_framed=1&_pmmsg=successfullysaved' . $append);
+ exit;
+ }
+ }
+ if($args['section'] == 'plugin_manager_admins'){
+ if(strtolower($this->get_demo($_SESSION['username'])) == strtolower(sprintf($this->rcmail->config->get('demo_user_account'),""))){
+ $this->rcmail->output->show_message($this->gettext('demoaccount'), 'error');
+ return $args;
+ }
+ $sql = 'SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $this->q('conf') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, 'admins');
+ $admins = $this->rcmail->db->fetch_assoc($res);
+ if(!$admins = unserialize($admins['value'])){
+ $admins = array();
+ }
+ $merge = get_input_value('_plugin_manager_admins', RCUBE_INPUT_POST);
+ $admins = array_merge(array($this->rcmail->user->data['username']), $merge);
+ $save = array();
+ foreach($admins as $idx => $admin){
+ if($admin){
+ $sql = 'SELECT ' . $this->q('username') . ' FROM ' . get_table_name('users') . ' WHERE ' . $this->q('username') . '=?';
+ $res = $this->rcmail->db->limitquery($sql, 0, 1, strtolower($admin));
+ if($res){
+ if(is_array($this->rcmail->db->fetch_assoc($res))){
+ $save[] = $admin;
+ }
+ else{
+ $this->rcmail->output->show_message($this->gettext('accountnotexists'), 'error');
+ }
+ }
+ }
+ }
+ asort($save);
+ $save = array_merge(array($this->rcmail->user->data['username']), $save);
+ $save = array_unique($save);
+ $sql = 'UPDATE ' . get_table_name('plugin_manager') . ' SET ' . $this->q('value') . '=? WHERE ' . $this->q('conf') . '=?';
+ $this->rcmail->db->query($sql, serialize($save), 'admins');
+ foreach($admins as $idx => $admin){
+ if($idx == 0) continue;
+ $config = get_input_value('_plugin_manager_config', RCUBE_INPUT_POST);
+ $sql = 'SELECT ' . $this->q('preferences') . ' FROM ' . get_table_name('users') . ' WHERE ' . $this->q('username') . '=? AND ' . $this->q('mail_host') . '=?';
+ if($res = $this->rcmail->db->limitquery($sql, 0, 1, $admin, $_SESSION['storage_host'])){
+ $prefs = $this->rcmail->db->fetch_assoc($res);
+ if($prefs = unserialize($prefs['preferences'])){
+ if(isset($config[$admin])){
+ $prefs = serialize(array_merge($prefs, array('plugin_manager_hash' => $this->rcmail->config->get('plugin_manager_hash'))));
+ }
+ else{
+ unset($prefs['plugin_manager_hash']);
+ $prefs = serialize($prefs);
+ }
+ }
+ else{
+ if(isset($config[$admin])){
+ $prefs = serialize(array('plugin_manager_hash' => $this->rcmail->config->get('plugin_manager_hash')));
+ }
+ else{
+ $prefs = serialize(array());
+ }
+ }
+ $sql = 'UPDATE ' . get_table_name('users') . ' SET ' . $this->q('preferences') . '=? WHERE ' . $this->q('username') . '=? AND ' . $this->q('mail_host') . '=?';
+ $this->rcmail->db->query($sql, $prefs, $admin, $_SESSION['storage_host']);
+ }
+ }
+ foreach($admins as $idx => $admin){
+ if($idx == 0) continue;
+ $config = get_input_value('_plugin_manager_customer', RCUBE_INPUT_POST);
+ $sql = 'SELECT ' . $this->q('preferences') . ' FROM ' . get_table_name('users') . ' WHERE ' . $this->q('username') . '=? AND ' . $this->q('mail_host') . '=?';
+ if($res = $this->rcmail->db->limitquery($sql, 0, 1, $admin, $_SESSION['storage_host'])){
+ $prefs = $this->rcmail->db->fetch_assoc($res);
+ if($prefs = unserialize($prefs['preferences'])){
+ if(isset($config[$admin])){
+ $prefs = serialize(array_merge($prefs, array('shared_customer_id' => $this->rcmail->config->get('customer_id'), 'plugin_manager_shared' => $this->rcmail->user->data['username'], 'own_customer_id' => $prefs['own_customer_id'] ? $prefs['own_customer_id'] : $prefs['customer_id'])));
+ }
+ else{
+ if(isset($prefs['own_customer_id'])){
+ $prefs['customer_id'] = $prefs['own_customer_id'];
+ }
+ unset($prefs['own_customer_id']);
+ unset($prefs['shared_customer_id']);
+ unset($prefs['plugin_manager_shared']);
+ $prefs = serialize($prefs);
+ }
+ }
+ else{
+ if(isset($config[$admin])){
+ $prefs = serialize(array('shared_customer_id' => $this->rcmail->config->get('customer_id'), 'plugin_manager_shared' => $this->rcmail->user->data['username'], 'own_customer_id' => $prefs['own_customer_id'] ? $prefs['own_customer_id'] : $prefs['customer_id']));
+ }
+ else{
+ $prefs = serialize(array());
+ }
+ }
+ $sql = 'UPDATE ' . get_table_name('users') . ' SET ' . $this->q('preferences') . '=? WHERE ' . $this->q('username') . '=? AND ' . $this->q('mail_host') . '=?';
+ $this->rcmail->db->query($sql, $prefs, $admin, $_SESSION['storage_host']);
+ }
+ }
+ }
+ else if($args['section'] == 'plugin_manager'){
+ $plugins = $this->config;
+ $pactive = $this->rcmail->config->get('plugin_manager_active', array());
+ $user = $this->rcmail->config->get('plugin_manager_user', array());
+ $config_plugin = get_input_value('_config_plugin', RCUBE_INPUT_POST);
+ $active = array();
+ $add_script = '';
+ foreach($plugins as $sections => $section){
+ foreach($section as $plugin => $props){
+ $posted = get_input_value('_plugin_manager_' . $plugin, RCUBE_INPUT_POST);
+ if($posted){
+ $plugins[$sections][$plugin]['active'] = 1;
+ $active[$plugin] = 1;
+ if($props['config'] && $config_plugin == $plugin){
+ if($props['section']){
+ $add_script .= "try{parent.rcmail.sections_list.select('" . $props['section'] . "')}catch(e){parent.rcmail.sections_list.clear_selection()};";
+ if($props['config']){
+ if($props['section'] == 'accountlink'){
+ if($this->rcmail->config->get('skin', 'classic') == 'larry'){
+ $add_script .= "parent.$('#preferences-frame').attr('src', '" . $props['config'] . "');";
+ }
+ else{
+ $add_script .= "parent.$('#prefs-frame').attr('src', '" . $props['config'] . "');";
+ }
+ }
+ else
+ $add_script .= "document.location.href='" . $props['config'] . "';";
+ }
+ }
+ }
+ else if($props['reload'] && !$add_script){
+ if($plugins[$sections][$plugin]['active'] != $pactive[$plugin]){
+ $add_script .= "parent.location.href='./?_task=settings&_action=plugin.plugin_manager&_section=plugin_manager';";
+ }
+ }
+ }
+ else{
+ $plugins[$sections][$plugin]['active'] = 0;
+ $active[$plugin] = 0;
+ if($props['reload'] && !$add_script){
+ if($plugins[$sections][$plugin]['active'] != $pactive[$plugin])
+ $add_script .= "parent.location.href='./?_task=settings&_action=plugin.plugin_manager&_section=plugin_manager';";
+ if($plugin == 'wrapper' && $add_script)
+ $add_script .= 'parent.' . $add_script;
+ }
+ if(is_array($plugins[$sections][$plugin]['unset'])){
+ $unsets = $plugins[$sections][$plugin]['unset'];
+ }
+ else if(is_string($plugins[$sections][$plugin]['unset'])){
+ $unsets = array($plugins[$sections][$plugin]['unset']);
+ }
+ if(is_array($unsets)){
+ foreach($unsets as $pref => $value){
+ $new = $this->rcmail->config->get($value);
+ $sav = $value;
+ $array = $this->rcmail->config->get($pref);
+ if(is_array($array)){
+ $new = $array;
+ $sav = $pref;
+ }
+ if(is_array($new)){
+ $new = $this->rcmail->config->get($pref);
+ unset($new[$pref]);
+ foreach($new as $key => $val){
+ if($val == $value){
+ unset($new[$key]);
+ }
+ }
+ if(is_numeric($key))
+ $new = array_values($new);
+ }
+ else{
+ $new = false;
+ unset($prefs[$sav]);
+ }
+ $args['prefs'][$sav] = $new;
+ }
+ }
+ }
+ }
+ }
+ $remote = get_input_value('_remote', RCUBE_INPUT_POST);
+ if($add_script){
+ if($remote)
+ $args['script'] = $add_script;
+ else
+ $this->rcmail->output->add_script($add_script);
+ }
+ $args['prefs']['plugin_manager_active'] = $active;
+ }
+ else if($args['section'] == 'plugin_manager_customer'){
+ if($id = get_input_value('_customer_id', RCUBE_INPUT_POST)){
+ $args['prefs']['customer_id'] = $id;
+ }
+ }
+ return $args;
+ }
+
+ function labels($label, $s = false){
+ $temparr = explode('.', $label);
+ if(count($temparr) > 1){
+ // plugin label
+ if(!is_array($this->labels[$temparr[0]])){
+ $plugins = $this->rcmail->config->get($this->plugin, array());
+ foreach($plugins as $sections => $section){
+ foreach($section as $plugin => $props){
+ if($plugin == $temparr[0]){
+ $localization = $props['localization'];
+ break;
+ }
+ }
+ if($localization){
+ break;
+ }
+ }
+ if(!$localization)
+ $localization = 'localization';
+ $path = INSTALL_PATH . 'plugins/' . $temparr[0] . '/' . $localization;
+ $file = $path . '/en_US.inc';
+ @include $file;
+ $file = $path . '/' . $_SESSION['language'] . '.inc';
+ $en_labels = $labels;
+ $en_msgs = $messages;
+ @include $file;
+ if(is_array($en_labels) && is_array($labels))
+ $labels = array_merge($en_labels, $labels);
+ if(is_array($en_msgs) && is_array($messages))
+ $messages = array_merge($en_msgs, $messages);
+ if(is_array($labels) && is_array($messages))
+ $labels = array_merge($messages, $labels);
+ $this->labels[$temparr[0]] = $labels;
+ }
+ if($this->labels[$temparr[0]][$temparr[1]]){
+ $label = $this->labels[$temparr[0]][$temparr[1]];
+ }
+ else{
+ $pm_label = $this->gettext($temparr[0] . '_' . $temparr[1]);
+ if(substr($label, 0, 1) == '[' && substr($label, strlen($label) - 1, 1) == ']'){
+ $label = '[' . $label . ']';
+ }
+ else{
+ $label = $pm_label;
+ }
+ }
+ }
+ else{
+ // default label
+ $label = $this->gettext($label);
+ }
+ if(substr($label, 0, 1) == '[' && substr($label, strlen($label) - 1, 1) == ']'){
+ // return best hestimation
+ $label = ucwords(substr(str_replace('_', ' ', $label), 1,strlen($label) - 2));
+ $label = '['.str_replace('.plugindescription', '', str_replace('.pluginname', '', $label)).']';
+ }
+ if($s || strpos($label, '%s') !== false){
+ if(!$s){
+ $s = '';
+ }
+ $label = sprintf($label, $s);
+ }
+ return Q($label);
+ }
+
+ function q($str){
+ return $this->rcmail->db->quoteIdentifier($str);
+ }
+
+ function fix_table_names($sql, $tables){
+ foreach($tables as $table){
+ $real_table = get_table_name($table);
+ if($real_table != $table){
+ $sql = preg_replace("/([^a-z0-9_])$table([^a-z0-9_])/i", "\\1$real_table\\2", $sql);
+ }
+ }
+ return $sql;
+ }
+
+ function AllPermutations($InArray, $InProcessedArray = array()){
+ $ReturnArray = array();
+ foreach($InArray as $Key=>$value){
+ $CopyArray = $InProcessedArray;
+ $CopyArray[$Key] = $value;
+ $TempArray = array_diff_key($InArray, $CopyArray);
+ if(count($TempArray) == 0){
+ $ReturnArray[] = $CopyArray;
+ }
+ else{
+ $ReturnArray = array_merge($ReturnArray, $this->AllPermutations($TempArray, $CopyArray));
+ }
+ }
+ return $ReturnArray;
+ }
+
+ function comment2ul($string){
+ $string = '<li>' . preg_replace('/<br(?: \/)?>/', "</li><li>", $string) . '</li>';
+ return html::tag('ul', array('class' => 'pm_update'), str_replace('<li></li>', '', $string));
+ }
+
+ function get_demo($string){
+ $temparr = explode("@",$string);
+ return preg_replace ('/[0-9 ]/i', '', $temparr[0]) . "@" . $temparr[count($temparr)-1];
+ }
+
+ function getVisitorIP(){
+ return rcube_utils::remote_addr();
+ }
+
+ function html_compress($p){
+ $page = $p['content'];
+ $reg = '/<(pre|textarea|script|style|code).*?>(.*?)<(\/pre|\/textarea|\/script|\/style|\/code)>/imsu';
+ $count = preg_match_all($reg, $page, $nocompress);
+ if($count > 0){
+ foreach($nocompress[0] as $content){
+ $page = str_replace($content, '<!-- '.md5($content).' -->', $page);
+ }
+ }
+ $search = array(
+ '/\>[^\S ]+/s', //strip whitespaces after tags, except space
+ '/[^\S ]+\</s', //strip whitespaces before tags, except space
+ '/(\s)+/s' // shorten multiple whitespace sequences
+ );
+ $replace = array(
+ '>',
+ '<',
+ '\\1'
+ );
+ $page = preg_replace($search, $replace, $page);
+ if($count > 0){
+ foreach($nocompress[0] as $content){
+ $page = str_replace('<!-- '.md5($content).' -->', $content, $page);
+ }
+ }
+ $p['content'] = $page;
+ return $p;
+ }
+
+ function gethost(){
+ if($host = $_SERVER['HTTP_X_FORWARDED_HOST']){
+ $elements = explode(',', $host);
+ $host = trim(end($elements));
+ }
+ else{
+ if(!$host = $_SERVER['HTTP_HOST']){
+ if(!$host = $_SERVER['SERVER_NAME']){
+ $host = !empty($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '';
+ }
+ }
+ }
+ $host = preg_replace('/:\d+$/', '', $host);
+ if(!$host){
+ $host = 'localhost';
+ }
+ return trim($host);
+ }
+
+ function sendmail($from, $to, $cc, $subject, $body){
+ $return = false;
+ if($from && ($to || $cc) && $subject && $body){
+ $body = str_replace('&amp;', '&', $body);
+ $LINE_LENGTH = $this->rcmail->config->get('line_length', 72);
+ $h2t = new html2text($body, false, true, 0);
+ $txt = rc_wordwrap($h2t->get_text(), $LINE_LENGTH, "\r\n");
+ $msg = array('subject' => '=?UTF-8?B?'. base64_encode($subject) . '?=', 'htmlbody' => $body, 'txtbody' => $txt);
+ $ctb = md5(rand() . microtime());
+ $headers = "Return-Path: $from\r\n";
+ $headers .= "MIME-Version: 1.0\r\n";
+ $headers .= "Content-Type: multipart/alternative; boundary=\"=_$ctb\"\r\n";
+ $headers .= "Reply-To: " . $this->replyto . "\r\n";
+ $headers .= "Date: " . date('r', time()) . "\r\n";
+ $headers .= "From: MyRoundcube Update Notifier <$from>\r\n";
+ if($to){
+ $headers .= "To: $to\r\n";
+ }
+ if($cc){
+ $headers .= "CC: $cc\r\n";
+ }
+ $headers .= "Subject: " . $msg['subject'] . "\r\n";
+ $headers .= "Reply-To: $from\r\n";
+ $msg_body .= "Content-Type: multipart/alternative; boundary=\"=_$ctb\"\r\n\r\n";
+ $txt_body = "--=_$ctb";
+ $txt_body .= "\r\n";
+ $txt_body .= "Content-Transfer-Encoding: 7bit\r\n";
+ $txt_body .= "Content-Type: text/plain; charset=" . RCMAIL_CHARSET . "\r\n";
+ $txt = rc_wordwrap($msg['txtbody'], $LINE_LENGTH, "\r\n");
+ $txt = wordwrap($txt, 998, "\r\n", true);
+ $txt_body .= "$txt\r\n";
+ $txt_body .= "--=_$ctb";
+ $txt_body .= "\r\n";
+ $msg_body .= $txt_body;
+ $msg_body .= "Content-Transfer-Encoding: quoted-printable\r\n";
+ $msg_body .= "Content-Type: text/html; charset=" . RCMAIL_CHARSET . "\r\n\r\n";
+ $msg_body .= str_replace("=","=3D",$msg['htmlbody']);
+ $msg_body .= "\r\n\r\n";
+ $msg_body .= "--=_$ctb--";
+ $msg_body .= "\r\n\r\n";
+ if(!is_object($this->rcmail->smtp)){
+ $this->rcmail->smtp_init(true);
+ }
+ $this->rcmail->smtp->connect();
+ if(!$to){
+ $to = $cc;
+ }
+ $return = $this->rcmail->smtp->send_mail($from, $to, $headers, $msg_body);
+ }
+ return $return;
+ }
+
+ private function _log($config, $http){
+ if($this->log){
+ write_log('plugin_manager', '--- REQUEST ----');
+ write_log('plugin_manager', $config);
+ write_log('plugin_manager', '--- RESPONSE ---');
+ write_log('plugin_manager', $http->error ? $http->error : $http->result);
+ }
+ }
+}
+?> \ No newline at end of file
diff --git a/plugin_manager/plugin_manager_fixes.js b/plugin_manager/plugin_manager_fixes.js
new file mode 100644
index 0000000..af08e6e
--- /dev/null
+++ b/plugin_manager/plugin_manager_fixes.js
@@ -0,0 +1,19 @@
+if(window.rcmail){
+ rcmail.addEventListener('init', function(){
+ // logo click (all Roundcube versions)
+ if(rcmail.env.skin == 'larry'){
+ $('#toplogo').attr('onclick', '');
+ $('#toplogo').click(function(){
+ $('.button-mail').click();
+ });
+ $('#toplogo').attr('style', 'cursor: pointer');
+ }
+ });
+
+ // fix date alignment
+ if(rcmail.env.task == 'mail' && !rcmail.env.framed && !rcmail.env.extwin){
+ rcmail.addEventListener('listupdate', function(){
+ $(window).trigger('resize');
+ });
+ }
+}
diff --git a/plugin_manager/plugin_manager_update.js b/plugin_manager/plugin_manager_update.js
new file mode 100644
index 0000000..73721ea
--- /dev/null
+++ b/plugin_manager/plugin_manager_update.js
@@ -0,0 +1,325 @@
+function backup(obj){
+ if(confirm("Please, backup your existing plugins. You won't be able to download an earlier plugin version once you have updated plugins to the latest beta version!\r\nClick OK to continue only if you have a recent backup.")){
+ news(obj);
+ }
+}
+
+function news(obj){
+ if($('#newsletter').prop('checked')){
+ if($('#firstname').val() == ''){
+ alert('Please enter your First Name');
+ return false;
+ }
+ if($('#lastname').val() == ''){
+ alert('Please enter your Last Name');
+ return false;
+ }
+ var nl = 0;
+ if($('#newsletter').prop('checked'))
+ nl = 1;
+ obj.href = obj.href + '&_newsletter=' + nl + '&_firstname=' + escape($('#firstname').val()) + '&_lastname=' + escape($('#lastname').val());
+ }
+ if($('#devbranch').prop('checked')){
+ obj.href = obj.href + '&_branch=dev';
+ }
+ else if($('#stablebranch').prop('checked')){
+ obj.href = obj.href + '&_branch=stable';
+ }
+ else if($('#betabranch').prop('checked')){
+ obj.href = obj.href + '&_branch=beta';
+ }
+ return true;
+}
+
+function pm_get_credits(){
+ rcmail.http_post(
+ 'plugin.plugin_manager_getcredits', ''
+ );
+}
+
+function pm_discard(){
+ $('.costs').prop('checked', false);
+ $('#cdlprice').text(pm_price());
+ $('#cdlremaining').text(parseInt($('#cdlcredits').text()) - parseInt($('#cdlprice').text()));
+}
+
+function pm_notinstalled(){
+ $('.notinstalled').prop('checked', false);
+ $('#cdlprice').text(pm_price());
+ $('#cdlremaining').text(parseInt($('#cdlcredits').text()) - parseInt($('#cdlprice').text()));
+}
+
+function pm_update_credits(response){
+ if(response){
+ if($('#cdlcredits').text() != ''){
+ if(parseInt(response) != parseInt($('#cdlcredits').text())){
+ var newcredits = parseInt(response) - parseInt($('#cdlcredits').text());
+ $('#cdlcredits').text(response);
+ $('#cdlprice').text(pm_price());
+ $('#cdlremaining').text(parseInt($('#cdlcredits').text()) - parseInt($('#cdlprice').text()));
+ rcmail.display_message('MyRC$ ' + newcredits + ' ' + rcmail.gettext('creditsupdated','plugin_manager'), 'confirmation');
+ }
+ }
+ }
+ window.setTimeout('pm_get_credits()', 1000 * 30);
+}
+
+function pm_hmail(hmail){
+ $('.chbox').each(function(){
+ if($(this).attr('id') && $(this).attr('id').indexOf('_hmail_') > -1){
+ if(!$(this).prop('disabled')){
+ $(this).prop('checked', hmail);
+ $(this).trigger('click');
+ $('#cdlprice').text(pm_price());
+ $('#cdlremaining').text(parseInt($('#cdlcredits').text()) - parseInt($('#cdlprice').text()));
+ }
+ }
+ });
+ var prop = new Array();
+ prop['name'] = 'plugin_manager_hmail';
+ prop['value'] = hmail ? 0 : 1;
+ rcmail.save_pref(prop);
+ //window.setTimeout('document.location.href = document.location.href + "&_t=" + new Date().getTime()', 500);
+}
+
+function pm_price(){
+ var price = 0;
+ var id;
+ $('.chbox').each(function(){
+ if($(this).prop('checked')){
+ id = $(this).attr('id');
+ if(id){
+ id = id.replace('chbox_', 'pmdlp_');
+ if($('#' + id).text()){
+ price = price + parseInt($('#' + id).text());
+ }
+ }
+ }
+ });
+ return price;
+}
+
+function pm_uncheck(){
+ $('.chbox').each(function(){
+ $(this).prop('checked', false);
+ });
+}
+
+function pmf(){
+ var checked = false;
+ $('.chbox').each(function(){
+ if($(this).prop('checked')){
+ checked = true;
+ }
+ });
+ if(!checked){
+ rcmail.display_message(rcmail.gettext('noupdates', 'plugin_manager'), 'notice');
+ return false;
+ }
+ var hint = '';
+ $('input[type=hidden]').each(function(){
+ if($(this).prop('name') !='_token' && $(this).prop('name') !='hosted_button_id' && $(this).prop('name') !='cmd'){
+ hint = hint + $(this).prop('name') + ': ' + $(this).val() + "\n";
+ }
+ });
+ if(hint != ''){
+ var price = pm_price();
+ if(price > parseInt($('#cdlcredits').text())){
+ if(confirm("The price for this download exeeds your MyRC$ credits!\n\nPlease buy credits or discard incurring costs downloads.\n\nYes, buy MyRC$ credits [ok].\nNo, discard downloads [cancel].")){
+ window.open('./?_task=settings&_action=plugin.plugin_manager_buycredits');
+ return false;
+ }
+ else{
+ pm_discard();
+ return false;
+ }
+ }
+ $('#pm_price').val(price);
+ hint = hint.replace('##placeholder##', price);
+ var conf = '';
+ if(price > 0){
+ conf = 'Balance' + "\n---------\n" + 'We will charge your account by MyRC$ ' + price + " for this download.\n---------\n";
+ }
+ else{
+ conf = 'This download is free.' + "\n---------\n\n";
+ }
+ conf = conf + 'The form you are about to submit to...' + "\n" + $('form').prop('action') + "\n" + '...contains hidden fields:' + "\n\n" + hint + "\n";
+ conf = conf + 'We respect your privacy. The information in this form is only used for your own customer account maintenance.' + "\n\n";
+ conf = conf + 'Do you agree?';
+ var ret = confirm(conf);
+ if(ret){
+ $('#toggle').prop('checked', false);
+ window.setTimeout('pm_uncheck();', 500);
+ $('#cdlcredits').text($('#cdlremaining').text());
+ $('#cdlprice').text(0);
+ }
+ return ret;
+ }
+ return true;
+}
+
+function pm_resize(fudge){
+ $("#mainscreen").css("top", "15px");
+ $("#mainscreen").css("bottom", "5px");
+ $("#header").hide();
+ $("#taskbar").hide();
+ $("#logo").hide();
+ $("#mainscreen").show();
+ $("#settings-sections").hide();
+ $("#pluginbody").css("left", 0);
+ $("body").show();
+ if($('#table-container').get(0)){
+ var top = $('#table-container').offset().top;
+ var footer = $('#update_footer').height();
+ var height = $(window).height() - top - footer - 70;
+ $('#table-container').height(height);
+ }
+}
+
+function pm_goToByScroll(id){
+ $('.qtip').hide();
+ $('#table-container').animate({scrollTop: $("#"+id).offset().top - $('#table').offset().top},'slow');
+}
+
+$(window).resize(function(){
+ $('#mainscreen').hide();
+ window.setTimeout("pm_resize();",200);
+});
+
+$(document).ready(function(){
+ // hide qtips
+ $('.about-link').click(function(){
+ $('.ui-tooltip').hide();
+ });
+ rcmail.addEventListener('init', function(evt){
+ rcmail.addEventListener('plugin.plugin_manager_getcredits', pm_update_credits);
+ });
+ var donate = $('#paypalcontainer').html();
+ $('#paypalcontainer').remove();
+ $('body').append(donate);
+ $('#message').hide();
+ $('#newsletter').click(function(){
+ $('#newletterdetails').toggle();
+ $('#firstname').focus();
+ });
+ $('#updatetoggle').click(function(){
+ if($(this).prop('checked')){
+ $(this).attr('title', rcmail.gettext('showall', 'plugin_manager'));
+ $('td').each(function(){
+ if($(this).hasClass('ok') || $(this).hasClass('thirdparty')){
+ $(this).parent().hide();
+ }
+ });
+ }
+ else{
+ $(this).attr('title', rcmail.gettext('hideuptodate', 'plugin_manager'));
+ $('td').each(function(){
+ if($(this).hasClass('ok') || $(this).hasClass('thirdparty')){
+ $(this).parent().show();
+ }
+ });
+ }
+ });
+ window.setTimeout('pm_get_credits()', 1000 * 30);
+ /*$('.chbox').each(function(){
+ $(this).prop('disabled', false);
+ });*/
+ $('.chbox').click(function(){
+ $('#cdlprice').text(pm_price());
+ $('#cdlremaining').text(parseInt($('#cdlcredits').text()) - parseInt($('#cdlprice').text()));
+ });
+ $('.anchorLink').on('click', function(){
+ id = 'pmu_' + $(this).attr('href').substr(1);
+ pm_goToByScroll(id);
+ });
+ $('#toggle').click(function(){
+ var stat = $(this).prop('checked');
+ $('.chbox').each(function(){
+ if(!$(this).prop('disabled') && $(this).is(':visible')){
+ $(this).prop('checked', stat);
+ }
+ });
+ $('#cdlprice').text(pm_price());
+ $('#cdlremaining').text(parseInt($('#cdlcredits').text()) - parseInt($('#cdlprice').text()));
+ });
+ $('#table-container').scroll(function(){
+ $('.qtip').hide();
+ });
+ $('th').mouseover(function(){
+ $('.qtip').hide();
+ });
+ $('#update_footer').mouseover(function(){
+ $('.qtip').hide();
+ });
+ $('td').each(function(){
+ if($(this).attr('title')){
+ var ct = {};
+ var temp = $(this).attr('title').split(' :: ');
+ if(temp.length == 2){
+ ct = {
+ title: temp[0],
+ text: temp[1]
+ }
+ }
+ else{
+ ct = {
+ text: $(this).attr('title')
+ }
+ }
+ var at = 'left bottom';
+ if($(this).attr('id')){
+ if($(this).attr('id').indexOf('pmu_') > -1){
+ at = 'bottom center';
+ }
+ }
+ $(this).qtip({
+ content: ct,
+ position: {
+ my: "top left",
+ at: at,
+ target: $(this),
+ viewport: $(window)
+ },
+ show: {
+ solo: true
+ },
+ hide: 'click',
+ style: {
+ classes: "ui-tooltip-light"
+ }
+ });
+ }
+ });
+ $('.chbox').each(function(){
+ if($(this).attr('title')){
+ var ct = {};
+ var temp = $(this).attr('title').split(' :: ');
+ if(temp.length == 2){
+ ct = {
+ title: temp[0],
+ text: temp[1]
+ }
+ }
+ else{
+ ct = {
+ text: $(this).attr('title')
+ }
+ }
+ $(this).qtip({
+ content: ct,
+ position: {
+ my: "top left",
+ at: "left bottom",
+ target: $(this),
+ viewport: $(window)
+ },
+ show: {
+ solo: true
+ },
+ style: {
+ classes: "ui-tooltip-red"
+ }
+ });
+ }
+ });
+}); \ No newline at end of file
diff --git a/plugin_manager/skins/classic/blank.html b/plugin_manager/skins/classic/blank.html
new file mode 100644
index 0000000..5368cac
--- /dev/null
+++ b/plugin_manager/skins/classic/blank.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title></title>
+ <!--[if IE]>
+ <style type="text/css">
+ body { width: expression((parseInt(document.documentElement.clientWidth)-20)+'px'); }
+ </style>
+ <![endif]-->
+</head>
+
+<body style="background-color:#F2F2F2;">
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugin_manager/skins/classic/download.png b/plugin_manager/skins/classic/download.png
new file mode 100644
index 0000000..2271b6d
--- /dev/null
+++ b/plugin_manager/skins/classic/download.png
Binary files differ
diff --git a/plugin_manager/skins/classic/myroundcube.html b/plugin_manager/skins/classic/myroundcube.html
new file mode 100644
index 0000000..100f46e
--- /dev/null
+++ b/plugin_manager/skins/classic/myroundcube.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title></title>
+ <!--[if IE]>
+ <style type="text/css">
+ body { width: expression((parseInt(document.documentElement.clientWidth)-20)+'px'); }
+ </style>
+ <![endif]-->
+</head>
+
+<body style="background-color:#F2F2F2;">
+
+<div style="margin:20px auto; text-align:center">
+<img src="watermark.gif" width="260" height="228" alt="" />
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugin_manager/skins/classic/plugin_manager.css b/plugin_manager/skins/classic/plugin_manager.css
new file mode 100644
index 0000000..efa5b43
--- /dev/null
+++ b/plugin_manager/skins/classic/plugin_manager.css
@@ -0,0 +1,178 @@
+#plugin_manager_overlay {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 4999;
+ background: rgba(0,0,0,0.5) !important;
+ background: #F6F6F6;
+ /** IE hacks */
+ filter: alpha(opacity=90);
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)";
+ width: expression(document.documentElement.clientWidth+'px');
+ height: expression(document.documentElement.clientHeight+'px');
+}
+
+#paypal{
+ position: absolute;
+ top: 65px;
+ right: 45px;
+ z-index: 9999;
+}
+
+.qtip{
+ max-width: none;
+}
+
+.asterix
+{
+ display: inline;
+ float: left;
+ margin-left: 5px;
+}
+
+.plugin_manager_ul
+{
+ list-style: none;
+ margin-top: 0px;
+}
+
+.plugin_manager_ul li
+{
+ padding-left: 0px;
+ margin-left:-40px;
+}
+
+.plugin_manager_ul input[type="checkbox"]
+{
+ margin-left: 0;
+ vertical-align: bottom;
+}
+
+.pm_control input[type="checkbox"]
+{
+ vertical-align: bottom;
+}
+
+.pm_section
+{
+ float: left;
+}
+
+.pm_update
+{
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px 15px;
+}
+
+#prefs-title-right
+{
+ color: #1f75cc;
+ font-size: 20px;
+ float: right;
+ margin-top: 7px;
+ margin-right: 25px;
+ display: inline;
+}
+
+#table
+{
+ table-layout:fixed;
+ width: 100%;
+}
+
+#table tbody tr td
+{
+ height: 20px;
+ padding: 5px;
+ font-size: 13px;
+ overflow: hidden;
+ vertical-align: middle;
+ word-wrap: break-word;
+ text-overflow: ellipsis;
+ -o-text-overflow: ellipsis;
+ border: 1px solid #EBEBEB;
+ cursor: default;
+}
+
+#table thead tr th
+{
+ height: 20px;
+ padding: 5px;
+ font-size: 13px;
+ overflow: hidden;
+ vertical-align: middle;
+ text-overflow: ellipsis;
+ -o-text-overflow: ellipsis;
+ border: 2px solid #EBEBEB;
+ cursor: default;
+}
+
+#rcheader
+{
+ font-size: 13px;
+}
+
+.vmismatch
+{
+ background-color: #EF9398;
+ border-radius: 5px 5px;
+ box-shadow: 0pt 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.vmatch
+{
+ background-color: #A6EF7B;
+ border-radius: 5px 5px;
+ box-shadow: 0pt 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.vupdate
+{
+ background-color: #EF9398;
+ border-radius: 5px 5px;
+ box-shadow: 0pt 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.rcok
+{
+ background: url(traffic-light-off.png) no-repeat;
+}
+
+.rcupdate
+{
+ background: url(traffic-light-exclamation.png) no-repeat;
+}
+
+.rcerror
+{
+ background: url(traffic-light-exclamation.png) no-repeat;
+}
+
+#table .ok
+{
+ background: url(traffic-light-off.png) center no-repeat;
+}
+
+#table .error
+{
+ background: url(traffic-light-exclamation.png) center no-repeat;
+}
+
+#table .update
+{
+ background: url(traffic-light-plus.png) center no-repeat;
+}
+
+#table .edit
+{
+ background: url(traffic-light-pencil.png) center no-repeat;
+}
+
+#table .off
+{
+ background: url(traffic-light-off.png) center no-repeat;
+} \ No newline at end of file
diff --git a/plugin_manager/skins/classic/plugin_manager_update.css b/plugin_manager/skins/classic/plugin_manager_update.css
new file mode 100644
index 0000000..346a0f3
--- /dev/null
+++ b/plugin_manager/skins/classic/plugin_manager_update.css
@@ -0,0 +1,69 @@
+.motd{
+ z-index: 9999;
+ position: absolute;
+ top: 5px;
+ margin-left: auto;
+ left: 50%;
+ margin-left: -200px;
+ width: 400px;
+ border-radius: 5px;
+ padding: 4px;
+ -moz-border-radius: 5px;
+ border: 1px solid #DEEEFC;
+ background-color: #F2F9FF;
+ text-align: justify;
+ color: #3F70BA;
+}
+
+.updatepm{
+ z-index: 9999;
+ position: absolute;
+ top: 30px;
+ margin-left: auto;
+ left: 50%;
+ margin-left: -200px;
+ width: 400px;
+ border-radius: 5px;
+ padding: 4px;
+ -moz-border-radius: 5px;
+ border: 1px solid #DEEEFC;
+ background: url(download.png) 20px 8px no-repeat #F2F9FF;
+ text-align: center;
+ color: #3F70BA;
+ cursor: pointer;
+}
+
+.updatepmrequired{
+ z-index: 9999;
+ position: absolute;
+ top: 30px;
+ margin-left: auto;
+ left: 50%;
+ margin-left: -200px;
+ width: 400px;
+ border-radius: 5px;
+ padding: 4px;
+ -moz-border-radius: 5px;
+ border: 1px solid #FEEBAB;
+ background: url(download.png) 20px 8px no-repeat #FEF8E1;
+ text-align: center;
+ color: #9E660D;
+ cursor: pointer;
+}
+
+.myrcerror{
+ z-index: 9999;
+ position: absolute;
+ top: 30px;
+ margin-left: auto;
+ left: 50%;
+ margin-left: -200px;
+ width: 400px;
+ border-radius: 5px;
+ padding: 4px;
+ -moz-border-radius: 5px;
+ background-color: #FF6B61;
+ border: 1px solid #FF0800;
+ text-align: center;
+ color: #733737;
+} \ No newline at end of file
diff --git a/plugin_manager/skins/classic/templates/config.html b/plugin_manager/skins/classic/templates/config.html
new file mode 100644
index 0000000..d2ff4ca
--- /dev/null
+++ b/plugin_manager/skins/classic/templates/config.html
@@ -0,0 +1,11 @@
+<roundcube:object name="doctype" value="html5" />
+<html>
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<roundcube:include file="/includes/links.html" />
+</head>
+<body class="iframe" style="margin: 0 0 0 0">
+<roundcube:object name="plugin.body" />
+<roundcube:include file="/includes/footer.html" />
+</body>
+</html> \ No newline at end of file
diff --git a/plugin_manager/skins/classic/templates/error.html b/plugin_manager/skins/classic/templates/error.html
new file mode 100644
index 0000000..aa12a8a
--- /dev/null
+++ b/plugin_manager/skins/classic/templates/error.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title><roundcube:object name="productname" /> :: ERROR</title>
+<roundcube:include file="/includes/links.html" />
+</head>
+<body>
+
+<div style="width:400px; margin:60px auto;">
+<roundcube:object name="plugin.body" />
+</div>
+
+</body>
+</html>
diff --git a/plugin_manager/skins/classic/templates/transfer.html b/plugin_manager/skins/classic/templates/transfer.html
new file mode 100644
index 0000000..7616cbb
--- /dev/null
+++ b/plugin_manager/skins/classic/templates/transfer.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<roundcube:include file="/includes/links.html" />
+</head>
+<body class="iframe">
+<roundcube:object name="plugin.body" />
+</body>
+</html>
diff --git a/plugin_manager/skins/classic/traffic-light-exclamation.png b/plugin_manager/skins/classic/traffic-light-exclamation.png
new file mode 100644
index 0000000..d547fab
--- /dev/null
+++ b/plugin_manager/skins/classic/traffic-light-exclamation.png
Binary files differ
diff --git a/plugin_manager/skins/classic/traffic-light-off.png b/plugin_manager/skins/classic/traffic-light-off.png
new file mode 100644
index 0000000..261565a
--- /dev/null
+++ b/plugin_manager/skins/classic/traffic-light-off.png
Binary files differ
diff --git a/plugin_manager/skins/classic/traffic-light-pencil.png b/plugin_manager/skins/classic/traffic-light-pencil.png
new file mode 100644
index 0000000..90b70ef
--- /dev/null
+++ b/plugin_manager/skins/classic/traffic-light-pencil.png
Binary files differ
diff --git a/plugin_manager/skins/classic/traffic-light-plus.png b/plugin_manager/skins/classic/traffic-light-plus.png
new file mode 100644
index 0000000..0bddb65
--- /dev/null
+++ b/plugin_manager/skins/classic/traffic-light-plus.png
Binary files differ
diff --git a/plugin_manager/skins/classic/traffic-light.png b/plugin_manager/skins/classic/traffic-light.png
new file mode 100644
index 0000000..9b458bc
--- /dev/null
+++ b/plugin_manager/skins/classic/traffic-light.png
Binary files differ
diff --git a/plugin_manager/skins/classic/watermark.gif b/plugin_manager/skins/classic/watermark.gif
new file mode 100644
index 0000000..03e3155
--- /dev/null
+++ b/plugin_manager/skins/classic/watermark.gif
Binary files differ
diff --git a/plugin_manager/skins/larry/blank.html b/plugin_manager/skins/larry/blank.html
new file mode 100644
index 0000000..f0487b2
--- /dev/null
+++ b/plugin_manager/skins/larry/blank.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title></title>
+<style type="text/css">
+
+html, body {
+ height: 95%;
+}
+
+</style>
+</head>
+<body>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugin_manager/skins/larry/download.png b/plugin_manager/skins/larry/download.png
new file mode 100644
index 0000000..2271b6d
--- /dev/null
+++ b/plugin_manager/skins/larry/download.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-bg_flat_0_aaaaaa_40x100.png b/plugin_manager/skins/larry/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644
index 0000000..9c012f6
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-bg_flat_0_aaaaaa_40x100.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-bg_flat_75_ffffff_40x100.png b/plugin_manager/skins/larry/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100644
index 0000000..a709a5d
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-bg_flat_75_ffffff_40x100.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-bg_glass_55_fbf9ee_1x400.png b/plugin_manager/skins/larry/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 0000000..ec6a7d5
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-bg_glass_55_fbf9ee_1x400.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-bg_glass_65_ffffff_1x400.png b/plugin_manager/skins/larry/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 0000000..f8de70a
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-bg_glass_75_dadada_1x400.png b/plugin_manager/skins/larry/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 0000000..3d1dfae
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-bg_glass_75_dadada_1x400.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-bg_glass_75_e6e6e6_1x400.png b/plugin_manager/skins/larry/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 0000000..548004c
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-bg_glass_75_e6e6e6_1x400.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-bg_glass_95_fef1ec_1x400.png b/plugin_manager/skins/larry/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 0000000..71dfda1
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-bg_glass_95_fef1ec_1x400.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/plugin_manager/skins/larry/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 0000000..92cbef3
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-icons_222222_256x240.png b/plugin_manager/skins/larry/images/ui-icons_222222_256x240.png
new file mode 100644
index 0000000..c1cb117
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-icons_2e83ff_256x240.png b/plugin_manager/skins/larry/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 0000000..84b601b
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-icons_2e83ff_256x240.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-icons_454545_256x240.png b/plugin_manager/skins/larry/images/ui-icons_454545_256x240.png
new file mode 100644
index 0000000..b6db1ac
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-icons_454545_256x240.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-icons_888888_256x240.png b/plugin_manager/skins/larry/images/ui-icons_888888_256x240.png
new file mode 100644
index 0000000..feea0e2
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-icons_888888_256x240.png
Binary files differ
diff --git a/plugin_manager/skins/larry/images/ui-icons_cd0a0a_256x240.png b/plugin_manager/skins/larry/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 0000000..ed5b6b0
--- /dev/null
+++ b/plugin_manager/skins/larry/images/ui-icons_cd0a0a_256x240.png
Binary files differ
diff --git a/plugin_manager/skins/larry/jqueryui.css b/plugin_manager/skins/larry/jqueryui.css
new file mode 100644
index 0000000..0e48b38
--- /dev/null
+++ b/plugin_manager/skins/larry/jqueryui.css
@@ -0,0 +1,462 @@
+/*! jQuery UI - v1.9.2 - 2013-06-15
+* http://jqueryui.com
+* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
+.ui-helper-clearfix:after { clear: both; }
+.ui-helper-clearfix { zoom: 1; }
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
+.ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; }
+.ui-accordion .ui-accordion-icons { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-noicons { padding-left: .7em; }
+.ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; }
+.ui-autocomplete {
+ position: absolute;
+ top: 0;
+ left: 0;
+ cursor: default;
+}
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; }
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; }
+button.ui-button-icons-only { width: 3.7em; }
+
+/*button text element */
+.ui-button .ui-button-text { display: block; line-height: 1.4; }
+.ui-button-text-only .ui-button-text { padding: .4em 1em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
+/* no icon support for input elements, provide padding by default */
+input.ui-button { padding: .4em 1em; }
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+
+/*button sets*/
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
+
+/* workarounds */
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 200px; /*must have*/
+ height: 200px; /*must have*/
+}.ui-dialog { position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden; }
+.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+.ui-menu { list-style:none; padding: 2px; margin: 0; display:block; outline: none; }
+.ui-menu .ui-menu { margin-top: -3px; position: absolute; }
+.ui-menu .ui-menu-item { margin: 0; padding: 0; zoom: 1; width: 100%; }
+.ui-menu .ui-menu-divider { margin: 5px -2px 5px -2px; height: 0; font-size: 0; line-height: 0; border-width: 1px 0 0 0; }
+.ui-menu .ui-menu-item a { text-decoration: none; display: block; padding: 2px .4em; line-height: 1.5; zoom: 1; font-weight: normal; }
+.ui-menu .ui-menu-item a.ui-state-focus,
+.ui-menu .ui-menu-item a.ui-state-active { font-weight: normal; margin: -1px; }
+
+.ui-menu .ui-state-disabled { font-weight: normal; margin: .4em 0 .2em; line-height: 1.5; }
+.ui-menu .ui-state-disabled a { cursor: default; }
+
+/* icon support */
+.ui-menu-icons { position: relative; }
+.ui-menu-icons .ui-menu-item a { position: relative; padding-left: 2em; }
+
+/* left-aligned */
+.ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; }
+
+/* right-aligned */
+.ui-menu .ui-menu-icon { position: static; float: right; }
+.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }.ui-spinner { position:relative; display: inline-block; overflow: hidden; padding: 0; vertical-align: middle; }
+.ui-spinner-input { border: none; background: none; padding: 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; margin-right: 22px; }
+.ui-spinner-button { width: 16px; height: 50%; font-size: .5em; padding: 0; margin: 0; text-align: center; position: absolute; cursor: default; display: block; overflow: hidden; right: 0; }
+.ui-spinner a.ui-spinner-button { border-top: none; border-bottom: none; border-right: none; } /* more specificity required here to overide default borders */
+.ui-spinner .ui-icon { position: absolute; margin-top: -8px; top: 50%; left: 0; } /* vertical centre icon */
+.ui-spinner-up { top: 0; }
+.ui-spinner-down { bottom: 0; }
+
+/* TR overrides */
+.ui-spinner .ui-icon-triangle-1-s {
+ /* need to fix icons sprite */
+ background-position:-65px -16px;
+}
+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
+.ui-tooltip {
+ padding: 8px;
+ position: absolute;
+ z-index: 9999;
+ max-width: 300px;
+ -webkit-box-shadow: 0 0 5px #aaa;
+ box-shadow: 0 0 5px #aaa;
+}
+/* Fades and background-images don't work well together in IE6, drop the image */
+* html .ui-tooltip {
+ background-image: none;
+}
+body .ui-tooltip { border-width: 2px; }
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc 50% 50% repeat-x; color: #222222; font-weight: bold; }
+.ui-widget-header a { color: #222222; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #212121; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } \ No newline at end of file
diff --git a/plugin_manager/skins/larry/manage-plugins-col.png b/plugin_manager/skins/larry/manage-plugins-col.png
new file mode 100644
index 0000000..a117439
--- /dev/null
+++ b/plugin_manager/skins/larry/manage-plugins-col.png
Binary files differ
diff --git a/plugin_manager/skins/larry/myroundcube.html b/plugin_manager/skins/larry/myroundcube.html
new file mode 100644
index 0000000..681c35a
--- /dev/null
+++ b/plugin_manager/skins/larry/myroundcube.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title></title>
+<style type="text/css">
+
+html, body {
+ height: 95%;
+}
+
+body {
+ background: url(../../../myrc_sprites/skins/larry/images/myrc_watermark.png) center no-repeat #fff;
+}
+
+</style>
+</head>
+<body>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugin_manager/skins/larry/plugin_manager.css b/plugin_manager/skins/larry/plugin_manager.css
new file mode 100644
index 0000000..bdf188c
--- /dev/null
+++ b/plugin_manager/skins/larry/plugin_manager.css
@@ -0,0 +1,208 @@
+#plugin_manager_overlay {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 4999;
+ background: rgba(0,0,0,0.5) !important;
+ background: #F6F6F6;
+ /** IE hacks */
+ filter: alpha(opacity=90);
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)";
+ width: expression(document.documentElement.clientWidth+'px');
+ height: expression(document.documentElement.clientHeight+'px');
+}
+
+legend{
+ padding-top: 15px;
+ margin-left: -2px;
+}
+
+#paypal{
+ position: absolute;
+ top: 0;
+ right: 15px;
+ z-index: 9999;
+}
+
+.qtip{
+ max-width: 350px;
+}
+
+#sections-table #rcmrowplugin_manager td.section{
+ background: url(manage-plugins-col.png) 6px 0px no-repeat;
+}
+
+#sections-table #rcmrowplugin_manager.selected td.section{
+ background: url(manage-plugins-col.png) 6px -25px no-repeat;
+}
+
+.asterix
+{
+ display: inline;
+ float: left;
+ margin-left: 5px;
+}
+
+.plugin_manager_ul
+{
+ list-style: none;
+ margin-top: 0px;
+}
+
+.plugin_manager_ul li
+{
+ padding-left: 0px;
+ margin-left:-40px;
+}
+
+.plugin_manager_ul input[type="checkbox"]
+{
+ margin-left: 0;
+ vertical-align: bottom;
+}
+
+.pm_control input[type="checkbox"]
+{
+ vertical-align: bottom;
+}
+
+.title
+{
+ color: #2c84e1;
+ padding-right: 10px;
+}
+
+.pm_section
+{
+ float: left;
+}
+
+.pm_update
+{
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px 15px;
+}
+
+table.propform td {
+ width: 1px !important;
+}
+
+table.propform td.pm_legend {
+ width: auto !important;
+ border-bottom: 0 solid #fff;
+}
+
+#prefs-title-right
+{
+ color: #1f75cc;
+ font-size: 20px;
+ float: right;
+ margin-top: 7px;
+ margin-right: 25px;
+ display: inline;
+}
+
+#table
+{
+ /*table-layout:fixed;
+ overflow: hidden;
+ white-space: nowrap;*/
+ width: 100%;
+}
+
+#table tbody tr td
+{
+ height: 20px;
+ padding: 5px;
+ font-size: 13px;
+ overflow: hidden;
+ vertical-align: middle;
+ word-wrap: break-word;
+ text-overflow: ellipsis;
+ -o-text-overflow: ellipsis;
+ border: 1px solid #EBEBEB;
+ cursor: default;
+}
+
+#table thead tr th
+{
+ height: 20px;
+ padding: 5px;
+ font-size: 13px;
+ overflow: hidden;
+ vertical-align: middle;
+ text-overflow: ellipsis;
+ -o-text-overflow: ellipsis;
+ border: 2px solid #EBEBEB;
+ cursor: default;
+}
+
+#rcheader
+{
+ font-size: 13px;
+}
+
+.vmismatch
+{
+ background-color: #EF9398;
+ border-radius: 5px 5px;
+ box-shadow: 0pt 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.vmatch
+{
+ background-color: #A6EF7B;
+ border-radius: 5px 5px;
+ box-shadow: 0pt 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.vupdate
+{
+ background-color: #EF9398;
+ border-radius: 5px 5px;
+ box-shadow: 0pt 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.rcok
+{
+ background: url(traffic-light-off.png) no-repeat;
+}
+
+.rcupdate
+{
+ background: url(traffic-light-exclamation.png) no-repeat;
+}
+
+.rcerror
+{
+ background: url(traffic-light-exclamation.png) no-repeat;
+}
+
+#table .ok
+{
+ background: url(traffic-light-off.png) center no-repeat;
+}
+
+#table .error
+{
+ background: url(traffic-light-exclamation.png) center no-repeat;
+}
+
+#table .update
+{
+ background: url(traffic-light-plus.png) center no-repeat;
+}
+
+#table .edit
+{
+ background: url(traffic-light-pencil.png) center no-repeat;
+}
+
+#table .off
+{
+ background: url(traffic-light-off.png) center no-repeat;
+} \ No newline at end of file
diff --git a/plugin_manager/skins/larry/plugin_manager_update.css b/plugin_manager/skins/larry/plugin_manager_update.css
new file mode 100644
index 0000000..65aa7a2
--- /dev/null
+++ b/plugin_manager/skins/larry/plugin_manager_update.css
@@ -0,0 +1,66 @@
+.motd{
+ z-index: 9997;
+ position: absolute;
+ top: 2px;
+ left: 50%;
+ margin-left: -200px;
+ width: 400px;
+ border-radius: 5px;
+ padding: 10px 10px 10px 10px;
+ -moz-border-radius: 5px;
+ border: 1px solid #DEEEFC;
+ background-color: #F2F9FF;
+ text-align: justify;
+ color: #3F70BA;
+}
+
+.updatepm{
+ z-index: 9998;
+ position: absolute;
+ top: 2px;
+ left: 50%;
+ margin-left: -200px;
+ width: 400px;
+ border-radius: 5px;
+ padding: 4px;
+ -moz-border-radius: 5px;
+ border: 1px solid #DEEEFC;
+ background: url(download.png) 20px 8px no-repeat #F2F9FF;
+ text-align: center;
+ color: #3F70BA;
+ cursor: pointer;
+}
+
+.updatepmrequired{
+ z-index: 9999;
+ position: absolute;
+ top: 2px;
+ left: 50%;
+ margin-left: -200px;
+ width: 400px;
+ border-radius: 5px;
+ padding: 4px;
+ -moz-border-radius: 5px;
+ border: 1px solid #FEEBAB;
+ background: url(download.png) 20px 8px no-repeat #FEF8E1;
+ text-align: center;
+ color: #9E660D;
+ cursor: pointer;
+}
+
+.myrcerror{
+ z-index: 9999;
+ position: absolute;
+ top: 2px;
+ margin-left: auto;
+ left: 50%;
+ margin-left: -200px;
+ width: 400px;
+ border-radius: 5px;
+ padding: 4px;
+ -moz-border-radius: 5px;
+ background-color: #FF6B61;
+ border: 1px solid #FF0800;
+ text-align: center;
+ color: #733737;
+} \ No newline at end of file
diff --git a/plugin_manager/skins/larry/templates/config.html b/plugin_manager/skins/larry/templates/config.html
new file mode 100644
index 0000000..d2ff4ca
--- /dev/null
+++ b/plugin_manager/skins/larry/templates/config.html
@@ -0,0 +1,11 @@
+<roundcube:object name="doctype" value="html5" />
+<html>
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<roundcube:include file="/includes/links.html" />
+</head>
+<body class="iframe" style="margin: 0 0 0 0">
+<roundcube:object name="plugin.body" />
+<roundcube:include file="/includes/footer.html" />
+</body>
+</html> \ No newline at end of file
diff --git a/plugin_manager/skins/larry/templates/error.html b/plugin_manager/skins/larry/templates/error.html
new file mode 100644
index 0000000..a577eea
--- /dev/null
+++ b/plugin_manager/skins/larry/templates/error.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<roundcube:include file="/includes/links.html" />
+</head>
+<body>
+
+<div class="uibox centerbox errorbox">
+<roundcube:object name="plugin.body" />
+</div>
+</body>
+</html>
diff --git a/plugin_manager/skins/larry/templates/transfer.html b/plugin_manager/skins/larry/templates/transfer.html
new file mode 100644
index 0000000..7616cbb
--- /dev/null
+++ b/plugin_manager/skins/larry/templates/transfer.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<roundcube:include file="/includes/links.html" />
+</head>
+<body class="iframe">
+<roundcube:object name="plugin.body" />
+</body>
+</html>
diff --git a/plugin_manager/skins/larry/traffic-light-exclamation.png b/plugin_manager/skins/larry/traffic-light-exclamation.png
new file mode 100644
index 0000000..d547fab
--- /dev/null
+++ b/plugin_manager/skins/larry/traffic-light-exclamation.png
Binary files differ
diff --git a/plugin_manager/skins/larry/traffic-light-off.png b/plugin_manager/skins/larry/traffic-light-off.png
new file mode 100644
index 0000000..261565a
--- /dev/null
+++ b/plugin_manager/skins/larry/traffic-light-off.png
Binary files differ
diff --git a/plugin_manager/skins/larry/traffic-light-pencil.png b/plugin_manager/skins/larry/traffic-light-pencil.png
new file mode 100644
index 0000000..90b70ef
--- /dev/null
+++ b/plugin_manager/skins/larry/traffic-light-pencil.png
Binary files differ
diff --git a/plugin_manager/skins/larry/traffic-light-plus.png b/plugin_manager/skins/larry/traffic-light-plus.png
new file mode 100644
index 0000000..0bddb65
--- /dev/null
+++ b/plugin_manager/skins/larry/traffic-light-plus.png
Binary files differ
diff --git a/plugin_manager/skins/larry/traffic-light.png b/plugin_manager/skins/larry/traffic-light.png
new file mode 100644
index 0000000..9b458bc
--- /dev/null
+++ b/plugin_manager/skins/larry/traffic-light.png
Binary files differ
diff --git a/settings/CHANGELOG b/settings/CHANGELOG
new file mode 100644
index 0000000..679894b
--- /dev/null
+++ b/settings/CHANGELOG
@@ -0,0 +1,11 @@
+VERSION COMMENT
+-----------------------------------------------------------------------------------------------------------------
+4.3 - It's time for a Changelog
+4.4 - Simplify plugin (remove config)
+4.4.1 - Larry CSS adjustments
+4.5 - Move Server Settings section to Account Administration section
+4.5.1 - Make plugin independent from plugin_manager plugin
+5.0 - calendar plugin adjustments
+5.0.1 - 5.0.2 - Implement myrc_sprites plugin
+5.0.3 - Removed depricated nabble code
+5.0.4 - Removed qtip plugin \ No newline at end of file
diff --git a/settings/LICENSE b/settings/LICENSE
new file mode 100644
index 0000000..11b1f5e
--- /dev/null
+++ b/settings/LICENSE
@@ -0,0 +1,84 @@
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+
+
+
+TERMS AND CONDITIONS
+--------------------
+
+User Agreement
+
+MyRoundcube Developers provides MyRoundcube Plugins (code) shall provide ("MyRoundcube Plugins") to
+you ("User") under the terms and conditions of this User Agreement ("the Agreement"). USER UNDERSTANDS
+AND ACKNOWLEDGES THAT USER IS ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers AND NOT THE WEB
+SITE WITH WHOM ANYTHING HAS ASSOCIATED TO BRING YOU THIS CODE. BY USING ("MyRoundcube Plugins") OR ANY
+PART OF ITS CODE YOU ARE AGREEING TO BECOME A PARTY TO THIS AGREEMENT WITH MyRoundcube Developers AND
+TO THE TERMS AND CONDITIONS HEREIN AND ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND ANY APPLICABLE
+ASSOCIATE STATEMENT IN THIS DOCUMENT. ALL MyRoundcube Developers SERVICES ARE PROVIDED ONLINE. PERSONS
+UNDER 13 MAY NOT BE ELEGIBLE TO ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers OR PURCHASE OUR
+SERVICES AND CODE DOWNLOADS.
+
+Acceptable Use Policy
+
+The following policy governs the use of the MyRoundcube Developers code. User will comply with the terms
+and spirit of the Agreement.
+
+(a) User shall not use MyRoundcube Plugins (code) in a manner that violates any city, state, national
+or international law or regulation, or which fails to comply with accepted Internet protocol. User
+shall not attempt to interfere in any way with MyRoundcube Plugins networks or network security, or
+attempt to use the MyRoundcube Plugins code to gain unauthorized access to any other computer system.
+(b) User shall at all times provide MyRoundcube Developers with accurate information. User shall not
+interfere in any way with another User's use of, or MyRoundcube Developers provision of the MyRoundcube
+Plugins. User shall not resell, rent, lease, grant a security interest in, or make commercial use of
+the MyRoundcube Plugins without the express written consent of MyRoundcube Developers.
+(c) User agrees not to transfer MyRoundcube Plugins (code) for gain or otherwise. Transfer of such code
+will result in termination of contract with end user.
+
+Limitation of Liability
+
+UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, TORT, CONTRACT, OR OTHERWISE, SHALL MyRoundcube
+Developers OR ITS LICENSORS OR RESELLERS BE LIABLE TO USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL,
+INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES RESULTING
+FROM THE USE OF OR THE INABILITY TO USE THE MyRoundcube Plugins (code), THE PERFORMANCE OF MyRoundcube
+Plugins (code) SERVICE, OR DAMAGES FOR LOSS OF GOODWILL, BUSINESS PROFIT, BUSINESS STOPPAGE, LOSS OF
+DATA OR BUSINESS INFORMATION, COMPUTER DAMAGE, OR DAMAGES RESULTING FROM UNAUTHORIZED ACCESS TO OR
+CHANGES MADE TO USER'S TRANSMISSIONS OR DATA, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES.
+IN NO EVENT WILL MyRoundcube Developers BE LIABLE FOR ANY DAMAGES IN EXCESS OF WHAT ANYTHING MyRoundcube
+Developers RECEIVED FROM USER FOR THE MyRoundcube Plugins (code).
+
+Terms
+
+You (the User) are permitted to use the code on unlimited servers you may own, rented or leased, as
+long as you own, rent or lease the server in which MyRoundcube plugins code is hosted.
+Exclusive: You (the User) agree to use the code in one server at a time. Multiple server deployments
+(multiserver setup), clusters or any other form of deployment that simultaneously executes MyRoundcube
+plugins in a live environment must purchase a separate download per server or installation thereof.
+
+Warranties
+
+Our code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+Terms Modifications
+
+We reserve the right to change or modify our Terms and Conditions at any time without prior notice.
+For questions, please contact our team at dev-team [at] myroundcube [dot] com.
+
+Copyright (c) 2012 - 2014
+MyRoundcube.com - A Division of Informative Computing Consultants, LLC.
+All rights reserved
+
+Informative Computing Consultants, LLC.
+21741 NW 8th CT
+Pembroke Pines
+Florida, 33029
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
diff --git a/settings/README b/settings/README
new file mode 100644
index 0000000..19c4d76
--- /dev/null
+++ b/settings/README
@@ -0,0 +1,8 @@
+settings
+--------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/
+
+
+MyRoundcube Dev Team
+www.myroundcube.com \ No newline at end of file
diff --git a/settings/config.inc.php.dist b/settings/config.inc.php.dist
new file mode 100644
index 0000000..7c36a96
--- /dev/null
+++ b/settings/config.inc.php.dist
@@ -0,0 +1,25 @@
+<?php
+
+/* settings plugin */
+
+/* limit languages:
+$config['limit_languages'] = array();
+shows all available languages!
+
+NOTICE: If you want to limit the choice of languages then
+ uncomment the following settings.
+ User's preferred language is always shown!
+*/
+$config['limit_languages'] = array("en_US", "de_DE", "fr_FR", "cs_CZ");
+
+/* limit skins:
+$config['limit_skins'] = array();
+shows all available skins!
+
+NOTICE: If you want to limit the choice of skins then
+ uncomment the following setting.
+ User's preferred skin is always shown!
+*/
+$config['limit_skins'] = array("classic", "larry");
+
+?> \ No newline at end of file
diff --git a/settings/localization/bg_BG.inc b/settings/localization/bg_BG.inc
new file mode 100644
index 0000000..17b1232
--- /dev/null
+++ b/settings/localization/bg_BG.inc
@@ -0,0 +1,26 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| language/_NEW_/labels.inc |
+| |
+| Language file of the RoundCube Webmail client |
+| Copyright (C) 2008-2009, RoundQube Dev. - Switzerland |
+| Licensed under the GNU GPL |
+| |
++-----------------------------------------------------------------------+
+| Author: |
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['menu'] = 'Меню';
+$labels['managefolders'] = 'Управление на папки';
+$labels['account'] = 'Администриране на профила';
+$labels['classic'] = 'По подразбиране';
+$labels['remotefolders'] = 'Специални папки';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Преглед на изгледа';
+
+?> \ No newline at end of file
diff --git a/settings/localization/ca_ES.inc b/settings/localization/ca_ES.inc
new file mode 100644
index 0000000..89f7956
--- /dev/null
+++ b/settings/localization/ca_ES.inc
@@ -0,0 +1,12 @@
+<?php
+
+$labels = array();
+$labels['menu'] = 'Menú';
+$labels['managefolders'] = 'Administrar carpetes';
+$labels['account'] = 'Administrar adreces';
+$labels['classic'] = 'Per defecte';
+$labels['remotefolders'] = 'Carpetes especials';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Previsualitzar tema';
+
+?> \ No newline at end of file
diff --git a/settings/localization/cs_CZ.inc b/settings/localization/cs_CZ.inc
new file mode 100644
index 0000000..c066801
--- /dev/null
+++ b/settings/localization/cs_CZ.inc
@@ -0,0 +1,27 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/cs_CZ.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: tachec - 01/20/2015 12:34:00
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Nastavení';
+$labels['plugindescription'] = 'Toto je pomocný doplněk. Je využíván několika dalšími doplňky (např. všemi hmail_* doplňky).';
+$labels['menu'] = 'Menu';
+$labels['managefolders'] = 'Správa složek';
+$labels['account'] = 'Administrace účtu';
+$labels['classic'] = 'Výchozí';
+$labels['larry'] = 'Larry';
+$labels['remotefolders'] = 'Speciální složky';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['serversettings.serversettings'] = 'Další nastavení účtu';
+$labels['serversettings.description'] = 'Další nastavení účtu';
+
+?> \ No newline at end of file
diff --git a/settings/localization/da_DK.inc b/settings/localization/da_DK.inc
new file mode 100644
index 0000000..c7a8b3e
--- /dev/null
+++ b/settings/localization/da_DK.inc
@@ -0,0 +1,15 @@
+<?php
+
+$labels=array();
+$labels['pluginname'] = 'Indstillinger';
+$labels['plugindescription'] = 'Dette er et hjælper modul. Det er krævet af flere andre moduler.';
+$labels['menu'] = 'Menu';
+$labels['managefolders'] = 'Håndter mapper';
+$labels['account'] = 'Administration af konto';
+$labels['classic'] = 'Standard';
+$labels['larry'] = 'Larry';
+$labels['remotefolders'] = 'Specielle mapper';
+$labels['myroundcube'] = 'Min RoundCube Webmail';
+$labels['skin_preview'] = 'Forhåndsvisning af brugerflade';
+
+?> \ No newline at end of file
diff --git a/settings/localization/de_CH.inc b/settings/localization/de_CH.inc
new file mode 100644
index 0000000..a480711
--- /dev/null
+++ b/settings/localization/de_CH.inc
@@ -0,0 +1,24 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/de_CH.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2012, Roland 'rosali' Liebl
+ | Licensed under the GNU GPL
+ |
+ +-----------------------------------------------------------------------+
+ | Author: myroundcube@mail4us.net - 03/21/2012 18:06:21
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['menu'] = 'Menue';
+$labels['managefolders'] = 'Ordner verwalten';
+$labels['account'] = 'Konto-Einstellungen';
+$labels['classic'] = 'Standard';
+$labels['remotefolders'] = 'Spezialordner';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Vorschau Benutzerobfläche';
+
+?> \ No newline at end of file
diff --git a/settings/localization/de_DE.inc b/settings/localization/de_DE.inc
new file mode 100644
index 0000000..c1da395
--- /dev/null
+++ b/settings/localization/de_DE.inc
@@ -0,0 +1,27 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/de_DE.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: myroundcube@mail4us.net - 01/12/2015 09:37:42
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Einstellungen';
+$labels['plugindescription'] = 'Diese Hilfserweiterung wird von einigen anderen Erweiterungen benötigt (z.B. alle hmail_* Erweiterungen).';
+$labels['menu'] = 'Menü';
+$labels['managefolders'] = 'Ordner verwalten';
+$labels['account'] = 'Konto-Einstellungen';
+$labels['classic'] = 'Standard';
+$labels['larry'] = 'Larry';
+$labels['remotefolders'] = 'Spezialordner';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['serversettings.serversettings'] = 'Weitere Kontoeinstellungen';
+$labels['serversettings.description'] = 'Weitere Kontoeinstellungen';
+
+?> \ No newline at end of file
diff --git a/settings/localization/en_GB.inc b/settings/localization/en_GB.inc
new file mode 100644
index 0000000..66be15a
--- /dev/null
+++ b/settings/localization/en_GB.inc
@@ -0,0 +1,26 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/en_GB.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2012, Roland 'rosali' Liebl
+ | Licensed under the GNU GPL
+ |
+ +-----------------------------------------------------------------------+
+ | Author: myroundcube@mail4us.net - 03/20/2012 09:35:29
+ +-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['menu'] = 'Menu';
+$labels['managefolders'] = 'Manage Folders';
+$labels['account'] = 'Account Administration';
+$labels['classic'] = 'Default';
+$labels['remotefolders'] = 'Special Folders';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Skin Preview';
+
+?> \ No newline at end of file
diff --git a/settings/localization/en_US.inc b/settings/localization/en_US.inc
new file mode 100644
index 0000000..3c6fd6d
--- /dev/null
+++ b/settings/localization/en_US.inc
@@ -0,0 +1,16 @@
+<?php
+
+$labels = array();
+$labels['pluginname'] = 'Settings';
+$labels['plugindescription'] = 'This is a helper plugin. It is required of several other plugins (f.e. all hmail_* plugins).';
+$labels['menu'] = 'Menu';
+$labels['managefolders'] = 'Manage Folders';
+$labels['account'] = 'Account Administration';
+$labels['classic'] = 'Default';
+$labels['larry'] = 'Larry';
+$labels['remotefolders'] = 'Special Folders';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['serversettings.serversettings'] = 'Other account\'s settings';
+$labels['serversettings.description'] = 'Other account\'s settings';
+
+?> \ No newline at end of file
diff --git a/settings/localization/es_ES.inc b/settings/localization/es_ES.inc
new file mode 100644
index 0000000..a57313d
--- /dev/null
+++ b/settings/localization/es_ES.inc
@@ -0,0 +1,27 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/es_ES.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 01/12/2015 10:28:29
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Configuración';
+$labels['plugindescription'] = 'Este es un complemento de ayuda. Es requerido por otros complemento (p.e. todos los complementos hmail_* ).';
+$labels['menu'] = 'Menú';
+$labels['managefolders'] = 'Administrar carpetas';
+$labels['account'] = 'Administrar cuentas';
+$labels['classic'] = 'Por defecto';
+$labels['larry'] = 'Larry';
+$labels['remotefolders'] = 'Carpetas especiales';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['serversettings.serversettings'] = 'Otras configuraciones de cuenta';
+$labels['serversettings.description'] = 'Otras configuraciones de cuenta';
+
+?> \ No newline at end of file
diff --git a/settings/localization/fi_FI.inc b/settings/localization/fi_FI.inc
new file mode 100644
index 0000000..b272f03
--- /dev/null
+++ b/settings/localization/fi_FI.inc
@@ -0,0 +1,27 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/fi_FI.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Markku Virtanen - 01/15/2015 09:52:40
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Asetukset';
+$labels['plugindescription'] = 'Tämä on helper lisäosa. Muut lisäosat käyttävät tätä lisäosaa (esim. kaikki hmail_* lisäosat).';
+$labels['menu'] = 'Valikko';
+$labels['managefolders'] = 'Hallinnoi kansioita';
+$labels['account'] = 'Tilin hallinta';
+$labels['classic'] = 'Oletus';
+$labels['larry'] = 'Larry';
+$labels['remotefolders'] = 'Erikoiskansiot';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['serversettings.serversettings'] = 'Muut tilin asetukset';
+$labels['serversettings.description'] = 'Muut tilin asetukset';
+
+?> \ No newline at end of file
diff --git a/settings/localization/fr_FR.inc b/settings/localization/fr_FR.inc
new file mode 100644
index 0000000..ec96973
--- /dev/null
+++ b/settings/localization/fr_FR.inc
@@ -0,0 +1,27 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/fr_FR.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Olivier Zolli - 01/20/2015 17:59:37
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Paramètres';
+$labels['plugindescription'] = 'Ce plugin est nécessaire pour le bon fonctionnement d\'autres plugins (par exemple tous les hmail* plugins)';
+$labels['menu'] = 'Menu';
+$labels['managefolders'] = 'Gestion des dossiers';
+$labels['account'] = 'Administration du compte';
+$labels['classic'] = 'Classic';
+$labels['larry'] = 'Larry';
+$labels['remotefolders'] = 'Dossiers spéciaux';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['serversettings.serversettings'] = 'Autres paramètres de compte';
+$labels['serversettings.description'] = 'Autres paramètres de compte';
+
+?> \ No newline at end of file
diff --git a/settings/localization/gl_ES.inc b/settings/localization/gl_ES.inc
new file mode 100644
index 0000000..a91c576
--- /dev/null
+++ b/settings/localization/gl_ES.inc
@@ -0,0 +1,12 @@
+<?php
+
+$labels = array();
+$labels['menu'] = 'Menú';
+$labels['managefolders'] = 'Xestionar os cartafoles';
+$labels['account'] = 'Xestionar as contas';
+$labels['classic'] = 'Por omisión';
+$labels['remotefolders'] = 'Cartafoles especiais';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Previsualizar tema';
+
+?> \ No newline at end of file
diff --git a/settings/localization/hu_HU.inc b/settings/localization/hu_HU.inc
new file mode 100644
index 0000000..06113ab
--- /dev/null
+++ b/settings/localization/hu_HU.inc
@@ -0,0 +1,26 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/hu_HU.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Mihaly Vukovics - 09/18/2013 13:29:57
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Beállítás';
+$labels['plugindescription'] = 'Ez egy segés beépűlő, Több egyéb beépülőmodul igényelheti';
+$labels['menu'] = 'Menü';
+$labels['managefolders'] = 'Mappák kezelése';
+$labels['account'] = 'Fiók kezelése';
+$labels['classic'] = 'Alapértelmezett';
+$labels['larry'] = 'Larry';
+$labels['remotefolders'] = 'Speciális mappák';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Téma előnézet';
+
+?> \ No newline at end of file
diff --git a/settings/localization/it_IT.inc b/settings/localization/it_IT.inc
new file mode 100644
index 0000000..7201935
--- /dev/null
+++ b/settings/localization/it_IT.inc
@@ -0,0 +1,26 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| language/it_IT/labels.inc |
+| |
+| Language file of the RoundCube Webmail client |
+| Copyright (C) 2008-2009, RoundQube Dev. - Switzerland |
+| Licensed under the GNU GPL |
+| |
++-----------------------------------------------------------------------+
+| Author: Matteo Bonora <develop@matteobonora.it> |
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['menu'] = 'Menù';
+$labels['managefolders'] = 'Gestisci Cartelle';
+$labels['account'] = 'Amministrazione Account';
+$labels['classic'] = 'Predefinito';
+$labels['remotefolders'] = 'Cartelle Speciali';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Anteprima Skin';
+
+?> \ No newline at end of file
diff --git a/settings/localization/nl_NL.inc b/settings/localization/nl_NL.inc
new file mode 100644
index 0000000..793a4dc
--- /dev/null
+++ b/settings/localization/nl_NL.inc
@@ -0,0 +1,27 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/nl_NL.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2012, Roland 'rosali' Liebl
+ | Licensed under the GNU GPL
+ |
+ +-----------------------------------------------------------------------+
+ | Author: HiJack! - 10/22/2012 20:03:26
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['menu'] = 'Menu';
+$labels['managefolders'] = 'Mappen beheren';
+$labels['account'] = 'Accountbeheer';
+$labels['classic'] = 'Standaard';
+$labels['remotefolders'] = 'Speciale mappen';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Themavoorbeeld';
+$labels['larry'] = 'Larry';
+$labels['pluginname'] = 'Instellingen';
+$labels['plugindescription'] = 'Dit is een ondersteunende plugin die vereist wordt door diverse andere plugins (o.a. alle hmail_* plugins).';
+
+?> \ No newline at end of file
diff --git a/settings/localization/pl_PL.inc b/settings/localization/pl_PL.inc
new file mode 100644
index 0000000..6dcc058
--- /dev/null
+++ b/settings/localization/pl_PL.inc
@@ -0,0 +1,29 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| language/pl_PL/labels.inc |
+| |
+| Language file of the RoundCube Webmail client |
+| Copyright (C) 2008-2009, RoundQube Dev. - Switzerland |
+| Licensed under the GNU GPL |
+| |
++-----------------------------------------------------------------------+
+| Author: |
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Ustawienia';
+$labels['plugindescription'] = 'To jest wtyczka pomocnicza. Jest wymagana przez inne wtyczki (np : hmail_xxx)';
+$labels['menu'] = 'Menu';
+$labels['managefolders'] = 'Zarządzanie folderami';
+$labels['account'] = 'Administracja kontem';
+$labels['classic'] = 'Domyślnie';
+$labels['remotefolders'] = 'Foldery specjalne';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Podgląd Skórki';
+$labels['larry'] = 'Larry';
+
+?> \ No newline at end of file
diff --git a/settings/localization/pt_BR.inc b/settings/localization/pt_BR.inc
new file mode 100644
index 0000000..fba065c
--- /dev/null
+++ b/settings/localization/pt_BR.inc
@@ -0,0 +1,25 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/pt_BR.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2012, Roland 'rosali' Liebl
+ | Licensed under the GNU GPL
+ |
+ +-----------------------------------------------------------------------+
+ | Author: filhocf - 08/24/2012 16:38:59
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['menu'] = 'Menu';
+$labels['managefolders'] = 'Gerenciar pastas';
+$labels['account'] = 'Administração da Conta';
+$labels['classic'] = 'Padrão';
+$labels['remotefolders'] = 'Pastas Especiais';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Visualizar Tema';
+$labels['larry'] = 'Larry';
+
+?> \ No newline at end of file
diff --git a/settings/localization/pt_PT.inc b/settings/localization/pt_PT.inc
new file mode 100644
index 0000000..8534bee
--- /dev/null
+++ b/settings/localization/pt_PT.inc
@@ -0,0 +1,26 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/pt_PT.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2012, Roland 'rosali' Liebl
+ | Licensed under the GNU GPL
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Ling Fude - 03/19/2012 15:19:25
+ +-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['menu'] = 'Menu';
+$labels['managefolders'] = 'Gerir pastas';
+$labels['account'] = 'Administração da conta';
+$labels['classic'] = 'Predefinido';
+$labels['remotefolders'] = 'Pastas especiais';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Pré-visualização da Skin';
+
+?> \ No newline at end of file
diff --git a/settings/localization/revision.inc.php b/settings/localization/revision.inc.php
new file mode 100644
index 0000000..76a34d7
--- /dev/null
+++ b/settings/localization/revision.inc.php
@@ -0,0 +1,11 @@
+<?php
+
+$ps_localization_update = serialize(
+ array(
+ 'translator' => 'Olivier Zolli',
+ 'language ' => 'fr_FR',
+ 'date' => '01/20/2015 17:59:37'
+ )
+);
+
+?> \ No newline at end of file
diff --git a/settings/localization/ru_RU.inc b/settings/localization/ru_RU.inc
new file mode 100644
index 0000000..fecaf85
--- /dev/null
+++ b/settings/localization/ru_RU.inc
@@ -0,0 +1,26 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/settings/localization/ru_RU.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2013, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Pavel - 01/26/2013 15:03:49
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Настройки';
+$labels['plugindescription'] = 'Это плагин подсказки. Он требует наличия некоторых других плагинов';
+$labels['menu'] = 'Меню';
+$labels['managefolders'] = 'Управление папками';
+$labels['account'] = 'Управление аккаунтом';
+$labels['classic'] = 'Настройки по умолчанию';
+$labels['remotefolders'] = 'Особые папки';
+$labels['myroundcube'] = 'Мой Roundcube';
+$labels['skin_preview'] = 'Предпросмотр Скина';
+$labels['larry'] = 'Ларри';
+
+?> \ No newline at end of file
diff --git a/settings/localization/sk_SK.inc b/settings/localization/sk_SK.inc
new file mode 100644
index 0000000..fbe6bc2
--- /dev/null
+++ b/settings/localization/sk_SK.inc
@@ -0,0 +1,28 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| language/sk_SK/labels.inc |
+| |
+| Language file of the RoundCube Webmail client |
+| Copyright (C) 2008-2012, RoundQube Dev. - Switzerland |
+| |
++-----------------------------------------------------------------------+
+| Author: |
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['pluginname'] = 'Nastavenia';
+$labels['plugindescription'] = 'Toto je pomocný plugin. Je požadovaný viacerými inými pluginmi (napr. všetky hmail_* pluginy).)';
+$labels['menu'] = 'Ponuka';
+$labels['managefolders'] = 'Spravuj priecinky';
+$labels['account'] = 'Administrácia úctu';
+$labels['classic'] = 'Predvolené';
+$labels['remotefolders'] = 'Špeciálne adresáre';
+$labels['myroundcube'] = 'MyRoundCube';
+$labels['skin_preview'] = 'Náhlad vzhladu';
+$labels['larry'] = 'Larry';
+
+?> \ No newline at end of file
diff --git a/settings/localization/sv_SE.inc b/settings/localization/sv_SE.inc
new file mode 100644
index 0000000..3e7fcda
--- /dev/null
+++ b/settings/localization/sv_SE.inc
@@ -0,0 +1,11 @@
+<?php
+
+$labels = array();
+$labels['menu'] = 'Meny';
+$labels['managefolders'] = 'Hantera mappar';
+$labels['account'] = 'Konto administration';
+$labels['classic'] = 'Standard';
+$labels['remotefolders'] = 'Speciella mappar';
+$labels['myroundcube'] = 'MinRoundCube';
+
+?> \ No newline at end of file
diff --git a/settings/localization/zh_CN.inc b/settings/localization/zh_CN.inc
new file mode 100644
index 0000000..aed911a
--- /dev/null
+++ b/settings/localization/zh_CN.inc
@@ -0,0 +1,10 @@
+<?php
+
+$labels = array();
+$labels['menu'] = '菜单';
+$labels['managefolders'] = '管理文件夹';
+$labels['account'] = '用户管理';
+$labels['classic'] = '默认';
+$labels['remotefolders'] = '特定文件夹';
+
+?> \ No newline at end of file
diff --git a/settings/localization/zh_TW.inc b/settings/localization/zh_TW.inc
new file mode 100644
index 0000000..7e6f345
--- /dev/null
+++ b/settings/localization/zh_TW.inc
@@ -0,0 +1,11 @@
+<?php
+
+$labels = array();
+$labels['menu'] = '菜單';
+$labels['managefolders'] = '管理文件夾';
+$labels['account'] = '用戶管理';
+$labels['classic'] = '默認';
+$labels['remotefolders'] = '特定文件夾';
+$labels['myroundcube'] = '我的RoundCube';
+
+?> \ No newline at end of file
diff --git a/settings/settings.js b/settings/settings.js
new file mode 100644
index 0000000..8aba9c9
--- /dev/null
+++ b/settings/settings.js
@@ -0,0 +1,27 @@
+$(document).ready(function(){
+ if(rcmail.env.skin == 'larry'){
+ if($('.minmodetoggle').get(0)){
+ var minmode = rcmail.get_cookie('minimalmode');
+ if(parseInt(minmode) || (minmode === null && $(window).height() < 850)){
+ $('#mainscreen').css('top', '55px');
+ }
+ $(window).resize(function(){
+ var minmode = rcmail.get_cookie('minimalmode');
+ if(parseInt(minmode) || (minmode === null && $(window).height() < 850)){
+ $('#mainscreen').css('top', '55px');
+ }
+ else{
+ $('#mainscreen').css('top', '132px');
+ }
+ });
+ }
+ }
+ if(parent.location.href != document.location.href){
+ if(rcmail.env.skin == 'larry'){
+ $('.formbuttons').hide();
+ }
+ else{
+ $('#formfooter').hide();
+ }
+ }
+}); \ No newline at end of file
diff --git a/settings/settings.php b/settings/settings.php
new file mode 100644
index 0000000..1452305
--- /dev/null
+++ b/settings/settings.php
@@ -0,0 +1,282 @@
+<?php
+#
+# This file is part of MyRoundcube "settings" plugin.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (C) 2011, Lazlo Westerhof
+# Lazlo Westerhof <roundcube@lazlo.me>
+# Copyright (C) 2014 Roland 'Rosali' Liebl
+# dev-team [at] myroundcube [dot] com
+# http://myroundcube.com
+#
+class settings extends rcube_plugin
+{
+ public $task = 'settings';
+ public $noajax = true;
+
+ private $sections = array('general', 'mailbox', 'compose', 'mailview', 'addressbook', 'folders', 'server');
+
+ /* unified plugin properties */
+ static private $plugin = 'settings';
+ static private $author = 'myroundcube@mail4us.net';
+ static private $authors_comments = '<a href="http://myroundcube.com/myroundcube-plugins/helper-plugin?settings" target="_blank">Documentation</a>';
+ static private $version = '5.0.4';
+ static private $date = '27-12-2014';
+ static private $licence = 'All Rights reserved';
+ static private $requirements = array(
+ 'Roundcube' => '1.0',
+ 'PHP' => '5.3',
+ 'required_plugins' => array('myrc_sprites' => 'require_plugin'),
+ );
+ static private $prefs = null;
+
+ function init(){
+ $rcmail = rcmail::get_instance();
+
+ $this->require_plugin('myrc_sprites');
+
+ $this->register_handler('plugin.account_sections', array($this, 'account_sections'));
+ $this->add_hook('preferences_sections_list', array($this, 'account_link'));
+ $this->add_hook('preferences_list', array($this, 'prefs_table'));
+ $this->add_hook('render_page', array($this, 'render_page'));
+
+ $skin = $rcmail->config->get('skin');
+ $this->include_stylesheet('skins/' . $skin . '/settings.css');
+
+ $this->add_texts('localization/');
+ $rcmail->output->add_label('settings.account');
+ }
+
+ static public function about($keys = false){
+ $requirements = self::$requirements;
+ foreach(array('required_', 'recommended_') as $prefix){
+ if(is_array($requirements[$prefix.'plugins'])){
+ foreach($requirements[$prefix.'plugins'] as $plugin => $method){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $class->about($keys),
+ );
+ }
+ else{
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $plugin,
+ );
+ }
+ }
+ }
+ }
+
+ return array(
+ 'plugin' => self::$plugin,
+ 'version' => self::$version,
+ 'date' => self::$date,
+ 'author' => self::$author,
+ 'comments' => self::$authors_comments,
+ 'licence' => self::$licence,
+ 'requirements' => $requirements,
+ );
+ }
+
+ function render_page($p){
+ if($p['template'] == 'settings'){
+ $rcmail = rcmail::get_instance();
+ $rcmail->output->add_script('$("#rcmrowserver").remove();', 'docready');
+ if(get_input_value('_accountsettings', RCUBE_INPUT_GET)){
+ $rcmail->output->add_script('$("#rcmrowaccountlink").trigger("mousedown").trigger("mouseup");', 'docready');
+ }
+ }
+ if($p['template'] == 'settingsedit' && get_input_value('_section', RCUBE_INPUT_GPC) == 'server'){
+ $rcmail = rcmail::get_instance();
+ $rcmail->output->add_script('$(".boxtitle").html("<a id=\'accountlink\' href=\'./?_task=settings&_action=edit-prefs&_section=accountlink&_framed=1\'>" + rcmail.gettext("settings.account") + "</a>&nbsp;&raquo;&nbsp;" + $(".boxtitle").html());', 'docready');
+ }
+ return $p;
+ }
+
+ function account_link($args){
+ $rcmail = rcmail::get_instance();
+ $skin = $rcmail->config->get('skin');
+ $temparr = array();
+ foreach($this->sections as $key => $section){
+ $temparr[$section] = $args['list'][$section];
+ unset($args['list'][$section]);
+ }
+ $args['list']['general'] = $temparr['general'];
+ $args['list']['mailbox'] = $temparr['mailbox'];
+ $args['list']['compose'] = $temparr['compose'];
+ $args['list']['mailview'] = $temparr['mailview'];
+ $args['list']['mh_preferences'] = array();
+ $args['list']['keyboard_shortcuts'] = array();
+ $args['list']['identitieslink'] = array();
+ $args['list']['addressbook'] = $temparr['addressbook'];
+ $args['list']['addressbookcarddavs'] = array();
+ $args['list']['addressbooksharing'] = array();
+ $args['list']['jabber'] = array();
+ $args['list']['folderslink'] = array();
+ $args['list']['folders'] = $temparr['folders'];
+ if($skin == 'classic'){
+ $args['list']['folders']['section'] = $args['list']['folders']['section'];
+ }
+ $args['list']['calendar'] = array();
+ $args['list']['calendarsharing'] = array();
+ $args['list']['plugin_manager'] = array();
+ $args['list']['plugin_manager_settings'] = array();
+ $args['list']['plugin_manager_admins'] = array();
+ $args['list']['plugin_manager_customer'] = array();
+ $args['list']['plugin_manager_update'] = array();
+ $args['list']['accountslink'] = array();
+ $args['list']['server'] = $temparr['server'];
+
+ $parts = (array) $GLOBALS['settingsnav'];
+ $temp = array();
+ foreach($parts as $plugin => $props){
+ if(class_exists($plugin)){
+ $temp[$this->gettext($plugin . '.' . $props['label'])][$plugin] = $props;
+ }
+ else{
+ unset($GLOBALS['settingsnav'][$plugin]);
+ }
+ }
+ ksort($temp);
+ $parts = $temp;
+ $GLOBALS['settingsnav'] = array();
+ foreach($parts as $label => $props){
+ foreach($props as $plugin => $settings){
+ if(class_exists($plugin)){
+ $GLOBALS['settingsnav'][$plugin] = $settings;
+ }
+ }
+ }
+ $parts = (array) $rcmail->config->get('settingsnav', $GLOBALS['settingsnav']);
+ foreach($parts as $plugin => $props){
+ if(!class_exists($plugin)){
+ unset($parts[$plugin]);
+ }
+ }
+ if($defaults = $_SESSION['plugin_manager_defaults']){
+ $active = $rcmail->config->get('plugin_manager_active', array());
+ if(is_array($defaults)){
+ foreach($defaults as $section => $plugins){
+ foreach($plugins as $plugin => $props){
+ if($props['active']){
+ $active[$plugin] = 1;
+ }
+ }
+ }
+ }
+ foreach($parts as $plugin => $props){
+ if($active[$plugin] != 1){
+ unset($parts[$plugin]);
+ }
+ }
+ }
+ if(class_exists('mysqladmin') && strtolower($rcmail->user->data['username']) == $rcmail->config->get('mysql_admin')){
+ $hm = array('autoban', 'autoresponder', 'forwarding', 'login', 'accounts', 'signature', 'spamfilter');
+ $detected = false;
+ foreach($hm as $dsn){
+ $c = $rcmail->config->get('db_hmail_' . $dsn . '_dsn');
+ if(is_string($c)){
+ $t = parse_url($c);
+ if($t['user'] && $t['pass']){
+ $parts = array_merge($parts, array( 'mysqladmin' =>
+ array('part' => '', 'label' => 'pluginname', 'href' => './?_action=plugin.mysqladmin&pma_login=1&db=db_hmail_' . $dsn . '_dsn', 'onclick' => 'rcmail.set_cookie("PMA_referrer", document.location.href);', 'descr' => 'mysqladmin')
+ )
+ );
+ $detected = true;
+ break;
+ }
+ }
+ }
+ }
+ if(!$detected){
+ $parts = array_merge($parts, array( 'mysqladmin' =>
+ array('part' => '', 'label' => 'pluginname', 'href' => './?_action=plugin.mysqladmin&pma_login=1&db=db_dsnw&dbt=users', 'onclick' => 'rcmail.set_cookie("PMA_referrer", document.location.href);', 'descr' => 'mysqladmin')
+ )
+ );
+ }
+ $parts = array_merge($parts, array( 'settings' =>
+ array('part' => '', 'label' => 'serversettings', 'href' => './?_task=settings&_action=edit-prefs&_section=server&_framed=1', 'descr' => 'serversettings')
+ )
+ );
+ if(count($parts) > 0){
+ $_SESSION['settingsnav'] = $parts;
+ $args['list']['accountlink']['id'] = 'accountlink';
+ $args['list']['accountlink']['section'] = $this->gettext('account');
+ if(strtolower($rcmail->user->data['username']) != strtolower($_SESSION['username'])){
+ unset($args['list']['accountlink']);
+ }
+ }
+ return $args;
+ }
+
+ function account_sections(){
+ $rcmail = rcmail::get_instance();
+
+ //display a message if required by url
+ if(isset($_GET['_msg'])){
+ $rcmail->output->command('display_message', urldecode($_GET['_msg']), $_GET['_type']);
+ }
+ $parts = (array) $_SESSION['settingsnav'];
+ $out = "<div id=\"userprefs-accountblocks\">\n";
+ foreach($parts as $key => $part){
+ if(!class_exists($key)){
+ continue;
+ }
+ if(!empty($part['descr'])){
+ $i++;
+ $out .= "<div class=\"userprefs-accountblock\" id='accountsblock_$i'>\n";
+ $out .= "<div class=\"userprefs-accountblock-border\">\n";
+ $out .= "&raquo;&nbsp;<a class=\"plugin-description-link\" href=\"" . $part['href'] . "\" onclick='" . $part['onclick'] . "'>" . $this->gettext($part['descr'] . '.' . $part['label']) . "</a>\n";
+ $out .= "</div>\n";
+ $out .= "</div>\n";
+ $out .= '
+<script>
+var element = $("#accountsblock_' . $i . '");
+element.qtip({
+ content: {title:\'' . addslashes($this->gettext($part['descr'] . '.' . $part['label'])) . '\', text: \'' . addslashes($this->gettext($part['descr'] . '.description')) . '\'},
+ position: {
+ my: "top left",
+ at: "left bottom",
+ target: element,
+ viewport: $(window)
+ },
+ hide: {
+ effect: function () { $(this).slideUp(5, function(){ $(this).dequeue(); }); }
+ },
+ style: {
+ classes: "ui-tooltip-light"
+ }
+});
+</script>
+';
+ }
+ }
+
+ $out .= "</div>\n<style>fieldset{border: none;}</style>\n";
+ return $out;
+ }
+
+ function prefs_table($args){
+ if(!get_input_value('_framed', RCUBE_INPUT_GPC) && $args['section'] == 'accountlink'){
+ $args['blocks'][$args['section']]['options'] = array(
+ 'title' => '',
+ 'content' => html::tag('div', array('id' => 'pm_dummy'), '')
+ );
+ return $args;
+ }
+ if ($args['section'] == 'accountlink') {
+ $args['blocks']['main']['options']['accountlink']['title'] = "";
+ $args['blocks']['main']['options']['accountlink']['content'] = $this->account_sections("");
+ $this->include_script('settings.js');
+ }
+ return $args;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/settings/skins/classic/settings.css b/settings/skins/classic/settings.css
new file mode 100644
index 0000000..c1bac41
--- /dev/null
+++ b/settings/skins/classic/settings.css
@@ -0,0 +1,52 @@
+#prefs-details
+{
+ /*margin-top: -20px;*/
+ left: 220px;
+}
+
+#prefs-details div.userprefs-accountblock
+{
+ /*float: left;*/
+ margin-right: 14px;
+ min-width: 450px;
+ padding: 5px 0px 0px 0px;
+ width: 100%;
+}
+
+#prefs-details div.userprefs-accountblock-border
+{
+ background-color: #EBEBEB;
+ border: 1px solid #999999;
+}
+
+.settingsplugin
+{
+ margin-top: 15px;
+}
+
+a.plugin-description-link:active, a.plugin-description-link:visited, a.plugin-description-link:link
+{
+ font-size: 13px;
+ font-weight: normal;
+ color: #999999;
+ text-decoration: none;
+ font-style: italic;
+}
+
+a.plugin-description-link:hover, a.plugin-description-link:focus
+{
+ font-weight: bold;
+}
+
+#prefs-details div.plugin-description-text
+{
+ padding: 2px 5px 5px 2px;
+ text-align: justify;
+ font-size: 11px;
+ font-weight: normal;
+ color: #666666;
+ background-color: #F9F9F9;
+ /*word-wrap: break-word;*/
+ width: 450px;
+ white-space: normal;
+} \ No newline at end of file
diff --git a/settings/skins/larry/images/account-admin-col.png b/settings/skins/larry/images/account-admin-col.png
new file mode 100644
index 0000000..17cddb4
--- /dev/null
+++ b/settings/skins/larry/images/account-admin-col.png
Binary files differ
diff --git a/settings/skins/larry/settings.css b/settings/skins/larry/settings.css
new file mode 100644
index 0000000..90d0887
--- /dev/null
+++ b/settings/skins/larry/settings.css
@@ -0,0 +1,65 @@
+#sections-table #rcmrowaccountlink td.section{
+ background-position: -8px -1036px;
+}
+
+#sections-table #rcmrowaccountlink.selected td.section{
+ background-position: -8px -1068px;
+}
+
+#accountlink
+{
+ font-size: 12px;
+}
+
+#prefs-details
+{
+ /*margin-top: -20px;*/
+ left: 220px;
+}
+
+#userprefs-accountblocks
+{
+ position: absolute;
+ left: 10px;
+ right: 10px;
+ margin-top: -25px;
+ background: #dfdfdf;
+ padding: 10px 10px 10px 10px;
+ border-radius: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+}
+
+.settingsplugin
+{
+ margin-top: 15px;
+}
+
+a.plugin-description-link:active, a.plugin-description-link:visited, a.plugin-description-link:link
+{
+ font-size: 13px;
+ font-weight: normal;
+ color: #376572;
+ text-shadow: 0px 1px 1px white;
+ text-decoration: none;
+ font-style: normal;
+}
+
+a.plugin-description-link:hover, a.plugin-description-link:focus
+{
+ /*font-weight: bold;*/
+ color: #999999;
+}
+
+#prefs-details div.plugin-description-text
+{
+ padding: 2px 5px 5px 2px;
+ text-align: justify;
+ font-size: 11px;
+ font-weight: normal;
+ color: #666666;
+ background-color: #F9F9F9;
+ /*word-wrap: break-word;*/
+ width: 450px;
+ white-space: normal;
+} \ No newline at end of file
diff --git a/show_pgp_mime b/show_pgp_mime
new file mode 160000
+Subproject 0909fcff77a81beb66395bb17a2de659e6fc442