aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2010-06-08 09:01:43 +0200
committerAlexander Sulfrian <alexander@sulfrian.net>2010-06-08 09:01:43 +0200
commitd1fa08fdc9cb11dccee76d668ff85df30458c295 (patch)
tree1d19df6405103577d872902486792e8c23bce711
parentd7c5ad7d6263fd1baf9bfdbaa4c50b70ef2fbdb2 (diff)
parent70d1f9d6fcaefe611e778b8dbf3bafea8934aa08 (diff)
downloadetherpad-d1fa08fdc9cb11dccee76d668ff85df30458c295.tar.gz
etherpad-d1fa08fdc9cb11dccee76d668ff85df30458c295.tar.xz
etherpad-d1fa08fdc9cb11dccee76d668ff85df30458c295.zip
Merge remote branch 'upstream/master'
Conflicts: etherpad/src/etherpad/control/pro/admin/pro_admin_control.js etherpad/src/etherpad/control/pro/pro_main_control.js etherpad/src/etherpad/control/pro_help_control.js etherpad/src/etherpad/globals.js etherpad/src/etherpad/legacy_urls.js etherpad/src/etherpad/pne/pne_utils.js etherpad/src/etherpad/pro/pro_utils.js etherpad/src/main.js etherpad/src/plugins/fileUpload/templates/fileUpload.ejs etherpad/src/plugins/testplugin/templates/page.ejs etherpad/src/static/css/pad2_ejs.css etherpad/src/static/css/pro-help.css etherpad/src/static/img/jun09/pad/protop.gif etherpad/src/static/js/store.js etherpad/src/themes/default/templates/framed/framedheader-pro.ejs etherpad/src/themes/default/templates/main/home.ejs etherpad/src/themes/default/templates/pro-help/main.ejs etherpad/src/themes/default/templates/pro-help/pro-help-template.ejs infrastructure/com.etherpad/licensing.scala trunk/etherpad/src/etherpad/collab/ace/contentcollector.js trunk/etherpad/src/etherpad/collab/ace/linestylefilter.js trunk/etherpad/src/static/css/home-opensource.css trunk/etherpad/src/static/js/ace.js trunk/etherpad/src/static/js/linestylefilter_client.js trunk/etherpad/src/templates/email/eepnet_license_info.ejs trunk/etherpad/src/templates/pad/pad_body2.ejs trunk/etherpad/src/templates/pad/pad_content.ejs trunk/etherpad/src/templates/pad/padfull_body.ejs trunk/etherpad/src/templates/pro/admin/pne-license-manager.ejs
-rw-r--r--.gitignore26
-rw-r--r--COPYING (renamed from trunk/COPYING)0
-rw-r--r--INSTALL31
-rw-r--r--LICENSE284
-rw-r--r--README.hooks24
-rw-r--r--README.md6
-rwxr-xr-xbin/build.sh40
-rwxr-xr-xbin/run.sh15
-rw-r--r--branches/test.txt1
-rw-r--r--debian/README6
-rw-r--r--debian/changelog17
-rw-r--r--debian/compat1
-rw-r--r--debian/config49
-rw-r--r--debian/control21
-rw-r--r--debian/copyright52
-rwxr-xr-xdebian/etherpad.init186
-rw-r--r--debian/po/POTFILES.in1
-rw-r--r--debian/po/fi.po76
-rw-r--r--debian/po/templates.pot58
-rwxr-xr-xdebian/postinst84
-rw-r--r--debian/postrm41
-rw-r--r--debian/preinst37
-rwxr-xr-xdebian/prerm45
-rwxr-xr-xdebian/rules112
-rw-r--r--debian/source/format1
-rw-r--r--debian/source/lintian-overrides8
-rw-r--r--debian/templates20
-rw-r--r--etherpad/.gitignore (renamed from trunk/etherpad/.gitignore)0
-rw-r--r--etherpad/bin/.gitignore (renamed from trunk/etherpad/bin/.gitignore)0
-rw-r--r--etherpad/bin/etherpad.default47
-rwxr-xr-xetherpad/bin/java-version.sh72
-rwxr-xr-xetherpad/bin/rebuildjar.sh161
-rwxr-xr-xetherpad/bin/run-local.sh65
-rwxr-xr-xetherpad/bin/setup-mysql-db.sh25
-rw-r--r--etherpad/etc/etherpad.local.properties.tmpl23
-rw-r--r--etherpad/etc/etherpad.localdev-default.properties23
-rw-r--r--etherpad/lib/dnsjava-2.0.6.jar (renamed from trunk/etherpad/lib/dnsjava-2.0.6.jar)bin268823 -> 268823 bytes
-rw-r--r--etherpad/lib/jbcrypt-0.3.jarbin0 -> 15505 bytes
-rw-r--r--etherpad/lib/jcommon-1.0.15.jar (renamed from trunk/etherpad/lib/jcommon-1.0.15.jar)bin309294 -> 309294 bytes
-rw-r--r--etherpad/lib/jfreechart-1.0.12.jar (renamed from trunk/etherpad/lib/jfreechart-1.0.12.jar)bin1368681 -> 1368681 bytes
-rw-r--r--etherpad/src/etherpad/admin/plugins.js247
-rw-r--r--etherpad/src/etherpad/admin/shell.js (renamed from trunk/etherpad/src/etherpad/admin/shell.js)0
-rw-r--r--etherpad/src/etherpad/billing/billing.js (renamed from trunk/etherpad/src/etherpad/billing/billing.js)0
-rw-r--r--etherpad/src/etherpad/billing/fields.js (renamed from trunk/etherpad/src/etherpad/billing/fields.js)0
-rw-r--r--etherpad/src/etherpad/billing/team_billing.js (renamed from trunk/etherpad/src/etherpad/billing/team_billing.js)0
-rw-r--r--etherpad/src/etherpad/collab/collab_server.js (renamed from trunk/etherpad/src/etherpad/collab/collab_server.js)0
-rw-r--r--etherpad/src/etherpad/collab/collabroom_server.js (renamed from trunk/etherpad/src/etherpad/collab/collabroom_server.js)0
-rw-r--r--etherpad/src/etherpad/collab/genimg.js (renamed from trunk/etherpad/src/etherpad/collab/genimg.js)0
-rw-r--r--etherpad/src/etherpad/collab/json_sans_eval.js (renamed from trunk/etherpad/src/etherpad/collab/json_sans_eval.js)0
-rw-r--r--etherpad/src/etherpad/collab/readonly_server.js (renamed from trunk/etherpad/src/etherpad/collab/readonly_server.js)0
-rw-r--r--etherpad/src/etherpad/collab/server_utils.js (renamed from trunk/etherpad/src/etherpad/collab/server_utils.js)0
-rw-r--r--etherpad/src/etherpad/control/aboutcontrol.js (renamed from trunk/etherpad/src/etherpad/control/aboutcontrol.js)0
-rw-r--r--etherpad/src/etherpad/control/admin/pluginmanager.js71
-rw-r--r--etherpad/src/etherpad/control/admincontrol.js1482
-rw-r--r--etherpad/src/etherpad/control/blogcontrol.js (renamed from trunk/etherpad/src/etherpad/control/blogcontrol.js)0
-rw-r--r--etherpad/src/etherpad/control/connection_diagnostics_control.js (renamed from trunk/etherpad/src/etherpad/control/connection_diagnostics_control.js)0
-rw-r--r--etherpad/src/etherpad/control/global_pro_account_control.js (renamed from trunk/etherpad/src/etherpad/control/global_pro_account_control.js)0
-rw-r--r--etherpad/src/etherpad/control/historycontrol.js (renamed from trunk/etherpad/src/etherpad/control/historycontrol.js)0
-rw-r--r--etherpad/src/etherpad/control/loadtestcontrol.js (renamed from trunk/etherpad/src/etherpad/control/loadtestcontrol.js)0
-rw-r--r--etherpad/src/etherpad/control/maincontrol.js (renamed from trunk/etherpad/src/etherpad/control/maincontrol.js)0
-rw-r--r--etherpad/src/etherpad/control/pad/pad_changeset_control.js (renamed from trunk/etherpad/src/etherpad/control/pad/pad_changeset_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pad/pad_control.js754
-rw-r--r--etherpad/src/etherpad/control/pad/pad_importexport_control.js (renamed from trunk/etherpad/src/etherpad/control/pad/pad_importexport_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pad/pad_view_control.js (renamed from trunk/etherpad/src/etherpad/control/pad/pad_view_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pne_manual_control.js (renamed from trunk/etherpad/src/etherpad/control/pne_manual_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pne_tracker_control.js (renamed from trunk/etherpad/src/etherpad/control/pne_tracker_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pro/account_control.js (renamed from trunk/etherpad/src/etherpad/control/pro/account_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pro/admin/account_manager_control.js (renamed from trunk/etherpad/src/etherpad/control/pro/admin/account_manager_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pro/admin/license_manager_control.js (renamed from trunk/etherpad/src/etherpad/control/pro/admin/license_manager_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pro/admin/pro_admin_control.js280
-rw-r--r--etherpad/src/etherpad/control/pro/admin/pro_config_control.js (renamed from trunk/etherpad/src/etherpad/control/pro/admin/pro_config_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pro/admin/team_billing_control.js (renamed from trunk/etherpad/src/etherpad/control/pro/admin/team_billing_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pro/pro_main_control.js (renamed from trunk/etherpad/src/etherpad/control/pro/pro_main_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pro/pro_padlist_control.js (renamed from trunk/etherpad/src/etherpad/control/pro/pro_padlist_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pro_beta_control.js (renamed from trunk/etherpad/src/etherpad/control/pro_beta_control.js)0
-rw-r--r--etherpad/src/etherpad/control/pro_signup_control.js (renamed from trunk/etherpad/src/etherpad/control/pro_signup_control.js)0
-rw-r--r--etherpad/src/etherpad/control/scriptcontrol.js (renamed from trunk/etherpad/src/etherpad/control/scriptcontrol.js)0
-rw-r--r--etherpad/src/etherpad/control/static_control.js76
-rw-r--r--etherpad/src/etherpad/control/statscontrol.js (renamed from trunk/etherpad/src/etherpad/control/statscontrol.js)0
-rw-r--r--etherpad/src/etherpad/control/store/eepnet_checkout_control.js (renamed from trunk/etherpad/src/etherpad/control/store/eepnet_checkout_control.js)0
-rw-r--r--etherpad/src/etherpad/control/store/storecontrol.js (renamed from trunk/etherpad/src/etherpad/control/store/storecontrol.js)0
-rw-r--r--etherpad/src/etherpad/control/testcontrol.js (renamed from trunk/etherpad/src/etherpad/control/testcontrol.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0000_test.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0000_test.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0001_eepnet_signups_init.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0001_eepnet_signups_init.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0002_eepnet_signups_2.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0002_eepnet_signups_2.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0003_create_tests_table_v2.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0003_create_tests_table_v2.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0004_convert_all_tables_to_innodb.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0004_convert_all_tables_to_innodb.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0005_create_billing_tables.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0005_create_billing_tables.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0006_eepnet_signups_3.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0006_eepnet_signups_3.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0007_create_pro_tables_v4.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0007_create_pro_tables_v4.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0008_persistent_vars.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0008_persistent_vars.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0009_pad_tables.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0009_pad_tables.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0010_pad_sqlmeta.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0010_pad_sqlmeta.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0011_pro_users_temppass.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0011_pro_users_temppass.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0012_pro_users_auto_signin.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0012_pro_users_auto_signin.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0013_pne_padv2_upgrade.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0013_pne_padv2_upgrade.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0014_pne_globalpadids.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0014_pne_globalpadids.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0015_padmeta_passwords.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0015_padmeta_passwords.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0016_pne_tracking_data.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0016_pne_tracking_data.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0017_pne_tracking_data_v2.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0017_pne_tracking_data_v2.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0018_eepnet_checkout_tables.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0018_eepnet_checkout_tables.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0019_padmeta_deleted.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0019_padmeta_deleted.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0020_padmeta_archived.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0020_padmeta_archived.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0021_pro_padmeta_json.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0021_pro_padmeta_json.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0022_create_userids_table.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0022_create_userids_table.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0023_create_usagestats_table.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0023_create_usagestats_table.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0024_statistics_table.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0024_statistics_table.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0025_rename_pro_users_table.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0025_rename_pro_users_table.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0026_create_guests_table.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0026_create_guests_table.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0027_pro_config.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0027_pro_config.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0028_ondemand_beta_emails.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0028_ondemand_beta_emails.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0029_lowercase_subdomains.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0029_lowercase_subdomains.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0030_fix_statistics_values.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0030_fix_statistics_values.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0031_deleted_pro_users.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0031_deleted_pro_users.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0032_reduce_topvalues_counts.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0032_reduce_topvalues_counts.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0033_pro_account_usage.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0033_pro_account_usage.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0034_create_recurring_billing_table.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0034_create_recurring_billing_table.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0035_add_email_to_paymentinfo.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0035_add_email_to_paymentinfo.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0036_create_missing_subscription_records.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0036_create_missing_subscription_records.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0037_create_pro_referral_table.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0037_create_pro_referral_table.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0038_pad_coarse_revs.js (renamed from trunk/etherpad/src/etherpad/db_migrations/m0038_pad_coarse_revs.js)0
-rw-r--r--etherpad/src/etherpad/db_migrations/m0040_create_plugin_tables.js40
-rw-r--r--etherpad/src/etherpad/db_migrations/migration_runner.js148
-rw-r--r--etherpad/src/etherpad/debug.js (renamed from trunk/etherpad/src/etherpad/debug.js)0
-rw-r--r--etherpad/src/etherpad/globals.js49
-rw-r--r--etherpad/src/etherpad/helpers.js306
-rw-r--r--etherpad/src/etherpad/importexport/importexport.js (renamed from trunk/etherpad/src/etherpad/importexport/importexport.js)0
-rw-r--r--etherpad/src/etherpad/legacy_urls.js37
-rw-r--r--etherpad/src/etherpad/licensing.js (renamed from trunk/etherpad/src/etherpad/licensing.js)0
-rw-r--r--etherpad/src/etherpad/log.js (renamed from trunk/etherpad/src/etherpad/log.js)0
-rw-r--r--etherpad/src/etherpad/metrics/metrics.js (renamed from trunk/etherpad/src/etherpad/metrics/metrics.js)0
-rw-r--r--etherpad/src/etherpad/pad/activepads.js (renamed from trunk/etherpad/src/etherpad/pad/activepads.js)0
-rw-r--r--etherpad/src/etherpad/pad/chatarchive.js (renamed from trunk/etherpad/src/etherpad/pad/chatarchive.js)0
-rw-r--r--etherpad/src/etherpad/pad/dbwriter.js (renamed from trunk/etherpad/src/etherpad/pad/dbwriter.js)0
-rw-r--r--etherpad/src/etherpad/pad/easysync2migration.js (renamed from trunk/etherpad/src/etherpad/pad/easysync2migration.js)0
-rw-r--r--etherpad/src/etherpad/pad/exporthtml.js (renamed from trunk/etherpad/src/etherpad/pad/exporthtml.js)0
-rw-r--r--etherpad/src/etherpad/pad/importhtml.js (renamed from trunk/etherpad/src/etherpad/pad/importhtml.js)0
-rw-r--r--etherpad/src/etherpad/pad/model.js655
-rw-r--r--etherpad/src/etherpad/pad/noprowatcher.js (renamed from trunk/etherpad/src/etherpad/pad/noprowatcher.js)0
-rw-r--r--etherpad/src/etherpad/pad/pad_migrations.js (renamed from trunk/etherpad/src/etherpad/pad/pad_migrations.js)0
-rw-r--r--etherpad/src/etherpad/pad/pad_security.js (renamed from trunk/etherpad/src/etherpad/pad/pad_security.js)0
-rw-r--r--etherpad/src/etherpad/pad/padevents.js (renamed from trunk/etherpad/src/etherpad/pad/padevents.js)0
-rw-r--r--etherpad/src/etherpad/pad/padusers.js (renamed from trunk/etherpad/src/etherpad/pad/padusers.js)0
-rw-r--r--etherpad/src/etherpad/pad/padutils.js191
-rw-r--r--etherpad/src/etherpad/pad/revisions.js (renamed from trunk/etherpad/src/etherpad/pad/revisions.js)0
-rw-r--r--etherpad/src/etherpad/pne/pne_utils.js149
-rw-r--r--etherpad/src/etherpad/pro/domains.js (renamed from trunk/etherpad/src/etherpad/pro/domains.js)0
-rw-r--r--etherpad/src/etherpad/pro/pro_account_auto_signin.js (renamed from trunk/etherpad/src/etherpad/pro/pro_account_auto_signin.js)0
-rw-r--r--etherpad/src/etherpad/pro/pro_accounts.js592
-rw-r--r--etherpad/src/etherpad/pro/pro_config.js (renamed from trunk/etherpad/src/etherpad/pro/pro_config.js)0
-rw-r--r--etherpad/src/etherpad/pro/pro_ldap_support.js217
-rw-r--r--etherpad/src/etherpad/pro/pro_pad_db.js (renamed from trunk/etherpad/src/etherpad/pro/pro_pad_db.js)0
-rw-r--r--etherpad/src/etherpad/pro/pro_pad_editors.js (renamed from trunk/etherpad/src/etherpad/pro/pro_pad_editors.js)0
-rw-r--r--etherpad/src/etherpad/pro/pro_padlist.js (renamed from trunk/etherpad/src/etherpad/pro/pro_padlist.js)0
-rw-r--r--etherpad/src/etherpad/pro/pro_padmeta.js (renamed from trunk/etherpad/src/etherpad/pro/pro_padmeta.js)0
-rw-r--r--etherpad/src/etherpad/pro/pro_quotas.js (renamed from trunk/etherpad/src/etherpad/pro/pro_quotas.js)0
-rw-r--r--etherpad/src/etherpad/pro/pro_utils.js169
-rw-r--r--etherpad/src/etherpad/quotas.js (renamed from trunk/etherpad/src/etherpad/quotas.js)0
-rw-r--r--etherpad/src/etherpad/sessions.js203
-rw-r--r--etherpad/src/etherpad/statistics/exceptions.js (renamed from trunk/etherpad/src/etherpad/statistics/exceptions.js)0
-rw-r--r--etherpad/src/etherpad/statistics/statistics.js (renamed from trunk/etherpad/src/etherpad/statistics/statistics.js)0
-rw-r--r--etherpad/src/etherpad/store/checkout.js (renamed from trunk/etherpad/src/etherpad/store/checkout.js)0
-rw-r--r--etherpad/src/etherpad/store/eepnet_checkout.js (renamed from trunk/etherpad/src/etherpad/store/eepnet_checkout.js)0
-rw-r--r--etherpad/src/etherpad/store/eepnet_trial.js (renamed from trunk/etherpad/src/etherpad/store/eepnet_trial.js)0
-rw-r--r--etherpad/src/etherpad/testing/testutils.js (renamed from trunk/etherpad/src/etherpad/testing/testutils.js)0
-rw-r--r--etherpad/src/etherpad/testing/unit_tests/t0000_test.js (renamed from trunk/etherpad/src/etherpad/testing/unit_tests/t0000_test.js)0
-rw-r--r--etherpad/src/etherpad/testing/unit_tests/t0001_sqlbase_transaction_rollback.js (renamed from trunk/etherpad/src/etherpad/testing/unit_tests/t0001_sqlbase_transaction_rollback.js)0
-rw-r--r--etherpad/src/etherpad/testing/unit_tests/t0002_license_generation.js (renamed from trunk/etherpad/src/etherpad/testing/unit_tests/t0002_license_generation.js)0
-rw-r--r--etherpad/src/etherpad/testing/unit_tests/t0003_persistent_vars.js (renamed from trunk/etherpad/src/etherpad/testing/unit_tests/t0003_persistent_vars.js)0
-rw-r--r--etherpad/src/etherpad/testing/unit_tests/t0004_sqlobj.js (renamed from trunk/etherpad/src/etherpad/testing/unit_tests/t0004_sqlobj.js)0
-rw-r--r--etherpad/src/etherpad/testing/unit_tests/t0005_easysync.js (renamed from trunk/etherpad/src/etherpad/testing/unit_tests/t0005_easysync.js)0
-rw-r--r--etherpad/src/etherpad/usage_stats/usage_stats.js (renamed from trunk/etherpad/src/etherpad/usage_stats/usage_stats.js)0
-rw-r--r--etherpad/src/etherpad/utils.js464
-rw-r--r--etherpad/src/main.js434
-rw-r--r--etherpad/src/plugins/fileUpload/controllers/fileUpload.js87
-rw-r--r--etherpad/src/plugins/fileUpload/hooks.js11
-rw-r--r--etherpad/src/plugins/fileUpload/main.js19
-rw-r--r--etherpad/src/plugins/fileUpload/models.js95
-rw-r--r--etherpad/src/plugins/fileUpload/templates/fileUpload.ejs32
-rw-r--r--etherpad/src/plugins/fileUpload/templates/fileUploaded.ejs5
-rw-r--r--etherpad/src/plugins/kafoo/main.js16
-rw-r--r--etherpad/src/plugins/testplugin/controllers/testplugin.js58
-rw-r--r--etherpad/src/plugins/testplugin/hooks.js15
-rw-r--r--etherpad/src/plugins/testplugin/main.js23
-rw-r--r--etherpad/src/plugins/testplugin/static/js/main.js11
-rw-r--r--etherpad/src/plugins/testplugin/static/js/test.js1
-rw-r--r--etherpad/src/plugins/testplugin/templates/page.ejs23
-rw-r--r--etherpad/src/plugins/testplugin/templates/testplugin.ejs33
-rw-r--r--etherpad/src/plugins/twitterStyleTags/controllers/tagBrowser.js103
-rw-r--r--etherpad/src/plugins/twitterStyleTags/hooks.js56
-rw-r--r--etherpad/src/plugins/twitterStyleTags/main.js45
-rw-r--r--etherpad/src/plugins/twitterStyleTags/models/tagQuery.js227
-rw-r--r--etherpad/src/plugins/twitterStyleTags/static/css/pad.css70
-rw-r--r--etherpad/src/plugins/twitterStyleTags/static/css/tagBrowser.css90
-rw-r--r--etherpad/src/plugins/twitterStyleTags/static/js/main.js48
-rw-r--r--etherpad/src/plugins/twitterStyleTags/templates/tagBrowser.ejs115
-rw-r--r--etherpad/src/plugins/twitterStyleTags/templates/tagRss.ejs69
-rw-r--r--etherpad/src/plugins/urlIndexer/controllers/urlBrowser.js132
-rw-r--r--etherpad/src/plugins/urlIndexer/hooks.js49
-rw-r--r--etherpad/src/plugins/urlIndexer/main.js34
-rw-r--r--etherpad/src/plugins/urlIndexer/templates/urlBrowser.ejs53
-rw-r--r--etherpad/src/static/crossdomain.xml (renamed from trunk/etherpad/src/static/crossdomain.xml)0
-rw-r--r--etherpad/src/static/css/admin/admin-stats.css (renamed from trunk/etherpad/src/static/css/admin/admin-stats.css)0
-rw-r--r--etherpad/src/static/css/admin/pluginmanager.css62
-rw-r--r--etherpad/src/static/css/broadcast.css (renamed from trunk/etherpad/src/static/css/broadcast.css)0
-rw-r--r--etherpad/src/static/css/etherpad.css (renamed from trunk/etherpad/src/static/css/etherpad.css)0
-rw-r--r--etherpad/src/static/css/framedpage.css (renamed from trunk/etherpad/src/static/css/framedpage.css)0
-rw-r--r--etherpad/src/static/css/global-pro-account.css (renamed from trunk/etherpad/src/static/css/global-pro-account.css)0
-rw-r--r--etherpad/src/static/css/home-opensource.css40
-rw-r--r--etherpad/src/static/css/lib/jquery.contextmenu.css (renamed from trunk/etherpad/src/static/css/lib/jquery.contextmenu.css)0
-rw-r--r--etherpad/src/static/css/pad2_ejs.css910
-rw-r--r--etherpad/src/static/css/pro-signup.css (renamed from trunk/etherpad/src/static/css/pro-signup.css)0
-rw-r--r--etherpad/src/static/css/pro/account.css (renamed from trunk/etherpad/src/static/css/pro/account.css)0
-rw-r--r--etherpad/src/static/css/pro/framedpage-pro.css (renamed from trunk/etherpad/src/static/css/pro/framedpage-pro.css)0
-rw-r--r--etherpad/src/static/css/pro/padlist.css (renamed from trunk/etherpad/src/static/css/pro/padlist.css)0
-rw-r--r--etherpad/src/static/css/pro/pro-admin.css (renamed from trunk/etherpad/src/static/css/pro/pro-admin.css)0
-rw-r--r--etherpad/src/static/css/pro/pro-home.css (renamed from trunk/etherpad/src/static/css/pro/pro-home.css)0
-rw-r--r--etherpad/src/static/favicon.ico (renamed from trunk/etherpad/src/static/favicon.ico)bin1354 -> 1354 bytes
-rw-r--r--etherpad/src/static/img/davy/bg/home-createpad.png (renamed from trunk/etherpad/src/static/img/davy/bg/home-createpad.png)bin4327 -> 4327 bytes
-rw-r--r--etherpad/src/static/img/davy/bg/product.png (renamed from trunk/etherpad/src/static/img/davy/bg/product.png)bin161 -> 161 bytes
-rw-r--r--etherpad/src/static/img/davy/btn/createpad-small.gif (renamed from trunk/etherpad/src/static/img/davy/btn/createpad-small.gif)bin3148 -> 3148 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/backgrad.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/backgrad.gif)bin697 -> 697 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/colorpicker.gifbin0 -> 2020 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/connectingbar.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/connectingbar.gif)bin10819 -> 10819 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/docpaneledge2.png (renamed from trunk/etherpad/src/static/img/jun09/pad/docpaneledge2.png)bin635 -> 635 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/docpanelmiddle2.png (renamed from trunk/etherpad/src/static/img/jun09/pad/docpanelmiddle2.png)bin295 -> 295 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_background.gifbin0 -> 181 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_background_left.gifbin0 -> 204 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_background_right.gifbin0 -> 867 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_bold.gifbin0 -> 224 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_clearauthorship.gifbin0 -> 397 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_groupleft.gifbin0 -> 186 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_groupright.gifbin0 -> 185 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_indent.gifbin0 -> 99 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_insertunorderedlist.gifbin0 -> 147 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_italic.gifbin0 -> 201 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_outdent.gifbin0 -> 99 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_redo.gifbin0 -> 232 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_save.gifbin0 -> 139 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_strikethrough.gifbin0 -> 336 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_underline.gifbin0 -> 223 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbar_undo.gifbin0 -> 230 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/editbarback.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/editbarback.gif)bin368 -> 368 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/feedbackbox2.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/feedbackbox2.gif)bin6262 -> 6262 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/fileicons.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/fileicons.gif)bin1397 -> 1397 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/hdraggie.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/hdraggie.gif)bin453 -> 453 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/icon_import_export.gifbin0 -> 96 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/icon_pad_options.gifbin0 -> 67 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/icon_saved_revisions.gifbin0 -> 81 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/icon_security.gifbin0 -> 87 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/icon_time_slider.gifbin0 -> 74 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/inviteshare.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/inviteshare.gif)bin511 -> 511 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/inviteshare2.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/inviteshare2.gif)bin1836 -> 1836 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/layoutbuttons.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/layoutbuttons.gif)bin3750 -> 3750 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/ok_or_cancel.gifbin0 -> 1630 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/overlay2.png (renamed from trunk/etherpad/src/static/img/jun09/pad/overlay2.png)bin149 -> 149 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/padtop5.gifbin0 -> 3872 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/padtop5.pngbin0 -> 6604 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/padtop5.xcfbin0 -> 44819 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/padtopback2.gifbin0 -> 372 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/public.gifbin0 -> 1034 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/roundcorner_left.gifbin0 -> 123 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/roundcorner_right.gifbin0 -> 131 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/roundcorner_right_orange.gifbin0 -> 171 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/savedrevarrows.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/savedrevarrows.gif)bin866 -> 866 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/savedrevsgfx2.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/savedrevsgfx2.gif)bin1904 -> 1904 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/sharebox4.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/sharebox4.gif)bin5788 -> 5788 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/sharedistri.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/sharedistri.gif)bin85 -> 85 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/syncdone.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/syncdone.gif)bin211 -> 211 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/syncing.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/syncing.gif)bin673 -> 673 bytes
-rw-r--r--etherpad/src/static/img/jun09/pad/viewbargfx.gif (renamed from trunk/etherpad/src/static/img/jun09/pad/viewbargfx.gif)bin155 -> 155 bytes
-rw-r--r--etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-cyan-menu-item-hover.gif (renamed from trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-cyan-menu-item-hover.gif)bin52 -> 52 bytes
-rw-r--r--etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-menu-item-hover.gif (renamed from trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-menu-item-hover.gif)bin52 -> 52 bytes
-rw-r--r--etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-semitransparent-menu-item-hover.png (renamed from trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-semitransparent-menu-item-hover.png)bin2837 -> 2837 bytes
-rw-r--r--etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-human-menu-item-hover.gif (renamed from trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-human-menu-item-hover.gif)bin195 -> 195 bytes
-rw-r--r--etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-osx-menu-item-hover.gif (renamed from trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-osx-menu-item-hover.gif)bin87 -> 87 bytes
-rw-r--r--etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-bg.gif (renamed from trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-bg.gif)bin64 -> 64 bytes
-rw-r--r--etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-menu-item-hover.gif (renamed from trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-menu-item-hover.gif)bin347 -> 347 bytes
-rw-r--r--etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-xp-bg.gif (renamed from trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-xp-bg.gif)bin223 -> 223 bytes
-rw-r--r--etherpad/src/static/img/may09/doc.gif (renamed from trunk/etherpad/src/static/img/may09/doc.gif)bin632 -> 632 bytes
-rw-r--r--etherpad/src/static/img/may09/html.gif (renamed from trunk/etherpad/src/static/img/may09/html.gif)bin1040 -> 1040 bytes
-rw-r--r--etherpad/src/static/img/may09/pdf.gif (renamed from trunk/etherpad/src/static/img/may09/pdf.gif)bin398 -> 398 bytes
-rw-r--r--etherpad/src/static/img/may09/txt.gif (renamed from trunk/etherpad/src/static/img/may09/txt.gif)bin381 -> 381 bytes
-rw-r--r--etherpad/src/static/img/misc/status-ball.gif (renamed from trunk/etherpad/src/static/img/misc/status-ball.gif)bin1553 -> 1553 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/crushed_button_depressed.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/crushed_button_depressed.png)bin4134 -> 4134 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/crushed_button_undepressed.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/crushed_button_undepressed.png)bin4166 -> 4166 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/crushed_current_location.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/crushed_current_location.png)bin1009 -> 1009 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/crushed_timeslider_mockup.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/crushed_timeslider_mockup.png)bin8164 -> 8164 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/current_location.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/current_location.png)bin1100 -> 1100 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/pause.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/pause.png)bin2883 -> 2883 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/play.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/play.png)bin3017 -> 3017 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/play_button.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/play_button.png)bin4867 -> 4867 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/star.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/star.png)bin3241 -> 3241 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/star_selected.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/star_selected.png)bin3242 -> 3242 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/stepper_buttons.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/stepper_buttons.png)bin4858 -> 4858 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/timeslider_background.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/timeslider_background.png)bin915 -> 915 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/timeslider_left.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/timeslider_left.png)bin1653 -> 1653 bytes
-rw-r--r--etherpad/src/static/img/pad/timeslider/timeslider_right.png (renamed from trunk/etherpad/src/static/img/pad/timeslider/timeslider_right.png)bin1581 -> 1581 bytes
-rw-r--r--etherpad/src/static/img/pro/box/blue-boxtop.gif (renamed from trunk/etherpad/src/static/img/pro/box/blue-boxtop.gif)bin523 -> 523 bytes
-rw-r--r--etherpad/src/static/img/pro/buttons/bluebutton120.gif (renamed from trunk/etherpad/src/static/img/pro/buttons/bluebutton120.gif)bin951 -> 951 bytes
-rw-r--r--etherpad/src/static/img/pro/header/pro-header-logo.png (renamed from trunk/etherpad/src/static/img/pro/header/pro-header-logo.png)bin5527 -> 5527 bytes
-rw-r--r--etherpad/src/static/img/pro/header/pro-header-plustopnav-back.gif (renamed from trunk/etherpad/src/static/img/pro/header/pro-header-plustopnav-back.gif)bin474 -> 474 bytes
-rw-r--r--etherpad/src/static/img/pro/padlist/gear-drop.gif (renamed from trunk/etherpad/src/static/img/pro/padlist/gear-drop.gif)bin300 -> 300 bytes
-rw-r--r--etherpad/src/static/img/pro/padlist/paper-icon.gif (renamed from trunk/etherpad/src/static/img/pro/padlist/paper-icon.gif)bin619 -> 619 bytes
-rw-r--r--etherpad/src/static/img/pro/padlist/trash-icon.gif (renamed from trunk/etherpad/src/static/img/pro/padlist/trash-icon.gif)bin1080 -> 1080 bytes
-rw-r--r--etherpad/src/static/img/pro/topnav/pro-topnav-back.gif (renamed from trunk/etherpad/src/static/img/pro/topnav/pro-topnav-back.gif)bin137 -> 137 bytes
-rw-r--r--etherpad/src/static/img/pro/topnav/pro-topnav-notch.gif (renamed from trunk/etherpad/src/static/img/pro/topnav/pro-topnav-notch.gif)bin92 -> 92 bytes
-rw-r--r--etherpad/src/static/js/billing.js (renamed from trunk/etherpad/src/static/js/billing.js)0
-rw-r--r--etherpad/src/static/js/billing_shared.js (renamed from trunk/etherpad/src/static/js/billing_shared.js)0
-rw-r--r--etherpad/src/static/js/broadcast.js610
-rw-r--r--etherpad/src/static/js/broadcast_revisions.js (renamed from trunk/etherpad/src/static/js/broadcast_revisions.js)0
-rw-r--r--etherpad/src/static/js/broadcast_slider.js (renamed from trunk/etherpad/src/static/js/broadcast_slider.js)0
-rw-r--r--etherpad/src/static/js/collab_client.js (renamed from trunk/etherpad/src/static/js/collab_client.js)0
-rw-r--r--etherpad/src/static/js/confirmation.js (renamed from trunk/etherpad/src/static/js/confirmation.js)0
-rw-r--r--etherpad/src/static/js/connection_diagnostics.js (renamed from trunk/etherpad/src/static/js/connection_diagnostics.js)0
-rw-r--r--etherpad/src/static/js/draggable.js (renamed from trunk/etherpad/src/static/js/draggable.js)0
-rw-r--r--etherpad/src/static/js/etherpad.js (renamed from trunk/etherpad/src/static/js/etherpad.js)0
-rw-r--r--[-rwxr-xr-x]etherpad/src/static/js/jquery-1.2.6.js (renamed from trunk/etherpad/src/static/js/jquery-1.2.6.js)0
-rw-r--r--etherpad/src/static/js/jquery-1.3.2.js (renamed from trunk/etherpad/src/static/js/jquery-1.3.2.js)0
-rw-r--r--etherpad/src/static/js/json2.js (renamed from trunk/etherpad/src/static/js/json2.js)0
-rw-r--r--etherpad/src/static/js/lib/jquery.contextmenu.js (renamed from trunk/etherpad/src/static/js/lib/jquery.contextmenu.js)0
-rw-r--r--etherpad/src/static/js/pad2.js (renamed from trunk/etherpad/src/static/js/pad2.js)0
-rw-r--r--etherpad/src/static/js/pad_chat.js (renamed from trunk/etherpad/src/static/js/pad_chat.js)0
-rw-r--r--etherpad/src/static/js/pad_connectionstatus.js (renamed from trunk/etherpad/src/static/js/pad_connectionstatus.js)0
-rw-r--r--etherpad/src/static/js/pad_cookie.js (renamed from trunk/etherpad/src/static/js/pad_cookie.js)0
-rw-r--r--etherpad/src/static/js/pad_docbar.js (renamed from trunk/etherpad/src/static/js/pad_docbar.js)0
-rw-r--r--etherpad/src/static/js/pad_editbar.js (renamed from trunk/etherpad/src/static/js/pad_editbar.js)0
-rw-r--r--etherpad/src/static/js/pad_editor.js (renamed from trunk/etherpad/src/static/js/pad_editor.js)0
-rw-r--r--etherpad/src/static/js/pad_impexp.js (renamed from trunk/etherpad/src/static/js/pad_impexp.js)0
-rw-r--r--etherpad/src/static/js/pad_modals.js (renamed from trunk/etherpad/src/static/js/pad_modals.js)0
-rw-r--r--etherpad/src/static/js/pad_savedrevs.js (renamed from trunk/etherpad/src/static/js/pad_savedrevs.js)0
-rw-r--r--etherpad/src/static/js/pad_userlist.js (renamed from trunk/etherpad/src/static/js/pad_userlist.js)0
-rw-r--r--etherpad/src/static/js/pad_utils.js (renamed from trunk/etherpad/src/static/js/pad_utils.js)0
-rw-r--r--etherpad/src/static/js/plugins.js22
-rw-r--r--etherpad/src/static/js/pricing.js (renamed from trunk/etherpad/src/static/js/pricing.js)0
-rw-r--r--etherpad/src/static/js/pro/guest-knock-client.js (renamed from trunk/etherpad/src/static/js/pro/guest-knock-client.js)0
-rw-r--r--etherpad/src/static/js/pro/pro-padlist-client.js (renamed from trunk/etherpad/src/static/js/pro/pro-padlist-client.js)0
-rw-r--r--etherpad/src/static/js/pro/signin-client.js (renamed from trunk/etherpad/src/static/js/pro/signin-client.js)0
-rw-r--r--etherpad/src/static/js/pulse.jquery.js (renamed from trunk/etherpad/src/static/js/pulse.jquery.js)0
-rw-r--r--etherpad/src/static/js/statpage.js (renamed from trunk/etherpad/src/static/js/statpage.js)0
-rw-r--r--etherpad/src/static/js/store.js116
-rw-r--r--etherpad/src/static/js/swfobject.js (renamed from trunk/etherpad/src/static/js/swfobject.js)0
-rw-r--r--etherpad/src/static/js/timeslider.js (renamed from trunk/etherpad/src/static/js/timeslider.js)0
-rw-r--r--etherpad/src/static/js/undo-xpopup.js (renamed from trunk/etherpad/src/static/js/undo-xpopup.js)0
-rw-r--r--etherpad/src/static/robots.txt1
-rw-r--r--etherpad/src/templates/pad/exporthtml.ejs (renamed from trunk/etherpad/src/templates/pad/exporthtml.ejs)0
-rw-r--r--etherpad/src/templates/pro/admin/pro-config.ejs (renamed from trunk/etherpad/src/templates/pro/admin/pro-config.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/500_body.ejs (renamed from trunk/etherpad/src/templates/500_body.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/admin/pluginmanager.ejs74
-rw-r--r--etherpad/src/themes/default/templates/email/padinvite.ejs (renamed from trunk/etherpad/src/templates/email/padinvite.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/framed/framedfooter.ejs (renamed from trunk/etherpad/src/templates/framed/framedfooter.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/framed/framedheader-pro.ejs78
-rw-r--r--etherpad/src/themes/default/templates/framed/framedheader.ejs (renamed from trunk/etherpad/src/templates/framed/framedheader.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/framed/framedpage-pro.ejs (renamed from trunk/etherpad/src/templates/framed/framedpage-pro.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/framed/framedpage.ejs (renamed from trunk/etherpad/src/templates/framed/framedpage.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/html.ejs (renamed from trunk/etherpad/src/templates/html.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/main/home.ejs62
-rw-r--r--etherpad/src/themes/default/templates/main/pro_signup_body.ejs (renamed from trunk/etherpad/src/templates/main/pro_signup_body.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/misc/pad_default.ejs (renamed from trunk/etherpad/src/templates/misc/pad_default.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/notice.ejs (renamed from trunk/etherpad/src/templates/notice.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pad/create_body.ejs (renamed from trunk/etherpad/src/templates/pad/create_body.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pad/pad_body2.ejs505
-rw-r--r--etherpad/src/themes/default/templates/pad/pad_iphone_body.ejs (renamed from trunk/etherpad/src/templates/pad/pad_iphone_body.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pad/padview_body.ejs (renamed from trunk/etherpad/src/templates/pad/padview_body.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/page.ejs135
-rw-r--r--etherpad/src/themes/default/templates/pro-account/recover.ejs (renamed from trunk/etherpad/src/templates/pro-account/recover.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro-account/sign-in.ejs (renamed from trunk/etherpad/src/templates/pro-account/sign-in.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/account/account-welcome-email.ejs (renamed from trunk/etherpad/src/templates/pro/account/account-welcome-email.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/account/forgot-password-email.ejs (renamed from trunk/etherpad/src/templates/pro/account/forgot-password-email.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/account/forgot-password.ejs (renamed from trunk/etherpad/src/templates/pro/account/forgot-password.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/account/my-account.ejs (renamed from trunk/etherpad/src/templates/pro/account/my-account.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/account/signin.ejs (renamed from trunk/etherpad/src/templates/pro/account/signin.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/admin/account-manager.ejs (renamed from trunk/etherpad/src/templates/pro/admin/account-manager.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/admin/admin-template.ejs (renamed from trunk/etherpad/src/templates/pro/admin/admin-template.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/admin/delete-account.ejs (renamed from trunk/etherpad/src/templates/pro/admin/delete-account.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/admin/manage-account.ejs (renamed from trunk/etherpad/src/templates/pro/admin/manage-account.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/admin/new-account.ejs (renamed from trunk/etherpad/src/templates/pro/admin/new-account.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/padlist/pro-padlist.ejs (renamed from trunk/etherpad/src/templates/pro/padlist/pro-padlist.ejs)0
-rw-r--r--etherpad/src/themes/default/templates/pro/pro_home.ejs (renamed from trunk/etherpad/src/templates/pro/pro_home.ejs)0
-rw-r--r--infrastructure/.gitignore (renamed from trunk/infrastructure/.gitignore)0
-rw-r--r--infrastructure/ace/.gitignore (renamed from trunk/infrastructure/ace/.gitignore)0
-rw-r--r--infrastructure/ace/README (renamed from trunk/infrastructure/ace/README)0
-rwxr-xr-xinfrastructure/ace/bin/make339
-rwxr-xr-xinfrastructure/ace/bin/serve (renamed from trunk/infrastructure/ace/bin/serve)0
-rw-r--r--infrastructure/ace/blog.txt (renamed from trunk/infrastructure/ace/blog.txt)0
-rw-r--r--infrastructure/ace/build/.gitignore (renamed from trunk/infrastructure/ace/build/.gitignore)0
-rw-r--r--infrastructure/ace/build/index.html (renamed from trunk/infrastructure/ace/build/index.html)0
-rw-r--r--infrastructure/ace/build/jquery-1.2.1.js (renamed from trunk/infrastructure/ace/build/jquery-1.2.1.js)0
-rw-r--r--infrastructure/ace/build/testcode.js (renamed from trunk/infrastructure/ace/build/testcode.js)0
-rw-r--r--infrastructure/ace/easysync-notes.txt (renamed from trunk/infrastructure/ace/easysync-notes.txt)0
l---------infrastructure/ace/lib/rhino-js-1.7r1.jar (renamed from trunk/infrastructure/ace/lib/rhino-js-1.7r1.jar)0
l---------infrastructure/ace/lib/yuicompressor-2.4-appjet.jar (renamed from trunk/infrastructure/ace/lib/yuicompressor-2.4-appjet.jar)0
-rw-r--r--infrastructure/ace/notes.txt (renamed from trunk/infrastructure/ace/notes.txt)0
-rw-r--r--infrastructure/ace/www/ace2_common.js (renamed from trunk/infrastructure/ace/www/ace2_common.js)0
-rw-r--r--infrastructure/ace/www/ace2_common_dev.js (renamed from trunk/infrastructure/ace/www/ace2_common_dev.js)0
-rw-r--r--infrastructure/ace/www/ace2_inner.js4809
-rw-r--r--infrastructure/ace/www/ace2_outer.js234
-rw-r--r--infrastructure/ace/www/ace2_wrapper.js (renamed from trunk/infrastructure/ace/www/ace2_wrapper.js)0
-rw-r--r--infrastructure/ace/www/bbtree.js (renamed from trunk/infrastructure/ace/www/bbtree.js)0
-rw-r--r--infrastructure/ace/www/changesettracker.js (renamed from trunk/infrastructure/ace/www/changesettracker.js)0
-rw-r--r--infrastructure/ace/www/colorutils.js (renamed from trunk/infrastructure/ace/www/colorutils.js)0
-rw-r--r--infrastructure/ace/www/contentcollector.js (renamed from trunk/infrastructure/ace/www/contentcollector.js)0
-rw-r--r--infrastructure/ace/www/cssmanager.js (renamed from trunk/infrastructure/ace/www/cssmanager.js)0
-rw-r--r--infrastructure/ace/www/dev.html (renamed from trunk/infrastructure/ace/www/dev.html)0
-rw-r--r--infrastructure/ace/www/domline.js232
-rw-r--r--infrastructure/ace/www/easy_sync.js (renamed from trunk/infrastructure/ace/www/easy_sync.js)0
-rw-r--r--infrastructure/ace/www/easysync2.js (renamed from trunk/infrastructure/ace/www/easysync2.js)0
-rw-r--r--infrastructure/ace/www/easysync2_tests.js (renamed from trunk/infrastructure/ace/www/easysync2_tests.js)0
-rw-r--r--infrastructure/ace/www/editor.css (renamed from trunk/infrastructure/ace/www/editor.css)0
-rw-r--r--infrastructure/ace/www/firebug/errorIcon.png (renamed from trunk/infrastructure/ace/www/firebug/errorIcon.png)bin457 -> 457 bytes
-rw-r--r--infrastructure/ace/www/firebug/firebug.css (renamed from trunk/infrastructure/ace/www/firebug/firebug.css)0
-rw-r--r--infrastructure/ace/www/firebug/firebug.html (renamed from trunk/infrastructure/ace/www/firebug/firebug.html)0
-rw-r--r--infrastructure/ace/www/firebug/firebug.js (renamed from trunk/infrastructure/ace/www/firebug/firebug.js)0
-rw-r--r--infrastructure/ace/www/firebug/firebugx.js (renamed from trunk/infrastructure/ace/www/firebug/firebugx.js)0
-rw-r--r--infrastructure/ace/www/firebug/infoIcon.png (renamed from trunk/infrastructure/ace/www/firebug/infoIcon.png)bin524 -> 524 bytes
-rw-r--r--infrastructure/ace/www/firebug/warningIcon.png (renamed from trunk/infrastructure/ace/www/firebug/warningIcon.png)bin516 -> 516 bytes
-rw-r--r--infrastructure/ace/www/index.html (renamed from trunk/infrastructure/ace/www/index.html)0
-rw-r--r--infrastructure/ace/www/inner.css (renamed from trunk/infrastructure/ace/www/inner.css)0
-rw-r--r--infrastructure/ace/www/jquery-1.2.1.js (renamed from trunk/infrastructure/ace/www/jquery-1.2.1.js)0
-rw-r--r--infrastructure/ace/www/lang_html.js (renamed from trunk/infrastructure/ace/www/lang_html.js)0
-rw-r--r--infrastructure/ace/www/lang_js.js (renamed from trunk/infrastructure/ace/www/lang_js.js)0
-rw-r--r--infrastructure/ace/www/lexer_support.js (renamed from trunk/infrastructure/ace/www/lexer_support.js)0
-rw-r--r--infrastructure/ace/www/linestylefilter.js287
-rw-r--r--infrastructure/ace/www/magicdom.js (renamed from trunk/infrastructure/ace/www/magicdom.js)0
-rw-r--r--infrastructure/ace/www/multilang_lexer.js (renamed from trunk/infrastructure/ace/www/multilang_lexer.js)0
-rw-r--r--infrastructure/ace/www/processing.js (renamed from trunk/infrastructure/ace/www/processing.js)0
-rw-r--r--infrastructure/ace/www/profiler.js (renamed from trunk/infrastructure/ace/www/profiler.js)0
-rw-r--r--infrastructure/ace/www/skiplist.js (renamed from trunk/infrastructure/ace/www/skiplist.js)0
-rw-r--r--infrastructure/ace/www/spanlist.js (renamed from trunk/infrastructure/ace/www/spanlist.js)0
-rw-r--r--infrastructure/ace/www/syntax-new.css (renamed from trunk/infrastructure/ace/www/syntax-new.css)0
-rw-r--r--infrastructure/ace/www/syntax.css (renamed from trunk/infrastructure/ace/www/syntax.css)0
-rw-r--r--infrastructure/ace/www/test.html (renamed from trunk/infrastructure/ace/www/test.html)0
-rw-r--r--infrastructure/ace/www/testcode.js (renamed from trunk/infrastructure/ace/www/testcode.js)0
-rw-r--r--infrastructure/ace/www/toSource.js (renamed from trunk/infrastructure/ace/www/toSource.js)0
-rw-r--r--infrastructure/ace/www/undomodule.js (renamed from trunk/infrastructure/ace/www/undomodule.js)0
-rw-r--r--infrastructure/ace/www/virtual_lines.js (renamed from trunk/infrastructure/ace/www/virtual_lines.js)0
-rwxr-xr-xinfrastructure/bin/classpath.sh (renamed from trunk/infrastructure/bin/classpath.sh)0
-rwxr-xr-xinfrastructure/bin/comp.sh (renamed from trunk/infrastructure/bin/comp.sh)0
-rwxr-xr-xinfrastructure/bin/compilecache.sh66
-rwxr-xr-xinfrastructure/bin/jscomp.sh (renamed from trunk/infrastructure/bin/jscomp.sh)0
-rwxr-xr-xinfrastructure/bin/makejar.sh74
-rwxr-xr-xinfrastructure/bin/makesars.sh (renamed from trunk/infrastructure/bin/makesars.sh)0
-rwxr-xr-xinfrastructure/bin/run.sh (renamed from trunk/infrastructure/bin/run.sh)0
-rw-r--r--infrastructure/com.etherpad.openofficeservice/importexport.scala287
-rw-r--r--infrastructure/com.etherpad/easysync2support.scala (renamed from trunk/infrastructure/com.etherpad/easysync2support.scala)0
-rw-r--r--infrastructure/com.etherpad/licensing.scala169
-rw-r--r--infrastructure/com.etherpad/main.scala (renamed from trunk/infrastructure/com.etherpad/main.scala)0
-rw-r--r--infrastructure/framework-src/modules/atomfeed.js (renamed from trunk/infrastructure/framework-src/modules/atomfeed.js)0
-rw-r--r--infrastructure/framework-src/modules/blob.js (renamed from trunk/infrastructure/framework-src/modules/blob.js)0
-rw-r--r--infrastructure/framework-src/modules/cache_utils.js (renamed from trunk/infrastructure/framework-src/modules/cache_utils.js)0
-rw-r--r--infrastructure/framework-src/modules/comet.js (renamed from trunk/infrastructure/framework-src/modules/comet.js)0
-rw-r--r--infrastructure/framework-src/modules/dateutils.js (renamed from trunk/infrastructure/framework-src/modules/dateutils.js)0
-rw-r--r--infrastructure/framework-src/modules/dispatch.js (renamed from trunk/infrastructure/framework-src/modules/dispatch.js)0
-rw-r--r--infrastructure/framework-src/modules/ejs.js477
-rw-r--r--infrastructure/framework-src/modules/email.js (renamed from trunk/infrastructure/framework-src/modules/email.js)0
-rw-r--r--infrastructure/framework-src/modules/exceptionutils.js (renamed from trunk/infrastructure/framework-src/modules/exceptionutils.js)0
-rw-r--r--infrastructure/framework-src/modules/execution.js61
-rw-r--r--infrastructure/framework-src/modules/fastJSON.js (renamed from trunk/infrastructure/framework-src/modules/fastJSON.js)0
-rw-r--r--infrastructure/framework-src/modules/faststatic.js342
-rw-r--r--infrastructure/framework-src/modules/fileutils.js (renamed from trunk/infrastructure/framework-src/modules/fileutils.js)0
-rw-r--r--infrastructure/framework-src/modules/funhtml.js (renamed from trunk/infrastructure/framework-src/modules/funhtml.js)0
-rw-r--r--infrastructure/framework-src/modules/global/appjet.js (renamed from trunk/infrastructure/framework-src/modules/global/appjet.js)0
-rw-r--r--infrastructure/framework-src/modules/global/request.js (renamed from trunk/infrastructure/framework-src/modules/global/request.js)0
-rw-r--r--infrastructure/framework-src/modules/global/response.js (renamed from trunk/infrastructure/framework-src/modules/global/response.js)0
-rw-r--r--infrastructure/framework-src/modules/image.js (renamed from trunk/infrastructure/framework-src/modules/image.js)0
-rw-r--r--infrastructure/framework-src/modules/jsutils.js (renamed from trunk/infrastructure/framework-src/modules/jsutils.js)0
-rw-r--r--infrastructure/framework-src/modules/netutils.js (renamed from trunk/infrastructure/framework-src/modules/netutils.js)0
-rw-r--r--infrastructure/framework-src/modules/process.js91
-rw-r--r--infrastructure/framework-src/modules/profiler.js (renamed from trunk/infrastructure/framework-src/modules/profiler.js)0
-rw-r--r--infrastructure/framework-src/modules/sessions.js (renamed from trunk/infrastructure/framework-src/modules/sessions.js)0
-rw-r--r--infrastructure/framework-src/modules/sqlbase/persistent_vars.js (renamed from trunk/infrastructure/framework-src/modules/sqlbase/persistent_vars.js)0
-rw-r--r--infrastructure/framework-src/modules/sqlbase/sqlbase.js (renamed from trunk/infrastructure/framework-src/modules/sqlbase/sqlbase.js)0
-rw-r--r--infrastructure/framework-src/modules/sqlbase/sqlcommon.js (renamed from trunk/infrastructure/framework-src/modules/sqlbase/sqlcommon.js)0
-rw-r--r--infrastructure/framework-src/modules/sqlbase/sqlobj.js551
-rw-r--r--infrastructure/framework-src/modules/stringutils.js (renamed from trunk/infrastructure/framework-src/modules/stringutils.js)0
-rw-r--r--infrastructure/framework-src/modules/sync.js (renamed from trunk/infrastructure/framework-src/modules/sync.js)0
-rw-r--r--infrastructure/framework-src/modules/timer.js (renamed from trunk/infrastructure/framework-src/modules/timer.js)0
-rw-r--r--infrastructure/framework-src/modules/varz.js (renamed from trunk/infrastructure/framework-src/modules/varz.js)0
-rw-r--r--infrastructure/framework-src/modules/yuicompressor.js (renamed from trunk/infrastructure/framework-src/modules/yuicompressor.js)0
-rw-r--r--infrastructure/framework-src/oncomet.js (renamed from trunk/infrastructure/framework-src/oncomet.js)0
-rw-r--r--infrastructure/framework-src/onerror.js (renamed from trunk/infrastructure/framework-src/onerror.js)0
-rw-r--r--infrastructure/framework-src/onprint.js (renamed from trunk/infrastructure/framework-src/onprint.js)0
-rw-r--r--infrastructure/framework-src/onrequest.js (renamed from trunk/infrastructure/framework-src/onrequest.js)0
-rw-r--r--infrastructure/framework-src/onreset.js (renamed from trunk/infrastructure/framework-src/onreset.js)0
-rw-r--r--infrastructure/framework-src/onsars.js (renamed from trunk/infrastructure/framework-src/onsars.js)0
-rw-r--r--infrastructure/framework-src/onscheduledtask.js (renamed from trunk/infrastructure/framework-src/onscheduledtask.js)0
-rw-r--r--infrastructure/framework-src/onshutdown.js (renamed from trunk/infrastructure/framework-src/onshutdown.js)0
-rw-r--r--infrastructure/framework-src/onstartup.js (renamed from trunk/infrastructure/framework-src/onstartup.js)0
-rw-r--r--infrastructure/framework-src/onsyntaxerror.js (renamed from trunk/infrastructure/framework-src/onsyntaxerror.js)0
-rw-r--r--infrastructure/framework-src/postamble.js (renamed from trunk/infrastructure/framework-src/postamble.js)0
-rw-r--r--infrastructure/framework-src/preamble.js (renamed from trunk/infrastructure/framework-src/preamble.js)0
-rw-r--r--infrastructure/framework-src/syntaxerror.js (renamed from trunk/infrastructure/framework-src/syntaxerror.js)0
-rw-r--r--infrastructure/lib/activation.jar (renamed from trunk/infrastructure/lib/activation.jar)bin56290 -> 56290 bytes
-rw-r--r--infrastructure/lib/c3p0-0.9.1.2.jar (renamed from trunk/infrastructure/lib/c3p0-0.9.1.2.jar)bin610790 -> 610790 bytes
-rw-r--r--infrastructure/lib/commons-fileupload-1.2.1-javadoc.jarbin0 -> 275779 bytes
-rw-r--r--infrastructure/lib/commons-fileupload-1.2.1-sources.jarbin0 -> 73721 bytes
-rw-r--r--infrastructure/lib/commons-fileupload-1.2.1.jarbin0 -> 57779 bytes
-rw-r--r--infrastructure/lib/commons-io-1.4-javadoc.jarbin0 -> 499643 bytes
-rw-r--r--infrastructure/lib/commons-io-1.4-sources.jarbin0 -> 163177 bytes
-rw-r--r--infrastructure/lib/commons-io-1.4.jarbin0 -> 109043 bytes
-rw-r--r--infrastructure/lib/commons-lang-2.4.jar (renamed from trunk/infrastructure/lib/commons-lang-2.4.jar)bin261809 -> 261809 bytes
-rw-r--r--infrastructure/lib/derby-10.5.1.1.jar (renamed from trunk/infrastructure/lib/derby-10.5.1.1.jar)bin2513361 -> 2513361 bytes
-rw-r--r--infrastructure/lib/derbytools.jar (renamed from trunk/infrastructure/lib/derbytools.jar)bin155796 -> 155796 bytes
-rw-r--r--infrastructure/lib/dnsjava-2.0.6.jar (renamed from trunk/infrastructure/lib/dnsjava-2.0.6.jar)bin268823 -> 268823 bytes
-rw-r--r--infrastructure/lib/java_uno-3.2.0.jarbin0 -> 4205 bytes
-rw-r--r--infrastructure/lib/jetty-6.1.20.jar (renamed from trunk/infrastructure/lib/jetty-6.1.20.jar)bin533605 -> 533605 bytes
-rw-r--r--infrastructure/lib/jetty-sslengine-6.1.20.jar (renamed from trunk/infrastructure/lib/jetty-sslengine-6.1.20.jar)bin18285 -> 18285 bytes
-rw-r--r--infrastructure/lib/jetty-util-6.1.20.jar (renamed from trunk/infrastructure/lib/jetty-util-6.1.20.jar)bin176016 -> 176016 bytes
-rw-r--r--infrastructure/lib/json.jar (renamed from trunk/infrastructure/lib/json.jar)bin42335 -> 42335 bytes
-rw-r--r--infrastructure/lib/juh-3.2.0.jarbin0 -> 55517 bytes
-rw-r--r--infrastructure/lib/jurt-3.2.0.jarbin0 -> 108138 bytes
-rw-r--r--infrastructure/lib/mail.jar (renamed from trunk/infrastructure/lib/mail.jar)bin356519 -> 356519 bytes
-rw-r--r--infrastructure/lib/manifest (renamed from trunk/infrastructure/lib/manifest)0
-rw-r--r--infrastructure/lib/rhino-js-1.7r1.jar (renamed from trunk/infrastructure/lib/rhino-js-1.7r1.jar)bin769000 -> 769000 bytes
-rw-r--r--infrastructure/lib/ridl-3.2.0.jarbin0 -> 256497 bytes
-rw-r--r--infrastructure/lib/sanselan-0.94aj.jar (renamed from trunk/infrastructure/lib/sanselan-0.94aj.jar)bin390426 -> 390426 bytes
-rw-r--r--infrastructure/lib/servlet-api-2.5-20081211.jar (renamed from trunk/infrastructure/lib/servlet-api-2.5-20081211.jar)bin134190 -> 134190 bytes
-rw-r--r--infrastructure/lib/tagsoup-1.2.jar (renamed from trunk/infrastructure/lib/tagsoup-1.2.jar)bin90023 -> 90023 bytes
-rw-r--r--infrastructure/lib/unoil-3.2.0.jarbin0 -> 1415707 bytes
-rw-r--r--infrastructure/lib/yuicompressor-2.4-appjet.jar (renamed from trunk/infrastructure/lib/yuicompressor-2.4-appjet.jar)bin574932 -> 574932 bytes
-rw-r--r--infrastructure/net.appjet.ajstdlib/ajstdlib.scala (renamed from trunk/infrastructure/net.appjet.ajstdlib/ajstdlib.scala)0
-rw-r--r--infrastructure/net.appjet.ajstdlib/sqlbase.scala (renamed from trunk/infrastructure/net.appjet.ajstdlib/sqlbase.scala)0
-rw-r--r--infrastructure/net.appjet.ajstdlib/streaming-client.js (renamed from trunk/infrastructure/net.appjet.ajstdlib/streaming-client.js)0
-rw-r--r--infrastructure/net.appjet.ajstdlib/streaming-iframe.html (renamed from trunk/infrastructure/net.appjet.ajstdlib/streaming-iframe.html)0
-rw-r--r--infrastructure/net.appjet.ajstdlib/streaming.scala (renamed from trunk/infrastructure/net.appjet.ajstdlib/streaming.scala)0
-rw-r--r--infrastructure/net.appjet.ajstdlib/timer.scala (renamed from trunk/infrastructure/net.appjet.ajstdlib/timer.scala)0
-rw-r--r--infrastructure/net.appjet.bodylock/bodylock.scala (renamed from trunk/infrastructure/net.appjet.bodylock/bodylock.scala)0
-rw-r--r--infrastructure/net.appjet.bodylock/compressor.scala (renamed from trunk/infrastructure/net.appjet.bodylock/compressor.scala)0
-rw-r--r--infrastructure/net.appjet.common.cli/cli.scala (renamed from trunk/infrastructure/net.appjet.common.cli/cli.scala)0
-rw-r--r--infrastructure/net.appjet.common.sars/sars.scala (renamed from trunk/infrastructure/net.appjet.common.sars/sars.scala)0
-rw-r--r--infrastructure/net.appjet.common.sars/sha1.scala (renamed from trunk/infrastructure/net.appjet.common.sars/sha1.scala)0
-rw-r--r--infrastructure/net.appjet.common/rhino/rhinospect.scala (renamed from trunk/infrastructure/net.appjet.common/rhino/rhinospect.scala)0
-rw-r--r--infrastructure/net.appjet.common/util/BCrypt.java (renamed from trunk/infrastructure/net.appjet.common/util/BCrypt.java)0
-rw-r--r--infrastructure/net.appjet.common/util/BetterFile.java (renamed from trunk/infrastructure/net.appjet.common/util/BetterFile.java)0
-rw-r--r--infrastructure/net.appjet.common/util/ClassReload.java (renamed from trunk/infrastructure/net.appjet.common/util/ClassReload.java)0
-rw-r--r--infrastructure/net.appjet.common/util/ExpiringMapping.java (renamed from trunk/infrastructure/net.appjet.common/util/ExpiringMapping.java)0
-rw-r--r--infrastructure/net.appjet.common/util/HttpServletRequestFactory.java (renamed from trunk/infrastructure/net.appjet.common/util/HttpServletRequestFactory.java)0
-rw-r--r--infrastructure/net.appjet.common/util/LenientFormatter.java (renamed from trunk/infrastructure/net.appjet.common/util/LenientFormatter.java)0
-rw-r--r--infrastructure/net.appjet.common/util/LimitedSizeMapping.java (renamed from trunk/infrastructure/net.appjet.common/util/LimitedSizeMapping.java)0
-rw-r--r--infrastructure/net.appjet.oui/ConfigParam.java (renamed from trunk/infrastructure/net.appjet.oui/ConfigParam.java)0
-rw-r--r--infrastructure/net.appjet.oui/FastJSON.scala (renamed from trunk/infrastructure/net.appjet.oui/FastJSON.scala)0
-rw-r--r--infrastructure/net.appjet.oui/GeneratedConfigParam.java (renamed from trunk/infrastructure/net.appjet.oui/GeneratedConfigParam.java)0
-rw-r--r--infrastructure/net.appjet.oui/config.scala245
-rw-r--r--infrastructure/net.appjet.oui/dynamicvar.scala (renamed from trunk/infrastructure/net.appjet.oui/dynamicvar.scala)0
-rw-r--r--infrastructure/net.appjet.oui/encryption.scala (renamed from trunk/infrastructure/net.appjet.oui/encryption.scala)0
-rw-r--r--infrastructure/net.appjet.oui/execution.scala660
-rw-r--r--infrastructure/net.appjet.oui/files.scala (renamed from trunk/infrastructure/net.appjet.oui/files.scala)0
-rw-r--r--infrastructure/net.appjet.oui/logging.scala (renamed from trunk/infrastructure/net.appjet.oui/logging.scala)0
-rw-r--r--infrastructure/net.appjet.oui/main.scala388
-rw-r--r--infrastructure/net.appjet.oui/monitoring.scala (renamed from trunk/infrastructure/net.appjet.oui/monitoring.scala)0
-rw-r--r--infrastructure/net.appjet.oui/network.scala (renamed from trunk/infrastructure/net.appjet.oui/network.scala)0
-rw-r--r--infrastructure/net.appjet.oui/servermodel.scala (renamed from trunk/infrastructure/net.appjet.oui/servermodel.scala)0
-rw-r--r--infrastructure/net.appjet.oui/stats.scala (renamed from trunk/infrastructure/net.appjet.oui/stats.scala)0
-rw-r--r--infrastructure/net.appjet.oui/synchronizer.scala (renamed from trunk/infrastructure/net.appjet.oui/synchronizer.scala)0
-rw-r--r--infrastructure/net.appjet.oui/util.scala (renamed from trunk/infrastructure/net.appjet.oui/util.scala)0
-rw-r--r--infrastructure/rhino1_7R1/apiClasses.properties (renamed from trunk/infrastructure/rhino1_7R1/apiClasses.properties)0
-rw-r--r--infrastructure/rhino1_7R1/build-date (renamed from trunk/infrastructure/rhino1_7R1/build-date)0
-rw-r--r--infrastructure/rhino1_7R1/build.properties (renamed from trunk/infrastructure/rhino1_7R1/build.properties)0
-rw-r--r--infrastructure/rhino1_7R1/build.xml (renamed from trunk/infrastructure/rhino1_7R1/build.xml)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/build.xml (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/build.xml)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/ClassDefinitionException.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/ClassDefinitionException.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/NotAFunctionException.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/NotAFunctionException.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/PropertyException.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/PropertyException.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/LogicalEquality.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/LogicalEquality.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/Namespace.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/Namespace.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/NamespaceHelper.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/NamespaceHelper.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/QName.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/QName.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XML.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XML.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLCtor.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLCtor.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLLibImpl.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLLibImpl.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLList.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLList.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLName.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLName.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLObjectImpl.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLObjectImpl.java)0
-rw-r--r--infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLWithScope.java (renamed from trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLWithScope.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/Control.java (renamed from trunk/infrastructure/rhino1_7R1/examples/Control.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/Counter.java (renamed from trunk/infrastructure/rhino1_7R1/examples/Counter.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/CounterTest.java (renamed from trunk/infrastructure/rhino1_7R1/examples/CounterTest.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/DynamicScopes.java (renamed from trunk/infrastructure/rhino1_7R1/examples/DynamicScopes.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/E4X/e4x_example.js (renamed from trunk/infrastructure/rhino1_7R1/examples/E4X/e4x_example.js)0
-rw-r--r--infrastructure/rhino1_7R1/examples/File.java (renamed from trunk/infrastructure/rhino1_7R1/examples/File.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/Foo.java (renamed from trunk/infrastructure/rhino1_7R1/examples/Foo.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/Matrix.java (renamed from trunk/infrastructure/rhino1_7R1/examples/Matrix.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/NervousText.html (renamed from trunk/infrastructure/rhino1_7R1/examples/NervousText.html)0
-rw-r--r--infrastructure/rhino1_7R1/examples/NervousText.js (renamed from trunk/infrastructure/rhino1_7R1/examples/NervousText.js)0
-rw-r--r--infrastructure/rhino1_7R1/examples/PrimitiveWrapFactory.java (renamed from trunk/infrastructure/rhino1_7R1/examples/PrimitiveWrapFactory.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/RunScript.java (renamed from trunk/infrastructure/rhino1_7R1/examples/RunScript.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/RunScript2.java (renamed from trunk/infrastructure/rhino1_7R1/examples/RunScript2.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/RunScript3.java (renamed from trunk/infrastructure/rhino1_7R1/examples/RunScript3.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/RunScript4.java (renamed from trunk/infrastructure/rhino1_7R1/examples/RunScript4.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/Shell.java (renamed from trunk/infrastructure/rhino1_7R1/examples/Shell.java)0
-rw-r--r--infrastructure/rhino1_7R1/examples/SwingApplication.js (renamed from trunk/infrastructure/rhino1_7R1/examples/SwingApplication.js)0
-rw-r--r--infrastructure/rhino1_7R1/examples/checkParam.js (renamed from trunk/infrastructure/rhino1_7R1/examples/checkParam.js)0
-rw-r--r--infrastructure/rhino1_7R1/examples/enum.js (renamed from trunk/infrastructure/rhino1_7R1/examples/enum.js)0
-rw-r--r--infrastructure/rhino1_7R1/examples/jsdoc.js (renamed from trunk/infrastructure/rhino1_7R1/examples/jsdoc.js)0
-rw-r--r--infrastructure/rhino1_7R1/examples/liveConnect.js (renamed from trunk/infrastructure/rhino1_7R1/examples/liveConnect.js)0
-rw-r--r--infrastructure/rhino1_7R1/examples/unique.js (renamed from trunk/infrastructure/rhino1_7R1/examples/unique.js)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/allclasses-frame.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/allclasses-frame.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/allclasses-noframe.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/allclasses-noframe.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/constant-values.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/constant-values.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/deprecated-list.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/deprecated-list.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/help-doc.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/help-doc.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/index-all.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/index-all.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/index.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/index.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Callable.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Callable.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassCache.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassCache.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassShutter.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassShutter.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/CompilerEnvirons.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/CompilerEnvirons.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Context.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Context.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextAction.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextAction.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.Listener.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.Listener.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EcmaError.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EcmaError.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ErrorReporter.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ErrorReporter.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EvaluatorException.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EvaluatorException.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Function.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Function.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/FunctionObject.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/FunctionObject.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/GeneratedClassLoader.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/GeneratedClassLoader.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ImporterTopLevel.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ImporterTopLevel.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/JavaScriptException.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/JavaScriptException.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RefCallable.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RefCallable.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RhinoException.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RhinoException.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Script.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Script.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Scriptable.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Scriptable.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ScriptableObject.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ScriptableObject.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/SecurityController.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/SecurityController.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Synchronizer.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Synchronizer.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrapFactory.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrapFactory.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrappedException.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrappedException.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Wrapper.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Wrapper.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/DebuggableScript.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/DebuggableScript.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-frame.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-frame.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-summary.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-summary.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-tree.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-tree.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/ClassCompiler.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/ClassCompiler.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-frame.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-frame.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-summary.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-summary.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-tree.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-tree.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-frame.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-frame.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-summary.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-summary.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-tree.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-tree.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableInputStream.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableInputStream.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableOutputStream.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableOutputStream.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-frame.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-frame.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-summary.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-summary.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-tree.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-tree.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/overview-frame.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/overview-frame.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/overview-summary.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/overview-summary.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/overview-tree.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/overview-tree.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/package-list (renamed from trunk/infrastructure/rhino1_7R1/javadoc/package-list)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/resources/inherit.gif (renamed from trunk/infrastructure/rhino1_7R1/javadoc/resources/inherit.gif)bin57 -> 57 bytes
-rw-r--r--infrastructure/rhino1_7R1/javadoc/serialized-form.html (renamed from trunk/infrastructure/rhino1_7R1/javadoc/serialized-form.html)0
-rw-r--r--infrastructure/rhino1_7R1/javadoc/stylesheet.css (renamed from trunk/infrastructure/rhino1_7R1/javadoc/stylesheet.css)0
-rw-r--r--infrastructure/rhino1_7R1/lib/jsr173_1.0_api.jar (renamed from trunk/infrastructure/rhino1_7R1/lib/jsr173_1.0_api.jar)bin23630 -> 23630 bytes
-rw-r--r--infrastructure/rhino1_7R1/lib/xbean.jar (renamed from trunk/infrastructure/rhino1_7R1/lib/xbean.jar)bin2664574 -> 2664574 bytes
-rw-r--r--infrastructure/rhino1_7R1/src/build.xml (renamed from trunk/infrastructure/rhino1_7R1/src/build.xml)0
-rw-r--r--infrastructure/rhino1_7R1/src/manifest (renamed from trunk/infrastructure/rhino1_7R1/src/manifest)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/classfile/ByteCode.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ByteCode.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/classfile/ClassFileWriter.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ClassFileWriter.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Arguments.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Arguments.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/BaseFunction.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/BaseFunction.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Callable.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Callable.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassCache.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassCache.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassShutter.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassShutter.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/CompilerEnvirons.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/CompilerEnvirons.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ConstProperties.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ConstProperties.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Context.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Context.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextAction.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextAction.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextFactory.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextFactory.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextListener.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextListener.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/DToA.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DToA.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Decompiler.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Decompiler.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefaultErrorReporter.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefaultErrorReporter.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefiningClassLoader.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefiningClassLoader.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Delegator.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Delegator.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/EcmaError.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EcmaError.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ErrorReporter.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ErrorReporter.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Evaluator.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Evaluator.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/EvaluatorException.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EvaluatorException.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Function.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Function.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionNode.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionNode.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionObject.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionObject.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/GeneratedClassLoader.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/GeneratedClassLoader.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionCall.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionCall.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionObject.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionObject.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdScriptableObject.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdScriptableObject.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ImporterTopLevel.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ImporterTopLevel.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterfaceAdapter.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterfaceAdapter.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpretedFunction.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpretedFunction.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpreterData.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpreterData.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaScriptException.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaScriptException.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Kit.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Kit.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/LazilyLoadedCtor.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/LazilyLoadedCtor.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeArray.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeArray.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeBoolean.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeBoolean.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeCall.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeCall.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeDate.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeDate.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeError.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeError.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeFunction.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeFunction.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGlobal.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGlobal.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeIterator.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeIterator.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaArray.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaArray.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaClass.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaClass.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaConstructor.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaConstructor.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaMethod.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaMethod.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaObject.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaObject.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaPackage.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaPackage.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaTopPackage.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaTopPackage.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeMath.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeMath.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeNumber.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeNumber.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeObject.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeObject.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeScript.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeScript.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeString.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeString.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeWith.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeWith.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/NodeTransformer.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NodeTransformer.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjArray.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjArray.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjToIntMap.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjToIntMap.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Parser.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Parser.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/PolicySecurityController.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/PolicySecurityController.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Ref.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Ref.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/RefCallable.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RefCallable.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/RegExpProxy.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RegExpProxy.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/RhinoException.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RhinoException.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Script.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Script.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptOrFnNode.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptOrFnNode.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptRuntime.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptRuntime.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Scriptable.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Scriptable.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptableObject.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptableObject.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecureCaller.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecureCaller.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityController.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityController.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityUtilities.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityUtilities.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/SpecialRef.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SpecialRef.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Synchronizer.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Synchronizer.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Token.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Token.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/TokenStream.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/TokenStream.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/UintMap.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UintMap.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Undefined.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Undefined.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/UniqueTag.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UniqueTag.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/VMBridge.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/VMBridge.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrapFactory.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrapFactory.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrappedException.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrappedException.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Wrapper.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Wrapper.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/continuations/Continuation.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/continuations/Continuation.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebugFrame.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebugFrame.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableObject.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableObject.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableScript.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableScript.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/Debugger.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/Debugger.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk11/VMBridge_jdk11.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk11/VMBridge_jdk11.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk13/VMBridge_jdk13.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk13/VMBridge_jdk13.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Block.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Block.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/ClassCompiler.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/ClassCompiler.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Codegen.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Codegen.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/DataFlowBitSet.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/DataFlowBitSet.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptFunctionNode.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptFunctionNode.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptRuntime.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptRuntime.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptTransformer.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptTransformer.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Optimizer.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Optimizer.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExp.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExp.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExpCtor.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExpCtor.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/RegExpImpl.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/RegExpImpl.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/SubString.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/SubString.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages.properties (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages.properties)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages_fr.properties (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages_fr.properties)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableInputStream.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableInputStream.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableOutputStream.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableOutputStream.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLLib.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLLib.java)0
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLObject.java (renamed from trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLObject.java)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/base.skip (renamed from trunk/infrastructure/rhino1_7R1/testsrc/base.skip)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/build.xml (renamed from trunk/infrastructure/rhino1_7R1/testsrc/build.xml)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/opt1.skip (renamed from trunk/infrastructure/rhino1_7R1/testsrc/opt1.skip)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java (renamed from trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java (renamed from trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java (renamed from trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html (renamed from trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/Bug409702Test.java (renamed from trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/Bug409702Test.java)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/JavaAcessibilityTest.java (renamed from trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/JavaAcessibilityTest.java)0
-rw-r--r--infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/PrivateAccessClass.java (renamed from trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/PrivateAccessClass.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/build.xml (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/build.xml)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/ToolErrorReporter.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/ToolErrorReporter.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Dim.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Dim.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/GuiCallback.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/GuiCallback.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Main.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Main.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/ScopeProvider.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/ScopeProvider.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/SwingGui.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/SwingGui.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/build.xml (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/build.xml)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/jsc/Main.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/jsc/Main.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java)0
-rw-r--r--infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java (renamed from trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/build.xml (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/build.xml)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java)0
-rw-r--r--infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java (renamed from trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java)0
-rw-r--r--infrastructure/yuicompressor/lib/jargs-1.0.jar (renamed from trunk/infrastructure/yuicompressor/lib/jargs-1.0.jar)bin11406 -> 11406 bytes
-rw-r--r--infrastructure/yuicompressor/lib/rhino-yuicompressor.jar (renamed from trunk/infrastructure/yuicompressor/lib/rhino-yuicompressor.jar)bin538064 -> 538064 bytes
-rwxr-xr-xinfrastructure/yuicompressor/make.sh (renamed from trunk/infrastructure/yuicompressor/make.sh)0
-rw-r--r--infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/Bootstrap.java (renamed from trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/Bootstrap.java)0
-rw-r--r--infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/CssCompressor.java (renamed from trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/CssCompressor.java)0
-rw-r--r--infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JarClassLoader.java (renamed from trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JarClassLoader.java)0
-rw-r--r--infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java (renamed from trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java)0
-rw-r--r--infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java (renamed from trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java)0
-rw-r--r--infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java (renamed from trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java)0
-rw-r--r--infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java (renamed from trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java)0
-rw-r--r--infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/YUICompressor.java (renamed from trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/YUICompressor.java)0
-rw-r--r--infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java (renamed from trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java)0
-rw-r--r--infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java (renamed from trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java)0
-rw-r--r--infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java (renamed from trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java)0
-rw-r--r--infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java (renamed from trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java)0
-rw-r--r--trunk/README290
-rwxr-xr-xtrunk/etherpad/bin/rebuildjar.sh75
-rwxr-xr-xtrunk/etherpad/bin/run-local.sh66
-rwxr-xr-xtrunk/etherpad/bin/setup-mysql-db.sh30
-rw-r--r--trunk/etherpad/etc/etherpad.changeme.properties16
-rw-r--r--trunk/etherpad/etc/etherpad.localdev-default.properties16
-rw-r--r--trunk/etherpad/lib/jbcrypt-0.2.jarbin26222 -> 0 bytes
-rw-r--r--trunk/etherpad/src/etherpad/collab/ace/domline.js210
-rw-r--r--trunk/etherpad/src/etherpad/collab/ace/easysync1.js923
-rw-r--r--trunk/etherpad/src/etherpad/collab/ace/easysync2.js1968
-rw-r--r--trunk/etherpad/src/etherpad/collab/ace/easysync2_tests.js877
-rw-r--r--trunk/etherpad/src/etherpad/control/admincontrol.js1471
-rw-r--r--trunk/etherpad/src/etherpad/control/pad/pad_control.js780
-rw-r--r--trunk/etherpad/src/etherpad/control/pro/admin/pro_admin_control.js283
-rw-r--r--trunk/etherpad/src/etherpad/control/static_control.js65
-rw-r--r--trunk/etherpad/src/etherpad/db_migrations/migration_runner.js147
-rw-r--r--trunk/etherpad/src/etherpad/globals.js41
-rw-r--r--trunk/etherpad/src/etherpad/helpers.js276
-rw-r--r--trunk/etherpad/src/etherpad/legacy_urls.js37
-rw-r--r--trunk/etherpad/src/etherpad/pad/model.js651
-rw-r--r--trunk/etherpad/src/etherpad/pad/padutils.js154
-rw-r--r--trunk/etherpad/src/etherpad/pne/pne_utils.js187
-rw-r--r--trunk/etherpad/src/etherpad/pro/pro_accounts.js496
-rw-r--r--trunk/etherpad/src/etherpad/pro/pro_utils.js165
-rw-r--r--trunk/etherpad/src/etherpad/sessions.js203
-rw-r--r--trunk/etherpad/src/etherpad/utils.js396
-rw-r--r--trunk/etherpad/src/main.js418
-rw-r--r--trunk/etherpad/src/static/css/beta.css49
-rw-r--r--trunk/etherpad/src/static/css/connection_diagnostics.css13
-rw-r--r--trunk/etherpad/src/static/css/fluxbb.css55
-rw-r--r--trunk/etherpad/src/static/css/home.css264
-rw-r--r--trunk/etherpad/src/static/css/pad.css1000
-rw-r--r--trunk/etherpad/src/static/css/pad2_ejs.css889
-rw-r--r--trunk/etherpad/src/static/css/pne-manual.css143
-rw-r--r--trunk/etherpad/src/static/css/pricing.css153
-rw-r--r--trunk/etherpad/src/static/css/pro/payment-required.css39
-rw-r--r--trunk/etherpad/src/static/css/stats.css71
-rw-r--r--trunk/etherpad/src/static/css/store/eepnet-checkout.css284
-rw-r--r--trunk/etherpad/src/static/css/store/ondemand-billing.css170
-rw-r--r--trunk/etherpad/src/static/css/store/store.css90
-rw-r--r--trunk/etherpad/src/static/img/about/appjet-logo-large.gifbin11045 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/appjet-logo-medium.pngbin4127 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/investors/mitchkapor.jpgbin30223 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/investors/pb.jpgbin23929 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/investors/pg.jpgbin28915 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/investors/sanjeev.jpgbin23342 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/investors/seth.jpgbin27346 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/aaron-david-iphones-thumb.jpgbin145654 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/aaron-david-iphones.jpgbin145654 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/aaron-google-air.jpgbin163592 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/aaron-headshot-thumb.jpgbin11310 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/aaron-headshot.jpgbin83517 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/aaron-headshot2-thumb.jpgbin29884 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/aaron-headshot2.jpgbin99738 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/aaron-headshot3-thumb.jpgbin27864 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/aaron-headshot3.jpgbin195114 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/daniel-headshot-thumb.jpgbin21991 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/david-headshot-thumb.jpgbin18650 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/david-headshot.jpgbin63296 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/davy-headshot.jpgbin20175 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/jd-headshot-thumb.jpgbin13008 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/jd-headshot.jpgbin37777 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/rhonda-headshot-thumb.jpgbin17360 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/people/rhonda-headshot.jpgbin133259 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/pier38.pngbin66877 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/quote-close.pngbin1361 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/quote-open.pngbin1341 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/about/screencastpreview800x600.jpgbin248364 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/account/betawarn.jpgbin13535 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/acecarets/000000.gifbin41 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/acecarets/666666.gifbin41 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/acecarets/999999.gifbin41 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/acecarets/default.gifbin43 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/backgrad.pngbin2276 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/black35.pngbin221 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/blank.gifbin129 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/modalbar.gifbin145 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/newpadicon.gifbin89 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/shadbot.pngbin149 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/shadleft.pngbin142 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/shadleftbot.pngbin172 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/shadlefttop.pngbin929 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/shadright.pngbin136 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/shadrightbot.pngbin174 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/shadrighttop.pngbin954 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/topbar.gifbin180 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/topbarlogo.gifbin1784 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/widthfull.gifbin104 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/widthfullactive.gifbin104 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/widthlim.gifbin102 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/apr09/widthlimactive.gifbin102 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/billing/amex.gifbin995 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/billing/creditcard.gifbin1229 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/billing/csc-help.gifbin9430 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/billing/disc.gifbin370 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/billing/invoice.gifbin424 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/billing/mc.gifbin1370 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/billing/paypal.gifbin812 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/billing/visa.gifbin724 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/blog/posts/new-features/fullwidth.gifbin7328 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/blog/posts/new-features/importexport.gifbin9758 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/blog/posts/new-features/richtext.gifbin2146 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/blog/posts/new-features/viewzoom.gifbin8257 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/blog/posts/pricing-survey-results.pngbin12994 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/blog/posts/pricing-survey.pngbin10589 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/blog/posts/time-slider-screenshot.gifbin6544 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/bg/home-features-bottom.gifbin308 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/bg/home-features-free-bottom.gifbin298 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/bg/home-features-paid-top.gifbin459 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/bg/home-features-top.gifbin489 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/bg/home-nav-selected.pngbin195 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/bg/home-screencast.pngbin5738 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/bg/home2.pngbin367 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/bg/product-nav-selected-white.pngbin196 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/bg/product-nav-selected.pngbin198 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/createpad-home.gifbin5839 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/createpad-large.gifbin6614 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/intro-screencast.pngbin815 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/intro-testimonials.pngbin816 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/learnmore.gifbin3103 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/signup-home-2.gifbin5827 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/signup-home-3.gifbin5735 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/signup-home-4.gifbin5818 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/signup-home.gifbin5815 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/btn/uses-more.gifbin1485 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/32/114.pngbin2424 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/32/15.pngbin2904 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/32/65.pngbin3028 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/32/78.pngbin2208 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/bullet.gifbin55 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/home-logo2.gifbin7136 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/home-screencast.pngbin65832 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/plane.gifbin56 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/product-logo.gifbin2222 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/screenshot.gifbin23708 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/use-meetings.gifbin10521 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/use-meetings.pngbin25506 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/use-programming.gifbin13655 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/use-programming.pngbin56154 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/use-writing.gifbin22275 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/gfx/use-writing.pngbin38264 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/davy/txt/home-button.gifbin4749 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/featuretour/code.gifbin27794 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/featuretour/edits.gifbin24788 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/featuretour/editsandusers.gifbin21815 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/featuretour/padlock.pngbin13061 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/featuretour/revisions.gifbin20820 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/featuretour/users.gifbin8843 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/framedheaderback.gifbin606 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/framedheaderlogo.gifbin8177 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/home_firstp.gifbin7754 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/home_firstp.pngbin15320 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/home_firstp2.gifbin7919 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/home_h1.gifbin11332 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/home_h1.pngbin28857 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/home_newpadbutton.gifbin6828 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/home_newpadbutton.pngbin10554 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/home_newpadbutton2.gifbin7112 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/home_newpadbutton_eepnet.gifbin5442 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/hometop_back.gifbin2743 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/nav1.gifbin10901 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/nav1_back.gifbin150 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/nav2.gifbin17028 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/feb09/screencast.gifbin20091 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/home/etherpad-mainheader1.jpgbin48871 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/home/headergradient.gifbin246 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/home/homeheader1.jpgbin33227 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/home/homeheader2.jpgbin33259 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/home/leftgrad.gifbin113 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/home/pencilpaperback.pngbin83487 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/home/screencapture1.gifbin106694 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/home/underdevicon.gifbin98 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/icon/downarrow.gifbin376 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/icon/feed.gifbin1135 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/bottomareagfx.gifbin1045 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/colorpicker.gifbin1806 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/connectionindicator.gifbin1185 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/docbarstates.pngbin3314 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/docbarstates2.pngbin4902 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/docbarstates3.pngbin4990 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/docpaneledge.pngbin589 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/docpanelmiddle.pngbin240 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/editbar.gifbin4667 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/editbar2.gifbin9156 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/overlay.pngbin141 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/padtop.gifbin8055 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/padtop2.gifbin6168 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/padtop3.gifbin7511 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/padtop4.gifbin8192 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/padtop5.pngbin18850 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/padtop5.xcfbin66525 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/padtopback.gifbin553 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/padtopback2.gifbin384 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/public.gifbin1141 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/sharebox2.gifbin8836 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/sharebox3.gifbin6056 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/jun09/pad/syncing2.gifbin172 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/bold.gifbin70 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/doc.pngbin3317 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/html.pngbin3468 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/italic.gifbin73 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/leftarrow.gifbin1016 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/leftarrow2.gifbin950 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/link.gifbin622 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/link.pngbin3323 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/odt.gifbin405 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/odt.pngbin3341 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/padlock.gifbin1053 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/padlockopen.gifbin109 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/passwordlocked.gifbin1053 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/passwordlocked_cropped.gifbin114 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/passwordnone.gifbin636 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/paypal.gifbin3794 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/pdf.pngbin3320 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/redo.gifbin78 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/txt.pngbin3139 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/underline.gifbin81 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/may09/undo.gifbin79 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/miniplane.gifbin70 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/misc/diagnostic-links.gifbin10132 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/misc/traclogo.gifbin5684 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/atlonglast.gifbin4901 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/banner1.jpgbin19897 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/banner2.jpgbin45052 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/banner3.jpgbin38726 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/banner4.jpgbin39563 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/banner5.gifbin24046 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/banner6.gifbin23655 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/banner7.gifbin24352 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/banner8.gifbin24724 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/banner9.gifbin24363 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/bannerback5.gifbin2957 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/bannerback6.gifbin2140 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/bodyback1.gifbin488 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/bodyback2.gifbin560 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/bodyback3.gifbin608 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/bodyback4.gifbin964 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/bodyback5.gifbin579 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/bodybacktop1.gifbin2991 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/computers.gifbin27542 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/computers2.gifbin27434 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/glossyblue.gifbin1521 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/glossyblue2.gifbin994 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/glossyblueh.gifbin920 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/insetrect.gifbin7056 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minilogo1-05e.gifbin2201 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minilogo1-07f.gifbin2252 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minilogo3.jpgbin12805 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minitopback1.gifbin954 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minitopback2.gifbin1598 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minitopbar1-05e.gifbin284 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minitopbar2-05e.gifbin330 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minitopbar2-07f.gifbin330 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minitopbar3.jpgbin12805 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minitopbar4.gifbin2818 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minitoplogo1.gifbin4184 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/minitoplogo2.gifbin3255 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/newpadmain.gifbin1172 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/newpadmainback.gifbin801 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/newpadmainbackh.gifbin801 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/pageshot.pngbin151570 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/pageshotmini.pngbin80505 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/sidehead-gradhilite.gifbin288 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/tinytriangle.gifbin62 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/topnav1.gifbin12521 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/topnav2.gifbin11286 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/topnav3.gifbin12363 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/topnav4.gifbin11803 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/topnav5.gifbin11650 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/topnav6.gifbin11295 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/topnavback1.gifbin1594 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/topnavback2.gifbin1299 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/topnavback3.gifbin380 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/usecasesnavdown.gifbin1388 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/usecasesnavdownh.gifbin1337 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/usecasesnavup.gifbin1119 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/usecasesnavuph.gifbin720 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/oct/watchscreencast.gifbin25840 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/animated-orb-orange-12.gifbin2614 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/backgrad.pngbin1290 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-eee-20.gifbin1052 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-20.gifbin1052 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-40.gifbin1009 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-60.gifbin1123 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/backshadow/botshadow-940-20-eee-20.gifbin1746 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/etherpad-logo-small-grad.gifbin1537 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/etherpad-logo-small.gifbin6664 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/etherpad-logo-small2.gifbin6646 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/expandy-arrow-down.gifbin500 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/expandy-arrow-right.gifbin296 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/expandy-arrow6-down-active.gifbin57 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/expandy-arrow6-down.gifbin57 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/expandy-arrow6-right-active.gifbin61 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/expandy-arrow6-right.gifbin61 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/header-revgrad.gifbin598 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/newpad.gifbin251 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/orb-greenred-12.gifbin1105 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/padbg1.jpgbin120888 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/padbg2.jpgbin44119 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/padbg3.jpgbin12577 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/padbg4.jpgbin12696 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/padbg5.jpgbin8158 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/padhead1.jpgbin13413 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/padhead2.jpgbin14104 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/padhead3.jpgbin6750 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/pencil-icon-small-blue.gifbin84 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/sidehead-grad.gifbin292 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/button_depressed.pngbin4610 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/button_undepressed.pngbin4625 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/crushed_pause.pngbin2876 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/crushed_play.pngbin2946 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/crushed_play_button.pngbin4305 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/current_location.gifbin1502 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/pause.gifbin3320 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/play.gifbin3297 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/star.gifbin3511 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pad/timeslider/timeslider_mockup.pngbin4860 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pricing/free.gifbin7419 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pricing/group.gifbin6783 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pricing/on-demand.gifbin5791 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pricing/private-network.gifbin4677 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pricing/support.gifbin2028 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pro/billing/cards-button.gifbin9524 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/pro/header/pro-header-back.gifbin213 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/tinyplane.gifbin59 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/img/wavejet.jpgbin55379 -> 0 bytes
-rw-r--r--trunk/etherpad/src/static/js/broadcast.js607
-rw-r--r--trunk/etherpad/src/static/js/colorutils.js91
-rw-r--r--trunk/etherpad/src/static/js/cssmanager_client.js88
-rw-r--r--trunk/etherpad/src/static/js/domline_client.js210
-rw-r--r--trunk/etherpad/src/static/js/easysync2_client.js1777
-rw-r--r--trunk/etherpad/src/static/js/pad.js.old1984
-rw-r--r--trunk/etherpad/src/static/js/store.js116
-rwxr-xr-xtrunk/etherpad/src/static/swf/vidplayer.swfbin41390 -> 0 bytes
-rw-r--r--trunk/etherpad/src/templates/beta/signup.ejs63
-rw-r--r--trunk/etherpad/src/templates/email/eepnet_purchase_receipt.ejs93
-rw-r--r--trunk/etherpad/src/templates/email/pro_beta_invite.ejs23
-rw-r--r--trunk/etherpad/src/templates/email/pro_payment_failure.ejs26
-rw-r--r--trunk/etherpad/src/templates/email/pro_payment_receipt.ejs55
-rw-r--r--trunk/etherpad/src/templates/framed/framedheader-pro.ejs76
-rw-r--r--trunk/etherpad/src/templates/main/home.ejs58
-rw-r--r--trunk/etherpad/src/templates/pad/create_body_rafter.ejs23
-rw-r--r--trunk/etherpad/src/templates/pad/pad_body.ejs69
-rw-r--r--trunk/etherpad/src/templates/pad/pad_download_link.ejs27
-rw-r--r--trunk/etherpad/src/templates/pad/padslider_body.ejs41
-rw-r--r--trunk/etherpad/src/templates/pad/total_users_exceeded.ejs29
-rw-r--r--trunk/etherpad/src/templates/pro/account/create-admin-account.ejs37
-rw-r--r--trunk/etherpad/src/templates/pro/account/global-multi-domain-recover-email.ejs27
-rw-r--r--trunk/etherpad/src/templates/pro/account/guest-knock.ejs27
-rw-r--r--trunk/etherpad/src/templates/pro/account/signin-guest.ejs51
-rw-r--r--trunk/etherpad/src/templates/pro/admin/admin.ejs15
-rw-r--r--trunk/etherpad/src/templates/pro/admin/billing-invoices.ejs45
-rw-r--r--trunk/etherpad/src/templates/pro/admin/manage-billing.ejs35
-rw-r--r--trunk/etherpad/src/templates/pro/admin/pne-config.ejs33
-rw-r--r--trunk/etherpad/src/templates/pro/admin/pne-dashboard.ejs40
-rw-r--r--trunk/etherpad/src/templates/pro/admin/pne-shell.ejs33
-rw-r--r--trunk/etherpad/src/templates/pro/admin/single-invoice.ejs47
-rw-r--r--trunk/etherpad/src/templates/pro/pro-payment-required.ejs51
-rw-r--r--trunk/etherpad/src/templates/statistics/stat_page.ejs89
-rw-r--r--trunk/etherpad/src/templates/store/csc-help.ejs23
-rw-r--r--trunk/etherpad/src/templates/store/eepnet-checkout/billing-info.ejs183
-rw-r--r--trunk/etherpad/src/templates/store/eepnet-checkout/cart.ejs119
-rw-r--r--trunk/etherpad/src/templates/store/eepnet-checkout/checkout-template.ejs38
-rw-r--r--trunk/etherpad/src/templates/store/eepnet-checkout/confirmation.ejs33
-rw-r--r--trunk/etherpad/src/templates/store/eepnet-checkout/license-info.ejs40
-rw-r--r--trunk/etherpad/src/templates/store/eepnet-checkout/purchase.ejs33
-rw-r--r--trunk/etherpad/src/templates/store/eepnet-checkout/receipt.ejs43
-rw-r--r--trunk/etherpad/src/templates/store/eepnet-checkout/summary.ejs91
-rw-r--r--trunk/etherpad/src/templates/store/eepnet-checkout/support-contract.ejs41
-rw-r--r--trunk/etherpad/src/templates/store/eepnet_download.ejs43
-rw-r--r--trunk/etherpad/src/templates/store/eepnet_eval_nextsteps.ejs40
-rw-r--r--trunk/etherpad/src/templates/store/eepnet_eval_signup.ejs125
-rwxr-xr-xtrunk/infrastructure/ace/bin/make337
-rw-r--r--trunk/infrastructure/ace/www/ace2_inner.js4817
-rw-r--r--trunk/infrastructure/ace/www/ace2_outer.js214
-rw-r--r--trunk/infrastructure/ace/www/domline.js210
-rw-r--r--trunk/infrastructure/ace/www/linestylefilter.js253
-rw-r--r--trunk/infrastructure/bin/compilecache.sh64
-rwxr-xr-xtrunk/infrastructure/bin/makejar.sh74
-rw-r--r--trunk/infrastructure/com.etherpad.openofficeservice/importexport.scala189
-rw-r--r--trunk/infrastructure/com.etherpad/licensing.scala169
-rw-r--r--trunk/infrastructure/framework-src/modules/ejs.js471
-rw-r--r--trunk/infrastructure/framework-src/modules/execution.js58
-rw-r--r--trunk/infrastructure/framework-src/modules/faststatic.js318
-rw-r--r--trunk/infrastructure/framework-src/modules/sqlbase/sqlobj.js505
-rw-r--r--trunk/infrastructure/net.appjet.oui/config.scala240
-rw-r--r--trunk/infrastructure/net.appjet.oui/execution.scala654
-rw-r--r--trunk/infrastructure/net.appjet.oui/main.scala386
-rw-r--r--trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java.orig910
-rw-r--r--trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig2159
-rw-r--r--trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java.orig417
-rw-r--r--trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java.orig1398
1228 files changed, 21668 insertions, 34143 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cc959da
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+*~
+etherpad/etc/etherpad.local.properties
+etherpad/src/etherpad/collab/ace/contentcollector.js
+etherpad/src/etherpad/collab/ace/domline.js
+etherpad/src/etherpad/collab/ace/easysync1.js
+etherpad/src/etherpad/collab/ace/easysync2.js
+etherpad/src/etherpad/collab/ace/easysync2_tests.js
+etherpad/src/etherpad/collab/ace/linestylefilter.js
+etherpad/src/static/js/ace.js
+etherpad/src/static/js/colorutils.js
+etherpad/src/static/js/cssmanager_client.js
+etherpad/src/static/js/domline_client.js
+etherpad/src/static/js/easysync2_client.js
+etherpad/src/static/js/linestylefilter_client.js
+etherpad/*.log
+infrastructure/lib/cos.jar
+build-arch-stamp
+build-indep-stamp
+configure-stamp
+infrastructure/lib/mysql-connector*.jar
+debian/etherpad.debhelper.log
+debian/etherpad.*.debhelper
+debian/etherpad.substvars
+debian/etherpad
+debian/files
+build-stamp
diff --git a/trunk/COPYING b/COPYING
index d645695..d645695 100644
--- a/trunk/COPYING
+++ b/COPYING
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..7d7985e
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,31 @@
+Installation instructions:
+
+* Install the dependencies: Scala 2.7, Sun Java JDK 6, libmysql-java
+
+* Uninstall gcj if it's installed as it seems to interfere with the
+ Scala compiler. You can safely reinstall it after compiling Etherpad
+ if you want to.
+
+* Edit the files bin/build.sh and bin/run.sh (and optionally
+ bin/etherpad.init.d) and change the paths to match your system.
+
+* Run bin/build.sh
+
+* Create a new user on your system called "etherpad"
+
+* Create a MySQL database "etherpad" and a database user "etherpad"
+
+* Copy etherpad/etc/etherpad.localdev-default.properties to etherpad/etc/etherpad.local.properties
+
+* Edit etherpad/etc/etherpad.local.properties and set
+ etherpad.SQL_JDBC_URL
+ Example etherpad.SQL_JDBC_URL = jdbc:mysql://localhost:3306/etherpad
+ etherpad.SQL_PASSWORD
+ etherpad.SQL_USERNAME = etherpad
+ etherpad.adminPass
+ topdomains
+ Example: topdomains = yourhostname.com,localhost
+
+* Create a link to bin/etherpad.init.d from /etc/init.d/etherpad
+
+* Run /etc/init.d/etherpad start
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c069ad6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,284 @@
+This distribution includes some code written by other organizations.
+The rest is Copyright 2007-2009 Google Inc. and licensed under the Apache License 2.0.
+
+>>>>>>>>>>>>>>
+Apache Commons Lang
+Copyright 2001-2008 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
+=========================================================================
+== NOTICE file corresponding to section 4(d) of the Apache License, ==
+== Version 2.0, in this case for the Apache Derby distribution. ==
+=========================================================================
+
+>>>>>>>>>>>>>>
+Apache Derby
+Copyright 2004-2008 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
+Portions of Derby were originally developed by
+International Business Machines Corporation and are
+licensed to the Apache Software Foundation under the
+"Software Grant and Corporate Contribution License Agreement",
+informally known as the "Derby CLA".
+The following copyright notice(s) were affixed to portions of the code
+with which this file is now or was at one time distributed
+and are placed here unaltered.
+
+(C) Copyright 1997,2004 International Business Machines Corporation. All rights reserved.
+
+(C) Copyright IBM Corp. 2003.
+
+The portion of the functionTests under 'nist' was originally
+developed by the National Institute of Standards and Technology (NIST),
+an agency of the United States Department of Commerce, and adapted by
+International Business Machines Corporation in accordance with the NIST
+Software Acknowledgment and Redistribution document at
+http://www.itl.nist.gov/div897/ctg/sql_form.htm
+
+>>>>>>>>>>>>>>
+Apache Harmony
+Copyright 2006, 2009 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+Portions of Apache Harmony were originally developed by
+Intel Corporation and are licensed to the Apache Software
+Foundation under the "Software Grant and Corporate Contribution
+License Agreement" and for which the following copyright notices
+apply
+ (C) Copyright 2005 Intel Corporation
+ (C) Copyright 2005-2006 Intel Corporation
+ (C) Copyright 2006 Intel Corporation
+
+>>>>>>>>>>>>>>
+==============================================================
+ Jetty Web Container
+ Copyright 1995-2006 Mort Bay Consulting Pty Ltd
+==============================================================
+
+The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd
+unless otherwise noted. It is licensed under the apache 2.0
+license.
+
+The javax.servlet package used by Jetty is copyright
+Sun Microsystems, Inc and Apache Software Foundation. It is
+distributed under the Common Development and Distribution License.
+You can obtain a copy of the license at
+https://glassfish.dev.java.net/public/CDDLv1.0.html.
+
+The UnixCrypt.java code ~Implements the one way cryptography used by
+Unix systems for simple password protection. Copyright 1996 Aki Yoshida,
+modified April 2001 by Iris Van den Broeke, Daniel Deville.
+Permission to use, copy, modify and distribute UnixCrypt
+for non-commercial or commercial purposes and without fee is
+granted provided that the copyright notice appears in all copies.
+
+The default JSP implementation is provided by the Glassfish JSP engine
+from project Glassfish http://glassfish.dev.java.net. Copyright 2005
+Sun Microsystems, Inc. and portions Copyright Apache Software Foundation.
+
+Some portions of the code are Copyright:
+ 2006 Tim Vernum
+ 1999 Jason Gilbert.
+
+The jboss integration module contains some LGPL code.
+
+The win32 Java Service Wrapper (v3.2.3) is Copyright (c) 1999, 2006
+Tanuki Software, Inc. and 2001 Silver Egg Technology. It is
+covered by an open license which is viewable at
+http://svn.codehaus.org/jetty/jetty/branches/jetty-6.1/extras/win32service/LICENSE.txt
+
+>>>>>>>>>>>>>>
+Apache Sanselan
+Copyright 2007-2009 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+>>>>>>>>>>>>>>
+TagSoup
+Copyright 2002-2008 by John Cowan
+
+>>>>>>>>>>>>>>
+dnsjava:
+
+Copyright (c) 1999-2005, Brian Wellington
+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 dnsjava project nor the names of its 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.
+
+>>>>>>>>>>>>>>
+jBCrypt:
+
+Copyright (c) 2006 Damien Miller
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+>>>>>>>>>>>>>>
+Scala:
+
+Copyright (c) 2002-2009 EPFL, Lausanne, unless otherwise specified.
+All rights reserved.
+
+This software was developed by the Programming Methods Laboratory of the
+Swiss Federal Institute of Technology (EPFL), Lausanne, Switzerland.
+
+Permission to use, copy, modify, and distribute this software in source
+or binary form for any purpose with or without fee is hereby granted,
+provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. 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.
+
+ 3. Neither the name of the EPFL nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+
+>>>>>>>>>>>>>>
+YUI Compressor:
+
+Copyright (c) 2009, Yahoo! Inc.
+All rights reserved.
+
+Redistribution and use of this software 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 Yahoo! Inc. nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission of Yahoo! Inc.
+
+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.
+
+>>>>>>>>>>>>>>
+jQuery
+Copyright (c) 2009 John Resig, http://jquery.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.
+
+>>>>>>>>>>>>>>
+jQuery Pulse:
+
+Copyright (c) 2008 James Padolsey - jp(at)qd9(dot)co.uk | http://james.padolsey.com / http://enhance.qd-creative.co.uk
+
+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.
+
+>>>>>>>>>>>>>>
+SWFObject v1.5
+Copyright (c) 2007 Geoff Stearns
+
+Licensed under the MIT License
+
+>>>>>>>>>>>>>>
+jQuery Context Menu Plugin:
+
+Original version copyright 2008 A Beautiful Site, LLC. Modifications by AppJet, Inc. released under the same license.
+
+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.
+
+>>>>>>>>>>>>>>
+c3p0
+Copyright (c) 2006 Machinery for Change, Inc.
+
+Licensed under the LGPL 2.1
+
+>>>>>>>>>>>>>>
+JCommon, JFreeChart
+Copyright (c) 2007-2009 Object Refinery Limited
+
+Licensed under the LGPL 2.1
+
+>>>>>>>>>>>>>>
+Mozilla Rhino
+
+Licensed under the MPL 1.1, GPL 2.0 or later
+
+
+>>>>>>>>>>>>>>
+MySQL Connector
+
+Licensed uder the GPL 2.0 or later with the FOSS exception
diff --git a/README.hooks b/README.hooks
new file mode 100644
index 0000000..d15949c
--- /dev/null
+++ b/README.hooks
@@ -0,0 +1,24 @@
+Hooks that plugins can provide
+
+All hooks must return either undefined/null or a list of return values. This might be an empty list or a list of just one value.
+
+handlePath
+ Registers new urls to serve
+ Parameters: None
+ Returns: Parameter suitable for Dispatcher
+renderPageBodyPre
+ Adds extra html before the body of a page
+ Parameters: bodyFileName, data, plugin
+ Returns: String(s) of html
+renderPageBodyPost
+ Adds extra html after the body of a page
+ Parameters: bodyFileName, data, plugin
+ Returns: String(s) of html
+serverStartup
+ Run right after server startup
+ Parameters: None
+ Returns: None
+serverShutdown
+ Run before server shutdown
+ Parameters: None
+ Returns: None
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c60e847
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# About Etherpad
+EtherPad is a web-based realtime collaborative document editor.
+
+EtherPad currently lives at <http://etherpad.org>
+
+For instructions to build and run EtherPad, see: <http://doc.etherpad.org/ep/tag/?query=installation>
diff --git a/bin/build.sh b/bin/build.sh
new file mode 100755
index 0000000..7aa70e3
--- /dev/null
+++ b/bin/build.sh
@@ -0,0 +1,40 @@
+#! /bin/bash
+
+################################################################################
+#
+# Copyright (c) 2010 penSec.IT UG (haftungsbeschränkt)
+# http://www.pensec.it
+# mail@pensec.it
+# Copyright (c) 2010 Egil Möller <egil.moller@piratpartiet.se>
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); 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 "AS IS" 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.
+#
+################################################################################
+
+#####
+# You have to change following lines to your requirements:
+#
+export JAVA_HOME="/usr/lib/jvm/java-6-sun/"
+export SCALA_HOME="/usr/share/java"
+export SCALA_LIBRARY_JAR="/usr/share/java/scala-library.jar"
+export MYSQL_CONNECTOR_JAR="/usr/share/java/mysql-connector-java.jar"
+export JAVA="/usr/lib/jvm/java-6-sun/bin/java"
+export SCALA="/usr/bin/scala"
+export PATH="/usr/lib/jvm/java-6-sun/bin:$PATH"
+#####
+
+# Rebuild jar
+( cd infrastructure; ./bin/makejar.sh; )
+( cd infrastructure/ace; bin/make normal etherpad; )
+cp infrastructure/build/appjet.jar etherpad/appjet-eth-dev.jar
+rm -rf infrastructure/{appjet,build,buildjs,buildcache}
diff --git a/bin/run.sh b/bin/run.sh
new file mode 100755
index 0000000..bd46b79
--- /dev/null
+++ b/bin/run.sh
@@ -0,0 +1,15 @@
+#! /bin/bash
+
+#####
+# You have to change following lines to your requirements:
+#
+export JAVA_HOME="/usr/lib/jvm/java-6-sun/"
+export SCALA_HOME=/usr/share/java
+export MYSQL_CONNECTOR_JAR=/usr/share/java/mysql-connector-java.jar
+export JAVA="/usr/lib/jvm/java-6-sun/bin/java"
+export SCALA="/usr/bin/scala"
+export PATH="/usr/lib/jvm/java-6-sun/bin:$PATH"
+#####
+
+cd etherpad
+exec bin/run-local.sh
diff --git a/branches/test.txt b/branches/test.txt
deleted file mode 100644
index faab00e..0000000
--- a/branches/test.txt
+++ /dev/null
@@ -1 +0,0 @@
-this is a test.
diff --git a/debian/README b/debian/README
new file mode 100644
index 0000000..21f1d88
--- /dev/null
+++ b/debian/README
@@ -0,0 +1,6 @@
+The Debian Package etherpad
+----------------------------
+
+Comments regarding the Package
+
+ -- Egil Möller <egil.moller@piratpartiet.se> Mon, 26 Apr 2010 19:51:51 +0200
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..a43df1b
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,17 @@
+etherpad (1.0.1) karmic; urgency=low
+
+ * Changed maintainer to Packaging
+
+ -- Etherpad Foundation (Packaging) <packaging@etherpad.org> Mon, 10 May 2010 19:22:19 +0200
+
+etherpad (1.0fixed) karmic; urgency=low
+
+ * Fixed installation scripts
+
+ -- Mikko Rantalainen <mikko.rantalainen@peda.net> Tue, 04 May 2010 12:57:28 +0300
+
+etherpad (1.0) unstable; urgency=low
+
+ * Initial Release.
+
+ -- Egil Möller <egil.moller@piratpartiet.se> Mon, 26 Apr 2010 19:51:51 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/debian/config b/debian/config
new file mode 100644
index 0000000..f97ab33
--- /dev/null
+++ b/debian/config
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+################################################################################
+#
+# Copyright (c) 2010 penSec.IT UG (haftungsbeschränkt)
+# http://www.pensec.it
+# mail@pensec.it
+# Copyright (c) 2010 Egil Möller <egil.moller@piratpartiet.se>
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); 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 "AS IS" 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.
+#
+################################################################################
+
+
+
+set -e
+. /usr/share/debconf/confmodule
+
+if [ -n "$ETHERPAD_DEBUG" ]; then
+ echo "now debugging $0 $@"
+ set -x
+fi
+
+db_version 2.0
+
+# Set up database
+. /usr/share/dbconfig-common/dpkg/config.mysql
+dbc_go etherpad $@
+
+db_input high "etherpad/admin_password" || true
+db_go
+
+db_get "etherpad/topdomains"
+if ! [ "$RET" ]; then
+ db_set "etherpad/topdomains" "$(hostname -f)"
+fi
+
+db_input high "etherpad/topdomains" || true
+db_go
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..feb76f6
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,21 @@
+Source: etherpad
+Section: contrib/httpd
+Priority: extra
+Maintainer: Etherpad Foundation (Packaging) <packaging@etherpad.org>
+Build-Depends: po-debconf, debhelper (>= 7)
+Build-Depends-indep: dbconfig-common, sun-java6-jdk, mysql-client, libmysql-java, scala (>= 2.7), scala-library (>= 2.7)
+Build-Conflicts: libgcj-common, java-gcj-compat-headless, java-gcj-compat, gcj-4.3-base
+Standards-Version: 3.8.4
+Homepage: http://github.com/ether/pad
+
+Package: etherpad
+Architecture: all
+Depends: ${misc:Depends}, sun-java6-jdk, mysql-client, libmysql-java, scala (>= 2.7), mysql-server, m4
+Pre-Depends: dbconfig-common, debconf, adduser
+Description: A web-based word processor that allows people to work
+ together in real-time.
+ .
+ When multiple people edit the same document simultaneously, any changes are
+ instantly reflected on everyone's screen. The result is a new and productive
+ way to collaborate on text documents, useful for meeting notes, drafting
+ sessions, education, team programming, and more.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..2fb4a07
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,52 @@
+This package was debianized by Egil Möller <egil.moller@piratpartiet.se> on
+Mon, 26 Apr 2010 19:51:51 +0200 and further fixed by Mikko Rantalainen.
+
+It was downloaded from http://github.com/ether/pad
+
+Upstream Author(s):
+
+ Aaron Iba <aaroniba@gmail.com>
+ Chris Ball <cjb@laptop.org>
+ Dan Bentley <dtbentley@gmail.com>
+ David Greenspan <davidgreenspan@gmail.com>
+ Egil Moeller <egil.moller@freecode.no>
+ Elliot Kroo <elliot@kroo.net>
+ Jeff Mitchell <etherpad@jefferai.org>
+ Jeppe Toustrup <jeppe@tenzer.dk>
+ Michael Prasuhn <mike@mikeyp.net>
+ Mikko Rantalainen <mikko.rantalainen@peda.net>
+ penSec.IT UG (haftungsbeschränkt) <etherpad@pensec.it>
+ Per Andersson <avtobiff@gmail.com>
+ Peter Martischka <pita@googlemail.com>
+ Unknown <root@primarypad.com>
+ Simon Bohlin <simon.bohlin@gmail.com>
+ Simon B @piratpartiet <simonb@redhog.org>
+
+Copyright:
+
+ Copyright (C) 2007-2009 Google Inc.
+ Copyright (C) 2009-2010 upstream authors, see above
+
+License:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted under the terms of the BSD License.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ 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 "AS IS" 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.
+
+On Debian systems, the complete text of the Apache 2.0 License can be
+found in `/usr/share/common-licenses/Apache-2.0'.
+
+The Debian packaging is copyright 2010, Egil Möller <egil.moller@piratpartiet.se> and
+is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+
diff --git a/debian/etherpad.init b/debian/etherpad.init
new file mode 100755
index 0000000..225ef3d
--- /dev/null
+++ b/debian/etherpad.init
@@ -0,0 +1,186 @@
+#!/bin/bash
+
+### BEGIN INIT INFO
+# Provides: etherpad
+# Required-Start: $networking $syslog $remote_fs
+# Required-Stop: $networking $syslog $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Run Etherpad
+# Description: A web-based word processor that allows
+# people to work together in real-time.
+# .
+# When multiple people edit the same document simultaneously,
+# any changes are instantly reflected on everyone's screen.
+# The result is a new and productive way to collaborate on
+# text documents, useful for meeting notes, drafting
+# sessions, education, team programming, and more.
+### END INIT INFO
+
+# Author: penSec.IT UG (haftungsbeschränkt) <mail@pensec.it>
+# Author: Per Andersson <avtobiff@gmail.com>
+# Author: Mikko Rantalainen <mikko.rantalainen@peda.net>
+
+################################################################################
+#
+# Copyright (c) 2010 penSec.IT UG (haftungsbeschränkt)
+# http://www.pensec.it
+# mail@pensec.it
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); 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 "AS IS" 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.
+#
+################################################################################
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="Collaborative real-time editor"
+NAME="etherpad"
+DAEMON_BASE="/usr/share/etherpad"
+DAEMON=$DAEMON_BASE/bin/run.sh
+DAEMON_ARGS=""
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+[ -f /etc/default/rcS ] && . /etc/default/rcS
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ start-stop-daemon --background --chdir $DAEMON_BASE --chuid etherpad:etherpad --start --quiet --make-pidfile --pidfile $PIDFILE --exec $DAEMON --test \
+ || return 1
+ start-stop-daemon --background --chdir $DAEMON_BASE --chuid etherpad:etherpad --start --quiet --make-pidfile --pidfile $PIDFILE --exec $DAEMON -- \
+ $DAEMON_ARGS \
+ || return 2
+ # Add code here, if necessary, that waits for the process to be ready
+ # to handle requests from services started subsequently which depend
+ # on this one. As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+ # Wait for children to finish too if this is a daemon that forks
+ # and if the daemon is only ever run from this initscript.
+ # If the above conditions are not satisfied then add some other code
+ # that waits for the process to drop all resources that could be
+ # needed by services started subsequently. A last resort is to
+ # sleep for some time.
+ start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
+ [ "$?" = 2 ] && return 2
+ # Many daemons don't delete their pidfiles when they exit.
+ rm -f $PIDFILE
+ return "$RETVAL"
+}
+
+#
+# Function that sends a SIGHUP to the daemon/service
+#
+do_reload() {
+ #
+ # If the daemon can reload its configuration without
+ # restarting (for example, when it is sent a SIGHUP),
+ # then implement that here.
+ #
+ start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE
+ return 0
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ status)
+ status_of_proc -p $PIDFILE "$DAEMON" "$NAME" && exit 0 || exit $?
+ ;;
+ #reload|force-reload)
+ #
+ # If do_reload() is not implemented then leave this commented out
+ # and leave 'force-reload' as an alias for 'restart'.
+ #
+ #log_daemon_msg "Reloading $DESC" "$NAME"
+ #do_reload
+ #log_end_msg $?
+ #;;
+ restart|force-reload)
+ #
+ # If the "reload" option is implemented then remove the
+ # 'force-reload' alias
+ #
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+ echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
+ exit 3
+ ;;
+esac
+
+:
+
diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in
new file mode 100644
index 0000000..cef83a3
--- /dev/null
+++ b/debian/po/POTFILES.in
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] templates
diff --git a/debian/po/fi.po b/debian/po/fi.po
new file mode 100644
index 0000000..788d6f0
--- /dev/null
+++ b/debian/po/fi.po
@@ -0,0 +1,76 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Mikko Rantalainen <mikko.rantalainen@peda.net>, 2010
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: etherpad@packages.debian.org\n"
+"POT-Creation-Date: 2010-05-06 11:07+0300\n"
+"PO-Revision-Date: 2010-05-06 11:13+0300\n"
+"Last-Translator: Mikko Rantalainen <mikko.rantalainen@peda.net>\n"
+"Language-Team: Peda.net\n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Virtaal 0.3.1\n"
+
+#. Type: password
+#. Default
+#. Note: the translation of this string should match the prompt below
+#: ../templates:1001
+msgid "password"
+msgstr "salasana"
+
+#. Type: password
+#. Description
+#. Note: the translation of this string should match the default password above
+#: ../templates:1002
+msgid "Etherpad administrator password:"
+msgstr "Etherpad-ylläpitäjän salasana:"
+
+#. Type: password
+#. Description
+#. Note: the translation of this string should match the default password above
+#: ../templates:1002
+msgid ""
+"The Etherpad system can be administrated with a browser. To make this safe, "
+"a good password should be set for the administrator. The default is password "
+"is \"password\" (THIS IS NOT SAFE)."
+msgstr ""
+"Etherpad-järjestelmää voidaan ylläpitää selaimella. Ylläpitäjällä tulee olla "
+"hyvä salasana, jotta tämä olisi turvallista. Oletuksena salasana on "
+"\"salasana\" (TÄMÄ EI OLE TURVALLINENN SALASANA)."
+
+#. Type: string
+#. Description
+#: ../templates:2001
+msgid "Fully qualified domain name of the site:"
+msgstr "Etherpad-palvelimen osoite (esimerkiksi example.com):"
+
+#. Type: string
+#. Description
+#: ../templates:2001
+msgid ""
+"The system needs to know the fully qualified domain name of the site where "
+"etherpad system is visible to the world. This may be different from the name "
+"of the system where etherpad is installed (e.g. in case of reverse proxy or "
+"port forwarding). Notice that if you enter \"example.com\" here, the service "
+"will be available at \"http://example.com:9000\" by default."
+msgstr ""
+"Järjestelmän tulee tietää Etherpad-palvelun täydellinen julkinen domain-"
+"nimi. Tämä voi olla eri kuin sen tietokoneen domain-nimi, johon palvelu "
+"asennetaan (esimerkiksi kun käytetään porttien uudelleenohjausta tai reverse "
+"proxy -määrityksiä). Huomaa, että jos syötät tässä \"example.com\", niin "
+"palvelu on oletuksena nähtävillä osoitteessa \"http://example.com:9000\"."
+
+#~ msgid "Please insert the administration password, default is password."
+#~ msgstr ""
+#~ "Koko Etherpad-asennuksen pääkäyttäjän salasana, oletus on \"salasana\"."
+
+#~ msgid "Please insert the domain name of your site."
+#~ msgstr ""
+#~ "Syötä tähän Etherpad-palvelimesi osoite. Varsinainen Etherpad-palvelu "
+#~ "toimii oletuksena portissa 9000 (esimerkiksi http://example.com:9000)."
diff --git a/debian/po/templates.pot b/debian/po/templates.pot
new file mode 100644
index 0000000..92cb5bc
--- /dev/null
+++ b/debian/po/templates.pot
@@ -0,0 +1,58 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: etherpad@packages.debian.org\n"
+"POT-Creation-Date: 2010-05-06 11:07+0300\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: password
+#. Default
+#. Note: the translation of this string should match the prompt below
+#: ../templates:1001
+msgid "password"
+msgstr ""
+
+#. Type: password
+#. Description
+#. Note: the translation of this string should match the default password above
+#: ../templates:1002
+msgid "Etherpad administrator password:"
+msgstr ""
+
+#. Type: password
+#. Description
+#. Note: the translation of this string should match the default password above
+#: ../templates:1002
+msgid ""
+"The Etherpad system can be administrated with a browser. To make this safe, "
+"a good password should be set for the administrator. The default is password "
+"is \"password\" (THIS IS NOT SAFE)."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../templates:2001
+msgid "Fully qualified domain name of the site:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../templates:2001
+msgid ""
+"The system needs to know the fully qualified domain name of the site where "
+"etherpad system is visible to the world. This may be different from the name "
+"of the system where etherpad is installed (e.g. in case of reverse proxy or "
+"port forwarding). Notice that if you enter \"example.com\" here, the service "
+"will be available at \"http://example.com:9000\" by default."
+msgstr ""
diff --git a/debian/postinst b/debian/postinst
new file mode 100755
index 0000000..3ce2754
--- /dev/null
+++ b/debian/postinst
@@ -0,0 +1,84 @@
+#!/bin/bash
+
+################################################################################
+#
+# Copyright (c) 2010 penSec.IT UG (haftungsbeschränkt)
+# http://www.pensec.it
+# mail@pensec.it
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); 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 "AS IS" 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.
+#
+################################################################################
+
+
+
+set -e
+. /usr/share/debconf/confmodule
+
+if [ -n "$ETHERPAD_DEBUG" ]; then
+ echo "now debugging $0 $@"
+ set -x
+fi
+
+db_version 2.0
+
+. /usr/share/dbconfig-common/dpkg/postinst.mysql
+dbc_go etherpad $@
+
+db_get "etherpad/admin_password"
+db_admin_password="$RET"
+db_get "etherpad/topdomains"
+db_topdomains="$RET"
+
+. /etc/dbconfig-common/etherpad.conf
+
+
+
+# Create system user
+if ! getent passwd etherpad > /dev/null ; then
+ echo 'Adding system-user for etherpad' 1>&2
+ adduser --system --group --quiet \
+ --home /usr/share/etherpad --no-create-home \
+ --disabled-login --force-badname etherpad
+fi
+
+# Give user the rights to write into the log & data directory
+chown -R etherpad:etherpad "/var/log/etherpad"
+chown -R etherpad:etherpad "/usr/share/etherpad/etherpad/data"
+# Give user the rights do write everywhere, did not yet figure
+# out which rights are necessary, exactly
+chown -R etherpad:etherpad "/usr/share/etherpad"
+
+if ! [ "$dbc_dbserver" ]; then
+ dbc_dbserver=localhost
+fi
+if ! [ "$dbc_dbport" ]; then
+ dbc_dbport=3306
+fi
+
+
+m4 \
+ -D __db_admin_password__="$db_admin_password" \
+ -D __dbc_dbserver__="$dbc_dbserver" \
+ -D __dbc_dbport__="$dbc_dbport" \
+ -D __dbc_dbname__="$dbc_dbname" \
+ -D __dbc_dbpass__="$dbc_dbpass" \
+ -D __dbc_dbuser__="$dbc_dbuser" \
+ -D __db_topdomains__="$db_topdomains" \
+ < /etc/etherpad/etherpad.local.properties.tmpl \
+ > /etc/etherpad/etherpad.local.properties
+
+chown etherpad:etherpad /etc/etherpad/etherpad.local.properties
+
+#DEBHELPER#
+
diff --git a/debian/postrm b/debian/postrm
new file mode 100644
index 0000000..1e555a0
--- /dev/null
+++ b/debian/postrm
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+################################################################################
+#
+# Copyright (c) 2010 penSec.IT UG (haftungsbeschränkt)
+# http://www.pensec.it
+# mail@pensec.it
+# Copyright (c) 2010 Egil Möller <egil.moller@piratpartiet.se>
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); 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 "AS IS" 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.
+#
+################################################################################
+
+
+
+set -e
+. /usr/share/debconf/confmodule
+
+if [ -n "$ETHERPAD_DEBUG" ]; then
+ echo "now debugging $0 $@"
+ set -x
+fi
+
+db_version 2.0
+
+# Set up database
+. /usr/share/dbconfig-common/dpkg/postrm.mysql
+dbc_go etherpad $@
+
+#DEBHELPER#
+
diff --git a/debian/preinst b/debian/preinst
new file mode 100644
index 0000000..9f854cb
--- /dev/null
+++ b/debian/preinst
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+################################################################################
+#
+# Copyright (c) 2010 penSec.IT UG (haftungsbeschränkt)
+# http://www.pensec.it
+# mail@pensec.it
+# Copyright (c) 2010 Egil Möller <egil.moller@piratpartiet.se>
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); 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 "AS IS" 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.
+#
+################################################################################
+
+
+
+set -e
+. /usr/share/debconf/confmodule
+
+if [ -n "$ETHERPAD_DEBUG" ]; then
+ echo "now debugging $0 $@"
+ set -x
+fi
+
+db_version 2.0
+
+#DEBHELPER#
+
diff --git a/debian/prerm b/debian/prerm
new file mode 100755
index 0000000..ddabe3e
--- /dev/null
+++ b/debian/prerm
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+################################################################################
+#
+# Copyright (c) 2010 penSec.IT UG (haftungsbeschränkt)
+# http://www.pensec.it
+# mail@pensec.it
+# Copyright (c) 2010 Egil Möller <egil.moller@piratpartiet.se>
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); 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 "AS IS" 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.
+#
+################################################################################
+
+
+
+set -e
+. /usr/share/debconf/confmodule
+
+if [ -n "$ETHERPAD_DEBUG" ]; then
+ echo "now debugging $0 $@"
+ set -x
+fi
+
+db_version 2.0
+
+# Set up database
+. /usr/share/dbconfig-common/dpkg/prerm.mysql
+dbc_go etherpad $@
+
+# Remove log+data directories, otherwise uninstall will fail
+rm -rf /var/log/etherpad
+rm -rf /usr/share/etherpad/etherpad/data
+
+#DEBHELPER#
+
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..d1253c7
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,112 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# This file is public domain software, originally written by Joey Hess.
+#
+# This version is for packages that are architecture independent.
+#
+# Rules to build etherpad
+#
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+build: build-stamp
+build-stamp:
+ dh_testdir
+
+ # Add here commands to compile the package.
+ #$(MAKE)
+ bin/build.sh
+ touch build-stamp
+
+clean:
+ # update template translation strings commented out as git-buildpackage complains that the file changes all the times otherwise...
+ # debconf-updatepo
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp
+
+ # Add here commands to clean up after the build process.
+ #$(MAKE) clean
+ #$(MAKE) distclean
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_prep
+ dh_installdirs
+
+ # Add here commands to install the package into debian/<packagename>.
+ #$(MAKE) prefix=`pwd`/debian/`dh_listpackages`/usr install
+
+ # Add here commands to install the indep part of the package into
+ # debian/<package>-doc.
+ #INSTALLDOC#
+
+ mkdir -p debian/etherpad/usr/share/etherpad
+
+ # try to copy content correctly
+ cp -a $$(ls | grep -E -v 'debian|LICENSE|COPYING|INSTALL') debian/etherpad/usr/share/etherpad
+ # fix ups (because the above copy is too dump), remove unneeded stuff
+ find debian/etherpad -type f -and -name ".gitignore" -exec rm {} +
+ find debian/etherpad -type f -and -name "build-stamp" -exec rm {} +
+
+ # create directory to save user data
+ mkdir -p debian/etherpad/usr/share/etherpad/etherpad/data
+
+ mkdir -p debian/etherpad/etc
+ mv debian/etherpad/usr/share/etherpad/etherpad/etc debian/etherpad/etc/etherpad
+ ln -s /etc/etherpad debian/etherpad/usr/share/etherpad/etherpad/etc
+
+ mkdir -p debian/etherpad/var/log/etherpad
+ mkdir -p debian/etherpad/usr/share/lintian/overrides
+ cp debian/source/lintian-overrides debian/etherpad/usr/share/lintian/overrides/etherpad
+
+ #mkdir -p debian/etherpad/etc/init.d
+ #ln -s /usr/share/etherpad/bin/etherpad.init.d debian/etherpad/etc/init.d/etherpad
+ dh_installinit --update-rcd-params="start 05 2 3 4 5 . stop 95 S 0 1 6 ."
+
+ dh_install -i
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs
+ dh_installdocs
+ # on the fly final copyright file creation:
+ cat debian/copyright LICENSE > debian/etherpad/usr/share/doc/etherpad/copyright
+ dh_installexamples
+# dh_installmenu
+ dh_installdebconf
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installcatalogs
+# dh_installpam
+# dh_installmime
+# dh_installinit
+# dh_installcron
+# dh_installinfo
+# dh_installwm
+# dh_installudev
+# dh_lintian
+# dh_bugfiles
+# dh_undocumented
+ dh_installman
+ dh_link
+ dh_compress
+ dh_fixperms
+# dh_perl
+ dh_installdeb
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+# Build architecture-dependent files here.
+binary-arch: build install
+# We have nothing to do by default.
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..89ae9db
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (native)
diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides
new file mode 100644
index 0000000..31f525d
--- /dev/null
+++ b/debian/source/lintian-overrides
@@ -0,0 +1,8 @@
+# The script infrastructure/ace/bin/serve is really a scala program
+# but contains magic to make it as executable shell script (the couple first
+# lines in the script will execute scala on itself):
+etherpad source: shell-script-fails-syntax-check ./usr/share/etherpad/infrastructure/ace/bin/serve
+etherpad binary: shell-script-fails-syntax-check ./usr/share/etherpad/infrastructure/ace/bin/serve
+# The template already has a comment for the default field, lintian would
+# want to have an extra comment inside the string to translate, I don't agree:
+etherpad source: translated-default-field templates: 4
diff --git a/debian/templates b/debian/templates
new file mode 100644
index 0000000..19c3886
--- /dev/null
+++ b/debian/templates
@@ -0,0 +1,20 @@
+Template: etherpad/admin_password
+Type: password
+# Note: the translation of this string should match the prompt below
+_Default: password
+# Note: the translation of this string should match the default password above
+_Description: Etherpad administrator password:
+ The Etherpad system can be administrated with a browser. To make this
+ safe, a good password should be set for the administrator.
+ The default is password is "password" (THIS IS NOT SAFE).
+
+Template: etherpad/topdomains
+Type: string
+Default: localhost
+_Description: Fully qualified domain name of the site:
+ The system needs to know the fully qualified domain name of the site where
+ etherpad system is visible to the world. This may be different from the
+ name of the system where etherpad is installed (e.g. in case of reverse proxy
+ or port forwarding). Notice that if you enter "example.com" here, the service
+ will be available at "http://example.com:9000" by default.
+
diff --git a/trunk/etherpad/.gitignore b/etherpad/.gitignore
index 5f41ae6..5f41ae6 100644
--- a/trunk/etherpad/.gitignore
+++ b/etherpad/.gitignore
diff --git a/trunk/etherpad/bin/.gitignore b/etherpad/bin/.gitignore
index 00fd678..00fd678 100644
--- a/trunk/etherpad/bin/.gitignore
+++ b/etherpad/bin/.gitignore
diff --git a/etherpad/bin/etherpad.default b/etherpad/bin/etherpad.default
new file mode 100644
index 0000000..dcceea9
--- /dev/null
+++ b/etherpad/bin/etherpad.default
@@ -0,0 +1,47 @@
+# Default settings for etherpad. This file is sourced by /bin/sh from
+# /etc/init.d/etherpad.
+
+# User and group to run as
+ETHERPAD_USER="etherpad"
+ETHERPAD_GROUP="etherpad"
+
+# Setup paths
+ETHERPAD_HOME=/usr/local/etherpad
+JAVA=/usr/bin/java
+JAVA_HOME=/usr/lib/jvm/java-6-openjdk
+SCALA=/usr/bin/scala
+SCALA_HOME=/usr/share/java
+MYSQL_CONNECTOR_JAR=/usr/share/java/mysql-connector-java.jar
+
+# Maximum amount of RAM to allocate
+MXRAM="1G"
+
+# Classpath
+CP="$ETHERPAD_HOME/etherpad/appjet-eth-dev.jar:$ETHERPAD_HOME/etherpad/data"
+for f in "$ETHERPAD_HOME"/etherpad/lib/*.jar; do
+ CP="$CP:$f"
+done
+
+# Java options
+JAVA_OPTS=""
+
+# Config file
+CFGFILE=/etc/etherpad/local.properties
+
+# Default options
+ETHERPAD_OPTS="-classpath $CP \
+ -server \
+ -Xmx${MXRAM} \
+ -Xms${MXRAM} \
+ -Djava.awt.headless=true \
+ -XX:MaxGCPauseMillis=500 \
+ -XX:+UseConcMarkSweepGC \
+ -XX:+CMSIncrementalMode \
+ -XX:CMSIncrementalSafetyFactor=50 \
+ -XX:+PrintGCDetails \
+ -XX:+PrintGCTimeStamps \
+ -Xloggc:$ETHERPAD_HOME/etherpad/data/logs/backend/jvm-gc.log \
+ -Dappjet.jmxremote=true \
+ $JAVA_OPTS \
+ net.appjet.oui.main \
+ --configFile=$CFGFILE"
diff --git a/etherpad/bin/java-version.sh b/etherpad/bin/java-version.sh
new file mode 100755
index 0000000..639920b
--- /dev/null
+++ b/etherpad/bin/java-version.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+# This script attempts to find an existing installation of Java that meets a minimum version
+# requirement on a Linux machine. If it is successful, it will export a JAVA_HOME environment
+# variable that can be used by another calling script.
+#
+# To specify the required version, set the REQUIRED_VERSION to the major version required,
+# e.g. 1.3, but not 1.3.1.
+REQUIRED_VERSION=1.6
+
+# Transform the required version string into a number that can be used in comparisons
+REQUIRED_VERSION=`echo $REQUIRED_VERSION | sed -e 's;\.;0;g'`
+# Check JAVA_HOME directory to see if Java version is adequate
+if [ $JAVA_HOME ]
+then
+ JAVA_EXE=$JAVA_HOME/bin/java
+ $JAVA_EXE -version 2> tmp.ver
+ VERSION=`cat tmp.ver | grep "java version" | awk '{ print substr($3, 2, length($3)-2); }'`
+ echo $VERSION
+ rm tmp.ver
+ VERSION=`echo $VERSION | awk '{ print substr($1, 1, 3); }' | sed -e 's;\.;0;g'`
+ if [ $VERSION ]
+ then
+ if [ $VERSION -ge $REQUIRED_VERSION ]
+ then
+ JAVA_HOME=`echo $JAVA_EXE | awk '{ print substr($1, 1, length($1)-9); }'`
+ else
+ JAVA_HOME=
+ fi
+ else
+ JAVA_HOME=
+ fi
+fi
+
+# If the existing JAVA_HOME directory is adequate, then leave it alone
+# otherwise, use 'locate' to search for other possible java candidates and
+# check their versions.
+if [ $JAVA_HOME ]
+then
+ :
+else
+ for JAVA_EXE in `locate bin/java | grep java$ | xargs echo`
+ do
+ if [ $JAVA_HOME ]
+ then
+ :
+ else
+ $JAVA_EXE -version 2> tmp.ver 1> /dev/null
+ VERSION=`cat tmp.ver | grep "java version" | awk '{ print substr($3, 2, length($3)-2); }'`
+ rm tmp.ver
+ VERSION=`echo $VERSION | awk '{ print substr($1, 1, 3); }' | sed -e 's;\.;0;g'`
+ if [ $VERSION ]
+ then
+ if [ $VERSION -ge $REQUIRED_VERSION ]
+ then
+ JAVA_HOME=`echo $JAVA_EXE`
+ else
+ echo "JAVA Version too old - Please install a new Java version"
+ fi
+ fi
+ fi
+ done
+fi
+
+# If the correct Java version is detected, then export the JAVA_HOME environment variable
+if [ $JAVA_HOME ]
+then
+ `export JAVA_HOME="$JAVA_HOME"`
+ export JAVA_HOME
+ #echo $JAVA_HOME
+fi
+
+
diff --git a/etherpad/bin/rebuildjar.sh b/etherpad/bin/rebuildjar.sh
new file mode 100755
index 0000000..d32d994
--- /dev/null
+++ b/etherpad/bin/rebuildjar.sh
@@ -0,0 +1,161 @@
+#!/bin/bash -e
+
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS-IS" 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.
+
+bin/java-version.sh
+
+if [ -z "$JAR" ]; then
+ if [ ! -z $(which fastjar 2>/dev/null) ]; then
+ # http://lists.gnu.org/archive/html/fastjar-dev/2009-12/msg00000.html
+ version=`fastjar --version | grep fastjar | sed 's/.* //g'`
+ if [[ "$version" = "0.97" || "$version" = "0.98" ]]; then
+ echo "fastjar version $version can't build EtherPad. Falling back to standard jar."
+ JAR=jar
+ else
+ JAR=fastjar
+ fi
+ else
+ JAR=jar
+ fi
+fi
+
+[ -z "$JAVA_HOME" ] && read -p "\$JAVA_HOME is not set, please enter the path to your Java installation: " JAVA_HOME
+if [ ! -e "$JAVA_HOME" ]; then
+ echo "The path to \$JAVA_HOME ($JAVA_HOME) does not exist, please check and try again."
+ exit 1
+else
+ export JAVA_HOME
+fi
+
+[ -z "$SCALA_HOME" ] && read -p "\$SCALA_HOME is not set, please enter the path to your Scala installation: " SCALA_HOME
+if [ ! -e "$SCALA_HOME" ]; then
+ echo "The path to \$SCALA_HOME ($SCALA_HOME) does not exist, please check and try again."
+ exit 1
+else
+ export SCALA_HOME
+fi
+
+if [ -z "$SCALA" ]; then
+ if [ `which scala 2>/dev/null 1>/dev/null` ]; then
+ SCALA=`which scala`
+ echo "Using 'scala' binary found at $SCALA. Set \$SCALA to use another one."
+ elif [ -x "$SCALA_HOME/bin/scala" ]; then
+ SCALA="$SCALA_HOME/bin/scala"
+ echo "Using 'scala' binary found at $SCALA. Set \$SCALA to use another one."
+ else
+ read -p "\$SCALA is not set and the 'scala' binary could not be found, please enter the path to the file: " SCALA
+ fi
+fi
+if [ ! -x "$SCALA" ]; then
+ echo "The path to \$SCALA ($SCALA) is not an executable file, please check and try again."
+ exit 1
+else
+ export SCALA
+fi
+
+if [ -z "$JAVA" ]; then
+ if [ `which java 2>/dev/null 1>/dev/null` ]; then
+ JAVA=`which java`
+ echo "Using 'java' binary found at $JAVA. Set \$JAVA to use another one."
+ elif [ -x "$JAVA_HOME/bin/java" ]; then
+ JAVA="$JAVA_HOME/bin/java"
+ echo "Using 'java' binary found at $JAVA. Set \$JAVA to use another one."
+ else
+ read -p "\$JAVA is not set and the 'java' binary could not be found, please enter the path to the file: " JAVA
+ fi
+fi
+if [ ! -x "$JAVA" ]; then
+ echo "The path to \$JAVA ($JAVA) is not an executeable file, please check and try again."
+ exit 1
+else
+ export JAVA
+fi
+
+[ -z "$MYSQL_CONNECTOR_JAR" ] && read -p "\$MYSQL_CONNECTOR_JAR is not set, please enter the path to the MySQL JDBC driver .jar file: " MYSQL_CONNECTOR_JAR
+if [ ! -e "$MYSQL_CONNECTOR_JAR" ]; then
+ echo "The path to \$MYSQL_CONNECTOR_JAR ($MYSQL_CONNECTOR_JAR) does not exist, please check and try again."
+ exit 1
+else
+ export MYSQL_CONNECTOR_JAR
+fi
+
+# Check for javac version. Unfortunately, javac doesn't tell you whether
+# it's Sun Java or OpenJDK, but the "java" binary that's in the same
+# directory will.
+if [ -e "$JAVA_HOME/bin/java" ]; then
+ ($JAVA_HOME/bin/java -version 2>&1) | {
+ while read file; do
+ javaver=$file
+ done
+ for word in $javaver; do
+ if [ $word != "Java" ]; then
+ echo "$JAVA_HOME/bin/java is from a non-Sun compiler, and may not be able to compile EtherPad. If you get syntax errors, you should point \$JAVA_HOME at a Sun Java JDK installation instead."
+ fi
+ break
+ done
+ }
+fi
+
+function notify {
+ if [ ! -z $(which growlnotify 2>/dev/null) ]; then
+ echo $0 finished | growlnotify
+ fi
+}
+trap notify EXIT
+
+source ../infrastructure/bin/compilecache.sh
+
+suffix="-dev";
+if [ "$1" == "prod" ]; then
+ suffix="";
+ shift;
+fi
+
+OWD=`pwd`
+cd ../infrastructure
+JAR=$JAR bin/makejar.sh $@
+
+rm -rf build/etherpad-jars
+mkdir -p build/etherpad-jars
+
+echo "including etherpad JARs..."
+
+JARFILES="echo ../etherpad/lib/*.jar"
+function genjar {
+ echo "unzipping JARs..."
+ pushd $1 >> /dev/null
+
+ for a in ../../../etherpad/lib/*.jar; do
+ $JAR xf $a
+ rm -rf META-INF/{MANIFEST.MF,NOTICE{,.txt},LICENSE{,.txt},INDEX.LIST,SUN_MICR.{RSA,SF},maven}
+ done
+
+ popd >> /dev/null
+}
+cacheonfiles JAR-etherpad "$JARFILES" genjar 1
+
+echo "updating..."
+
+pushd buildcache/JAR-etherpad >> /dev/null
+$JAR uf ../../build/appjet.jar `ls . | grep -v "^t$"`
+
+echo "done."
+
+popd >> /dev/null
+
+dst="$OWD/appjet-eth$suffix.jar"
+cp -f build/appjet.jar $dst
+cd $OWD
+echo "wrote $dst"
diff --git a/etherpad/bin/run-local.sh b/etherpad/bin/run-local.sh
new file mode 100755
index 0000000..a559fce
--- /dev/null
+++ b/etherpad/bin/run-local.sh
@@ -0,0 +1,65 @@
+#!/bin/bash -e
+
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS-IS" 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.
+
+mkdir -p data/appjet
+
+MXRAM="1G"
+if [ ! -z $1 ]; then
+ if [ ! '-' = `echo $1 | head -c 1` ]; then
+ MXRAM="$1";
+ shift;
+ fi
+fi
+
+CP="appjet-eth-dev.jar:data"
+for f in lib/*.jar; do
+ CP="$CP:$f"
+done
+
+if [ -z "$JAVA" ]; then
+ JAVA=java
+fi
+
+# etherpad properties file
+cfg_file=./etc/etherpad.local.properties
+if [ ! -f $cfg_file ]; then
+ cfg_file=./etc/etherpad.localdev-default.properties
+fi
+if [[ $1 == "--cfg" ]]; then
+ cfg_file=${2}
+ shift;
+ shift;
+fi
+
+echo "Using config file: ${cfg_file}"
+
+exec $JAVA -classpath $CP \
+ -server \
+ -Xmx${MXRAM} \
+ -Xms${MXRAM} \
+ -Djava.awt.headless=true \
+ -XX:MaxGCPauseMillis=500 \
+ -XX:+UseConcMarkSweepGC \
+ -XX:+CMSIncrementalMode \
+ -XX:CMSIncrementalSafetyFactor=50 \
+ -XX:+PrintGCDetails \
+ -XX:+PrintGCTimeStamps \
+ -Xloggc:./data/logs/backend/jvm-gc.log \
+ -Dappjet.jmxremote=true \
+ $JAVA_OPTS \
+ net.appjet.oui.main \
+ --configFile=${cfg_file} \
+ "$@"
diff --git a/etherpad/bin/setup-mysql-db.sh b/etherpad/bin/setup-mysql-db.sh
new file mode 100755
index 0000000..45901ac
--- /dev/null
+++ b/etherpad/bin/setup-mysql-db.sh
@@ -0,0 +1,25 @@
+#!/bin/bash -e
+
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS-IS" 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.
+
+db="etherpad"
+
+echo "Creating etherpad ${db}..."
+echo "create database ${db};" | ${mysql} -u root -p
+
+echo "Granting priviliges..."
+echo "grant all privileges on ${db}.* to 'etherpad'@'localhost' identified by 'password';" | ${mysql} -u root -p
+
+echo "Success"
diff --git a/etherpad/etc/etherpad.local.properties.tmpl b/etherpad/etc/etherpad.local.properties.tmpl
new file mode 100644
index 0000000..d9bb899
--- /dev/null
+++ b/etherpad/etc/etherpad.local.properties.tmpl
@@ -0,0 +1,23 @@
+alwaysHttps = false
+ajstdlibHome = ../infrastructure/framework-src/modules
+appjetHome = ./data/appjet
+devMode = false
+etherpad.adminPass = __db_admin_password__
+etherpad.fakeProduction = false
+etherpad.isProduction = true
+etherpad.proAccounts = true
+etherpad.SQL_JDBC_DRIVER = com.mysql.jdbc.Driver
+etherpad.SQL_JDBC_URL = jdbc:mysql://__dbc_dbserver__:__dbc_dbport__/__dbc_dbname__
+etherpad.SQL_PASSWORD = __dbc_dbpass__
+etherpad.SQL_USERNAME = __dbc_dbuser__
+hidePorts = false
+listen = 9000
+logDir = /var/log/etherpad
+modulePath = ./src
+motdPage = /ep/pad/view/ro.3PfHCD0ApLc/latest?fullScreen=1&slider=0&sidebar=0
+topdomains = __db_topdomains__,localhost,localhost.localdomain
+transportPrefix = /comet
+transportUseWildcardSubdomains = true
+useHttpsUrls = false
+useVirtualFileRoot = ./src
+theme = default
diff --git a/etherpad/etc/etherpad.localdev-default.properties b/etherpad/etc/etherpad.localdev-default.properties
new file mode 100644
index 0000000..374101f
--- /dev/null
+++ b/etherpad/etc/etherpad.localdev-default.properties
@@ -0,0 +1,23 @@
+alwaysHttps = false
+ajstdlibHome = ../infrastructure/framework-src/modules
+appjetHome = ./data/appjet
+devMode = true
+etherpad.adminPass = password
+etherpad.fakeProduction = false
+etherpad.isProduction = false
+etherpad.proAccounts = true
+etherpad.SQL_JDBC_DRIVER = com.mysql.jdbc.Driver
+etherpad.SQL_JDBC_URL = jdbc:mysql://localhost:3306/etherpad
+etherpad.SQL_PASSWORD = password
+etherpad.SQL_USERNAME = etherpad
+hidePorts = false
+listen = 9000
+logDir = ./data/logs
+modulePath = ./src
+motdPage = /ep/pad/view/ro.3PfHCD0ApLc/latest?fullScreen=1&slider=0&sidebar=0
+topdomains = localhost,localbox.info
+transportPrefix = /comet
+transportUseWildcardSubdomains = true
+useHttpsUrls = false
+useVirtualFileRoot = ./src
+theme = default
diff --git a/trunk/etherpad/lib/dnsjava-2.0.6.jar b/etherpad/lib/dnsjava-2.0.6.jar
index e41f9b0..e41f9b0 100644
--- a/trunk/etherpad/lib/dnsjava-2.0.6.jar
+++ b/etherpad/lib/dnsjava-2.0.6.jar
Binary files differ
diff --git a/etherpad/lib/jbcrypt-0.3.jar b/etherpad/lib/jbcrypt-0.3.jar
new file mode 100644
index 0000000..04fbbb3
--- /dev/null
+++ b/etherpad/lib/jbcrypt-0.3.jar
Binary files differ
diff --git a/trunk/etherpad/lib/jcommon-1.0.15.jar b/etherpad/lib/jcommon-1.0.15.jar
index d0dc26d..d0dc26d 100644
--- a/trunk/etherpad/lib/jcommon-1.0.15.jar
+++ b/etherpad/lib/jcommon-1.0.15.jar
Binary files differ
diff --git a/trunk/etherpad/lib/jfreechart-1.0.12.jar b/etherpad/lib/jfreechart-1.0.12.jar
index 73be90f..73be90f 100644
--- a/trunk/etherpad/lib/jfreechart-1.0.12.jar
+++ b/etherpad/lib/jfreechart-1.0.12.jar
Binary files differ
diff --git a/etherpad/src/etherpad/admin/plugins.js b/etherpad/src/etherpad/admin/plugins.js
new file mode 100644
index 0000000..385e2ca
--- /dev/null
+++ b/etherpad/src/etherpad/admin/plugins.js
@@ -0,0 +1,247 @@
+/**
+ * Copyright 2009 RedHog, Egil Möller <egil.moller@piratpartiet.se>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("faststatic");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+
+import("etherpad.utils.*");
+import("etherpad.collab.server_utils");
+import("etherpad.globals.*");
+import("etherpad.log");
+import("etherpad.pad.padusers");
+import("etherpad.pro.pro_utils");
+import("etherpad.helpers");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("sqlbase.sqlbase");
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+import("exceptionutils");
+import("execution");
+
+jimport("java.io.File",
+ "java.io.DataInputStream",
+ "java.io.FileInputStream",
+ "java.lang.Byte",
+ "java.io.FileReader",
+ "java.io.BufferedReader",
+ "net.appjet.oui.JarVirtualFile");
+
+pluginsLoaded = false;
+pluginModules = {};
+plugins = {};
+hooks = {};
+clientHooks = {};
+
+function loadAvailablePlugin(pluginName) {
+ if (plugins[pluginName] != undefined)
+ return plugins[pluginName];
+
+ var pluginsDir = new Packages.java.io.File("src/plugins");
+
+ var pluginFile = new Packages.java.io.File(pluginsDir, pluginName + '/main.js');
+ if (pluginFile.exists()) {
+ var pluginModulePath = pluginFile.getPath().replace(new RegExp("src/\(.*\)\.js"), "$1").replace("/", ".", "g");
+ var importStmt = "import('" + pluginModulePath + "')";
+ try {
+ var res = execution.fancyAssEval(importStmt, "main;");
+ res = new res.init();
+ return res;
+ } catch (e) {
+ log.info({errorLoadingPlugin:exceptionutils.getStackTracePlain(e)});
+ }
+ }
+ return null;
+}
+
+function loadAvailablePlugins() {
+ var pluginsDir = new Packages.java.io.File("src/plugins");
+
+ var pluginNames = pluginsDir.list();
+
+ for (i = 0; i < pluginNames.length; i++) {
+ var plugin = loadAvailablePlugin(pluginNames[i]);
+ if (plugin != null)
+ pluginModules[pluginNames[i]] = plugin
+ }
+}
+
+function loadPluginHooks(pluginName) {
+ function registerHookNames(hookSet, type) {
+ return function (hook) {
+ var row = {hook:hook, type:type, plugin:pluginName};
+ if (hookSet[hook] == undefined) hookSet[hook] = [];
+ hookSet[hook].push(row);
+ return row;
+ }
+ }
+ plugins[pluginName] = pluginModules[pluginName].hooks.map(registerHookNames(hooks, 'server'));
+ if (pluginModules[pluginName].client != undefined && pluginModules[pluginName].client.hooks != undefined)
+ plugins[pluginName] = plugins[pluginName].concat(pluginModules[pluginName].client.hooks.map(registerHookNames(clientHooks, 'client')));
+}
+
+function unloadPluginHooks(pluginName) {
+ for (var hookSet in [hooks, clientHooks])
+ for (var hookName in hookSet) {
+ var hook = hookSet[hookName];
+ for (i = hook.length - 1; i >= 0; i--)
+ if (hook[i].plugin == pluginName)
+ hook.splice(i, 1);
+ }
+ delete plugins[pluginName];
+}
+
+function loadInstalledHooks() {
+ var sql = '' +
+ 'select ' +
+ ' hook.name as hook, ' +
+ ' hook_type.name as type, ' +
+ ' plugin.name as plugin, ' +
+ ' plugin_hook.original_name as original ' +
+ 'from ' +
+ ' plugin ' +
+ ' left outer join plugin_hook on ' +
+ ' plugin.id = plugin_hook.plugin_id ' +
+ ' left outer join hook on ' +
+ ' plugin_hook.hook_id = hook.id ' +
+ ' left outer join hook_type on ' +
+ ' hook.type_id = hook_type.id ' +
+ 'order by hook.name, plugin.name';
+
+ var rows = sqlobj.executeRaw(sql, {});
+ for (var i = 0; i < rows.length; i++) {
+ var row = rows[i];
+
+ if (plugins[row.plugin] == undefined)
+ plugins[row.plugin] = [];
+ plugins[row.plugin].push(row);
+
+ var hookSet;
+
+ if (row.type == 'server')
+ hookSet = hooks;
+ else if (row.type == 'client')
+ hookSet = clientHooks;
+
+ if (hookSet[row.hook] == undefined)
+ hookSet[row.hook] = [];
+ if (row.hook != 'null')
+ hookSet[row.hook].push(row);
+ }
+}
+
+function selectOrInsert(table, columns) {
+ var res = sqlobj.selectSingle(table, columns);
+ if (res !== null)
+ return res;
+ sqlobj.insert(table, columns);
+ return sqlobj.selectSingle(table, columns);
+}
+
+function saveInstalledHooks(pluginName) {
+ var plugin = sqlobj.selectSingle('plugin', {name:pluginName});
+
+ if (plugin !== null) {
+ sqlobj.deleteRows('plugin_hook', {plugin_id:plugin.id});
+ if (plugins[pluginName] === undefined)
+ sqlobj.deleteRows('plugin', {name:pluginName});
+ }
+
+ if (plugins[pluginName] !== undefined) {
+ if (plugin === null)
+ plugin = selectOrInsert('plugin', {name:pluginName});
+
+ for (var i = 0; i < plugins[pluginName].length; i++) {
+ var row = plugins[pluginName][i];
+
+ var hook_type = selectOrInsert('hook_type', {name:row.type});
+ var hook = selectOrInsert('hook', {name:row.hook, type_id:hook_type.id});
+
+ sqlobj.insert("plugin_hook", {plugin_id:plugin.id, hook_id:hook.id});
+ }
+ }
+}
+
+
+function loadPlugins(force) {
+ if (pluginsLoaded && force == undefined) return;
+ pluginsLoaded = true;
+ loadAvailablePlugins();
+ loadInstalledHooks();
+}
+
+
+/* User API */
+function enablePlugin(pluginName) {
+ loadPlugins();
+ loadPluginHooks(pluginName);
+ saveInstalledHooks(pluginName);
+ try {
+ pluginModules[pluginName].install();
+ } catch (e) {
+ unloadPluginHooks(pluginName);
+ saveInstalledHooks(pluginName);
+ throw e;
+ }
+}
+
+function disablePlugin(pluginName) {
+ loadPlugins();
+ try {
+ pluginModules[pluginName].uninstall();
+ } catch (e) {
+ log.info({errorUninstallingPlugin:exceptionutils.getStackTracePlain(e)});
+ }
+ unloadPluginHooks(pluginName);
+ saveInstalledHooks(pluginName);
+}
+
+function registerClientHandlerJS() {
+ loadPlugins();
+ for (pluginName in plugins) {
+ var plugin = pluginModules[pluginName];
+ if (plugin.client !== undefined) {
+ helpers.includeJs("plugins/" + pluginName + "/main.js");
+ if (plugin.client.modules != undefined)
+ for (j = 0; j < client.modules.length; j++)
+ helpers.includeJs("plugins/" + pluginName + "/" + plugin.client.modules[j] + ".js");
+ }
+ }
+ helpers.addClientVars({hooks:clientHooks});
+ helpers.includeJs("plugins.js");
+}
+
+function callHook(hookName, args) {
+ loadPlugins();
+ if (hooks[hookName] === undefined)
+ return [];
+ var res = [];
+
+ for (var i = 0; i < hooks[hookName].length; i++) {
+ var plugin = hooks[hookName][i];
+ var pluginRes = pluginModules[plugin.plugin][plugin.original || hookName](args);
+ if (pluginRes != undefined && pluginRes != null)
+ for (var j = 0; j < pluginRes.length; j++)
+ res.push(pluginRes[j]); /* Don't use Array.concat as it flatterns arrays within the array */
+ }
+ return res;
+}
+
+function callHookStr(hookName, args, sep, pre, post) {
+ if (sep == undefined) sep = '';
+ if (pre == undefined) pre = '';
+ if (post == undefined) post = '';
+ return callHook(hookName, args).map(function (x) { return pre + x + post}).join(sep || "");
+}
diff --git a/trunk/etherpad/src/etherpad/admin/shell.js b/etherpad/src/etherpad/admin/shell.js
index 391d524..391d524 100644
--- a/trunk/etherpad/src/etherpad/admin/shell.js
+++ b/etherpad/src/etherpad/admin/shell.js
diff --git a/trunk/etherpad/src/etherpad/billing/billing.js b/etherpad/src/etherpad/billing/billing.js
index 444c233..444c233 100644
--- a/trunk/etherpad/src/etherpad/billing/billing.js
+++ b/etherpad/src/etherpad/billing/billing.js
diff --git a/trunk/etherpad/src/etherpad/billing/fields.js b/etherpad/src/etherpad/billing/fields.js
index 4a307ac..4a307ac 100644
--- a/trunk/etherpad/src/etherpad/billing/fields.js
+++ b/etherpad/src/etherpad/billing/fields.js
diff --git a/trunk/etherpad/src/etherpad/billing/team_billing.js b/etherpad/src/etherpad/billing/team_billing.js
index ae8ae8a..ae8ae8a 100644
--- a/trunk/etherpad/src/etherpad/billing/team_billing.js
+++ b/etherpad/src/etherpad/billing/team_billing.js
diff --git a/trunk/etherpad/src/etherpad/collab/collab_server.js b/etherpad/src/etherpad/collab/collab_server.js
index 78c9921..78c9921 100644
--- a/trunk/etherpad/src/etherpad/collab/collab_server.js
+++ b/etherpad/src/etherpad/collab/collab_server.js
diff --git a/trunk/etherpad/src/etherpad/collab/collabroom_server.js b/etherpad/src/etherpad/collab/collabroom_server.js
index ab1f844..ab1f844 100644
--- a/trunk/etherpad/src/etherpad/collab/collabroom_server.js
+++ b/etherpad/src/etherpad/collab/collabroom_server.js
diff --git a/trunk/etherpad/src/etherpad/collab/genimg.js b/etherpad/src/etherpad/collab/genimg.js
index 04d1b3b..04d1b3b 100644
--- a/trunk/etherpad/src/etherpad/collab/genimg.js
+++ b/etherpad/src/etherpad/collab/genimg.js
diff --git a/trunk/etherpad/src/etherpad/collab/json_sans_eval.js b/etherpad/src/etherpad/collab/json_sans_eval.js
index 6cbd497..6cbd497 100644
--- a/trunk/etherpad/src/etherpad/collab/json_sans_eval.js
+++ b/etherpad/src/etherpad/collab/json_sans_eval.js
diff --git a/trunk/etherpad/src/etherpad/collab/readonly_server.js b/etherpad/src/etherpad/collab/readonly_server.js
index e367f04..e367f04 100644
--- a/trunk/etherpad/src/etherpad/collab/readonly_server.js
+++ b/etherpad/src/etherpad/collab/readonly_server.js
diff --git a/trunk/etherpad/src/etherpad/collab/server_utils.js b/etherpad/src/etherpad/collab/server_utils.js
index ece3aea..ece3aea 100644
--- a/trunk/etherpad/src/etherpad/collab/server_utils.js
+++ b/etherpad/src/etherpad/collab/server_utils.js
diff --git a/trunk/etherpad/src/etherpad/control/aboutcontrol.js b/etherpad/src/etherpad/control/aboutcontrol.js
index 9d77142..9d77142 100644
--- a/trunk/etherpad/src/etherpad/control/aboutcontrol.js
+++ b/etherpad/src/etherpad/control/aboutcontrol.js
diff --git a/etherpad/src/etherpad/control/admin/pluginmanager.js b/etherpad/src/etherpad/control/admin/pluginmanager.js
new file mode 100644
index 0000000..c4bee5b
--- /dev/null
+++ b/etherpad/src/etherpad/control/admin/pluginmanager.js
@@ -0,0 +1,71 @@
+/**
+ * Copyright 2009 RedHog, Egil Möller <egil.moller@piratpartiet.se>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("faststatic");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+
+import("etherpad.utils.*");
+import("etherpad.collab.server_utils");
+import("etherpad.globals.*");
+import("etherpad.log");
+import("etherpad.pad.padusers");
+import("etherpad.pro.pro_utils");
+import("etherpad.helpers");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("etherpad.admin.plugins");
+import("etherpad.pad.padutils");
+
+
+function onRequest() {
+ plugins.loadPlugins();
+
+ if (request.params.action == 'install') {
+ plugins.enablePlugin(request.params.plugin);
+ } else if (request.params.action == 'uninstall') {
+ plugins.disablePlugin(request.params.plugin);
+ } else if (request.params.action == 'reinstall') {
+ plugins.disablePlugin(request.params.plugin);
+ plugins.loadPlugins(1);
+ plugins.enablePlugin(request.params.plugin);
+ }
+
+ helpers.addClientVars({
+ userAgent: request.headers["User-Agent"],
+ debugEnabled: request.params.djs,
+ clientIp: request.clientAddr,
+ colorPalette: COLOR_PALETTE,
+ serverTimestamp: +(new Date),
+ isProPad: pro_utils.isProDomainRequest(),
+ userIsGuest: padusers.isGuest(padusers.getUserId()),
+ userId: padusers.getUserId(),
+ });
+
+
+ padutils.setOptsAndCookiePrefs(request);
+ var prefs = helpers.getClientVar('cookiePrefsToSet');
+ var bodyClass = (prefs.isFullWidth ? "fullwidth" : "limwidth")
+
+ renderHtml("admin/pluginmanager.ejs",
+ {
+ prefs: prefs,
+ config: appjet.config,
+ bodyClass: 'nonpropad',
+ isPro: pro_utils.isProDomainRequest(),
+ isProAccountHolder: pro_utils.isProDomainRequest() && ! padusers.isGuest(padusers.getUserId()),
+ account: getSessionProAccount(), // may be falsy
+ });
+ return true;
+}
diff --git a/etherpad/src/etherpad/control/admincontrol.js b/etherpad/src/etherpad/control/admincontrol.js
new file mode 100644
index 0000000..ec48824
--- /dev/null
+++ b/etherpad/src/etherpad/control/admincontrol.js
@@ -0,0 +1,1482 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("fastJSON");
+import("netutils");
+import("funhtml.*");
+import("stringutils.{html,sprintf,startsWith,md5}");
+import("jsutils.*");
+import("sqlbase.sqlbase");
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+import("varz");
+import("comet");
+import("dispatch.{Dispatcher,PrefixMatcher,DirMatcher,forward}");
+
+import("etherpad.billing.team_billing");
+import("etherpad.globals.*");
+import("etherpad.utils.*");
+import("etherpad.licensing");
+import("etherpad.sessions.getSession");
+import("etherpad.sessions");
+import("etherpad.statistics.statistics");
+import("etherpad.log");
+import("etherpad.admin.shell");
+import("etherpad.usage_stats.usage_stats");
+import("etherpad.control.blogcontrol");
+import("etherpad.control.pro_beta_control");
+import("etherpad.control.statscontrol");
+import("etherpad.statistics.exceptions");
+import("etherpad.store.checkout");
+
+import("etherpad.pad.activepads");
+import("etherpad.pad.model");
+import("etherpad.pad.padutils");
+import("etherpad.pad.dbwriter");
+import("etherpad.collab.collab_server");
+
+import("etherpad.pro.pro_accounts");
+import("etherpad.pro.pro_utils");
+import("etherpad.pro.domains");
+import("etherpad.admin.plugins");
+import("etherpad.control.admin.pluginmanager");
+
+jimport("java.lang.System.out.println");
+
+jimport("net.appjet.oui.cometlatencies");
+jimport("net.appjet.oui.appstats");
+
+
+//----------------------------------------------------------------
+
+function _isAuthorizedAdmin() {
+ if (!isProduction()) {
+ return true;
+ }
+ return (getSession().adminAuth === true);
+}
+
+var _mainLinks = [
+ ['exceptions', 'Exceptions Monitor'],
+ ['usagestats/', 'Usage Stats'],
+ ['padinspector', 'Pad Inspector'],
+ ['dashboard', 'Dashboard'],
+ ['eepnet-licenses', 'EEPNET Licenses'],
+ ['config', 'appjet.config'],
+ ['shell', 'Shell'],
+ ['timings', 'timing data'],
+ ['broadcast-message', 'Pad Broadcast'],
+// ['analytics', 'Google Analytics'],
+ ['varz', 'varz'],
+ ['genlicense', 'Manually generate a license key'],
+ ['flows', 'Flows (warning: slow)'],
+ ['diagnostics', 'Pad Connection Diagnostics'],
+ ['cachebrowser', 'Cache Browser'],
+ ['pne-tracker', 'PNE Tracking Stats'],
+ ['reload-blog-db', 'Reload blog DB'],
+ ['pro-domain-accounts', 'Pro Domain Accounts'],
+ ['beta-valve', 'Beta Valve'],
+ ['reset-subscription', "Reset Subscription"],
+ ['pluginmanager/', "Plugin manager"]
+];
+
+function onRequest(name) {
+ if (name == "auth") {
+ return;
+ }
+ if (!_isAuthorizedAdmin()) {
+ getSession().cont = request.path;
+ response.redirect('/ep/admin/auth');
+ }
+
+ var disp = new Dispatcher();
+
+ disp.addLocations(plugins.callHook("handleAdminPath"));
+
+ disp.addLocations([
+ [PrefixMatcher('/ep/admin/pluginmanager/'), forward(pluginmanager)],
+ [PrefixMatcher('/ep/admin/usagestats/'), forward(statscontrol)]
+ ]);
+
+ return disp.dispatch();
+}
+
+function _commonHead() {
+ return HEAD(STYLE(
+ "html {font-family:Verdana,Helvetica,sans-serif;}",
+ "body {padding: 2em;}"
+ ));
+}
+
+//----------------------------------------------------------------
+
+function render_auth() {
+ var cont = getSession().cont;
+ if (getSession().message) {
+ response.write(DIV(P(B(getSession().message))));
+ delete getSession().message;
+ }
+ if (request.method == "GET") {
+ response.write(FORM({method: "POST", action: request.path},
+ P("Are you an admin?"),
+ LABEL("Password:"),
+ INPUT({type: "password", name: "password", value: ""}),
+ INPUT({type: "submit", value: "submit"})
+ ));
+ }
+ if (request.method == "POST") {
+ var pass = request.params.password;
+ if (pass === appjet.config['etherpad.adminPass']) {
+ getSession().adminAuth = true;
+ if (cont) {
+ response.redirect(cont);
+ } else {
+ response.redirect("/ep/admin/main");
+ }
+ } else {
+ getSession().message = "Bad Password.";
+ response.redirect(request.path);
+ }
+ }
+}
+
+function render_main() {
+ var div = DIV();
+
+ div.push(A({href: "/"}, html("&laquo;"), " home"));
+ div.push(H1("Admin"));
+
+ function addMenuItem(l) {
+ div.push(DIV(A({href: l[0]}, l[1])));
+ }
+
+ plugins.callHook("adminMenu").forEach(addMenuItem);
+ _mainLinks.forEach(addMenuItem);
+
+ if (sessions.isAnEtherpadAdmin()) {
+ div.push(P(A({href: "/ep/admin/setadminmode?v=false"},
+ "Exit Admin Mode")));
+ }
+ else {
+ div.push(P(A({href: "/ep/admin/setadminmode?v=true"},
+ "Enter Admin Mode")));
+ }
+ response.write(HTML(_commonHead(), BODY(div)));
+}
+
+//----------------------------------------------------------------
+
+function render_config() {
+
+ vars = [];
+ eachProperty(appjet.config, function(k,v) {
+ vars.push(k);
+ });
+
+ vars.sort();
+
+ response.setContentType('text/plain; charset=utf-8');
+ vars.forEach(function(v) {
+ response.write("appjet.config."+v+" = "+appjet.config[v]+"\n");
+ });
+}
+
+//----------------------------------------------------------------
+
+function render_test() {
+ response.setContentType("text/plain");
+ response.write(Packages.net.appjet.common.util.ExpiringMapping + "\n");
+ var m = new Packages.net.appjet.common.util.ExpiringMapping(10 * 1000);
+ response.write(m.toString() + "\n");
+ m.get("test");
+ return;
+ response.write(m.toString());
+}
+
+function render_dashboard() {
+ var body = BODY();
+ body.push(A({href: '/ep/admin/'}, html("&laquo; Admin")));
+ body.push(H1({style: "border-bottom: 1px solid black;"}, "Dashboard"));
+
+ /*
+ body.push(H2({style: "color: #226; font-size: 1em;"}, "License"));
+ var license = licensing.getLicense();
+ body.push(P(TT(" Licensed To (name): "+license.personName)));
+ body.push(P(TT(" Licensed To (organization): "+license.organizationName)));
+ body.push(P(TT(" Software Edition: "+license.editionName)));
+ var quota = ((license.userQuota > 0) ? license.userQuota : 'unlimited');
+ body.push(P(TT(" User Quota: "+quota)));
+ var expires = (license.expiresDate ? (license.expiresDate.toString()) : 'never');
+ body.push(P(TT(" Expires: "+expires)));
+ */
+
+ /*
+ body.push(H2({style: "color: #226; font-size: 1em;"}, "Active User Quota"));
+
+ var activeUserCount = licensing.getActiveUserCount();
+ var activeUserQuota = licensing.getActiveUserQuota();
+ var activeUserWindowStart = licensing.getActiveUserWindowStart();
+
+ body.push(P(TT(" Since ", B(activeUserWindowStart.toString()), ", ",
+ "you have used ", B(activeUserCount), " of ", B(activeUserQuota),
+ " active users.")));
+*/
+ body.push(H2({style: "color: #226; font-size: 1em;"}, "Uptime"));
+ body.push(P({style: "margin-left: 25px;"}, "Server running for "+renderServerUptime()+"."))
+
+ body.push(H2({style: "color: #226; font-size: 1em;"}, "Response codes"));
+ body.push(renderResponseCodes());
+
+ body.push(H2({style: "color: #226; font-size: 1em;"}, "Comet Connections"));
+ body.push(renderPadConnections());
+
+ body.push(H2({style: "color: #226; font-size: 1em;"}, "Comet Stats"));
+ body.push(renderCometStats());
+
+ body.push(H2({style: "color: #226; font-size: 1em;"}, "Recurring revenue, monthly"));
+ body.push(renderRevenueStats());
+
+ response.write(HTML(_commonHead(), body));
+}
+
+// Note: This function is called by the PNE dashboard (pro_admin_control.js)! Be careful.
+function renderPadConnections() {
+ var d = DIV();
+ var lastCount = cometlatencies.lastCount();
+
+ if (lastCount.isDefined()) {
+ var countMap = {};
+ Array.prototype.map.call(lastCount.get().elements().collect().toArray().unbox(
+ java.lang.Class.forName("java.lang.Object")),
+ function(x) {
+ countMap[x._1()] = x._2();
+ });
+ var totalConnected = 0;
+ var ul = UL();
+ eachProperty(countMap, function(k,v) {
+ ul.push(LI(k+": "+v));
+ if (/^\d+$/.test(v)) {
+ totalConnected += Number(v);
+ }
+ });
+ ul.push(LI(B("Total: ", totalConnected)));
+ d.push(ul);
+ } else {
+ d.push("Still collecting data... check back in a minute.");
+ }
+ return d;
+}
+
+// Note: This function is called by the PNE dashboard (pro_admin_control.js)! Be careful.
+function renderCometStats() {
+ var d = DIV();
+ var lastStats = cometlatencies.lastStats();
+ var lastCount = cometlatencies.lastCount();
+
+
+ if (lastStats.isDefined()) {
+ d.push(P("Realtime transport latency percentiles (microseconds):"));
+ var ul = UL();
+ lastStats.map(scalaF1(function(s) {
+ ['50', '90', '95', '99', 'max'].forEach(function(id) {
+ var fn = id;
+ if (id != "max") {
+ fn = ("p"+fn);
+ id = id+"%";
+ }
+ ul.push(LI(id, ": <", s[fn](), html("&micro;"), "s"));
+ });
+ }));
+ d.push(ul);
+ } else {
+ d.push(P("Still collecting data... check back in a minutes."));
+ }
+
+ /* ["p50", "p90", "p95", "p99", "max"].forEach(function(id) {
+ ul.push(LI(B(
+
+ return DIV(P(sprintf("50%% %d\t90%% %d\t95%% %d\t99%% %d\tmax %d",
+ s.p50(), s.p90(), s.p95(), s.p99(), s.max())),
+ P(sprintf("%d total messages", s.count())));
+ }})).get();*/
+
+
+ return d;
+}
+
+// Note: This function is called by the PNE dashboard (pro_admin_control.js)! Be careful.
+function renderResponseCodes() {
+ var statusCodeFrequencyNames = ["minute", "hour", "day", "week"];
+ var data = { };
+ var statusCodes = appstats.stati();
+ for (var i = 0; i < statusCodes.length; ++i) {
+ var name = statusCodeFrequencyNames[i];
+ var map = statusCodes[i];
+ map.foreach(scalaF1(function(pair) {
+ if (! (pair._1() in data)) data[pair._1()] = {};
+ var scmap = data[pair._1()];
+ scmap[name] = pair._2().count();
+ }));
+ };
+ var stats = TABLE({id: "responsecodes-table", style: "margin-left: 25px;",
+ border: 1, cellspacing: 0, cellpadding: 4},
+ TR.apply(TR, statusCodeFrequencyNames.map(function(name) {
+ return TH({colspan: 2}, "Last", html("&nbsp;"), name);
+ })));
+ var sortedStati = [];
+ eachProperty(data, function(k) {
+ sortedStati.push(k);
+ });
+ sortedStati.sort();
+ sortedStati.forEach(function(k, i) { // k is status code.
+ var row = TR();
+ statusCodeFrequencyNames.forEach(function(name) {
+ row.push(TD({style: 'width: 2em;'}, data[k][name] ? k+":" : ""));
+ row.push(TD(data[k][name] ? data[k][name] : ""));
+ });
+ stats.push(row);
+ });
+ return stats;
+}
+
+// Note: This function is called by the PNE dashboard (pro_admin_control.js)! Be careful.
+function renderServerUptime() {
+ var labels = ["seconds", "minutes", "hours", "days"];
+ var ratios = [60, 60, 24];
+ var time = appjet.uptime / 1000;
+ var pos = 0;
+ while (pos < ratios.length && time / ratios[pos] > 1.1) {
+ time = time / ratios[pos];
+ pos++;
+ }
+ return sprintf("%.1f %s", time, labels[pos]);
+}
+
+function renderRevenueStats() {
+ var subs = team_billing.getAllSubscriptions();
+ var total = 0;
+ var totalUsers = 0;
+ subs.forEach(function(sub) {
+ var users = team_billing.getMaxUsers(sub.customer);
+ var cost = team_billing.calculateSubscriptionCost(users, sub.coupon);
+ if (cost > 0) {
+ totalUsers += users;
+ total += cost;
+ }
+ });
+ return "US $"+checkout.dollars(total)+", from "+subs.length+" domains and "+totalUsers+" users.";
+}
+
+//----------------------------------------------------------------
+// Broadcasting Messages
+//----------------------------------------------------------------
+
+function render_broadcast_message_get() {
+ var body = BODY(FORM({action: request.path, method: 'post'},
+ H3('Broadcast Message to All Active Pad Clients:'),
+ TEXTAREA({name: 'msgtext', style: 'width: 100%; height: 100px;'}),
+ H3('JavaScript code to be eval()ed on client (optional, be careful!): '),
+ TEXTAREA({name: 'jscode', style: 'width: 100%; height: 100px;'}),
+ INPUT({type: 'submit', value: 'Broadcast Now'})));
+ response.write(HTML(body));
+}
+
+function render_broadcast_message_post() {
+ var msgText = request.params.msgtext;
+ var jsCode = request.params.jscode;
+ if (!(msgText || jsCode)) {
+ response.write("No mesage text or jscode specified.");
+ response.stop();
+ return;
+ }
+ collab_server.broadcastServerMessage({
+ type: 'NOTICE',
+ text: msgText,
+ js: jsCode
+ });
+ response.write(HTML(BODY(P("OK"), P(A({href: request.path}, "back")))));
+}
+
+function render_shell() {
+ shell.handleRequest();
+}
+
+//----------------------------------------------------------------
+// pad inspector
+//----------------------------------------------------------------
+
+function _getPadUrl(globalPadId) {
+ var superdomain = pro_utils.getRequestSuperdomain();
+ var domain;
+ if (padutils.isProPadId(globalPadId)) {
+ var domainId = padutils.getDomainId(globalPadId);
+ domain = domains.getDomainRecord(domainId).subDomain +
+ '.' + superdomain;
+ }
+ else {
+ domain = superdomain;
+ }
+ var localId = padutils.globalToLocalId(globalPadId);
+ return "http://"+httpHost(domain)+"/"+localId;
+}
+
+function render_padinspector_get() {
+ var padId = request.params.padId;
+ if (!padId) {
+ response.write(FORM({action: request.path, method: 'get', style: 'border: 1px solid #ccc; background-color: #eee; padding: .2em 1em;'},
+ P("Pad Lookup: ",
+ INPUT({name: 'padId', value: '<enter pad id>'}),
+ INPUT({type: 'submit'}))));
+
+ // show recently active pads; the number of them may vary; lots of
+ // activity in a pad will push others off the list
+ response.write(H3("Recently Active Pads:"));
+ var recentlyActiveTable = TABLE({cellspacing: 0, cellpadding: 6, border: 1,
+ style: 'font-family: monospace;'});
+ var recentPads = activepads.getActivePads();
+ recentPads.forEach(function (info) {
+ var time = info.timestamp; // number
+ var pid = info.padId;
+ model.accessPadGlobal(pid, function(pad) {
+ if (pad.exists()) {
+ var numRevisions = pad.getHeadRevisionNumber();
+ var connected = collab_server.getNumConnections(pad);
+ recentlyActiveTable.push(
+ TR(TD(B(pid)),
+ TD({style: 'font-style: italic;'}, timeAgo(time)),
+ TD(connected+" connected"),
+ TD(numRevisions+" revisions"),
+ TD(A({href: qpath({padId: pid, revtext: "HEAD"})}, "HEAD")),
+ TD(A({href: qpath({padId: pid})}, "inspect")),
+ TD(A({href: qpath({padId: pid, snoop: 1})}, "snoop"))
+ ));
+ }
+ }, "r");
+ });
+ response.write(recentlyActiveTable);
+ response.stop();
+ }
+ if (startsWith(padId, '/')) {
+ padId = padId.substr(1);
+ }
+ if (request.params.snoop) {
+ sessions.setIsAnEtherpadAdmin(true);
+ response.redirect(_getPadUrl(padId));
+ }
+ if (request.params.setsupportstimeslider) {
+ var v = (String(request.params.setsupportstimeslider).toLowerCase() ==
+ 'true');
+ model.accessPadGlobal(padId, function(pad) {
+ pad.setSupportsTimeSlider(v);
+ });
+ response.write("on pad "+padId+": setSupportsTimeSlider("+v+")");
+ response.stop();
+ }
+ model.accessPadGlobal(padId, function(pad) {
+ if (! pad.exists()) {
+ response.write("Pad not found: /"+padId);
+ }
+ else {
+ var headRev = pad.getHeadRevisionNumber();
+ var div = DIV({style: 'font-family: monospace;'});
+
+ if (request.params.revtext) {
+ var i;
+ if (request.params.revtext == "HEAD") {
+ i = headRev;
+ } else {
+ i = Number(request.params.revtext);
+ }
+ var infoObj = {};
+ div.push(H2(A({href: request.path}, "PadInspector"),
+ ' > ', A({href: request.path+'?padId='+padId}, "/"+padId),
+ ' > ', "Revision ", i, "/", headRev,
+ SPAN({style: 'color: #949;'}, ' [ ', pad.getRevisionDate(i).toString(), ' ] ')));
+ div.push(H3("Browse Revisions: ",
+ ((i > 0) ? A({id: 'previous', href: qpath({revtext: (i-1)})}, '<< previous') : ''),
+ ' ',
+ ((i < pad.getHeadRevisionNumber()) ? A({id: 'next', href: qpath({revtext:(i+1)})}, 'next >>') : '')),
+ DIV({style: 'padding: 1em; border: 1px solid #ccc;'},
+ pad.getRevisionText(i, infoObj)));
+ if (infoObj.badLastChar) {
+ div.push(P("Bad last character of text (not newline): "+infoObj.badLastChar));
+ }
+ } else if (request.params.dumpstorage) {
+ div.push(P(collab_server.dumpStorageToString(pad)));
+ } else if (request.params.showlatest) {
+ div.push(P(pad.text()));
+ } else {
+ div.push(H2(A({href: request.path}, "PadInspector"), ' > ', "/"+padId));
+ // no action
+ div.push(P(A({href: qpath({revtext: 'HEAD'})}, 'HEAD='+headRev)));
+ div.push(P(A({href: qpath({dumpstorage: 1})}, 'dumpstorage')));
+ var supportsTimeSlider = pad.getSupportsTimeSlider();
+ if (supportsTimeSlider) {
+ div.push(P(A({href: qpath({setsupportstimeslider: 'false'})}, 'hide slider')));
+ }
+ else {
+ div.push(P(A({href: qpath({setsupportstimeslider: 'true'})}, 'show slider')));
+ }
+ }
+ }
+
+ var script = SCRIPT({type: 'text/javascript'}, html([
+ '$(document).keydown(function(e) {',
+ ' var h = undefined;',
+ ' if (e.keyCode == 37) { h = $("#previous").attr("href"); }',
+ ' if (e.keyCode == 39) { h = $("#next").attr("href"); }',
+ ' if (h) { window.location.href = h; }',
+ '});'
+ ].join('\n')));
+
+ response.write(HTML(
+ HEAD(SCRIPT({type: 'text/javascript', src: '/static/js/jquery-1.3.2.js?'+(+(new Date))})),
+ BODY(div, script)));
+ }, "r");
+}
+
+function render_analytics() {
+ response.redirect("https://www.google.com/analytics/reporting/?reset=1&id=12611622");
+}
+
+//----------------------------------------------------------------
+// eepnet license display
+//----------------------------------------------------------------
+
+function render_eepnet_licenses() {
+ var data = sqlobj.selectMulti('eepnet_signups', {}, {orderBy: 'date'});
+ var t = TABLE({border: 1, cellspacing: 0, cellpadding: 2});
+ var cols = ['date','email','orgName','firstName','lastName', 'jobTitle','phone','estUsers'];
+ data.forEach(function(x) {
+ var tr = TR();
+ cols.forEach(function(colname) {
+ tr.push(TD(x[colname]));
+ });
+ t.push(tr);
+ });
+ response.write(HTML(BODY({style: 'font-family: monospace;'}, t)));
+}
+
+//----------------------------------------------------------------
+// pad integrity
+//----------------------------------------------------------------
+
+/*function render_changesettest_get() {
+ var nums = [0, 1, 2, 3, 0xfffffff, 0x02345678, 4];
+ var str = Changeset.numberArrayToString(nums);
+ var result = Changeset.numberArrayFromString(str);
+ var resultArray = result[0];
+ var remainingString = result[1];
+ var bad = false;
+ if (remainingString) {
+ response.write(P("remaining string length is: "+remainingString.length));
+ bad = true;
+ }
+ if (nums.length != resultArray.length) {
+ response.write(P("length mismatch: "+nums.length+" / "+resultArray.length));
+ bad = true;
+ }
+ response.write(P(nums[2]));
+ for(var i=0;i<nums.length;i++) {
+ var a = nums[i];
+ var b = resultArray[i];
+ if (a !== b) {
+ response.write(P("mismatch at element "+i+": "+a+" / "+b));
+ bad = true;
+ }
+ }
+ if (! bad) {
+ response.write("SUCCESS");
+ }
+}*/
+
+/////////
+
+function render_appendtest() {
+ var padId = request.params.padId;
+ var mode = request.params.mode;
+ var text = request.params.text;
+
+ model.accessPadGlobal(padId, function(pad) {
+ if (mode == "append") {
+ collab_server.appendPadText(pad, text);
+ }
+ else if (mode == "replace") {
+ collab_server.setPadText(pad, text);
+ }
+ });
+}
+
+//function render_flushall() {
+// dbwriter.writeAllToDB(null, true);
+// response.write("OK");
+//}
+
+//function render_flushpad() {
+// var padId = request.params.padId;
+// model.accessPadGlobal(padId, function(pad) {
+// dbwriter.writePad(pad, true);
+// });
+// response.write("OK");
+//}
+
+/*function render_foo() {
+ locking.doWithPadLock("CAT", function() {
+ sqlbase.createJSONTable("STUFF");
+ sqlbase.putJSON("STUFF", "dogs", {very:"bad"});
+ response.write(sqlbase.getJSON("STUFF", "dogs")); // {very:"bad"}
+ response.write(',');
+ response.write(sqlbase.getJSON("STUFF", "cats")); // undefined
+ response.write("<br/>");
+
+ sqlbase.createStringArrayTable("SEQUENCES");
+ sqlbase.putStringArrayElement("SEQUENCES", "fibo", 0, "1");
+ sqlbase.putStringArrayElement("SEQUENCES", "fibo", 1, "1");
+ sqlbase.putStringArrayElement("SEQUENCES", "fibo", 2, "2");
+ sqlbase.putStringArrayElement("SEQUENCES", "fibo", 3, "3");
+ sqlbase.putStringArrayElement("SEQUENCES", "fibo", 4, "5");
+ sqlbase.putStringArrayElement("SEQUENCES", "fibo", 30, "number30");
+ sqlbase.putStringArrayElement("SEQUENCES", "fibo", 29, "number29");
+ sqlbase.deleteStringArrayElement("SEQUENCES", "fibo", 29);
+ sqlbase.putConsecutiveStringArrayElements("SEQUENCES", "fibo", 19, [19,20,21,22]);
+ var a = [];
+ for(var i=0;i<31;i++) {
+ a.push(sqlbase.getStringArrayElement("SEQUENCES", "fibo", i));
+ }
+ response.write(a.join(',')); // 1,1,2,3,5,,, ... 19,20,21,22, ... ,,,number30
+ });
+}*/
+
+function render_timings() {
+ var timer = Packages.net.appjet.ajstdlib.timer;
+ var opnames = timer.getOpNames();
+
+ response.write(P(A({href: '/ep/admin/timingsreset'}, "reset all")));
+
+ var t = TABLE({border: 1, cellspacing: 0, cellpadding: 3, style: 'font-family: monospace;'});
+ t.push(TR(TH("operation"),
+ TH("sample_count"),
+ TH("total_ms"),
+ TH("avg_ms")));
+
+ function r(x) {
+ return sprintf("%09.2f", x);
+ }
+ var rows = [];
+ for (var i = 0; i < opnames.length; i++) {
+ var stats = timer.getStats(opnames[i]);
+ rows.push([String(opnames[i]),
+ Math.floor(stats[0]),
+ stats[1],
+ stats[2]]);
+ }
+
+ var si = Number(request.params.sb || 0);
+
+ rows.sort(function(a,b) { return cmp(b[si],a[si]); });
+
+ rows.forEach(function(row) {
+ t.push(TR(TD(row[0]),
+ TD(row[1]),
+ TD(r(row[2])),
+ TD(r(row[3]))));
+ });
+
+ response.write(t);
+}
+
+function render_timingsreset() {
+ Packages.net.appjet.ajstdlib.timer.reset();
+ response.redirect('/ep/admin/timings');
+}
+
+// function render_jsontest() {
+// response.setContentType('text/plain; charset=utf-8');
+
+// var a = [];
+// a[0] = 5;
+// a[1] = 6;
+// a[9] = 8;
+// a['foo'] = "should appear";
+
+// jtest(a);
+
+// var obj1 = {
+// a: 1,
+// b: 2,
+// q: [true,true,,,,,,false,false,,,,{},{a:{a:{a:{a:{a:{a:[[{a:{a:false}}]]}}}}}}],
+// c: "foo",
+// d: {
+// nested: { obj: 'yo' },
+// bar: "baz"
+// },
+// e: 3.6,
+// 1: "numeric value",
+// 2: "anohter numeric value",
+// 2.46: "decimal numeric value",
+// foo: 3.212312310,
+// bar: 0.234242e-10,
+// baz: null,
+// ar: [{}, '1', [], [[[[]]]]],
+// n1: null,
+// n2: undefined,
+// n3: false,
+// n4: "null",
+// n5: "undefined"
+// };
+
+// jtest(obj1);
+
+// var obj2 = {
+// t1: 1232738532270
+// };
+
+// jtest(obj2);
+
+// // a javascript object plus numeric ids
+// var obj3 = {};
+// obj3["foo"] = "bar";
+// obj3[1] = "aaron";
+// obj3[2] = "iba";
+
+// jtest(obj3);
+
+// function jtest(x) {
+// response.write('----------------------------------------------------------------\n\n');
+
+// var str1 = JSON.stringify(x);
+// var str2 = fastJSON.stringify(x);
+
+// var str1_ = JSON.stringify(JSON.parse(str1));
+// var str2_ = fastJSON.stringify(fastJSON.parse(str2));
+
+// response.write([str1,str2].join('\n') + '\n\n');
+// response.write([str1_,str2_].join('\n') + '\n\n');
+// }
+// }
+
+function render_varz() {
+ var varzes = varz.getSnapshot();
+ response.setContentType('text/plain; charset=utf-8');
+ for (var k in varzes) {
+ response.write(k+': '+varzes[k]+'\n');
+ }
+}
+
+function render_extest() {
+ throw new Error("foo");
+}
+
+
+function _diagnosticRecordToHtml(obj) {
+ function valToHtml(o, noborder) {
+ if (typeof (o) != 'object') {
+ return String(o);
+ }
+ var t = TABLE((noborder ? {} : {style: "border-left: 1px solid black; border-top: 1px solid black;"}));
+ if (typeof (o.length) != 'number') {
+ eachProperty(o, function(k, v) {
+ var tr = TR();
+ tr.push(TD({valign: "top", align: "right"}, B(k)));
+ tr.push(TD(valToHtml(v)));
+ t.push(tr);
+ });
+ } else {
+ if (o.length == 0) return "(empty array)";
+ for (var i = 0; i < o.length; ++i) {
+ var tr = TR();
+ tr.push(TD({valign: "top", align: "right"}, B(i)));
+ tr.push(TD(valToHtml(o[i])));
+ t.push(tr);
+ }
+ }
+ return t;
+ }
+ return valToHtml(obj, true);
+}
+
+function render_diagnostics() {
+ var start = Number(request.params.start || 0);
+ var count = Number(request.params.count || 100);
+ var diagnostic_entries = sqlbase.getAllJSON("PAD_DIAGNOSTIC", start, count);
+ var expandArray = request.params.expand || [];
+
+ if (typeof (expandArray) == 'string') expandArray = [expandArray];
+ var expand = {};
+ for (var i = 0; i < expandArray.length; ++i) {
+ expand[expandArray[i]] = true;
+ }
+
+ function makeLink(text, expand, collapse, start0, count0) {
+ start0 = (typeof(start0) == "number" ? start0 : start);
+ count0 = count0 || count;
+ collapse = collapse || [];
+ expand = expand || [];
+
+ var collapseObj = {};
+ for (var i = 0; i < collapse.length; ++i) {
+ collapseObj[collapse[i]] = true;
+ }
+ var expandString =
+ expandArray.concat(expand).filter(function(x) { return ! collapseObj[x] }).map(function(x) { return "expand="+encodeURIComponent(x) }).join("&");
+
+ var url = request.path + "?start="+start0+"&count="+count0+"&"+expandString+(expand.length == 1 ? "#"+md5(expand[0]) : "");
+
+ return A({href: url}, text);
+ }
+
+ var t = TABLE({border: 1, cellpadding: 2, style: "font-family: monospace;"});
+ diagnostic_entries.forEach(function(ent) {
+ var tr = TR()
+ tr.push(TD({valign: "top", align: "right"}, (new Date(Number(ent.id.split("-")[0]))).toString()));
+ tr.push(TD({valign: "top", align: "right"}, ent.id));
+ if (expand[ent.id]) {
+ tr.push(TD(A({name: md5(ent.id)}, makeLink("(collapse)", false, [ent.id])), BR(),
+ _diagnosticRecordToHtml(ent.value)));
+ } else {
+ tr.push(TD(A({name: md5(ent.id)}, makeLink(_diagnosticRecordToHtml({padId: ent.value.padId, disconnectedMessage: ent.value.disconnectedMessage}), [ent.id]))));
+ }
+ t.push(tr);
+ });
+
+ var body = BODY();
+ body.push(P("Showing entries ", start, "-", start+diagnostic_entries.length, ". ",
+ (start > 0 ? makeLink("Show previous "+count+".", [], [], start-count) : ""),
+ (diagnostic_entries.length == count ? makeLink("Show next "+count+".", [], [], start+count) : "")));
+ body.push(t);
+
+ response.write(HTML(body));
+}
+
+//----------------------------------------------------------------
+import("etherpad.billing.billing");
+
+function render_testbillingdirect() {
+ var invoiceId = billing.createInvoice();
+ var ret = billing.directPurchase(invoiceId, 0, 'EEPNET', 500, 'DISCOUNT', {
+ cardType: "Visa",
+ cardNumber: "4501251685453214",
+ cardExpiration: "042019",
+ cardCvv: "123",
+ nameSalutation: "Dr.",
+ nameFirst: "John",
+ nameMiddle: "D",
+ nameLast: "Zamfirescu",
+ nameSuffix: "none",
+ addressStreet: "531 Main St. Apt. 1227",
+ addressStreet2: "",
+ addressCity: "New York",
+ addressState: "NY",
+ addressCountry: "US",
+ addressZip: "10044"
+ }, "https://"+request.host+"/ep/about/testbillingnotify");
+ if (ret.status == 'success') {
+ response.write(P("Success! Invoice id: "+ret.purchaseInfo.invoiceId+" for "+ret.purchaseInfo.cost));
+ } else {
+ response.write(P("Failure: "+ret.toSource()))
+ }
+}
+
+function render_testbillingrecurring() {
+ var invoiceId = billing.createInvoice();
+ var ret = billing.directPurchase(invoiceId, 0, 'EEPNET', 1, 'DISCOUNT', {
+ cardType: "Visa",
+ cardNumber: "4501251685453214",
+ cardExpiration: "042019",
+ cardCvv: "123",
+ nameSalutation: "Dr.",
+ nameFirst: "John",
+ nameMiddle: "D",
+ nameLast: "Zamfirescu",
+ nameSuffix: "none",
+ addressStreet: "531 Main St. Apt. 1227",
+ addressStreet2: "",
+ addressCity: "New York",
+ addressState: "NY",
+ addressCountry: "US",
+ addressZip: "10044"
+ }, "https://"+request.host+"/ep/about/testbillingnotify", true);
+ if (ret.status == 'success') {
+ var transactionId = billing.getTransaction(ret.purchaseInfo.transactionId).txnId;
+ var purchaseId = ret.purchaseInfo.purchaseId;
+ response.write(P("Direct billing successful. PayPal transaction id: ", transactionId));
+
+ invoiceId = billing.createInvoice();
+ ret = billing.asyncRecurringPurchase(
+ invoiceId, purchaseId, transactionId, 500,
+ "https://"+request.host+"/ep/about/testbillingnotify");
+ if (ret.status == 'success') {
+ response.write(P("Woot! Recurrent billing successful! ", ret.purchaseInfo.invoiceId, " for ", ret.purchaseInfo.cost));
+ } else {
+ response.write(P("Failure: "+ret.toSource()));
+ }
+ } else {
+ response.write("Direct billing failure: "+ret.toSource());
+ }
+}
+
+function render_testbillingexpress() {
+ var urlPrefix = "http://"+request.host+request.path;
+ var session = sessions.getSession();
+ var notifyUrl = "http://"+request.host+"/ep/about/testbillingnotify";
+
+ switch (request.params.step) {
+ case '0':
+ response.write(P("You'll be charged $400 for EEPNET. Click the link below to go to paypal."));
+ response.write(A({href: urlPrefix+"?step=1"}, "Link"));
+ break;
+ case '1':
+ var ret = billing.beginExpressPurchase(1, 'EEPNET', 400, 'DISCOUNT', urlPrefix+"?step=2", urlPrefix+"?step=0", notifyUrl);
+ if (ret.status != 'success') {
+ response.write("Error: "+ret.debug.toSource());
+ response.stop();
+ }
+ session.purchaseInfo = ret.purchaseInfo;
+ response.redirect(paypalPurchaseUrl(ret.purchaseInfo.token));
+ break;
+ case '2':
+ var ret = billing.continueExpressPurchase(session.purchaseInfo);
+ if (! ret.status == 'success') {
+ response.write("Error: "+ret.debug.toSource());
+ response.stop();
+ }
+ session.payerInfo = ret.payerInfo;
+
+ response.write(P("You approved the transaction. Click 'confirm' to confirm."));
+ response.write(A({href: urlPrefix+"?step=3"}, "Confirm"));
+ break;
+ case '3':
+ var ret = billing.completeExpressPurchase(session.purchaseInfo, session.payerInfo, notifyUrl);
+ if (ret.status == 'failure') {
+ response.write("Error: "+ret.debug.toSource());
+ response.stop();
+ }
+ if (ret.status == 'pending') {
+ response.write("Your charge is pending. You will be notified by email when your payment clears. Your invoice number is "+session.purchaseInfo.invoiceId);
+ response.stop();
+ }
+
+ response.write(P("Purchase completed: invoice # is "+session.purchaseInfo.invoiceId+" for "+session.purchaseInfo.cost));
+ break;
+ default:
+ response.redirect(request.path+"?step=0");
+ }
+}
+
+//----------------------------------------------------------------
+
+function render_genlicense_get() {
+
+ var t = TABLE({border: 1});
+ function ti(id, label) {
+ t.push(TR(TD({align: "right"}, LABEL({htmlFor: id}, label+":")),
+ TD(INPUT({id: id, name: id, type: 'text', size: 40}))));
+ }
+
+ ti("name", "Name of Licensee");
+ ti("org", "Name of Organization");
+ ti("userQuota", "User Quota");
+
+ t.push(TR(TD({align: "right"}, LABEL("Software Edtition:")),
+ TD( SELECT({name: "edition"},
+ OPTION({value: licensing.getEditionId('PRIVATE_NETWORK_EVALUATION')},
+ "Private Network EVALUATION"),
+ OPTION({value: licensing.getEditionId('PRIVATE_NETWORK')},
+ "Private Network")))));
+
+ ti("expdays", "Number of days until expiration\n(leave blank if never expires)");
+
+ t.push(TR(TD({colspan: 2}, INPUT({type: "submit"}))));
+
+ var f = FORM({action: request.path, method: "post"});
+ f.push(t);
+
+ response.write(HTML(BODY(f)));
+}
+
+function render_genlicense_post() {
+ var name = request.params.name;
+ var org = request.params.org;
+ var editionId = +request.params.edition;
+ var editionName = licensing.getEditionName(editionId);
+ var userQuota = +request.params.userQuota;
+
+ var expiresTime = null;
+ if (request.params.expdays) {
+ expiresTime = +(new Date) + 1000*60*60*24*(+request.params.expdays);
+ }
+
+ var licenseKey = licensing.generateNewKey(
+ name,
+ org,
+ expiresTime,
+ editionId,
+ userQuota
+ );
+
+ // verify
+ if (!licensing.isValidKey(licenseKey)) {
+ throw Error("License key I just created is not valid: "+licenseKey);
+ }
+
+ // TODO: write to database??
+ //
+
+ // display
+ var licenseInfo = licensing.decodeLicenseInfoFromKey(licenseKey);
+ var t = TABLE({border: 1});
+ function line(k, v) {
+ t.push(TR(TD({align: "right"}, k+":"),
+ TD(v)));
+ }
+
+ var key = licenseKey.split(":")[2];
+ if ((key.length % 2) != 0) {
+ key = key + "+";
+ }
+ var keyLine1 = key.substr(0, key.length/2);
+ var keyLine2 = key.substr(key.length/2, key.length);
+
+ line("Name", licenseInfo.personName);
+ line("Organization", licenseInfo.organizationName);
+ line("Key", P(keyLine1, BR(), keyLine2));
+ line("Software Edition", licenseInfo.editionName);
+ line("User Quota", licenseInfo.userQuota);
+ line("Expires", (+licenseInfo.expiresDate > 0) ? licenseInfo.expiresDate.toString() : "(never)");
+
+ response.write(HTML(BODY(t)));
+}
+
+//----------------------------------------------------------------
+
+import("etherpad.metrics.metrics");
+
+function render_flows() {
+ if (request.params.imgId && getSession()[request.params.imgId]) {
+ var arr = getSession()[request.params.imgId];
+ metrics[arr[0]](arr[1], Array.prototype.slice.call(arr[2]));
+ response.stop();
+ }
+
+ function drawHistogram(name, h) {
+ var imgKey = Math.round(Math.random()*1e12);
+ print(IMG({src: request.path+"?imgId="+imgKey}));
+ getSession()[imgKey] = ["respondWithPieChart", name, h];
+ }
+
+ var body = BODY();
+ function print() {
+ for (var i = 0; i < arguments.length; ++i) {
+ body.push(arguments[i]);
+ }
+ }
+
+ var [startDate, endDate] = [7, 1].map(function(a) { return new Date(Date.now() - 86400*1000*a); });
+
+ var allFlows = metrics.getFlows(startDate, endDate);
+
+/*
+ print(P("All flows:"));
+
+ eachProperty(allFlows, function(k, flows) {
+ print(P(k, html(" &raquo; ")));
+ flows.forEach(function(flow) {
+ print(P(flow.toString()));
+ });
+ });
+ response.write(HTML(body));
+ return;
+*/
+
+ print(P("Parsing logs from: "+startDate+" through "+endDate));
+
+ var fs =
+ [metrics.getFunnel(startDate, endDate, ['/ep/about/pricing', '/ep/about/pricing-eepnet', '/ep/store/eepnet-eval-signup'], true),
+ metrics.getFunnel(startDate, endDate, ['/ep/about/pricing', '/ep/about/pricing-free'], true),
+ metrics.getFunnel(startDate, endDate, ['/ep/about/pricing', '/ep/about/pricing-eepod'], true),
+ metrics.getFunnel(startDate, endDate, ['/ep/about/pricing', '/ep/store/eepnet-eval-signup'], true),
+ metrics.getFunnel(startDate, endDate, ['/', '(pad)']),
+ metrics.getFunnel(startDate, endDate, ['/', '/ep/pad/newpad'], true),
+ metrics.getFunnel(startDate, endDate, ['/ep/about/screencast', '(pad)'])];
+
+ function vcnt(i, i2) {
+ return fs[i].visitorCounts[i2];
+ }
+ function pct(f) {
+ return ""+Math.round(f*10000)/100+"%"
+ }
+ function cntAndPct(i, i2) {
+ if (i2 === undefined) { i2 = 1; }
+ return ""+vcnt(i, i2)+" ("+pct(vcnt(i, i2)/vcnt(i, i2-1))+")";
+ }
+ print(P("Of ", vcnt(0, 0), " visitors to the pricing page, ",
+ cntAndPct(0), " of them viewed eepnet, (", cntAndPct(0, 2), " of those downloaded), ",
+ cntAndPct(1), " of them viewed free, and ",
+ cntAndPct(2), " of them viewed eepod. ",
+ cntAndPct(3), " of them clicked on the eval signup link straight up."
+ ),
+ P("Of ", vcnt(4, 0), " visitors to the home page, ",
+ cntAndPct(4), " of them went to a pad page in the same flow; ",
+ cntAndPct(5), " of them clicked the new pad button immediately."),
+ P("Of ", vcnt(6, 0), " vistitors to the screencast page, ",
+ cntAndPct(6), " of them visisted a pad page in the same flow."));
+
+ var origins = metrics.getOrigins(startDate, endDate, true);
+ print(P("Flow first origins: "));
+ drawHistogram("first origins", origins.flowFirsts);
+
+ var firstHits = metrics.getOrigins(startDate, endDate, false, true);
+ var padFirstHits = 0;
+ var nonPadFirstHits = 0;
+ print(P("First paths hit: "));
+ drawHistogram("first paths", firstHits.flowFirsts);
+ firstHits.flowFirsts.filter(function(x) {
+ if (x.value != '/' && ! startsWith(x.value, "/ep/")) {
+ padFirstHits += x.count;
+ return false;
+ }
+ nonPadFirstHits += x.count;
+ return true;
+ });
+ print(P("Some pad page: "+padFirstHits),
+ P("Non-pad page: "+nonPadFirstHits));
+
+ var exitsFromHomepage = metrics.getExits(startDate, endDate, '/', true);
+ print(P("Exits from homepage: "));
+ drawHistogram("exits", exitsFromHomepage.histogram)
+
+ response.write(HTML(body));
+}
+
+//----------------------------------------------------------------
+
+import("etherpad.pad.pad_migrations");
+
+function render_padmigrations() {
+ var residue = (request.params.r || 0);
+ var modulus = (request.params.m || 1);
+ var name = (request.params.n || (residue+"%"+modulus));
+ pad_migrations.runBackgroundMigration(residue, modulus, name);
+ response.write("done");
+ return true;
+}
+
+// TODO: add ability to delete entries?
+// TODO: show sizes?
+function render_cachebrowser() {
+ var path = request.params.path;
+ if (path && path.charAt(0) == ',') {
+ path = path.substr(1);
+ }
+ var pathArg = (path || "");
+ var c = appjet.cache;
+ if (path) {
+ path.split(",").forEach(function(part) {
+ c = c[part];
+ });
+ }
+
+ var d = DIV({style: 'font-family: monospace; text-decoration: none;'});
+
+ d.push(H3("appjet.cache --> "+pathArg.split(",").join(" --> ")));
+
+ var t = TABLE({border: 1});
+ keys(c).sort().forEach(function(k) {
+ var v = c[k];
+ if (v && (typeof(v) == 'object') && (!v.getDate)) {
+ t.push(TR(TD(A({style: 'text-decoration: none;',
+ href: request.path+"?path="+pathArg+","+k}, k))));
+ } else {
+ t.push(TR(TD(k), TD(v)));
+ }
+ });
+
+ d.push(t);
+ response.write(d);
+}
+
+function render_pne_tracker_get() {
+ var data = sqlobj.selectMulti('pne_tracking_data', {}, {});
+ data.sort(function(x, y) { return cmp(y.date, x.date); });
+
+ var t = TABLE();
+
+ var headrow = TR();
+ ['date', 'remote host', 'keyHash', 'name', 'value'].forEach(function(x) {
+ headrow.push(TH({align: "left", style: "padding: 0 6px;"}, x));
+ });
+ t.push(headrow);
+
+ data.forEach(function(d) {
+ var tr = TR();
+
+ tr.push(TD(d.date.toString().split(' ').slice(0,5).join('-')));
+
+ if (d.remoteIp) {
+ tr.push(TD(netutils.getHostnameFromIp(d.remoteIp) || d.remoteIp));
+ } else {
+ tr.push(TD("-"));
+ }
+
+ if (d.keyHash) {
+ tr.push(TD(A({href: '/ep/admin/pne-tracker-lookup-keyhash?hash='+d.keyHash}, d.keyHash)));
+ } else {
+ tr.push(TD("-"));
+ }
+
+ tr.push(TD(d.name));
+ tr.push(TD(d.value));
+
+ t.push(tr);
+ });
+
+ response.write(HTML(HEAD(html("<style>td { border-bottom: 1px solid #ddd; border-right: 1px solid #ddd; padding: 0 6px; } \n tr:hover { background: #ffc; }</style>"),
+ BODY({style: "font-family: monospace; font-size: 12px;"}, t))));
+}
+
+function render_pne_tracker_lookup_keyhash_get() {
+ var hash = request.params.hash;
+ // brute force it
+ var allLicenses = sqlobj.selectMulti('eepnet_signups', {}, {});
+ var record = null;
+ var i = 0;
+ while (i < allLicenses.length && record == null) {
+ var d = allLicenses[i];
+ if (md5(d.licenseKey).substr(0, 16) == hash) {
+ record = d;
+ }
+ i++;
+ }
+ if (!record) {
+ response.write("Not found. Perhaps this was a test download from local development, or a paid customer whose licenses we don't currently look through on this page.");
+ } else {
+ var kl = keys(record).sort();
+ var t = TABLE();
+ kl.forEach(function(k) {
+ t.push(TR(TH({align: "right"}, k+":"),
+ TD({style: "padding-left: 1em;"}, record[k])));
+ });
+ response.write(HTML(BODY(DIV({style: "font-family: monospace;"},
+ DIV(H1("Trial Signup Record:")), t))));
+ }
+}
+
+function render_reload_blog_db_get() {
+ var d = DIV();
+ if (request.params.ok) {
+ d.push(DIV(P("OK")));
+ }
+ d.push(FORM({method: "post", action: request.path},
+ INPUT({type: "submit", value: "Reload Blog DB Now"})));
+ response.write(HTML(BODY(d)));
+}
+
+function render_reload_blog_db_post() {
+ blogcontrol.reloadBlogDb();
+ response.redirect(request.path+"?ok=1");
+}
+
+function render_pro_domain_accounts() {
+ var accounts = sqlobj.selectMulti('pro_accounts', {}, {});
+ var domains = sqlobj.selectMulti('pro_domains', {}, {});
+
+ // build domain map
+ var domainMap = {};
+ domains.forEach(function(d) { domainMap[d.id] = d; });
+ accounts.sort(function(a,b) { return cmp(b.lastLoginDate, a.lastLoginDate); });
+
+ var b = BODY({style: "font-family: monospace;"});
+ b.push(accounts.length + " pro accounts.");
+ var t = TABLE({border: 1});
+ t.push(TR(TH("email"),
+ TH("domain"),
+ TH("lastLogin")));
+ accounts.forEach(function(u) {
+ t.push(TR(TD(u.email),
+ TD(domainMap[u.domainId].subDomain+"."+request.domain),
+ TD(u.lastLoginDate)));
+ });
+
+ b.push(t);
+
+ response.write(HTML(b));
+}
+
+
+function render_beta_valve_get() {
+ var d = DIV(
+ P("Beta Valve Status: ",
+ (pro_beta_control.isValveOpen() ?
+ SPAN({style: "color: green;"}, B("OPEN")) :
+ SPAN({style: "color: red;"}, B("CLOSED")))),
+ P(FORM({action: '/ep/admin/beta-valve-toggle', method: "post"},
+ BUTTON({type: "submit"}, "Toggle"))));
+
+ var t = TABLE({border: 1, cellspacing: 0, cellpadding: 4, style: "font-family: monospace;"});
+ var signupList = sqlobj.selectMulti('pro_beta_signups', {}, {});
+ signupList.sort(function(a, b) {
+ return cmp(b.signupDate, a.signupDate);
+ });
+
+ d.push(HR());
+
+ if (getSession().betaAdminMessage) {
+ d.push(DIV({style: "border: 1px solid #ccc; padding: 1em; background: #eee;"},
+ getSession().betaAdminMessage));
+ delete getSession().betaAdminMessage;
+ }
+
+ d.push(P(signupList.length + " beta signups"));
+
+ d.push(FORM({action: '/ep/admin/beta-invite-multisend', method: 'post'},
+ P("Send ", INPUT({type: 'text', name: 'count', size: 3}), " invites."),
+ INPUT({type: "submit"})));
+
+ t.push(TR(TH("id"), TH("email"), TH("signupDate"),
+ TH("activationDate"), TH("activationCode"), TH(' ')));
+
+ signupList.forEach(function(s) {
+ var tr = TR();
+ tr.push(TD(s.id),
+ TD(s.email),
+ TD(s.signupDate),
+ TD(s.isActivated ? s.activationDate : "-"),
+ TD(s.activationCode));
+ if (!s.activationCode) {
+ tr.push(TD(FORM({action: '/ep/admin/beta-invite-send', method: 'post'},
+ INPUT({type: 'hidden', name: 'id', value: s.id}),
+ INPUT({type: 'submit', value: "Send Invite"}))));
+ } else {
+ tr.push(TD(' '));
+ }
+ t.push(tr);
+ });
+ d.push(t);
+ response.write(d);
+}
+
+function render_beta_valve_toggle_post() {
+ pro_beta_control.toggleValve();
+ response.redirect('/ep/admin/beta-valve');
+}
+
+function render_beta_invite_send_post() {
+ var id = request.params.id;
+ pro_beta_control.sendInvite(id);
+ response.redirect('/ep/admin/beta-valve');
+}
+
+function render_beta_invite_multisend_post() {
+ var count = request.params.count;
+ var signupList = sqlobj.selectMulti('pro_beta_signups', {}, {});
+ signupList.sort(function(a, b) {
+ return cmp(a.signupDate, b.signupDate);
+ });
+ var sent = 0;
+ for (var i = 0; ((i < signupList.length) && (sent < count)); i++) {
+ var record = signupList[i];
+ if (!record.activationCode) {
+ pro_beta_control.sendInvite(record.id);
+ sent++;
+ }
+ }
+ getSession().betaAdminMessage = (sent+" invites sent.");
+ response.redirect('/ep/admin/beta-valve');
+}
+
+function render_usagestats() {
+ response.redirect("/ep/admin/usagestats/");
+}
+
+function render_exceptions() {
+ exceptions.render();
+}
+
+function render_setadminmode() {
+ sessions.setIsAnEtherpadAdmin(
+ String(request.params.v).toLowerCase() == "true");
+ response.redirect("/ep/admin/");
+}
+
+// --------------------------------------------------------------
+// billing-related
+// --------------------------------------------------------------
+
+// some of these functions are only used from selenium tests, and so have no UI.
+
+function render_setdomainpaidthrough() {
+ var domainName = request.params.domain;
+ var when = new Date(Number(request.params.paidthrough));
+ if (! domainName || ! when) {
+ response.write("fail");
+ response.stop();
+ }
+ var domain = domains.getDomainRecordFromSubdomain(domainName);
+ var domainId = domain.id;
+
+ var subscription = team_billing.getSubscriptionForCustomer(domainId);
+ if (subscription) {
+ billing.updatePurchase(subscription.id, {paidThrough: when});
+ team_billing.domainCacheClear(domainId);
+ response.write("OK");
+ } else {
+ response.write("fail");
+ }
+}
+
+function render_runsubscriptions() {
+ team_billing.processAllSubscriptions();
+ response.write("OK");
+}
+
+function render_reset_subscription() {
+ var body = BODY();
+ if (request.isGet) {
+ body.push(FORM({method: "POST"},
+ "Subdomain: ", INPUT({type: "text", name: "subdomain"}), BUTTON({name: "clear"}, "Go")));
+ } else if (request.isPost) {
+ if (! request.params.confirm) {
+ var domain = domains.getDomainRecordFromSubdomain(request.params.subdomain);
+ var admins = pro_accounts.listAllDomainAdmins(domain.id);
+ body.push(P("Domain ", domain.subDomain, ".", request.domain, "; admins:"));
+ var p = UL();
+ admins.forEach(function(admin) {
+ p.push(LI(admin.fullName, " <", admin.email, ">"));
+ });
+ body.push(p);
+ var subscription = team_billing.getSubscriptionForCustomer(domain.id);
+ if (subscription) {
+ body.push(P("Subscription is currently ", subscription.status, ", and paid through: ", checkout.formatDate(subscription.paidThrough), "."))
+ body.push(FORM({method: "POST"},
+ INPUT({type: "hidden", name: "subdomain", value: request.params.subdomain}),
+ "Are you sure? ", BUTTON({name: "confirm", value: "yes"}, "YES")));
+ } else {
+ body.push(P("No current subscription"));
+ }
+ } else {
+ var domain = domains.getDomainRecordFromSubdomain(request.params.subdomain);
+ sqlcommon.inTransaction(function() {
+ team_billing.resetMaxUsers(domain.id);
+ sqlobj.deleteRows('billing_purchase', {customer: domain.id, type: 'subscription'});
+ team_billing.domainCacheClear(domain.id);
+ team_billing.clearRecurringBillingInfo(domain.id);
+ });
+ body.push("Done!")
+ }
+ }
+ body.push(A({href: request.path}, html("&laquo; back")));
+ response.write(HTML(body));
+} \ No newline at end of file
diff --git a/trunk/etherpad/src/etherpad/control/blogcontrol.js b/etherpad/src/etherpad/control/blogcontrol.js
index 9ec485d..9ec485d 100644
--- a/trunk/etherpad/src/etherpad/control/blogcontrol.js
+++ b/etherpad/src/etherpad/control/blogcontrol.js
diff --git a/trunk/etherpad/src/etherpad/control/connection_diagnostics_control.js b/etherpad/src/etherpad/control/connection_diagnostics_control.js
index aaa1bb3..aaa1bb3 100644
--- a/trunk/etherpad/src/etherpad/control/connection_diagnostics_control.js
+++ b/etherpad/src/etherpad/control/connection_diagnostics_control.js
diff --git a/trunk/etherpad/src/etherpad/control/global_pro_account_control.js b/etherpad/src/etherpad/control/global_pro_account_control.js
index 65d2124..65d2124 100644
--- a/trunk/etherpad/src/etherpad/control/global_pro_account_control.js
+++ b/etherpad/src/etherpad/control/global_pro_account_control.js
diff --git a/trunk/etherpad/src/etherpad/control/historycontrol.js b/etherpad/src/etherpad/control/historycontrol.js
index a78cfad..a78cfad 100644
--- a/trunk/etherpad/src/etherpad/control/historycontrol.js
+++ b/etherpad/src/etherpad/control/historycontrol.js
diff --git a/trunk/etherpad/src/etherpad/control/loadtestcontrol.js b/etherpad/src/etherpad/control/loadtestcontrol.js
index 2a4e3f7..2a4e3f7 100644
--- a/trunk/etherpad/src/etherpad/control/loadtestcontrol.js
+++ b/etherpad/src/etherpad/control/loadtestcontrol.js
diff --git a/trunk/etherpad/src/etherpad/control/maincontrol.js b/etherpad/src/etherpad/control/maincontrol.js
index 261ddaf..261ddaf 100644
--- a/trunk/etherpad/src/etherpad/control/maincontrol.js
+++ b/etherpad/src/etherpad/control/maincontrol.js
diff --git a/trunk/etherpad/src/etherpad/control/pad/pad_changeset_control.js b/etherpad/src/etherpad/control/pad/pad_changeset_control.js
index 5af7ed0..5af7ed0 100644
--- a/trunk/etherpad/src/etherpad/control/pad/pad_changeset_control.js
+++ b/etherpad/src/etherpad/control/pad/pad_changeset_control.js
diff --git a/etherpad/src/etherpad/control/pad/pad_control.js b/etherpad/src/etherpad/control/pad/pad_control.js
new file mode 100644
index 0000000..32ff8a3
--- /dev/null
+++ b/etherpad/src/etherpad/control/pad/pad_control.js
@@ -0,0 +1,754 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("funhtml.*");
+import("comet");
+import("email.sendEmail");
+import("fastJSON");
+import("jsutils.eachProperty");
+import("sqlbase.sqlbase");
+import("stringutils.{toHTML,md5}");
+import("stringutils");
+
+import("etherpad.collab.collab_server");
+import("etherpad.debug.dmesg");
+import("etherpad.globals.*");
+import("etherpad.helpers");
+import("etherpad.licensing");
+import("etherpad.quotas");
+import("etherpad.log");
+import("etherpad.log.{logRequest,logException}");
+import("etherpad.sessions");
+import("etherpad.sessions.getSession");
+import("etherpad.utils.*");
+import("etherpad.pro.pro_padmeta");
+import("etherpad.pro.pro_pad_db");
+import("etherpad.pro.pro_utils");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("etherpad.pro.domains");
+import("etherpad.pro.pro_config");
+import("etherpad.pne.pne_utils");
+import("etherpad.pro.pro_quotas");
+
+import("etherpad.pad.revisions");
+import("etherpad.pad.chatarchive");
+import("etherpad.pad.model");
+import("etherpad.pad.padutils");
+import("etherpad.pad.padusers");
+import("etherpad.control.pad.pad_view_control");
+import("etherpad.control.pad.pad_changeset_control");
+import("etherpad.control.pad.pad_importexport_control");
+import("etherpad.collab.readonly_server");
+
+import("dispatch.{Dispatcher,PrefixMatcher,DirMatcher,forward}");
+
+jimport("java.lang.System.out.println");
+
+var DISABLE_PAD_CREATION = false;
+
+function onStartup() {
+ sqlbase.createJSONTable("PAD_DIAGNOSTIC");
+}
+
+function onRequest() {
+
+ // TODO: take a hard look at /ep/pad/FOO/BAR/ dispatching.
+ // Perhaps standardize on /ep/pad/<pad-id>/foo
+ if (request.path.indexOf('/ep/pad/auth/') == 0) {
+ if (request.isGet) {
+ return render_auth_get();
+ }
+ if (request.isPost) {
+ return render_auth_post();
+ }
+ }
+
+ if (pro_utils.isProDomainRequest()) {
+ pro_quotas.perRequestBillingCheck();
+ }
+
+ var disp = new Dispatcher();
+ disp.addLocations([
+ [PrefixMatcher('/ep/pad/view/'), forward(pad_view_control)],
+ [PrefixMatcher('/ep/pad/changes/'), forward(pad_changeset_control)],
+ [PrefixMatcher('/ep/pad/impexp/'), forward(pad_importexport_control)],
+ [PrefixMatcher('/ep/pad/export/'), pad_importexport_control.renderExport]
+ ]);
+ return disp.dispatch();
+}
+
+//----------------------------------------------------------------
+// utils
+//----------------------------------------------------------------
+
+function getDefaultPadText() {
+ if (pro_utils.isProDomainRequest()) {
+ return pro_config.getConfig().defaultPadText;
+ }
+ return renderTemplateAsString("misc/pad_default.ejs", {padUrl: request.url.split("?", 1)[0]});
+}
+
+function assignName(pad, userId) {
+ if (padusers.isGuest(userId)) {
+ // use pad-specific name if possible
+ var userData = pad.getAuthorData(userId);
+ var nm = (userData && userData.name) || padusers.getUserName() || null;
+
+ // don't let name guest typed in last once we've assigned a name
+ // for this pad, so the user can change it
+ delete getSession().guestDisplayName;
+
+ return nm;
+ }
+ else {
+ return padusers.getUserName();
+ }
+}
+
+function assignColorId(pad, userId) {
+ // use pad-specific color if possible
+ var userData = pad.getAuthorData(userId);
+ if (userData && ('colorId' in userData)) {
+ return userData.colorId;
+ }
+
+ // assign random unique color
+ function r(n) {
+ return Math.floor(Math.random() * n);
+ }
+ var colorsUsed = {};
+ var users = collab_server.getConnectedUsers(pad);
+ var availableColors = [];
+ users.forEach(function(u) {
+ colorsUsed[u.colorId] = true;
+ });
+ for (var i = 0; i < COLOR_PALETTE.length; i++) {
+ if (!colorsUsed[i]) {
+ availableColors.push(i);
+ }
+ }
+ if (availableColors.length > 0) {
+ return availableColors[r(availableColors.length)];
+ } else {
+ return r(COLOR_PALETTE.length);
+ }
+}
+
+function _getPrivs() {
+ return {
+ maxRevisions: quotas.getMaxSavedRevisionsPerPad()
+ };
+}
+
+//----------------------------------------------------------------
+// linkfile (a file that users can save that redirects them to
+// a particular pad; auto-download)
+//----------------------------------------------------------------
+function render_linkfile() {
+ var padId = request.params.padId;
+
+ renderHtml("pad/pad_download_link.ejs", {
+ padId: padId
+ });
+
+ response.setHeader("Content-Disposition", "attachment; filename=\""+padId+".html\"");
+}
+
+//----------------------------------------------------------------
+// newpad
+//----------------------------------------------------------------
+
+function render_newpad() {
+ var session = getSession();
+ var padId;
+
+ if (pro_utils.isProDomainRequest()) {
+ padId = pro_pad_db.getNextPadId();
+ } else {
+ padId = randomUniquePadId();
+ }
+
+ session.instantCreate = padId;
+ response.redirect("/"+padId);
+}
+
+// Tokbox
+function render_newpad_xml_post() {
+ var localPadId;
+ if (pro_utils.isProDomainRequest()) {
+ localPadId = pro_pad_db.getNextPadId();
+ } else {
+ localPadId = randomUniquePadId();
+ }
+ // <RAFTER>
+ if (DISABLE_PAD_CREATION) {
+ if (! pro_utils.isProDomainRequest()) {
+ utils.render500();
+ return;
+ }
+ }
+ // </RAFTER>
+
+ padutils.accessPadLocal(localPadId, function(pad) {
+ if (!pad.exists()) {
+ pad.create(getDefaultPadText());
+ }
+ });
+ response.setContentType('text/plain; charset=utf-8');
+ response.write([
+ '<newpad>',
+ '<url>http://'+request.host+'/'+localPadId+'</url>',
+ '</newpad>'
+ ].join('\n'));
+}
+
+//----------------------------------------------------------------
+// pad
+//----------------------------------------------------------------
+
+function _createIfNecessary(localPadId, pad) {
+ if (pad.exists()) {
+ delete getSession().instantCreate;
+ return;
+ }
+ // make sure localPadId is valid.
+ var validPadId = padutils.makeValidLocalPadId(localPadId);
+ if (localPadId != validPadId) {
+ response.redirect('/'+validPadId);
+ }
+ // <RAFTER>
+ if (DISABLE_PAD_CREATION) {
+ if (! pro_utils.isProDomainRequest()) {
+ response.redirect("/ep/pad/create?padId="+encodeURIComponent(localPadId));
+ return;
+ }
+ }
+ // </RAFTER>
+ // tokbox may use createImmediately
+ if (request.params.createImmediately || getSession().instantCreate == localPadId) {
+ pad.create(getDefaultPadText());
+ delete getSession().instantCreate;
+ return;
+ }
+ response.redirect("/ep/pad/create?padId="+encodeURIComponent(localPadId));
+}
+
+function _promptForMobileDevices(pad) {
+ // TODO: also work with blackbery and windows mobile and others
+ if (request.userAgent.isIPhone() && (!request.params.skipIphoneCheck)) {
+ renderHtml("pad/pad_iphone_body.ejs", {padId: pad.getLocalId()});
+ response.stop();
+ }
+}
+
+function _checkPadQuota(pad) {
+ var numConnectedUsers = collab_server.getNumConnections(pad);
+ var maxUsersPerPad = quotas.getMaxSimultaneousPadEditors(pad.getId());
+
+ if (numConnectedUsers >= maxUsersPerPad) {
+ log.info("rendered-padfull");
+ renderFramed('pad/padfull_body.ejs',
+ {maxUsersPerPad: maxUsersPerPad, padId: pad.getLocalId()});
+ response.stop();
+ }
+
+ if (pne_utils.isPNE()) {
+ if (!licensing.canSessionUserJoin()) {
+ renderFramed('pad/total_users_exceeded.ejs', {
+ userQuota: licensing.getActiveUserQuota(),
+ activeUserWindowHours: licensing.getActiveUserWindowHours()
+ });
+ response.stop();
+ }
+ }
+}
+
+function _checkIfDeleted(pad) {
+ // TODO: move to access control check on access?
+ if (pro_utils.isProDomainRequest()) {
+ pro_padmeta.accessProPad(pad.getId(), function(propad) {
+ if (propad.exists() && propad.isDeleted()) {
+ renderNoticeString("This pad has been deleted.");
+ response.stop();
+ }
+ });
+ }
+}
+
+function render_pad(localPadId) {
+ var proTitle = null, documentBarTitle, initialPassword = null;
+ var isPro = isProDomainRequest();
+ var userId = padusers.getUserId();
+
+ var opts = {};
+ var globalPadId;
+
+ if (isPro) {
+ pro_quotas.perRequestBillingCheck();
+ }
+
+ padutils.accessPadLocal(localPadId, function(pad) {
+ globalPadId = pad.getId();
+ request.cache.globalPadId = globalPadId;
+ _createIfNecessary(localPadId, pad);
+ _promptForMobileDevices(pad);
+ _checkPadQuota(pad);
+ _checkIfDeleted(pad);
+
+ if (request.params.inviteTo) {
+ getSession().nameGuess = request.params.inviteTo;
+ response.redirect('/'+localPadId);
+ }
+ var displayName;
+ if (request.params.displayName) { // tokbox
+ displayName = String(request.params.displayName);
+ }
+ else {
+ displayName = assignName(pad, userId);
+ }
+
+ if (isProDomainRequest()) {
+ pro_padmeta.accessProPadLocal(localPadId, function(propad) {
+ proTitle = propad.getDisplayTitle();
+ initialPassword = propad.getPassword();
+ });
+ }
+ documentBarTitle = (proTitle || "Public Pad");
+
+ var specialKey = request.params.specialKey ||
+ (sessions.isAnEtherpadAdmin() ? collab_server.getSpecialKey('invisible') :
+ null);
+
+ helpers.addClientVars({
+ padId: localPadId,
+ globalPadId: globalPadId,
+ userAgent: request.headers["User-Agent"],
+ collab_client_vars: collab_server.getCollabClientVars(pad),
+ debugEnabled: request.params.djs,
+ clientIp: request.clientAddr,
+ colorPalette: COLOR_PALETTE,
+ nameGuess: (getSession().nameGuess || null),
+ initialRevisionList: revisions.getRevisionList(pad),
+ serverTimestamp: +(new Date),
+ accountPrivs: _getPrivs(),
+ chatHistory: chatarchive.getRecentChatBlock(pad, 30),
+ numConnectedUsers: collab_server.getNumConnections(pad),
+ isProPad: isPro,
+ initialTitle: documentBarTitle,
+ initialPassword: initialPassword,
+ initialOptions: pad.getPadOptionsObj(),
+ userIsGuest: padusers.isGuest(userId),
+ userId: userId,
+ userName: displayName,
+ userColor: assignColorId(pad, userId),
+ specialKey: specialKey,
+ specialKeyTranslation: collab_server.translateSpecialKey(specialKey),
+ });
+ });
+
+ var isProUser = (isPro && ! padusers.isGuest(userId));
+
+ padutils.setOptsAndCookiePrefs(request);
+ var prefs = helpers.getClientVar('cookiePrefsToSet');
+ var bodyClass = (prefs.isFullWidth ? "fullwidth" : "limwidth") +
+ " "+(isPro ? "propad" : "nonpropad")+" "+
+ (isProUser ? "prouser" : "nonprouser");
+
+
+ renderHtml("pad/pad_body2.ejs",
+ {localPadId:localPadId,
+ pageTitle:toHTML(proTitle || localPadId),
+ initialTitle:toHTML(documentBarTitle),
+ bodyClass: bodyClass,
+ hasOffice: hasOffice(),
+ isPro: isPro,
+ isProAccountHolder: isProUser,
+ account: getSessionProAccount(), // may be falsy
+ toHTML: toHTML,
+ prefs: prefs,
+ signinUrl: '/ep/account/sign-in?cont='+
+ encodeURIComponent(request.url),
+ fullSuperdomain: pro_utils.getFullSuperdomainHost()
+ });
+ return true;
+}
+
+function render_create_get() {
+ var padId = request.params.padId;
+ // <RAFTER>
+ var template = (DISABLE_PAD_CREATION && ! pro_utils.isProDomainRequest()) ?
+ "pad/create_body_rafter.ejs" :
+ "pad/create_body.ejs";
+ // </RAFTER>
+ renderFramed(template, {padId: padId,
+ fullSuperdomain: pro_utils.getFullSuperdomainHost()});
+}
+
+function render_create_post() {
+ var padId = request.params.padId;
+ getSession().instantCreate = padId;
+ response.redirect("/"+padId);
+}
+
+//----------------------------------------------------------------
+// saverevision
+//----------------------------------------------------------------
+
+function render_saverevision_post() {
+ var padId = request.params.padId;
+ var savedBy = request.params.savedBy;
+ var savedById = request.params.savedById;
+ var revNum = request.params.revNum;
+ var privs = _getPrivs();
+ padutils.accessPadLocal(padId, function(pad) {
+ if (! pad.exists()) { response.notFound(); }
+ var currentRevs = revisions.getRevisionList(pad);
+ if (currentRevs.length >= privs.maxRevisions) {
+ response.forbid();
+ }
+ var savedRev = revisions.saveNewRevision(pad, savedBy, savedById,
+ revNum);
+ readonly_server.broadcastNewRevision(pad, savedRev);
+ response.setContentType('text/x-json');
+ response.write(fastJSON.stringify(revisions.getRevisionList(pad)));
+ });
+}
+
+function render_saverevisionlabel_post() {
+ var userId = request.params.userId;
+ var padId = request.params.padId;
+ var revId = request.params.revId;
+ var newLabel = request.params.newLabel;
+ padutils.accessPadLocal(padId, function(pad) {
+ revisions.setLabel(pad, revId, userId, newLabel);
+ response.setContentType('text/x-json');
+ response.write(fastJSON.stringify(revisions.getRevisionList(pad)));
+ });
+}
+
+function render_getrevisionatext_get() {
+ var padId = request.params.padId;
+ var revId = request.params.revId;
+ var result = null;
+
+ var rev = padutils.accessPadLocal(padId, function(pad) {
+ var r = revisions.getStoredRevision(pad, revId);
+ var forWire = collab_server.getATextForWire(pad, r.revNum);
+ result = {atext:forWire.atext, apool:forWire.apool,
+ historicalAuthorData:forWire.historicalAuthorData};
+ return r;
+ }, "r");
+
+ response.setContentType('text/plain; charset=utf-8');
+ response.write(fastJSON.stringify(result));
+}
+
+//----------------------------------------------------------------
+// reconnect
+//----------------------------------------------------------------
+
+function _recordDiagnosticInfo(padId, diagnosticInfoJson) {
+
+ var diagnosticInfo = {};
+ try {
+ diagnosticInfo = fastJSON.parse(diagnosticInfoJson);
+ } catch (ex) {
+ log.warn("Error parsing diagnosticInfoJson: "+ex);
+ diagnosticInfo = {error: "error parsing JSON"};
+ }
+
+ // ignore userdups, unauth
+ if (diagnosticInfo.disconnectedMessage == "userdup" ||
+ diagnosticInfo.disconnectedMessage == "unauth") {
+ return;
+ }
+
+ var d = new Date();
+
+ diagnosticInfo.date = +d;
+ diagnosticInfo.strDate = String(d);
+ diagnosticInfo.clientAddr = request.clientAddr;
+ diagnosticInfo.padId = padId;
+ diagnosticInfo.headers = {};
+ eachProperty(request.headers, function(k,v) {
+ diagnosticInfo.headers[k] = v;
+ });
+
+ var uid = diagnosticInfo.uniqueId;
+
+ sqlbase.putJSON("PAD_DIAGNOSTIC", (diagnosticInfo.date)+"-"+uid, diagnosticInfo);
+
+}
+
+function recordMigratedDiagnosticInfo(objArray) {
+ objArray.forEach(function(obj) {
+ sqlbase.putJSON("PAD_DIAGNOSTIC", (obj.date)+"-"+obj.uniqueId, obj);
+ });
+}
+
+function render_reconnect() {
+ var localPadId = request.params.padId;
+ var globalPadId = padutils.getGlobalPadId(localPadId);
+ var userId = (padutils.getPrefsCookieUserId() || undefined);
+ var hasClientErrors = false;
+ var uniqueId;
+ try {
+ var obj = fastJSON.parse(request.params.diagnosticInfo);
+ uniqueId = obj.uniqueId;
+ errorMessage = obj.disconnectedMessage;
+ hasClientErrors = obj.collabDiagnosticInfo.errors.length > 0;
+ } catch (e) {
+ // guess it doesn't have errors.
+ }
+
+ log.custom("reconnect", {globalPadId: globalPadId, userId: userId,
+ uniqueId: uniqueId,
+ hasClientErrors: hasClientErrors,
+ errorMessage: errorMessage });
+
+ try {
+ _recordDiagnosticInfo(globalPadId, request.params.diagnosticInfo);
+ } catch (ex) {
+ log.warn("Error recording diagnostic info: "+ex+" / "+request.params.diagnosticInfo);
+ }
+
+ try {
+ _applyMissedChanges(localPadId, request.params.missedChanges);
+ } catch (ex) {
+ log.warn("Error applying missed changes: "+ex+" / "+request.params.missedChanges);
+ }
+
+ response.redirect('/'+localPadId);
+}
+
+/* posted asynchronously by the client as soon as reconnect dialogue appears. */
+function render_connection_diagnostic_info_post() {
+ var localPadId = request.params.padId;
+ var globalPadId = padutils.getGlobalPadId(localPadId);
+ var userId = (padutils.getPrefsCookieUserId() || undefined);
+ var hasClientErrors = false;
+ var uniqueId;
+ var errorMessage;
+ try {
+ var obj = fastJSON.parse(request.params.diagnosticInfo);
+ uniqueId = obj.uniqueId;
+ errorMessage = obj.disconnectedMessage;
+ hasClientErrors = obj.collabDiagnosticInfo.errors.length > 0;
+ } catch (e) {
+ // guess it doesn't have errors.
+ }
+ log.custom("disconnected_autopost", {globalPadId: globalPadId, userId: userId,
+ uniqueId: uniqueId,
+ hasClientErrors: hasClientErrors,
+ errorMessage: errorMessage});
+
+ try {
+ _recordDiagnosticInfo(globalPadId, request.params.diagnosticInfo);
+ } catch (ex) {
+ log.warn("Error recording diagnostic info: "+ex+" / "+request.params.diagnosticInfo);
+ }
+ response.setContentType('text/plain; charset=utf-8');
+ response.write("OK");
+}
+
+function _applyMissedChanges(localPadId, missedChangesJson) {
+ var missedChanges;
+ try {
+ missedChanges = fastJSON.parse(missedChangesJson);
+ } catch (ex) {
+ log.warn("Error parsing missedChangesJson: "+ex);
+ return;
+ }
+
+ padutils.accessPadLocal(localPadId, function(pad) {
+ if (pad.exists()) {
+ collab_server.applyMissedChanges(pad, missedChanges);
+ }
+ });
+}
+
+//----------------------------------------------------------------
+// feedback
+//----------------------------------------------------------------
+
+function render_feedback_post() {
+ var feedback = request.params.feedback;
+ var localPadId = request.params.padId;
+ var globalPadId = padutils.getGlobalPadId(localPadId);
+ var username = request.params.username;
+ var email = request.params.email;
+ var subject = 'EtherPad Feedback from '+request.clientAddr+' / '+globalPadId+' / '+username;
+
+ if (feedback.indexOf("@") > 0) {
+ subject = "@ "+subject;
+ }
+
+ feedback += "\n\n--\n";
+ feedback += ("User Agent: "+request.headers['User-Agent'] + "\n");
+ feedback += ("Session Referer: "+getSession().initialReferer + "\n");
+ feedback += ("Email: "+email+"\n");
+
+ // log feedback
+ var userId = padutils.getPrefsCookieUserId();
+ log.custom("feedback", {
+ globalPadId: globalPadId,
+ userId: userId,
+ email: email,
+ username: username,
+ feedback: request.params.feedback});
+
+ sendEmail(
+ 'feedback@pad.spline.inf.fu-berlin.de',
+ 'feedback@pad.spline.inf.fu-berlin.de',
+ subject,
+ {},
+ feedback
+ );
+ response.write("OK");
+}
+
+//----------------------------------------------------------------
+// emailinvite
+//----------------------------------------------------------------
+
+function render_emailinvite_post() {
+ var toEmails = String(request.params.toEmails).split(',');
+ var padId = String(request.params.padId);
+ var username = String(request.params.username);
+ var subject = String(request.params.subject);
+ var message = String(request.params.message);
+
+ log.custom("padinvite",
+ {toEmails: toEmails, padId: padId, username: username,
+ subject: subject, message: message});
+
+ var fromAddr = '"EtherPad" <noreply@pad.spline.inf.fu-berlin.de>';
+ // client enforces non-empty subject and message
+ var subj = '[EtherPad] '+subject;
+ var body = renderTemplateAsString('email/padinvite.ejs',
+ {body: message});
+ var headers = {};
+ var proAccount = getSessionProAccount();
+ if (proAccount) {
+ headers['Reply-To'] = proAccount.email;
+ }
+
+ response.setContentType('text/plain; charset=utf-8');
+ try {
+ sendEmail(toEmails, fromAddr, subj, headers, body);
+ response.write("OK");
+ } catch (e) {
+ logException(e);
+ response.setStatusCode(500);
+ response.write("Error");
+ }
+}
+
+//----------------------------------------------------------------
+// time-slider
+//----------------------------------------------------------------
+function render_slider() {
+ var parts = request.path.split('/');
+ var padOpaqueRef = parts[4];
+
+ helpers.addClientVars({padOpaqueRef:padOpaqueRef});
+
+ renderHtml("pad/padslider_body.ejs", {
+ // properties go here
+ });
+
+ return true;
+}
+
+//----------------------------------------------------------------
+// auth
+//----------------------------------------------------------------
+
+function render_auth_get() {
+ var parts = request.path.split('/');
+ var localPadId = parts[4];
+ var errDiv;
+ if (getSession().padPassErr) {
+ errDiv = DIV({style: "border: 1px solid #fcc; background: #ffeeee; padding: 1em; margin: 1em 0;"},
+ B(getSession().padPassErr));
+ delete getSession().padPassErr;
+ } else {
+ errDiv = DIV();
+ }
+ renderFramedHtml(function() {
+ return DIV({className: "fpcontent"},
+ DIV({style: "margin: 1em;"},
+ errDiv,
+ FORM({style: "border: 1px solid #ccc; padding: 1em; background: #fff6cc;",
+ action: request.path+'?'+request.query,
+ method: "post"},
+ LABEL(B("Please enter the password required to access this pad:")),
+ BR(), BR(),
+ INPUT({type: "text", name: "password"}), INPUT({type: "submit", value: "Submit"})
+ /*DIV(BR(), "Or ", A({href: '/ep/account/sign-in'}, "sign in"), ".")*/
+ )),
+ DIV({style: "padding: 0 1em;"},
+ P({style: "color: #444;"},
+ "If you have forgotten a pad's password, contact your site administrator.",
+ " Site administrators can recover lost pad text through the \"Admin\" tab.")
+ )
+ );
+ });
+ return true;
+}
+
+function render_auth_post() {
+ var parts = request.path.split('/');
+ var localPadId = parts[4];
+ var domainId = domains.getRequestDomainId();
+ if (!getSession().padPasswordAuth) {
+ getSession().padPasswordAuth = {};
+ }
+ var currentPassword = pro_padmeta.accessProPadLocal(localPadId, function(propad) {
+ return propad.getPassword();
+ });
+ if (request.params.password == currentPassword) {
+ var globalPadId = padutils.getGlobalPadId(localPadId);
+ getSession().padPasswordAuth[globalPadId] = true;
+ } else {
+ getSession().padPasswordAuth[globalPadId] = false;
+ getSession().padPassErr = "Incorrect password.";
+ }
+ var cont = request.params.cont;
+ if (!cont) {
+ cont = '/'+localPadId;
+ }
+ response.redirect(cont);
+}
+
+//----------------------------------------------------------------
+// chathistory
+//----------------------------------------------------------------
+
+function render_chathistory_get() {
+ var padId = request.params.padId;
+ var start = Number(request.params.start || 0);
+ var end = Number(request.params.end || 0);
+ var result = null;
+
+ var rev = padutils.accessPadLocal(padId, function(pad) {
+ result = chatarchive.getChatBlock(pad, start, end);
+ }, "r");
+
+ response.setContentType('text/plain; charset=utf-8');
+ response.write(fastJSON.stringify(result));
+}
+
diff --git a/trunk/etherpad/src/etherpad/control/pad/pad_importexport_control.js b/etherpad/src/etherpad/control/pad/pad_importexport_control.js
index b7e5f4d..b7e5f4d 100644
--- a/trunk/etherpad/src/etherpad/control/pad/pad_importexport_control.js
+++ b/etherpad/src/etherpad/control/pad/pad_importexport_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pad/pad_view_control.js b/etherpad/src/etherpad/control/pad/pad_view_control.js
index 0606d2c..0606d2c 100644
--- a/trunk/etherpad/src/etherpad/control/pad/pad_view_control.js
+++ b/etherpad/src/etherpad/control/pad/pad_view_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pne_manual_control.js b/etherpad/src/etherpad/control/pne_manual_control.js
index 0dd65f8..0dd65f8 100644
--- a/trunk/etherpad/src/etherpad/control/pne_manual_control.js
+++ b/etherpad/src/etherpad/control/pne_manual_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pne_tracker_control.js b/etherpad/src/etherpad/control/pne_tracker_control.js
index ee36645..ee36645 100644
--- a/trunk/etherpad/src/etherpad/control/pne_tracker_control.js
+++ b/etherpad/src/etherpad/control/pne_tracker_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pro/account_control.js b/etherpad/src/etherpad/control/pro/account_control.js
index 031dbe6..031dbe6 100644
--- a/trunk/etherpad/src/etherpad/control/pro/account_control.js
+++ b/etherpad/src/etherpad/control/pro/account_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pro/admin/account_manager_control.js b/etherpad/src/etherpad/control/pro/admin/account_manager_control.js
index 8f93b2e..8f93b2e 100644
--- a/trunk/etherpad/src/etherpad/control/pro/admin/account_manager_control.js
+++ b/etherpad/src/etherpad/control/pro/admin/account_manager_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pro/admin/license_manager_control.js b/etherpad/src/etherpad/control/pro/admin/license_manager_control.js
index ca6d6a6..ca6d6a6 100644
--- a/trunk/etherpad/src/etherpad/control/pro/admin/license_manager_control.js
+++ b/etherpad/src/etherpad/control/pro/admin/license_manager_control.js
diff --git a/etherpad/src/etherpad/control/pro/admin/pro_admin_control.js b/etherpad/src/etherpad/control/pro/admin/pro_admin_control.js
new file mode 100644
index 0000000..51d6ba3
--- /dev/null
+++ b/etherpad/src/etherpad/control/pro/admin/pro_admin_control.js
@@ -0,0 +1,280 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("stringutils");
+import("funhtml.*");
+import("dispatch.{Dispatcher,DirMatcher,forward}");
+
+import("etherpad.licensing");
+import("etherpad.control.admincontrol");
+import("etherpad.control.pro.admin.license_manager_control");
+import("etherpad.control.pro.admin.account_manager_control");
+import("etherpad.control.pro.admin.pro_config_control");
+import("etherpad.control.pro.admin.team_billing_control");
+
+import("etherpad.pad.padutils");
+
+import("etherpad.admin.shell");
+import("etherpad.sessions");
+import("etherpad.sessions.getSession");
+
+import("etherpad.pne.pne_utils");
+import("etherpad.pro.pro_accounts");
+import("etherpad.utils.*");
+
+//----------------------------------------------------------------
+
+var _pathPrefix = '/ep/admin/';
+
+var _PRO = 1;
+var _PNE_ONLY = 2;
+var _ONDEMAND_ONLY = 3;
+
+function _getLeftnavItems() {
+ var nav = [
+ _PRO, [
+ [_PRO, null, "Admin"],
+ [_PNE_ONLY, "pne-dashboard", "Server Dashboard"],
+ [_PRO, "account-manager/", "Manage Accounts"],
+ [_PRO, "recover-padtext", "Recover Pad Text"],
+ [_PRO, null, "Configuration"],
+ [_PRO, [[_PNE_ONLY, "pne-config", "Private Server Configuration"],
+ [_PRO, "pro-config", "Application Configuration"]]],
+ ]
+ ];
+ return nav;
+}
+
+function renderAdminLeftNav() {
+ function _make(x) {
+ if ((x[0] == _PNE_ONLY) && !pne_utils.isPNE()) {
+ return null;
+ }
+ if ((x[0] == _ONDEMAND_ONLY) && pne_utils.isPNE()) {
+ return null;
+ }
+
+ if (x[1] instanceof Array) {
+ return _makelist(x[1]);
+ } else {
+ return _makeitem(x);
+ }
+ }
+ var selected;
+ function _makeitem(x) {
+ if (x[1]) {
+ var p = x[1];
+ if (x[1].charAt(0) != '/') {
+ p = _pathPrefix+p;
+ }
+ var li = LI(A({href: p}, x[2]));
+ if (stringutils.startsWith(request.path, p)) {
+ // select the longest prefix match.
+ if (! selected || p.length > selected.path.length) {
+ selected = {path: p, li: li};
+ }
+ }
+ return li;
+ } else {
+ return LI(DIV({className: 'leftnav-title'}, x[2]));
+ }
+ }
+ function _makelist(x) {
+ var ul = UL();
+ x.forEach(function(y) {
+ var t = _make(y);
+ if (t) { ul.push(t); }
+ });
+ return ul;
+ }
+ var d = DIV(_make(_getLeftnavItems()));
+ if (selected) {
+ selected.li.attribs.className = "selected";
+ }
+ // leftnav looks stupid when it's not very tall.
+ for (var i = 0; i < 10; i++) { d.push(BR()); }
+ return d;
+}
+
+function renderAdminPage(p, data) {
+ appjet.requestCache.proTopNavSelection = 'admin';
+ function getAdminContent() {
+ if (typeof(p) == 'function') {
+ return p();
+ } else {
+ return renderTemplateAsString('pro/admin/'+p+'.ejs', data);
+ }
+ }
+ renderFramed('pro/admin/admin-template.ejs', {
+ getAdminContent: getAdminContent,
+ renderAdminLeftNav: renderAdminLeftNav,
+ validLicense: pne_utils.isServerLicensed(),
+ });
+}
+
+//----------------------------------------------------------------
+
+function onRequest() {
+ var disp = new Dispatcher();
+ disp.addLocations([
+ [DirMatcher(license_manager_control.getPath()), forward(license_manager_control)],
+ [DirMatcher('/ep/admin/account-manager/'), forward(account_manager_control)],
+ [DirMatcher('/ep/admin/pro-config/'), forward(pro_config_control)],
+ [DirMatcher('/ep/admin/billing/'), forward(team_billing_control)],
+ ]);
+
+ if (disp.dispatch()) {
+ return true;
+ }
+
+ // request will be handled by this module.
+ pro_accounts.requireAdminAccount();
+}
+
+function render_main() {
+// renderAdminPage('admin');
+ response.redirect('/ep/admin/account-manager/')
+}
+
+function render_pne_dashboard() {
+ renderAdminPage('pne-dashboard', {
+ renderUptime: admincontrol.renderServerUptime,
+ renderResponseCodes: admincontrol.renderResponseCodes,
+ renderPadConnections: admincontrol.renderPadConnections,
+ renderTransportStats: admincontrol.renderCometStats,
+ todayActiveUsers: licensing.getActiveUserCount(),
+ userQuota: licensing.getActiveUserQuota()
+ });
+}
+
+var _documentedServerOptions = [
+ 'listen',
+ 'listenSecure',
+ 'transportUseWildcardSubdomains',
+ 'sslKeyStore',
+ 'sslKeyPassword',
+ 'etherpad.soffice',
+ 'etherpad.adminPass',
+ 'etherpad.SQL_JDBC_DRIVER',
+ 'etherpad.SQL_JDBC_URL',
+ 'etherpad.SQL_USERNAME',
+ 'etherpad.SQL_PASSWORD',
+ 'smtpServer',
+ 'smtpUser',
+ 'smtpPass',
+ 'configFile',
+ 'etherpad.licenseKey',
+ 'verbose'
+];
+
+function render_pne_config_get() {
+ renderAdminPage('pne-config', {
+ propKeys: _documentedServerOptions,
+ appjetConfig: appjet.config
+ });
+}
+
+function render_pne_advanced_get() {
+ response.redirect("/ep/admin/shell");
+}
+
+function render_shell_get() {
+ if (!(pne_utils.isPNE() || sessions.isAnEtherpadAdmin())) {
+ return false;
+ }
+ appjet.requestCache.proTopNavSelection = 'admin';
+ renderAdminPage('pne-shell', {
+ oldCmd: getSession().pneAdminShellCmd,
+ result: getSession().pneAdminShellResult,
+ elapsedMs: getSession().pneAdminShellElapsed
+ });
+ delete getSession().pneAdminShellResult;
+ delete getSession().pneAdminShellElapsed;
+}
+
+function render_shell_post() {
+ if (!(pne_utils.isPNE() || sessions.isAnEtherpadAdmin())) {
+ return false;
+ }
+ var cmd = request.params.cmd;
+ var start = +(new Date);
+ getSession().pneAdminShellCmd = cmd;
+ getSession().pneAdminShellResult = shell.getResult(cmd);
+ getSession().pneAdminShellElapsed = +(new Date) - start;
+ response.redirect(request.path);
+}
+
+function render_recover_padtext_get() {
+ function getNumRevisions(localPadId) {
+ return padutils.accessPadLocal(localPadId, function(pad) {
+ if (!pad.exists()) { return null; }
+ return 1+pad.getHeadRevisionNumber();
+ });
+ }
+ function getPadText(localPadId, revNum) {
+ return padutils.accessPadLocal(localPadId, function(pad) {
+ if (!pad.exists()) { return null; }
+ return pad.getRevisionText(revNum);
+ });
+ }
+
+ var localPadId = request.params.localPadId;
+ var revNum = request.params.revNum;
+
+ var d = DIV({style: "font-size: .8em;"});
+
+ d.push(FORM({action: request.path, method: "get"},
+ P({style: "margin-top: 0;"}, LABEL("Pad ID: "),
+ INPUT({type: "text", name: "localPadId", value: localPadId || ""}),
+ INPUT({type: "submit", value: "Submit"}))));
+
+ var showPadHelp = false;
+ var revisions = null;
+
+ if (!localPadId) {
+ showPadHelp = true;
+ } else {
+ revisions = getNumRevisions(localPadId);
+ if (!revisions) {
+ d.push(P("Pad not found: "+localPadId));
+ } else {
+ d.push(P(B(localPadId), " has ", revisions, " revisions."));
+ d.push(P("Enter a revision number (0-"+revisions+") to recover the pad text for that revision:"));
+ d.push(FORM({action: request.path, method: "get"},
+ P(LABEL("Revision number:"),
+ INPUT({type: "hidden", name: "localPadId", value: localPadId}),
+ INPUT({type: "text", name: "revNum", value: revNum || (revisions - 1)}),
+ INPUT({type: "submit", value: "Submit"}))));
+ }
+ }
+
+ if (showPadHelp) {
+ d.push(P({style: "font-size: 1em; color: #555;"},
+ 'The pad ID is the same as the URL to the pad, without the leading "/".',
+ ' For example, if the pad lives at http://pad.spline.inf.fu-berlin.de/foobar,',
+ ' then the pad ID is "foobar" (without the quotes).'))
+ }
+
+ if (revisions && revNum && (revNum < revisions)) {
+ var padText = getPadText(localPadId, revNum);
+ d.push(P(B("Pad text for ["+localPadId+"] revision #"+revNum)));
+ d.push(DIV({style: "font-family: monospace; border: 1px solid #ccc; background: #ffe; padding: 1em;"}, padText));
+ }
+
+ renderAdminPage(function() { return d; });
+}
+
+
diff --git a/trunk/etherpad/src/etherpad/control/pro/admin/pro_config_control.js b/etherpad/src/etherpad/control/pro/admin/pro_config_control.js
index b03da45..b03da45 100644
--- a/trunk/etherpad/src/etherpad/control/pro/admin/pro_config_control.js
+++ b/etherpad/src/etherpad/control/pro/admin/pro_config_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pro/admin/team_billing_control.js b/etherpad/src/etherpad/control/pro/admin/team_billing_control.js
index 5be6a0e..5be6a0e 100644
--- a/trunk/etherpad/src/etherpad/control/pro/admin/team_billing_control.js
+++ b/etherpad/src/etherpad/control/pro/admin/team_billing_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pro/pro_main_control.js b/etherpad/src/etherpad/control/pro/pro_main_control.js
index b4e3bc4..b4e3bc4 100644
--- a/trunk/etherpad/src/etherpad/control/pro/pro_main_control.js
+++ b/etherpad/src/etherpad/control/pro/pro_main_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pro/pro_padlist_control.js b/etherpad/src/etherpad/control/pro/pro_padlist_control.js
index 9a90c67..9a90c67 100644
--- a/trunk/etherpad/src/etherpad/control/pro/pro_padlist_control.js
+++ b/etherpad/src/etherpad/control/pro/pro_padlist_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pro_beta_control.js b/etherpad/src/etherpad/control/pro_beta_control.js
index ec99b43..ec99b43 100644
--- a/trunk/etherpad/src/etherpad/control/pro_beta_control.js
+++ b/etherpad/src/etherpad/control/pro_beta_control.js
diff --git a/trunk/etherpad/src/etherpad/control/pro_signup_control.js b/etherpad/src/etherpad/control/pro_signup_control.js
index 6bf7cc3..6bf7cc3 100644
--- a/trunk/etherpad/src/etherpad/control/pro_signup_control.js
+++ b/etherpad/src/etherpad/control/pro_signup_control.js
diff --git a/trunk/etherpad/src/etherpad/control/scriptcontrol.js b/etherpad/src/etherpad/control/scriptcontrol.js
index 16efc60..16efc60 100644
--- a/trunk/etherpad/src/etherpad/control/scriptcontrol.js
+++ b/etherpad/src/etherpad/control/scriptcontrol.js
diff --git a/etherpad/src/etherpad/control/static_control.js b/etherpad/src/etherpad/control/static_control.js
new file mode 100644
index 0000000..d938b26
--- /dev/null
+++ b/etherpad/src/etherpad/control/static_control.js
@@ -0,0 +1,76 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("faststatic");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+
+import("etherpad.utils.*");
+import("etherpad.globals.*");
+import("etherpad.admin.plugins");
+
+function onRequest() {
+ var staticBase = '/static';
+
+ var opts = {cache: isProduction()};
+
+ var disp = new Dispatcher();
+
+ /* FIXME: Is there a more effective way to do this? */
+ for (plugin in plugins.plugins) {
+ disp.addLocations([
+ [PrefixMatcher('/static/js/plugins/'+plugin+'/'), faststatic.directoryServer('/plugins/' + plugin + '/static/js/', opts)],
+ [PrefixMatcher('/static/css/plugins/'+plugin+'/'), faststatic.directoryServer('/plugins/' + plugin + '/static/css/', opts)],
+ [PrefixMatcher('/static/swf/plugins/'+plugin+'/'), faststatic.directoryServer('/plugins/' + plugin + '/static/swf/', opts)],
+ [PrefixMatcher('/static/html/plugins/'+plugin+'/'), faststatic.directoryServer('/plugins/' + plugin + '/static/html/', opts)],
+ [PrefixMatcher('/static/zip/plugins/'+plugin+'/'), faststatic.directoryServer('/plugins/' + plugin + '/static/zip/', opts)]]);
+ }
+
+ var serveFavicon = faststatic.singleFileServer(staticBase + '/favicon.ico', opts);
+ var serveCrossDomain = faststatic.singleFileServer(staticBase + '/crossdomain.xml', opts);
+ var serveStaticDir = faststatic.directoryServer(staticBase, opts);
+ var serveCompressed = faststatic.compressedFileServer(opts);
+ var serveJs = faststatic.directoryServer(staticBase+'/js/', opts);
+ var serveCss = faststatic.directoryServer(staticBase+'/css/', opts);
+ var serveSwf = faststatic.directoryServer(staticBase+'/swf/', opts);
+ var serveHtml = faststatic.directoryServer(staticBase+'/html/', opts);
+ var serveZip = faststatic.directoryServer(staticBase+'/zip/', opts);
+
+ disp.addLocations([
+ ['/favicon.ico', serveFavicon],
+ ['/robots.txt', serveRobotsTxt],
+ ['/crossdomain.xml', serveCrossDomain],
+ [PrefixMatcher('/static/html/'), serveHtml],
+ [PrefixMatcher('/static/js/'), serveJs],
+ [PrefixMatcher('/static/css/'), serveCss],
+ [PrefixMatcher('/static/swf/'), serveSwf],
+ [PrefixMatcher('/static/zip/'), serveZip],
+ [PrefixMatcher('/static/compressed/'), serveCompressed],
+ [PrefixMatcher('/static/'), serveStaticDir]
+ ]);
+
+ return disp.dispatch();
+}
+
+function serveRobotsTxt(name) {
+ response.neverCache();
+ response.setContentType('text/plain');
+ response.write('User-agent: *\n');
+ if (!isProduction()) {
+ response.write('Disallow: /\n');
+ }
+ response.stop();
+ return true;
+}
diff --git a/trunk/etherpad/src/etherpad/control/statscontrol.js b/etherpad/src/etherpad/control/statscontrol.js
index 3659107..3659107 100644
--- a/trunk/etherpad/src/etherpad/control/statscontrol.js
+++ b/etherpad/src/etherpad/control/statscontrol.js
diff --git a/trunk/etherpad/src/etherpad/control/store/eepnet_checkout_control.js b/etherpad/src/etherpad/control/store/eepnet_checkout_control.js
index ddd4973..ddd4973 100644
--- a/trunk/etherpad/src/etherpad/control/store/eepnet_checkout_control.js
+++ b/etherpad/src/etherpad/control/store/eepnet_checkout_control.js
diff --git a/trunk/etherpad/src/etherpad/control/store/storecontrol.js b/etherpad/src/etherpad/control/store/storecontrol.js
index 43569e4..43569e4 100644
--- a/trunk/etherpad/src/etherpad/control/store/storecontrol.js
+++ b/etherpad/src/etherpad/control/store/storecontrol.js
diff --git a/trunk/etherpad/src/etherpad/control/testcontrol.js b/etherpad/src/etherpad/control/testcontrol.js
index ed13006..ed13006 100644
--- a/trunk/etherpad/src/etherpad/control/testcontrol.js
+++ b/etherpad/src/etherpad/control/testcontrol.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0000_test.js b/etherpad/src/etherpad/db_migrations/m0000_test.js
index 7df9bfd..7df9bfd 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0000_test.js
+++ b/etherpad/src/etherpad/db_migrations/m0000_test.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0001_eepnet_signups_init.js b/etherpad/src/etherpad/db_migrations/m0001_eepnet_signups_init.js
index 0e65779..0e65779 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0001_eepnet_signups_init.js
+++ b/etherpad/src/etherpad/db_migrations/m0001_eepnet_signups_init.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0002_eepnet_signups_2.js b/etherpad/src/etherpad/db_migrations/m0002_eepnet_signups_2.js
index 786e4e9..786e4e9 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0002_eepnet_signups_2.js
+++ b/etherpad/src/etherpad/db_migrations/m0002_eepnet_signups_2.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0003_create_tests_table_v2.js b/etherpad/src/etherpad/db_migrations/m0003_create_tests_table_v2.js
index f121145..f121145 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0003_create_tests_table_v2.js
+++ b/etherpad/src/etherpad/db_migrations/m0003_create_tests_table_v2.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0004_convert_all_tables_to_innodb.js b/etherpad/src/etherpad/db_migrations/m0004_convert_all_tables_to_innodb.js
index 959865d..959865d 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0004_convert_all_tables_to_innodb.js
+++ b/etherpad/src/etherpad/db_migrations/m0004_convert_all_tables_to_innodb.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0005_create_billing_tables.js b/etherpad/src/etherpad/db_migrations/m0005_create_billing_tables.js
index 0dfd37e..0dfd37e 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0005_create_billing_tables.js
+++ b/etherpad/src/etherpad/db_migrations/m0005_create_billing_tables.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0006_eepnet_signups_3.js b/etherpad/src/etherpad/db_migrations/m0006_eepnet_signups_3.js
index 349b27a..349b27a 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0006_eepnet_signups_3.js
+++ b/etherpad/src/etherpad/db_migrations/m0006_eepnet_signups_3.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0007_create_pro_tables_v4.js b/etherpad/src/etherpad/db_migrations/m0007_create_pro_tables_v4.js
index bda5853..bda5853 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0007_create_pro_tables_v4.js
+++ b/etherpad/src/etherpad/db_migrations/m0007_create_pro_tables_v4.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0008_persistent_vars.js b/etherpad/src/etherpad/db_migrations/m0008_persistent_vars.js
index 30e379a..30e379a 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0008_persistent_vars.js
+++ b/etherpad/src/etherpad/db_migrations/m0008_persistent_vars.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0009_pad_tables.js b/etherpad/src/etherpad/db_migrations/m0009_pad_tables.js
index 93f5a62..93f5a62 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0009_pad_tables.js
+++ b/etherpad/src/etherpad/db_migrations/m0009_pad_tables.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0010_pad_sqlmeta.js b/etherpad/src/etherpad/db_migrations/m0010_pad_sqlmeta.js
index 36150b1..36150b1 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0010_pad_sqlmeta.js
+++ b/etherpad/src/etherpad/db_migrations/m0010_pad_sqlmeta.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0011_pro_users_temppass.js b/etherpad/src/etherpad/db_migrations/m0011_pro_users_temppass.js
index 5ac8b26..5ac8b26 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0011_pro_users_temppass.js
+++ b/etherpad/src/etherpad/db_migrations/m0011_pro_users_temppass.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0012_pro_users_auto_signin.js b/etherpad/src/etherpad/db_migrations/m0012_pro_users_auto_signin.js
index ddd4cf6..ddd4cf6 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0012_pro_users_auto_signin.js
+++ b/etherpad/src/etherpad/db_migrations/m0012_pro_users_auto_signin.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0013_pne_padv2_upgrade.js b/etherpad/src/etherpad/db_migrations/m0013_pne_padv2_upgrade.js
index 146923a..146923a 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0013_pne_padv2_upgrade.js
+++ b/etherpad/src/etherpad/db_migrations/m0013_pne_padv2_upgrade.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0014_pne_globalpadids.js b/etherpad/src/etherpad/db_migrations/m0014_pne_globalpadids.js
index 445b32d..445b32d 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0014_pne_globalpadids.js
+++ b/etherpad/src/etherpad/db_migrations/m0014_pne_globalpadids.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0015_padmeta_passwords.js b/etherpad/src/etherpad/db_migrations/m0015_padmeta_passwords.js
index 8fa98bb..8fa98bb 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0015_padmeta_passwords.js
+++ b/etherpad/src/etherpad/db_migrations/m0015_padmeta_passwords.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0016_pne_tracking_data.js b/etherpad/src/etherpad/db_migrations/m0016_pne_tracking_data.js
index abcc93f..abcc93f 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0016_pne_tracking_data.js
+++ b/etherpad/src/etherpad/db_migrations/m0016_pne_tracking_data.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0017_pne_tracking_data_v2.js b/etherpad/src/etherpad/db_migrations/m0017_pne_tracking_data_v2.js
index 1067840..1067840 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0017_pne_tracking_data_v2.js
+++ b/etherpad/src/etherpad/db_migrations/m0017_pne_tracking_data_v2.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0018_eepnet_checkout_tables.js b/etherpad/src/etherpad/db_migrations/m0018_eepnet_checkout_tables.js
index 6e10000..6e10000 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0018_eepnet_checkout_tables.js
+++ b/etherpad/src/etherpad/db_migrations/m0018_eepnet_checkout_tables.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0019_padmeta_deleted.js b/etherpad/src/etherpad/db_migrations/m0019_padmeta_deleted.js
index 1f9ecbb..1f9ecbb 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0019_padmeta_deleted.js
+++ b/etherpad/src/etherpad/db_migrations/m0019_padmeta_deleted.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0020_padmeta_archived.js b/etherpad/src/etherpad/db_migrations/m0020_padmeta_archived.js
index a776622..a776622 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0020_padmeta_archived.js
+++ b/etherpad/src/etherpad/db_migrations/m0020_padmeta_archived.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0021_pro_padmeta_json.js b/etherpad/src/etherpad/db_migrations/m0021_pro_padmeta_json.js
index 9f357b7..9f357b7 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0021_pro_padmeta_json.js
+++ b/etherpad/src/etherpad/db_migrations/m0021_pro_padmeta_json.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0022_create_userids_table.js b/etherpad/src/etherpad/db_migrations/m0022_create_userids_table.js
index 23ca8d3..23ca8d3 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0022_create_userids_table.js
+++ b/etherpad/src/etherpad/db_migrations/m0022_create_userids_table.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0023_create_usagestats_table.js b/etherpad/src/etherpad/db_migrations/m0023_create_usagestats_table.js
index 927cdc9..927cdc9 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0023_create_usagestats_table.js
+++ b/etherpad/src/etherpad/db_migrations/m0023_create_usagestats_table.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0024_statistics_table.js b/etherpad/src/etherpad/db_migrations/m0024_statistics_table.js
index 9d6e58c..9d6e58c 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0024_statistics_table.js
+++ b/etherpad/src/etherpad/db_migrations/m0024_statistics_table.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0025_rename_pro_users_table.js b/etherpad/src/etherpad/db_migrations/m0025_rename_pro_users_table.js
index a429f41..a429f41 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0025_rename_pro_users_table.js
+++ b/etherpad/src/etherpad/db_migrations/m0025_rename_pro_users_table.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0026_create_guests_table.js b/etherpad/src/etherpad/db_migrations/m0026_create_guests_table.js
index 7c41309..7c41309 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0026_create_guests_table.js
+++ b/etherpad/src/etherpad/db_migrations/m0026_create_guests_table.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0027_pro_config.js b/etherpad/src/etherpad/db_migrations/m0027_pro_config.js
index 9cbb629..9cbb629 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0027_pro_config.js
+++ b/etherpad/src/etherpad/db_migrations/m0027_pro_config.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0028_ondemand_beta_emails.js b/etherpad/src/etherpad/db_migrations/m0028_ondemand_beta_emails.js
index f708363..f708363 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0028_ondemand_beta_emails.js
+++ b/etherpad/src/etherpad/db_migrations/m0028_ondemand_beta_emails.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0029_lowercase_subdomains.js b/etherpad/src/etherpad/db_migrations/m0029_lowercase_subdomains.js
index 36b76ab..36b76ab 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0029_lowercase_subdomains.js
+++ b/etherpad/src/etherpad/db_migrations/m0029_lowercase_subdomains.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0030_fix_statistics_values.js b/etherpad/src/etherpad/db_migrations/m0030_fix_statistics_values.js
index aeaa40f..aeaa40f 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0030_fix_statistics_values.js
+++ b/etherpad/src/etherpad/db_migrations/m0030_fix_statistics_values.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0031_deleted_pro_users.js b/etherpad/src/etherpad/db_migrations/m0031_deleted_pro_users.js
index b9744a3..b9744a3 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0031_deleted_pro_users.js
+++ b/etherpad/src/etherpad/db_migrations/m0031_deleted_pro_users.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0032_reduce_topvalues_counts.js b/etherpad/src/etherpad/db_migrations/m0032_reduce_topvalues_counts.js
index 5e748f5..5e748f5 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0032_reduce_topvalues_counts.js
+++ b/etherpad/src/etherpad/db_migrations/m0032_reduce_topvalues_counts.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0033_pro_account_usage.js b/etherpad/src/etherpad/db_migrations/m0033_pro_account_usage.js
index 4b33f52..4b33f52 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0033_pro_account_usage.js
+++ b/etherpad/src/etherpad/db_migrations/m0033_pro_account_usage.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0034_create_recurring_billing_table.js b/etherpad/src/etherpad/db_migrations/m0034_create_recurring_billing_table.js
index 491581b..491581b 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0034_create_recurring_billing_table.js
+++ b/etherpad/src/etherpad/db_migrations/m0034_create_recurring_billing_table.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0035_add_email_to_paymentinfo.js b/etherpad/src/etherpad/db_migrations/m0035_add_email_to_paymentinfo.js
index a49e9f9..a49e9f9 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0035_add_email_to_paymentinfo.js
+++ b/etherpad/src/etherpad/db_migrations/m0035_add_email_to_paymentinfo.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0036_create_missing_subscription_records.js b/etherpad/src/etherpad/db_migrations/m0036_create_missing_subscription_records.js
index ce77734..ce77734 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0036_create_missing_subscription_records.js
+++ b/etherpad/src/etherpad/db_migrations/m0036_create_missing_subscription_records.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0037_create_pro_referral_table.js b/etherpad/src/etherpad/db_migrations/m0037_create_pro_referral_table.js
index 7a9982c..7a9982c 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0037_create_pro_referral_table.js
+++ b/etherpad/src/etherpad/db_migrations/m0037_create_pro_referral_table.js
diff --git a/trunk/etherpad/src/etherpad/db_migrations/m0038_pad_coarse_revs.js b/etherpad/src/etherpad/db_migrations/m0038_pad_coarse_revs.js
index 1e9a53c..1e9a53c 100644
--- a/trunk/etherpad/src/etherpad/db_migrations/m0038_pad_coarse_revs.js
+++ b/etherpad/src/etherpad/db_migrations/m0038_pad_coarse_revs.js
diff --git a/etherpad/src/etherpad/db_migrations/m0040_create_plugin_tables.js b/etherpad/src/etherpad/db_migrations/m0040_create_plugin_tables.js
new file mode 100644
index 0000000..62e8ff7
--- /dev/null
+++ b/etherpad/src/etherpad/db_migrations/m0040_create_plugin_tables.js
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("etherpad.utils.isPrivateNetworkEdition");
+import("sqlbase.sqlobj");
+import("sqlbase.sqlcommon");
+
+function run() {
+ sqlobj.createTable('plugin', {
+ id: 'INT NOT NULL '+sqlcommon.autoIncrementClause()+' PRIMARY KEY',
+ name: 'VARCHAR(128) character set utf8 collate utf8_bin UNIQUE NOT NULL'
+ });
+ sqlobj.createTable('hook_type', {
+ id: 'INT NOT NULL '+sqlcommon.autoIncrementClause()+' PRIMARY KEY',
+ name: 'VARCHAR(128) character set utf8 collate utf8_bin UNIQUE NOT NULL'
+ });
+ sqlobj.createTable('hook', {
+ id: 'INT NOT NULL '+sqlcommon.autoIncrementClause()+' PRIMARY KEY',
+ type_id: 'INT NOT NULL REFERENCES hook_type(id)',
+ name: 'VARCHAR(128) character set utf8 collate utf8_bin NOT NULL'
+ });
+ sqlobj.createTable('plugin_hook', {
+ plugin_id: 'INT NOT NULL REFERENCES plugin(id)',
+ hook_id: 'INT NOT NULL REFERENCES hook(id)',
+ original_name: 'VARCHAR(128) character set utf8 collate utf8_bin'
+ });
+}
diff --git a/etherpad/src/etherpad/db_migrations/migration_runner.js b/etherpad/src/etherpad/db_migrations/migration_runner.js
new file mode 100644
index 0000000..f4fa861
--- /dev/null
+++ b/etherpad/src/etherpad/db_migrations/migration_runner.js
@@ -0,0 +1,148 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+// Database migrations.
+
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+
+import("etherpad.globals.*");
+import("etherpad.utils.*");
+import("etherpad.log");
+import("etherpad.pne.pne_utils");
+
+jimport("java.lang.System.out.println");
+
+//----------------------------------------------------------------
+// 1 migration per file
+//----------------------------------------------------------------
+
+var migrations = [
+ "m0000_test",
+ "m0001_eepnet_signups_init",
+ "m0002_eepnet_signups_2",
+ "m0003_create_tests_table_v2",
+ "m0004_convert_all_tables_to_innodb",
+ "m0005_create_billing_tables",
+ "m0006_eepnet_signups_3",
+ "m0007_create_pro_tables_v4",
+ "m0008_persistent_vars",
+ "m0009_pad_tables",
+ "m0010_pad_sqlmeta",
+ "m0011_pro_users_temppass",
+ "m0012_pro_users_auto_signin",
+ "m0013_pne_padv2_upgrade",
+ "m0014_pne_globalpadids",
+ "m0015_padmeta_passwords",
+ "m0016_pne_tracking_data",
+ "m0017_pne_tracking_data_v2",
+ "m0018_eepnet_checkout_tables",
+ "m0019_padmeta_deleted",
+ "m0020_padmeta_archived",
+ "m0021_pro_padmeta_json",
+ "m0022_create_userids_table",
+ "m0023_create_usagestats_table",
+ "m0024_statistics_table",
+ "m0025_rename_pro_users_table",
+ "m0026_create_guests_table",
+ "m0027_pro_config",
+ "m0028_ondemand_beta_emails",
+ "m0029_lowercase_subdomains",
+ "m0030_fix_statistics_values",
+ "m0031_deleted_pro_users",
+ "m0032_reduce_topvalues_counts",
+ "m0033_pro_account_usage",
+ "m0034_create_recurring_billing_table",
+ "m0035_add_email_to_paymentinfo",
+ "m0036_create_missing_subscription_records",
+ "m0037_create_pro_referral_table",
+ "m0038_pad_coarse_revs",
+ "m0040_create_plugin_tables"
+];
+
+var mscope = this;
+migrations.forEach(function(m) {
+ import.call(mscope, "etherpad.db_migrations."+m);
+});
+
+//----------------------------------------------------------------
+
+function dmesg(m) {
+ if ((!isProduction()) || appjet.cache.db_migrations_print_debug) {
+ log.info(m);
+ println(m);
+ }
+}
+
+function onStartup() {
+ appjet.cache.db_migrations_print_debug = true;
+ if (!sqlcommon.doesTableExist("db_migrations")) {
+ appjet.cache.db_migrations_print_debug = false;
+ sqlobj.createTable('db_migrations', {
+ id: 'INT NOT NULL '+sqlcommon.autoIncrementClause()+' PRIMARY KEY',
+ name: 'VARCHAR(255) NOT NULL UNIQUE',
+ completed: 'TIMESTAMP'
+ });
+ }
+
+ if (pne_utils.isPNE()) { pne_utils.checkDbVersionUpgrade(); }
+ runMigrations();
+ if (pne_utils.isPNE()) { pne_utils.saveDbVersion(); }
+}
+
+function _migrationName(m) {
+ m = m.replace(/^m\d+\_/, '');
+ m = m.replace(/\_/g, '-');
+ return m;
+}
+
+function getCompletedMigrations() {
+ var completedMigrationsList = sqlobj.selectMulti('db_migrations', {}, {});
+ var completedMigrations = {};
+
+ completedMigrationsList.forEach(function(c) {
+ completedMigrations[c.name] = true;
+ });
+
+ return completedMigrations;
+}
+
+function runMigrations() {
+ var completedMigrations = getCompletedMigrations();
+
+ dmesg("Checking for database migrations...");
+ migrations.forEach(function(m) {
+ var name = _migrationName(m);
+ if (!completedMigrations[name]) {
+ sqlcommon.inTransaction(function() {
+ dmesg("performing database migration: ["+name+"]");
+ var startTime = +(new Date);
+
+ mscope[m].run();
+
+ var elapsedMs = +(new Date) - startTime;
+ dmesg("migration completed in "+elapsedMs+"ms");
+
+ sqlobj.insert('db_migrations', {
+ name: name,
+ completed: new Date()
+ });
+ });
+ }
+ });
+}
+
+
diff --git a/trunk/etherpad/src/etherpad/debug.js b/etherpad/src/etherpad/debug.js
index 069ad14..069ad14 100644
--- a/trunk/etherpad/src/etherpad/debug.js
+++ b/etherpad/src/etherpad/debug.js
diff --git a/etherpad/src/etherpad/globals.js b/etherpad/src/etherpad/globals.js
new file mode 100644
index 0000000..fcd5519
--- /dev/null
+++ b/etherpad/src/etherpad/globals.js
@@ -0,0 +1,49 @@
+/**
+ * Copyright 2009 Google Inc.
+ * Copyright 2010 Pita, Peter Martischka <petermartischka@googlemail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+//----------------------------------------------------------------
+// global variabls
+//----------------------------------------------------------------
+
+var COMETPATH = "/comet";
+
+var COLOR_PALETTE = ['#ffc7c7','#fff1c7','#e3ffc7','#c7ffd5','#c7ffff','#c7d5ff','#e3c7ff','#ffc7f1','#ff8f8f','#ffe38f','#c7ff8f','#8fffab','#8fffff','#8fabff','#c78fff','#ff8fe3','#d97979','#d9c179','#a9d979','#79d991','#79d9d9','#7991d9','#a979d9','#d979c1','#d9a9a9','#d9cda9','#c1d9a9','#a9d9b5','#a9d9d9','#a9b5d9','#c1a9d9','#d9a9cd'];
+
+var trueRegex = /\s*true\s*/i;
+
+function isProduction() {
+ return (trueRegex.test(appjet.config['etherpad.isProduction']));
+}
+
+function isProAccountEnabled() {
+ return (appjet.config['etherpad.proAccounts'] == "true");
+}
+
+function domainEnabled(domain) {
+ var enabled = appjet.config.topdomains.split(',');
+ for (var i = 0; i < enabled.length; i++)
+ if (domain == enabled[i])
+ return true;
+ return false;
+}
+
+var PNE_RELEASE_VERSION = "1.1.3";
+var PNE_RELEASE_DATE = "June 15, 2009";
+
+var PRO_FREE_ACCOUNTS = 1e9;
+
+
diff --git a/etherpad/src/etherpad/helpers.js b/etherpad/src/etherpad/helpers.js
new file mode 100644
index 0000000..3996a3b
--- /dev/null
+++ b/etherpad/src/etherpad/helpers.js
@@ -0,0 +1,306 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("fastJSON");
+import("jsutils.eachProperty");
+import("faststatic");
+import("comet");
+import("funhtml.META");
+
+import("etherpad.globals.*");
+import("etherpad.debug.dmesg");
+
+import("etherpad.pro.pro_utils");
+
+jimport("java.lang.System.out.println");
+
+//----------------------------------------------------------------
+// array that supports contains() in O(1)
+
+var _UniqueArray = function() {
+ this._a = [];
+ this._m = {};
+};
+_UniqueArray.prototype.add = function(x) {
+ if (!this._m[x]) {
+ this._a.push(x);
+ this._m[x] = true;
+ }
+};
+_UniqueArray.prototype.asArray = function() {
+ return this._a;
+};
+
+//----------------------------------------------------------------
+// EJS template helpers
+//----------------------------------------------------------------
+
+function _hd() {
+ if (!appjet.requestCache.helperData) {
+ appjet.requestCache.helperData = {
+ clientVars: {},
+ htmlTitle: "",
+ headExtra: "",
+ bodyId: "",
+ bodyClasses: new _UniqueArray(),
+ cssIncludes: new _UniqueArray(),
+ jsIncludes: new _UniqueArray(),
+ includeCometJs: false,
+ suppressGA: false,
+ showHeader: true,
+ robotsPolicy: null
+ };
+ }
+ return appjet.requestCache.helperData;
+}
+
+function addBodyClass(c) {
+ _hd().bodyClasses.add(c);
+}
+
+function addClientVars(vars) {
+ eachProperty(vars, function(k,v) {
+ _hd().clientVars[k] = v;
+ });
+}
+
+function getClientVar(name) {
+ return _hd().clientVars[name];
+}
+
+function addToHead(stuff) {
+ _hd().headExtra += stuff;
+}
+
+function setHtmlTitle(t) {
+ _hd().htmlTitle = t;
+}
+
+function setBodyId(id) {
+ _hd().bodyId = id;
+}
+
+function includeJs(relpath) {
+ _hd().jsIncludes.add(relpath);
+}
+
+function includeJQuery() {
+ includeJs("jquery-1.3.2.js");
+}
+
+function includeCss(relpath) {
+ _hd().cssIncludes.add(relpath);
+}
+
+function includeCometJs() {
+ _hd().includeCometJs = true;
+}
+
+function suppressGA() {
+ _hd().suppressGA = true;
+}
+
+function hideHeader() {
+ _hd().showHeader = false;
+}
+
+//----------------------------------------------------------------
+// for rendering HTML
+//----------------------------------------------------------------
+
+function bodyClasses() {
+ return _hd().bodyClasses.asArray().join(' ');
+}
+
+function clientVarsScript() {
+ var x = _hd().clientVars;
+ x = fastJSON.stringify(x);
+ if (x == '{}') {
+ return '<!-- no client vars -->';
+ }
+ x = x.replace(/</g, '\\x3c');
+ return [
+ '<script type="text/javascript">',
+ ' // <![CDATA[',
+ 'var clientVars = '+x+';',
+ ' // ]]>',
+ '</script>'
+ ].join('\n');
+}
+
+function htmlTitle() {
+ return _hd().htmlTitle;
+}
+
+function bodyId() {
+ return _hd().bodyId;
+}
+
+function baseHref() {
+ return request.scheme + "://"+ request.host + "/";
+}
+
+function headExtra() {
+ return _hd().headExtra;
+}
+
+function jsIncludes() {
+ if (isProduction()) {
+ var jsincludes = _hd().jsIncludes.asArray();
+ if (_hd().includeCometJs) {
+ jsincludes.splice(0, 0, {
+ getPath: function() { return 'comet-client.js'; },
+ getContents: function() { return comet.clientCode(); },
+ getMTime: function() { return comet.clientMTime(); }
+ });
+ }
+ if (jsincludes.length < 1) { return ''; }
+ var key = faststatic.getCompressedFilesKey('js', '/static/js', jsincludes);
+ return '<script type="text/javascript" src="/static/compressed/'+key+'"></script>';
+ } else {
+ var ts = +(new Date);
+ var r = [];
+ if (_hd().includeCometJs) {
+ r.push('<script type="text/javascript" src="'+COMETPATH+'/js/client.js?'+ts+'"></script>');
+ }
+ _hd().jsIncludes.asArray().forEach(function(relpath) {
+ r.push('<script type="text/javascript" src="/static/js/'+relpath+'?'+ts+'"></script>');
+ });
+ return r.join('\n');
+ }
+}
+
+function cssIncludes() {
+ if (isProduction()) {
+ var key = faststatic.getCompressedFilesKey('css', '/static/css', _hd().cssIncludes.asArray());
+ return '<link href="/static/compressed/'+key+'" rel="stylesheet" type="text/css" />';
+ } else {
+ var ts = +(new Date);
+ var r = [];
+ _hd().cssIncludes.asArray().forEach(function(relpath) {
+ r.push('<link href="/static/css/'+relpath+'?'+ts+'" rel="stylesheet" type="text/css" />');
+ });
+ return r.join('\n');
+ }
+}
+
+function oemail(username) {
+ return '&lt;<a class="obfuscemail" href="mailto:'+username+'@p*d.sp***e.inf.fu-berlin.de">'+
+ username+'@p*d.sp***e.inf.fu-berlin.de</a>&gt;';
+}
+
+function googleAnalytics() {
+ // GA disabled always now.
+ return '';
+
+ if (!isProduction()) { return ''; }
+ if (_hd().suppressGA) { return ''; }
+ return [
+ '<script type="text/javascript">',
+ ' var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");',
+ ' document.write(unescape("%3Cscript src=\'" + gaJsHost + "google-analytics.com/ga.js\' type=\'text/javascript\'%3E%3C/script%3E"));',
+ '</script>',
+ '<script type="text/javascript">',
+ 'try {',
+ ' var pageTracker = _gat._getTracker("UA-6236278-1");',
+ ' pageTracker._trackPageview();',
+ '} catch(err) {}</script>'
+ ].join('\n');
+}
+
+function isHeaderVisible() {
+ return _hd().showHeader;
+}
+
+function setRobotsPolicy(policy) {
+ _hd().robotsPolicy = policy;
+}
+function robotsMeta() {
+ if (!_hd().robotsPolicy) { return ''; }
+ var content = "";
+ content += (_hd().robotsPolicy.index ? 'INDEX' : 'NOINDEX');
+ content += ", ";
+ content += (_hd().robotsPolicy.follow ? 'FOLLOW' : 'NOFOLLOW');
+ return META({name: "ROBOTS", content: content});
+}
+
+function thawteSiteSeal() {
+ return [
+ '<div>',
+ '<table width="10" border="0" cellspacing="0" align="center">',
+ '<tr>',
+ '<td>',
+ '<script src="https://siteseal.thawte.com/cgi/server/thawte_seal_generator.exe"></script>',
+ '</td>',
+ '</tr>',
+ '<tr>',
+ '<td height="0" align="center">',
+ '<a style="color:#AD0034" target="_new"',
+ 'href="http://www.thawte.com/digital-certificates/">',
+ '<span style="font-family:arial; font-size:8px; color:#AD0034">',
+ 'ABOUT SSL CERTIFICATES</span>',
+ '</a>',
+ '</td>',
+ '</tr>',
+ '</table>',
+ '</div>'
+ ].join('\n');
+}
+
+function clearFloats() {
+ return '<div style="clear: both;"><!-- --></div>';
+}
+
+function rafterBlogUrl() {
+ return '/ep/blog/posts/google-acquires-appjet';
+}
+
+function rafterNote() {
+ return """<div style='border: 1px solid #ccc; background: #fee; padding: 1em; margin: 1em 0;'>
+ <b>Note: </b>We are no longer accepting new accounts. <a href='"""+rafterBlogUrl()+"""'>Read more</a>.
+ </div>""";
+}
+
+function rafterTerminationDate() {
+ return "March 31, 2010";
+}
+
+function updateToUrl(setParams, deleteParams, setPath) {
+ var params = {};
+
+ for (param in request.params)
+ if (deleteParams === undefined || deleteParams.indexOf(param) == -1)
+ params[param] = request.params[param];
+
+ if (setParams !== undefined)
+ for (param in setParams)
+ params[param] = setParams[param];
+
+ var path = request.path;
+ if (setPath !== undefined)
+ path = setPath;
+
+ var paramStr = '';
+ for (param in params) {
+ if (paramStr == '')
+ paramStr += '?';
+ else
+ paramStr += '&';
+ paramStr += param + '=' + params[param];
+ }
+
+ return path + paramStr;
+} \ No newline at end of file
diff --git a/trunk/etherpad/src/etherpad/importexport/importexport.js b/etherpad/src/etherpad/importexport/importexport.js
index 304a1f4..304a1f4 100644
--- a/trunk/etherpad/src/etherpad/importexport/importexport.js
+++ b/etherpad/src/etherpad/importexport/importexport.js
diff --git a/etherpad/src/etherpad/legacy_urls.js b/etherpad/src/etherpad/legacy_urls.js
new file mode 100644
index 0000000..d8aa629
--- /dev/null
+++ b/etherpad/src/etherpad/legacy_urls.js
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+/* legacy URLs only apply to the public main site. (not Pro or PNE). */
+
+var _legacyURLs = {
+ '/ep/beta-signup': '/',
+ '/ep/talktostrangers': '/',
+ '/ep/about/pricing-eepod': '/ep/about/pricing-pro',
+ '/static/html/enterprise-etherpad-installguide.html': '/ep/pne-manual/',
+ '/static/html/eepnet/eepnet-changelog.html': '/ep/pne-manual/changelog',
+ '/static/html/eepnet/eepnet-installguide.html': '/ep/pne-manual/',
+ '/ep/blog/posts/back-online-until-open-sourced': '/ep/blog/posts/etherpad-back-online-until-open-sourced'
+};
+
+function checkPath() {
+ var p = request.path;
+ var match = _legacyURLs[p];
+
+ if (match) {
+ response.redirect(match);
+ }
+}
+
diff --git a/trunk/etherpad/src/etherpad/licensing.js b/etherpad/src/etherpad/licensing.js
index 2337456..2337456 100644
--- a/trunk/etherpad/src/etherpad/licensing.js
+++ b/etherpad/src/etherpad/licensing.js
diff --git a/trunk/etherpad/src/etherpad/log.js b/etherpad/src/etherpad/log.js
index cfc82de..cfc82de 100644
--- a/trunk/etherpad/src/etherpad/log.js
+++ b/etherpad/src/etherpad/log.js
diff --git a/trunk/etherpad/src/etherpad/metrics/metrics.js b/etherpad/src/etherpad/metrics/metrics.js
index 435a5be..435a5be 100644
--- a/trunk/etherpad/src/etherpad/metrics/metrics.js
+++ b/etherpad/src/etherpad/metrics/metrics.js
diff --git a/trunk/etherpad/src/etherpad/pad/activepads.js b/etherpad/src/etherpad/pad/activepads.js
index 07f5e2e..07f5e2e 100644
--- a/trunk/etherpad/src/etherpad/pad/activepads.js
+++ b/etherpad/src/etherpad/pad/activepads.js
diff --git a/trunk/etherpad/src/etherpad/pad/chatarchive.js b/etherpad/src/etherpad/pad/chatarchive.js
index 2f8e33a..2f8e33a 100644
--- a/trunk/etherpad/src/etherpad/pad/chatarchive.js
+++ b/etherpad/src/etherpad/pad/chatarchive.js
diff --git a/trunk/etherpad/src/etherpad/pad/dbwriter.js b/etherpad/src/etherpad/pad/dbwriter.js
index 233622b..233622b 100644
--- a/trunk/etherpad/src/etherpad/pad/dbwriter.js
+++ b/etherpad/src/etherpad/pad/dbwriter.js
diff --git a/trunk/etherpad/src/etherpad/pad/easysync2migration.js b/etherpad/src/etherpad/pad/easysync2migration.js
index c2a1523..c2a1523 100644
--- a/trunk/etherpad/src/etherpad/pad/easysync2migration.js
+++ b/etherpad/src/etherpad/pad/easysync2migration.js
diff --git a/trunk/etherpad/src/etherpad/pad/exporthtml.js b/etherpad/src/etherpad/pad/exporthtml.js
index 2512603..2512603 100644
--- a/trunk/etherpad/src/etherpad/pad/exporthtml.js
+++ b/etherpad/src/etherpad/pad/exporthtml.js
diff --git a/trunk/etherpad/src/etherpad/pad/importhtml.js b/etherpad/src/etherpad/pad/importhtml.js
index 4a48c6f..4a48c6f 100644
--- a/trunk/etherpad/src/etherpad/pad/importhtml.js
+++ b/etherpad/src/etherpad/pad/importhtml.js
diff --git a/etherpad/src/etherpad/pad/model.js b/etherpad/src/etherpad/pad/model.js
new file mode 100644
index 0000000..3f44dfa
--- /dev/null
+++ b/etherpad/src/etherpad/pad/model.js
@@ -0,0 +1,655 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("fastJSON");
+import("sqlbase.sqlbase");
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+import("timer");
+import("sync");
+
+import("etherpad.collab.ace.easysync2.{Changeset,AttribPool}");
+import("etherpad.log");
+import("etherpad.pad.padevents");
+import("etherpad.pad.padutils");
+import("etherpad.pad.dbwriter");
+import("etherpad.pad.pad_migrations");
+import("etherpad.pad.pad_security");
+import("etherpad.collab.collab_server");
+import("cache_utils.syncedWithCache");
+import("etherpad.admin.plugins");
+
+jimport("net.appjet.common.util.LimitedSizeMapping");
+
+jimport("java.lang.System.out.println");
+
+jimport("java.util.concurrent.ConcurrentHashMap");
+jimport("net.appjet.oui.GlobalSynchronizer");
+jimport("net.appjet.oui.exceptionlog");
+
+function onStartup() {
+ appjet.cache.pads = {};
+ appjet.cache.pads.meta = new ConcurrentHashMap();
+ appjet.cache.pads.temp = new ConcurrentHashMap();
+ appjet.cache.pads.revs = new ConcurrentHashMap();
+ appjet.cache.pads.revs10 = new ConcurrentHashMap();
+ appjet.cache.pads.revs100 = new ConcurrentHashMap();
+ appjet.cache.pads.revs1000 = new ConcurrentHashMap();
+ appjet.cache.pads.chat = new ConcurrentHashMap();
+ appjet.cache.pads.revmeta = new ConcurrentHashMap();
+ appjet.cache.pads.authors = new ConcurrentHashMap();
+ appjet.cache.pads.apool = new ConcurrentHashMap();
+}
+
+var _JSON_CACHE_SIZE = 10000;
+
+// to clear: appjet.cache.padmodel.modelcache.map.clear()
+function _getModelCache() {
+ return syncedWithCache('padmodel.modelcache', function(cache) {
+ if (! cache.map) {
+ cache.map = new LimitedSizeMapping(_JSON_CACHE_SIZE);
+ }
+ return cache.map;
+ });
+}
+
+function cleanText(txt) {
+ return txt.replace(/\r\n/g,'\n').replace(/\r/g,'\n').replace(/\t/g, ' ').replace(/\xa0/g, ' ');
+}
+
+/**
+ * Access a pad object, which is passed as an argument to
+ * the given padFunc, which is executed inside an exclusive lock,
+ * and return the result. If the pad doesn't exist, a wrapper
+ * object is still created and passed to padFunc, and it can
+ * be used to check whether the pad exists and create it.
+ *
+ * Note: padId is a GLOBAL id.
+ */
+function accessPadGlobal(padId, padFunc, rwMode) {
+ // this may make a nested call to accessPadGlobal, so do it first
+ pad_security.checkAccessControl(padId, rwMode);
+
+ // pad is never loaded into memory (made "active") unless it has been migrated.
+ // Migrations do not use accessPad, but instead access the database directly.
+ pad_migrations.ensureMigrated(padId);
+
+ var mode = (rwMode || "rw").toLowerCase();
+
+ if (! appjet.requestCache.padsAccessing) {
+ appjet.requestCache.padsAccessing = {};
+ }
+ if (appjet.requestCache.padsAccessing[padId]) {
+ // nested access to same pad
+ var p = appjet.requestCache.padsAccessing[padId];
+ var m = p._meta;
+ if (m && mode != "r") {
+ m.status.lastAccess = +new Date();
+ m.status.dirty = true;
+ }
+ return padFunc(p);
+ }
+
+ return doWithPadLock(padId, function() {
+ return sqlcommon.inTransaction(function() {
+ var meta = _getPadMetaData(padId); // null if pad doesn't exist yet
+
+ if (meta && ! meta.status) {
+ meta.status = { validated: false };
+ }
+
+ if (meta && mode != "r") {
+ meta.status.lastAccess = +new Date();
+ }
+
+ function getCurrentAText() {
+ var tempObj = pad.tempObj();
+ if (! tempObj.atext) {
+ tempObj.atext = pad.getInternalRevisionAText(meta.head);
+ }
+ return tempObj.atext;
+ }
+ function addRevision(theChangeset, author, optDatestamp) {
+ var atext = getCurrentAText();
+ var newAText = Changeset.applyToAText(theChangeset, atext, pad.pool());
+ Changeset.copyAText(newAText, atext); // updates pad.tempObj().atext!
+
+ var newRev = ++meta.head;
+
+ var revs = _getPadStringArray(padId, "revs");
+ revs.setEntry(newRev, theChangeset);
+
+ var revmeta = _getPadStringArray(padId, "revmeta");
+ var thisRevMeta = {t: (optDatestamp || (+new Date())),
+ a: getNumForAuthor(author)};
+ if ((newRev % meta.keyRevInterval) == 0) {
+ thisRevMeta.atext = atext;
+ }
+ revmeta.setJSONEntry(newRev, thisRevMeta);
+
+ updateCoarseChangesets(true);
+ }
+ function getNumForAuthor(author, dontAddIfAbsent) {
+ return pad.pool().putAttrib(['author',author||''], dontAddIfAbsent);
+ }
+ function getAuthorForNum(n) {
+ // must return null if n is an attrib number that isn't an author
+ var pair = pad.pool().getAttrib(n);
+ if (pair && pair[0] == 'author') {
+ return pair[1];
+ }
+ return null;
+ }
+
+ function updateCoarseChangesets(onlyIfPresent) {
+ // this is fast to run if the coarse changesets
+ // are up-to-date or almost up-to-date;
+ // if there's no coarse changeset data,
+ // it may take a while.
+
+ if (! meta.coarseHeads) {
+ if (onlyIfPresent) {
+ return;
+ }
+ else {
+ meta.coarseHeads = {10:-1, 100:-1, 1000:-1};
+ }
+ }
+ var head = meta.head;
+ // once we reach head==9, coarseHeads[10] moves
+ // from -1 up to 0; at head==19 it moves up to 1
+ var desiredCoarseHeads = {
+ 10: Math.floor((head-9)/10),
+ 100: Math.floor((head-99)/100),
+ 1000: Math.floor((head-999)/1000)
+ };
+ var revs = _getPadStringArray(padId, "revs");
+ var revs10 = _getPadStringArray(padId, "revs10");
+ var revs100 = _getPadStringArray(padId, "revs100");
+ var revs1000 = _getPadStringArray(padId, "revs1000");
+ var fineArrays = [revs, revs10, revs100];
+ var coarseArrays = [revs10, revs100, revs1000];
+ var levels = [10, 100, 1000];
+ var dirty = false;
+ for(var z=0;z<3;z++) {
+ var level = levels[z];
+ var coarseArray = coarseArrays[z];
+ var fineArray = fineArrays[z];
+ while (meta.coarseHeads[level] < desiredCoarseHeads[level]) {
+ dirty = true;
+ // for example, if the current coarse head is -1,
+ // compose 0-9 inclusive of the finer level and call it 0
+ var x = meta.coarseHeads[level] + 1;
+ var cs = fineArray.getEntry(10 * x);
+ for(var i=1;i<=9;i++) {
+ cs = Changeset.compose(cs, fineArray.getEntry(10*x + i),
+ pad.pool());
+ }
+ coarseArray.setEntry(x, cs);
+ meta.coarseHeads[level] = x;
+ }
+ }
+ if (dirty) {
+ meta.status.dirty = true;
+ }
+ }
+
+ /////////////////// "Public" API starts here (functions used by collab_server or other modules)
+ var pad = {
+ // Operations that write to the data structure should
+ // set meta.dirty = true. Any pad access that isn't
+ // done in "read" mode also sets dirty = true.
+ getId: function() { return padId; },
+ exists: function() { return !!meta; },
+ create: function(optText) {
+ meta = {};
+ meta.head = -1; // incremented below by addRevision
+ pad.tempObj().atext = Changeset.makeAText("\n");
+ meta.padId = padId,
+ meta.keyRevInterval = 100;
+ meta.numChatMessages = 0;
+ var t = +new Date();
+ meta.status = { validated: true };
+ meta.status.lastAccess = t;
+ meta.status.dirty = true;
+ meta.supportsTimeSlider = true;
+
+ var firstChangeset = Changeset.makeSplice("\n", 0, 0,
+ cleanText(optText || ''));
+ addRevision(firstChangeset, '');
+
+ _insertPadMetaData(padId, meta);
+
+ sqlobj.insert("PAD_SQLMETA", {
+ id: padId, version: 2, creationTime: new Date(t), lastWriteTime: new Date(),
+ headRev: meta.head }); // headRev is not authoritative, just for info
+
+ padevents.onNewPad(pad);
+ },
+ destroy: function() { // you may want to collab_server.bootAllUsers first
+ padevents.onDestroyPad(pad);
+
+ _destroyPadStringArray(padId, "revs");
+ _destroyPadStringArray(padId, "revs10");
+ _destroyPadStringArray(padId, "revs100");
+ _destroyPadStringArray(padId, "revs1000");
+ _destroyPadStringArray(padId, "revmeta");
+ _destroyPadStringArray(padId, "chat");
+ _destroyPadStringArray(padId, "authors");
+ _removePadMetaData(padId);
+ _removePadAPool(padId);
+ sqlobj.deleteRows("PAD_SQLMETA", { id: padId });
+ meta = null;
+ },
+ writeToDB: function() {
+ var meta2 = {};
+ for(var k in meta) meta2[k] = meta[k];
+ delete meta2.status;
+ sqlbase.putJSON("PAD_META", padId, meta2);
+
+ plugins.callHook("padModelWriteToDB", {pad:pad, padId:padId});
+
+ _getPadStringArray(padId, "revs").writeToDB();
+ _getPadStringArray(padId, "revs10").writeToDB();
+ _getPadStringArray(padId, "revs100").writeToDB();
+ _getPadStringArray(padId, "revs1000").writeToDB();
+ _getPadStringArray(padId, "revmeta").writeToDB();
+ _getPadStringArray(padId, "chat").writeToDB();
+ _getPadStringArray(padId, "authors").writeToDB();
+ sqlbase.putJSON("PAD_APOOL", padId, pad.pool().toJsonable());
+
+ var props = { headRev: meta.head, lastWriteTime: new Date() };
+ _writePadSqlMeta(padId, props);
+ },
+ pool: function() {
+ return _getPadAPool(padId);
+ },
+ getHeadRevisionNumber: function() { return meta.head; },
+ getRevisionAuthor: function(r) {
+ var n = _getPadStringArray(padId, "revmeta").getJSONEntry(r).a;
+ return getAuthorForNum(Number(n));
+ },
+ getRevisionChangeset: function(r) {
+ return _getPadStringArray(padId, "revs").getEntry(r);
+ },
+ tempObj: function() { return _getPadTemp(padId); },
+ getKeyRevisionNumber: function(r) {
+ return Math.floor(r / meta.keyRevInterval) * meta.keyRevInterval;
+ },
+ getInternalRevisionAText: function(r) {
+ var cacheKey = "atext/C/"+r+"/"+padId;
+ var modelCache = _getModelCache();
+ var cachedValue = modelCache.get(cacheKey);
+ if (cachedValue) {
+ modelCache.touch(cacheKey);
+ //java.lang.System.out.println("HIT! "+cacheKey);
+ return Changeset.cloneAText(cachedValue);
+ }
+ //java.lang.System.out.println("MISS! "+cacheKey);
+
+ var revs = _getPadStringArray(padId, "revs");
+ var keyRev = pad.getKeyRevisionNumber(r);
+ var revmeta = _getPadStringArray(padId, "revmeta");
+ var atext = revmeta.getJSONEntry(keyRev).atext;
+ var curRev = keyRev;
+ var targetRev = r;
+ var apool = pad.pool();
+ while (curRev < targetRev) {
+ curRev++;
+ var cs = pad.getRevisionChangeset(curRev);
+ atext = Changeset.applyToAText(cs, atext, apool);
+ }
+ modelCache.put(cacheKey, Changeset.cloneAText(atext));
+ return atext;
+ },
+ getInternalRevisionText: function(r, optInfoObj) {
+ var atext = pad.getInternalRevisionAText(r);
+ var text = atext.text;
+ if (optInfoObj) {
+ if (text.slice(-1) != "\n") {
+ optInfoObj.badLastChar = text.slice(-1);
+ }
+ }
+ return text;
+ },
+ getRevisionText: function(r, optInfoObj) {
+ var internalText = pad.getInternalRevisionText(r, optInfoObj);
+ return internalText.slice(0, -1);
+ },
+ atext: function() { return Changeset.cloneAText(getCurrentAText()); },
+ text: function() { return pad.atext().text; },
+ getRevisionDate: function(r) {
+ var revmeta = _getPadStringArray(padId, "revmeta");
+ return new Date(revmeta.getJSONEntry(r).t);
+ },
+ // note: calls like appendRevision will NOT notify clients of the change!
+ // you must go through collab_server.
+ // Also, be sure to run cleanText() on any text to strip out carriage returns
+ // and other stuff.
+ appendRevision: function(theChangeset, author, optDatestamp) {
+ addRevision(theChangeset, author || '', optDatestamp);
+ },
+ appendChatMessage: function(obj) {
+ var index = meta.numChatMessages;
+ meta.numChatMessages++;
+ var chat = _getPadStringArray(padId, "chat");
+ chat.setJSONEntry(index, obj);
+ },
+ getNumChatMessages: function() {
+ return meta.numChatMessages;
+ },
+ getChatMessage: function(i) {
+ var chat = _getPadStringArray(padId, "chat");
+ return chat.getJSONEntry(i);
+ },
+ getPadOptionsObj: function() {
+ var data = pad.getDataRoot();
+ if (! data.padOptions) {
+ data.padOptions = {};
+ }
+ if ((! data.padOptions.guestPolicy) ||
+ (data.padOptions.guestPolicy == 'ask')) {
+ data.padOptions.guestPolicy = 'deny';
+ }
+ return data.padOptions;
+ },
+ getGuestPolicy: function() {
+ // allow/ask/deny
+ return pad.getPadOptionsObj().guestPolicy;
+ },
+ setGuestPolicy: function(policy) {
+ pad.getPadOptionsObj().guestPolicy = policy;
+ },
+ getDataRoot: function() {
+ var dataRoot = meta.dataRoot;
+ if (! dataRoot) {
+ dataRoot = {};
+ meta.dataRoot = dataRoot;
+ }
+ return dataRoot;
+ },
+ // returns an object, changes to which are not reflected
+ // in the DB; use setAuthorData for mutation
+ getAuthorData: function(author) {
+ var authors = _getPadStringArray(padId, "authors");
+ var n = getNumForAuthor(author, true);
+ if (n < 0) {
+ return null;
+ }
+ else {
+ return authors.getJSONEntry(n);
+ }
+ },
+ setAuthorData: function(author, data) {
+ var authors = _getPadStringArray(padId, "authors");
+ var n = getNumForAuthor(author);
+ authors.setJSONEntry(n, data);
+ },
+ adoptChangesetAttribs: function(cs, oldPool) {
+ return Changeset.moveOpsToNewPool(cs, oldPool, pad.pool());
+ },
+ eachATextAuthor: function(atext, func) {
+ var seenNums = {};
+ Changeset.eachAttribNumber(atext.attribs, function(n) {
+ if (! seenNums[n]) {
+ seenNums[n] = true;
+ var author = getAuthorForNum(n);
+ if (author) {
+ func(author, n);
+ }
+ }
+ });
+ },
+ getCoarseChangeset: function(start, numChangesets) {
+ updateCoarseChangesets();
+
+ if (!(numChangesets == 10 || numChangesets == 100 ||
+ numChangesets == 1000)) {
+ return null;
+ }
+ var level = numChangesets;
+ var x = Math.floor(start / level);
+ if (!(x >= 0 && x*level == start)) {
+ return null;
+ }
+
+ var cs = _getPadStringArray(padId, "revs"+level).getEntry(x);
+
+ if (! cs) {
+ return null;
+ }
+
+ return cs;
+ },
+ getSupportsTimeSlider: function() {
+ if (! ('supportsTimeSlider' in meta)) {
+ if (padutils.isProPadId(padId)) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ return !! meta.supportsTimeSlider;
+ }
+ },
+ setSupportsTimeSlider: function(v) {
+ meta.supportsTimeSlider = v;
+ },
+ get _meta() { return meta; }
+ };
+
+ try {
+ padutils.setCurrentPad(padId);
+ appjet.requestCache.padsAccessing[padId] = pad;
+ return padFunc(pad);
+ }
+ finally {
+ padutils.clearCurrentPad();
+ delete appjet.requestCache.padsAccessing[padId];
+ if (meta) {
+ if (mode != "r") {
+ meta.status.dirty = true;
+ }
+ if (meta.status.dirty) {
+ dbwriter.notifyPadDirty(padId);
+ }
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Call an arbitrary function with no arguments inside an exclusive
+ * lock on a padId, and return the result.
+ */
+function doWithPadLock(padId, func) {
+ var lockName = "document/"+padId;
+ return sync.doWithStringLock(lockName, func);
+}
+
+function isPadLockHeld(padId) {
+ var lockName = "document/"+padId;
+ return GlobalSynchronizer.isHeld(lockName);
+}
+
+/**
+ * Get pad meta-data object, which is stored in SQL as JSON
+ * but cached in appjet.cache. Returns null if pad doesn't
+ * exist at all (does NOT create it). Requires pad lock.
+ */
+function _getPadMetaData(padId) {
+ var padMeta = appjet.cache.pads.meta.get(padId);
+ if (! padMeta) {
+ // not in cache
+ padMeta = sqlbase.getJSON("PAD_META", padId);
+ if (! padMeta) {
+ // not in SQL
+ padMeta = null;
+ }
+ else {
+ appjet.cache.pads.meta.put(padId, padMeta);
+ }
+ }
+ return padMeta;
+}
+
+/**
+ * Sets a pad's meta-data object, such as when creating
+ * a pad for the first time. Requires pad lock.
+ */
+function _insertPadMetaData(padId, obj) {
+ appjet.cache.pads.meta.put(padId, obj);
+}
+
+/**
+ * Removes a pad's meta data, writing through to the database.
+ * Used for the rare case of deleting a pad.
+ */
+function _removePadMetaData(padId) {
+ appjet.cache.pads.meta.remove(padId);
+ sqlbase.deleteJSON("PAD_META", padId);
+}
+
+function _getPadAPool(padId) {
+ var padAPool = appjet.cache.pads.apool.get(padId);
+ if (! padAPool) {
+ // not in cache
+ padAPool = new AttribPool();
+ padAPoolJson = sqlbase.getJSON("PAD_APOOL", padId);
+ if (padAPoolJson) {
+ // in SQL
+ padAPool.fromJsonable(padAPoolJson);
+ }
+ appjet.cache.pads.apool.put(padId, padAPool);
+ }
+ return padAPool;
+}
+
+/**
+ * Removes a pad's apool data, writing through to the database.
+ * Used for the rare case of deleting a pad.
+ */
+function _removePadAPool(padId) {
+ appjet.cache.pads.apool.remove(padId);
+ sqlbase.deleteJSON("PAD_APOOL", padId);
+}
+
+/**
+ * Get an object for a pad that's not persisted in storage,
+ * e.g. for tracking open connections. Creates object
+ * if necessary. Requires pad lock.
+ */
+function _getPadTemp(padId) {
+ var padTemp = appjet.cache.pads.temp.get(padId);
+ if (! padTemp) {
+ padTemp = {};
+ appjet.cache.pads.temp.put(padId, padTemp);
+ }
+ return padTemp;
+}
+
+/**
+ * Returns an object with methods for manipulating a string array, where name
+ * is something like "revs" or "chat". The object must be acquired and used
+ * all within a pad lock.
+ */
+function _getPadStringArray(padId, name) {
+ var padFoo = appjet.cache.pads[name].get(padId);
+ if (! padFoo) {
+ padFoo = {};
+ // writes go into writeCache, which is authoritative for reads;
+ // reads cause pages to be read into readCache
+ padFoo.readCache = {};
+ padFoo.writeCache = {};
+ appjet.cache.pads[name].put(padId, padFoo);
+ }
+ var tableName = "PAD_"+name.toUpperCase();
+ var self = {
+ getEntry: function(idx) {
+ var n = Number(idx);
+ if (padFoo.writeCache[n]) return padFoo.writeCache[n];
+ if (padFoo.readCache[n]) return padFoo.readCache[n];
+ sqlbase.getPageStringArrayElements(tableName, padId, n, padFoo.readCache);
+ return padFoo.readCache[n]; // null if not present in SQL
+ },
+ setEntry: function(idx, value) {
+ var n = Number(idx);
+ var v = String(value);
+ padFoo.writeCache[n] = v;
+ },
+ getJSONEntry: function(idx) {
+ var result = self.getEntry(idx);
+ if (! result) return result;
+ return fastJSON.parse(String(result));
+ },
+ setJSONEntry: function(idx, valueObj) {
+ self.setEntry(idx, fastJSON.stringify(valueObj));
+ },
+ writeToDB: function() {
+ sqlbase.putDictStringArrayElements(tableName, padId, padFoo.writeCache);
+ // copy key-vals of writeCache into readCache
+ var readCache = padFoo.readCache;
+ var writeCache = padFoo.writeCache;
+ for(var p in writeCache) {
+ readCache[p] = writeCache[p];
+ }
+ padFoo.writeCache = {};
+ }
+ };
+ return self;
+}
+
+/**
+ * Destroy a string array; writes through to the database. Must be
+ * called within a pad lock.
+ */
+function _destroyPadStringArray(padId, name) {
+ appjet.cache.pads[name].remove(padId);
+ var tableName = "PAD_"+name.toUpperCase();
+ sqlbase.clearStringArray(tableName, padId);
+}
+
+/**
+ * SELECT the row of PAD_SQLMETA for the given pad. Requires pad lock.
+ */
+function _getPadSqlMeta(padId) {
+ return sqlobj.selectSingle("PAD_SQLMETA", { id: padId });
+}
+
+function _writePadSqlMeta(padId, updates) {
+ sqlobj.update("PAD_SQLMETA", { id: padId }, updates);
+}
+
+
+// called from dbwriter
+function removeFromMemory(pad) {
+ // safe to call if all data is written to SQL, otherwise will lose data;
+ var padId = pad.getId();
+ appjet.cache.pads.meta.remove(padId);
+ appjet.cache.pads.revs.remove(padId);
+ appjet.cache.pads.revs10.remove(padId);
+ appjet.cache.pads.revs100.remove(padId);
+ appjet.cache.pads.revs1000.remove(padId);
+ appjet.cache.pads.chat.remove(padId);
+ appjet.cache.pads.revmeta.remove(padId);
+ appjet.cache.pads.apool.remove(padId);
+ collab_server.removeFromMemory(pad);
+}
+
+
diff --git a/trunk/etherpad/src/etherpad/pad/noprowatcher.js b/etherpad/src/etherpad/pad/noprowatcher.js
index 8eb2a92..8eb2a92 100644
--- a/trunk/etherpad/src/etherpad/pad/noprowatcher.js
+++ b/etherpad/src/etherpad/pad/noprowatcher.js
diff --git a/trunk/etherpad/src/etherpad/pad/pad_migrations.js b/etherpad/src/etherpad/pad/pad_migrations.js
index e81cf63..e81cf63 100644
--- a/trunk/etherpad/src/etherpad/pad/pad_migrations.js
+++ b/etherpad/src/etherpad/pad/pad_migrations.js
diff --git a/trunk/etherpad/src/etherpad/pad/pad_security.js b/etherpad/src/etherpad/pad/pad_security.js
index 0ff8783..0ff8783 100644
--- a/trunk/etherpad/src/etherpad/pad/pad_security.js
+++ b/etherpad/src/etherpad/pad/pad_security.js
diff --git a/trunk/etherpad/src/etherpad/pad/padevents.js b/etherpad/src/etherpad/pad/padevents.js
index 52b303c..52b303c 100644
--- a/trunk/etherpad/src/etherpad/pad/padevents.js
+++ b/etherpad/src/etherpad/pad/padevents.js
diff --git a/trunk/etherpad/src/etherpad/pad/padusers.js b/etherpad/src/etherpad/pad/padusers.js
index f04f0eb..f04f0eb 100644
--- a/trunk/etherpad/src/etherpad/pad/padusers.js
+++ b/etherpad/src/etherpad/pad/padusers.js
diff --git a/etherpad/src/etherpad/pad/padutils.js b/etherpad/src/etherpad/pad/padutils.js
new file mode 100644
index 0000000..b53de11
--- /dev/null
+++ b/etherpad/src/etherpad/pad/padutils.js
@@ -0,0 +1,191 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("fastJSON");
+import("stringutils");
+
+import("etherpad.control.pro.account_control");
+
+import("etherpad.pro.pro_utils");
+import("etherpad.pro.domains");
+import("etherpad.pro.pro_accounts");
+import("etherpad.pro.pro_padmeta");
+import("etherpad.pad.model");
+import("etherpad.sessions.getSession");
+import("etherpad.helpers");
+
+jimport("java.lang.System.out.println");
+
+
+function setCurrentPad(p) {
+ appjet.context.attributes().update("currentPadId", p);
+}
+
+function clearCurrentPad() {
+ appjet.context.attributes()['$minus$eq']("currentPadId");
+}
+
+function getCurrentPad() {
+ var padOpt = appjet.context.attributes().get("currentPadId");
+ if (padOpt.isEmpty()) return null;
+ return padOpt.get();
+}
+
+function _parseCookie(text) {
+ try {
+ var cookieData = fastJSON.parse(unescape(text));
+ return cookieData;
+ }
+ catch (e) {
+ return null;
+ }
+}
+
+function getPrefsCookieData() {
+ var prefsCookie = request.cookies['prefs'];
+ if (!prefsCookie) {
+ return null;
+ }
+
+ return _parseCookie(prefsCookie);
+}
+
+function getPrefsCookieUserId() {
+ var cookieData = getPrefsCookieData();
+ if (! cookieData) {
+ return null;
+ }
+ return cookieData.userId || null;
+}
+
+/**
+ * Not valid to call this function outisde a HTTP request.
+ */
+function accessPadLocal(localPadId, fn, rwMode) {
+ if (!request.isDefined) {
+ throw Error("accessPadLocal() cannot run outside an HTTP request.");
+ }
+ var globalPadId = getGlobalPadId(localPadId);
+ var fnwrap = function(pad) {
+ pad.getLocalId = function() {
+ return getLocalPadId(pad);
+ };
+ return fn(pad);
+ }
+ return model.accessPadGlobal(globalPadId, fnwrap, rwMode);
+}
+
+/**
+ * Not valid to call this function outisde a HTTP request.
+ */
+function getGlobalPadId(localPadId) {
+ if (!request.isDefined) {
+ throw Error("getGlobalPadId() cannot run outside an HTTP request.");
+ }
+ if (pro_utils.isProDomainRequest()) {
+ return makeGlobalId(domains.getRequestDomainId(), localPadId);
+ } else {
+ // pad.spline.inf.fu-berlin.de pads
+ return localPadId;
+ }
+}
+
+function makeGlobalId(domainId, localPadId) {
+ return [domainId, localPadId].map(String).join('$');
+}
+
+function globalToLocalId(globalId) {
+ var parts = globalId.split('$');
+ if (parts.length == 1) {
+ return parts[0];
+ } else {
+ return parts[1];
+ }
+}
+
+function getLocalPadId(pad) {
+ var globalId = pad.getId();
+ return globalToLocalId(globalId);
+}
+
+function isProPadId(globalPadId) {
+ return (globalPadId.indexOf("$") > 0);
+}
+
+function isProPad(pad) {
+ return isProPadId(pad.getId());
+}
+
+function getDomainId(globalPadId) {
+ var parts = globalPadId.split("$");
+ if (parts.length < 2) {
+ return null;
+ } else {
+ return Number(parts[0]);
+ }
+}
+
+function makeValidLocalPadId(str) {
+ return str.replace(/[^a-zA-Z0-9\-]/g, '-');
+}
+
+function getProDisplayTitle(localPadId, title) {
+ if (title) {
+ return title;
+ }
+ if (stringutils.isNumeric(localPadId)) {
+ return ("Untitled "+localPadId);
+ } else {
+ return (localPadId);
+ }
+}
+
+
+function setOptsAndCookiePrefs(request) {
+ opts = {};
+ if (request.params.fullScreen) { // tokbox, embedding
+ opts.fullScreen = true;
+ }
+ if (request.params.tokbox) {
+ opts.tokbox = true;
+ }
+ if (request.params.sidebar) {
+ opts.sidebar = Boolean(Number(request.params.sidebar));
+ }
+ helpers.addClientVars({opts: opts});
+
+
+ var prefs = getPrefsCookieData();
+
+ var prefsToSet = {
+ fullWidth:false,
+ hideSidebar:false
+ };
+ if (prefs) {
+ prefsToSet.isFullWidth = !! prefs.fullWidth;
+ prefsToSet.hideSidebar = !! prefs.hideSidebar;
+ }
+ if (opts.fullScreen) {
+ prefsToSet.isFullWidth = true;
+ if (opts.tokbox) {
+ prefsToSet.hideSidebar = true;
+ }
+ }
+ if ('sidebar' in opts) {
+ prefsToSet.hideSidebar = ! opts.sidebar;
+ }
+ helpers.addClientVars({cookiePrefsToSet: prefsToSet});
+}
diff --git a/trunk/etherpad/src/etherpad/pad/revisions.js b/etherpad/src/etherpad/pad/revisions.js
index c7c84e8..c7c84e8 100644
--- a/trunk/etherpad/src/etherpad/pad/revisions.js
+++ b/etherpad/src/etherpad/pad/revisions.js
diff --git a/etherpad/src/etherpad/pne/pne_utils.js b/etherpad/src/etherpad/pne/pne_utils.js
new file mode 100644
index 0000000..073ad2a
--- /dev/null
+++ b/etherpad/src/etherpad/pne/pne_utils.js
@@ -0,0 +1,149 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("funhtml.*");
+import("stringutils.md5");
+import("sqlbase.persistent_vars");
+
+import("etherpad.licensing");
+
+jimport("java.lang.System.out.println");
+jimport("java.lang.System");
+
+
+function isPNE() {
+ if (appjet.cache.fakePNE || appjet.config['etherpad.fakePNE']) {
+ return true;
+ }
+ if (getVersionString()) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Versioning scheme: we basically just use the apache scheme of MAJOR.MINOR.PATCH:
+ *
+ * Versions are denoted using a standard triplet of integers: MAJOR.MINOR.PATCH. The
+ * basic intent is that MAJOR versions are incompatible, large-scale upgrades of the API.
+ * MINOR versions retain source and binary compatibility with older minor versions, and
+ * changes in the PATCH level are perfectly compatible, forwards and backwards.
+ */
+
+function getVersionString() {
+ return appjet.config['etherpad.pneVersion'];
+}
+
+function parseVersionString(x) {
+ var parts = x.split('.');
+ return {
+ major: Number(parts[0] || 0),
+ minor: Number(parts[1] || 0),
+ patch: Number(parts[2] || 0)
+ };
+}
+
+/* returns {major: int, minor: int, patch: int} */
+function getVersionNumbers() {
+ return parseVersionString(getVersionString());
+}
+
+function checkDbVersionUpgrade() {
+ var dbVersionString = persistent_vars.get("db_pne_version");
+ var runningVersionString = getVersionString();
+
+ if (!dbVersionString) {
+ println("Upgrading to Private Network Edition, version: "+runningVersionString);
+ return;
+ }
+
+ var dbVersion = parseVersionString(dbVersionString);
+ var runningVersion = getVersionNumbers();
+ var trueRegex = /\s*true\s*/i;
+ var force = trueRegex.test(appjet.config['etherpad.forceDbUpgrade']);
+
+ if (!force && (runningVersion.major != dbVersion.major)) {
+ println("Error: you are attempting to update an EtherPad["+dbVersionString+
+ "] database to version ["+runningVersionString+"]. This is not possible.");
+ println("Exiting...");
+ System.exit(1);
+ }
+ if (!force && (runningVersion.minor < dbVersion.minor)) {
+ println("Error: your etherpad database is at a newer version ["+dbVersionString+"] than"+
+ " the current running etherpad ["+runningVersionString+"]. Please upgrade to the "+
+ " latest version.");
+ println("Exiting...");
+ System.exit(1);
+ }
+ if (!force && (runningVersion.minor > (dbVersion.minor + 1))) {
+ println("\n\nWARNING: you are attempting to upgrade from version "+dbVersionString+" to version "+
+ runningVersionString+". It is recommended that you upgrade one minor version at a time."+
+ " (The \"minor\" version number is the second number separated by dots. For example,"+
+ " if you are running version 1.2, it is recommended that you upgrade to 1.3 and then 1.4 "+
+ " instead of going directly from 1.2 to 1.4.");
+ println("\n\nIf you really want to do this, you can force us to attempt the upgrade with "+
+ " the --etherpad.forceDbUpgrade=true flag.");
+ println("\n\nExiting...");
+ System.exit(1);
+ }
+ if (runningVersion.minor > dbVersion.minor) {
+ println("Upgrading database to version "+runningVersionString);
+ }
+}
+
+function saveDbVersion() {
+ var dbVersionString = persistent_vars.get("db_pne_version");
+ if (getVersionString() != dbVersionString) {
+ persistent_vars.put('db_pne_version', getVersionString());
+ println("Upgraded Private Network Edition version to ["+getVersionString()+"]");
+ }
+}
+
+// These are a list of some of the config vars documented in the PNE manual. They are here
+// temporarily, until we move them to the PNE config UI.
+
+var _eepneAllowedConfigVars = [
+ 'configFile',
+ 'etherpad.soffice',
+ 'etherpad.useMySQL',
+ 'etherpad.SQL_JDBC_DRIVER',
+ 'etherpad.SQL_JDBC_URL',
+ 'etherpad.SQL_PASSWORD',
+ 'etherpad.SQL_USERNAME',
+ 'etherpad.adminPass',
+ 'etherpad.licenseKey',
+ 'listen',
+ 'listenSecure',
+ 'smtpPass',
+ 'smtpServer',
+ 'smtpUser',
+ 'sslKeyPassword',
+ 'sslKeyStore'
+];
+
+function isServerLicensed() {
+ return true;
+}
+
+function enableTrackingAgain() {
+}
+
+function pneTrackerHtml() {
+ appjet.cache.noMorePneTracking = true;
+}
+
+
+
diff --git a/trunk/etherpad/src/etherpad/pro/domains.js b/etherpad/src/etherpad/pro/domains.js
index e56a408..e56a408 100644
--- a/trunk/etherpad/src/etherpad/pro/domains.js
+++ b/etherpad/src/etherpad/pro/domains.js
diff --git a/trunk/etherpad/src/etherpad/pro/pro_account_auto_signin.js b/etherpad/src/etherpad/pro/pro_account_auto_signin.js
index ebcd227..ebcd227 100644
--- a/trunk/etherpad/src/etherpad/pro/pro_account_auto_signin.js
+++ b/etherpad/src/etherpad/pro/pro_account_auto_signin.js
diff --git a/etherpad/src/etherpad/pro/pro_accounts.js b/etherpad/src/etherpad/pro/pro_accounts.js
new file mode 100644
index 0000000..98df6bb
--- /dev/null
+++ b/etherpad/src/etherpad/pro/pro_accounts.js
@@ -0,0 +1,592 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+// library for pro accounts
+
+import("funhtml.*");
+import("sqlbase.sqlobj");
+import("sqlbase.sqlcommon.inTransaction");
+import("email.sendEmail");
+import("cache_utils.syncedWithCache");
+import("stringutils.*");
+
+import("etherpad.globals.*");
+import("etherpad.sessions");
+import("etherpad.sessions.getSession");
+import("etherpad.utils.*");
+import("etherpad.pro.domains");
+import("etherpad.control.pro.account_control");
+import("etherpad.pro.pro_utils");
+import("etherpad.pro.pro_ldap_support.*");
+import("etherpad.pro.pro_quotas");
+import("etherpad.pad.padusers");
+import("etherpad.log");
+import("etherpad.billing.team_billing");
+
+import("process.*");
+import("fastJSON")
+
+jimport("org.mindrot.BCrypt");
+jimport("java.lang.System.out.println");
+
+function _dmesg(m) {
+ if (!isProduction()) {
+ println(m);
+ }
+}
+
+function _computePasswordHash(p) {
+ var pwh;
+ pwh = BCrypt.hashpw(p, BCrypt.gensalt(10));
+ return pwh;
+}
+
+function _withCache(name, fn) {
+ return syncedWithCache('pro_accounts.'+name, fn);
+}
+
+//----------------------------------------------------------------
+// validation
+//----------------------------------------------------------------
+
+function validateEmail(email) {
+ if (!email) { return "Email is required."; }
+ if (!isValidEmail(email)) { return "\""+email+"\" does not look like a valid email address."; }
+ return null;
+}
+
+function validateFullName(name) {
+ if (!name) { return "Full name is required."; }
+ if (name.length < 2) { return "Full name must be at least 2 characters."; }
+ return null;
+}
+
+function validatePassword(p) {
+ if (!p) { return "Password is required."; }
+ if (p.length < 6) { return "Passwords must be at least 6 characters."; }
+ return null;
+}
+
+function validateEmailDomainPair(email, domainId) {
+ // TODO: make sure the same email address cannot exist more than once within
+ // the same domainid.
+}
+
+/* if domainId is null, then use domainId of current request. */
+function createNewAccount(domainId, fullName, email, password, isAdmin, skipValidation) {
+ if (!domainId) {
+ domainId = domains.getRequestDomainId();
+ }
+ if (!skipValidation) {
+ skipValidation = false;
+ }
+ email = trim(email);
+ isAdmin = !!isAdmin; // convert to bool
+
+ // validation
+ if (!skipValidation) {
+ var e;
+ e = validateEmail(email); if (e) { throw Error(e); }
+ e = validateFullName(fullName); if (e) { throw Error(e); }
+ e = validatePassword(password); if (e) { throw Error(e); }
+ }
+
+ // xss normalization
+ fullName = toHTML(fullName);
+
+ // make sure account does not already exist on this domain.
+ var ret = inTransaction(function() {
+ var existingAccount = getAccountByEmail(email, domainId);
+ if (existingAccount) {
+ throw Error("There is already an account with that email address.");
+ }
+ // No existing account. Proceed.
+ var now = new Date();
+ var account = {
+ domainId: domainId,
+ fullName: fullName,
+ email: email,
+ passwordHash: _computePasswordHash(password),
+ createdDate: now,
+ isAdmin: isAdmin
+ };
+ return sqlobj.insert('pro_accounts', account);
+ });
+
+ _withCache('does-domain-admin-exist', function(cache) {
+ delete cache[domainId];
+ });
+
+ pro_quotas.updateAccountUsageCount(domainId);
+ updateCachedActiveCount(domainId);
+
+ if (ret) {
+ log.custom('pro-accounts',
+ {type: "account-created",
+ accountId: ret,
+ domainId: domainId,
+ name: fullName,
+ email: email,
+ admin: isAdmin});
+ }
+
+ return ret;
+}
+
+function _checkAccess(account) {
+ if (sessions.isAnEtherpadAdmin()) {
+ return;
+ }
+ if (account.domainId != domains.getRequestDomainId()) {
+ throw Error("access denied");
+ }
+}
+
+function setPassword(account, newPass) {
+ _checkAccess(account);
+ var passHash = _computePasswordHash(newPass);
+ sqlobj.update('pro_accounts', {id: account.id}, {passwordHash: passHash});
+ markDirtySessionAccount(account.id);
+}
+
+function setTempPassword(account, tempPass) {
+ _checkAccess(account);
+ var tempPassHash = _computePasswordHash(tempPass);
+ sqlobj.update('pro_accounts', {id: account.id}, {tempPassHash: tempPassHash});
+ markDirtySessionAccount(account.id);
+}
+
+function setEmail(account, newEmail) {
+ _checkAccess(account);
+ sqlobj.update('pro_accounts', {id: account.id}, {email: newEmail});
+ markDirtySessionAccount(account.id);
+}
+
+function setFullName(account, newName) {
+ _checkAccess(account);
+ sqlobj.update('pro_accounts', {id: account.id}, {fullName: newName});
+ markDirtySessionAccount(account.id);
+}
+
+function setIsAdmin(account, newVal) {
+ _checkAccess(account);
+ sqlobj.update('pro_accounts', {id: account.id}, {isAdmin: newVal});
+ markDirtySessionAccount(account.id);
+}
+
+function setDeleted(account) {
+ _checkAccess(account);
+ if (!isNumeric(account.id)) {
+ throw new Error("Invalid account id: "+account.id);
+ }
+ sqlobj.update('pro_accounts', {id: account.id}, {isDeleted: true});
+ markDirtySessionAccount(account.id);
+ pro_quotas.updateAccountUsageCount(account.domainId);
+ updateCachedActiveCount(account.domainId);
+
+ log.custom('pro-accounts',
+ {type: "account-deleted",
+ accountId: account.id,
+ domainId: account.domainId,
+ name: account.fullName,
+ email: account.email,
+ admin: account.isAdmin,
+ createdDate: account.createdDate.getTime()});
+}
+
+//----------------------------------------------------------------
+
+function doesAdminExist() {
+ var domainId = domains.getRequestDomainId();
+ return _withCache('does-domain-admin-exist', function(cache) {
+ if (cache[domainId] === undefined) {
+ _dmesg("cache miss for doesAdminExist (domainId="+domainId+")");
+ var admins = sqlobj.selectMulti('pro_accounts', {domainId: domainId, isAdmin: true}, {});
+ cache[domainId] = (admins.length > 0);
+ }
+ return cache[domainId]
+ });
+}
+
+function attemptSingleSignOn() {
+ if(!appjet.config['etherpad.SSOScript']) return null;
+
+ // pass request.cookies to a small user script
+ var file = appjet.config['etherpad.SSOScript'];
+
+ var cmd = exec(file);
+
+ // note that this will block until script execution returns
+ var result = cmd.write(fastJSON.stringify(request.cookies)).result();
+ var val = false;
+
+ // we try to parse the result as a JSON string, if not, return null.
+ try {
+ if(!!(val=fastJSON.parse(result))) {
+ return val;
+ }
+ } catch(e) {}
+ return null;
+}
+
+function getSessionProAccount() {
+ if (sessions.isAnEtherpadAdmin()) {
+ return getEtherpadAdminAccount();
+ }
+ var account = getSession().proAccount;
+ if (!account) {
+ return null;
+ }
+ if (account.isDeleted) {
+ delete getSession().proAccount;
+ return null;
+ }
+ return account;
+}
+
+function isAccountSignedIn() {
+ if (getSessionProAccount()) {
+ return true;
+ } else {
+ // if the user is not signed in, check to see if he should be signed in
+ // by calling an external script.
+ if(appjet.config['etherpad.SSOScript']) {
+ var ssoResult = attemptSingleSignOn();
+ if(ssoResult && ('email' in ssoResult)) {
+ var user = getAccountByEmail(ssoResult['email']);
+ if (!user) {
+ var email = ssoResult['email'];
+ var pass = ssoResult['password'] || "";
+ var name = ssoResult['fullname'] || "unnamed";
+ createNewAccount(null, name, email, pass, false, true);
+ user = getAccountByEmail(email, null);
+ }
+
+ signInSession(user);
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
+
+function isAdminSignedIn() {
+ return isAccountSignedIn() && getSessionProAccount().isAdmin;
+}
+
+function requireAccount(message) {
+ if ((request.path == "/ep/account/sign-in") ||
+ (request.path == "/ep/account/sign-out") ||
+ (request.path == "/ep/account/guest-sign-in") ||
+ (request.path == "/ep/account/guest-knock") ||
+ (request.path == "/ep/account/forgot-password")) {
+ return;
+ }
+
+ function checkSessionAccount() {
+ if (!getSessionProAccount()) {
+ if (message) {
+ account_control.setSigninNotice(message);
+ }
+ response.redirect('/ep/account/sign-in?cont='+encodeURIComponent(request.url));
+ }
+ }
+
+ checkSessionAccount();
+
+ if (getSessionProAccount().domainId != domains.getRequestDomainId()) {
+ // This should theoretically never happen unless the account is spoofing cookies / trying to
+ // hack the site.
+ pro_utils.renderFramedMessage("Permission denied.");
+ response.stop();
+ }
+ // update dirty session account if necessary
+ _withCache('dirty-session-accounts', function(cache) {
+ var uid = getSessionProAccount().id;
+ if (cache[uid]) {
+ reloadSessionAccountData(uid);
+ cache[uid] = false;
+ }
+ });
+
+ // need to check again in case dirty update caused account to be marked
+ // deleted.
+ checkSessionAccount();
+}
+
+function requireAdminAccount() {
+ requireAccount();
+ if (!getSessionProAccount().isAdmin) {
+ pro_utils.renderFramedMessage("Permission denied.");
+ response.stop();
+ }
+}
+
+/* returns undefined on success, error string otherise. */
+function authenticateSignIn(email, password) {
+ // blank passwords are not allowed to sign in.
+ if (password == "") return "Please provide a password.";
+
+ // If the email ends with our ldap suffix...
+ var isLdapSuffix = getLDAP() && getLDAP().isLDAPSuffix(email);
+
+ if(isLdapSuffix && !getLDAP()) {
+ return "LDAP not yet configured. Please contact your system admininstrator.";
+ }
+
+ // if there is an error in the LDAP configuration, return the error message
+ if(getLDAP() && getLDAP().error) {
+ return getLDAP().error + " Please contact your system administrator.";
+ }
+
+ if(isLdapSuffix && getLDAP()) {
+ var ldapuser = email.substr(0, email.indexOf(getLDAP().getLDAPSuffix()));
+ var ldapResult = getLDAP().login(ldapuser, password);
+
+ if (ldapResult.error == true) {
+ return ldapResult.message + "";
+ }
+
+ var accountRecord = getAccountByEmail(email, null);
+
+ // if this is the first time this user has logged in, create a user
+ // for him/her
+ if (!accountRecord) {
+ // password to store in database -- a blank password means the user
+ // cannot authenticate normally (e.g. must go through SSO or LDAP)
+ var ldapPass = "";
+
+ // create a new user (skipping validation of email/users/passes)
+ createNewAccount(null, ldapResult.getFullName(), email, ldapPass, false, true);
+ accountRecord = getAccountByEmail(email, null);
+ }
+
+ signInSession(accountRecord);
+ return undefined; // success
+ }
+
+ var accountRecord = getAccountByEmail(email, null);
+ if (!accountRecord) {
+ return "Account not found: "+email;
+ }
+
+ if (BCrypt.checkpw(password, accountRecord.passwordHash) != true) {
+ return "Incorrect password. Please try again.";
+ }
+
+ signInSession(accountRecord);
+
+ return undefined; // success
+}
+
+function signOut() {
+ delete getSession().proAccount;
+}
+
+function authenticateTempSignIn(uid, tempPass) {
+ var emsg = "That password reset link that is no longer valid.";
+
+ var account = getAccountById(uid);
+ if (!account) {
+ return emsg+" (Account not found.)";
+ }
+ if (account.domainId != domains.getRequestDomainId()) {
+ return emsg+" (Wrong domain.)";
+ }
+ if (!account.tempPassHash) {
+ return emsg+" (Expired.)";
+ }
+ if (BCrypt.checkpw(tempPass, account.tempPassHash) != true) {
+ return emsg+" (Bad temp pass.)";
+ }
+
+ signInSession(account);
+
+ getSession().accountMessage = "Please choose a new password";
+ getSession().changePass = true;
+
+ response.redirect("/ep/account/");
+}
+
+function signInSession(account) {
+ account.lastLoginDate = new Date();
+ account.tempPassHash = null;
+ sqlobj.updateSingle('pro_accounts', {id: account.id}, account);
+ reloadSessionAccountData(account.id);
+ padusers.notifySignIn();
+}
+
+function listAllDomainAccounts(domainId) {
+ if (domainId === undefined) {
+ domainId = domains.getRequestDomainId();
+ }
+ var records = sqlobj.selectMulti('pro_accounts',
+ {domainId: domainId, isDeleted: false}, {});
+ return records;
+}
+
+function listAllDomainAdmins(domainId) {
+ if (domainId === undefined) {
+ domainId = domains.getRequestDomainId();
+ }
+ var records = sqlobj.selectMulti('pro_accounts',
+ {domainId: domainId, isDeleted: false, isAdmin: true},
+ {});
+ return records;
+}
+
+function getActiveCount(domainId) {
+ var records = sqlobj.selectMulti('pro_accounts',
+ {domainId: domainId, isDeleted: false}, {});
+ return records.length;
+}
+
+/* getAccountById works for deleted and non-deleted accounts.
+ * The assumption is that cases whewre you look up an account by ID, you
+ * want the account info even if the account has been deleted. For
+ * example, when asking who created a pad.
+ */
+function getAccountById(accountId) {
+ var r = sqlobj.selectSingle('pro_accounts', {id: accountId});
+ if (r) {
+ return r;
+ } else {
+ return undefined;
+ }
+}
+
+/* getting an account by email only returns the account if it is
+ * not deleted. The assumption is that when you look up an account by
+ * email address, you only want active accounts. Furthermore, some
+ * deleted accounts may match a given email, but only one non-deleted
+ * account should ever match a single (email,domainId) pair.
+ */
+function getAccountByEmail(email, domainId) {
+ if (!domainId) {
+ domainId = domains.getRequestDomainId();
+ }
+ var r = sqlobj.selectSingle('pro_accounts', {domainId: domainId, email: email, isDeleted: false});
+ if (r) {
+ return r;
+ } else {
+ return undefined;
+ }
+}
+
+function getFullNameById(id) {
+ if (!id) {
+ return null;
+ }
+
+ return _withCache('names-by-id', function(cache) {
+ if (cache[id] === undefined) {
+ _dmesg("cache miss for getFullNameById (accountId="+id+")");
+ var r = getAccountById(id);
+ if (r) {
+ cache[id] = r.fullName;
+ } else {
+ cache[id] = false;
+ }
+ }
+ if (cache[id]) {
+ return cache[id];
+ } else {
+ return null;
+ }
+ });
+}
+
+function getTempSigninUrl(account, tempPass) {
+ if(appjet.config.listenSecurePort != 0 || appjet.config.useHttpsUrls)
+ return [
+ 'https://', httpsHost(pro_utils.getFullProHost()), '/ep/account/sign-in?',
+ 'uid=', account.id, '&tp=', tempPass
+ ].join('');
+ else
+ return [
+ 'http://', httpHost(pro_utils.getFullProHost()), '/ep/account/sign-in?',
+ 'uid=', account.id, '&tp=', tempPass
+ ].join('');
+}
+
+
+// TODO: this session account object storage / dirty cache is a
+// ridiculous hack. What we should really do is have a caching/access
+// layer for accounts similar to accessPad() and accessProPadMeta(), and
+// have that abstraction take care of caching and marking accounts as
+// dirty. This can be incorporated into getSessionProAccount(), and we
+// should actually refactor that into accessSessionProAccount().
+
+/* will force session data for this account to be updated next time that
+ * account requests a page. */
+function markDirtySessionAccount(uid) {
+ var domainId = domains.getRequestDomainId();
+
+ _withCache('dirty-session-accounts', function(cache) {
+ cache[uid] = true;
+ });
+ _withCache('names-by-id', function(cache) {
+ delete cache[uid];
+ });
+ _withCache('does-domain-admin-exist', function(cache) {
+ delete cache[domainId];
+ });
+}
+
+function reloadSessionAccountData(uid) {
+ if (!uid) {
+ uid = getSessionProAccount().id;
+ }
+ getSession().proAccount = getAccountById(uid);
+}
+
+function getAllAccountsWithEmail(email) {
+ var accountRecords = sqlobj.selectMulti('pro_accounts', {email: email, isDeleted: false}, {});
+ return accountRecords;
+}
+
+function getEtherpadAdminAccount() {
+ return {
+ id: 0,
+ isAdmin: true,
+ fullName: "ETHERPAD ADMIN",
+ email: "support@pad.spline.inf.fu-berlin.de",
+ domainId: domains.getRequestDomainId(),
+ isDeleted: false
+ };
+}
+
+function getCachedActiveCount(domainId) {
+ return _withCache('user-counts.'+domainId, function(c) {
+ if (!c.count) {
+ c.count = getActiveCount(domainId);
+ }
+ return c.count;
+ });
+}
+
+function updateCachedActiveCount(domainId) {
+ _withCache('user-counts.'+domainId, function(c) {
+ c.count = getActiveCount(domainId);
+ });
+}
+
+
+
+
+
+
diff --git a/trunk/etherpad/src/etherpad/pro/pro_config.js b/etherpad/src/etherpad/pro/pro_config.js
index d2d119f..d2d119f 100644
--- a/trunk/etherpad/src/etherpad/pro/pro_config.js
+++ b/etherpad/src/etherpad/pro/pro_config.js
diff --git a/etherpad/src/etherpad/pro/pro_ldap_support.js b/etherpad/src/etherpad/pro/pro_ldap_support.js
new file mode 100644
index 0000000..a657af1
--- /dev/null
+++ b/etherpad/src/etherpad/pro/pro_ldap_support.js
@@ -0,0 +1,217 @@
+import("fastJSON");
+
+jimport("net.appjet.common.util.BetterFile")
+
+jimport("java.lang.System.out.println");
+jimport("javax.naming.directory.DirContext");
+jimport("javax.naming.directory.SearchControls");
+jimport("javax.naming.directory.InitialDirContext");
+jimport("javax.naming.directory.SearchResult");
+jimport("javax.naming.NamingEnumeration");
+jimport("javax.naming.Context");
+jimport("java.util.Hashtable");
+
+function LDAP(config, errortext) {
+ if(!config)
+ this.error = errortext;
+ else
+ this.error = false;
+
+ this.ldapConfig = config;
+}
+
+function _dmesg(m) {
+ // if (!isProduction()) {
+ println(new String(m));
+ // }
+}
+
+/**
+ * an ldap result object
+ *
+ * will either have error = true, with a corrisponding error message,
+ * or will have error = false, with a corrisponding results object message
+ */
+function LDAPResult(msg, error, ldap) {
+ if(!ldap) ldap = getLDAP();
+ if(!error) error = false;
+ this.message = msg;
+ this.ldap = ldap;
+ this.error = error;
+}
+
+/**
+ * returns the full name attribute, as specified by the 'nameAttribute' config
+ * value.
+ */
+LDAPResult.prototype.getFullName = function() {
+ return this.message[this.ldap.ldapConfig['nameAttribute']][0];
+}
+
+/**
+ * Handy function for creating an LDAPResult object
+ */
+function ldapMessage(success, msg) {
+ var message = msg;
+ if(typeof(msg) == String) {
+ message = "LDAP " +
+ (success ? "Success" : "Error") + ": " + msg;
+ }
+
+ var result = new LDAPResult(message);
+ result.error = !success;
+ return result;
+}
+
+// returns the associated ldap results object, with an error flag of false
+var ldapSuccess =
+ function(msg) { return ldapMessage.apply(this, [true, msg]); };
+
+// returns a helpful error message
+var ldapError =
+ function(msg) { return ldapMessage.apply(this, [false, msg]); };
+
+/* build an LDAP Query (searches for an objectClass and uid) */
+LDAP.prototype.buildLDAPQuery = function(queryUser) {
+ if(queryUser && queryUser.match(/[\w_-]+/)) {
+ return "(&(objectClass=" +
+ this.ldapConfig['userClass'] + ")(uid=" +
+ queryUser + "))"
+ } else return null;
+}
+
+LDAP.prototype.login = function(queryUser, queryPass) {
+ var query = this.buildLDAPQuery(queryUser);
+ if(!query) { return ldapError("invalid LDAP username"); }
+
+ try {
+ var context = LDAP.authenticate(this.ldapConfig['url'],
+ this.ldapConfig['principal'],
+ this.ldapConfig['password']);
+
+ if(!context) {
+ return ldapError("could not authenticate principle user.");
+ }
+
+ var ctrl = new SearchControls();
+ ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ var results = context.search(this.ldapConfig['rootPath'], query, ctrl);
+
+ // if the user is found
+ if(results.hasMore()) {
+ var result = results.next();
+
+ // grab the absolute path to the user
+ var userResult = result.getNameInNamespace();
+ var authed = !!LDAP.authenticate(this.ldapConfig['url'],
+ userResult,
+ queryPass)
+
+ // return the LDAP info on the user upon success
+ return authed ?
+ ldapSuccess(LDAP.parse(result)) :
+ ldapError("Incorrect password. Please try again.");
+ } else {
+ return ldapError("User "+queryUser+" not found in LDAP.");
+ }
+
+ // if there are errors in the search, log them and return "unknown error"
+ } catch (e) {
+ _dmesg(e);
+ return ldapError(new String(e))
+ }
+};
+
+LDAP.prototype.isLDAPSuffix = function(email) {
+ return email.indexOf(this.ldapConfig['ldapSuffix']) ==
+ (email.length-this.ldapConfig['ldapSuffix'].length);
+}
+
+LDAP.prototype.getLDAPSuffix = function() {
+ return this.ldapConfig['ldapSuffix'];
+}
+
+/* static function returns a DirContext, or undefined upon authentation err */
+LDAP.authenticate = function(url, user, pass) {
+ var context = null;
+ try {
+ var env = new Hashtable();
+ env.put(Context.INITIAL_CONTEXT_FACTORY,
+ "com.sun.jndi.ldap.LdapCtxFactory");
+ env.put( Context.SECURITY_PRINCIPAL, user );
+ env.put( Context.SECURITY_CREDENTIALS, pass );
+ env.put(Context.PROVIDER_URL, url);
+ context = new InitialDirContext(env);
+ } catch (e) {
+ // bind failed.
+ }
+ return context;
+}
+
+/* turn a res */
+LDAP.parse = function(result) {
+ var resultobj = {};
+ try {
+ var attrs = result.getAttributes();
+ var ids = attrs.getIDs();
+
+ while(ids.hasMore()) {
+ var id = ids.next().toString();
+ resultobj[id] = [];
+
+ var attr = attrs.get(id);
+
+ for(var i=0; i<attr.size(); i++) {
+ resultobj[id].push(attr.get(i).toString());
+ }
+ }
+ } catch (e) {
+ // naming error
+ return {'keys': e}
+ }
+
+ return resultobj;
+}
+
+LDAP.ldapSingleton = false;
+
+// load in ldap configuration from a file...
+function readLdapConfig(file) {
+ var fileContents = BetterFile.getFileContents(file);
+
+ if(fileContents == null)
+ return "File not found.";
+
+ var configObject = fastJSON.parse(fileContents);
+ if(configObject['ldapSuffix']) {
+ LDAP.ldapSuffix = configObject['ldapSuffix'];
+ }
+ return configObject;
+}
+
+// Sample Configuration file:
+// {
+// "userClass" : "person",
+// "url" : "ldap://localhost:10389",
+// "principal" : "uid=admin,ou=system",
+// "password" : "secret",
+// "rootPath" : "ou=users,ou=system",
+// "nameAttribute": "displayname",
+// "ldapSuffix" : "@ldap"
+// }
+
+// appjet.config['etherpad.useLdapConfiguration'] = "/Users/kroo/Documents/Projects/active/AppJet/ldapConfig.json";
+function getLDAP() {
+ if (! LDAP.ldapSingleton &&
+ appjet.config['etherpad.useLdapConfiguration']) {
+ var config = readLdapConfig(appjet.config['etherpad.useLdapConfiguration']);
+ var error = null;
+ if(!config) {
+ config = null;
+ error = "Error reading LDAP configuration file."
+ }
+ LDAP.ldapSingleton = new LDAP(config, error);
+ }
+
+ return LDAP.ldapSingleton;
+} \ No newline at end of file
diff --git a/trunk/etherpad/src/etherpad/pro/pro_pad_db.js b/etherpad/src/etherpad/pro/pro_pad_db.js
index dbb412c..dbb412c 100644
--- a/trunk/etherpad/src/etherpad/pro/pro_pad_db.js
+++ b/etherpad/src/etherpad/pro/pro_pad_db.js
diff --git a/trunk/etherpad/src/etherpad/pro/pro_pad_editors.js b/etherpad/src/etherpad/pro/pro_pad_editors.js
index a90f05b..a90f05b 100644
--- a/trunk/etherpad/src/etherpad/pro/pro_pad_editors.js
+++ b/etherpad/src/etherpad/pro/pro_pad_editors.js
diff --git a/trunk/etherpad/src/etherpad/pro/pro_padlist.js b/etherpad/src/etherpad/pro/pro_padlist.js
index 73b179c..73b179c 100644
--- a/trunk/etherpad/src/etherpad/pro/pro_padlist.js
+++ b/etherpad/src/etherpad/pro/pro_padlist.js
diff --git a/trunk/etherpad/src/etherpad/pro/pro_padmeta.js b/etherpad/src/etherpad/pro/pro_padmeta.js
index 6f911b2..6f911b2 100644
--- a/trunk/etherpad/src/etherpad/pro/pro_padmeta.js
+++ b/etherpad/src/etherpad/pro/pro_padmeta.js
diff --git a/trunk/etherpad/src/etherpad/pro/pro_quotas.js b/etherpad/src/etherpad/pro/pro_quotas.js
index ed69e1c..ed69e1c 100644
--- a/trunk/etherpad/src/etherpad/pro/pro_quotas.js
+++ b/etherpad/src/etherpad/pro/pro_quotas.js
diff --git a/etherpad/src/etherpad/pro/pro_utils.js b/etherpad/src/etherpad/pro/pro_utils.js
new file mode 100644
index 0000000..d3098d7
--- /dev/null
+++ b/etherpad/src/etherpad/pro/pro_utils.js
@@ -0,0 +1,169 @@
+/**
+ * Copyright 2009 Google Inc.
+ * Copyright 2010 Pita, Peter Martischka <petermartischka@googlemail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("funhtml.*");
+import("stringutils.startsWith");
+
+import("etherpad.utils.*");
+import("etherpad.globals.*");
+import("etherpad.log");
+import("etherpad.pne.pne_utils");
+import("etherpad.pro.pro_accounts");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("etherpad.pro.domains");
+import("etherpad.pro.pro_quotas");
+import("etherpad.sessions");
+import("etherpad.sessions.getSession");
+
+import("etherpad.control.pro.pro_main_control");
+
+jimport("java.lang.System.out.println");
+
+function _stripComet(x) {
+ if (x.indexOf('.comet.') > 0) {
+ x = x.split('.comet.')[1];
+ }
+ return x;
+}
+
+function getProRequestSubdomain() {
+ var d = _stripComet(request.domain);
+ return d.split('.')[0];
+}
+
+function getRequestSuperdomain() {
+ var parts = request.domain.split('.');
+ while (parts.length > 0) {
+ var domain = parts.join('.');
+ if (domainEnabled(domain)) {
+ return domain;
+ }
+ parts.shift();
+ }
+ return false;
+}
+
+function isProDomainRequest() {
+ if(!isProAccountEnabled())
+ return false;
+ // the result of this function never changes within the same request.
+ var c = appjet.requestCache;
+ if (c.isProDomainRequest === undefined) {
+ c.isProDomainRequest = _computeIsProDomainRequest();
+ }
+ return c.isProDomainRequest;
+}
+
+function _computeIsProDomainRequest() {
+ if (pne_utils.isPNE()) {
+ return true;
+ }
+
+ var domain = _stripComet(request.domain);
+
+ if (domainEnabled(domain)) {
+ return false;
+ }
+
+ var requestSuperdomain = getRequestSuperdomain();
+
+ if (domainEnabled(requestSuperdomain)) {
+ // now see if this subdomain is actually in our database.
+ if (domains.getRequestDomainRecord()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+function preDispatchAccountCheck() {
+ // if account is not logged in, redirect to /ep/account/login
+ //
+ // if it's PNE and there is no admin account, allow them to create an admin
+ // account.
+
+ if (pro_main_control.isActivationAllowed()) {
+ return;
+ }
+
+ if (!pro_accounts.doesAdminExist()) {
+ if (request.path != '/ep/account/create-admin-account') {
+ // should only happen for eepnet installs
+ response.redirect('/ep/account/create-admin-account');
+ }
+ } else {
+ pro_accounts.requireAccount();
+ }
+
+ pro_quotas.perRequestBillingCheck();
+}
+
+function renderFramedMessage(m) {
+ renderFramedHtml(
+ DIV(
+ {style: "font-size: 2em; padding: 2em; margin: 4em; border: 1px solid #ccc; background: #e6e6e6;"},
+ m));
+}
+
+function getFullProDomain() {
+ // TODO: have a special config param for this? --etherpad.canonicalDomain
+ return request.domain;
+}
+
+// domain, including port if necessary
+function getFullProHost() {
+ var h = getFullProDomain();
+ var parts = request.host.split(':');
+ if (parts.length > 1) {
+ h += (':' + parts[1]);
+ }
+ return h;
+}
+
+function getFullSuperdomainHost() {
+ if (isProDomainRequest()) {
+ var h = getRequestSuperdomain()
+ var parts = request.host.split(':');
+ if (parts.length > 1) {
+ h += (':' + parts[1]);
+ }
+ return h;
+ } else {
+ return request.host;
+ }
+}
+
+function getEmailFromAddr() {
+ var fromDomain = 'pad.spline.inf.fu-berlin.de';
+ if (pne_utils.isPNE()) {
+ fromDomain = getFullProDomain();
+ }
+ return ('"EtherPad" <noreply@'+fromDomain+'>');
+}
+
+function renderGlobalProNotice() {
+ if (request.cache.globalProNotice) {
+ return DIV({className: 'global-pro-notice'},
+ request.cache.globalProNotice);
+ } else {
+ return "";
+ }
+}
+
diff --git a/trunk/etherpad/src/etherpad/quotas.js b/etherpad/src/etherpad/quotas.js
index 7e939ec..7e939ec 100644
--- a/trunk/etherpad/src/etherpad/quotas.js
+++ b/etherpad/src/etherpad/quotas.js
diff --git a/etherpad/src/etherpad/sessions.js b/etherpad/src/etherpad/sessions.js
new file mode 100644
index 0000000..f430ddd
--- /dev/null
+++ b/etherpad/src/etherpad/sessions.js
@@ -0,0 +1,203 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("sessions");
+import("stringutils.randomHash");
+import("funhtml.*");
+
+import("etherpad.log");
+import("etherpad.globals.*");
+import("etherpad.pro.pro_utils");
+import("etherpad.utils.*");
+import("cache_utils.syncedWithCache");
+
+jimport("java.lang.System.out.println");
+
+var _TRACKING_COOKIE_NAME = "ET";
+var _SESSION_COOKIE_NAME = "ES";
+
+function _updateInitialReferrer(data) {
+
+ if (data.initialReferer) {
+ return;
+ }
+
+ var ref = request.headers["Referer"];
+
+ if (!ref) {
+ return;
+ }
+ if (ref.indexOf('http://'+request.host) == 0) {
+ return;
+ }
+ if (ref.indexOf('https://'+request.host) == 0) {
+ return;
+ }
+
+ data.initialReferer = ref;
+ log.custom("referers", {referer: ref});
+}
+
+function _getScopedDomain(subDomain) {
+ var d = request.domain;
+ if (d.indexOf(".") == -1) {
+ // special case for "localhost". For some reason, firefox does not like cookie domains
+ // to be ".localhost".
+ return undefined;
+ }
+ if (subDomain) {
+ d = subDomain + "." + d;
+ }
+ return "." + d;
+}
+//--------------------------------------------------------------------------------
+
+// pass in subDomain to get the session data for a particular subdomain --
+// intended for debugging.
+function getSession(subDomain) {
+ var sessionData = sessions.getSession({
+ cookieName: _SESSION_COOKIE_NAME,
+ domain: _getScopedDomain(subDomain)
+ });
+ _updateInitialReferrer(sessionData);
+ return sessionData;
+}
+
+function getSessionId() {
+ return sessions.getSessionId(_SESSION_COOKIE_NAME, false, _getScopedDomain());
+}
+
+function _getGlobalSessionId() {
+ return (request.isDefined && request.cookies[_SESSION_COOKIE_NAME]) || null;
+}
+
+function isAnEtherpadAdmin() {
+ var sessionId = _getGlobalSessionId();
+ if (! sessionId) {
+ return false;
+ }
+
+ return syncedWithCache("isAnEtherpadAdmin", function(c) {
+ return !! c[sessionId];
+ });
+}
+
+function setIsAnEtherpadAdmin(v) {
+ var sessionId = _getGlobalSessionId();
+ if (! sessionId) {
+ return;
+ }
+
+ syncedWithCache("isAnEtherpadAdmin", function(c) {
+ if (v) {
+ c[sessionId] = true;
+ }
+ else {
+ delete c[sessionId];
+ }
+ });
+}
+
+//--------------------------------------------------------------------------------
+
+function setTrackingCookie() {
+ if (request.cookies[_TRACKING_COOKIE_NAME]) {
+ return;
+ }
+
+ var trackingVal = randomHash(16);
+ var expires = new Date(32503708800000); // year 3000
+
+ response.setCookie({
+ name: _TRACKING_COOKIE_NAME,
+ value: trackingVal,
+ path: "/",
+ domain: _getScopedDomain(),
+ expires: expires
+ });
+}
+
+function getTrackingId() {
+ // returns '-' if no tracking ID (caller can assume)
+ return (request.cookies[_TRACKING_COOKIE_NAME] || response.getCookie(_TRACKING_COOKIE_NAME) || '-');
+}
+
+//--------------------------------------------------------------------------------
+
+function preRequestCookieCheck() {
+ if (isStaticRequest()) {
+ return;
+ }
+
+ // If this function completes without redirecting, then it means
+ // there is a valid session cookie and tracking cookie.
+
+ if (request.cookies[_SESSION_COOKIE_NAME] &&
+ request.cookies[_TRACKING_COOKIE_NAME]) {
+
+ if (request.params.cookieShouldBeSet) {
+ response.redirect(qpath({cookieShouldBeSet: null}));
+ }
+ return;
+ }
+
+ // Only superdomains can set cookies.
+ var isSuperdomain = domainEnabled(request.domain);
+
+ if (isSuperdomain) {
+ // superdomain without cookies
+
+ getSession();
+ setTrackingCookie();
+
+ // check if we need to redirect back to a subdomain.
+ if ((request.path == "/") &&
+ (request.params.setCookie) &&
+ (request.params.contUrl)) {
+
+ var contUrl = request.params.contUrl;
+ if (contUrl.indexOf("?") == -1) {
+ contUrl += "?";
+ }
+ contUrl += "&cookieShouldBeSet=1";
+ response.redirect(contUrl);
+ }
+ } else {
+ var parts = request.domain.split(".");
+ if (parts.length < 3) {
+ // invalid superdomain
+ response.write("invalid superdomain");
+ response.stop();
+ }
+ // subdomain without cookies
+ if (request.params.cookieShouldBeSet) {
+ log.warn("Cookie failure!");
+ renderFramedHtml(DIV({style: "border: 1px solid #ccc; padding: 1em; width: 600px; margin: 1em auto; font-size: 1.4em;"},
+ P("Please enable cookies in your browser in order to access this site."),
+ BR(),
+ P(A({href: "/"}, "Continue"))));
+ response.stop();
+ } else {
+ var contUrl = request.url;
+ var p = request.host.split(':')[1];
+ p = (p ? (":"+p) : "");
+ response.redirect(request.scheme+"://"+pro_utils.getRequestSuperdomain()+p+
+ "/?setCookie=1&contUrl="+encodeURIComponent(contUrl));
+ }
+ }
+}
+
+
diff --git a/trunk/etherpad/src/etherpad/statistics/exceptions.js b/etherpad/src/etherpad/statistics/exceptions.js
index 723085d..723085d 100644
--- a/trunk/etherpad/src/etherpad/statistics/exceptions.js
+++ b/etherpad/src/etherpad/statistics/exceptions.js
diff --git a/trunk/etherpad/src/etherpad/statistics/statistics.js b/etherpad/src/etherpad/statistics/statistics.js
index 8174405..8174405 100644
--- a/trunk/etherpad/src/etherpad/statistics/statistics.js
+++ b/etherpad/src/etherpad/statistics/statistics.js
diff --git a/trunk/etherpad/src/etherpad/store/checkout.js b/etherpad/src/etherpad/store/checkout.js
index 2a4d7e7..2a4d7e7 100644
--- a/trunk/etherpad/src/etherpad/store/checkout.js
+++ b/etherpad/src/etherpad/store/checkout.js
diff --git a/trunk/etherpad/src/etherpad/store/eepnet_checkout.js b/etherpad/src/etherpad/store/eepnet_checkout.js
index 62137d3..62137d3 100644
--- a/trunk/etherpad/src/etherpad/store/eepnet_checkout.js
+++ b/etherpad/src/etherpad/store/eepnet_checkout.js
diff --git a/trunk/etherpad/src/etherpad/store/eepnet_trial.js b/etherpad/src/etherpad/store/eepnet_trial.js
index 570d351..570d351 100644
--- a/trunk/etherpad/src/etherpad/store/eepnet_trial.js
+++ b/etherpad/src/etherpad/store/eepnet_trial.js
diff --git a/trunk/etherpad/src/etherpad/testing/testutils.js b/etherpad/src/etherpad/testing/testutils.js
index eac7840..eac7840 100644
--- a/trunk/etherpad/src/etherpad/testing/testutils.js
+++ b/etherpad/src/etherpad/testing/testutils.js
diff --git a/trunk/etherpad/src/etherpad/testing/unit_tests/t0000_test.js b/etherpad/src/etherpad/testing/unit_tests/t0000_test.js
index 9e0e78b..9e0e78b 100644
--- a/trunk/etherpad/src/etherpad/testing/unit_tests/t0000_test.js
+++ b/etherpad/src/etherpad/testing/unit_tests/t0000_test.js
diff --git a/trunk/etherpad/src/etherpad/testing/unit_tests/t0001_sqlbase_transaction_rollback.js b/etherpad/src/etherpad/testing/unit_tests/t0001_sqlbase_transaction_rollback.js
index 96a74e4..96a74e4 100644
--- a/trunk/etherpad/src/etherpad/testing/unit_tests/t0001_sqlbase_transaction_rollback.js
+++ b/etherpad/src/etherpad/testing/unit_tests/t0001_sqlbase_transaction_rollback.js
diff --git a/trunk/etherpad/src/etherpad/testing/unit_tests/t0002_license_generation.js b/etherpad/src/etherpad/testing/unit_tests/t0002_license_generation.js
index 67c79d8..67c79d8 100644
--- a/trunk/etherpad/src/etherpad/testing/unit_tests/t0002_license_generation.js
+++ b/etherpad/src/etherpad/testing/unit_tests/t0002_license_generation.js
diff --git a/trunk/etherpad/src/etherpad/testing/unit_tests/t0003_persistent_vars.js b/etherpad/src/etherpad/testing/unit_tests/t0003_persistent_vars.js
index 0898fbe..0898fbe 100644
--- a/trunk/etherpad/src/etherpad/testing/unit_tests/t0003_persistent_vars.js
+++ b/etherpad/src/etherpad/testing/unit_tests/t0003_persistent_vars.js
diff --git a/trunk/etherpad/src/etherpad/testing/unit_tests/t0004_sqlobj.js b/etherpad/src/etherpad/testing/unit_tests/t0004_sqlobj.js
index 7f8c996..7f8c996 100644
--- a/trunk/etherpad/src/etherpad/testing/unit_tests/t0004_sqlobj.js
+++ b/etherpad/src/etherpad/testing/unit_tests/t0004_sqlobj.js
diff --git a/trunk/etherpad/src/etherpad/testing/unit_tests/t0005_easysync.js b/etherpad/src/etherpad/testing/unit_tests/t0005_easysync.js
index 9cd3f21..9cd3f21 100644
--- a/trunk/etherpad/src/etherpad/testing/unit_tests/t0005_easysync.js
+++ b/etherpad/src/etherpad/testing/unit_tests/t0005_easysync.js
diff --git a/trunk/etherpad/src/etherpad/usage_stats/usage_stats.js b/etherpad/src/etherpad/usage_stats/usage_stats.js
index 59074ed..59074ed 100644
--- a/trunk/etherpad/src/etherpad/usage_stats/usage_stats.js
+++ b/etherpad/src/etherpad/usage_stats/usage_stats.js
diff --git a/etherpad/src/etherpad/utils.js b/etherpad/src/etherpad/utils.js
new file mode 100644
index 0000000..65ebe1f
--- /dev/null
+++ b/etherpad/src/etherpad/utils.js
@@ -0,0 +1,464 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("exceptionutils");
+import("fileutils.{readFile,fileLastModified}");
+import("ejs.EJS");
+import("funhtml.*");
+import("stringutils");
+import("stringutils.startsWith");
+import("jsutils.*");
+
+import("etherpad.sessions");
+import("etherpad.sessions.getSession");
+import("etherpad.globals.*");
+import("etherpad.helpers");
+import("etherpad.collab.collab_server");
+import("etherpad.pad.model");
+import("etherpad.pro.domains");
+import("etherpad.pne.pne_utils");
+import("etherpad.pro.pro_utils");
+import("etherpad.pro.pro_config");
+import("etherpad.pro.pro_accounts");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("etherpad.log");
+import("etherpad.admin.plugins");
+
+jimport("java.lang.System.out.print");
+jimport("java.lang.System.out.println");
+
+jimport("java.io.File");
+
+//----------------------------------------------------------------
+// utilities
+//----------------------------------------------------------------
+
+// returns globally-unique padId
+function randomUniquePadId() {
+ var id = stringutils.randomString(10);
+ while (model.accessPadGlobal(id, function(p) { return p.exists(); }, "r")) {
+ id = stringutils.randomString(10);
+ }
+ return id;
+}
+
+//----------------------------------------------------------------
+// template rendering
+//----------------------------------------------------------------
+
+function findExistsingFile(files) {
+ for (var i = 0; i < files.length; i++) {
+ var f = new File('./src' + files[i]);
+ if (f.exists())
+ return files[i];
+ }
+}
+
+function findTemplate(filename, plugin) {
+ var files = [];
+
+ var pluginList = [plugin];
+ try {
+ if (plugin.forEach !== undefined)
+ pluginList = plugin;
+ else
+ pluginList = [plugin];
+ } catch (e) {}
+
+ pluginList.forEach(function (plugin) {
+ if (plugin != undefined) {
+ files.push('/plugins/' + plugin + '/templates/' + filename);
+ files.push('/themes/' + appjet.config.theme + '/plugins/' + plugin + '/templates/' + filename);
+ files.push('/themes/default/plugins/' + plugin + '/templates/' + filename);
+ }
+ });
+ files.push('/themes/' + appjet.config.theme + '/templates/' + filename);
+ files.push('/themes/default/templates/' + filename);
+
+ return findExistsingFile(files);
+}
+
+function Template(params, plugin) {
+ this._defines = {}
+ this._params = params;
+ this._params.template = this;
+ this._plugin = plugin;
+}
+
+Template.prototype.define = function(name, fn) {
+ this._defines[name] = fn;
+ return '';
+}
+
+Template.prototype.use = function (name, fn, arg) {
+ if (this._defines[name] != undefined)
+ return this._defines[name](arg);
+ else if (fn != undefined)
+ return fn(arg);
+ else
+ return '';
+}
+
+Template.prototype.inherit = function (template) {
+ return renderTemplateAsString(template, this._params, this._plugin);
+}
+
+function renderTemplateAsString(filename, data, plugin) {
+ data = data || {};
+ data.helpers = helpers; // global helpers
+ data.plugins = plugins; // Access callHook and the like...
+ if (data.template == undefined)
+ new Template(data, plugin);
+
+ var f = findTemplate(filename, plugin); //"/templates/"+filename;
+ if (! appjet.scopeCache.ejs) {
+ appjet.scopeCache.ejs = {};
+ }
+ var cacheObj = appjet.scopeCache.ejs[filename];
+ if (cacheObj === undefined || fileLastModified(f) > cacheObj.mtime) {
+ var templateText = readFile(f);
+ templateText += "<%: template.use('body', function () { return ''; }); %> ";
+ cacheObj = {};
+ cacheObj.tmpl = new EJS({text: templateText, name: filename});
+ cacheObj.mtime = fileLastModified(f);
+ appjet.scopeCache.ejs[filename] = cacheObj;
+ }
+ var html = cacheObj.tmpl.render(data);
+ return html;
+}
+
+function renderTemplate(filename, data, plugin) {
+ response.write(renderTemplateAsString(filename, data, plugin));
+ if (request.acceptsGzip) {
+ response.setGzip(true);
+ }
+}
+
+function renderHtml(bodyFileName, data, plugin) {
+ var bodyHtml = renderTemplateAsString(bodyFileName, data, plugin);
+ bodyHtml = plugins.callHookStr("renderPageBodyPre", {bodyFileName:bodyFileName, data:data, plugin:plugin}) +
+ bodyHtml +
+ plugins.callHookStr("renderPageBodyPost", {bodyFileName:bodyFileName, data:data, plugin:plugin});
+ response.write(renderTemplateAsString("html.ejs", {bodyHtml: bodyHtml}));
+ if (request.acceptsGzip) {
+ response.setGzip(true);
+ }
+}
+
+function renderFramedHtml(contentHtml, plugin) {
+ var getContentHtml;
+ if (typeof(contentHtml) == 'function') {
+ getContentHtml = contentHtml;
+ } else {
+ getContentHtml = function() { return contentHtml; }
+ }
+
+ var template = "framed/framedpage.ejs";
+ if (isProDomainRequest()) {
+ template = "framed/framedpage-pro.ejs";
+ }
+
+ renderHtml(template, {
+ renderHeader: renderMainHeader,
+ renderFooter: renderMainFooter,
+ getContentHtml: getContentHtml,
+ isProDomainRequest: isProDomainRequest(),
+ renderGlobalProNotice: pro_utils.renderGlobalProNotice
+ }, plugin);
+}
+
+function renderFramed(bodyFileName, data, plugin) {
+ function _getContentHtml() {
+ return renderTemplateAsString(bodyFileName, data, plugin);
+ }
+ renderFramedHtml(_getContentHtml);
+}
+
+function renderFramedError(error, plugin) {
+ var content = DIV({className: 'fpcontent'},
+ DIV({style: "padding: 2em 1em;"},
+ DIV({style: "padding: 1em; border: 1px solid #faa; background: #fdd;"},
+ B("Error: "), error)));
+ renderFramedHtml(content, plugin);
+}
+
+function renderNotice(bodyFileName, data, plugin) {
+ renderNoticeString(renderTemplateAsString(bodyFileName, data, plugin), plugin);
+}
+
+function renderNoticeString(contentHtml, plugin) {
+ renderFramed("notice.ejs", {content: contentHtml}, plugin);
+}
+
+function render404(noStop, plugin) {
+ response.reset();
+ response.setStatusCode(404);
+ renderFramedHtml(DIV({className: "fpcontent"},
+ DIV({style: "padding: 2em 1em;"},
+ DIV({style: "border: 1px solid #aaf; background: #def; padding: 1em; font-size: 150%;"},
+ "404 not found: "+request.path))), plugin);
+ if (! noStop) {
+ response.stop();
+ }
+}
+
+function render500(ex, plugin) {
+ response.reset();
+ response.setStatusCode(500);
+ var trace = null;
+ if (ex && (!isProduction())) {
+ trace = exceptionutils.getStackTracePlain(ex);
+ }
+ renderFramed("500_body.ejs", {trace: trace}, plugin);
+}
+
+function _renderEtherpadDotComHeader(data) {
+ if (!data) {
+ data = {selected: ''};
+ }
+ data.html = stringutils.html;
+ data.UL = UL;
+ data.LI = LI;
+ data.A = A;
+ data.isPNE = isPrivateNetworkEdition();
+ return renderTemplateAsString("framed/framedheader.ejs", data);
+}
+
+function _renderProHeader(data) {
+ if (!pro_accounts.isAccountSignedIn()) {
+ return '<div style="height: 140px;">&nbsp;</div>';
+ }
+
+ var r = domains.getRequestDomainRecord();
+ if (!data) { data = {}; }
+ data.navSelection = (data.navSelection || appjet.requestCache.proTopNavSelection || '');
+ data.proDomainOrgName = pro_config.getConfig().siteName;
+ data.isPNE = isPrivateNetworkEdition();
+ data.account = getSessionProAccount();
+ data.validLicense = pne_utils.isServerLicensed();
+ data.pneTrackerHtml = pne_utils.pneTrackerHtml();
+ data.isAnEtherpadAdmin = sessions.isAnEtherpadAdmin();
+ data.fullSuperdomain = pro_utils.getFullSuperdomainHost();
+ return renderTemplateAsString("framed/framedheader-pro.ejs", data);
+}
+
+function renderMainHeader(data) {
+ if (isProDomainRequest()) {
+ return _renderProHeader(data);
+ } else {
+ return _renderEtherpadDotComHeader(data);
+ }
+}
+
+function renderMainFooter() {
+ return renderTemplateAsString("framed/framedfooter.ejs", {
+ isProDomainRequest: isProDomainRequest()
+ });
+}
+
+//----------------------------------------------------------------
+// isValidEmail
+//----------------------------------------------------------------
+
+// TODO: make better and use the better version on the client in
+// various places as well (pad.js and etherpad.js)
+function isValidEmail(x) {
+ return (x &&
+ ((x.length > 0) &&
+ (x.match(/^[\w\.\_\+\-]+\@[\w\_\-]+\.[\w\_\-\.]+$/))));
+}
+
+//----------------------------------------------------------------
+
+function timeAgo(d, now) {
+ if (!now) { now = new Date(); }
+
+ function format(n, word) {
+ n = Math.round(n);
+ return ('' + n + ' ' + word + (n != 1 ? 's' : '') + ' ago');
+ }
+
+ d = (+now - (+d)) / 1000;
+ if (d < 60) { return format(d, 'second'); }
+ d /= 60;
+ if (d < 60) { return format(d, 'minute'); }
+ d /= 60;
+ if (d < 24) { return format(d, 'hour'); }
+ d /= 24;
+ return format(d, 'day');
+};
+
+
+//----------------------------------------------------------------
+// linking to a set of new CGI parameters
+//----------------------------------------------------------------
+function qpath(m) {
+ var q = {};
+ if (request.query) {
+ request.query.split('&').forEach(function(kv) {
+ if (kv) {
+ var parts = kv.split('=');
+ q[parts[0]] = parts[1];
+ }
+ });
+ }
+ eachProperty(m, function(k,v) {
+ q[k] = v;
+ });
+ var r = request.path + '?';
+ eachProperty(q, function(k,v) {
+ if (v !== undefined && v !== null) {
+ r += ('&' + k + '=' + v);
+ }
+ });
+ return r;
+}
+
+//----------------------------------------------------------------
+
+function ipToHostname(ip) {
+ var DNS = Packages.org.xbill.DNS;
+
+ if (!DNS.Address.isDottedQuad(ip)) {
+ return null
+ }
+
+ try {
+ var addr = DNS.Address.getByAddress(ip);
+ return DNS.Address.getHostName(addr);
+ } catch (ex) {
+ return null;
+ }
+}
+
+function extractGoogleQuery(ref) {
+ ref = String(ref);
+ ref = ref.toLowerCase();
+ if (!(ref.indexOf("google") >= 0)) {
+ return "";
+ }
+
+ ref = ref.split('?')[1];
+
+ var q = "";
+ ref.split("&").forEach(function(x) {
+ var parts = x.split("=");
+ if (parts[0] == "q") {
+ q = parts[1];
+ }
+ });
+
+ q = decodeURIComponent(q);
+ q = q.replace(/\+/g, " ");
+
+ return q;
+}
+
+function isTestEmail(x) {
+ return (x.indexOf("+appjetseleniumtest+") >= 0);
+}
+
+function isPrivateNetworkEdition() {
+ return pne_utils.isPNE();
+}
+
+function isProDomainRequest() {
+ return pro_utils.isProDomainRequest();
+}
+
+function hasOffice() {
+ return appjet.config["etherpad.soffice"] || appjet.config["etherpad.sofficeConversionServer"];
+}
+
+////////// console progress bar
+
+function startConsoleProgressBar(barWidth, updateIntervalSeconds) {
+ barWidth = barWidth || 40;
+ updateIntervalSeconds = ((typeof updateIntervalSeconds) == "number" ? updateIntervalSeconds : 1.0);
+
+ var unseenStatus = null;
+ var lastPrintTime = 0;
+ var column = 0;
+
+ function replaceLineWith(str) {
+ //print((new Array(column+1)).join('\b')+str);
+ print('\r'+str);
+ column = str.length;
+ }
+
+ var bar = {
+ update: function(frac, msg, force) {
+ var t = +new Date();
+ if ((!force) && ((t - lastPrintTime)/1000 < updateIntervalSeconds)) {
+ unseenStatus = {frac:frac, msg:msg};
+ }
+ else {
+ var pieces = [];
+ pieces.push(' ', (' '+Math.round(frac*100)).slice(-3), '%', ' [');
+ var barEndLoc = Math.max(0, Math.min(barWidth-1, Math.floor(frac*barWidth)));
+ for(var i=0;i<barWidth;i++) {
+ if (i < barEndLoc) pieces.push('=');
+ else if (i == barEndLoc) pieces.push('>');
+ else pieces.push(' ');
+ }
+ pieces.push('] ', msg || '');
+ replaceLineWith(pieces.join(''));
+
+ unseenStatus = null;
+ lastPrintTime = t;
+ }
+ },
+ finish: function() {
+ if (unseenStatus) {
+ bar.update(unseenStatus.frac, unseenStatus.msg, true);
+ }
+ println();
+ }
+ };
+
+ println();
+ bar.update(0, null, true);
+
+ return bar;
+}
+
+function isStaticRequest() {
+ return (startsWith(request.path, '/static/') ||
+ startsWith(request.path, '/favicon.ico') ||
+ startsWith(request.path, '/robots.txt'));
+}
+
+function httpsHost(h) {
+ h = h.split(":")[0]; // strip any existing port
+ if (appjet.config.listenSecurePort != "443" && !appjet.config.hidePorts) {
+ h = (h + ":" + appjet.config.listenSecurePort);
+ }
+ return h;
+}
+
+function httpHost(h) {
+ h = h.split(":")[0]; // strip any existing port
+ if (appjet.config.listenPort != "80" && !appjet.config.hidePorts) {
+ h = (h + ":" + appjet.config.listenPort);
+ }
+ return h;
+}
+
+function toJavaException(e) {
+ var exc = ((e instanceof java.lang.Throwable) && e) || e.rhinoException || e.javaException ||
+ new java.lang.Throwable(e.message+"/"+e.fileName+"/"+e.lineNumber);
+ return exc;
+}
diff --git a/etherpad/src/main.js b/etherpad/src/main.js
new file mode 100644
index 0000000..53671cf
--- /dev/null
+++ b/etherpad/src/main.js
@@ -0,0 +1,434 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("dispatch.{Dispatcher,PrefixMatcher,DirMatcher,forward}");
+import("exceptionutils");
+import("fastJSON");
+import("jsutils.*");
+import("sqlbase.sqlcommon");
+import("stringutils");
+import("sessions.{readLatestSessionsFromDisk,writeSessionsToDisk}");
+
+import("etherpad.billing.team_billing");
+import("etherpad.globals.*");
+import("etherpad.log.{logRequest,logException}");
+import("etherpad.log");
+import("etherpad.utils.*");
+import("etherpad.statistics.statistics");
+import("etherpad.sessions");
+import("etherpad.db_migrations.migration_runner");
+import("etherpad.importexport.importexport");
+import("etherpad.legacy_urls");
+
+import("etherpad.control.aboutcontrol");
+import("etherpad.control.admincontrol");
+import("etherpad.control.blogcontrol");
+import("etherpad.control.connection_diagnostics_control");
+import("etherpad.control.global_pro_account_control");
+import("etherpad.control.historycontrol");
+import("etherpad.control.loadtestcontrol");
+import("etherpad.control.maincontrol");
+import("etherpad.control.pad.pad_control");
+import("etherpad.control.pne_manual_control");
+import("etherpad.control.pne_tracker_control");
+import("etherpad.control.pro.admin.license_manager_control");
+import("etherpad.control.pro_beta_control");
+import("etherpad.control.pro.pro_main_control");
+import("etherpad.control.pro_signup_control");
+import("etherpad.control.scriptcontrol");
+import("etherpad.control.static_control");
+import("etherpad.control.store.storecontrol");
+import("etherpad.control.testcontrol");
+
+import("etherpad.pne.pne_utils");
+import("etherpad.pro.pro_pad_editors");
+import("etherpad.pro.pro_utils");
+import("etherpad.pro.pro_config");
+
+import("etherpad.collab.collabroom_server");
+import("etherpad.collab.collab_server");
+import("etherpad.collab.readonly_server");
+import("etherpad.collab.genimg");
+import("etherpad.pad.model");
+import("etherpad.pad.dbwriter");
+import("etherpad.pad.pad_migrations");
+import("etherpad.pad.noprowatcher");
+
+import("etherpad.admin.plugins");
+
+jimport("java.lang.System.out.println");
+
+serverhandlers.startupHandler = function() {
+ // Order matters.
+ checkSystemRequirements();
+
+ var sp = function(k) { return appjet.config['etherpad.SQL_'+k] || null; };
+ sqlcommon.init(sp('JDBC_DRIVER'), sp('JDBC_URL'), sp('USERNAME'), sp('PASSWORD'));
+
+ log.onStartup();
+ statistics.onStartup();
+ migration_runner.onStartup();
+ pad_migrations.onStartup();
+ model.onStartup();
+ collab_server.onStartup();
+ pad_control.onStartup();
+ dbwriter.onStartup();
+ blogcontrol.onStartup();
+ importexport.onStartup();
+ pro_pad_editors.onStartup();
+ noprowatcher.onStartup();
+ team_billing.onStartup();
+ collabroom_server.onStartup();
+ readLatestSessionsFromDisk();
+
+ plugins.callHook('serverStartup');
+};
+
+serverhandlers.resetHandler = function() {
+ statistics.onReset();
+}
+
+serverhandlers.shutdownHandler = function() {
+ plugins.callHook('serverShutdown');
+
+ appjet.cache.shutdownHandlerIsRunning = true;
+
+ log.callCatchingExceptions(writeSessionsToDisk);
+ log.callCatchingExceptions(dbwriter.onShutdown);
+ log.callCatchingExceptions(sqlcommon.onShutdown);
+ log.callCatchingExceptions(pro_pad_editors.onShutdown);
+};
+
+//----------------------------------------------------------------
+// request handling
+//----------------------------------------------------------------
+
+serverhandlers.requestHandler = function() {
+ checkRequestIsWellFormed();
+ sessions.preRequestCookieCheck();
+ checkHost();
+ checkHTTPS();
+ handlePath();
+};
+
+// In theory, this should never get called.
+// Exceptions that are thrown in frontend etherpad javascript should
+// always be caught and treated specially.
+// If serverhandlers.errorHandler gets called, then it's a bug in the frontend.
+serverhandlers.errorHandler = function(ex) {
+ logException(ex);
+ response.setStatusCode(500);
+ if (request.isDefined) {
+ render500(ex);
+ } else {
+ if (! isProduction()) {
+ response.write(exceptionutils.getStackTracePlain(ex));
+ } else {
+ response.write(ex.getMessage());
+ }
+ }
+};
+
+serverhandlers.postRequestHandler = function() {
+ logRequest();
+};
+
+//----------------------------------------------------------------
+// Scheduled tasks
+//----------------------------------------------------------------
+
+serverhandlers.tasks.writePad = function(globalPadId) {
+ dbwriter.taskWritePad(globalPadId);
+};
+serverhandlers.tasks.flushPad = function(globalPadId, reason) {
+ dbwriter.taskFlushPad(globalPadId, reason);
+};
+serverhandlers.tasks.checkForStalePads = function() {
+ dbwriter.taskCheckForStalePads();
+};
+serverhandlers.tasks.statisticsDailyUpdate = function() {
+ //statistics.dailyUpdate();
+};
+serverhandlers.tasks.doSlowFileConversion = function(from, to, bytes, cont) {
+ return importexport.doSlowFileConversion(from, to, bytes, cont);
+};
+serverhandlers.tasks.proPadmetaFlushEdits = function(domainId) {
+ pro_pad_editors.flushEditsNow(domainId);
+};
+serverhandlers.tasks.noProWatcherCheckPad = function(globalPadId) {
+ noprowatcher.checkPad(globalPadId);
+};
+serverhandlers.tasks.collabRoomDisconnectSocket = function(connectionId, socketId) {
+ collabroom_server.disconnectDefunctSocket(connectionId, socketId);
+};
+
+//----------------------------------------------------------------
+// cometHandler()
+//----------------------------------------------------------------
+
+serverhandlers.cometHandler = function(op, id, data) {
+ checkRequestIsWellFormed();
+ if (!data) {
+ // connect/disconnect message, notify all comet receivers
+ collabroom_server.handleComet(op, id, data);
+ return;
+ }
+
+ while (data[data.length-1] == '\u0000') {
+ data = data.substr(0, data.length-1);
+ }
+
+ var wrapper;
+ try {
+ wrapper = fastJSON.parse(data);
+ } catch (err) {
+ try {
+ // after removing \u0000 might have to add '}'
+ wrapper = fastJSON.parse(data+'}');
+ }
+ catch (err) {
+ log.custom("invalid-json", {data: data});
+ throw err;
+ }
+ }
+ if(wrapper.type == "COLLABROOM") {
+ collabroom_server.handleComet(op, id, wrapper.data);
+ } else {
+ //println("incorrectly wrapped data: " + wrapper['type']);
+ }
+};
+
+//----------------------------------------------------------------
+// sarsHandler()
+//----------------------------------------------------------------
+
+serverhandlers.sarsHandler = function(str) {
+ str = String(str);
+ println("sarsHandler: parsing JSON string (length="+str.length+")");
+ var message = fastJSON.parse(str);
+ println("dispatching SARS message of type "+message.type);
+ if (message.type == "migrateDiagnosticRecords") {
+ pad_control.recordMigratedDiagnosticInfo(message.records);
+ return 'OK';
+ }
+ return 'UNKNOWN_MESSAGE_TYPE';
+};
+
+//----------------------------------------------------------------
+// checkSystemRequirements()
+//----------------------------------------------------------------
+function checkSystemRequirements() {
+ var jv = Packages.java.lang.System.getProperty("java.version");
+ jv = +(String(jv).split(".").slice(0,2).join("."));
+ if (jv < 1.6) {
+ println("Error: EtherPad requires JVM 1.6 or greater.");
+ println("Your version of the JVM is: "+jv);
+ println("Aborting...");
+ Packages.java.lang.System.exit(1);
+ }
+}
+
+function checkRequestIsWellFormed() {
+ // We require the "host" field to be present.
+ // This should always be true, as long as the protocl is HTTP/1.1
+ // TODO: check (request.protocol != "HTTP/1.1")
+ if (request.isDefined && !request.host) {
+ response.setStatusCode(505);
+ response.setContentType('text/plain');
+ response.write('Protocol not supported. HTTP/1.1 required.');
+ response.stop();
+ }
+}
+
+//----------------------------------------------------------------
+// checkHost()
+//----------------------------------------------------------------
+function checkHost() {
+ var trueRegex = /\s*true\s*/i;
+ if (trueRegex.test(appjet.config['etherpad.skipHostnameCheck'])) {
+ return;
+ }
+
+ if (isPrivateNetworkEdition()) {
+ return;
+ }
+
+ // we require the domain to either be <superdomain> or a pro domain request.
+ if (domainEnabled(request.domain)) {
+ return;
+ }
+ if (pro_utils.isProDomainRequest()) {
+ return;
+ }
+
+ // redirect to main site
+ var newurl = "http://pad.spline.inf.fu-berlin.de/"+request.path;
+ if (request.query) { newurl += "?"+request.query; }
+ response.redirect(newurl);
+}
+
+//----------------------------------------------------------------
+// checkHTTPS()
+//----------------------------------------------------------------
+
+// Check for HTTPS
+function checkHTTPS() {
+ /* Open-source note: this function used to check the protocol and make
+ * sure that pages that needed to be secure went over HTTPS, and pages
+ * that didn't go over HTTP. However, when we open-sourced the code,
+ * we disabled HTTPS because we didn't want to ship the pad.spline.inf.fu-berlin.de
+ * private crypto keys. --aiba */
+ return;
+
+
+ if (stringutils.startsWith(request.path, "/static/")) { return; }
+
+ if (sessions.getSession().disableHttps || request.params.disableHttps) {
+ sessions.getSession().disableHttps = true;
+ println("setting session diableHttps");
+ return;
+ }
+
+ var _ports = {
+ http: appjet.config.listenPort,
+ https: appjet.config.listenSecurePort
+ };
+ var _defaultPorts = {
+ http: 80,
+ https: 443
+ };
+
+ // Require HTTPS for the following paths:
+ var _requiredHttpsPrefixes = [
+ '/ep/admin', // pro and main site
+ '/ep/account', // pro only
+ ];
+
+ var httpsRequired = false;
+ _requiredHttpsPrefixes.forEach(function(p) {
+ if (stringutils.startsWith(request.path, p)) {
+ httpsRequired = true;
+ }
+ });
+
+ if (isProDomainRequest() && pro_config.getConfig().alwaysHttps) {
+ httpsRequired = true;
+ }
+
+ if (httpsRequired && !request.isSSL) {
+ _redirectToScheme("https");
+ }
+ if (!httpsRequired && request.isSSL) {
+ _redirectToScheme("http");
+ }
+
+ function _redirectToScheme(scheme) {
+ var url = scheme + "://";
+ url += request.host.split(':')[0]; // server
+
+ if (_ports[scheme] != _defaultPorts[scheme]) {
+ url += ':'+_ports[scheme];
+ }
+
+ url += request.path;
+ if (request.query) {
+ url += "?"+request.query;
+ }
+ response.redirect(url);
+ }
+}
+
+//----------------------------------------------------------------
+// dispatching
+//----------------------------------------------------------------
+
+function handlePath() {
+ // Default. Can be overridden in case of static files.
+ response.neverCache();
+
+ plugins.registerClientHandlerJS();
+
+ // these paths are handled identically on all sites/subdomains.
+ var commonDispatcher = new Dispatcher();
+
+ commonDispatcher.addLocations(plugins.callHook('handlePath'));
+
+ commonDispatcher.addLocations([
+ ['/favicon.ico', forward(static_control)],
+ ['/robots.txt', forward(static_control)],
+ ['/crossdomain.xml', forward(static_control)],
+ [PrefixMatcher('/static/'), forward(static_control)],
+ [PrefixMatcher('/ep/genimg/'), genimg.renderPath],
+ [PrefixMatcher('/ep/pad/'), forward(pad_control)],
+ [PrefixMatcher('/ep/script/'), forward(scriptcontrol)],
+ [/^\/([^\/]+)$/, pad_control.render_pad],
+ [DirMatcher('/ep/unit-tests/'), forward(testcontrol)],
+ [DirMatcher('/ep/pne-manual/'), forward(pne_manual_control)],
+ ]);
+
+ // these paths are main site only
+ var mainsiteDispatcher = new Dispatcher();
+ mainsiteDispatcher.addLocations([
+ ['/', maincontrol.render_main],
+ [DirMatcher('/ep/beta-account/'), forward(pro_beta_control)],
+ [DirMatcher('/ep/pro-signup/'), forward(pro_signup_control)],
+ [DirMatcher('/ep/about/'), forward(aboutcontrol)],
+ [DirMatcher('/ep/admin/'), forward(admincontrol)],
+ [DirMatcher('/ep/blog/posts/'), blogcontrol.render_post],
+ [DirMatcher('/ep/blog/'), forward(blogcontrol)],
+ [DirMatcher('/ep/connection-diagnostics/'), forward(connection_diagnostics_control)],
+ [DirMatcher('/ep/loadtest/'), forward(loadtestcontrol)],
+ [DirMatcher('/ep/tpne/'), forward(pne_tracker_control)],
+ [DirMatcher('/ep/pro-account/'), forward(global_pro_account_control)],
+ [/^\/ep\/pad\/history\/(\w+)\/(.*)$/, historycontrol.render_history],
+ [PrefixMatcher('/ep/pad/slider/'), pad_control.render_slider],
+ [DirMatcher('/ep/store/'), forward(storecontrol)],
+ [PrefixMatcher('/ep/'), forward(maincontrol)]
+ ]);
+
+ // these paths are pro only
+ var proDispatcher = new Dispatcher();
+ proDispatcher.addLocations([
+ ['/', pro_main_control.render_main],
+ [PrefixMatcher('/ep/'), forward(pro_main_control)],
+ ]);
+
+ // dispatching logic: first try common, then dispatch to
+ // main site or pro.
+
+ if (commonDispatcher.dispatch()) {
+ return;
+ }
+
+ // Check if there is a pro domain associated with this request.
+ if (isProDomainRequest()) {
+ pro_utils.preDispatchAccountCheck();
+ if (proDispatcher.dispatch()) {
+ return;
+ }
+ } else {
+ if (mainsiteDispatcher.dispatch()) {
+ return;
+ }
+ }
+
+ if (!isProDomainRequest()) {
+ legacy_urls.checkPath();
+ }
+
+ render404();
+}
+
diff --git a/etherpad/src/plugins/fileUpload/controllers/fileUpload.js b/etherpad/src/plugins/fileUpload/controllers/fileUpload.js
new file mode 100644
index 0000000..d6585f1
--- /dev/null
+++ b/etherpad/src/plugins/fileUpload/controllers/fileUpload.js
@@ -0,0 +1,87 @@
+/**
+ * Copyright 2009 RedHog, Egil Möller <egil.moller@piratpartiet.se>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("faststatic");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+
+import("etherpad.utils.*");
+import("etherpad.collab.server_utils");
+import("etherpad.globals.*");
+import("etherpad.log");
+import("etherpad.pad.padusers");
+import("etherpad.pro.pro_utils");
+import("etherpad.helpers");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("sqlbase.sqlbase");
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+import("plugins.fileUpload.models");
+jimport("org.apache.commons.fileupload");
+
+function onRequest() {
+ var isPro = pro_utils.isProDomainRequest();
+ var userId = padusers.getUserId();
+
+
+ helpers.addClientVars({
+ userAgent: request.headers["User-Agent"],
+ debugEnabled: request.params.djs,
+ clientIp: request.clientAddr,
+ colorPalette: COLOR_PALETTE,
+ serverTimestamp: +(new Date),
+ isProPad: isPro,
+ userIsGuest: padusers.isGuest(userId),
+ userId: userId,
+ });
+
+ var isProUser = (isPro && ! padusers.isGuest(userId));
+
+ if (request.isPost) {
+ var uploads = [];
+ var itemFactory = new fileupload.disk.DiskFileItemFactory();
+ var handler = new fileupload.servlet.ServletFileUpload(itemFactory);
+ var items = handler.parseRequest(request.underlying).toArray();
+ for (var i = 0; i < items.length; i++){
+ if (!items[i].isFormField())
+ uploads.push('/up/' + models.storeFile(items[i]));
+ }
+
+ response.setContentType("text/json; charset=utf-8");
+ response.write(
+ renderTemplateAsString(
+ "fileUploaded.ejs",
+ {
+ uploads: uploads,
+ isPro: isPro,
+ isProAccountHolder: isProUser,
+ account: getSessionProAccount(), // may be falsy
+ },
+ 'fileUpload'));
+ if (request.acceptsGzip) {
+ response.setGzip(true);
+ }
+ } else {
+ renderHtml(
+ "fileUpload.ejs",
+ {
+ isPro: isPro,
+ isProAccountHolder: isProUser,
+ account: getSessionProAccount(), // may be falsy
+ },
+ 'fileUpload');
+ }
+ return true;
+}
diff --git a/etherpad/src/plugins/fileUpload/hooks.js b/etherpad/src/plugins/fileUpload/hooks.js
new file mode 100644
index 0000000..0948c17
--- /dev/null
+++ b/etherpad/src/plugins/fileUpload/hooks.js
@@ -0,0 +1,11 @@
+import("etherpad.log");
+import("faststatic");
+import("etherpad.utils.*");
+import("etherpad.globals.*");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+import("plugins.fileUpload.controllers.fileUpload");
+
+function handlePath() {
+ return [[PrefixMatcher('/ep/fileUpload/'), forward(fileUpload)],
+ [PrefixMatcher('/up/'), faststatic.directoryServer('/plugins/fileUpload/upload/', {cache: isProduction()})]];
+}
diff --git a/etherpad/src/plugins/fileUpload/main.js b/etherpad/src/plugins/fileUpload/main.js
new file mode 100644
index 0000000..71bd819
--- /dev/null
+++ b/etherpad/src/plugins/fileUpload/main.js
@@ -0,0 +1,19 @@
+import("etherpad.log");
+import("plugins.fileUpload.hooks");
+
+function init() {
+ this.hooks = ['handlePath'];
+ this.description = 'File upload manager adds a button to pads to upload a file. A URL to the uploaded file is then inserted into the pad.';
+ this.handlePath = hooks.handlePath;
+ this.install = install;
+ this.uninstall = uninstall;
+}
+
+function install() {
+ log.info("Installing fileUpload");
+}
+
+function uninstall() {
+ log.info("Uninstalling fileUpload");
+}
+
diff --git a/etherpad/src/plugins/fileUpload/models.js b/etherpad/src/plugins/fileUpload/models.js
new file mode 100644
index 0000000..f8fb563
--- /dev/null
+++ b/etherpad/src/plugins/fileUpload/models.js
@@ -0,0 +1,95 @@
+/**
+ * Copyright 2009 RedHog, Egil Möller <egil.moller@piratpartiet.se>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("etherpad.utils.*");
+import("etherpad.globals.*");
+import("etherpad.log");
+import("sqlbase.sqlbase");
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+
+jimport("java.io.File",
+ "java.io.DataInputStream",
+ "java.io.FileInputStream",
+ "java.lang.Byte",
+ "java.io.FileReader",
+ "java.io.BufferedReader",
+ "java.security.MessageDigest",
+ "java.lang.Runtime");
+
+
+/* Normal base64 encoding, except we don't care about adding newlines */
+function base64Encode(stringArray) {
+ base64code = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/";
+
+ /* Pad array to nearest three byte multiple */
+ var padding = (3 - (stringArray.length % 3)) % 3;
+ var padded = java.lang.reflect.Array.newInstance(Byte.TYPE, stringArray.length + padding);
+ java.lang.System.arraycopy(stringArray, 0, padded, 0, stringArray.length);
+ stringArray = padded;
+
+ var encoded = "";
+ for (var i = 0; i < stringArray.length; i += 3) {
+ var j = (((stringArray[i] & 0xff) << 16) +
+ ((stringArray[i + 1] & 0xff) << 8) +
+ (stringArray[i + 2] & 0xff));
+ encoded = (encoded +
+ base64code.charAt((j >> 18) & 0x3f) +
+ base64code.charAt((j >> 12) & 0x3f) +
+ base64code.charAt((j >> 6) & 0x3f) +
+ base64code.charAt(j & 0x3f));
+ }
+ /* replace padding with "=" */
+ return encoded.substring(0, encoded.length - padding) + "==".substring(0, padding);
+}
+
+
+function makeSymlink(destination, source) {
+ return Runtime.getRuntime().exec(['ln', '-s', source.getPath(), destination.getPath()]).waitFor();
+}
+
+
+/* Reads a File and updates a digest with its content */
+function updateDigestFromFile(digest, file) {
+ var handle = new java.io.FileInputStream(file);
+
+ var bytes = java.lang.reflect.Array.newInstance(Byte.TYPE, 512);
+ var nbytes = 0;
+
+ while ((nbytes = handle.read(bytes, 0, 512)) != -1)
+ digest.update(bytes, 0, nbytes);
+
+ handle.close();
+}
+
+
+/* Stores a org.apache.commons.fileupload.disk.DiskFileItem permanently and returns a filename. */
+function storeFile(fileItem) {
+ var nameParts = fileItem.name.split('.');
+ var extension = nameParts[nameParts.length-1];
+
+ var digest = MessageDigest.getInstance("SHA1");
+ updateDigestFromFile(digest, fileItem.getStoreLocation());
+ var checksum = base64Encode(digest.digest());
+
+ fileItem.write(File("src/plugins/fileUpload/upload/" + checksum));
+
+ makeSymlink(
+ File("src/plugins/fileUpload/upload/" + checksum + '.' + extension),
+ File(checksum));
+
+ return checksum + '.' + extension;
+}
diff --git a/etherpad/src/plugins/fileUpload/templates/fileUpload.ejs b/etherpad/src/plugins/fileUpload/templates/fileUpload.ejs
new file mode 100644
index 0000000..57f33e6
--- /dev/null
+++ b/etherpad/src/plugins/fileUpload/templates/fileUpload.ejs
@@ -0,0 +1,32 @@
+<% /* Copyright 2009 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %>
+<%
+ helpers.setHtmlTitle("Test plugin");
+ helpers.setBodyId("padbody");
+ helpers.addBodyClass("limwidth nonpropad nonprouser");
+ helpers.includeCss("pad2_ejs.css");
+ helpers.setRobotsPolicy({index: false, follow: false})
+ helpers.includeJQuery();
+ helpers.includeCometJs();
+ helpers.includeJs("json2.js");
+ helpers.addToHead('\n<style type="text/css" title="dynamicsyntax"></style>\n');
+%>
+
+<div id="padpage">
+ <form method="POST" enctype="multipart/form-data">
+ <input type="file" name="fileParam">
+ <button type="submit">Submit</button>
+ </form>
+
+</div>
diff --git a/etherpad/src/plugins/fileUpload/templates/fileUploaded.ejs b/etherpad/src/plugins/fileUpload/templates/fileUploaded.ejs
new file mode 100644
index 0000000..5a62f7e
--- /dev/null
+++ b/etherpad/src/plugins/fileUpload/templates/fileUploaded.ejs
@@ -0,0 +1,5 @@
+[
+<% for (var i = 0; i < uploads.length; i++) { %>
+ '<%= uploads[i] %>',
+<% } %>
+]
diff --git a/etherpad/src/plugins/kafoo/main.js b/etherpad/src/plugins/kafoo/main.js
new file mode 100644
index 0000000..f645576
--- /dev/null
+++ b/etherpad/src/plugins/kafoo/main.js
@@ -0,0 +1,16 @@
+import("etherpad.log");
+
+function init() {
+ this.hooks = [];
+ this.description = 'KaBar plugin';
+ this.install = install;
+ this.uninstall = uninstall;
+}
+
+function install() {
+ log.info("Installing testplugin");
+}
+
+function uninstall() {
+ log.info("Uninstalling testplugin");
+}
diff --git a/etherpad/src/plugins/testplugin/controllers/testplugin.js b/etherpad/src/plugins/testplugin/controllers/testplugin.js
new file mode 100644
index 0000000..da74ade
--- /dev/null
+++ b/etherpad/src/plugins/testplugin/controllers/testplugin.js
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2009 RedHog, Egil Möller <egil.moller@piratpartiet.se>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("faststatic");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+
+import("etherpad.utils.*");
+import("etherpad.collab.server_utils");
+import("etherpad.globals.*");
+import("etherpad.log");
+import("etherpad.pad.padusers");
+import("etherpad.pro.pro_utils");
+import("etherpad.helpers");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("sqlbase.sqlbase");
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+
+function onRequest() {
+ var isPro = pro_utils.isProDomainRequest();
+ var userId = padusers.getUserId();
+
+ helpers.addClientVars({
+ userAgent: request.headers["User-Agent"],
+ debugEnabled: request.params.djs,
+ clientIp: request.clientAddr,
+ colorPalette: COLOR_PALETTE,
+ serverTimestamp: +(new Date),
+ isProPad: isPro,
+ userIsGuest: padusers.isGuest(userId),
+ userId: userId,
+ });
+
+ var isProUser = (isPro && ! padusers.isGuest(userId));
+
+ renderHtml(
+ "testplugin.ejs",
+ {
+ isPro: isPro,
+ isProAccountHolder: isProUser,
+ account: getSessionProAccount(), // may be falsy
+ },
+ 'testplugin');
+ return true;
+}
diff --git a/etherpad/src/plugins/testplugin/hooks.js b/etherpad/src/plugins/testplugin/hooks.js
new file mode 100644
index 0000000..493a2c2
--- /dev/null
+++ b/etherpad/src/plugins/testplugin/hooks.js
@@ -0,0 +1,15 @@
+import("etherpad.log");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+import("plugins.testplugin.controllers.testplugin");
+
+function serverStartup() {
+ log.info("Server startup for testplugin");
+}
+
+function serverShutdown() {
+ log.info("Server shutdown for testplugin");
+}
+
+function handlePath() {
+ return [[PrefixMatcher('/ep/testplugin/'), forward(testplugin)]];
+}
diff --git a/etherpad/src/plugins/testplugin/main.js b/etherpad/src/plugins/testplugin/main.js
new file mode 100644
index 0000000..49b447c
--- /dev/null
+++ b/etherpad/src/plugins/testplugin/main.js
@@ -0,0 +1,23 @@
+import("etherpad.log");
+import("plugins.testplugin.hooks");
+import("plugins.testplugin.static.js.main");
+
+function init() {
+ this.hooks = ['serverStartup', 'serverShutdown', 'handlePath'];
+ this.client = new main.init();
+ this.description = 'Test Plugin';
+ this.serverStartup = hooks.serverStartup;
+ this.serverShutdown = hooks.serverShutdown;
+ this.handlePath = hooks.handlePath;
+ this.install = install;
+ this.uninstall = uninstall;
+}
+
+function install() {
+ log.info("Installing testplugin");
+}
+
+function uninstall() {
+ log.info("Uninstalling testplugin");
+}
+
diff --git a/etherpad/src/plugins/testplugin/static/js/main.js b/etherpad/src/plugins/testplugin/static/js/main.js
new file mode 100644
index 0000000..f08b8f7
--- /dev/null
+++ b/etherpad/src/plugins/testplugin/static/js/main.js
@@ -0,0 +1,11 @@
+function init() {
+ this.hooks = ['kafoo'];
+ this.kafoo = kafoo;
+}
+
+function kafoo() {
+ alert('hej');
+}
+
+/* used on the client side only */
+testplugin = new init();
diff --git a/etherpad/src/plugins/testplugin/static/js/test.js b/etherpad/src/plugins/testplugin/static/js/test.js
new file mode 100644
index 0000000..83fb40c
--- /dev/null
+++ b/etherpad/src/plugins/testplugin/static/js/test.js
@@ -0,0 +1 @@
+plugins.callHook("kafoo");
diff --git a/etherpad/src/plugins/testplugin/templates/page.ejs b/etherpad/src/plugins/testplugin/templates/page.ejs
new file mode 100644
index 0000000..71633c0
--- /dev/null
+++ b/etherpad/src/plugins/testplugin/templates/page.ejs
@@ -0,0 +1,23 @@
+<% /* Copyright 2009 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %>
+
+<% template.define('body', function() { var ejs_data=''; %>
+ <div id="blabla">
+ <h1>Page header</h1>
+ <%: template.use('content', function() { var ejs_data=''; %>
+ Original content
+ <% return ejs_data; }); %>
+ <div>footer</div>
+ </div>
+<% return ejs_data; }); %>
diff --git a/etherpad/src/plugins/testplugin/templates/testplugin.ejs b/etherpad/src/plugins/testplugin/templates/testplugin.ejs
new file mode 100644
index 0000000..69c4453
--- /dev/null
+++ b/etherpad/src/plugins/testplugin/templates/testplugin.ejs
@@ -0,0 +1,33 @@
+<% /* Copyright 2009 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %>
+<%
+ helpers.setHtmlTitle("Test plugin");
+ helpers.setBodyId("padbody");
+ helpers.addBodyClass("limwidth nonpropad nonprouser");
+ helpers.includeCss("pad2_ejs.css");
+ helpers.setRobotsPolicy({index: false, follow: false})
+ helpers.includeJQuery();
+ helpers.includeCometJs();
+ helpers.includeJs("json2.js");
+ helpers.includeJs("plugins/testplugin/test.js");
+ helpers.addToHead('\n<style type="text/css" title="dynamicsyntax"></style>\n');
+%>
+
+<% template.inherit('page.ejs') %>
+
+<% template.define('content', function() { var ejs_data=''; %>
+ <div id="padpage">
+ Welcome to the test plugin
+ </div>
+<% return ejs_data; }); %>
diff --git a/etherpad/src/plugins/twitterStyleTags/controllers/tagBrowser.js b/etherpad/src/plugins/twitterStyleTags/controllers/tagBrowser.js
new file mode 100644
index 0000000..5335ab7
--- /dev/null
+++ b/etherpad/src/plugins/twitterStyleTags/controllers/tagBrowser.js
@@ -0,0 +1,103 @@
+/**
+ * Copyright 2009 RedHog, Egil Möller <egil.moller@piratpartiet.se>
+ * Copyright 2010 Pita, Peter Martischka <petermartischka@googlemail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("plugins.twitterStyleTags.models.tagQuery");
+
+import("faststatic");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+
+import("etherpad.utils.*");
+import("etherpad.collab.server_utils");
+import("etherpad.globals.*");
+import("etherpad.log");
+import("etherpad.pad.padusers");
+import("etherpad.pro.pro_utils");
+import("etherpad.helpers");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("sqlbase.sqlbase");
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+import("etherpad.pad.padutils");
+
+
+function onRequest() {
+ var tags = tagQuery.queryToTags(request.params.query);
+
+ /* Create the pad filter sql */
+ var querySql = tagQuery.getQueryToSql(tags.tags.concat(['public']), tags.antiTags);
+
+ /* Use the pad filter sql to figure out which tags to show in the tag browser this time. */
+ var queryNewTagsSql = tagQuery.newTagsSql(querySql);
+ var newTags = sqlobj.executeRaw(queryNewTagsSql.sql, queryNewTagsSql.params);
+
+ padSql = tagQuery.padInfoSql(querySql, 10);
+ var matchingPads = sqlobj.executeRaw(padSql.sql, padSql.params);
+
+ for (i = 0; i < matchingPads.length; i++) {
+ matchingPads[i].TAGS = matchingPads[i].TAGS.split('#');
+ }
+
+ var isPro = pro_utils.isProDomainRequest();
+ var userId = padusers.getUserId();
+
+ helpers.addClientVars({
+ userAgent: request.headers["User-Agent"],
+ debugEnabled: request.params.djs,
+ clientIp: request.clientAddr,
+ colorPalette: COLOR_PALETTE,
+ serverTimestamp: +(new Date),
+ isProPad: isPro,
+ userIsGuest: padusers.isGuest(userId),
+ userId: userId,
+ });
+
+ var isProUser = (isPro && ! padusers.isGuest(userId));
+
+ padutils.setOptsAndCookiePrefs(request);
+ var prefs = helpers.getClientVar('cookiePrefsToSet');
+ var bodyClass = (prefs.isFullWidth ? "fullwidth" : "limwidth")
+
+ var info = {
+ prefs: prefs,
+ config: appjet.config,
+ tagQuery: tagQuery,
+ padIdToReadonly: server_utils.padIdToReadonly,
+ tags: tags.tags,
+ antiTags: tags.antiTags,
+ newTags: newTags,
+ matchingPads: matchingPads,
+ bodyClass: 'nonpropad',
+ isPro: isPro,
+ isProAccountHolder: isProUser,
+ account: getSessionProAccount(), // may be falsy
+ };
+
+ var format = "html";
+ if (request.params.format != undefined)
+ format = request.params.format;
+
+ if (format == "html")
+ renderHtml("tagBrowser.ejs", info, 'twitterStyleTags');
+ else if (format == "rss") {
+ response.setContentType("application/xml; charset=utf-8");
+ response.write(renderTemplateAsString("tagRss.ejs", info, 'twitterStyleTags'));
+ if (request.acceptsGzip) {
+ response.setGzip(true);
+ }
+ }
+ return true;
+}
diff --git a/etherpad/src/plugins/twitterStyleTags/hooks.js b/etherpad/src/plugins/twitterStyleTags/hooks.js
new file mode 100644
index 0000000..1072579
--- /dev/null
+++ b/etherpad/src/plugins/twitterStyleTags/hooks.js
@@ -0,0 +1,56 @@
+import("etherpad.log");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+import("plugins.twitterStyleTags.controllers.tagBrowser");
+import("sqlbase.sqlobj");
+
+function handlePath() {
+ return [[PrefixMatcher('/ep/tag/'), forward(tagBrowser)]];
+}
+
+function padModelWriteToDB(args) {
+ /* Update tags for the pad */
+
+ var new_tags = args.pad.text().match(new RegExp("#[^,#=!\\s][^,#=!\\s]*", "g"));
+ if (new_tags == null) new_tags = new Array();
+ for (i = 0; i < new_tags.length; i++)
+ new_tags[i] = new_tags[i].substring(1);
+ var new_tags_str = new_tags.join('#')
+
+ var old_tags_row = sqlobj.selectSingle("PAD_TAG_CACHE", { PAD_ID: args.padId });
+ var old_tags_str;
+ if (old_tags_row !== null)
+ old_tags_str = old_tags_row['TAGS'];
+ else
+ old_tags_str = '';
+
+ // var old_tags = old_tags_str != '' ? old_tags_str.split('#') : new Array();
+
+ if (new_tags_str != old_tags_str) {
+ // log.info({message: 'Updating tags', new_tags:new_tags, old_tags:old_tags});
+
+ if (old_tags_row)
+ sqlobj.update("PAD_TAG_CACHE", {PAD_ID: args.padId }, {TAGS: new_tags.join('#')});
+ else
+ sqlobj.insert("PAD_TAG_CACHE", {PAD_ID: args.padId, TAGS: new_tags.join('#')});
+
+ sqlobj.deleteRows("PAD_TAG", {PAD_ID: args.padId});
+
+ for (i = 0; i < new_tags.length; i++) {
+ var tag_row = sqlobj.selectSingle("TAG", { NAME: new_tags[i] });
+ if (tag_row === null) {
+ sqlobj.insert("TAG", {NAME: new_tags[i]});
+ tag_row = sqlobj.selectSingle("TAG", { NAME: new_tags[i] });
+ }
+ sqlobj.insert("PAD_TAG", {PAD_ID: args.padId, TAG_ID: tag_row['ID']});
+ }
+ }
+}
+
+function docbarItemsAll() {
+ return ["<td class='docbarbutton'><a href='/ep/tag/'>Home</a></td>"];
+}
+
+function docbarItemsTagBrowser() {
+ return ["<td class='docbarbutton'><a href='/ep/tag/'>Pads</a></td>"];
+}
+
diff --git a/etherpad/src/plugins/twitterStyleTags/main.js b/etherpad/src/plugins/twitterStyleTags/main.js
new file mode 100644
index 0000000..d64abff
--- /dev/null
+++ b/etherpad/src/plugins/twitterStyleTags/main.js
@@ -0,0 +1,45 @@
+import("etherpad.log");
+import("plugins.twitterStyleTags.hooks");
+import("plugins.twitterStyleTags.static.js.main");
+import("sqlbase.sqlobj");
+import("sqlbase.sqlcommon");
+
+function init() {
+ this.hooks = ['handlePath', 'aceGetFilterStack', 'aceCreateDomLine', 'padModelWriteToDB', 'docbarItemsAll', 'docbarItemsTagBrowser'];
+ this.client = new main.init();
+ this.description = 'Twitter-style tags allows the user to tag pads by writing #tagname anywhere in the pad text. Tags are automatically linked to searches for that tag in other pads. This plugin also provides an alternative home-page for Etherpad with a display of the last changed public pads as well as that information available as an RSS stream.';
+ this.handlePath = hooks.handlePath;
+ this.aceGetFilterStack = main.aceGetFilterStack;
+ this.aceCreateDomLine = main.aceCreateDomLine;
+ this.padModelWriteToDB = hooks.padModelWriteToDB;
+ this.docbarItemsAll = hooks.docbarItemsAll;
+ this.docbarItemsTagBrowser = hooks.docbarItemsTagBrowser;
+
+ this.install = install;
+ this.uninstall = uninstall;
+}
+
+function install() {
+ log.info("Installing Twitter-style tags");
+
+ sqlobj.createTable('TAG', {
+ ID: 'int not null '+sqlcommon.autoIncrementClause()+' primary key',
+ NAME: 'varchar(128) character set utf8 collate utf8_bin not null',
+ });
+
+ sqlobj.createTable('PAD_TAG', {
+ PAD_ID: 'varchar(128) character set utf8 collate utf8_bin not null references PAD_META(ID)',
+ TAG_ID: 'int default NULL references TAG(ID)',
+ });
+
+ sqlobj.createTable('PAD_TAG_CACHE', {
+ PAD_ID: 'varchar(128) character set utf8 collate utf8_bin unique not null references PAD_META(ID)',
+ TAGS: 'varchar(1024) collate utf8_bin not null',
+ });
+
+}
+
+function uninstall() {
+ log.info("Uninstalling Twitter-style tags");
+}
+
diff --git a/etherpad/src/plugins/twitterStyleTags/models/tagQuery.js b/etherpad/src/plugins/twitterStyleTags/models/tagQuery.js
new file mode 100644
index 0000000..8a32ef7
--- /dev/null
+++ b/etherpad/src/plugins/twitterStyleTags/models/tagQuery.js
@@ -0,0 +1,227 @@
+/**
+ * Copyright 2010 RedHog, Egil Möller <egil.moller@piratpartiet.se>
+ * Copyright 2010 Pita, Peter Martischka <petermartischka@googlemail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("sqlbase.sqlbase");
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+import("etherpad.log");
+
+function tagsToQuery(tags, antiTags) {
+ var prefixed = [];
+ for (i = 0; i < antiTags.length; i++)
+ prefixed[i] = '!' + antiTags[i];
+ return tags.concat(prefixed).join(',');
+}
+
+function queryToTags(query) {
+ var tags = {
+ tags: new Array(),
+ antiTags: new Array()
+ };
+
+ if (query != undefined && query != '') {
+ var query = query.split(',');
+ for (i = 0; i < query.length; i++)
+ if (query[i][0] == '!')
+ tags.antiTags.push(query[i].substring(1));
+ else
+ tags.tags.push(query[i]);
+ }
+ return tags;
+}
+
+function stringFormat(text, obj) {
+ var name;
+ for (name in obj) {
+ //iterate through the params and replace their placeholders from the original text
+ text = text.replace(new RegExp('%\\(' + name + '\\)s', 'gi' ), obj[name]);
+ }
+ return text;
+}
+
+/* All these sql query functions both takes a querySql object as
+ * parameter and returns one. This object has two members - sql and
+ * params. Sql is a string of an sql table name or a subqyery in
+ * parens. The table pr subquery should have an ID column containing a
+ * PAD_ID.
+ */
+
+/* Filters pads by tags and anti-tags */
+function getQueryToSql(tags, antiTags, querySql) {
+ var queryTable;
+ var queryParams;
+
+ if (querySql == null) {
+ queryTable = 'PAD_META';
+ queryParams = [];
+ } else {
+ queryTable = querySql.sql;
+ queryParams = querySql.params;
+ }
+
+ var exceptArray = [];
+ var joinArray = [];
+ var whereArray = [];
+ var exceptParamArray = [];
+ var joinParamArray = [];
+
+ var info = new Object();
+ info.queryTable = queryTable;
+ info.n = 0;
+ var i;
+
+ for (i = 0; i < antiTags.length; i++) {
+ tag = antiTags[i];
+ exceptArray.push(
+ stringFormat(
+ 'left join (PAD_TAG as pt%(n)s ' +
+ ' join TAG AS t%(n)s on ' +
+ ' t%(n)s.NAME = ? ' +
+ ' and t%(n)s.ID = pt%(n)s.TAG_ID) on ' +
+ ' pt%(n)s.PAD_ID = p.ID ',
+ info));
+ whereArray.push(stringFormat('pt%(n)s.TAG_ID is null', info));
+ exceptParamArray.push(tag);
+ info.n += 1;
+ }
+ for (i = 0; i < tags.length; i++) {
+ tag = tags[i];
+ joinArray.push(
+ stringFormat(
+ 'join PAD_TAG as pt%(n)s on ' +
+ ' pt%(n)s.PAD_ID = p.ID ' +
+ 'join TAG as t%(n)s on ' +
+ ' t%(n)s.ID = pt%(n)s.TAG_ID ' +
+ ' and t%(n)s.NAME = ? ',
+ info));
+ joinParamArray.push(tag);
+ info.n += 1;
+ }
+
+ info["joins"] = joinArray.join(' ');
+ info["excepts"] = exceptArray.join(' ');
+ info["wheres"] = whereArray.length > 0 ? ' where ' + whereArray.join(' and ') : '';
+
+ /* Create a subselect from all the joins */
+ return {
+ sql: stringFormat(
+ '(select distinct ' +
+ ' p.ID ' +
+ ' from ' +
+ ' %(queryTable)s as p ' +
+ ' %(joins)s ' +
+ ' %(excepts)s ' +
+ ' %(wheres)s ' +
+ ') ',
+ info),
+ params: queryParams.concat(joinParamArray).concat(exceptParamArray)};
+}
+
+/* Returns the sql to count the number of results from some other
+ * query. */
+function nrSql(querySql) {
+ var queryTable;
+ var queryParams;
+
+ if (querySql == null) {
+ queryTable = 'PAD_META';
+ queryParams = [];
+ } else {
+ queryTable = querySql.sql;
+ queryParams = querySql.params;
+ }
+
+ var info = [];
+ info['query_sql'] = queryTable
+ return {
+ sql: stringFormat('(select count(*) as total from %(query_sql)s as q)', info),
+ params: queryParams};
+}
+
+/* Returns the sql to select the 10 best new tags to tack on to a
+ * query, that is, the tags that are closest to halving the result-set
+ * if tacked on. */
+function newTagsSql(querySql) {
+ var queryTable;
+ var queryParams;
+
+ if (querySql == null) {
+ queryTable = 'PAD_META';
+ queryParams = [];
+ } else {
+ queryTable = querySql.sql;
+ queryParams = querySql.params;
+ }
+
+ var info = [];
+ info["query_post_table"] = queryTable;
+ var queryNrSql = nrSql(querySql);
+ info["query_nr_sql"] = queryNrSql.sql;
+ queryNrParams = queryNrSql.params;
+
+ return {
+ sql: stringFormat('' +
+ 'select ' +
+ ' t.NAME tagname, ' +
+ ' count(tp.PAD_ID) as matches, ' +
+ ' tn.total - count(tp.PAD_ID) as antimatches, ' +
+ ' abs(count(tp.PAD_ID) - (tn.total / 2)) as weight ' +
+ 'from ' +
+ ' TAG as t, ' +
+ ' PAD_TAG as tp, ' +
+ ' %(query_nr_sql)s as tn ' +
+ 'where ' +
+ ' tp.TAG_ID = t.ID ' +
+ ' and tp.PAD_ID in %(query_post_table)s ' +
+ ' and tp.PAD_ID NOT LIKE \'%$%\'' +
+ 'group by t.NAME, tn.total ' +
+ 'having ' +
+ ' count(tp.PAD_ID) > 0 and count(tp.PAD_ID) < tn.total ' +
+ 'order by ' +
+ ' abs(count(tp.PAD_ID) - (tn.total / 2)) asc ' +
+ 'limit 10 ' +
+ '', info),
+ params: queryNrParams.concat(queryParams)};
+}
+
+/* Select the X last changed matching pads and some extra information
+ * on them. Except the Pro Pads*/
+function padInfoSql(querySql, limit, offset) {
+ var sql = '' +
+ 'select ' +
+ ' m.id as ID, ' +
+ ' DATE_FORMAT(m.lastWriteTime, \'%a, %d %b %Y %H:%i:%s GMT\') as lastWriteTime, ' +
+ ' c.TAGS ' +
+ 'from ' +
+ querySql.sql + ' as q ' +
+ ' join PAD_SQLMETA as m on ' +
+ ' m.id = q.ID ' +
+ ' join PAD_TAG_CACHE as c on ' +
+ ' c.PAD_ID = q.ID ' +
+ 'where ' +
+ ' m.id NOT LIKE \'%$%\'' +
+ 'order by ' +
+ ' m.lastWriteTime desc ';
+ if (limit != undefined)
+ sql += 'limit ' + limit + " ";
+ if (offset != undefined)
+ sql += 'offset ' + offset + " ";
+ return {
+ sql: sql,
+ params: querySql.params
+ };
+}
diff --git a/etherpad/src/plugins/twitterStyleTags/static/css/pad.css b/etherpad/src/plugins/twitterStyleTags/static/css/pad.css
new file mode 100644
index 0000000..e144de5
--- /dev/null
+++ b/etherpad/src/plugins/twitterStyleTags/static/css/pad.css
@@ -0,0 +1,70 @@
+.padtag a,
+.padtag a:visited,
+a.padtag,
+a.padtag:visited,
+a.anti_padtag,
+a.anti_padtag:visited {
+ text-decoration: none !important;
+ color: #2e2eaa !important;
+
+ border-style: solid;
+ border-width: 1px;
+
+ border-left-color: #8c8c8c;
+ border-right-color: #707070;
+ border-top-color: #9c9c9c;
+ border-bottom-color: #606060;
+
+ -moz-border-radius-topleft: 3pt;
+ -moz-border-radius-topright: 3pt;
+ -moz-border-radius-bottomleft: 3pt;
+ -moz-border-radius-bottomright: 3pt;
+ -webkit-border-top-left-radius: 3pt;
+ -webkit-border-top-right-radius: 3pt;
+ -webkit-border-bottom-left-radius: 3pt;
+ -webkit-border-bottom-right-radius: 3pt;
+
+ padding-left: 2pt;
+ padding-right: 2pt
+}
+
+a.anti_padtag,
+a.anti_padtag:visited {
+ color: #aa2e2e !important;
+ border-left-color: #aa8c8c;
+ border-right-color: #aa7070;
+ border-top-color: #aa9c9c;
+ border-bottom-color: #aa6060;
+}
+
+.padtag_public a,
+.padtag_public a:visited,
+a.padtag_public,
+a.padtag_public:visited {
+ color: #2e772e !important;
+ background-color: #99ff99 !important;
+
+ border-style: solid;
+ border-width: 1px;
+
+ border-left-color: #8caa8c;
+ border-right-color: #70aa70;
+ border-top-color: #9caa9c;
+ border-bottom-color: #60aa60;
+}
+
+.padtag_writable a,
+.padtag_writable a:visited,
+a.padtag_writable,
+a.padtag_writable:visited {
+ color: #2e2e77 !important;
+ background-color: #9999ff !important;
+
+ border-style: solid;
+ border-width: 1px;
+
+ border-left-color: #8c8caa;
+ border-right-color: #7070aa;
+ border-top-color: #9c9caa;
+ border-bottom-color: #6060aa;
+}
diff --git a/etherpad/src/plugins/twitterStyleTags/static/css/tagBrowser.css b/etherpad/src/plugins/twitterStyleTags/static/css/tagBrowser.css
new file mode 100644
index 0000000..55fcda2
--- /dev/null
+++ b/etherpad/src/plugins/twitterStyleTags/static/css/tagBrowser.css
@@ -0,0 +1,90 @@
+.padtag a,
+.padtag a:visited,
+a.padtag,
+a.padtag:visited,
+a.anti_padtag,
+a.anti_padtag:visited {
+ line-height: 1.7em;
+}
+
+dt {
+ padding-bottom: 2pt;
+}
+
+dd {
+ padding-left: 20pt;
+ padding-bottom: 10pt;
+}
+
+h1 {
+ font-size: 12pt;
+ margin-top: 5pt;
+}
+
+.label {
+ font-size: 14pt;
+}
+
+#editorcontainer {
+ padding: 5pt;
+}
+
+#editorcontainerbox {
+ overflow: auto;
+ height: auto;
+}
+
+
+.query-refiner {
+ float: right;
+ padding: 10pt;
+ margin-left: 5pt;
+ margin-bottom: 5pt;
+ border: 1px solid #9C9C9C;
+ width: 40%;
+}
+
+.query-refiner h1 {
+ margin-bottom: 2pt;
+ margin-top: 0;
+}
+
+#home-newpad, #home-newteam {
+ display: block;
+ background-color: #a3bde0;
+ color: #555555;
+ border-style: solid;
+ border-width: 2px;
+ border-left-color: #d6e2f1;
+ border-right-color: #86aee1;
+ border-top-color: #d6e2f1;
+ border-bottom-color: #86aee1;
+ margin: 10pt;
+ text-align: center;
+ text-decoration: none;
+ padding-top: 50pt;
+ padding-bottom: 50pt;
+ font-size: 20pt;
+ -moz-border-radius-topleft: 3pt;
+ -moz-border-radius-topright: 3pt;
+ -moz-border-radius-bottomleft: 3pt;
+ -moz-border-radius-bottomright: 3pt;
+ -webkit-border-top-left-radius: 3pt;
+ -webkit-border-top-right-radius: 3pt;
+ -webkit-border-bottom-left-radius: 3pt;
+ -webkit-border-bottom-right-radius: 3pt;
+}
+
+#editbarinner {
+ line-height: 29px;
+ font-size: 16px;
+ padding-left: 6pt;
+}
+
+#editbarinner a {
+ font-size: 12px;
+}
+
+#padchat iframe {
+ border: none;
+}
diff --git a/etherpad/src/plugins/twitterStyleTags/static/js/main.js b/etherpad/src/plugins/twitterStyleTags/static/js/main.js
new file mode 100644
index 0000000..a83e3e8
--- /dev/null
+++ b/etherpad/src/plugins/twitterStyleTags/static/js/main.js
@@ -0,0 +1,48 @@
+function init() {
+ this.hooks = ['aceInitInnerdocbodyHead', 'aceGetFilterStack', 'aceCreateDomLine'];
+ this.aceInitInnerdocbodyHead = aceInitInnerdocbodyHead;
+ this.aceGetFilterStack = aceGetFilterStack;
+ this.aceCreateDomLine = aceCreateDomLine;
+}
+
+function aceInitInnerdocbodyHead(args) {
+ args.iframeHTML.push('\'<link rel="stylesheet" type="text/css" href="/static/css/plugins/twitterStyleTags/pad.css"/>\'');
+}
+
+function aceGetFilterStack(args) {
+ return [
+ args.linestylefilter.getRegexpFilter(
+ new RegExp("#[^,#=!\\s][^,#=!\\s]*", "g"), 'padtag'),
+ args.linestylefilter.getRegexpFilter(
+ new RegExp("=[^#=\\s][^#=\\s]*", "g"), 'padtagsearch')
+ ];
+}
+
+function aceCreateDomLine(args) {
+ if (args.cls.indexOf('padtagsearch') >= 0) {
+ var href;
+ cls = args.cls.replace(/(^| )padtagsearch:(\S+)/g, function(x0, space, padtagsearch) {
+ href = '/ep/tag/?query=' + padtagsearch.substring(1);
+ return space + "padtagsearch padtagsearch_" + padtagsearch.substring(1);
+ });
+
+ return [{
+ cls: cls,
+ extraOpenTags: '<a href="' + href.replace(/\"/g, '&quot;') + '">',
+ extraCloseTags: '</a>'}];
+ } else if (args.cls.indexOf('padtag') >= 0) {
+ var href;
+ cls = args.cls.replace(/(^| )padtag:(\S+)/g, function(x0, space, padtag) {
+ href = '/ep/tag/?query=' + padtag.substring(1);
+ return space + "padtag padtag_" + padtag.substring(1);
+ });
+
+ return [{
+ cls: cls,
+ extraOpenTags: '<a href="' + href.replace(/\"/g, '&quot;') + '">',
+ extraCloseTags: '</a>'}];
+ }
+}
+
+/* used on the client side only */
+twitterStyleTags = new init();
diff --git a/etherpad/src/plugins/twitterStyleTags/templates/tagBrowser.ejs b/etherpad/src/plugins/twitterStyleTags/templates/tagBrowser.ejs
new file mode 100644
index 0000000..e101196
--- /dev/null
+++ b/etherpad/src/plugins/twitterStyleTags/templates/tagBrowser.ejs
@@ -0,0 +1,115 @@
+<% /*
+Copyright 2009 Google Inc.
+Copyright 2010 Pita, Peter Martischka <petermartischka@googlemail.com>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %>
+<%
+ template.inherit('page.ejs');
+ helpers.setHtmlTitle("EtherPad: Browse tags");
+ helpers.includeCss("plugins/twitterStyleTags/tagBrowser.css");
+ helpers.includeCss("plugins/twitterStyleTags/pad.css");
+ helpers.addToHead('\n<link rel="alternate" href="' + helpers.updateToUrl({format:'rss'}) + '" type="application/rss+xml" title="Query results as RSS" />\n');
+
+ function inArray(item, arr) {
+ for (var i = 0; i < arr.length; i++)
+ if (arr[i] == item)
+ return true;
+ return false;
+ }
+%>
+<% template.define('docBarTitle', function() { var ejs_data=''; %>
+ <td id="docbarpadtitle"><span>Browse Tags</span></td>
+<% return ejs_data; }); %>
+
+<%
+ template.define('docBarItems', function() {
+ return plugins.callHookStr('docbarItemsTagBrowserPad', {}, '', '', '') +
+ plugins.callHookStr('docbarItemsTagBrowser', {}, '', '', '');
+ });
+%>
+
+<% template.define('sideBar', function() { var ejs_data=''; %>
+ <div id="padusers">
+ <% if (isProAccountEnabled()) { %>
+ <a href="/ep/pad/newpad" style="padding: 25px 0" id="home-newpad">
+ Create new pad
+ </a>
+ <a href="/ep/pro-signup/" style="padding: 25px 0" id="home-newteam">
+ Create new team
+ </a>
+ <% } else { %>
+ <a href="/ep/pad/newpad" id="home-newpad">
+ Create new pad
+ </a>
+ <% } %>
+ </div>
+
+ <div id="hdraggie"><!-- --></div>
+
+ <div id="padchat"><iframe src="<%= config['motdPage'] %>" width="100%" height="100%"></iframe></div>
+<% return ejs_data; }); %>
+
+<% template.define('editBarItemsLeft', function() { var ejs_data=''; %>
+ <td>
+ Query:
+ <% if (tags.length == 0 && antiTags.length == 0) { %>
+ Latest changed pads
+ <% } else { %>
+ <% for (i = 0; i < tags.length; i++) { %>
+ <a href="<%= helpers.updateToUrl({query:tagQuery.tagsToQuery(tags.filter(function (tag) { return tag != tags[i]}), antiTags)}) %>" class="padtag" title="<%= tags[i] %> matches">#<%= tags[i] %></a>
+ <% } %>
+ <% for (i = 0; i < antiTags.length; i++) { %>
+ <a href="<%= helpers.updateToUrl({query:tagQuery.tagsToQuery(tags, antiTags.filter(function (tag) { return tag != antiTags[i]}))}) %>" class="anti_padtag" title="<%= antiTags[i] %> matches">!#<%= antiTags[i] %></a>
+ <% } %>
+ <% } %>
+ </td>
+<% return ejs_data; }); %>
+
+<% template.define('contentArea', function() { var ejs_data=''; %>
+ <div id="editorcontainer">
+ <div class="query-refiner">
+ <%: template.use('queryRefiner', function() { var ejs_data=''; %>
+ <h1>Search for pads that have the tag</h1>
+ <% for (i = 0; i < newTags.length; i++) { %>
+ <a href="<%= helpers.updateToUrl({query:tagQuery.tagsToQuery(tags.concat([newTags[i].tagname]),antiTags)}) %>" class="padtag" title="<%= newTags[i].matches %> matches">#<%= newTags[i].tagname %></a>
+ <% } %>
+
+ <h1>Search for pads that <em>don't</em> have the tag</h1>
+ <% for (i = 0; i < newTags.length; i++) { %>
+ <a href="<%= helpers.updateToUrl({query:tagQuery.tagsToQuery(tags,antiTags.concat([newTags[i].tagname]))}) %>" class="anti_padtag" title="<%= newTags[i].antimatches %> matches">!#<%= newTags[i].tagname %></a>
+ <% } %>
+ <% return ejs_data; }); %>
+ </div>
+
+ <dl>
+ <%: template.use('queryResult', function() { var ejs_data=''; %>
+ <% for (i = 0; i < matchingPads.length; i++) { %>
+ <%
+ var matchingPadId = matchingPads[i].ID;
+ var matchingPadUrl = matchingPadId;
+ if (!inArray('writable', matchingPads[i].TAGS)) {
+ matchingPadId = padIdToReadonly(matchingPads[i].ID);
+ matchingPadUrl = 'ep/pad/view/' + matchingPadId + '/latest';
+ }
+ %>
+ <dt><a href="/<%= matchingPadUrl %>"><%= matchingPadId %></a><dt>
+ <dd>
+ <% for (j = 0; j < matchingPads[i].TAGS.length; j++) { %>
+ <a href="<%= helpers.updateToUrl({query:tagQuery.tagsToQuery(tags.concat([matchingPads[i].TAGS[j]]), antiTags)}) %>" class="padtag" title="<%= matchingPads[i].TAGS[j] %> matches">#<%= matchingPads[i].TAGS[j] %></a>
+ <% } %>
+ </dd>
+ <% } %>
+ <% return ejs_data; }); %>
+ </dl>
+ </div>
+<% return ejs_data; }); %>
diff --git a/etherpad/src/plugins/twitterStyleTags/templates/tagRss.ejs b/etherpad/src/plugins/twitterStyleTags/templates/tagRss.ejs
new file mode 100644
index 0000000..2d06781
--- /dev/null
+++ b/etherpad/src/plugins/twitterStyleTags/templates/tagRss.ejs
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<%
+ function inArray(item, arr) {
+ for (var i = 0; i < arr.length; i++)
+ if (arr[i] == item)
+ return true;
+ return false;
+ }
+%>
+<rss version="2.0">
+ <channel>
+ <title>
+ <% if (tags.length == 0 && antiTags.length == 0) { %>
+ Latest changed pads
+ <% } else { %>
+ <% for (i = 0; i < tags.length; i++) { %>
+ #<%= tags[i] %>
+ <% } %>
+ <% for (i = 0; i < antiTags.length; i++) { %>
+ !#<%= antiTags[i] %>
+ <% } %>
+ <% } %>
+ </title>
+ <link>http://liftoff.msfc.nasa.gov/</link>
+ <description>
+ Etherpad pads / changes for the query:
+ <% if (tags.length == 0 && antiTags.length == 0) { %>
+ Latest changed pads
+ <% } else { %>
+ <% for (i = 0; i < tags.length; i++) { %>
+ #<%= tags[i] %>
+ <% } %>
+ <% for (i = 0; i < antiTags.length; i++) { %>
+ !#<%= antiTags[i] %>
+ <% } %>
+ <% } %>
+ </description>
+ <language>en-us</language>
+ <pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate>
+ <lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate>
+ <docs>http://blogs.law.harvard.edu/tech/rss</docs>
+ <generator>Etherpad</generator>
+ <managingEditor>editor@example.com</managingEditor>
+ <webMaster>webmaster@example.com</webMaster>
+
+ <% for (i = 0; i < matchingPads.length; i++) { %>
+ <%
+ var matchingPadId = matchingPads[i].ID;
+ var matchingPadUrl = matchingPadId;
+ if (!inArray('writable', matchingPads[i].TAGS)) {
+ matchingPadId = padIdToReadonly(matchingPads[i].ID);
+ matchingPadUrl = 'ep/pad/view/' + matchingPadId + '/latest';
+ }
+ %>
+ <item>
+ <title><%= matchingPadId %></title>
+ <link>http://<%= request.host %>/<%= matchingPadUrl %></link>
+ <description>
+ <% for (j = 0; j < matchingPads[i].TAGS.length; j++) { %>
+ #<%= matchingPads[i].TAGS[j] %>
+ <% } %>
+ </description>
+ <pubDate><%= matchingPads[i].lastWriteTime %></pubDate>
+ <guid>http://<%= request.host %>/<%= matchingPadUrl %></guid>
+ </item>
+ <% } %>
+
+ </channel>
+</rss> \ No newline at end of file
diff --git a/etherpad/src/plugins/urlIndexer/controllers/urlBrowser.js b/etherpad/src/plugins/urlIndexer/controllers/urlBrowser.js
new file mode 100644
index 0000000..cdb9602
--- /dev/null
+++ b/etherpad/src/plugins/urlIndexer/controllers/urlBrowser.js
@@ -0,0 +1,132 @@
+/**
+ * Copyright 2009 RedHog, Egil Möller <egil.moller@piratpartiet.se>
+ * Copyright 2010 Pita, Peter Martischka <petermartischka@googlemail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("plugins.twitterStyleTags.models.tagQuery");
+
+import("faststatic");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+
+import("etherpad.utils.*");
+import("etherpad.collab.server_utils");
+import("etherpad.globals.*");
+import("etherpad.log");
+import("etherpad.pad.padusers");
+import("etherpad.pro.pro_utils");
+import("etherpad.helpers");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("sqlbase.sqlbase");
+import("sqlbase.sqlcommon");
+import("sqlbase.sqlobj");
+import("etherpad.pad.padutils");
+
+function urlSql(querySql, limit, offset) {
+ var sql = '' +
+ 'select ' +
+ ' u.URL, ' +
+ ' m.id as ID, ' +
+ ' DATE_FORMAT(m.lastWriteTime, \'%a, %d %b %Y %H:%i:%s GMT\') as lastWriteTime, ' +
+ ' c.TAGS ' +
+ 'from ' +
+ querySql.sql + ' as q ' +
+ ' join PAD_SQLMETA as m on ' +
+ ' m.id = q.ID ' +
+ ' join PAD_TAG_CACHE as c on ' +
+ ' c.PAD_ID = q.ID ' +
+ ' join PAD_URL as u on ' +
+ ' u.PAD_ID = q.ID ' +
+ 'where ' +
+ ' m.id NOT LIKE \'%$%\'' +
+ 'order by ' +
+ ' u.URL asc ';
+ if (limit != undefined)
+ sql += 'limit ' + limit + " ";
+ if (offset != undefined)
+ sql += 'offset ' + offset + " ";
+ return {
+ sql: sql,
+ params: querySql.params
+ };
+}
+
+function onRequest() {
+ var tags = tagQuery.queryToTags(request.params.query);
+
+ /* Create the pad filter sql */
+ var querySql = tagQuery.getQueryToSql(tags.tags.concat(['public']), tags.antiTags);
+
+ /* Use the pad filter sql to figure out which tags to show in the tag browser this time. */
+ var queryNewTagsSql = tagQuery.newTagsSql(querySql);
+ var newTags = sqlobj.executeRaw(queryNewTagsSql.sql, queryNewTagsSql.params);
+
+ url = urlSql(querySql, 10);
+ var matchingUrls = sqlobj.executeRaw(url.sql, url.params);
+
+ for (i = 0; i < matchingUrls.length; i++) {
+ matchingUrls[i].TAGS = matchingUrls[i].TAGS.split('#');
+ }
+
+ var isPro = pro_utils.isProDomainRequest();
+ var userId = padusers.getUserId();
+
+ helpers.addClientVars({
+ userAgent: request.headers["User-Agent"],
+ debugEnabled: request.params.djs,
+ clientIp: request.clientAddr,
+ colorPalette: COLOR_PALETTE,
+ serverTimestamp: +(new Date),
+ isProPad: isPro,
+ userIsGuest: padusers.isGuest(userId),
+ userId: userId,
+ });
+
+ var isProUser = (isPro && ! padusers.isGuest(userId));
+
+ padutils.setOptsAndCookiePrefs(request);
+ var prefs = helpers.getClientVar('cookiePrefsToSet');
+ var bodyClass = (prefs.isFullWidth ? "fullwidth" : "limwidth")
+
+ var info = {
+ prefs: prefs,
+ config: appjet.config,
+ tagQuery: tagQuery,
+ padIdToReadonly: server_utils.padIdToReadonly,
+ tags: tags.tags,
+ antiTags: tags.antiTags,
+ newTags: newTags,
+ matchingPads: [],
+ matchingUrls: matchingUrls,
+ bodyClass: 'nonpropad',
+ isPro: isPro,
+ isProAccountHolder: isProUser,
+ account: getSessionProAccount(), // may be falsy
+ };
+
+ var format = "html";
+ if (request.params.format != undefined)
+ format = request.params.format;
+
+ if (format == "html")
+ renderHtml("urlBrowser.ejs", info, ['urlIndexer', 'twitterStyleTags']);
+ else if (format == "rss") {
+ response.setContentType("application/xml; charset=utf-8");
+ response.write(renderTemplateAsString("tagRss.ejs", info, 'urlIndexer'));
+ if (request.acceptsGzip) {
+ response.setGzip(true);
+ }
+ }
+ return true;
+}
diff --git a/etherpad/src/plugins/urlIndexer/hooks.js b/etherpad/src/plugins/urlIndexer/hooks.js
new file mode 100644
index 0000000..e0ff050
--- /dev/null
+++ b/etherpad/src/plugins/urlIndexer/hooks.js
@@ -0,0 +1,49 @@
+import("etherpad.log");
+import("dispatch.{Dispatcher,PrefixMatcher,forward}");
+import("sqlbase.sqlobj");
+import("plugins.urlIndexer.controllers.urlBrowser");
+
+function handlePath() {
+ return [[PrefixMatcher('/ep/url'), forward(urlBrowser)]];
+}
+
+REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/;
+REGEX_URLCHAR = new RegExp('('+/[-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/.source+'|'+REGEX_WORDCHAR.source+')');
+REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:)/.source+REGEX_URLCHAR.source+'*(?![:.,;])'+REGEX_URLCHAR.source, 'g');
+
+function padModelWriteToDB(args) {
+ /* Update tags for the pad */
+
+ var new_urls = args.pad.text().match(REGEX_URL);
+ if (new_urls == null) new_urls = new Array();
+ var new_urls_str = new_urls.join(' ')
+
+ var old_urls_row = sqlobj.selectSingle("PAD_URL_CACHE", { PAD_ID: args.padId });
+ var old_urls_str;
+ if (old_urls_row !== null)
+ old_urls_str = old_urls_row['URLS'];
+ else
+ old_urls_str = '';
+
+ // var old_urls = old_urls_str != '' ? old_urls_str.split(' ') : new Array();
+
+ if (new_urls_str != old_urls_str) {
+ // log.info({message: 'Updating urls', new_urls:new_urls, old_urls:old_urls});
+
+ if (old_urls_row)
+ sqlobj.update("PAD_URL_CACHE", {PAD_ID: args.padId }, {URLS: new_urls.join(' ')});
+ else
+ sqlobj.insert("PAD_URL_CACHE", {PAD_ID: args.padId, URLS: new_urls.join(' ')});
+
+ sqlobj.deleteRows("PAD_URL", {PAD_ID: args.padId});
+
+ for (i = 0; i < new_urls.length; i++) {
+ sqlobj.insert("PAD_URL", {PAD_ID: args.padId, URL: new_urls[i]});
+ }
+ }
+}
+
+function docbarItemsTagBrowser() {
+ return ["<td class='docbarbutton'><a href='/ep/url/'>URLs</a></td>"];
+}
+
diff --git a/etherpad/src/plugins/urlIndexer/main.js b/etherpad/src/plugins/urlIndexer/main.js
new file mode 100644
index 0000000..18bdef1
--- /dev/null
+++ b/etherpad/src/plugins/urlIndexer/main.js
@@ -0,0 +1,34 @@
+import("etherpad.log");
+import("plugins.urlIndexer.hooks");
+import("sqlbase.sqlobj");
+import("sqlbase.sqlcommon");
+
+function init() {
+ this.hooks = ['padModelWriteToDB', 'handlePath', 'docbarItemsTagBrowser'];
+ this.description = 'Indexes URLs linked to in pads so that they can be displayed outside pads, searched for etc.';
+ this.padModelWriteToDB = hooks.padModelWriteToDB;
+ this.handlePath = hooks.handlePath;
+ this.docbarItemsTagBrowser = hooks.docbarItemsTagBrowser;
+
+ this.install = install;
+ this.uninstall = uninstall;
+}
+
+function install() {
+ log.info("Installing urlIndexer");
+
+ sqlobj.createTable('PAD_URL', {
+ PAD_ID: 'varchar(128) character set utf8 collate utf8_bin not null references PAD_META(ID)',
+ URL: 'varchar(1024) character set utf8 collate utf8_bin not null',
+ });
+
+ sqlobj.createTable('PAD_URL_CACHE', {
+ PAD_ID: 'varchar(128) character set utf8 collate utf8_bin unique not null references PAD_META(ID)',
+ URLS: 'text collate utf8_bin not null',
+ });
+}
+
+function uninstall() {
+ log.info("Uninstalling urlIndexer");
+}
+
diff --git a/etherpad/src/plugins/urlIndexer/templates/urlBrowser.ejs b/etherpad/src/plugins/urlIndexer/templates/urlBrowser.ejs
new file mode 100644
index 0000000..1996dc5
--- /dev/null
+++ b/etherpad/src/plugins/urlIndexer/templates/urlBrowser.ejs
@@ -0,0 +1,53 @@
+<% /*
+Copyright 2009 Google Inc.
+Copyright 2010 Pita, Peter Martischka <petermartischka@googlemail.com>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %>
+<%
+ template.inherit('tagBrowser.ejs');
+ helpers.setHtmlTitle("EtherPad: Browse URLs by tags");
+ helpers.includeCss("plugins/twitterStyleTags/tagBrowser.css");
+ helpers.includeCss("plugins/twitterStyleTags/pad.css");
+ helpers.addToHead('\n<link rel="alternate" href="' + helpers.updateToUrl({format:'rss'}) + '" type="application/rss+xml" title="Query results as RSS" />\n');
+
+ function inArray(item, arr) {
+ for (var i = 0; i < arr.length; i++)
+ if (arr[i] == item)
+ return true;
+ return false;
+ }
+%>
+
+<% template.define('docBarTitle', function() { var ejs_data=''; %>
+ <td id="docbarpadtitle"><span>Browse URLs by tags</span></td>
+<% return ejs_data; }); %>
+
+<% template.define('queryResult', function() { var ejs_data=''; %>
+ <% for (i = 0; i < matchingUrls.length; i++) { %>
+ <%
+ var matchingPadId = matchingUrls[i].ID;
+ var matchingPadUrl = matchingPadId;
+ if (!inArray('writable', matchingUrls[i].TAGS)) {
+ matchingPadId = padIdToReadonly(matchingUrls[i].ID);
+ matchingPadUrl = 'ep/pad/view/' + matchingPadId + '/latest';
+ }
+ %>
+ <dt><a href="<%= matchingUrls[i].URL %>"><%= matchingUrls[i].URL %></a><dt>
+ <dd>
+ <a href="<%= matchingPadUrl %>"><%= matchingPadId %></a>:
+ <% for (j = 0; j < matchingUrls[i].TAGS.length; j++) { %>
+ <a href="<%= helpers.updateToUrl({query:tagQuery.tagsToQuery(tags.concat([matchingUrls[i].TAGS[j]]), antiTags)}) %>" class="padtag" title="<%= matchingUrls[i].TAGS[j] %> matches">#<%= matchingUrls[i].TAGS[j] %></a>
+ <% } %>
+ </dd>
+ <% } %>
+<% return ejs_data; }); %>
diff --git a/trunk/etherpad/src/static/crossdomain.xml b/etherpad/src/static/crossdomain.xml
index 9e76390..9e76390 100644
--- a/trunk/etherpad/src/static/crossdomain.xml
+++ b/etherpad/src/static/crossdomain.xml
diff --git a/trunk/etherpad/src/static/css/admin/admin-stats.css b/etherpad/src/static/css/admin/admin-stats.css
index 94e0d19..94e0d19 100644
--- a/trunk/etherpad/src/static/css/admin/admin-stats.css
+++ b/etherpad/src/static/css/admin/admin-stats.css
diff --git a/etherpad/src/static/css/admin/pluginmanager.css b/etherpad/src/static/css/admin/pluginmanager.css
new file mode 100644
index 0000000..136a713
--- /dev/null
+++ b/etherpad/src/static/css/admin/pluginmanager.css
@@ -0,0 +1,62 @@
+#editorcontainer {
+ padding: 5pt;
+}
+
+#editorcontainerbox {
+ overflow: auto;
+ height: auto;
+}
+
+#editbarinner {
+ line-height: 36px;
+ font-size: 16px;
+ padding-left: 6pt;
+}
+
+#editbarinner a {
+ font-size: 12px;
+}
+
+#editorcontainerbox table {
+ margin: 10pt;
+ border-collapse: collapse;
+}
+
+#editorcontainerbox table tr th {
+ font-weight: bold;
+ background: #c3c3c3;
+}
+
+#editorcontainerbox table tr td,
+#editorcontainerbox table tr th {
+ border: 1px solid #c3c3c3;
+ padding: 2pt;
+}
+
+#editorcontainerbox table tr:first-child th,
+#editorcontainerbox table tr:first-child td {
+ border-top-color: #e6e6e6;
+}
+
+#editorcontainerbox table tr th:first-child,
+#editorcontainerbox table tr td:first-child {
+ border-left-color: #e6e6e6;
+}
+
+.mousover_parent .mouseover_child {
+ display: none;
+ position: absolute;
+ padding: 4pt;
+
+ border-top-color: #e6e6e6;
+ border-bottom-color: #c3c3c3;
+ border-left-color: #e6e6e6;
+ border-right-color: #c3c3c3;
+ border: 1px solid;
+
+ background: #ffffff;
+}
+
+.mousover_parent:hover .mouseover_child {
+ display: block;
+}
diff --git a/trunk/etherpad/src/static/css/broadcast.css b/etherpad/src/static/css/broadcast.css
index afb65b8..afb65b8 100644
--- a/trunk/etherpad/src/static/css/broadcast.css
+++ b/etherpad/src/static/css/broadcast.css
diff --git a/trunk/etherpad/src/static/css/etherpad.css b/etherpad/src/static/css/etherpad.css
index 70bf464..70bf464 100644
--- a/trunk/etherpad/src/static/css/etherpad.css
+++ b/etherpad/src/static/css/etherpad.css
diff --git a/trunk/etherpad/src/static/css/framedpage.css b/etherpad/src/static/css/framedpage.css
index a99554b..a99554b 100644
--- a/trunk/etherpad/src/static/css/framedpage.css
+++ b/etherpad/src/static/css/framedpage.css
diff --git a/trunk/etherpad/src/static/css/global-pro-account.css b/etherpad/src/static/css/global-pro-account.css
index 6c34446..6c34446 100644
--- a/trunk/etherpad/src/static/css/global-pro-account.css
+++ b/etherpad/src/static/css/global-pro-account.css
diff --git a/etherpad/src/static/css/home-opensource.css b/etherpad/src/static/css/home-opensource.css
new file mode 100644
index 0000000..bb0201e
--- /dev/null
+++ b/etherpad/src/static/css/home-opensource.css
@@ -0,0 +1,40 @@
+
+#home {
+ width: 600px;
+ margin: 0 auto;
+ padding: 2em;
+ text-align: center;
+}
+
+#home #title {
+ font-size: 3.6em;
+}
+
+#home a#home-newpad{
+ display: block;
+ padding: 1em;
+ margin: 12px 60px;
+ font-size: 1.6em;
+ border: 1px solid black;
+ background: #049;
+ color: #fff;
+}
+
+#home a#home-newpad:hover{
+ background: #26b;
+}
+
+#home a#home-newteam {
+ display: block;
+ padding: 1em;
+ margin: 12px 60px;
+ font-size: 1.6em;
+ border: 1px solid black;
+ background: #940;
+ color: #fff;
+}
+
+#home a#home-newteam:hover {
+ background: #b26;
+}
+
diff --git a/trunk/etherpad/src/static/css/lib/jquery.contextmenu.css b/etherpad/src/static/css/lib/jquery.contextmenu.css
index 15a69aa..15a69aa 100644
--- a/trunk/etherpad/src/static/css/lib/jquery.contextmenu.css
+++ b/etherpad/src/static/css/lib/jquery.contextmenu.css
diff --git a/etherpad/src/static/css/pad2_ejs.css b/etherpad/src/static/css/pad2_ejs.css
new file mode 100644
index 0000000..71176ee
--- /dev/null
+++ b/etherpad/src/static/css/pad2_ejs.css
@@ -0,0 +1,910 @@
+
+*,html.body { margin: 0; padding: 0; }
+
+h1, h2, h3, h4, h5, h6 { display: inline; line-height: 2em; }
+
+.clear { clear: both; }
+
+html { font-size: 62.5%; }
+
+body { background: #ebebeb url(/static/img/jun09/pad/backgrad.gif) repeat-x left top; }
+body, textarea { font-family: Arial, sans-serif; }
+
+#padpage { margin-left: auto; margin-right: auto; width: 900px; }
+
+body.fullwidth #padpage { width: auto; margin-left: 6px; margin-right: 6px; min-width: 800px; }
+body.squish1width #padpage { width: 900px; }
+body.squish2width #padpage { width: 800px; }
+
+#topbar { height: 25px; background: #326cbd url(/static/img/jun09/pad/padtopback2.gif) repeat-x left top;
+ position: relative; }
+
+#topbarleft { float: left; height: 100%; overflow: hidden;
+ background: url(/static/img/jun09/pad/padtop5.png) no-repeat left top; width: 5px; }
+#topbarright { float: right; height: 100%; overflow: hidden;
+ background: url(/static/img/jun09/pad/padtop5.png) no-repeat right top; width: 5px; }
+
+.propad #topbar { background: #2c2c2c url(/static/img/jun09/pad/protop.png) repeat-x 0 -25px; }
+.propad #topbarleft { background: url(/static/img/jun09/pad/protop.png) no-repeat left top; }
+.propad #topbarright { background: url(/static/img/jun09/pad/protop.png) no-repeat right top; }
+
+a#backtoprosite, #accountnav {
+ display: block; position: absolute; height: 15px; line-height: 15px;
+ width: auto; top: 5px; font-size: 1.2em;
+}
+a#backtoprosite, #accountnav a { color: #cde7ff; text-decoration: underline; }
+
+a#backtoprosite { padding-left: 20px; left: 6px;
+ background: url(/static/img/jun09/pad/protop.png) no-repeat -5px -6px; }
+#accountnav { right: 10px; color: #fff; }
+
+#topbarcenter { margin-left: 150px; margin-right: 150px; }
+a#topbaretherpad { margin-left: auto; margin-right: auto; display: block; width: 127px;
+ position: relative; top: 0px; height: 0; padding-top: 25px;
+ background: url(/static/img/jun09/pad/padtop5.png) no-repeat -397px 0px; overflow: hidden; }
+
+.propad a#topbaretherpad { background: url(/static/img/jun09/pad/protop.png) no-repeat -397px 0px; }
+
+#specialkeyarea { top: 5px; left: 250px; color: yellow; font-weight: bold;
+ font-size: 1.5em; position: absolute; }
+
+#alertbar { margin-top: 6px;
+opacity: 0; filter: alpha(opacity = 0); /* IE */
+display: none;
+}
+
+#servermsg { position: relative; zoom: 1; border: 1px solid #992;
+ background: #ffc; padding: 0.8em; font-size: 1.2em; }
+#servermsg h3 { font-weight: bold; margin-right: 10px;
+ margin-bottom: 1em; float: left; width: auto; }
+#servermsg #servermsgdate { font-style: italic; font-weight: normal; color: #666; }
+a#hidetopmsg { position: absolute; right: 5px; bottom: 5px; }
+
+#shuttingdown { position: relative; zoom: 1; border: 1px solid #992;
+ background: #ffc; padding: 0.6em; font-size: 1.2em; margin-top: 6px; }
+
+#docbar { margin-top: 6px; height: 25px; position: relative; zoom: 1;
+ background: #fbfbfb url(/static/img/jun09/pad/padtopback2.gif) repeat-x 0 -31px; }
+
+.docbarbutton
+{
+ padding-top: 2px;
+ padding-bottom: 2px;
+ padding-left: 4px;
+ padding-right: 4px;
+ border-left: 1px solid #CCC;
+ white-space: nowrap;
+}
+
+.docbarbutton img
+{
+ border: 0px;
+ width: 13px;
+ margin-right: 2px;
+ vertical-align: middle;
+ margin-top: 3px;
+ margin-bottom: 2px;
+}
+
+.docbarbutton a
+{
+ font-size: 10px;
+ line-height: 18px;
+ text-decoration: none;
+ color: #444;
+ font-weight: bold;
+}
+
+.docbarbutton.highlight
+{
+ background-color: #fef2bd;
+ border: 1px solid #CCC;
+ border-right: 0px;
+}
+
+#docbarleft { position: absolute; left: 0; top: 0; height: 100%;
+ overflow: hidden;
+ background: url(/static/img/jun09/pad/padtop5.gif) no-repeat left -31px; width: 7px; }
+
+<% /* changing the size of the title / rename area means adjusting
+ the #docbarpadtitle.width, #padtitlebuttons.left,
+ and #padtitleedit.width */ %>
+
+#docbarpadtitle { position: absolute; height: auto; left: 9px;
+ width: 280px; font-size: 1.6em; color: #444; font-weight: normal;
+ line-height: 22px; margin-left: 2px; height: 22px; top: 2px;
+ overflow: hidden; text-overflow: ellipsis /*not supported in FF*/;
+ white-space:nowrap; }
+.docbar-public #docbarpadtitle { padding-left: 22px;
+ background: url(/static/img/jun09/pad/public.gif) no-repeat left center; }
+
+#docbarrenamelink { position: absolute; top: 6px;
+ font-size: 1.1em; display: none; }
+#docbarrenamelink a { color: #999; }
+#docbarrenamelink a:hover { color: #48d; }
+#padtitlebuttons { position: absolute; width: 74px; zoom: 1;
+ height: 17px; top: 4px; left: 170px; display: none;
+ background: url(/static/img/jun09/pad/ok_or_cancel.gif) 0px 0px; }
+#padtitlesave { position: absolute; display: block;
+ height: 0; padding-top: 17px; overflow: hidden;
+ width: 23px; left: 0; top: 0; }
+#padtitlecancel { position: absolute; display: block;
+ height: 0; padding-top: 17px; overflow: hidden;
+ width: 35px; right: 0; top: 0; }
+#padtitleedit { position: absolute; top: 2px; left: 5px;
+ height: 15px; padding: 2px; font-size: 1.4em;
+ background: white; border-left: 1px solid #c3c3c3;
+ border-top: 1px solid #c3c3c3;
+ border-right: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;
+ width: 150px; display: none;
+}
+
+#padmain { margin-top: 6px; position: relative; zoom: 1; }
+
+#padeditor { margin-right: 300px; zoom: 1; }
+.hidesidebar #padeditor { margin-right: 0; }
+
+#editbar { height: 36px;
+ background: #a5bfe2 url(/static/img/jun09/pad/editbar_background.gif) repeat-x; position: relative; }
+
+#editbarleft { float: left; height: 100%; overflow: hidden;
+ background: url(/static/img/jun09/pad/editbar_background_left.gif) no-repeat left top; width: 2px; }
+#editbarright { float: right; height: 100%; overflow: hidden;
+ background: url(/static/img/jun09/pad/editbar_background_right.gif) no-repeat right top; width: 2px; }
+
+#editbartable
+{
+ position:absolute;
+ top: 6px;
+ left: 7px;
+ width: 250px;
+ height: 24px;
+ width:520px;
+}
+
+#editbarsavetable
+{
+ position:absolute;
+ top: 6px;
+ right: 7px;
+ height: 24px;
+ width:23px;
+}
+
+#editbarsavetable td, #editbartable td
+{
+ white-space: nowrap;
+}
+
+.editbarbutton
+{
+ border-top: 1px solid #8b9eba;
+ border-bottom: 1px solid #8b9eba;
+ border-left: 1px solid #758aa9;
+ background-color: white;
+}
+
+.editbarbutton img
+{
+ margin: 0px 2px;
+ border: 0px;
+ width: 16px;
+ height: 16px;
+}
+
+.editbarbutton a:active
+{
+ position: relative;
+ top: 1px;
+ left: 1px;
+}
+
+.editbargroupsfirst
+{
+ border-left-width: 0px !important;
+}
+
+#editbar #syncstatussyncing { position: absolute; height: 26px; width: 26px;
+ background: url(/static/img/jun09/pad/syncing2.gif) no-repeat center center;
+ right: 38px; top: 5px; display: none; }
+#editbar #syncstatusdone { position: absolute; height: 26px; width: 26px;
+ background: url(/static/img/jun09/pad/syncdone.gif) no-repeat center center;
+ right: 38px; top: 5px; display: none; }
+
+#editorcontainerbox {
+ border-left: 1px solid #c4c4c4; border-right: 1px solid #c4c4c4;
+ border-bottom: 1px solid #c4c4c4;
+ background: #fff; overflow: hidden; position: relative;
+ zoom: 1; height: 397px; /*...initially*/ }
+
+#editorcontainer { height: 100%; }
+
+#editorcontainer iframe { width: 100%; padding: 0; margin: 0; }
+
+#editorloadingbox { padding-top: 100px; padding-bottom: 100px; font-size: 2.5em; color: #aaa;
+ text-align: center; position: absolute; width: 100%; height: 30px; z-index: 100; }
+
+#padsidebar { float: right; width: 290px; }
+.hidesidebar #padsidebar { width: 0; overflow: hidden; }
+
+#padusers { border: 1px solid #c4c4c4; background: #fafafa; position: relative; zoom: 1; }
+
+#myuser { background: #d9e7f9; padding: 5px; height: 53px; position: relative; }
+#myswatchbox { position: absolute; left: 5px; top: 5px; width: 22px; height: 22px;
+ /*border-top: 1px solid #c3cfe0; border-left: 1px solid #c3cfe0;
+ border-right: 1px solid #ecf3fc; border-bottom: 1px solid #ecf3fc;*/
+ border: 1px solid #bbb;
+ padding: 1px; background: transparent; cursor: pointer; }
+#myuser .myswatchboxhoverable, #myuser .myswatchboxunhoverable {
+ background: white;
+}
+#myuser .myswatchboxhoverable:hover {
+ background: #bbb;
+}
+#myswatch { width: 100%; height: 100%; background: transparent;/*...initially*/ }
+#mycolorpicker {
+ background: url(/static/img/jun09/pad/colorpicker.gif) no-repeat left top;
+ width: 232px; height: 140px;
+ position: absolute;
+ left: 13px; top: 13px; z-index: 101;
+ display: none;/*...initially*/
+}
+#mycolorpicker .n1 { left: 13px; }
+#mycolorpicker .n2 { left: 40px; }
+#mycolorpicker .n3 { left: 67px; }
+#mycolorpicker .n4 { left: 94px; }
+#mycolorpicker .n5 { left: 121px; }
+#mycolorpicker .n6 { left: 148px; }
+#mycolorpicker .n7 { left: 175px; }
+#mycolorpicker .n8 { left: 202px; }
+
+#mycolorpicker .n9 { left: 13px; top: 34px ! important;}
+#mycolorpicker .n10 { left: 40px; top: 34px ! important;}
+#mycolorpicker .n11 { left: 67px; top: 34px ! important;}
+#mycolorpicker .n12 { left: 94px; top: 34px ! important;}
+#mycolorpicker .n13 { left: 121px; top: 34px ! important;}
+#mycolorpicker .n14 { left: 148px; top: 34px ! important;}
+#mycolorpicker .n15 { left: 175px; top: 34px ! important;}
+#mycolorpicker .n16 { left: 202px; top: 34px ! important;}
+
+#mycolorpicker .n17 { left: 13px; top: 56px ! important;}
+#mycolorpicker .n18 { left: 40px; top: 56px ! important;}
+#mycolorpicker .n19 { left: 67px; top: 56px ! important;}
+#mycolorpicker .n20 { left: 94px; top: 56px ! important;}
+#mycolorpicker .n21 { left: 121px; top: 56px ! important;}
+#mycolorpicker .n22 { left: 148px; top: 56px ! important;}
+#mycolorpicker .n23 { left: 175px; top: 56px ! important;}
+#mycolorpicker .n24 { left: 202px; top: 56px ! important;}
+
+#mycolorpicker .n25 { left: 13px; top: 78px ! important;}
+#mycolorpicker .n26 { left: 40px; top: 78px ! important;}
+#mycolorpicker .n27 { left: 67px; top: 78px ! important;}
+#mycolorpicker .n28 { left: 94px; top: 78px ! important;}
+#mycolorpicker .n29 { left: 121px; top: 78px ! important;}
+#mycolorpicker .n30 { left: 148px; top: 78px ! important;}
+#mycolorpicker .n31 { left: 175px; top: 78px ! important;}
+#mycolorpicker .n32 { left: 202px; top: 78px ! important;}
+
+#mycolorpicker .pickerswatchouter {
+ border: 1px solid white;
+ width: 15px; height: 15px; position: absolute;
+ top: 12px;
+}
+#mycolorpicker .pickerswatch {
+ border: 1px solid #999;
+ width: 13px;
+ height: 13px;
+ position: absolute;
+ left: 0; top: 0;
+}
+#mycolorpicker .picked { border: 1px solid #666 !important; }
+#mycolorpicker .picked .pickerswatch { border: 1px solid #666; }
+#mycolorpickersave { position: absolute; left: 14px; top: 102px;
+ width: 47px; height: 0; padding-top: 20px; overflow: hidden;
+ cursor: pointer; }
+#mycolorpickercancel { position: absolute; left: 87px; top: 102px;
+ width: 44px; height: 0; padding-top: 20px; overflow: hidden;
+ cursor: pointer; }
+#myusernameform { margin-left: 35px; }
+#myusernameedit { font-size: 1.6em; color: #444;
+ padding: 3px; height: 18px; margin: 0; border: 0;
+ width: 197px; background: transparent; }
+#myusernameform input.editable { border: 1px solid #bbb; }
+#myuser .myusernameedithoverable:hover { background: white; }
+#mystatusform { margin-left: 35px; margin-top: 5px; }
+#mystatusedit { font-size: 1.2em; color: #777;
+ font-style: italic; display: none;
+ padding: 2px; height: 14px; margin: 0; border: 1px solid #bbb;
+ width: 199px; background: transparent; }
+#myusernameform .editactive, #myusernameform .editempty {
+ background: white; border-left: 1px solid #c3c3c3;
+ border-top: 1px solid #c3c3c3;
+ border-right: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;
+}
+#myusernameform .editempty { color: #ef641e; }
+
+#otherusers {
+ height: 100px;/*...initially*/
+ overflow: auto;
+}
+
+table#otheruserstable { display: none; }
+#nootherusers { padding: 10px; font-size: 1.2em; color: #999; font-weight: bold;}
+#nootherusers a { color: #48d; }
+
+#otheruserstable td {
+ border-bottom: 1px solid #e1e1e1;
+ height: 26px;
+ vertical-align: middle;
+ padding: 0 2px;
+}
+
+#otheruserstable .swatch {
+ border: 1px solid #999; width: 13px; height: 13px; overflow: hidden;
+ margin: 0 4px;
+}
+
+.usertdswatch { width: 1%; }
+.usertdname { font-size: 1.3em; color: #444; }
+.usertdstatus { font-size: 1.1em; font-style: italic; color: #999; }
+.usertdactivity { font-size: 1.1em; color: #777; }
+
+.usertdname input { border: 1px solid #bbb; width: 80px; padding: 2px; }
+.usertdname input.editactive, .usertdname input.editempty {
+ background: white; border-left: 1px solid #c3c3c3;
+ border-top: 1px solid #c3c3c3;
+ border-right: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;
+}
+.usertdname input.editempty { color: #888; font-style: italic;}
+
+#userlistbuttonarea { height: 28px; position: relative;
+ background: url(/static/img/jun09/pad/inviteshare2.gif) repeat-x 0 0; }
+#sharebutton {
+ background: url(/static/img/jun09/pad/inviteshare2.gif) no-repeat 0 -31px;
+ position: absolute; display: block; top: 3px; padding-top: 23px;
+ height: 0; overflow: hidden; width: 96px; left: 96px; }
+
+ /*#guestslabel { font-size: 1.2em; position: absolute; width: auto;
+ height: 22px; line-height: 22px; top: 4px; left: 8px; }
+#guestsmenu { font-size: 1.2em; position: absolute; left: 100px;
+ top: 5px; width: 95px; }
+.guestpolicystuff { display: none; }*/
+
+.guestprompt { border: 1px solid #ccc; font-size: 1.2em;
+ padding: 5px; color: #222; background: #ffc; }
+.guestprompt .choices { float: right; }
+.guestprompt a { margin: 0 0.5em; }
+
+#hdraggie {
+ background: url(/static/img/jun09/pad/hdraggie.gif) repeat-x center top;
+ height: 10px; cursor: S-resize; }
+
+#padchat { border: 1px solid #c4c4c4; }
+
+#chattop { background: #ecf2fa; padding: 5px; font-size: 1.2em; border-bottom: 1px solid #ddd; }
+#chattop a { color: #36b; }
+#chatlines { height: 198px;/*...initially*/ overflow: auto; background: #fafafa; position: relative; }
+#chatlines .chatline { color: #444; padding-left: 5px; padding-top: 2px; padding-bottom: 2px;
+ background: #ddd; overflow: hidden; }
+#chatlines .chatlinetime { display: block; font-size: 1em; color: #666; float: right; width: auto;
+ padding-right: 5px; }
+#chatlines .chatlinename, #chatlines .chatlinetext { font-size: 1.2em; }
+#chatlines h2 { margin: 0; padding-left: 5px; padding-top: 2px; padding-bottom: 2px; color: #999; font-style: italic; font-weight: bold; font-size: 1.2em; }
+#chatbottom { background: #ecf2fa; padding: 4px; }
+#chatprompt { font-size: 1.2em; color: #444; float: left; line-height: 22px; width: 35px; text-align: right; }
+#chatentryform { margin-left: 40px; }
+#chatentrybox { font-size: 1.2em; color: #444;
+ padding: 2px; height: 16px; margin: 0; border-left: 1px solid #c3c3c3;
+ border-top: 1px solid #c3c3c3;
+ border-right: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;
+ width: 230px; }
+#padchat a#chatloadmore { display: none; font-size: 1.2em; padding: 2px 5px; font-style: italic; }
+#padchat #chatloadingmore { display: none; font-size: 1.2em; padding: 2px 5px; font-style: italic;
+ color: #999; }
+#padchat a#chatloadmore:focus { outline: 0; }
+
+#djs { font-family: monospace; font-size: 10pt;
+ height: 200px; overflow: auto; border: 1px solid #ccc;
+ background: #fee; margin: 0; padding: 6px;
+}
+#djs p { margin: 0; padding: 0; display: block; }
+
+#connectionbox {
+ position: absolute; left: 0; top: 0; width: 100%;
+ height: 191px;/*...initially; #padusers height */
+ z-index: 10; zoom: 1; overflow: hidden;
+}
+#connectionboxinner {
+ position: relative; width: 100%; height: 100%; overflow: hidden;
+}
+.cboxconnecting #connectionboxinner {
+ background: #ffd url(/static/img/jun09/pad/connectingbar.gif) no-repeat center 60px;
+}
+.cboxreconnecting #connectionboxinner {
+ background: #fed url(/static/img/jun09/pad/connectingbar.gif) no-repeat center 60px;
+}
+.cboxdisconnected #connectionboxinner {
+ background: #fdd;
+}
+.cboxdisconnected #connectionboxinner div { display: none; }
+.cboxdisconnected_userdup #connectionboxinner #disconnected_userdup { display: block; }
+.cboxdisconnected_initsocketfail #connectionboxinner #disconnected_initsocketfail { display: block; }
+.cboxdisconnected_looping #connectionboxinner #disconnected_looping { display: block; }
+.cboxdisconnected_slowcommit #connectionboxinner #disconnected_slowcommit { display: block; }
+.cboxdisconnected_unauth #connectionboxinner #disconnected_unauth { display: block; }
+.cboxdisconnected_unknown #connectionboxinner #disconnected_unknown { display: block; }
+.cboxdisconnected_initsocketfail #connectionboxinner #reconnect_advise,
+.cboxdisconnected_looping #connectionboxinner #reconnect_advise,
+.cboxdisconnected_slowcommit #connectionboxinner #reconnect_advise,
+.cboxdisconnected_unknown #connectionboxinner #reconnect_advise { display: block; }
+.cboxdisconnected div#reconnect_form { display: block; }
+.cboxdisconnected .disconnected h2 { display: none; }
+.cboxdisconnected .disconnected .h2_disconnect { display: block; }
+.cboxdisconnected_userdup .disconnected h2.h2_disconnect { display: none; }
+.cboxdisconnected_userdup .disconnected h2.h2_userdup { display: block; }
+.cboxdisconnected_unauth .disconnected h2.h2_disconnect { display: none; }
+.cboxdisconnected_unauth .disconnected h2.h2_unauth { display: block; }
+
+#connectionstatus {
+ position: absolute; width: 37px; height: 32px; overflow: hidden;
+ right: 0;
+ z-index: 11;
+}
+#connectionboxinner .connecting {
+ margin-top: 20px;
+ font-size: 2.0em; color: #555;
+ text-align: center; display: none;
+}
+.cboxconnecting #connectionboxinner .connecting { display: block; }
+
+#connectionboxinner .disconnected h2 {
+ font-size: 1.8em; color: #333;
+ text-align: left;
+ margin-top: 10px; margin-left: 10px; margin-right: 10px;
+ margin-bottom: 10px;
+}
+#connectionboxinner .disconnected p {
+ margin: 10px 10px;
+ font-size: 1.2em;
+ line-height: 1.1;
+ color: #333;
+}
+#connectionboxinner .disconnected { display: none; }
+.cboxdisconnected #connectionboxinner .disconnected { display: block; }
+
+#connectionboxinner .reconnecting {
+ margin-top: 20px;
+ font-size: 1.6em; color: #555;
+ text-align: center; display: none;
+}
+.cboxreconnecting #connectionboxinner .reconnecting { display: block; }
+
+#reconnect_form button {
+ position: relative; width: 268px; height: 28px; left: 10px;
+ font-size: 12pt;
+}
+
+/* We give docbar a higher z-index than its descendant impexp-wrapper in
+ order to allow the Import/Export panel to be on top of stuff lower
+ down on the page in IE. Strange but it works! */
+#docbar { z-index: 52; }
+
+#impexp-wrapper { width: 500px; right: 10px; }
+#impexp-panel { height: 160px; }
+.docbarimpexp-closing #impexp-wrapper { z-index: 50; }
+
+#savedrevs-wrapper { width: 100%; left: 0; }
+#savedrevs-panel { height: 79px; }
+.docbarsavedrevs-closing #savedrevs-wrapper { z-index: 50; }
+#savedrevs-wrapper .dbpanel-rightedge { background-position: 0 -10px; }
+
+#options-wrapper { width: 340px; right: 200px; }
+#options-panel { height: 114px; }
+.docbaroptions-closing #options-wrapper { z-index: 50; }
+
+#security-wrapper { width: 320px; right: 300px; }
+#security-panel { height: 130px; }
+.docbarsecurity-closing #security-wrapper { z-index: 50; }
+
+#revision-notifier { position: absolute; right: 8px; top: 25px;
+ width: auto; height: auto; font-size: 1.2em; background: #ffc;
+ border: 1px solid #aaa; color: #444; padding: 3px 5px;
+ display: none; z-index: 55; }
+#revision-notifier .label { color: #777; font-weight: bold; }
+
+/* We don't ever actually hide the wrapper, even when the panel is
+ cloased, so that its contents can always be manipulated accurately. */
+.dbpanel-wrapper { position: absolute;
+ overflow: hidden; /* animated: */ height: 0; top: 25px; /* /animated */
+ z-index: 51; zoom: 1; }
+.dbpanel-panel { position: absolute; bottom: 0; width: 100%; }
+
+.dbpanel-middle { margin-left: 7px; margin-right: 7px;
+ position: relative; height: 100%; overflow: hidden; zoom: 1; }
+.dbpanel-inner { background: #f7f7f7 /* covered up by images */;
+ width: 100%; height: 100%; position: absolute; overflow: hidden; top: -10px; }
+
+.dbpanel-top { position: absolute; top: 0; width: 100%;
+ height: 400px; background-image: url(/static/img/jun09/pad/docpanelmiddle2.png);
+ background-position: left top; }
+
+.dbpanel-bottom { position: absolute; height: 400px;
+ bottom: -390px; width: 100%;
+ background-image: url(/static/img/jun09/pad/docpanelmiddle2.png);
+ background-position: left top;
+}
+
+* html .dbpanel-top, * html .dbpanel-bottom { /* for IE 6+ */
+ background-color: transparent;
+ background-image: url(/static/img/apr09/blank.gif);
+ /* scale the image instead of repeating, but it amounts to the same */
+ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/static/img/jun09/pad/docpanelmiddle2.png", sizingMethod="scale");
+}
+
+.dbpanel-leftedge, .dbpanel-rightedge, .dbpanel-botleftcorner, .dbpanel-botrightcorner {
+ position: absolute;
+ background-repeat: no-repeat;
+ background-color: transparent;
+ background-image: url(/static/img/jun09/pad/docpaneledge2.png);
+}
+
+.dbpanel-leftedge, .dbpanel-rightedge { height: 100%; width: 7px; bottom: 11px; }
+.dbpanel-botleftcorner, .dbpanel-botrightcorner { height: 11px; width: 7px; bottom: 0; }
+
+.dbpanel-leftedge, .dbpanel-botleftcorner { left: 0; background-position: -7px 0; }
+.dbpanel-rightedge, .dbpanel-botrightcorner { right: 0; background-position: 0 0; }
+
+#importexport { position: absolute; top: 5px; left: 0; font-size: 1.2em; color: #444;
+ height: 100%; width: 100%; }
+
+* html .dbpanel-leftedge, * html .dbpanel-rightedge, * html .dbpanel-botleftcorner, * html .dbpanel-botrightcorner {
+ background-color: transparent;
+ background-image: url(/static/img/apr09/blank.gif);
+ /* crop the image */
+ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/static/img/jun09/pad/docpaneledge2.png", sizingMethod="crop");
+}
+* html .dbpanel-leftedge, * html .dbpanel-botleftcorner { left: -7px; width: 14px; }
+
+#impexp-importlabel { position: absolute; top: 5px; left: 10px; width: 300px; }
+
+#importform { position: absolute; top: 24px; left: 5px; width: 300px; height: 60px; }
+#importformsubmitdiv, #importformfilediv { padding: 5px 5px; }
+#importexport .importformenabled {
+ background: #cfc;
+ border: 1px solid #292;
+}
+#importexport span.nowrap { white-space: nowrap; }
+#importexport #importstatusball { margin-left: 3px; padding-top: 1px; display: none; }
+#importexport #importarrow { margin-left: 5px; padding-top: 1px; display: none; }
+#importexport .importmessage { border: 1px solid #992;
+ background: #ffc; padding: 5px; font-size: 85%; display: none; }
+#importexport #importmessagefail { margin-top: 5px; }
+#importexport #importmessagesuccess { margin: 0 20px; }
+#importexport a.disabledexport {
+ color: #333; text-decoration: none;
+ opacity: 0.5; filter: alpha(opacity = 50) /*IE*/;
+}
+#importexport #importfileinput { padding: 2px 0; }
+#importexport #importsubmitinput { padding: 2px; }
+
+#impexp-divider { position: absolute; left: 320px; top: 5px; height: 135px; width: 2px;
+ background: #ddd; }
+#impexp-close { display: block; position: absolute; right: 2px; bottom: 15px;
+ width: auto; height: auto; font-size: 85%; color: #444;
+ z-index: 61 /* > clickcatcher */}
+#impexp-disabled-clickcatcher {
+ display: none;
+ position: absolute; width: 100%; height: 100%;
+ z-index: 60;
+}
+
+#impexp-exportlabel { position: absolute; top: 5px; left: 350px;
+ width: 300px; }
+#exportlinks .exportlink {
+ display: block; position: absolute; height: 22px; width: auto;
+ background-repeat: no-repeat;
+ background-image: url(/static/img/jun09/pad/fileicons.gif);
+ line-height: 22px; padding-left: 22px; padding-right: 2px;
+}
+#exportlinks .n1 { left: 350px; top: 30px; }
+#exportlinks .n2 { left: 350px; top: 57px; }
+#exportlinks .n3 { left: 350px; top: 84px; }
+#exportlinks .n4 { left: 485px; top: 30px; }
+#exportlinks .n5 { left: 485px; top: 57px; }
+#exportlinks .n6 { left: 485px; top: 84px; }
+#exportlinks .exporthrefdoc { background-position: 2px -1px; }
+#exportlinks .exporthrefhtml { background-position: 2px -25px; }
+#exportlinks .exporthreflink { background-position: 2px -49px; }
+#exportlinks .exporthrefodt { background-position: 2px -73px; }
+#exportlinks .exporthrefpdf { background-position: 2px -97px; }
+#exportlinks .exporthreftxt { background-position: 2px -121px; }
+
+#savedrevisions { position: absolute; top: 0; left: 0; font-size: 1.2em;
+ color: #444; height: 100%; width: 100%; }
+#savedrevs-scrolly { height: 75px; width: auto; margin-right: 136px;
+ overflow: hidden; position: relative; top: 1px;
+}
+#savedrevs-scrollleft { height: 100%; width: 14px; position: absolute;
+ left: 0; top: 0; cursor: pointer;
+ background: url(/static/img/jun09/pad/savedrevarrows.gif) no-repeat right top;
+}
+#savedrevs-scrollright { height: 100%; width: 14px; position: absolute;
+ right: 0; top: 0; cursor: pointer;
+ background: url(/static/img/jun09/pad/savedrevarrows.gif) no-repeat left top;
+}
+#savedrevs-scrolly .disabledscrollleft { background-position: right bottom; }
+#savedrevs-scrolly .disabledscrollright { background-position: left bottom; }
+#savedrevs-scrollouter { margin-left: 14px; margin-right: 14px;
+ width: auto; height: 100%; overflow: hidden; position: relative;
+}
+#savedrevs-scrollinner { position: absolute; width: 1px; height: 100%;
+ overflow: visible; right: 0/*...initially*/; top: 0; }
+#savedrevisions .srouterbox { width: 120px; height: 100%;
+ position: absolute; top: 0;
+}
+#savedrevisions .srinnerbox { position: relative; top: 8px;
+ height: 59px; width: auto; border-left: 1px solid #ddd;
+ padding: 0 8px 0 8px; }
+#savedrevisions a.srname { display: block; white-space: nowrap;
+ text-overflow: ellipsis /*no FF support*/; overflow: hidden;
+ text-decoration: none; color: #444; cursor: text;
+ padding: 1px; height: 14px; position: relative; left: -1px;
+ width: 100px /*specify for proper overflow in IE*/;
+}
+#savedrevisions a.srname:hover { text-decoration: none; color: #444;
+ border: 1px solid #ccc; padding: 0; }
+#savedrevisions .sractions { font-size: 85%; color: #ccc;
+ margin-top: 1px; height: 12px; }
+#savedrevisions .sractions a { text-decoration: none;
+ color: #06c; }
+#savedrevisions .sractions a:hover { text-decoration: underline; }
+#savedrevisions .srtime { color: #666; font-size: 90%;
+ white-space: nowrap; margin-top: 3px; }
+#savedrevisions .srauthor { color: #666; font-size: 90%;
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis /*no FF*/;
+}
+#savedrevisions .srtwirly { position: absolute; display: block;
+ bottom: 0; right: 10px; display: none; }
+#savedrevisions .srnameedit {
+ position: absolute;
+}
+#savedrevs-savenow { display: block; position: absolute;
+ overflow: hidden; height: 0; padding-top: 24px; width: 81px;
+ top: 22px; right: 27px;
+ background: url(/static/img/jun09/pad/savedrevsgfx2.gif) no-repeat 0 0;
+}
+#savedrevs-savenow:active { background-position: 0 -24px; }
+#savedrevs-close { display: block; position: absolute; right: 7px; bottom: 8px;
+ width: auto; height: auto; font-size: 85%; color: #444; }
+form#reconnectform { display: none; }
+
+#padoptions { position: absolute; top: 0; left: 0; font-size: 1.2em;
+ color: #444; height: 100%; width: 100%; line-height: 15px; }
+#options-viewhead { font-weight: bold; position: absolute; top: 10px; left: 15px;
+ width: auto; height: auto; }
+#padoptions label { display: block; }
+#padoptions input { padding: 0; margin: 0; }
+#options-colorscheck { position: absolute; left: 15px; top: 34px; width: 15px; height: 15px; }
+#options-colorslabel { position: absolute; left: 35px; top: 34px; }
+#options-linenoscheck { position: absolute; left: 15px; top: 57px; width: 15px; height: 15px; }
+#options-linenoslabel { position: absolute; left: 35px; top: 57px; }
+#options-fontlabel { position: absolute; left: 15px; top: 82px; }
+#viewfontmenu { position: absolute; top: 80px; left: 90px; width: 110px; }
+#options-viewexplain { position: absolute; left: 215px; top: 15px; width: 100px; height: 70px;
+ padding-left: 10px; padding-top: 10px; border-left: 1px solid #ccc;
+ line-height: 20px; font-weight: bold; color: #999; }
+#options-close { display: block; position: absolute; right: 7px; bottom: 8px;
+ width: auto; height: auto; font-size: 85%; color: #444; }
+
+#padsecurity { position: absolute; top: 0; left: 0; font-size: 1.2em;
+ color: #444; height: 100%; width: 100%; line-height: 15px; }
+#security-close { display: block; position: absolute; right: 7px; bottom: 8px;
+ width: auto; height: auto; font-size: 85%; color: #444; }
+#security-passhead { font-weight: bold; position: absolute; top: 90px; left: 15px;
+ width: auto; height: auto; }
+#security-passbody { position: absolute; left: 75px; top: 90px; }
+#security-passwordedit { height: 15px; border: 1px solid #bbb;
+ position: absolute; top: 0; left: 15px; width: 120px; }
+#security-password a { text-decoration: none; display: block;
+ width: auto; height: auto; }
+#password-savelink, #password-cancellink {position: absolute; top: 0; }
+#security-password a:hover { text-decoration: underline; }
+#password-savelink { left: 144px; color: #06c; }
+#password-cancellink { left: 180px; color: #666; }
+#password-nonedit { left: 15px; position: absolute;
+ width: 220px; top: 0; }
+#password-setlink { color: #06c; }
+#password-clearlink { color: #06c; }
+#password-display { height: 15px; width: auto; }
+#password-inedit { display: none; }
+#password-display, #password-setlink, #password-clearlink {
+ float: left; margin-right: 10px;
+}
+#password-display { font-size: 18px; }
+#security-password .nopassword #password-display { font-size: 100%; }
+#security-password .nopassword #password-clearlink { display: none; }
+#security-password .nopassword #password-setlink { left: 60px; }
+
+#security-access { position: absolute; left: 15px; width: 200px; }
+#security-accesshead { font-weight: bold; position: absolute; top: 10px;
+ left: 0; width: auto; height: auto; }
+#security-access input, #security-access label { position: absolute; }
+#security-access input { left: 10px; }
+#security-access label { left: 30px; width: 250px; }
+#access-private, #access-private-label { top: 35px; }
+#access-public, #access-public-label { top: 60px; }
+#security-access label { color: #999; }
+#security-access label strong { font-weight: normal; padding-right: 10px;
+ color: #444; }
+
+#mainmodals { z-index: 600; /* higher than the modals themselves
+ so that modals are on top in IE */ }
+
+.modalfield { font-size: 1.2em; padding: 1px; border: 1px solid #bbb;
+ position: absolute;}
+#mainmodals .editempty { color: #aaa; }
+
+<% feedbackbox = {width:400, height:270}; %>
+#feedbackbox {
+ position: absolute; display: none;
+ width: <%=feedbackbox.width%>px; height: <%=feedbackbox.height%>px;
+ left: 100px/*set in code*/; bottom: 50px;
+ z-index: 501; zoom: 1;
+}
+#feedbackbox-tl, #feedbackbox-tr, #feedbackbox-bl, #feedbackbox-br,
+#feedbackbox-hide, #feedbackbox-send, #feedbackbox-back {
+ position: absolute; display: block;
+ background-repeat: no-repeat;
+ background-image: url(/static/img/jun09/pad/feedbackbox2.gif);
+}
+#feedbackbox-tl { width: <%=feedbackbox.width-8%>px;
+ height: <%=feedbackbox.height-8%>px; left: 0; top: 0;
+ background-position: left top; }
+#feedbackbox-tr { width: 8px; height: <%=feedbackbox.height-8%>px;
+ right: 0; top: 0; background-position: right top; }
+#feedbackbox-bl { width: <%=feedbackbox.width-8%>px;
+ height: 8px; left: 0; bottom: 0;
+ background-position: left bottom; }
+#feedbackbox-br { width: 8px; height: 8px; bottom: 0; right: 0;
+ background-position: right bottom; }
+#feedbackbox-hide { width: 22px; height: 22px; right: 9px; top: 7px;
+ background-position: -569px -6px;
+}
+#feedbackbox-back { width: <%=feedbackbox.width-16%>px;
+ height: <%=feedbackbox.height-16%>px; left: 8px; top: 8px;
+ background-position: -8px -8px;
+ background-color: white; }
+#feedbackbox-contents { width: <%=feedbackbox.width-16%>px;
+ height: <%=feedbackbox.height-16%>px; left: 8px; top: 8px;
+ position: absolute; font-size: 1.4em; color: #444; }
+#feedbackbox-contentsinner { padding: 10px; }
+#feedbackbox-send { width: 50px; height: 22px; right: 15px; bottom: 15px;
+ background-position: -535px -363px;
+}
+#feedbackbox-email { left: 90px; top: 48px; width: 356px; height: auto; }
+#feedbackbox-message { left: 90px; top: 84px; width: 358px; height: 100px; }
+#feedbackbox-response { position: absolute; bottom: 15px; left: 15px;
+ width: 390px; height: auto; font-size: 1.2em; display: none; }
+#feedbackbox .goodresponse { font-weight: bold; color: green; }
+#feedbackbox .badresponse { font-weight: bold; color: red; }
+#feedbackbox p { margin-bottom: 1em; }
+#feedbackbox ul { margin: 1em 0 1em 2em }
+#feedbackbox li { padding: 0.3em 0; }
+#feedbackbox li a { display: block; font-weight: bold; }
+#feedbackbox li a:hover { background: #ffe; }
+#feedbackbox a, #feedbackbox li a:visited { color: #47b; }
+#feedbackbox tt { font-size: 110%; }
+
+<% var shareboxfull = {width:485, height:326}; %>
+#sharebox {
+ position: absolute;
+ width: 485px;
+ left: 300px/*set in code*/; top: 100px; display: none;
+ z-index: 501; zoom: 1;
+ overflow: hidden;
+ background: white; border: 1px solid #999;
+}
+#sharebox { height: 160px/*set in code*/; }
+.nonprouser #sharebox { height: 110px/*set in code*/; }
+#sharebox-inner { width: 100%; }
+#sharebox-forms { position: absolute; top: 50px; width: 100%; }
+#sharebox-hide, #sharebox-send {
+ position: absolute; background-repeat: no-repeat;
+ background-image: url(/static/img/jun09/pad/sharebox4.gif);
+}
+#sharebox-hide, #sharebox-send { display: block; }
+#sharebox-hide { width: 22px; height: 22px; right: 9px; top: 7px;
+ background-position: <%= -(shareboxfull.width-31) %>px -6px;
+}
+#sharebox-send { width: 87px; height: 22px; right: 15px; top: <%= shareboxfull.height-22-15 %>px;
+ background-position: <%= -(shareboxfull.width-87-15) %>px <%= -(shareboxfull.height-22-15) %>px;
+}
+#sharebox-url { position: absolute; left: 20px; top: 42px; width: 440px; height: 18px;
+ text-align: left; font-size: 1.3em; line-height: 18px; padding: 2px; }
+
+#sharebox-to { left: 90px; top: 117px; height: auto; width: 378px; background: #ffe; }
+#sharebox-subject { left: 90px; top: 150px; height: auto; width: 378px; font-weight: bold; }
+#sharebox-message { left: 90px; top: 182px; width: 380px; height: 90px; }
+#sharebox-response { position: absolute; bottom: 15px; left: 15px;
+ width: 350px; height: auto; font-size: 1.2em; display: none; }
+#sharebox .goodresponse { font-weight: bold; color: green; }
+#sharebox .badresponse { font-weight: bold; color: red; }
+#sharebox-dislink { position: absolute; left: 12px; top: 78px;
+ height: 22px; width: 220px; cursor: pointer;
+ background-image: url(/static/img/jun09/pad/sharedistri.gif);
+ background-repeat: no-repeat;
+ background-position: 0 5px;
+}
+.sharebox-open #sharebox-dislink { background-position: 0 -28px; }
+#sharebox-shownwhenexpanded { display: none; }
+.sharebox-open #sharebox-shownwhenexpanded { display: block; }
+
+#sharebox-pastelink { font-size: 155%; font-weight: bold;
+ top: 13px; left: 17px; position: absolute; color: #444; }
+#sharebox-orsend { font-size: 145%; font-weight: bold;
+ top: 80px; left: 31px; position: absolute; color: #444; }
+#sharebox-fieldname-to, #sharebox-fieldname-subject, #sharebox-fieldname-message {
+ position: absolute; font-weight: bold; font-size: 125%;
+ left: 15px; color: #222;
+}
+#sharebox-fieldname-to { top: 119px; }
+#sharebox-fieldname-subject { top: 152px; }
+#sharebox-fieldname-message { top: 183px; }
+
+#sharebox-stripe { position: absolute; left: 10px;
+ width: 436px; top: 8px; height: 45px; line-height: 1.2; }
+#sharebox-stripe div { padding: 5px; font-size: 130%; }
+#sharebox-stripe strong { font-weight: bold; }
+.sharebox-stripe-public { background: #cfc; }
+.sharebox-stripe-private { background: #fec; }
+.sharebox-stripe-public .private { display: none; }
+.sharebox-stripe-private .public { display: none; }
+#sharebox-stripe a { color: #06c; }
+
+.nonprouser #sharebox-stripe { display: none; }
+.nonprouser #sharebox-forms { top: 0; }
+
+#viewbarcontents { display: none; }
+#viewzoomtitle {
+ position: absolute; left: 10px; top: 4px; height: 20px; line-height: 20px;
+ width: auto;
+}
+#viewzoommenu {
+ position: absolute; top: 3px; left: 50px;
+ width: 65px;
+}
+#bottomarea { height: 28px; overflow: hidden; position: relative;
+ font-size: 1.2em; color: #444; }
+#widthprefcheck { position: absolute;
+ background-image: url(/static/img/jun09/pad/layoutbuttons.gif);
+ background-repeat: no-repeat; cursor: pointer;
+ width: 86px; height: 20px; top: 4px; right: 2px; }
+.widthprefunchecked { background-position: -1px -1px; }
+.widthprefchecked { background-position: -1px -23px; }
+#sidebarcheck { position: absolute;
+ background-image: url(/static/img/jun09/pad/layoutbuttons.gif);
+ background-repeat: no-repeat; cursor: pointer;
+ width: 86px; height: 20px; top: 4px; right: 90px; }
+.sidebarunchecked { background-position: -1px -45px; }
+.sidebarchecked { background-position: -1px -67px; }
+#feedbackbutton { display: block; position: absolute; width: 68px;
+ height: 0; padding-top: 17px; overflow: hidden;
+ background: url(/static/img/jun09/pad/bottomareagfx.gif);
+ top: 5px; right: 220px;
+}
+
+#modaloverlay {
+ z-index: 500; display: none;
+ background-image: url(/static/img/jun09/pad/overlay2.png);
+ background-repeat: repeat-both;
+ width: 100%; position: absolute;
+ height: 400px; left: 0; top: 0;
+}
+
+* html #modaloverlay { /* for IE 6+ */
+ opacity: 1; /* in case this is looked at */
+ background-image: none;
+ background-repeat: no-repeat;
+ /* scale the image */
+ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/static/img/jun09/pad/overlay2.png", sizingMethod="scale");
+}
diff --git a/trunk/etherpad/src/static/css/pro-signup.css b/etherpad/src/static/css/pro-signup.css
index b58d86d..b58d86d 100644
--- a/trunk/etherpad/src/static/css/pro-signup.css
+++ b/etherpad/src/static/css/pro-signup.css
diff --git a/trunk/etherpad/src/static/css/pro/account.css b/etherpad/src/static/css/pro/account.css
index 212a847..212a847 100644
--- a/trunk/etherpad/src/static/css/pro/account.css
+++ b/etherpad/src/static/css/pro/account.css
diff --git a/trunk/etherpad/src/static/css/pro/framedpage-pro.css b/etherpad/src/static/css/pro/framedpage-pro.css
index cffa58b..cffa58b 100644
--- a/trunk/etherpad/src/static/css/pro/framedpage-pro.css
+++ b/etherpad/src/static/css/pro/framedpage-pro.css
diff --git a/trunk/etherpad/src/static/css/pro/padlist.css b/etherpad/src/static/css/pro/padlist.css
index 13d3171..13d3171 100644
--- a/trunk/etherpad/src/static/css/pro/padlist.css
+++ b/etherpad/src/static/css/pro/padlist.css
diff --git a/trunk/etherpad/src/static/css/pro/pro-admin.css b/etherpad/src/static/css/pro/pro-admin.css
index e7462c9..e7462c9 100644
--- a/trunk/etherpad/src/static/css/pro/pro-admin.css
+++ b/etherpad/src/static/css/pro/pro-admin.css
diff --git a/trunk/etherpad/src/static/css/pro/pro-home.css b/etherpad/src/static/css/pro/pro-home.css
index 03f163a..03f163a 100644
--- a/trunk/etherpad/src/static/css/pro/pro-home.css
+++ b/etherpad/src/static/css/pro/pro-home.css
diff --git a/trunk/etherpad/src/static/favicon.ico b/etherpad/src/static/favicon.ico
index a833c3a..a833c3a 100644
--- a/trunk/etherpad/src/static/favicon.ico
+++ b/etherpad/src/static/favicon.ico
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/home-createpad.png b/etherpad/src/static/img/davy/bg/home-createpad.png
index e34e643..e34e643 100644
--- a/trunk/etherpad/src/static/img/davy/bg/home-createpad.png
+++ b/etherpad/src/static/img/davy/bg/home-createpad.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/product.png b/etherpad/src/static/img/davy/bg/product.png
index 5a6f6f2..5a6f6f2 100644
--- a/trunk/etherpad/src/static/img/davy/bg/product.png
+++ b/etherpad/src/static/img/davy/bg/product.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/createpad-small.gif b/etherpad/src/static/img/davy/btn/createpad-small.gif
index 5df6502..5df6502 100644
--- a/trunk/etherpad/src/static/img/davy/btn/createpad-small.gif
+++ b/etherpad/src/static/img/davy/btn/createpad-small.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/backgrad.gif b/etherpad/src/static/img/jun09/pad/backgrad.gif
index 8fee1a5..8fee1a5 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/backgrad.gif
+++ b/etherpad/src/static/img/jun09/pad/backgrad.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/colorpicker.gif b/etherpad/src/static/img/jun09/pad/colorpicker.gif
new file mode 100644
index 0000000..effa3cc
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/colorpicker.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/connectingbar.gif b/etherpad/src/static/img/jun09/pad/connectingbar.gif
index 34f54e9..34f54e9 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/connectingbar.gif
+++ b/etherpad/src/static/img/jun09/pad/connectingbar.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/docpaneledge2.png b/etherpad/src/static/img/jun09/pad/docpaneledge2.png
index c119c74..c119c74 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/docpaneledge2.png
+++ b/etherpad/src/static/img/jun09/pad/docpaneledge2.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/docpanelmiddle2.png b/etherpad/src/static/img/jun09/pad/docpanelmiddle2.png
index d251c23..d251c23 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/docpanelmiddle2.png
+++ b/etherpad/src/static/img/jun09/pad/docpanelmiddle2.png
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_background.gif b/etherpad/src/static/img/jun09/pad/editbar_background.gif
new file mode 100644
index 0000000..54ef6e4
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_background.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_background_left.gif b/etherpad/src/static/img/jun09/pad/editbar_background_left.gif
new file mode 100644
index 0000000..fe8d06e
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_background_left.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_background_right.gif b/etherpad/src/static/img/jun09/pad/editbar_background_right.gif
new file mode 100644
index 0000000..55ab00a
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_background_right.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_bold.gif b/etherpad/src/static/img/jun09/pad/editbar_bold.gif
new file mode 100644
index 0000000..d22bcaf
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_bold.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_clearauthorship.gif b/etherpad/src/static/img/jun09/pad/editbar_clearauthorship.gif
new file mode 100644
index 0000000..2c6d109
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_clearauthorship.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_groupleft.gif b/etherpad/src/static/img/jun09/pad/editbar_groupleft.gif
new file mode 100644
index 0000000..3e18749
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_groupleft.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_groupright.gif b/etherpad/src/static/img/jun09/pad/editbar_groupright.gif
new file mode 100644
index 0000000..bf8b757
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_groupright.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_indent.gif b/etherpad/src/static/img/jun09/pad/editbar_indent.gif
new file mode 100644
index 0000000..989523a
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_indent.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_insertunorderedlist.gif b/etherpad/src/static/img/jun09/pad/editbar_insertunorderedlist.gif
new file mode 100644
index 0000000..b032d59
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_insertunorderedlist.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_italic.gif b/etherpad/src/static/img/jun09/pad/editbar_italic.gif
new file mode 100644
index 0000000..a017402
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_italic.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_outdent.gif b/etherpad/src/static/img/jun09/pad/editbar_outdent.gif
new file mode 100644
index 0000000..4b9bf38
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_outdent.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_redo.gif b/etherpad/src/static/img/jun09/pad/editbar_redo.gif
new file mode 100644
index 0000000..826a254
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_redo.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_save.gif b/etherpad/src/static/img/jun09/pad/editbar_save.gif
new file mode 100644
index 0000000..2ccced6
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_save.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_strikethrough.gif b/etherpad/src/static/img/jun09/pad/editbar_strikethrough.gif
new file mode 100644
index 0000000..92ffa23
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_strikethrough.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_underline.gif b/etherpad/src/static/img/jun09/pad/editbar_underline.gif
new file mode 100644
index 0000000..ec3cc4e
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_underline.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/editbar_undo.gif b/etherpad/src/static/img/jun09/pad/editbar_undo.gif
new file mode 100644
index 0000000..78ae0be
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/editbar_undo.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/editbarback.gif b/etherpad/src/static/img/jun09/pad/editbarback.gif
index ab51802..ab51802 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/editbarback.gif
+++ b/etherpad/src/static/img/jun09/pad/editbarback.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/feedbackbox2.gif b/etherpad/src/static/img/jun09/pad/feedbackbox2.gif
index f1b8f5b..f1b8f5b 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/feedbackbox2.gif
+++ b/etherpad/src/static/img/jun09/pad/feedbackbox2.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/fileicons.gif b/etherpad/src/static/img/jun09/pad/fileicons.gif
index 26f6388..26f6388 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/fileicons.gif
+++ b/etherpad/src/static/img/jun09/pad/fileicons.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/hdraggie.gif b/etherpad/src/static/img/jun09/pad/hdraggie.gif
index 0a6fe3e..0a6fe3e 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/hdraggie.gif
+++ b/etherpad/src/static/img/jun09/pad/hdraggie.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/icon_import_export.gif b/etherpad/src/static/img/jun09/pad/icon_import_export.gif
new file mode 100644
index 0000000..1b77245
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/icon_import_export.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/icon_pad_options.gif b/etherpad/src/static/img/jun09/pad/icon_pad_options.gif
new file mode 100644
index 0000000..68c79a7
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/icon_pad_options.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/icon_saved_revisions.gif b/etherpad/src/static/img/jun09/pad/icon_saved_revisions.gif
new file mode 100644
index 0000000..8040145
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/icon_saved_revisions.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/icon_security.gif b/etherpad/src/static/img/jun09/pad/icon_security.gif
new file mode 100644
index 0000000..9131fc3
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/icon_security.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/icon_time_slider.gif b/etherpad/src/static/img/jun09/pad/icon_time_slider.gif
new file mode 100644
index 0000000..5e4b4ab
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/icon_time_slider.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/inviteshare.gif b/etherpad/src/static/img/jun09/pad/inviteshare.gif
index 55345e5..55345e5 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/inviteshare.gif
+++ b/etherpad/src/static/img/jun09/pad/inviteshare.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/inviteshare2.gif b/etherpad/src/static/img/jun09/pad/inviteshare2.gif
index 98d4c85..98d4c85 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/inviteshare2.gif
+++ b/etherpad/src/static/img/jun09/pad/inviteshare2.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/layoutbuttons.gif b/etherpad/src/static/img/jun09/pad/layoutbuttons.gif
index ea43432..ea43432 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/layoutbuttons.gif
+++ b/etherpad/src/static/img/jun09/pad/layoutbuttons.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/ok_or_cancel.gif b/etherpad/src/static/img/jun09/pad/ok_or_cancel.gif
new file mode 100644
index 0000000..76ba692
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/ok_or_cancel.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/overlay2.png b/etherpad/src/static/img/jun09/pad/overlay2.png
index c3d3f1c..c3d3f1c 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/overlay2.png
+++ b/etherpad/src/static/img/jun09/pad/overlay2.png
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/padtop5.gif b/etherpad/src/static/img/jun09/pad/padtop5.gif
new file mode 100644
index 0000000..e6e071d
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/padtop5.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/padtop5.png b/etherpad/src/static/img/jun09/pad/padtop5.png
new file mode 100644
index 0000000..22a0db7
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/padtop5.png
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/padtop5.xcf b/etherpad/src/static/img/jun09/pad/padtop5.xcf
new file mode 100644
index 0000000..c0bf7e4
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/padtop5.xcf
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/padtopback2.gif b/etherpad/src/static/img/jun09/pad/padtopback2.gif
new file mode 100644
index 0000000..db46567
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/padtopback2.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/public.gif b/etherpad/src/static/img/jun09/pad/public.gif
new file mode 100644
index 0000000..ac3093b
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/public.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/roundcorner_left.gif b/etherpad/src/static/img/jun09/pad/roundcorner_left.gif
new file mode 100644
index 0000000..000de75
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/roundcorner_left.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/roundcorner_right.gif b/etherpad/src/static/img/jun09/pad/roundcorner_right.gif
new file mode 100644
index 0000000..97acfbf
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/roundcorner_right.gif
Binary files differ
diff --git a/etherpad/src/static/img/jun09/pad/roundcorner_right_orange.gif b/etherpad/src/static/img/jun09/pad/roundcorner_right_orange.gif
new file mode 100644
index 0000000..717e3fc
--- /dev/null
+++ b/etherpad/src/static/img/jun09/pad/roundcorner_right_orange.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/savedrevarrows.gif b/etherpad/src/static/img/jun09/pad/savedrevarrows.gif
index 2aa2e41..2aa2e41 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/savedrevarrows.gif
+++ b/etherpad/src/static/img/jun09/pad/savedrevarrows.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/savedrevsgfx2.gif b/etherpad/src/static/img/jun09/pad/savedrevsgfx2.gif
index 45c3459..45c3459 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/savedrevsgfx2.gif
+++ b/etherpad/src/static/img/jun09/pad/savedrevsgfx2.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/sharebox4.gif b/etherpad/src/static/img/jun09/pad/sharebox4.gif
index eccaa7e..eccaa7e 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/sharebox4.gif
+++ b/etherpad/src/static/img/jun09/pad/sharebox4.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/sharedistri.gif b/etherpad/src/static/img/jun09/pad/sharedistri.gif
index 8eb5891..8eb5891 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/sharedistri.gif
+++ b/etherpad/src/static/img/jun09/pad/sharedistri.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/syncdone.gif b/etherpad/src/static/img/jun09/pad/syncdone.gif
index e4d971b..e4d971b 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/syncdone.gif
+++ b/etherpad/src/static/img/jun09/pad/syncdone.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/syncing.gif b/etherpad/src/static/img/jun09/pad/syncing.gif
index bbc731f..bbc731f 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/syncing.gif
+++ b/etherpad/src/static/img/jun09/pad/syncing.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/viewbargfx.gif b/etherpad/src/static/img/jun09/pad/viewbargfx.gif
index 396483a..396483a 100644
--- a/trunk/etherpad/src/static/img/jun09/pad/viewbargfx.gif
+++ b/etherpad/src/static/img/jun09/pad/viewbargfx.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-cyan-menu-item-hover.gif b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-cyan-menu-item-hover.gif
index d0e428e..d0e428e 100644
--- a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-cyan-menu-item-hover.gif
+++ b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-cyan-menu-item-hover.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-menu-item-hover.gif b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-menu-item-hover.gif
index 8240ba3..8240ba3 100644
--- a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-menu-item-hover.gif
+++ b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-menu-item-hover.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-semitransparent-menu-item-hover.png b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-semitransparent-menu-item-hover.png
index 6314d53..6314d53 100644
--- a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-semitransparent-menu-item-hover.png
+++ b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-gloss-semitransparent-menu-item-hover.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-human-menu-item-hover.gif b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-human-menu-item-hover.gif
index 7e70aae..7e70aae 100644
--- a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-human-menu-item-hover.gif
+++ b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-human-menu-item-hover.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-osx-menu-item-hover.gif b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-osx-menu-item-hover.gif
index aa802e0..aa802e0 100644
--- a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-osx-menu-item-hover.gif
+++ b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-osx-menu-item-hover.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-bg.gif b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-bg.gif
index 565e771..565e771 100644
--- a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-bg.gif
+++ b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-bg.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-menu-item-hover.gif b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-menu-item-hover.gif
index 2825eb1..2825eb1 100644
--- a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-menu-item-hover.gif
+++ b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-vista-menu-item-hover.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-xp-bg.gif b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-xp-bg.gif
index 11b238c..11b238c 100644
--- a/trunk/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-xp-bg.gif
+++ b/etherpad/src/static/img/lib/jquery.contextmenu.images/cmenu-xp-bg.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/doc.gif b/etherpad/src/static/img/may09/doc.gif
index 2b62080..2b62080 100644
--- a/trunk/etherpad/src/static/img/may09/doc.gif
+++ b/etherpad/src/static/img/may09/doc.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/html.gif b/etherpad/src/static/img/may09/html.gif
index f7837e5..f7837e5 100644
--- a/trunk/etherpad/src/static/img/may09/html.gif
+++ b/etherpad/src/static/img/may09/html.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/pdf.gif b/etherpad/src/static/img/may09/pdf.gif
index 1614d2c..1614d2c 100644
--- a/trunk/etherpad/src/static/img/may09/pdf.gif
+++ b/etherpad/src/static/img/may09/pdf.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/txt.gif b/etherpad/src/static/img/may09/txt.gif
index c3f026e..c3f026e 100644
--- a/trunk/etherpad/src/static/img/may09/txt.gif
+++ b/etherpad/src/static/img/may09/txt.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/misc/status-ball.gif b/etherpad/src/static/img/misc/status-ball.gif
index 085ccae..085ccae 100644
--- a/trunk/etherpad/src/static/img/misc/status-ball.gif
+++ b/etherpad/src/static/img/misc/status-ball.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/crushed_button_depressed.png b/etherpad/src/static/img/pad/timeslider/crushed_button_depressed.png
index d75dcce..d75dcce 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/crushed_button_depressed.png
+++ b/etherpad/src/static/img/pad/timeslider/crushed_button_depressed.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/crushed_button_undepressed.png b/etherpad/src/static/img/pad/timeslider/crushed_button_undepressed.png
index d86e3f3..d86e3f3 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/crushed_button_undepressed.png
+++ b/etherpad/src/static/img/pad/timeslider/crushed_button_undepressed.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/crushed_current_location.png b/etherpad/src/static/img/pad/timeslider/crushed_current_location.png
index 76e0835..76e0835 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/crushed_current_location.png
+++ b/etherpad/src/static/img/pad/timeslider/crushed_current_location.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/crushed_timeslider_mockup.png b/etherpad/src/static/img/pad/timeslider/crushed_timeslider_mockup.png
index f4ccbf1..f4ccbf1 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/crushed_timeslider_mockup.png
+++ b/etherpad/src/static/img/pad/timeslider/crushed_timeslider_mockup.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/current_location.png b/etherpad/src/static/img/pad/timeslider/current_location.png
index ab02792..ab02792 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/current_location.png
+++ b/etherpad/src/static/img/pad/timeslider/current_location.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/pause.png b/etherpad/src/static/img/pad/timeslider/pause.png
index 657782c..657782c 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/pause.png
+++ b/etherpad/src/static/img/pad/timeslider/pause.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/play.png b/etherpad/src/static/img/pad/timeslider/play.png
index 19afe03..19afe03 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/play.png
+++ b/etherpad/src/static/img/pad/timeslider/play.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/play_button.png b/etherpad/src/static/img/pad/timeslider/play_button.png
index bc1736d..bc1736d 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/play_button.png
+++ b/etherpad/src/static/img/pad/timeslider/play_button.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/star.png b/etherpad/src/static/img/pad/timeslider/star.png
index e0c7099..e0c7099 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/star.png
+++ b/etherpad/src/static/img/pad/timeslider/star.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/star_selected.png b/etherpad/src/static/img/pad/timeslider/star_selected.png
index c336589..c336589 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/star_selected.png
+++ b/etherpad/src/static/img/pad/timeslider/star_selected.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/stepper_buttons.png b/etherpad/src/static/img/pad/timeslider/stepper_buttons.png
index e011a45..e011a45 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/stepper_buttons.png
+++ b/etherpad/src/static/img/pad/timeslider/stepper_buttons.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/timeslider_background.png b/etherpad/src/static/img/pad/timeslider/timeslider_background.png
index faa45c6..faa45c6 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/timeslider_background.png
+++ b/etherpad/src/static/img/pad/timeslider/timeslider_background.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/timeslider_left.png b/etherpad/src/static/img/pad/timeslider/timeslider_left.png
index 594d86b..594d86b 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/timeslider_left.png
+++ b/etherpad/src/static/img/pad/timeslider/timeslider_left.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/timeslider_right.png b/etherpad/src/static/img/pad/timeslider/timeslider_right.png
index 3bf10a2..3bf10a2 100644
--- a/trunk/etherpad/src/static/img/pad/timeslider/timeslider_right.png
+++ b/etherpad/src/static/img/pad/timeslider/timeslider_right.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/box/blue-boxtop.gif b/etherpad/src/static/img/pro/box/blue-boxtop.gif
index 38e3538..38e3538 100644
--- a/trunk/etherpad/src/static/img/pro/box/blue-boxtop.gif
+++ b/etherpad/src/static/img/pro/box/blue-boxtop.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/buttons/bluebutton120.gif b/etherpad/src/static/img/pro/buttons/bluebutton120.gif
index 2f22003..2f22003 100644
--- a/trunk/etherpad/src/static/img/pro/buttons/bluebutton120.gif
+++ b/etherpad/src/static/img/pro/buttons/bluebutton120.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/header/pro-header-logo.png b/etherpad/src/static/img/pro/header/pro-header-logo.png
index b36daa8..b36daa8 100644
--- a/trunk/etherpad/src/static/img/pro/header/pro-header-logo.png
+++ b/etherpad/src/static/img/pro/header/pro-header-logo.png
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/header/pro-header-plustopnav-back.gif b/etherpad/src/static/img/pro/header/pro-header-plustopnav-back.gif
index f7398fe..f7398fe 100644
--- a/trunk/etherpad/src/static/img/pro/header/pro-header-plustopnav-back.gif
+++ b/etherpad/src/static/img/pro/header/pro-header-plustopnav-back.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/padlist/gear-drop.gif b/etherpad/src/static/img/pro/padlist/gear-drop.gif
index ded0f24..ded0f24 100644
--- a/trunk/etherpad/src/static/img/pro/padlist/gear-drop.gif
+++ b/etherpad/src/static/img/pro/padlist/gear-drop.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/padlist/paper-icon.gif b/etherpad/src/static/img/pro/padlist/paper-icon.gif
index 161b66e..161b66e 100644
--- a/trunk/etherpad/src/static/img/pro/padlist/paper-icon.gif
+++ b/etherpad/src/static/img/pro/padlist/paper-icon.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/padlist/trash-icon.gif b/etherpad/src/static/img/pro/padlist/trash-icon.gif
index 74b5ede..74b5ede 100644
--- a/trunk/etherpad/src/static/img/pro/padlist/trash-icon.gif
+++ b/etherpad/src/static/img/pro/padlist/trash-icon.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/topnav/pro-topnav-back.gif b/etherpad/src/static/img/pro/topnav/pro-topnav-back.gif
index 336fd05..336fd05 100644
--- a/trunk/etherpad/src/static/img/pro/topnav/pro-topnav-back.gif
+++ b/etherpad/src/static/img/pro/topnav/pro-topnav-back.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/topnav/pro-topnav-notch.gif b/etherpad/src/static/img/pro/topnav/pro-topnav-notch.gif
index 5dbe57b..5dbe57b 100644
--- a/trunk/etherpad/src/static/img/pro/topnav/pro-topnav-notch.gif
+++ b/etherpad/src/static/img/pro/topnav/pro-topnav-notch.gif
Binary files differ
diff --git a/trunk/etherpad/src/static/js/billing.js b/etherpad/src/static/js/billing.js
index c9fa30e..c9fa30e 100644
--- a/trunk/etherpad/src/static/js/billing.js
+++ b/etherpad/src/static/js/billing.js
diff --git a/trunk/etherpad/src/static/js/billing_shared.js b/etherpad/src/static/js/billing_shared.js
index dc3a00c..dc3a00c 100644
--- a/trunk/etherpad/src/static/js/billing_shared.js
+++ b/etherpad/src/static/js/billing_shared.js
diff --git a/etherpad/src/static/js/broadcast.js b/etherpad/src/static/js/broadcast.js
new file mode 100644
index 0000000..8ea0a15
--- /dev/null
+++ b/etherpad/src/static/js/broadcast.js
@@ -0,0 +1,610 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+// just in case... (todo: this must be somewhere else in the client code.)
+// Below Array#map code was direct pasted by AppJet/Etherpad, licence unknown. Possible source: http://www.tutorialspoint.com/javascript/array_map.htm
+if (!Array.prototype.map)
+{
+ Array.prototype.map = function(fun /*, thisp*/)
+ {
+ var len = this.length >>> 0;
+ if (typeof fun != "function")
+ throw new TypeError();
+
+ var res = new Array(len);
+ var thisp = arguments[1];
+ for (var i = 0; i < len; i++)
+ {
+ if (i in this)
+ res[i] = fun.call(thisp, this[i], i, this);
+ }
+
+ return res;
+ };
+}
+
+// Below Array#forEach code was direct pasted by AppJet/Etherpad, licence unknown. Possible source: http://www.tutorialspoint.com/javascript/array_foreach.htm
+if (!Array.prototype.forEach)
+{
+ Array.prototype.forEach = function(fun /*, thisp*/)
+ {
+ var len = this.length >>> 0;
+ if (typeof fun != "function")
+ throw new TypeError();
+
+ var thisp = arguments[1];
+ for (var i = 0; i < len; i++)
+ {
+ if (i in this)
+ fun.call(thisp, this[i], i, this);
+ }
+ };
+}
+
+// Below Array#indexOf code was direct pasted by AppJet/Etherpad, licence unknown. Possible source: http://www.tutorialspoint.com/javascript/array_indexof.htm
+if (!Array.prototype.indexOf)
+{
+ Array.prototype.indexOf = function(elt /*, from*/)
+ {
+ var len = this.length >>> 0;
+
+ var from = Number(arguments[1]) || 0;
+ from = (from < 0)
+ ? Math.ceil(from)
+ : Math.floor(from);
+ if (from < 0)
+ from += len;
+
+ for (; from < len; from++)
+ {
+ if (from in this &&
+ this[from] === elt)
+ return from;
+ }
+ return -1;
+ };
+}
+
+function debugLog() {
+ try {
+ // console.log.apply(console, arguments);
+ } catch (e) {console.log("error printing: ",e);}
+}
+
+function randomString() {
+ return "_"+Math.floor(Math.random() * 1000000);
+}
+
+// for IE
+if ($.browser.msie) {
+ try {
+ document.execCommand("BackgroundImageCache", false, true);
+ } catch (e) {}
+}
+
+var userId = "hiddenUser" + randomString();
+var socketId;
+var socket;
+
+var channelState = "DISCONNECTED";
+
+var appLevelDisconnectReason = null;
+
+var padContents = {
+ currentRevision: clientVars.revNum,
+ currentTime : clientVars.currentTime,
+ currentLines: Changeset.splitTextLines(clientVars.initialStyledContents.atext.text),
+ currentDivs : null, // to be filled in once the dom loads
+ apool: (new AttribPool()).fromJsonable(clientVars.initialStyledContents.apool),
+ alines: Changeset.splitAttributionLines(
+ clientVars.initialStyledContents.atext.attribs,
+ clientVars.initialStyledContents.atext.text),
+
+ // generates a jquery element containing HTML for a line
+ lineToElement: function(line, aline) {
+ var element = document.createElement("div");
+ var emptyLine = (line == '\n');
+ var domInfo = domline.createDomLine(! emptyLine, true);
+ linestylefilter.populateDomLine(line, aline, this.apool,
+ domInfo);
+ domInfo.prepareForAdd();
+ element.className = domInfo.node.className;
+ element.innerHTML = domInfo.node.innerHTML;
+ element.id = Math.random();
+ return $(element);
+ },
+
+ applySpliceToDivs: function(start, numRemoved, newLines) {
+ // remove spliced-out lines from DOM
+ for(var i=start; i<start+numRemoved && i<this.currentDivs.length; i++) {
+ debugLog("removing", this.currentDivs[i].attr('id'));
+ this.currentDivs[i].remove();
+ }
+
+ // remove spliced-out line divs from currentDivs array
+ this.currentDivs.splice(start, numRemoved);
+
+ var newDivs = [];
+ for(var i=0;i<newLines.length;i++) {
+ newDivs.push(this.lineToElement(newLines[i],
+ this.alines[start+i]));
+ }
+
+ // grab the div just before the first one
+ var startDiv = this.currentDivs[start-1] || null;
+
+ // insert the div elements into the correct place, in the correct order
+ for(var i=0; i<newDivs.length; i++) {
+ if (startDiv) {
+ startDiv.after(newDivs[i]);
+ }
+ else {
+ $("#padcontent").prepend(newDivs[i]);
+ }
+ startDiv = newDivs[i];
+ }
+
+ // insert new divs into currentDivs array
+ newDivs.unshift(0); // remove 0 elements
+ newDivs.unshift(start);
+ this.currentDivs.splice.apply(this.currentDivs, newDivs);
+ return this;
+ },
+
+ // splice the lines
+ splice: function(start, numRemoved, newLinesVA) {
+ var newLines = Array.prototype.slice.call(arguments, 2).map(
+ function(s) { return s; });
+
+ // apply this splice to the divs
+ this.applySpliceToDivs(start, numRemoved, newLines);
+
+ // call currentLines.splice, to keep the currentLines array up to date
+ newLines.unshift(numRemoved);
+ newLines.unshift(start);
+ this.currentLines.splice.apply(this.currentLines, arguments);
+ },
+ // returns the contents of the specified line I
+ get: function(i) {
+ return this.currentLines[i];
+ },
+ // returns the number of lines in the document
+ length: function() {
+ return this.currentLines.length;
+ },
+
+ getActiveAuthors: function() {
+ var self = this;
+ var authors = [];
+ var seenNums = {};
+ var alines = self.alines;
+ for(var i=0;i<alines.length;i++) {
+ Changeset.eachAttribNumber(alines[i], function(n) {
+ if (! seenNums[n]) {
+ seenNums[n] = true;
+ if (self.apool.getAttribKey(n) == 'author') {
+ var a = self.apool.getAttribValue(n);
+ if (a) {
+ authors.push(a);
+ }
+ }
+ }
+ });
+ }
+ authors.sort();
+ return authors;
+ }
+};
+
+function callCatchingErrors(catcher, func) {
+ try {
+ wrapRecordingErrors(catcher, func)();
+ }
+ catch (e) { /*absorb*/ }
+}
+
+function wrapRecordingErrors(catcher, func) {
+ return function() {
+ try {
+ return func.apply(this, Array.prototype.slice.call(arguments));
+ }
+ catch (e) {
+ // caughtErrors.push(e);
+ // caughtErrorCatchers.push(catcher);
+ // caughtErrorTimes.push(+new Date());
+ // console.dir({catcher: catcher, e: e});
+ debugLog(e); // TODO(kroo): added temporary, to catch errors
+ throw e;
+ }
+ };
+}
+
+function loadedNewChangeset(changesetForward, changesetBackward, revision, timeDelta) {
+ var broadcasting = (BroadcastSlider.getSliderPosition() == revisionInfo.latest);
+ debugLog("broadcasting:", broadcasting, BroadcastSlider.getSliderPosition(), revisionInfo.latest, revision);
+ revisionInfo.addChangeset(revision, revision+1, changesetForward, changesetBackward, timeDelta);
+ BroadcastSlider.setSliderLength(revisionInfo.latest);
+ if(broadcasting)
+ applyChangeset(changesetForward, revision+1, false, timeDelta);
+}
+
+/*
+ At this point, we must be certain that the changeset really does map from
+ the current revision to the specified revision. Any mistakes here will
+ cause the whole slider to get out of sync.
+ */
+function applyChangeset(changeset, revision, preventSliderMovement, timeDelta) {
+ // disable the next 'gotorevision' call handled by a timeslider update
+ if(!preventSliderMovement) {
+ goToRevisionIfEnabledCount ++;
+ BroadcastSlider.setSliderPosition(revision);
+ }
+
+ try {
+ // must mutate attribution lines before text lines
+ Changeset.mutateAttributionLines(changeset, padContents.alines, padContents.apool);
+ }catch(e) { debugLog(e); }
+
+ Changeset.mutateTextLines(changeset, padContents);
+ padContents.currentRevision = revision;
+ padContents.currentTime += timeDelta * 1000;
+ debugLog('Time Delta: ',timeDelta)
+ updateTimer();
+ BroadcastSlider.setAuthors(padContents.getActiveAuthors().map(function(name) {return authorData[name];}));
+}
+
+function updateTimer() {
+ var zpad = function(str, length) {
+ str = str+"";
+ while(str.length < length)
+ str = '0'+str;
+ return str;
+ }
+ var date = new Date(padContents.currentTime);
+ var dateFormat = function() {
+ var month = zpad(date.getMonth()+1,2);
+ var day = zpad(date.getDate(),2);
+ var year = (date.getFullYear());
+ var hours = zpad(date.getHours(),2);
+ var minutes = zpad(date.getMinutes(),2);
+ var seconds = zpad(date.getSeconds(),2);
+ return ([month,'/',day,'/',year,' ',hours,':',minutes,':',seconds].join(""));
+ }
+
+ $('#timer').html(dateFormat());
+
+ var revisionDate = [
+ "Saved",
+ [
+ "Jan", "Feb", "March", "April", "May", "June",
+ "July", "Aug", "Sept", "Oct", "Nov", "Dec"
+ ][date.getMonth()],
+ date.getDate()+",",
+ date.getFullYear()
+ ].join(" ")
+ $('#revision_date').html(revisionDate)
+
+}
+
+function goToRevision(newRevision) {
+ padContents.targetRevision = newRevision;
+ var self = this;
+ var path = revisionInfo.getPath(padContents.currentRevision, newRevision);
+ debugLog('newRev: ', padContents.currentRevision, path);
+ if( path.status == 'complete') {
+ var cs = path.changesets;
+ debugLog("status: complete, changesets: ",cs, "path:", path);
+ var changeset = cs[0];
+ var timeDelta = path.times[0];
+ for(var i=1; i<cs.length; i++) {
+ changeset = Changeset.compose(changeset, cs[i], padContents.apool);
+ timeDelta += path.times[i];
+ }
+ if(changeset)
+ applyChangeset(changeset, path.rev, true, timeDelta);
+ } else if(path.status == "partial") {
+ debugLog('partial');
+ var sliderLocation = padContents.currentRevision;
+ // callback is called after changeset information is pulled from server
+ // this may never get called, if the changeset has already been loaded
+ var update = function(start, end) {
+ // if we've called goToRevision in the time since, don't goToRevision
+ goToRevision(padContents.targetRevision);
+ };
+
+ // do our best with what we have...
+ var cs = path.changesets;
+
+ var changeset = cs[0];
+ var timeDelta = path.times[0];
+ for(var i=1; i<cs.length; i++) {
+ changeset = Changeset.compose(changeset, cs[i], padContents.apool);
+ timeDelta += path.times[i];
+ }
+ if(changeset)
+ applyChangeset(changeset, path.rev, true, timeDelta);
+
+
+ if(BroadcastSlider.getSliderLength() > 10000) {
+ var start = (Math.floor((newRevision) / 10000) * 10000); // revision 0 to 10
+ changesetLoader.queueUp(start, 100);
+ }
+
+ if(BroadcastSlider.getSliderLength() > 1000) {
+ var start = (Math.floor((newRevision) / 1000) * 1000); // (start from -1, go to 19) + 1
+ changesetLoader.queueUp(start, 10);
+ }
+
+ start = (Math.floor((newRevision) / 100) * 100);
+
+ changesetLoader.queueUp(start, 1, update);
+ }
+ BroadcastSlider.setAuthors(padContents.getActiveAuthors().map(function(name) {return authorData[name];}));
+}
+
+var changesetLoader = {
+ running: false,
+ resolved: [],
+ requestQueue1: [],
+ requestQueue2: [],
+ requestQueue3: [],
+ queueUp: function(revision, width, callback) {
+ if(revision < 0) revision = 0;
+ // if(changesetLoader.requestQueue.indexOf(revision) != -1)
+ // return; // already in the queue.
+ if(changesetLoader.resolved.indexOf(revision+"_"+width) != -1)
+ return; // already loaded from the server
+ changesetLoader.resolved.push(revision+"_"+width);
+
+ var requestQueue = width == 1 ? changesetLoader.requestQueue3 :
+ width == 10 ? changesetLoader.requestQueue2 :
+ changesetLoader.requestQueue1;
+ requestQueue.push({'rev': revision, 'res': width, 'callback': callback});
+ if(!changesetLoader.running) {
+ changesetLoader.running = true;
+ setTimeout(changesetLoader.loadFromQueue, 10);
+ }
+ },
+ loadFromQueue: function() {
+ var self = changesetLoader;
+ var requestQueue = self.requestQueue1.length > 0 ? self.requestQueue1 :
+ self.requestQueue2.length > 0 ? self.requestQueue2 :
+ self.requestQueue3.length > 0 ? self.requestQueue3 : null;
+
+ if(!requestQueue) {
+ self.running = false;
+ return;
+ }
+
+ var request = requestQueue.pop();
+ var granularity = request.res;
+ var callback = request.callback;
+ var start = request.rev;
+ debugLog("loadinging revision", start, "through ajax");
+ $.getJSON(
+ "/ep/pad/changes/"+clientVars.padIdForUrl+"?s="+start + "&g="+granularity,
+ function(data, textStatus) {
+ if(textStatus !== "success") {
+ console.log(textStatus);
+ BroadcastSlider.showReconnectUI();
+ }
+ self.handleResponse(data, start, granularity, callback);
+
+ setTimeout(self.loadFromQueue, 10); // load the next ajax function
+ }
+ );
+ },
+ handleResponse: function(data, start, granularity, callback) {
+ debugLog("response: ", data);
+ var pool = (new AttribPool()).fromJsonable(data.apool);
+ for(var i=0; i<data.forwardsChangesets.length; i++) {
+ var astart = start + i * granularity - 1; // rev -1 is a blank single line
+ var aend = start + (i+1) * granularity - 1;// totalRevs is the most recent revision
+ if(aend > data.actualEndNum - 1) aend = data.actualEndNum - 1;
+ debugLog("adding changeset:", astart, aend);
+ var forwardcs = Changeset.moveOpsToNewPool(data.forwardsChangesets[i], pool, padContents.apool);
+ var backwardcs = Changeset.moveOpsToNewPool(data.backwardsChangesets[i], pool, padContents.apool);
+ revisionInfo.addChangeset(astart, aend, forwardcs, backwardcs, data.timeDeltas[i]);
+ }
+ if(callback)callback(start - 1, start + data.forwardsChangesets.length * granularity - 1);
+ }
+};
+
+function handleMessageFromServer() {
+ debugLog("handleMessage:", arguments);
+ var obj = arguments[0]['data'];
+ var expectedType = "COLLABROOM";
+
+ obj = JSON.parse(obj);
+ if (obj['type'] == expectedType) {
+ obj = obj['data'];
+
+ if (obj['type'] == "NEW_CHANGES") {
+ debugLog(obj);
+ var changeset = Changeset.moveOpsToNewPool(
+ obj.changeset, (new AttribPool()).fromJsonable(obj.apool),
+ padContents.apool);
+
+ var changesetBack = Changeset.moveOpsToNewPool(
+ obj.changesetBack, (new AttribPool()).fromJsonable(obj.apool),
+ padContents.apool);
+
+ loadedNewChangeset(changeset, changesetBack, obj.newRev-1, obj.timeDelta);
+ }
+ else if (obj['type'] == "NEW_AUTHORDATA") {
+ var authorMap = {};
+ authorMap[obj.author] = obj.data;
+ receiveAuthorData(authorMap);
+ BroadcastSlider.setAuthors(padContents.getActiveAuthors().map(function(name) {return authorData[name];}));
+ } else if (obj['type'] == "NEW_SAVEDREV") {
+ var savedRev = obj.savedRev;
+ BroadcastSlider.addSavedRevision(savedRev.revNum, savedRev);
+ }
+ } else {
+ debugLog("incorrect message type: " + obj['type'] + ", expected " + expectedType);
+ }
+}
+
+function handleSocketClosed(params) {
+ debugLog("socket closed!", params);
+ socket = null;
+
+ BroadcastSlider.showReconnectUI();
+ // var reason = appLevelDisconnectReason || params.reason;
+ // var shouldReconnect = params.reconnect;
+ // if (shouldReconnect) {
+ // // determine if this is a tight reconnect loop due to weird connectivity problems
+ // // reconnectTimes.push(+new Date());
+ // var TOO_MANY_RECONNECTS = 8;
+ // var TOO_SHORT_A_TIME_MS = 10000;
+ // if (reconnectTimes.length >= TOO_MANY_RECONNECTS &&
+ // ((+new Date()) - reconnectTimes[reconnectTimes.length-TOO_MANY_RECONNECTS]) <
+ // TOO_SHORT_A_TIME_MS) {
+ // setChannelState("DISCONNECTED", "looping");
+ // }
+ // else {
+ // setChannelState("RECONNECTING", reason);
+ // setUpSocket();
+ // }
+ // }
+ // else {
+ // BroadcastSlider.showReconnectUI();
+ // setChannelState("DISCONNECTED", reason);
+ // }
+}
+
+function sendMessage(msg) {
+ socket.postMessage(JSON.stringify({type: "COLLABROOM", data: msg}));
+}
+
+function setUpSocket() {
+ // required for Comet
+ if ((! $.browser.msie) &&
+ (! ($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0))) {
+ document.domain = document.domain; // for comet
+ }
+
+ var success = false;
+ callCatchingErrors("setUpSocket", function() {
+ appLevelDisconnectReason = null;
+
+ socketId = String(Math.floor(Math.random()*1e12));
+ socket = new WebSocket(socketId);
+ socket.onmessage = wrapRecordingErrors("socket.onmessage", handleMessageFromServer);
+ socket.onclosed = wrapRecordingErrors("socket.onclosed", handleSocketClosed);
+ socket.onopen = wrapRecordingErrors("socket.onopen", function() {
+ setChannelState("CONNECTED");
+ var msg = { type:"CLIENT_READY", roomType:'padview',
+ roomName:'padview/'+clientVars.viewId,
+ data: { lastRev:clientVars.revNum,
+ userInfo:{userId: userId} } };
+ sendMessage(msg);
+ });
+ // socket.onhiccup = wrapRecordingErrors("socket.onhiccup", handleCometHiccup);
+ // socket.onlogmessage = function(x) {debugLog(x); };
+ socket.connect();
+ success = true;
+ });
+ if (success) {
+ //initialStartConnectTime = +new Date();
+ }
+ else {
+ abandonConnection("initsocketfail");
+ }
+}
+
+function setChannelState(newChannelState, moreInfo) {
+ if (newChannelState != channelState) {
+ channelState = newChannelState;
+ // callbacks.onChannelStateChange(channelState, moreInfo);
+ }
+}
+
+function abandonConnection(reason) {
+ if (socket) {
+ socket.onclosed = function() {};
+ socket.onhiccup = function() {};
+ socket.disconnect();
+ }
+ socket = null;
+ setChannelState("DISCONNECTED", reason);
+}
+
+window['onloadFuncts'] = [];
+window.onload = function() {
+ window['isloaded'] = true;
+ window['onloadFuncts'].forEach(function(funct) {
+ funct();
+ });
+};
+
+// to start upon window load, just push a function onto this array
+window['onloadFuncts'].push(setUpSocket);
+window['onloadFuncts'].push(function() {
+ // set up the currentDivs and DOM
+ padContents.currentDivs = [];
+ $("#padcontent").html("");
+ for(var i=0; i<padContents.currentLines.length; i++) {
+ var div = padContents.lineToElement(padContents.currentLines[i],
+ padContents.alines[i]);
+ padContents.currentDivs.push(div);
+ $("#padcontent").append(div);
+ }
+ debugLog(padContents.currentDivs);
+});
+
+// this is necessary to keep infinite loops of events firing,
+// since goToRevision changes the slider position
+var goToRevisionIfEnabledCount = 0;
+var goToRevisionIfEnabled = function() {
+ if(goToRevisionIfEnabledCount > 0) {
+ goToRevisionIfEnabledCount --;
+ } else {
+ goToRevision.apply(goToRevision, arguments);
+ }
+}
+
+BroadcastSlider.onSlider(goToRevisionIfEnabled);
+
+(function() {
+ for(var i=0; i<clientVars.initialChangesets.length; i++) {
+ var csgroup = clientVars.initialChangesets[i];
+ var start = clientVars.initialChangesets[i].start;
+ var granularity = clientVars.initialChangesets[i].granularity;
+ debugLog("loading changest on startup: ", start, granularity, csgroup);
+ changesetLoader.handleResponse(csgroup, start, granularity, null);
+ }
+})();
+
+var dynamicCSS = makeCSSManager('dynamicsyntax');
+var authorData = {};
+
+function receiveAuthorData(newAuthorData) {
+ for(var author in newAuthorData) {
+ var data = newAuthorData[author];
+ if ((typeof data.colorId) == 'number') {
+ var bgcolor = clientVars.colorPalette[data.colorId];
+ if (bgcolor && dynamicCSS) {
+ dynamicCSS.selectorStyle(
+ '.'+linestylefilter.getAuthorClassName(author)).backgroundColor =
+ bgcolor;
+ }
+ }
+ authorData[author] = data;
+ }
+}
+
+receiveAuthorData(clientVars.historicalAuthorData);
diff --git a/trunk/etherpad/src/static/js/broadcast_revisions.js b/etherpad/src/static/js/broadcast_revisions.js
index 7e99003..7e99003 100644
--- a/trunk/etherpad/src/static/js/broadcast_revisions.js
+++ b/etherpad/src/static/js/broadcast_revisions.js
diff --git a/trunk/etherpad/src/static/js/broadcast_slider.js b/etherpad/src/static/js/broadcast_slider.js
index 371663e..371663e 100644
--- a/trunk/etherpad/src/static/js/broadcast_slider.js
+++ b/etherpad/src/static/js/broadcast_slider.js
diff --git a/trunk/etherpad/src/static/js/collab_client.js b/etherpad/src/static/js/collab_client.js
index d8834d7..d8834d7 100644
--- a/trunk/etherpad/src/static/js/collab_client.js
+++ b/etherpad/src/static/js/collab_client.js
diff --git a/trunk/etherpad/src/static/js/confirmation.js b/etherpad/src/static/js/confirmation.js
index a0f725c..a0f725c 100644
--- a/trunk/etherpad/src/static/js/confirmation.js
+++ b/etherpad/src/static/js/confirmation.js
diff --git a/trunk/etherpad/src/static/js/connection_diagnostics.js b/etherpad/src/static/js/connection_diagnostics.js
index cc43d46..cc43d46 100644
--- a/trunk/etherpad/src/static/js/connection_diagnostics.js
+++ b/etherpad/src/static/js/connection_diagnostics.js
diff --git a/trunk/etherpad/src/static/js/draggable.js b/etherpad/src/static/js/draggable.js
index 97a1a3d..97a1a3d 100644
--- a/trunk/etherpad/src/static/js/draggable.js
+++ b/etherpad/src/static/js/draggable.js
diff --git a/trunk/etherpad/src/static/js/etherpad.js b/etherpad/src/static/js/etherpad.js
index 4e51dbf..4e51dbf 100644
--- a/trunk/etherpad/src/static/js/etherpad.js
+++ b/etherpad/src/static/js/etherpad.js
diff --git a/trunk/etherpad/src/static/js/jquery-1.2.6.js b/etherpad/src/static/js/jquery-1.2.6.js
index 88e661e..88e661e 100755..100644
--- a/trunk/etherpad/src/static/js/jquery-1.2.6.js
+++ b/etherpad/src/static/js/jquery-1.2.6.js
diff --git a/trunk/etherpad/src/static/js/jquery-1.3.2.js b/etherpad/src/static/js/jquery-1.3.2.js
index 9263574..9263574 100644
--- a/trunk/etherpad/src/static/js/jquery-1.3.2.js
+++ b/etherpad/src/static/js/jquery-1.3.2.js
diff --git a/trunk/etherpad/src/static/js/json2.js b/etherpad/src/static/js/json2.js
index 32988c2..32988c2 100644
--- a/trunk/etherpad/src/static/js/json2.js
+++ b/etherpad/src/static/js/json2.js
diff --git a/trunk/etherpad/src/static/js/lib/jquery.contextmenu.js b/etherpad/src/static/js/lib/jquery.contextmenu.js
index 42cc17e..42cc17e 100644
--- a/trunk/etherpad/src/static/js/lib/jquery.contextmenu.js
+++ b/etherpad/src/static/js/lib/jquery.contextmenu.js
diff --git a/trunk/etherpad/src/static/js/pad2.js b/etherpad/src/static/js/pad2.js
index 14ac762..14ac762 100644
--- a/trunk/etherpad/src/static/js/pad2.js
+++ b/etherpad/src/static/js/pad2.js
diff --git a/trunk/etherpad/src/static/js/pad_chat.js b/etherpad/src/static/js/pad_chat.js
index 35903c2..35903c2 100644
--- a/trunk/etherpad/src/static/js/pad_chat.js
+++ b/etherpad/src/static/js/pad_chat.js
diff --git a/trunk/etherpad/src/static/js/pad_connectionstatus.js b/etherpad/src/static/js/pad_connectionstatus.js
index cc06728..cc06728 100644
--- a/trunk/etherpad/src/static/js/pad_connectionstatus.js
+++ b/etherpad/src/static/js/pad_connectionstatus.js
diff --git a/trunk/etherpad/src/static/js/pad_cookie.js b/etherpad/src/static/js/pad_cookie.js
index 3cc31ed..3cc31ed 100644
--- a/trunk/etherpad/src/static/js/pad_cookie.js
+++ b/etherpad/src/static/js/pad_cookie.js
diff --git a/trunk/etherpad/src/static/js/pad_docbar.js b/etherpad/src/static/js/pad_docbar.js
index 586b20f..586b20f 100644
--- a/trunk/etherpad/src/static/js/pad_docbar.js
+++ b/etherpad/src/static/js/pad_docbar.js
diff --git a/trunk/etherpad/src/static/js/pad_editbar.js b/etherpad/src/static/js/pad_editbar.js
index 34b774a..34b774a 100644
--- a/trunk/etherpad/src/static/js/pad_editbar.js
+++ b/etherpad/src/static/js/pad_editbar.js
diff --git a/trunk/etherpad/src/static/js/pad_editor.js b/etherpad/src/static/js/pad_editor.js
index f2fab26..f2fab26 100644
--- a/trunk/etherpad/src/static/js/pad_editor.js
+++ b/etherpad/src/static/js/pad_editor.js
diff --git a/trunk/etherpad/src/static/js/pad_impexp.js b/etherpad/src/static/js/pad_impexp.js
index e928332..e928332 100644
--- a/trunk/etherpad/src/static/js/pad_impexp.js
+++ b/etherpad/src/static/js/pad_impexp.js
diff --git a/trunk/etherpad/src/static/js/pad_modals.js b/etherpad/src/static/js/pad_modals.js
index c9f48b5..c9f48b5 100644
--- a/trunk/etherpad/src/static/js/pad_modals.js
+++ b/etherpad/src/static/js/pad_modals.js
diff --git a/trunk/etherpad/src/static/js/pad_savedrevs.js b/etherpad/src/static/js/pad_savedrevs.js
index ec06a1f..ec06a1f 100644
--- a/trunk/etherpad/src/static/js/pad_savedrevs.js
+++ b/etherpad/src/static/js/pad_savedrevs.js
diff --git a/trunk/etherpad/src/static/js/pad_userlist.js b/etherpad/src/static/js/pad_userlist.js
index 13bfd6a..13bfd6a 100644
--- a/trunk/etherpad/src/static/js/pad_userlist.js
+++ b/etherpad/src/static/js/pad_userlist.js
diff --git a/trunk/etherpad/src/static/js/pad_utils.js b/etherpad/src/static/js/pad_utils.js
index de606ad..de606ad 100644
--- a/trunk/etherpad/src/static/js/pad_utils.js
+++ b/etherpad/src/static/js/pad_utils.js
diff --git a/etherpad/src/static/js/plugins.js b/etherpad/src/static/js/plugins.js
new file mode 100644
index 0000000..f7a5990
--- /dev/null
+++ b/etherpad/src/static/js/plugins.js
@@ -0,0 +1,22 @@
+plugins = {
+ callHook: function (hookName, args) {
+ var hook = clientVars.hooks[hookName];
+ if (hook === undefined)
+ return [];
+ var res = [];
+ for (var i = 0, N=hook.length; i < N; i++) {
+ var plugin = hook[i];
+ var pluginRes = eval(plugin.plugin)[plugin.original || hookName](args);
+ if (pluginRes != undefined && pluginRes != null)
+ res = res.concat(pluginRes);
+ }
+ return res;
+ },
+
+ callHookStr: function (hookName, args, sep, pre, post) {
+ if (sep == undefined) sep = '';
+ if (pre == undefined) pre = '';
+ if (post == undefined) post = '';
+ return callHook(hookName, args).map(function (x) { return pre + x + post}).join(sep || "");
+ }
+};
diff --git a/trunk/etherpad/src/static/js/pricing.js b/etherpad/src/static/js/pricing.js
index 913d5ce..913d5ce 100644
--- a/trunk/etherpad/src/static/js/pricing.js
+++ b/etherpad/src/static/js/pricing.js
diff --git a/trunk/etherpad/src/static/js/pro/guest-knock-client.js b/etherpad/src/static/js/pro/guest-knock-client.js
index bace225..bace225 100644
--- a/trunk/etherpad/src/static/js/pro/guest-knock-client.js
+++ b/etherpad/src/static/js/pro/guest-knock-client.js
diff --git a/trunk/etherpad/src/static/js/pro/pro-padlist-client.js b/etherpad/src/static/js/pro/pro-padlist-client.js
index ba50d95..ba50d95 100644
--- a/trunk/etherpad/src/static/js/pro/pro-padlist-client.js
+++ b/etherpad/src/static/js/pro/pro-padlist-client.js
diff --git a/trunk/etherpad/src/static/js/pro/signin-client.js b/etherpad/src/static/js/pro/signin-client.js
index 62847e5..62847e5 100644
--- a/trunk/etherpad/src/static/js/pro/signin-client.js
+++ b/etherpad/src/static/js/pro/signin-client.js
diff --git a/trunk/etherpad/src/static/js/pulse.jquery.js b/etherpad/src/static/js/pulse.jquery.js
index b23aede..b23aede 100644
--- a/trunk/etherpad/src/static/js/pulse.jquery.js
+++ b/etherpad/src/static/js/pulse.jquery.js
diff --git a/trunk/etherpad/src/static/js/statpage.js b/etherpad/src/static/js/statpage.js
index be2948c..be2948c 100644
--- a/trunk/etherpad/src/static/js/statpage.js
+++ b/etherpad/src/static/js/statpage.js
diff --git a/etherpad/src/static/js/store.js b/etherpad/src/static/js/store.js
new file mode 100644
index 0000000..5750f42
--- /dev/null
+++ b/etherpad/src/static/js/store.js
@@ -0,0 +1,116 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+
+store = {};
+
+$(document).ready(function() {
+ if ($('#downloadpage').size() > 0) {
+ $("#license_agree, #license_agree_label").click(function() {
+ if ($("#license_agree").attr("checked")) {
+ $("a.downloadbutton_disabled").removeClass("downloadbutton_disabled")
+ .addClass("downloadbutton")
+ .attr('href', '/ep/store/eepnet-download-nextsteps');
+ } else {
+ $("a.downloadbutton").removeClass("downloadbutton")
+ .addClass("downloadbutton_disabled")
+ .attr('href', 'javascript:void store.mustAgree()');
+ }
+ });
+ }
+
+ if ($('#eepnet_trial_signup_page').size() > 0) {
+ store.eepnetTrial.init();
+ }
+
+});
+
+store.mustAgree = function() {
+ alert("You must first click 'Accept License' before downloading this software.");
+};
+
+//----------------------------------------------------------------
+// trial download page
+//----------------------------------------------------------------
+
+store.eepnetTrial = {};
+
+store.eepnetTrial.init = function() {
+ $("#submit").attr("disabled", false);
+ $("input.signupData").keydown(function() {
+ $("#submit").attr("disabled", false);
+ });
+ $("input.signupData").change(function() {
+ $("#submit").attr("disabled", false);
+ });
+};
+
+store.eepnetTrial.handleError = function(msg) {
+ $('#processingmsg').hide();
+ $('#dlsignup').show();
+ $("#errormsg").hide().html(msg).fadeIn("fast");
+ var href = window.location.href;
+ href = href.split("#")[0];
+ window.location.href = (href + "#toph2");
+ $('#submit').attr('disabled', false);
+};
+
+store.eepnetTrial.submit = function() {
+
+ $("#errormsg").hide();
+ $('#dlsignup').hide();
+ $('#processingmsg').fadeIn('fast');
+
+ // first submit...
+ var data = {};
+ $(".signupData").each(function() {
+ data[$(this).attr("id")] = $(this).val();
+ });
+ data.industry = $('#industry').val();
+
+ $('#submit').attr('disabled', true);
+
+ $.ajax({
+ type: 'post',
+ url: '/ep/store/eepnet-eval-signup',
+ data: data,
+ success: success,
+ error: error
+ });
+
+ function success(text) {
+ var responseData = eval("("+text+")");
+ if (responseData.error) {
+ store.eepnetTrial.handleError(responseData.error);
+ return;
+ }
+
+ store.eepnetTrial.submitWebToLead(responseData);
+ }
+
+ function error(e) {
+ store.eepnetTrial.handleError("Oops! There was an error processing your request.");
+ }
+};
+
+store.eepnetTrial.submitWebToLead = function(data) {
+ for (k in data) {
+ $('#wl_'+k).val(data[k]);
+ }
+ setTimeout(function() { $('#wlform').submit(); }, 50);
+};
+
+
diff --git a/trunk/etherpad/src/static/js/swfobject.js b/etherpad/src/static/js/swfobject.js
index b741304..b741304 100644
--- a/trunk/etherpad/src/static/js/swfobject.js
+++ b/etherpad/src/static/js/swfobject.js
diff --git a/trunk/etherpad/src/static/js/timeslider.js b/etherpad/src/static/js/timeslider.js
index 552a971..552a971 100644
--- a/trunk/etherpad/src/static/js/timeslider.js
+++ b/etherpad/src/static/js/timeslider.js
diff --git a/trunk/etherpad/src/static/js/undo-xpopup.js b/etherpad/src/static/js/undo-xpopup.js
index 89cfb4d..89cfb4d 100644
--- a/trunk/etherpad/src/static/js/undo-xpopup.js
+++ b/etherpad/src/static/js/undo-xpopup.js
diff --git a/etherpad/src/static/robots.txt b/etherpad/src/static/robots.txt
new file mode 100644
index 0000000..4f9540b
--- /dev/null
+++ b/etherpad/src/static/robots.txt
@@ -0,0 +1 @@
+User-agent: * \ No newline at end of file
diff --git a/trunk/etherpad/src/templates/pad/exporthtml.ejs b/etherpad/src/templates/pad/exporthtml.ejs
index 288a595..288a595 100644
--- a/trunk/etherpad/src/templates/pad/exporthtml.ejs
+++ b/etherpad/src/templates/pad/exporthtml.ejs
diff --git a/trunk/etherpad/src/templates/pro/admin/pro-config.ejs b/etherpad/src/templates/pro/admin/pro-config.ejs
index 32cb610..32cb610 100644
--- a/trunk/etherpad/src/templates/pro/admin/pro-config.ejs
+++ b/etherpad/src/templates/pro/admin/pro-config.ejs
diff --git a/trunk/etherpad/src/templates/500_body.ejs b/etherpad/src/themes/default/templates/500_body.ejs
index 34549ed..34549ed 100644
--- a/trunk/etherpad/src/templates/500_body.ejs
+++ b/etherpad/src/themes/default/templates/500_body.ejs
diff --git a/etherpad/src/themes/default/templates/admin/pluginmanager.ejs b/etherpad/src/themes/default/templates/admin/pluginmanager.ejs
new file mode 100644
index 0000000..cc47928
--- /dev/null
+++ b/etherpad/src/themes/default/templates/admin/pluginmanager.ejs
@@ -0,0 +1,74 @@
+<% /* Copyright 2009 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %>
+<%
+ template.inherit('page.ejs');
+ helpers.setHtmlTitle("EtherPad: Manage plugins");
+ helpers.includeCss("admin/pluginmanager.css");
+
+ function inArray(item, arr) {
+ for (var i = 0; i < arr.length; i++)
+ if (arr[i] == item)
+ return true;
+ return false;
+ }
+%>
+
+<% template.define('docBarTitle', function() { var ejs_data=''; %>
+ <td id="docbarpadtitle"><span>Plugin manager</span></td>
+<% return ejs_data; }); %>
+
+
+<% template.define('docBarItems', function() { var ejs_data=''; %>
+ <%: plugins.callHookStr('docbarItemsPluginManager', {}, '', '<td class="docbarbutton">', '</td>'); %>
+<% return ejs_data; }); %>
+
+<% template.define('contentArea', function() { var ejs_data=''; %>
+ <div id="editorcontainer">
+ <table>
+ <tr>
+ <th>Module name</th>
+ <th>Status</th>
+ <th></th>
+ </tr>
+ <% for (var plugin in plugins.pluginModules) { %>
+ <tr>
+ <td class="mousover_parent">
+ <%= plugin %>
+ <div class="mouseover_child">
+ <%= plugins.pluginModules[plugin].description %>
+ </div>
+ </td>
+ <td>
+ <% if (plugins.plugins[plugin] !== undefined) { %>
+ Installed
+ <% } else { %>
+ Not installed
+ <% } %>
+ </td>
+ <td>
+ <% if (plugins.plugins[plugin] !== undefined) { %>
+ <a href="/ep/admin/pluginmanager/?plugin=<%= plugin %>&action=uninstall">Uninstall</a>
+ <a href="/ep/admin/pluginmanager/?plugin=<%= plugin %>&action=reinstall">Reinstall</a>
+ <% if (plugins.plugins[plugin].configLink !== undefined) { %>
+ <a href="<%= plugins.plugins[plugin].configLink %>">Configure</a>
+ <% } %>
+ <% } else { %>
+ <a href="/ep/admin/pluginmanager/?plugin=<%= plugin %>&action=install">Install</a>
+ <% } %>
+ </td>
+ </tr>
+ <% } %>
+ </table>
+ </div>
+<% return ejs_data; }); %>
diff --git a/trunk/etherpad/src/templates/email/padinvite.ejs b/etherpad/src/themes/default/templates/email/padinvite.ejs
index 0f729e3..0f729e3 100644
--- a/trunk/etherpad/src/templates/email/padinvite.ejs
+++ b/etherpad/src/themes/default/templates/email/padinvite.ejs
diff --git a/trunk/etherpad/src/templates/framed/framedfooter.ejs b/etherpad/src/themes/default/templates/framed/framedfooter.ejs
index 7994e38..7994e38 100644
--- a/trunk/etherpad/src/templates/framed/framedfooter.ejs
+++ b/etherpad/src/themes/default/templates/framed/framedfooter.ejs
diff --git a/etherpad/src/themes/default/templates/framed/framedheader-pro.ejs b/etherpad/src/themes/default/templates/framed/framedheader-pro.ejs
new file mode 100644
index 0000000..afb8a67
--- /dev/null
+++ b/etherpad/src/themes/default/templates/framed/framedheader-pro.ejs
@@ -0,0 +1,78 @@
+<% /*
+Copyright 2009 Google Inc.
+Copyright 2010 Pita, Peter Martischka <petermartischka@googlemail.com>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %><% helpers.addBodyClass("pro-withtopbar"); %>
+
+<div id="pro-topbar">
+
+ <div id="pro-topbar-inner">
+
+ <% if (account) { %>
+ <div id="accountnav">
+ <%= toHTML(account.email) %>
+ <a href="/ep/account/sign-out">(sign out)</a>
+ </div>
+ <% } else { %>
+ <% // TODO: eventually have sign-in link here. %>
+ <% } %>
+
+ <div id="org-name">
+ <a href="/">
+ <%= proDomainOrgName %>
+ </a>
+
+ <% if (isAnEtherpadAdmin) { %>
+ <span style="color: #ff0; padding-left: 2em; font-weight: bold;">INVISIBLE ADMIN MODE</span>
+ <% } %>
+ </div>
+
+ <div style="clear: both;"><!-- --></div>
+
+ </div>
+</div>
+
+<% function renderProTopNav() {
+ var links = [
+ ['/', 'Home', 'home'],
+ ['/ep/padlist/', 'Pads', 'padlist'],
+ ['/ep/account/', 'My Account', 'account'],
+ ];
+ if (account && account.isAdmin) {
+ links.push(['/ep/admin/', 'Admin', 'admin']);
+ }
+ var ul = UL();
+ links.forEach(function(l) {
+ var c = l[2];
+ var selc = (request.path == l[0] || navSelection == c) ? " selected" : "";
+ ul.push(LI({className: 'topnav_'+c+selc},
+ A({href: request.scheme + '://'+request.host+l[0]}, l[1])));
+ });
+ return ul;
+} %>
+
+ <%= pneTrackerHtml %>
+
+<div id="pro-topnav">
+ <div id="pro-topnav-inner">
+ <%= renderProTopNav() %>
+ <%= helpers.clearFloats() %>
+ </div>
+</div>
+
+<!--
+<div id="shuttingdown">
+ <strong style="color:red">Note: EtherPad.com is shutting down March 31, 2010.</strong>
+ <a href="http://<%= fullSuperdomain %>/ep/blog/posts/google-acquires-appjet">(more info)</a>
+</div>
+-->
diff --git a/trunk/etherpad/src/templates/framed/framedheader.ejs b/etherpad/src/themes/default/templates/framed/framedheader.ejs
index d6c25cb..d6c25cb 100644
--- a/trunk/etherpad/src/templates/framed/framedheader.ejs
+++ b/etherpad/src/themes/default/templates/framed/framedheader.ejs
diff --git a/trunk/etherpad/src/templates/framed/framedpage-pro.ejs b/etherpad/src/themes/default/templates/framed/framedpage-pro.ejs
index b3acb07..b3acb07 100644
--- a/trunk/etherpad/src/templates/framed/framedpage-pro.ejs
+++ b/etherpad/src/themes/default/templates/framed/framedpage-pro.ejs
diff --git a/trunk/etherpad/src/templates/framed/framedpage.ejs b/etherpad/src/themes/default/templates/framed/framedpage.ejs
index b1590f8..b1590f8 100644
--- a/trunk/etherpad/src/templates/framed/framedpage.ejs
+++ b/etherpad/src/themes/default/templates/framed/framedpage.ejs
diff --git a/trunk/etherpad/src/templates/html.ejs b/etherpad/src/themes/default/templates/html.ejs
index 056d7a7..056d7a7 100644
--- a/trunk/etherpad/src/templates/html.ejs
+++ b/etherpad/src/themes/default/templates/html.ejs
diff --git a/etherpad/src/themes/default/templates/main/home.ejs b/etherpad/src/themes/default/templates/main/home.ejs
new file mode 100644
index 0000000..7041bee
--- /dev/null
+++ b/etherpad/src/themes/default/templates/main/home.ejs
@@ -0,0 +1,62 @@
+<% /*
+Copyright 2009 Google Inc.
+Copyright 2010 Pita, Peter Martischka <petermartischka@googlemail.com>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %><% helpers.setHtmlTitle("SplinePad [beta]: Open-Sourced!"); %>
+
+<% helpers.includeCss("home-opensource.css"); %>
+
+<div id="home">
+ <div id="title">
+ SplinePad
+ </div>
+
+ <div id="buttons">
+ <a id="home-newpad" href="/ep/pad/newpad">
+ Create new pad
+ </a>
+ <% if (isProAccountEnabled()) { %>
+ <a id="home-newteam" href="/ep/pro-signup/">
+ Create team site
+ </a>
+ <% } %>
+ </div>
+
+ <div id="tos">
+ <h1>
+ <b>Terms of service and Privacy notice</b>
+ </h1>
+
+ <p>
+ <b>Privacy:</b> We guarantee that we will not intentionally hand
+ over your data to any third party.
+ </p>
+
+ <p>
+ <b>Terms:</b> By using splinepad, you certify to agree to the
+ following terms of service: We are not responsible, and cannot
+ be held liable for any loss or damages that may be caused by the
+ result of our service.
+ </p>
+
+ <p>
+ <b>In short:</b> We love the "Datenschutzgesetz" and if
+ something is wrong, we didn't do it.
+ </p>
+
+ Have fun with splinepad.
+ </div>
+
+</div>
+
+
diff --git a/trunk/etherpad/src/templates/main/pro_signup_body.ejs b/etherpad/src/themes/default/templates/main/pro_signup_body.ejs
index ff35dfc..ff35dfc 100644
--- a/trunk/etherpad/src/templates/main/pro_signup_body.ejs
+++ b/etherpad/src/themes/default/templates/main/pro_signup_body.ejs
diff --git a/trunk/etherpad/src/templates/misc/pad_default.ejs b/etherpad/src/themes/default/templates/misc/pad_default.ejs
index 96b7e25..96b7e25 100644
--- a/trunk/etherpad/src/templates/misc/pad_default.ejs
+++ b/etherpad/src/themes/default/templates/misc/pad_default.ejs
diff --git a/trunk/etherpad/src/templates/notice.ejs b/etherpad/src/themes/default/templates/notice.ejs
index 311694f..311694f 100644
--- a/trunk/etherpad/src/templates/notice.ejs
+++ b/etherpad/src/themes/default/templates/notice.ejs
diff --git a/trunk/etherpad/src/templates/pad/create_body.ejs b/etherpad/src/themes/default/templates/pad/create_body.ejs
index 742821f..742821f 100644
--- a/trunk/etherpad/src/templates/pad/create_body.ejs
+++ b/etherpad/src/themes/default/templates/pad/create_body.ejs
diff --git a/etherpad/src/themes/default/templates/pad/pad_body2.ejs b/etherpad/src/themes/default/templates/pad/pad_body2.ejs
new file mode 100644
index 0000000..5c886fb
--- /dev/null
+++ b/etherpad/src/themes/default/templates/pad/pad_body2.ejs
@@ -0,0 +1,505 @@
+<% /*
+Copyright 2009 Google Inc.
+Copyright 2010 Pita, Peter Martischka
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %>
+
+<%
+ template.inherit('page.ejs');
+
+ helpers.setHtmlTitle("EtherPad: "+pageTitle);
+ helpers.includeJs("ace.js");
+ helpers.includeJs("collab_client.js");
+ helpers.includeJs("pad_userlist.js");
+ helpers.includeJs("pad_chat.js");
+ helpers.includeJs("pad_impexp.js");
+ helpers.includeJs("pad_savedrevs.js");
+ helpers.includeJs("pad_connectionstatus.js");
+
+ var padUrlAttrValue = request.url.split("?", 1)[0].replace(/\"/g, '&quot;');
+
+ function exportLink(type, n, label, requiresOffice, url, title) {
+ url = url || '/ep/pad/export/'+localPadId+'/latest?format='+type;
+ var classes = ["exportlink", "exporthref"+type, "n"+n];
+ if (requiresOffice && !hasOffice) {
+ classes.push("disabledexport");
+ }
+ else {
+ classes.push("requiresoffice");
+ }
+ var pieces = ['<a'];
+ pieces.push(' class="', classes.join(' '), '"');
+ pieces.push(' target="_blank"');
+ pieces.push(' href="', url, '"');
+ if (title) {
+ pieces.push(' title="', title.replace(/\"/g, "&quot;"), '"'); //"
+ }
+ pieces.push('>', label);
+ /* if (title) {
+ pieces.push('<sup>?</sup>');
+ }*/
+ pieces.push('</a>');
+ return pieces.join('');
+ }
+%>
+
+
+<% template.define('docBarTitle', function() { var ejs_data=''; %>
+ <td id="docbarpadtitle"><span><%= initialTitle %></span></td>
+<% return ejs_data; }); %>
+
+
+<% template.define('docBarTitleEditor', function() { var ejs_data=''; %>
+ <% if (isProAccountHolder) { %>
+ <div id="docbarrenamelink">
+ <a href="javascript:void(0)">(rename)</a>
+ </div>
+ <% } /* isProAccountHolder */ %>
+ <input type="text" id="padtitleedit"/>
+ <div id="padtitlebuttons">
+ <a id="padtitlesave" href="javascript:void(0)">Save</a>
+ <a id="padtitlecancel" href="javascript:void(0)">Cancel</a>
+ </div>
+<% return ejs_data; }); %>
+
+
+<% template.define('docBarItems', function() { var ejs_data=''; %>
+ <%: plugins.callHookStr('docbarItemsPad', {}, '', '<td class="docbarbutton">', '</td>'); %>
+ <% if (isProAccountHolder) { %>
+ <td id="docbarsecurity-outer" class="docbarbutton">
+ <a href="javascript:void(0)" id="docbarsecurity">
+ <img src="/static/img/jun09/pad/icon_security.gif">Security
+ </a>
+ </td>
+ <% } /* isProAccountHolder */ %>
+ <td id="docbaroptions-outer" class="docbarbutton">
+ <a href="javascript:void(0)" id="docbaroptions">
+ <img src="/static/img/jun09/pad/icon_pad_options.gif">Pad&nbsp;Options</a>
+ </td>
+ <td id="docbarimpexp-outer" class="docbarbutton">
+ <a href="javascript:void(0)" id="docbarimpexp">
+ <img src="/static/img/jun09/pad/icon_import_export.gif">Import/Export</a>
+ </td>
+ <td id="docbarsavedrevs-outer" class="docbarbutton">
+ <a href="javascript:void(0)" id="docbarsavedrevs">
+ <img src="/static/img/jun09/pad/icon_saved_revisions.gif">Saved&nbsp;revisions</a>
+ </td>
+ <td id="docbarslider-outer" class="docbarbutton highlight">
+ <a target="_blank" href="/ep/pad/view/<%= localPadId %>/latest" id="docbarslider">
+ <img src="/static/img/jun09/pad/icon_time_slider.gif">Time&nbsp;Slider</a>
+ </td>
+<% return ejs_data; }); %>
+
+
+<% template.define('docBarDropdowns', function() { var ejs_data=''; %>
+ <div id="impexp-wrapper" class="dbpanel-wrapper">
+ <div id="impexp-panel" class="dbpanel-panel">
+ <div class="dbpanel-leftedge"><!-- --></div>
+ <div class="dbpanel-rightedge"><!-- --></div>
+ <div class="dbpanel-botleftcorner"><!-- --></div>
+ <div class="dbpanel-botrightcorner"><!-- --></div>
+ <div class="dbpanel-middle">
+ <div class="dbpanel-inner">
+ <div class="dbpanel-top"><!-- --></div>
+ </div>
+ <div class="dbpanel-bottom"><!-- --></div>
+ <div id="importexport">
+ <div id="impexp-import">
+ <div id="impexp-importlabel"><b>Import</b> from text file, HTML, Word, or RTF:</div>
+ <form id="importform" method="post" action="/ep/pad/impexp/import"
+ target="importiframe" enctype="multipart/form-data">
+ <div class="importformdiv" id="importformfilediv">
+ <input type="file" name="file" size="20" id="importfileinput" />
+ <div class="importmessage" id="importmessagefail"></div>
+ </div>
+ <div class="importmessage" id="importmessagesuccess">Successful!</div>
+ <div class="importformdiv" id="importformsubmitdiv">
+ <input type="hidden" name="padId" value="<%= encodeURIComponent(localPadId) %>" />
+ <span class="nowrap">
+ <input type="submit" name="submit" value="Import Now" disabled="disabled" id="importsubmitinput" />
+ <img alt="" id="importstatusball" src="/static/img/misc/status-ball.gif" align="top" />
+ <img alt="" id="importarrow" src="/static/img/may09/leftarrow2.gif" align="top" />
+ </span>
+ </div>
+ </form>
+ </div><!-- /impexp-import -->
+ <div id="impexp-export">
+ <div id="impexp-exportlabel"><b>Export</b> current pad as:</div>
+ <div id="exportlinks">
+ <%= exportLink('html', 1, 'HTML', false) %>
+ <%= exportLink('txt', 2, 'Plain text', false) %>
+ <%= exportLink('link', 3, 'Bookmark file', false, '/ep/pad/linkfile?padId='+localPadId, 'This will save a file that, when opened, takes you to this pad.') %>
+ <%= exportLink('doc', 4, 'Microsoft Word', true) %>
+ <%= exportLink('pdf', 5, 'PDF', true) %>
+ <%= exportLink('odt', 6, 'OpenDocument', true) %>
+ </div>
+ </div><!-- /impexp-export -->
+ <div id="impexp-divider"><!-- --></div>
+ <div id="impexp-disabled-clickcatcher"><!-- --></div>
+ <a id="impexp-close" href="javascript:void(0)">Hide</a>
+ </div><!-- /importexport -->
+ </div>
+ </div>
+ </div>
+ <div id="savedrevs-wrapper" class="dbpanel-wrapper">
+ <div id="savedrevs-panel" class="dbpanel-panel">
+ <div class="dbpanel-leftedge"><!-- --></div>
+ <div class="dbpanel-rightedge"><!-- --></div>
+ <div class="dbpanel-botleftcorner"><!-- --></div>
+ <div class="dbpanel-botrightcorner"><!-- --></div>
+ <div class="dbpanel-middle">
+ <div class="dbpanel-inner">
+ <div class="dbpanel-top"><!-- --></div>
+ </div>
+ <div class="dbpanel-bottom"><!-- --></div>
+ </div>
+ <div id="savedrevisions">
+ <a href="javascript:void(0)" id="savedrevs-savenow">
+ Save Now
+ </a>
+ <div id="savedrevs-scrolly">
+ <div id="savedrevs-scrollleft" class="disabledscrollleft"><!-- --></div>
+ <div id="savedrevs-scrollright" class="disabledscrollright"><!-- --></div>
+ <div id="savedrevs-scrollouter">
+ <div id="savedrevs-scrollinner">
+ <!-- -->
+ </div>
+ </div>
+ </div>
+ <a id="savedrevs-close" href="javascript:void(0)">Hide</a>
+ </div><!-- /savedrevs close -->
+ </div>
+ </div><!-- /savedrevs-wrapper -->
+ <div id="revision-notifier"><span class="label">Saved:</span> <span class="name">Revision 1</span></div>
+ <div id="options-wrapper" class="dbpanel-wrapper">
+ <div id="options-panel" class="dbpanel-panel">
+ <div class="dbpanel-leftedge"><!-- --></div>
+ <div class="dbpanel-rightedge"><!-- --></div>
+ <div class="dbpanel-botleftcorner"><!-- --></div>
+ <div class="dbpanel-botrightcorner"><!-- --></div>
+ <div class="dbpanel-middle">
+ <div class="dbpanel-inner">
+ <div class="dbpanel-top"><!-- --></div>
+ </div>
+ <div class="dbpanel-bottom"><!-- --></div>
+ </div>
+ <div id="padoptions">
+ <div id="options-viewhead">Shared view options:</div>
+ <input type="checkbox" id="options-colorscheck" />
+ <label for="options-colorscheck" id="options-colorslabel">Authorship colors</label>
+ <input type="checkbox" id="options-linenoscheck" />
+ <label for="options-linenoscheck" id="options-linenoslabel">Line numbers</label>
+ <div id="options-fontlabel">Display font:</div>
+ <select id="viewfontmenu"><option value="normal">Normal</option><option value="monospace">Monospaced</option></select>
+ <div id="options-viewexplain">These options affect everyone's view of the pad.</div>
+ <a id="options-close" href="javascript:void(0)">Hide</a>
+ </div>
+ </div>
+ </div><!-- /options-wrapper -->
+ <% if (isProAccountHolder) { %>
+ <div id="security-wrapper" class="dbpanel-wrapper">
+ <div id="security-panel" class="dbpanel-panel">
+ <div class="dbpanel-leftedge"><!-- --></div>
+ <div class="dbpanel-rightedge"><!-- --></div>
+ <div class="dbpanel-botleftcorner"><!-- --></div>
+ <div class="dbpanel-botrightcorner"><!-- --></div>
+ <div class="dbpanel-middle">
+ <div class="dbpanel-inner">
+ <div class="dbpanel-top"><!-- --></div>
+ </div>
+ <div class="dbpanel-bottom"><!-- --></div>
+ </div>
+ <div id="padsecurity">
+ <div id="security-access">
+ <div id="security-accesshead">Pad Access:</div>
+ <input type="radio" name="padaccess" id="access-private" value="deny"/>
+ <label for="access-private" id="access-private-label"><strong>Private</strong> (Team account-holders only)</label>
+ <input type="radio" name="padaccess" id="access-public" value="allow"/>
+ <label for="access-public" id="access-public-label"><strong>Public</strong> (Allow Internet guests)</label>
+ </div>
+ <div id="security-password">
+ <div id="security-passhead">Password:</div>
+ <div id="security-passbody">
+ <div class="nopassword" id="password-nonedit">
+ <div id="password-display">None</div>
+ <a href="javascript:void(0)" id="password-setlink">Set...</a>
+ <a href="javascript:void(0)" id="password-clearlink">Clear</a>
+ </div>
+ <div id="password-inedit">
+ <a href="javascript:void(0)" id="password-savelink">Save</a>
+ <a href="javascript:void(0)" id="password-cancellink">Cancel</a>
+ <input type="text" id="security-passwordedit" maxlength="31" />
+ </div>
+ </div>
+ </div>
+ <a id="security-close" href="javascript:void(0)">Hide</a>
+ </div>
+ </div>
+ </div><!-- /security-wrapper -->
+ <% } /* isProAccountHolder */ %>
+<% return ejs_data; }); %>
+
+
+<% template.define('sideBar', function() { var ejs_data=''; %>
+ <div id="padusers">
+ <div id="connectionbox" class="cboxconnecting">
+ <div id="connectionboxinner">
+ <div class="connecting">
+ Connecting...
+ </div>
+ <div class="reconnecting">
+ Reestablishing connection...
+ </div>
+ <div class="disconnected">
+ <h2 class="h2_disconnect">Disconnected.</h2>
+ <h2 class="h2_userdup">Opened in another window.</h2>
+ <h2 class="h2_unauth">No Authorization.</h2>
+ <div id="disconnected_looping">
+ <p><b>We're having trouble talking to the EtherPad synchronization server.</b>
+ You may be connecting through an incompatible firewall or proxy server.</p>
+ </div>
+ <div id="disconnected_initsocketfail">
+ <p><b>We were unable to connect to the EtherPad synchronization server.</b>
+ This may be due to an incompatibility with your web
+ browser or internet connection.</p>
+ </div>
+ <div id="disconnected_userdup">
+ <p><b>You seem to have opened this pad in another browser window.</b>
+ If you'd like to use this window instead, you can reconnect.</p>
+ </div>
+ <div id="disconnected_unknown">
+ <p><b>Lost connection with the EtherPad synchronization
+ server.</b> This may be due to a loss of network connectivity.</p>
+ </div>
+ <div id="disconnected_slowcommit">
+ <p><b>Server not responding.</b> This may be due to network connectivity issues or high load on the server.</p>
+ </div>
+ <div id="disconnected_unauth">
+ <p>Your browser's credentials or permissions have changed while viewing this pad. Try reconnecting.</p>
+ </div>
+ <div id="reconnect_advise">
+ <p>If this continues to happen, please <a target="_blank" href="/ep/support">let us know</a>
+ (opens in new window).</p>
+ </div>
+ <div id="reconnect_form">
+ <button id="forcereconnect">Reconnect Now</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div id="connectionstatus">
+ <!-- -->
+ </div>
+
+ <div id="myuser">
+ <div id="mycolorpicker">
+ <div>
+ <div class="pickerswatchouter n1"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n2"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n3"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n4"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n5"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n6"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n7"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n8"><div class="pickerswatch"><!-- --></div></div>
+ </div><div>
+ <div class="pickerswatchouter n9"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n10"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n11"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n12"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n13"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n14"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n15"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n16"><div class="pickerswatch"><!-- --></div></div>
+ </div><div>
+ <div class="pickerswatchouter n17"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n18"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n19"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n20"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n21"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n22"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n23"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n24"><div class="pickerswatch"><!-- --></div></div>
+ </div><div>
+ <div class="pickerswatchouter n25"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n26"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n27"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n28"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n29"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n30"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n31"><div class="pickerswatch"><!-- --></div></div>
+ <div class="pickerswatchouter n32"><div class="pickerswatch"><!-- --></div></div>
+ </div>
+ <div id="mycolorpickersave">Save</div>
+ <div id="mycolorpickercancel">Cancel</div>
+ </div>
+ <div id="myswatchbox"><div id="myswatch"><!-- --></div></div>
+ <div id="myusernameform"><input type="text" id="myusernameedit" disabled="disabled" /></div>
+ <div id="mystatusform"><input type="text" id="mystatusedit" disabled="disabled" /></div>
+ </div>
+ <div id="otherusers">
+ <div id="guestprompts"><!-- --></div>
+ <table id="otheruserstable" cellspacing="0" cellpadding="0" border="0">
+ <tr><td></td></tr>
+ </table>
+ <div id="nootherusers"><a href="javascript:void(0)">Invite</a> other users and they will show up here.</div>
+ </div>
+ <div id="userlistbuttonarea">
+ <a href="javascript:void(0)" id="sharebutton">Share</a>
+ </div>
+ </div> <!-- /padusers -->
+
+ <div id="hdraggie"><!-- --></div>
+
+ <div id="padchat">
+ <!-- <div id="chattop"><a href="#">View chat logs...</a></div> -->
+ <div id="chatlines">
+ <a href="javascript:void(0)" id="chatloadmore">Load more history...</a>
+ <div id="chatloadingmore">Loading history...</div>
+ </div>
+ <div id="chatbottom">
+ <div id="chatprompt">Chat:</div>
+ <div id="chatentryform"><input type="text" id="chatentrybox"/></div>
+ </div>
+ </div>
+<% return ejs_data; }); %>
+
+
+<% template.define('editBarItemsLeft', function() { var ejs_data=''; %>
+ <td><img src="/static/img/jun09/pad/editbar_groupleft.gif" width="2" height="24"></td>
+ <td class="editbarbutton editbargroupsfirst"><a href="javascript:void (window.pad&&pad.editbarClick('bold'));" title="Bold (ctrl-B)"><img src="/static/img/jun09/pad/editbar_bold.gif"></a></td>
+ <td class="editbarbutton"> <a href="javascript:void (window.pad&&pad.editbarClick('italic'));" title="Italics (ctrl-I)"><img src="/static/img/jun09/pad/editbar_italic.gif"></a></td>
+ <td class="editbarbutton"> <a href="javascript:void (window.pad&&pad.editbarClick('underline'));" title="Underline (ctrl-U)"><img src="/static/img/jun09/pad/editbar_underline.gif"></a></td>
+ <td class="editbarbutton"> <a href="javascript:void (window.pad&&pad.editbarClick('strikethrough'));" title="Strikethrough"><img src="/static/img/jun09/pad/editbar_strikethrough.gif"></a></td>
+ <td><img src="/static/img/jun09/pad/editbar_groupright.gif" width="2" height="24"></td>
+
+ <td>&nbsp;&nbsp;</td>
+
+ <td><img src="/static/img/jun09/pad/editbar_groupleft.gif" width="2" height="24"></td>
+ <td class="editbarbutton editbargroupsfirst"><a href="javascript:void (window.pad&&pad.editbarClick('insertunorderedlist'));" title="Toggle Bullet List"><img src="/static/img/jun09/pad/editbar_insertunorderedlist.gif"></a></td>
+ <td><img src="/static/img/jun09/pad/editbar_groupright.gif" width="2" height="24"></td>
+
+ <td>&nbsp;&nbsp;</td>
+
+ <td><img src="/static/img/jun09/pad/editbar_groupleft.gif" width="2" height="24"></td>
+ <td class="editbarbutton editbargroupsfirst"><a href="javascript:void (window.pad&&pad.editbarClick('indent'));" title="Indent List"><img src="/static/img/jun09/pad/editbar_indent.gif"></a></td>
+ <td class="editbarbutton"><a href="javascript:void (window.pad&&pad.editbarClick('outdent'));" title="Unindent List"><img src="/static/img/jun09/pad/editbar_outdent.gif"></a></td>
+ <td><img src="/static/img/jun09/pad/editbar_groupright.gif" width="2" height="24"></td>
+
+ <td>&nbsp;&nbsp;</td>
+
+ <td><img src="/static/img/jun09/pad/editbar_groupleft.gif" width="2" height="24"></td>
+ <td class="editbarbutton editbargroupsfirst"><a href="javascript:void (window.pad&&pad.editbarClick('clearauthorship'));" title="Clear Authorship Colors"><img src="/static/img/jun09/pad/editbar_clearauthorship.gif"></a></td>
+ <td><img src="/static/img/jun09/pad/editbar_groupright.gif" width="2" height="24"></td>
+
+ <td>&nbsp;&nbsp;</td>
+
+ <td><img src="/static/img/jun09/pad/editbar_groupleft.gif" width="2" height="24"></td>
+ <td class="editbarbutton editbargroupsfirst"><a href="javascript:void (window.pad&&pad.editbarClick('undo'));" title="Undo (ctrl-Z)"><img src="/static/img/jun09/pad/editbar_undo.gif"></a></td>
+ <td class="editbarbutton"><a href="javascript:void (window.pad&&pad.editbarClick('redo'));" title="Redo (ctrl-Y)"><img src="/static/img/jun09/pad/editbar_redo.gif"></a></td>
+ <td><img src="/static/img/jun09/pad/editbar_groupright.gif" width="2" height="24"></td>
+<% return ejs_data; }); %>
+
+
+<% template.define('editBarItemsRight', function() { var ejs_data=''; %>
+ <td><img src="/static/img/jun09/pad/editbar_groupleft.gif" width="2" height="24"></td>
+ <td class="editbarbutton editbargroupsfirst"><a href="javascript:void (window.pad&&pad.editbarClick('save'));" title="Save Revision"><img src="/static/img/jun09/pad/editbar_save.gif"></a></td>
+ <td><img src="/static/img/jun09/pad/editbar_groupright.gif" width="2" height="24"></td>
+<% return ejs_data; }); %>
+
+
+<% template.define('contentArea', function() { var ejs_data=''; %>
+ <div id="editorloadingbox">Loading...</div>
+ <div id="editorcontainer"><!-- --></div>
+<% return ejs_data; }); %>
+
+
+<% template.define('modals', function() { var ejs_data=''; %>
+ <div id="modaloverlay"><div id="modaloverlay-inner"><!-- --></div></div>
+
+ <div id="mainmodals">
+ <div id="feedbackbox">
+ <div id="feedbackbox-tl"><!-- --></div>
+ <div id="feedbackbox-tr"><!-- --></div>
+ <div id="feedbackbox-bl"><!-- --></div>
+ <div id="feedbackbox-br"><!-- --></div>
+ <div id="feedbackbox-back"><!-- --></div>
+ <%/* <a href="javascript:void(0)" id="feedbackbox-send"><!-- --></a>
+ <input type="text" id="feedbackbox-email" class="modalfield" />
+ <textarea id="feedbackbox-message" rows="6" cols="40" class="modalfield"></textarea>
+ <div id="feedbackbox-response"><!-- --></div>*/%>
+ <div id="feedbackbox-contents">
+ <div id="feedbackbox-contentsinner">
+ <p><strong>Great, we love feedback! What kind?</strong></p>
+ <ul id="uservoicelinks">
+ <li><a href="http://uservoice.etherpad.com/pages/17280-feature-requests" target="_blank">Feature Request</a></li>
+ <li><a href="http://uservoice.etherpad.com/pages/17285-bugs-and-problems" target="_blank">Bug Report</a></li>
+ <li><a href="http://uservoice.etherpad.com/pages/22732-how-are-you-using-etherpad-" target="_blank">How I'm Using It</a></li>
+ <li><a href="http://uservoice.etherpad.com/pages/22751-general-questions" target="_blank">Other Question</a></li>
+ <li><a href="http://uservoice.etherpad.com/pages/22733-general-feedback" target="_blank">Other Feedback</a></li>
+ </ul>
+ <p>These links will open UserVoice in a new window.</p>
+ <p id="feedbackemails">You can also send email to <a href="feedback"><tt>feedback</tt></a>, <a href="support"><tt>support</tt></a>, or <a href="bugs"><tt>bugs</tt></a> at <tt>etherpad.com</tt>.</p>
+ </div>
+ </div>
+ <a href="javascript:void(0)" id="feedbackbox-hide"><!-- --></a>
+ </div>
+ <div id="sharebox">
+ <div id="sharebox-inner">
+ <a href="javascript:void(0)" id="sharebox-hide"><!-- --></a>
+ <div id="sharebox-stripe" class="sharebox-stripe-private">
+ <div class="public">
+ <strong>Public Pad:</strong> This pad is accessible to anyone who
+ visits its URL. To make it private, <a href="javascript:void(0)" class="setsecurity">change security settings</a>.
+ </div>
+ <div class="private">
+ <strong>Private Pad:</strong> This pad is only accessible to team account-holders. To allow anyone to access it, <a href="javascript:void(0)" class="setsecurity">change security settings</a>.
+ </div>
+ </div>
+ <div id="sharebox-forms">
+ <div id="sharebox-pastelink">Paste link over email or IM:</div>
+ <div id="sharebox-orsend">or send an email invitation...</div>
+ <a href="javascript:void(0)" id="sharebox-send"><!-- --></a>
+ <input id="sharebox-url" type="text" readonly="readonly" value="<%=padUrlAttrValue%>"/>
+ <input type="text" id="sharebox-to" class="modalfield" />
+ <input type="text" id="sharebox-subject" class="modalfield" />
+ <textarea id="sharebox-message" rows="6" cols="40" class="modalfield"></textarea>
+ <div id="sharebox-fieldname-to">To</div>
+ <div id="sharebox-fieldname-subject">Subject</div>
+ <div id="sharebox-fieldname-message">Message</div>
+ <div id="sharebox-dislink"><!-- --></div>
+ </div>
+ <div id="sharebox-shownwhenexpanded">
+ <div id="sharebox-response"><!-- --></div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <% if (request.params.djs) { %>
+ <div id="djs"><!-- --></div>
+ <% } %>
+
+ <form id="reconnectform"
+ method="post"
+ action="/ep/pad/reconnect"
+ accept-charset="UTF-8"
+ style="display: none;">
+ <input type="hidden" class="padId" name="padId" />
+ <input type="hidden" class="diagnosticInfo"
+ name="diagnosticInfo" />
+ <input type="hidden" class="missedChanges" name="missedChanges" />
+ </form>
+
+<% return ejs_data; }); %>
diff --git a/trunk/etherpad/src/templates/pad/pad_iphone_body.ejs b/etherpad/src/themes/default/templates/pad/pad_iphone_body.ejs
index 96279ce..96279ce 100644
--- a/trunk/etherpad/src/templates/pad/pad_iphone_body.ejs
+++ b/etherpad/src/themes/default/templates/pad/pad_iphone_body.ejs
diff --git a/trunk/etherpad/src/templates/pad/padview_body.ejs b/etherpad/src/themes/default/templates/pad/padview_body.ejs
index e18ff12..e18ff12 100644
--- a/trunk/etherpad/src/templates/pad/padview_body.ejs
+++ b/etherpad/src/themes/default/templates/pad/padview_body.ejs
diff --git a/etherpad/src/themes/default/templates/page.ejs b/etherpad/src/themes/default/templates/page.ejs
new file mode 100644
index 0000000..3d1632a
--- /dev/null
+++ b/etherpad/src/themes/default/templates/page.ejs
@@ -0,0 +1,135 @@
+<% /*
+Copyright 2009 Google Inc.
+Copyright 2010 Pita, Peter Martischka
+
+Licensed under the Apache License, Version 2.0 (the "License");
+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 "AS-IS" 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. */ %>
+<%
+ helpers.setBodyId("padbody");
+ helpers.addBodyClass(bodyClass);
+ helpers.includeCss("pad2_ejs.css");
+ helpers.includeJs("undo-xpopup.js");
+ helpers.includeCometJs();
+ helpers.includeJQuery();;
+ helpers.includeJs("json2.js");
+ helpers.includeJs("colorutils.js");
+ helpers.includeJs("draggable.js");
+ helpers.includeJs("pad_utils.js");
+ helpers.includeJs("pad_cookie.js");
+ helpers.includeJs("pad_editor.js");
+ helpers.includeJs("pad_editbar.js");
+ helpers.includeJs("pad_docbar.js");
+ helpers.includeJs("pad_modals.js");
+ helpers.includeJs("pad2.js");
+ helpers.suppressGA();
+ helpers.setRobotsPolicy({index: false, follow: false});
+
+%>
+
+<% template.define('body', function() { var ejs_data=''; %>
+ <div id="padpage">
+ <div id="padtop">
+ <div id="topbar">
+ <% /* floated left */ %>
+ <div id="topbarleft"><!-- --></div>
+ <% /* <a href="#" id="topbarnewpad">New Pad</a> */ %>
+ <% /* floated right */ %>
+ <div id="topbarright"><!-- --></div>
+ <% /* <a href="#" id="topbarfullwidth">Toggle Width</a> */ %>
+ <% /* non-floated */ %>
+ <div id="topbarcenter">
+ <a href="/" id="topbaretherpad">EtherPad</a>
+ </div>
+ <% if (isProAccountHolder) { %>
+ <a id="backtoprosite" href="/ep/padlist/">Return to pad list</a>
+ <div id="accountnav"><%= toHTML(account.email) %>
+ <a href="/ep/account/sign-out">(sign out)</a>
+ </div>
+ <% } else if (isPro) { %>
+ <div id="accountnav">
+ <a href="<%= signinUrl %>">sign in</a>
+ </div>
+ <% } %>
+ <div id="specialkeyarea"><!-- --></div>
+ </div>
+ <div id="alertbar">
+ <div id="servermsg">
+ <h3>Server Notice<span id="servermsgdate"><!-- --></span>:</h3>
+ <a id="hidetopmsg" href="javascript: void pad.hideServerMessage()">hide</a>
+ <p id="servermsgtext"><!-- --></p>
+ </div>
+ </div>
+
+ <div id="docbar">
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" id="docbartable">
+ <tr>
+ <td><img src="/static/img/jun09/pad/roundcorner_left.gif"></td>
+ <%: template.use('docBarTitle'); %>
+ <td width="100%">&nbsp;</td>
+ <%: template.use('docBarItems'); %>
+ <%: plugins.callHookStr('docbarItemsAll', {}, '', '', ''); %>
+ <td><img src="/static/img/jun09/pad/roundcorner_right_orange.gif"></td>
+ </tr>
+ </table>
+ <%: template.use('docBarTitleEditor'); %>
+ <%: template.use('docBarDropdowns'); %>
+ </div><!-- /docbar -->
+ </div>
+
+ <div id="padmain">
+ <div id="padsidebar"><%: template.use('sideBar'); %></div>
+
+ <div id="padeditor">
+ <div id="editbar" class="disabledtoolbar">
+ <% /* floated left */ %>
+ <div id="editbarleft"><!-- --></div>
+ <% /* floated right */ %>
+ <div id="editbarright"><!-- --></div>
+ <% /* non-floated */ %>
+ <div id="editbarinner">
+ <table cellpadding="0" cellspacing="0" border = "0" id="editbartable">
+ <tr>
+ <%: template.use('editBarItemsLeft'); %>
+ <td width="100%">&nbsp;</td>
+ </tr>
+ </table>
+ <table cellpadding="0" cellspacing="0" border = "0" id="editbarsavetable">
+ <tr>
+ <%: template.use('editBarItemsRight'); %>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id="editorcontainerbox"><%: template.use('contentArea'); %></div>
+ </div><!-- /padeditor -->
+
+ <div id="bottomarea">
+ <div id="viewbarcontents">
+ <div id="viewzoomtitle">Zoom:</div>
+ <select id="viewzoommenu"><option value="z85">85%</option><option value="z100">100%</option><option value="z115">115%</option><option value="z150">150%</option><option value="z200">200%</option><option value="z300">300%</option></select>
+ </div>
+
+ <div id="widthprefcheck"
+ class="<%= (prefs.isFullWidth?'widthprefchecked':'widthprefunchecked') %>"
+ ><!-- --></div>
+ <div id="sidebarcheck"
+ class="<%= (prefs.hideSidebar?'sidebarunchecked':'sidebarchecked') %>"
+ ><!-- --></div>
+ </div>
+
+ </div><!-- /padmain -->
+
+ </div><!-- /padpage -->
+
+ <%: template.use('modals'); %>
+
+<% return ejs_data; }); %>
diff --git a/trunk/etherpad/src/templates/pro-account/recover.ejs b/etherpad/src/themes/default/templates/pro-account/recover.ejs
index 686fe3b..686fe3b 100644
--- a/trunk/etherpad/src/templates/pro-account/recover.ejs
+++ b/etherpad/src/themes/default/templates/pro-account/recover.ejs
diff --git a/trunk/etherpad/src/templates/pro-account/sign-in.ejs b/etherpad/src/themes/default/templates/pro-account/sign-in.ejs
index 470bbc4..470bbc4 100644
--- a/trunk/etherpad/src/templates/pro-account/sign-in.ejs
+++ b/etherpad/src/themes/default/templates/pro-account/sign-in.ejs
diff --git a/trunk/etherpad/src/templates/pro/account/account-welcome-email.ejs b/etherpad/src/themes/default/templates/pro/account/account-welcome-email.ejs
index 33e1ac5..33e1ac5 100644
--- a/trunk/etherpad/src/templates/pro/account/account-welcome-email.ejs
+++ b/etherpad/src/themes/default/templates/pro/account/account-welcome-email.ejs
diff --git a/trunk/etherpad/src/templates/pro/account/forgot-password-email.ejs b/etherpad/src/themes/default/templates/pro/account/forgot-password-email.ejs
index 4595cee..4595cee 100644
--- a/trunk/etherpad/src/templates/pro/account/forgot-password-email.ejs
+++ b/etherpad/src/themes/default/templates/pro/account/forgot-password-email.ejs
diff --git a/trunk/etherpad/src/templates/pro/account/forgot-password.ejs b/etherpad/src/themes/default/templates/pro/account/forgot-password.ejs
index bbc78dd..bbc78dd 100644
--- a/trunk/etherpad/src/templates/pro/account/forgot-password.ejs
+++ b/etherpad/src/themes/default/templates/pro/account/forgot-password.ejs
diff --git a/trunk/etherpad/src/templates/pro/account/my-account.ejs b/etherpad/src/themes/default/templates/pro/account/my-account.ejs
index 9634285..9634285 100644
--- a/trunk/etherpad/src/templates/pro/account/my-account.ejs
+++ b/etherpad/src/themes/default/templates/pro/account/my-account.ejs
diff --git a/trunk/etherpad/src/templates/pro/account/signin.ejs b/etherpad/src/themes/default/templates/pro/account/signin.ejs
index c67bea6..c67bea6 100644
--- a/trunk/etherpad/src/templates/pro/account/signin.ejs
+++ b/etherpad/src/themes/default/templates/pro/account/signin.ejs
diff --git a/trunk/etherpad/src/templates/pro/admin/account-manager.ejs b/etherpad/src/themes/default/templates/pro/admin/account-manager.ejs
index f1b443f..f1b443f 100644
--- a/trunk/etherpad/src/templates/pro/admin/account-manager.ejs
+++ b/etherpad/src/themes/default/templates/pro/admin/account-manager.ejs
diff --git a/trunk/etherpad/src/templates/pro/admin/admin-template.ejs b/etherpad/src/themes/default/templates/pro/admin/admin-template.ejs
index a54964f..a54964f 100644
--- a/trunk/etherpad/src/templates/pro/admin/admin-template.ejs
+++ b/etherpad/src/themes/default/templates/pro/admin/admin-template.ejs
diff --git a/trunk/etherpad/src/templates/pro/admin/delete-account.ejs b/etherpad/src/themes/default/templates/pro/admin/delete-account.ejs
index 3de2122..3de2122 100644
--- a/trunk/etherpad/src/templates/pro/admin/delete-account.ejs
+++ b/etherpad/src/themes/default/templates/pro/admin/delete-account.ejs
diff --git a/trunk/etherpad/src/templates/pro/admin/manage-account.ejs b/etherpad/src/themes/default/templates/pro/admin/manage-account.ejs
index 72529b4..72529b4 100644
--- a/trunk/etherpad/src/templates/pro/admin/manage-account.ejs
+++ b/etherpad/src/themes/default/templates/pro/admin/manage-account.ejs
diff --git a/trunk/etherpad/src/templates/pro/admin/new-account.ejs b/etherpad/src/themes/default/templates/pro/admin/new-account.ejs
index 2f2cccf..2f2cccf 100644
--- a/trunk/etherpad/src/templates/pro/admin/new-account.ejs
+++ b/etherpad/src/themes/default/templates/pro/admin/new-account.ejs
diff --git a/trunk/etherpad/src/templates/pro/padlist/pro-padlist.ejs b/etherpad/src/themes/default/templates/pro/padlist/pro-padlist.ejs
index b762679..b762679 100644
--- a/trunk/etherpad/src/templates/pro/padlist/pro-padlist.ejs
+++ b/etherpad/src/themes/default/templates/pro/padlist/pro-padlist.ejs
diff --git a/trunk/etherpad/src/templates/pro/pro_home.ejs b/etherpad/src/themes/default/templates/pro/pro_home.ejs
index bcf7443..bcf7443 100644
--- a/trunk/etherpad/src/templates/pro/pro_home.ejs
+++ b/etherpad/src/themes/default/templates/pro/pro_home.ejs
diff --git a/trunk/infrastructure/.gitignore b/infrastructure/.gitignore
index 8cde493..8cde493 100644
--- a/trunk/infrastructure/.gitignore
+++ b/infrastructure/.gitignore
diff --git a/trunk/infrastructure/ace/.gitignore b/infrastructure/ace/.gitignore
index 4083037..4083037 100644
--- a/trunk/infrastructure/ace/.gitignore
+++ b/infrastructure/ace/.gitignore
diff --git a/trunk/infrastructure/ace/README b/infrastructure/ace/README
index 275684f..275684f 100644
--- a/trunk/infrastructure/ace/README
+++ b/infrastructure/ace/README
diff --git a/infrastructure/ace/bin/make b/infrastructure/ace/bin/make
new file mode 100755
index 0000000..98a48f4
--- /dev/null
+++ b/infrastructure/ace/bin/make
@@ -0,0 +1,339 @@
+#!/bin/sh
+mkdir -p ../../etherpad/src/etherpad/collab/ace
+mkdir -p ../../etherpad/src/static/js
+exec scala -classpath lib/yuicompressor-2.4-appjet.jar:lib/rhino-js-1.7r1.jar $0 $@
+!#
+
+import java.io._;
+
+def superpack(input: String): String = {
+ // this function is self-contained; takes a string, returns an expression
+ // that evaluates to that string
+ // XXX (This compresses well but decompression is too slow)
+
+ // constraints on special chars:
+ // - this string must be able to go in a character class
+ // - each char must be able to go in single quotes
+ val specialChars = "-~@%$#*^_`()|abcdefghijklmnopqrstuvwxyz=!+,.;:?{}";
+ val specialCharsSet:Set[Char] = Set(specialChars:_*);
+ def containsSpecialChar(str: String) = str.exists(specialCharsSet.contains(_));
+
+ val toks:Array[String] = (
+ "@|[a-zA-Z0-9]+|[^@a-zA-Z0-9]{1,3}").r.findAllIn(input).collect.toArray;
+
+ val stringCounts = {
+ val m = new scala.collection.mutable.HashMap[String,Int];
+ def incrementCount(s: String) = { m(s) = m.getOrElse(s, 0) + 1; }
+ for(s <- toks) incrementCount(s);
+ m;
+ }
+
+ val estimatedSavings = scala.util.Sorting.stableSort(
+ for((s,n) <- stringCounts.toArray; savings = s.length*n
+ if (savings > 8 || containsSpecialChar(s)))
+ yield (s,n,savings),
+ (x:(String,Int,Int))=> -x._3);
+
+ def strLast(str: String, n: Int) = str.substring(str.length - n, str.length);
+ // order of encodeNames is very important!
+ val encodeNames = for(n <- 0 until (36*36); c <- specialChars) yield c.toString+strLast("0"+Integer.toString(n, 36).toUpperCase, 2);
+
+ val thingsToReplace:Seq[String] = estimatedSavings.map(_._1);
+ assert(encodeNames.length >= thingsToReplace.length);
+
+ val replacements = Map(thingsToReplace.elements.zipWithIndex.map({
+ case (str, i) => (str, encodeNames(i));
+ }).collect:_*);
+ def encode(tk: String) = if (replacements.contains(tk)) replacements(tk) else tk;
+
+ val afterReplace = toks.map(encode(_)).mkString.replaceAll(
+ "(["+specialChars+"])(?=..[^0-9A-Z])(00|0)", "$1");
+
+ def makeSingleQuotedContents(str: String): String = {
+ str.replace("\\", "\\\\").replace("'", "\\'").replace("<", "\\x3c").replace("\n", "\\n").
+ replace("\r", "\\n").replace("\t", "\\t");
+ }
+
+ val expansionMap = new scala.collection.mutable.HashMap[Char,scala.collection.mutable.ArrayBuffer[String]];
+ for(i <- 0 until thingsToReplace.length; sc = encodeNames(i).charAt(0);
+ e = thingsToReplace(i)) {
+ expansionMap.getOrElseUpdate(sc, new scala.collection.mutable.ArrayBuffer[String]) +=
+ (if (e == "@") "" else e);
+ }
+ val expansionMapLiteral = "{"+(for((sc,strs) <- expansionMap) yield {
+ "'"+sc+"':'"+makeSingleQuotedContents(strs.mkString("@"))+"'";
+ }).mkString(",")+"}";
+
+ val expr = ("(function(m){m="+expansionMapLiteral+
+ ";for(var k in m){if(m.hasOwnProperty(k))m[k]=m[k].split('@')};return '"+
+ makeSingleQuotedContents(afterReplace)+
+ "'.replace(/(["+specialChars+
+ "])([0-9A-Z]{0,2})/g,function(a,b,c){return m[b][parseInt(c||'0',36)]||'@'})}())");
+ /*val expr = ("(function(m){m="+expansionMapLiteral+
+ ";for(var k in m){if(m.hasOwnProperty(k))m[k]=m[k].split('@')};"+
+ "var result=[];var i=0;var s='"+makeSingleQuotedContents(afterReplace)+
+ "';var len=s.length;while (i<len) {var x=s.charAt(i); var L=m[x],a = s.charAt(i+1),b = s.charAt(i+2);if (L) { var c;if (!(a >= 'A' && a <= 'Z' || a >= '0' && a <= '9')) {c=L[0];i++} else if (!(b >= 'A' && b <= 'Z' || b >= '0' && b <= '9')) {c = L[parseInt(a,36)]; i+=2} else {c = L[parseInt(a+b,36)]; i+=3}; result.push(c||'@'); } else {result.push(x); i++} }; return result.join(''); }())");*/
+
+ def evaluateString(js: String): String = {
+ import org.mozilla.javascript._;
+ ContextFactory.getGlobal.call(new ContextAction {
+ def run(cx: Context) = {
+ val scope = cx.initStandardObjects;
+ cx.evaluateString(scope, js, "<cmd>", 1, null) } }).asInstanceOf[String];
+ }
+
+ def putFile(str: String, path: String): Unit = {
+ import java.io._;
+ val writer = new FileWriter(path);
+ writer.write(str);
+ writer.close;
+ }
+
+ val exprOut = evaluateString(expr);
+ if (exprOut != input) {
+ putFile(input, "/tmp/superpack.input");
+ putFile(expr, "/tmp/superpack.expr");
+ putFile(exprOut, "/tmp/superpack.output");
+ error("Superpacked string does not evaluate to original string; check /tmp/superpack.*");
+ }
+
+ val singleLiteral = "'"+makeSingleQuotedContents(input)+"'";
+ if (singleLiteral.length < expr.length) {
+ singleLiteral;
+ }
+ else {
+ expr;
+ }
+}
+
+def doMake {
+
+ lazy val isEtherPad = (args.length >= 2 && args(1) == "etherpad");
+ lazy val isNoHelma = (args.length >= 2 && args(1) == "nohelma");
+
+ def getFile(path:String): String = {
+ val builder = new StringBuilder(1000);
+ val reader = new BufferedReader(new FileReader(path));
+ val buf = new Array[Char](1024);
+ var numRead = 0;
+ while({ numRead = reader.read(buf); numRead } != -1) {
+ builder.append(buf, 0, numRead);
+ }
+ reader.close;
+ return builder.toString;
+ }
+
+ def putFile(str: String, path: String): Unit = {
+ val writer = new FileWriter(path);
+ writer.write(str);
+ writer.close;
+ }
+
+ def writeToString(func:(Writer=>Unit)): String = {
+ val writer = new StringWriter;
+ func(writer);
+ return writer.toString;
+ }
+
+ def compressJS(code: String, wrap: Boolean): String = {
+ import yuicompressor.org.mozilla.javascript.{ErrorReporter, EvaluatorException};
+ object MyErrorReporter extends ErrorReporter {
+ def warning(message:String, sourceName:String, line:Int, lineSource:String, lineOffset:Int) {
+ if (message startsWith "Try to use a single 'var' statement per scope.") return;
+ if (line < 0) System.err.println("\n[WARNING] " + message);
+ else System.err.println("\n[WARNING] " + line + ':' + lineOffset + ':' + message);
+ }
+ def error(message:String, sourceName:String, line:Int, lineSource:String, lineOffset:Int) {
+ if (line < 0) System.err.println("\n[ERROR] " + message);
+ else System.err.println("\n[ERROR] " + line + ':' + lineOffset + ':' + message);
+ }
+ def runtimeError(message:String, sourceName:String, line:Int, lineSource:String, lineOffset:Int): EvaluatorException = {
+ error(message, sourceName, line, lineSource, lineOffset);
+ return new EvaluatorException(message);
+ }
+ }
+
+ val munge = true;
+ val verbose = false;
+ val optimize = true;
+ val compressor = new com.yahoo.platform.yui.compressor.JavaScriptCompressor(new StringReader(code), MyErrorReporter);
+ return writeToString(compressor.compress(_, if (wrap) 100 else -1, munge, verbose, true, !optimize));
+ }
+
+ def compressCSS(code: String, wrap: Boolean): String = {
+ val compressor = new com.yahoo.platform.yui.compressor.CssCompressor(new StringReader(code));
+ return writeToString(compressor.compress(_, if (wrap) 100 else -1));
+ }
+
+ import java.util.regex.{Pattern, Matcher, MatchResult};
+
+ def stringReplace(orig: String, regex: String, groupReferences:Boolean, func:(MatchResult=>String)): String = {
+ val buf = new StringBuffer;
+ val m = Pattern.compile(regex).matcher(orig);
+ while (m.find) {
+ var str = func(m);
+ if (! groupReferences) {
+ str = str.replace("\\", "\\\\").replace("$", "\\$");
+ }
+ m.appendReplacement(buf, str);
+ }
+ m.appendTail(buf);
+ return buf.toString;
+ }
+
+ def stringToExpression(str: String): String = {
+ var contents = str.replace("\\", "\\\\").replace("'", "\\'").replace("<", "\\x3c").replace("\n", "\\n").
+ replace("\r", "\\n").replace("\t", "\\t");
+ contents = contents.replace("\\/", "\\\\x2f"); // for Norton Internet Security
+ val result = "'"+contents+"'";
+ result;
+ }
+
+ val srcDir = "www";
+ val destDir = "build";
+ var code = getFile(srcDir+"/ace2_outer.js");
+
+ val useCompression = true; //if (isEtherPad) false else true;
+
+ code = stringReplace(code, "\\$\\$INCLUDE_([A-Z_]+)\\([\"']([^\"']+)[\"']\\)", false, (m:MatchResult) => {
+ val includeType = m.group(1);
+ val paths = m.group(2);
+ val pathsArray = paths.replaceAll("""/\*.*?\*/""", "").split(" +").filter(_.length > 0);
+ def getSubcode = pathsArray.map(p => getFile(srcDir+"/"+p)).mkString("\n");
+ val doPack = (stringToExpression _);
+ includeType match {
+ case "JS" => {
+ var subcode = getSubcode;
+ subcode = subcode.replaceAll("var DEBUG=true;//\\$\\$[^\n\r]*", "var DEBUG=false;");
+ if (useCompression) subcode = compressJS(subcode, true);
+ "('\\x3cscript type=\"text/javascript\">//<!--\\n'+" + doPack(subcode) +
+ "+'//-->\\n</script>')";
+ }
+ case "CSS" => {
+ var subcode = getSubcode;
+ if (useCompression) subcode = compressCSS(subcode, false);
+ "('<style type=\"text/css\">'+" + doPack(subcode) + "+'</style>')";
+ }
+ case "JS_Q" => {
+ var subcode = getSubcode
+ subcode = subcode.replaceAll("var DEBUG=true;//\\$\\$[^\n\r]*", "var DEBUG=false;");
+ if (useCompression) subcode = compressJS(subcode, true);
+ "('(\\'\\\\x3cscript type=\"text/javascript\">//<!--\\\\n\\'+'+" +
+ doPack(stringToExpression(subcode)) +
+ "+'+\\'//-->\\\\n\\\\x3c/script>\\')')";
+ }
+ case "CSS_Q" => {
+ var subcode = getSubcode;
+ if (useCompression) subcode = compressCSS(subcode, false);
+ "('(\\'<style type=\"text/css\">\\'+'+" + doPack(stringToExpression(subcode)) +
+ "+'+\\'\\\\x3c/style>\\')')";
+ }
+ case ("JS_DEV" | "CSS_DEV") => "''";
+ case ("JS_Q_DEV" | "CSS_Q_DEV") => "'\\'\\''";
+ //case _ => "$$INCLUDE_"+includeType+"(\"../www/"+path+"\")";
+ }
+ });
+
+ if (useCompression) code = compressJS(code, true);
+
+ putFile(code, destDir+"/ace2bare.js");
+
+ //var wrapper = getFile(srcDir+"/ace2_wrapper.js");
+ //if (useCompression) wrapper = compressJS(wrapper, true);
+ putFile(/*wrapper+"\n"+*/code, destDir+"/ace2.js");
+
+ var index = getFile(srcDir+"/index.html");
+ index = index.replaceAll("<!--\\s*DEBUG\\s*-->\\s*([\\s\\S]+?)\\s*<!--\\s*/DEBUG\\s*-->", "");
+ index = index.replaceAll("<!--\\s*PROD:\\s*([\\s\\S]+?)\\s*-->", "$1");
+ putFile(index, destDir+"/index.html");
+
+ putFile(getFile(srcDir+"/testcode.js"), destDir+"/testcode.js");
+
+ def copyFile(fromFile: String, toFile: String) {
+ if (0 != Runtime.getRuntime.exec("cp "+fromFile+" "+toFile).waitFor) {
+ printf("copy failed (%s -> %s).\n", fromFile, toFile);
+ }
+ }
+
+ def replaceFirstLine(txt: String, newFirstLine: String): String = {
+ var newlinePos = txt.indexOf('\n');
+ newFirstLine + txt.substring(newlinePos);
+ }
+
+ if (isEtherPad) {
+ copyFile("build/ace2.js", "../../etherpad/src/static/js/ace.js");
+
+ def copyFileToEtherpad(fromName: String, toName: String) {
+ var code = getFile(srcDir+"/"+fromName);
+ code = "// DO NOT EDIT THIS FILE, edit "+
+ "infrastructure/ace/www/"+fromName+"\n"+code;
+ code = code.replaceAll("""(?<=\n)\s*//\s*%APPJET%:\s*""", "");
+ putFile(code, "../../etherpad/src/etherpad/collab/ace/"+toName);
+ }
+ def copyFileToClientSide(fromName: String, toName: String) {
+ var code = getFile(srcDir+"/"+fromName);
+ code = "// DO NOT EDIT THIS FILE, edit "+
+ "infrastructure/ace/www/"+fromName+"\n"+code;
+ code = code.replaceAll("""(?<=\n)\s*//\s*%APPJET%:.*?\n""", "");
+ code = code.replaceAll("""(?<=\n)\s*//\s*%CLIENT FILE ENDS HERE%[\s\S]*""",
+ "");
+ putFile(code, "../../etherpad/src/static/js/"+toName);
+ }
+
+ copyFileToEtherpad("easy_sync.js", "easysync1.js");
+ copyFileToEtherpad("easysync2.js", "easysync2.js");
+ copyFileToEtherpad("contentcollector.js", "contentcollector.js");
+ copyFileToEtherpad("easysync2_tests.js", "easysync2_tests.js");
+ copyFileToClientSide("colorutils.js", "colorutils.js");
+ copyFileToClientSide("easysync2.js", "easysync2_client.js");
+ copyFileToEtherpad("linestylefilter.js", "linestylefilter.js");
+ copyFileToClientSide("linestylefilter.js", "linestylefilter_client.js");
+ copyFileToEtherpad("domline.js", "domline.js");
+ copyFileToClientSide("domline.js", "domline_client.js");
+ copyFileToClientSide("cssmanager.js", "cssmanager_client.js");
+ }
+ /*else if (! isNoHelma) {
+ copyFile("build/ace2.js", "../helma_apps/appjet/protectedStatic/js/ace.js");
+ }*/
+}
+
+def remakeLoop {
+
+ def getStamp: Long = {
+ return (new java.io.File("www").listFiles.
+ filter(! _.getName.endsWith("~")).
+ filter(! _.getName.endsWith("#")).
+ filter(! _.getName.startsWith(".")).map(_.lastModified).
+ reduceLeft(Math.max(_:Long,_:Long)));
+ }
+
+ var madeStamp:Long = 0;
+ var errorStamp:Long = 0;
+ while (true) {
+ Thread.sleep(500);
+ val s = getStamp;
+ if (s > madeStamp && s != errorStamp) {
+ Thread.sleep(1000);
+ if (getStamp == s) {
+ madeStamp = s;
+ print("Remaking... ");
+ try {
+ doMake;
+ println("OK");
+ }
+ catch { case e => {
+ println("ERROR");
+ errorStamp = s;
+ } }
+ }
+ }
+ }
+
+}
+
+if (args.length >= 1 && args(0) == "auto") {
+ remakeLoop;
+}
+else {
+ doMake;
+}
diff --git a/trunk/infrastructure/ace/bin/serve b/infrastructure/ace/bin/serve
index e02e042..e02e042 100755
--- a/trunk/infrastructure/ace/bin/serve
+++ b/infrastructure/ace/bin/serve
diff --git a/trunk/infrastructure/ace/blog.txt b/infrastructure/ace/blog.txt
index 0b095a2..0b095a2 100644
--- a/trunk/infrastructure/ace/blog.txt
+++ b/infrastructure/ace/blog.txt
diff --git a/trunk/infrastructure/ace/build/.gitignore b/infrastructure/ace/build/.gitignore
index 4dc709e..4dc709e 100644
--- a/trunk/infrastructure/ace/build/.gitignore
+++ b/infrastructure/ace/build/.gitignore
diff --git a/trunk/infrastructure/ace/build/index.html b/infrastructure/ace/build/index.html
index b8c8505..b8c8505 100644
--- a/trunk/infrastructure/ace/build/index.html
+++ b/infrastructure/ace/build/index.html
diff --git a/trunk/infrastructure/ace/build/jquery-1.2.1.js b/infrastructure/ace/build/jquery-1.2.1.js
index b4eb132..b4eb132 100644
--- a/trunk/infrastructure/ace/build/jquery-1.2.1.js
+++ b/infrastructure/ace/build/jquery-1.2.1.js
diff --git a/trunk/infrastructure/ace/build/testcode.js b/infrastructure/ace/build/testcode.js
index f393335..f393335 100644
--- a/trunk/infrastructure/ace/build/testcode.js
+++ b/infrastructure/ace/build/testcode.js
diff --git a/trunk/infrastructure/ace/easysync-notes.txt b/infrastructure/ace/easysync-notes.txt
index 6808f40..6808f40 100644
--- a/trunk/infrastructure/ace/easysync-notes.txt
+++ b/infrastructure/ace/easysync-notes.txt
diff --git a/trunk/infrastructure/ace/lib/rhino-js-1.7r1.jar b/infrastructure/ace/lib/rhino-js-1.7r1.jar
index f41e23b..f41e23b 120000
--- a/trunk/infrastructure/ace/lib/rhino-js-1.7r1.jar
+++ b/infrastructure/ace/lib/rhino-js-1.7r1.jar
diff --git a/trunk/infrastructure/ace/lib/yuicompressor-2.4-appjet.jar b/infrastructure/ace/lib/yuicompressor-2.4-appjet.jar
index 3953af5..3953af5 120000
--- a/trunk/infrastructure/ace/lib/yuicompressor-2.4-appjet.jar
+++ b/infrastructure/ace/lib/yuicompressor-2.4-appjet.jar
diff --git a/trunk/infrastructure/ace/notes.txt b/infrastructure/ace/notes.txt
index d9e1fda..d9e1fda 100644
--- a/trunk/infrastructure/ace/notes.txt
+++ b/infrastructure/ace/notes.txt
diff --git a/trunk/infrastructure/ace/www/ace2_common.js b/infrastructure/ace/www/ace2_common.js
index 4a08de6..4a08de6 100644
--- a/trunk/infrastructure/ace/www/ace2_common.js
+++ b/infrastructure/ace/www/ace2_common.js
diff --git a/trunk/infrastructure/ace/www/ace2_common_dev.js b/infrastructure/ace/www/ace2_common_dev.js
index 8fb88b0..8fb88b0 100644
--- a/trunk/infrastructure/ace/www/ace2_common_dev.js
+++ b/infrastructure/ace/www/ace2_common_dev.js
diff --git a/infrastructure/ace/www/ace2_inner.js b/infrastructure/ace/www/ace2_inner.js
new file mode 100644
index 0000000..33c13e8
--- /dev/null
+++ b/infrastructure/ace/www/ace2_inner.js
@@ -0,0 +1,4809 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+function OUTER(gscope) {
+
+ var DEBUG=true;//$$ build script replaces the string "var DEBUG=true;//$$" with "var DEBUG=false;"
+
+ var isSetUp = false;
+
+ var THE_TAB = ' ';//4
+ var MAX_LIST_LEVEL = 8;
+
+ var LINE_NUMBER_PADDING_RIGHT = 4;
+ var LINE_NUMBER_PADDING_LEFT = 4;
+ var MIN_LINEDIV_WIDTH = 20;
+ var EDIT_BODY_PADDING_TOP = 8;
+ var EDIT_BODY_PADDING_LEFT = 8;
+
+ var caughtErrors = [];
+
+ var thisAuthor = '';
+
+ var disposed = false;
+
+ var editorInfo = parent.editorInfo;
+
+ var iframe = window.frameElement;
+ var outerWin = iframe.ace_outerWin;
+ iframe.ace_outerWin = null; // prevent IE 6 memory leak
+ var sideDiv = iframe.nextSibling;
+ var lineMetricsDiv = sideDiv.nextSibling;
+ var overlaysdiv = lineMetricsDiv.nextSibling;
+ initLineNumbers();
+
+ var outsideKeyDown = function(evt) {};
+ var outsideKeyPress = function(evt) { return true; };
+ var outsideNotifyDirty = function() {};
+
+ // selFocusAtStart -- determines whether the selection extends "backwards", so that the focus
+ // point (controlled with the arrow keys) is at the beginning; not supported in IE, though
+ // native IE selections have that behavior (which we try not to interfere with).
+ // Must be false if selection is collapsed!
+ var rep = { lines: newSkipList(), selStart: null, selEnd: null, selFocusAtStart: false,
+ alltext: "", alines: [],
+ apool: new AttribPool() };
+ // lines, alltext, alines, and DOM are set up in setup()
+ if (undoModule.enabled) {
+ undoModule.apool = rep.apool;
+ }
+
+ var root, doc; // set in setup()
+
+ var isEditable = true;
+ var doesWrap = true;
+ var hasLineNumbers = true;
+ var isStyled = true;
+
+ // space around the innermost iframe element
+ var iframePadLeft = MIN_LINEDIV_WIDTH + LINE_NUMBER_PADDING_RIGHT + EDIT_BODY_PADDING_LEFT;
+ var iframePadTop = EDIT_BODY_PADDING_TOP;
+ var iframePadBottom = 0, iframePadRight = 0;
+
+ var console = (DEBUG && top.console);
+ if (! console) {
+ var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+ "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+ console = {};
+ for (var i = 0; i < names.length; ++i)
+ console[names[i]] = function() {};
+ //console.error = function(str) { alert(str); };
+ }
+ var PROFILER = window.PROFILER;
+ if (!PROFILER) {
+ PROFILER = function() { return {start:noop, mark:noop, literal:noop, end:noop, cancel:noop}; };
+ }
+ function noop() {}
+ function identity(x) { return x; }
+
+ // "dmesg" is for displaying messages in the in-page output pane
+ // visible when "?djs=1" is appended to the pad URL. It generally
+ // remains a no-op unless djs is enabled, but we make a habit of
+ // only calling it in error cases or while debugging.
+ var dmesg = noop;
+ window.dmesg = noop;
+
+ var scheduler = parent;
+
+ var textFace = 'monospace';
+ var textSize = 12;
+ function textLineHeight() { return Math.round(textSize * 4/3); }
+
+ var dynamicCSS = null;
+ function initDynamicCSS() {
+ dynamicCSS = makeCSSManager("dynamicsyntax");
+ }
+
+ var changesetTracker = makeChangesetTracker(scheduler, rep.apool, {
+ withCallbacks: function(operationName, f) {
+ inCallStackIfNecessary(operationName, function() {
+ fastIncorp(1);
+ f({
+ setDocumentAttributedText: function(atext) {
+ setDocAText(atext);
+ },
+ applyChangesetToDocument: function(changeset, preferInsertionAfterCaret) {
+ var oldEventType = currentCallStack.editEvent.eventType;
+ currentCallStack.startNewEvent("nonundoable");
+
+ performDocumentApplyChangeset(changeset, preferInsertionAfterCaret);
+
+ currentCallStack.startNewEvent(oldEventType);
+ }
+ });
+ });
+ }
+ });
+
+ var authorInfos = {}; // presence of key determines if author is present in doc
+
+ function setAuthorInfo(author, info) {
+ if ((typeof author) != "string") {
+ throw new Error("setAuthorInfo: author ("+author+") is not a string");
+ }
+ if (! info) {
+ delete authorInfos[author];
+ if (dynamicCSS) {
+ dynamicCSS.removeSelectorStyle(getAuthorColorClassSelector(getAuthorClassName(author)));
+ }
+ }
+ else {
+ authorInfos[author] = info;
+ if (info.bgcolor) {
+ if (dynamicCSS) {
+ var bgcolor = info.bgcolor;
+ if ((typeof info.fade) == "number") {
+ bgcolor = fadeColor(bgcolor, info.fade);
+ }
+
+ dynamicCSS.selectorStyle(getAuthorColorClassSelector(
+ getAuthorClassName(author))).backgroundColor = bgcolor;
+ }
+ }
+ }
+ }
+
+ function getAuthorClassName(author) {
+ return "author-"+author.replace(/[^a-y0-9]/g, function(c) {
+ if (c == ".") return "-";
+ return 'z'+c.charCodeAt(0)+'z';
+ });
+ }
+ function className2Author(className) {
+ if (className.substring(0,7) == "author-") {
+ return className.substring(7).replace(/[a-y0-9]+|-|z.+?z/g, function(cc) {
+ if (cc == '-') return '.';
+ else if (cc.charAt(0) == 'z') {
+ return String.fromCharCode(Number(cc.slice(1,-1)));
+ }
+ else {
+ return cc;
+ }
+ });
+ }
+ return null;
+ }
+ function getAuthorColorClassSelector(oneClassName) {
+ return ".authorColors ."+oneClassName;
+ }
+ function setUpTrackingCSS() {
+ if (dynamicCSS) {
+ var backgroundHeight = lineMetricsDiv.offsetHeight;
+ var lineHeight = textLineHeight();
+ var extraBodding = 0;
+ var extraTodding = 0;
+ if (backgroundHeight < lineHeight) {
+ extraBodding = Math.ceil((lineHeight - backgroundHeight)/2);
+ extraTodding = lineHeight - backgroundHeight - extraBodding;
+ }
+ var spanStyle = dynamicCSS.selectorStyle("#innerdocbody span");
+ spanStyle.paddingTop = extraTodding+"px";
+ spanStyle.paddingBottom = extraBodding+"px";
+ }
+ }
+ function boldColorFromColor(lightColorCSS) {
+ var color = colorutils.css2triple(lightColorCSS);
+
+ // amp up the saturation to full
+ color = colorutils.saturate(color);
+
+ // normalize brightness based on luminosity
+ color = colorutils.scaleColor(color, 0, 0.5 / colorutils.luminosity(color));
+
+ return colorutils.triple2css(color);
+ }
+ function fadeColor(colorCSS, fadeFrac) {
+ var color = colorutils.css2triple(colorCSS);
+ color = colorutils.blend(color, [1,1,1], fadeFrac);
+ return colorutils.triple2css(color);
+ }
+
+ function doAlert(str) {
+ scheduler.setTimeout(function() { alert(str); }, 0);
+ }
+
+ var currentCallStack = null;
+ function inCallStack(type, action) {
+ if (disposed) return;
+
+ if (currentCallStack) {
+ console.error("Can't enter callstack "+type+", already in "+
+ currentCallStack.type);
+ }
+
+ var profiling = false;
+ function profileRest() {
+ profiling = true;
+ console.profile();
+ }
+
+ function newEditEvent(eventType) {
+ return {eventType:eventType, backset: null};
+ }
+
+ function submitOldEvent(evt) {
+ if (rep.selStart && rep.selEnd) {
+ var selStartChar =
+ rep.lines.offsetOfIndex(rep.selStart[0]) + rep.selStart[1];
+ var selEndChar =
+ rep.lines.offsetOfIndex(rep.selEnd[0]) + rep.selEnd[1];
+ evt.selStart = selStartChar;
+ evt.selEnd = selEndChar;
+ evt.selFocusAtStart = rep.selFocusAtStart;
+ }
+ if (undoModule.enabled) {
+ var undoWorked = false;
+ try {
+ if (evt.eventType == "setup" || evt.eventType == "importText" ||
+ evt.eventType == "setBaseText") {
+ undoModule.clearHistory();
+ }
+ else if (evt.eventType == "nonundoable") {
+ if (evt.changeset) {
+ undoModule.reportExternalChange(evt.changeset);
+ }
+ }
+ else {
+ undoModule.reportEvent(evt);
+ }
+ undoWorked = true;
+ }
+ finally {
+ if (! undoWorked) {
+ undoModule.enabled = false; // for safety
+ }
+ }
+ }
+ }
+
+ function startNewEvent(eventType, dontSubmitOld) {
+ var oldEvent = currentCallStack.editEvent;
+ if (! dontSubmitOld) {
+ submitOldEvent(oldEvent);
+ }
+ currentCallStack.editEvent = newEditEvent(eventType);
+ return oldEvent;
+ }
+
+ currentCallStack = {type: type, docTextChanged: false, selectionAffected: false,
+ userChangedSelection: false,
+ domClean: false, profileRest:profileRest,
+ isUserChange: false, // is this a "user change" type of call-stack
+ repChanged: false, editEvent: newEditEvent(type),
+ startNewEvent:startNewEvent};
+ var cleanExit = false;
+ var result;
+ try {
+ result = action();
+ //console.log("Just did action for: "+type);
+ cleanExit = true;
+ }
+ catch (e) {
+ caughtErrors.push({error: e, time: +new Date()});
+ dmesg(e.toString());
+ throw e;
+ }
+ finally {
+ var cs = currentCallStack;
+ //console.log("Finished action for: "+type);
+ if (cleanExit) {
+ submitOldEvent(cs.editEvent);
+ if (cs.domClean && cs.type != "setup") {
+ if (cs.isUserChange) {
+ if (cs.repChanged) parenModule.notifyChange();
+ else parenModule.notifyTick();
+ }
+ recolorModule.recolorLines();
+ if (cs.selectionAffected) {
+ updateBrowserSelectionFromRep();
+ }
+ if ((cs.docTextChanged || cs.userChangedSelection) && cs.type != "applyChangesToBase") {
+ scrollSelectionIntoView();
+ }
+ if (cs.docTextChanged && cs.type.indexOf("importText") < 0) {
+ outsideNotifyDirty();
+ }
+ }
+ }
+ else {
+ // non-clean exit
+ if (currentCallStack.type == "idleWorkTimer") {
+ idleWorkTimer.atLeast(1000);
+ }
+ }
+ currentCallStack = null;
+ if (profiling) console.profileEnd();
+ }
+ return result;
+ }
+
+ function inCallStackIfNecessary(type, action) {
+ if (! currentCallStack) {
+ inCallStack(type, action);
+ }
+ else {
+ action();
+ }
+ }
+
+ function recolorLineByKey(key) {
+ if (rep.lines.containsKey(key)) {
+ var offset = rep.lines.offsetOfKey(key);
+ var width = rep.lines.atKey(key).width;
+ recolorLinesInRange(offset, offset + width);
+ }
+ }
+
+ function getLineKeyForOffset(charOffset) {
+ return rep.lines.atOffset(charOffset).key;
+ }
+
+ var recolorModule = (function() {
+ var dirtyLineKeys = {};
+
+ var module = {};
+ module.setCharNeedsRecoloring = function(offset) {
+ if (offset >= rep.alltext.length) {
+ offset = rep.alltext.length-1;
+ }
+ dirtyLineKeys[getLineKeyForOffset(offset)] = true;
+ }
+
+ module.setCharRangeNeedsRecoloring = function(offset1, offset2) {
+ if (offset1 >= rep.alltext.length) {
+ offset1 = rep.alltext.length-1;
+ }
+ if (offset2 >= rep.alltext.length) {
+ offset2 = rep.alltext.length-1;
+ }
+ var firstEntry = rep.lines.atOffset(offset1);
+ var lastKey = rep.lines.atOffset(offset2).key;
+ dirtyLineKeys[lastKey] = true;
+ var entry = firstEntry;
+ while (entry && entry.key != lastKey) {
+ dirtyLineKeys[entry.key] = true;
+ entry = rep.lines.next(entry);
+ }
+ }
+
+ module.recolorLines = function() {
+ for(var k in dirtyLineKeys) {
+ recolorLineByKey(k);
+ }
+ dirtyLineKeys = {};
+ }
+
+ return module;
+ })();
+
+ var parenModule = (function() {
+ var module = {};
+ module.notifyTick = function() { handleFlashing(false); };
+ module.notifyChange = function() { handleFlashing(true); };
+ module.shouldNormalizeOnChar = function (c) {
+ if (parenFlashRep.active) {
+ // avoid highlight style from carrying on to typed text
+ return true;
+ }
+ c = String.fromCharCode(c);
+ return !! (bracketMap[c]);
+ }
+
+ var parenFlashRep = { active: false, whichChars: null, whichLineKeys: null, expireTime: null };
+ var bracketMap = {'(': 1, ')':-1, '[':2, ']':-2, '{':3, '}':-3};
+ var bracketRegex = /[{}\[\]()]/g;
+ function handleFlashing(docChanged) {
+ function getSearchRange(aroundLoc) {
+ var rng = getVisibleCharRange();
+ var d = 100; // minimum radius
+ var e = 3000; // maximum radius;
+ if (rng[0] > aroundLoc-d) rng[0] = aroundLoc-d;
+ if (rng[0] < aroundLoc-e) rng[0] = aroundLoc-e;
+ if (rng[0] < 0) rng[0] = 0;
+ if (rng[1] < aroundLoc+d) rng[1] = aroundLoc+d;
+ if (rng[1] > aroundLoc+e) rng[1] = aroundLoc+e;
+ if (rng[1] > rep.lines.totalWidth()) rng[1] = rep.lines.totalWidth();
+ return rng;
+ }
+ function findMatchingVisibleBracket(startLoc, forwards) {
+ var rng = getSearchRange(startLoc);
+ var str = rep.alltext.substring(rng[0], rng[1]);
+ var bstr = str.replace(bracketRegex, '('); // handy for searching
+ var loc = startLoc - rng[0];
+ var bracketState = [];
+ var foundParen = false;
+ var goodParen = false;
+ function nextLoc() {
+ if (loc < 0) return;
+ if (forwards) loc++; else loc--;
+ if (loc < 0 || loc >= str.length) loc = -1;
+ if (loc >= 0) {
+ if (forwards) loc = bstr.indexOf('(', loc);
+ else loc = bstr.lastIndexOf('(', loc);
+ }
+ }
+ while ((! foundParen) && (loc >= 0)) {
+ if (getCharType(loc + rng[0]) == "p") {
+ var b = bracketMap[str.charAt(loc)]; // -1, 1, -2, 2, -3, 3
+ var into = forwards;
+ var typ = b;
+ if (typ < 0) { into = ! into; typ = -typ; }
+ if (into) bracketState.push(typ);
+ else {
+ var recent = bracketState.pop();
+ if (recent != typ) {
+ foundParen = true; goodParen = false;
+ }
+ else if (bracketState.length == 0) {
+ foundParen = true; goodParen = true;
+ }
+ }
+ }
+ //console.log(bracketState.toSource());
+ if ((! foundParen) && (loc >= 0)) nextLoc();
+ }
+ if (! foundParen) return null;
+ return {chr: (loc + rng[0]), good: goodParen};
+ }
+
+ var r = parenFlashRep;
+ var charsToHighlight = null;
+ var linesToUnhighlight = null;
+ if (r.active && (docChanged || (now() > r.expireTime))) {
+ linesToUnhighlight = r.whichLineKeys;
+ r.active = false;
+ }
+ if ((! r.active) && docChanged && isCaret() && caretColumn() > 0) {
+ var caret = caretDocChar();
+ if (caret > 0 && getCharType(caret-1) == "p") {
+ var charBefore = rep.alltext.charAt(caret-1);
+ if (bracketMap[charBefore]) {
+ var lookForwards = (bracketMap[charBefore] > 0);
+ var findResult = findMatchingVisibleBracket(caret-1, lookForwards);
+ if (findResult) {
+ var mateLoc = findResult.chr;
+ var mateGood = findResult.good;
+ r.active = true;
+ charsToHighlight = {};
+ charsToHighlight[caret-1] = 'flash';
+ charsToHighlight[mateLoc] = (mateGood ? 'flash' : 'flashbad');
+ r.whichLineKeys = [];
+ r.whichLineKeys.push(getLineKeyForOffset(caret-1));
+ r.whichLineKeys.push(getLineKeyForOffset(mateLoc));
+ r.expireTime = now() + 4000;
+ newlyActive = true;
+ }
+ }
+ }
+
+ }
+ if (linesToUnhighlight) {
+ recolorLineByKey(linesToUnhighlight[0]);
+ recolorLineByKey(linesToUnhighlight[1]);
+ }
+ if (r.active && charsToHighlight) {
+ function f(txt, cls, next, ofst) {
+ var flashClass = charsToHighlight[ofst];
+ if (cls) {
+ next(txt, cls+" "+flashClass);
+ }
+ else next(txt, cls);
+ }
+ for(var c in charsToHighlight) {
+ recolorLinesInRange((+c), (+c)+1, null, f);
+ }
+ }
+ }
+
+ return module;
+ })();
+
+ function dispose() {
+ disposed = true;
+ if (idleWorkTimer) idleWorkTimer.never();
+ teardown();
+ }
+
+ function checkALines() {
+ return; // disable for speed
+ function error() { throw new Error("checkALines"); }
+ if (rep.alines.length != rep.lines.length()) {
+ error();
+ }
+ for(var i=0;i<rep.alines.length;i++) {
+ var aline = rep.alines[i];
+ var lineText = rep.lines.atIndex(i).text+"\n";
+ var lineTextLength = lineText.length;
+ var opIter = Changeset.opIterator(aline);
+ var alineLength = 0;
+ while (opIter.hasNext()) {
+ var o = opIter.next();
+ alineLength += o.chars;
+ if (opIter.hasNext()) {
+ if (o.lines != 0) error();
+ }
+ else {
+ if (o.lines != 1) error();
+ }
+ }
+ if (alineLength != lineTextLength) {
+ error();
+ }
+ }
+ }
+
+ function setWraps(newVal) {
+ doesWrap = newVal;
+ var dwClass = "doesWrap";
+ setClassPresence(root, "doesWrap", doesWrap);
+ scheduler.setTimeout(function() {
+ inCallStackIfNecessary("setWraps", function() {
+ fastIncorp(7);
+ recreateDOM();
+ fixView();
+ });
+ }, 0);
+ }
+
+ function setStyled(newVal) {
+ var oldVal = isStyled;
+ isStyled = !!newVal;
+
+ if (newVal != oldVal) {
+ if (! newVal) {
+ // clear styles
+ inCallStackIfNecessary("setStyled", function() {
+ fastIncorp(12);
+ var clearStyles = [];
+ for(var k in STYLE_ATTRIBS) {
+ clearStyles.push([k,'']);
+ }
+ performDocumentApplyAttributesToCharRange(0, rep.alltext.length, clearStyles);
+ });
+ }
+ }
+ }
+
+ function setTextFace(face) {
+ textFace = face;
+ root.style.fontFamily = textFace;
+ lineMetricsDiv.style.fontFamily = textFace;
+ scheduler.setTimeout(function() {
+ setUpTrackingCSS();
+ }, 0);
+ }
+
+ function setTextSize(size) {
+ textSize = size;
+ root.style.fontSize = textSize+"px";
+ root.style.lineHeight = textLineHeight()+"px";
+ sideDiv.style.lineHeight = textLineHeight()+"px";
+ lineMetricsDiv.style.fontSize = textSize+"px";
+ scheduler.setTimeout(function() {
+ setUpTrackingCSS();
+ }, 0);
+ }
+
+ function recreateDOM() {
+ // precond: normalized
+ recolorLinesInRange(0, rep.alltext.length);
+ }
+
+ function setEditable(newVal) {
+ isEditable = newVal;
+
+ // the following may fail, e.g. if iframe is hidden
+ if (! isEditable) {
+ setDesignMode(false);
+ }
+ else {
+ setDesignMode(true);
+ }
+ setClassPresence(root, "static", ! isEditable);
+ }
+
+ function enforceEditability() {
+ setEditable(isEditable);
+ }
+
+ function importText(text, undoable, dontProcess) {
+ var lines;
+ if (dontProcess) {
+ if (text.charAt(text.length-1) != "\n") {
+ throw new Error("new raw text must end with newline");
+ }
+ if (/[\r\t\xa0]/.exec(text)) {
+ throw new Error("new raw text must not contain CR, tab, or nbsp");
+ }
+ lines = text.substring(0, text.length-1).split('\n');
+ }
+ else {
+ lines = map(text.split('\n'), textify);
+ }
+ var newText = "\n";
+ if (lines.length > 0) {
+ newText = lines.join('\n')+'\n';
+ }
+
+ inCallStackIfNecessary("importText"+(undoable?"Undoable":""), function() {
+ setDocText(newText);
+ });
+
+ if (dontProcess && rep.alltext != text) {
+ throw new Error("mismatch error setting raw text in importText");
+ }
+ }
+
+ function importAText(atext, apoolJsonObj, undoable) {
+ atext = Changeset.cloneAText(atext);
+ if (apoolJsonObj) {
+ var wireApool = (new AttribPool()).fromJsonable(apoolJsonObj);
+ atext.attribs = Changeset.moveOpsToNewPool(atext.attribs, wireApool, rep.apool);
+ }
+ inCallStackIfNecessary("importText"+(undoable?"Undoable":""), function() {
+ setDocAText(atext);
+ });
+ }
+
+ function setDocAText(atext) {
+ fastIncorp(8);
+
+ var oldLen = rep.lines.totalWidth();
+ var numLines = rep.lines.length();
+ var upToLastLine = rep.lines.offsetOfIndex(numLines-1);
+ var lastLineLength = rep.lines.atIndex(numLines-1).text.length;
+ var assem = Changeset.smartOpAssembler();
+ var o = Changeset.newOp('-');
+ o.chars = upToLastLine;
+ o.lines = numLines-1;
+ assem.append(o);
+ o.chars = lastLineLength;
+ o.lines = 0;
+ assem.append(o);
+ Changeset.appendATextToAssembler(atext, assem);
+ var newLen = oldLen + assem.getLengthChange();
+ var changeset = Changeset.checkRep(
+ Changeset.pack(oldLen, newLen, assem.toString(),
+ atext.text.slice(0, -1)));
+ performDocumentApplyChangeset(changeset);
+
+ performSelectionChange([0,rep.lines.atIndex(0).lineMarker],
+ [0,rep.lines.atIndex(0).lineMarker]);
+
+ idleWorkTimer.atMost(100);
+
+ if (rep.alltext != atext.text) {
+ dmesg(htmlPrettyEscape(rep.alltext));
+ dmesg(htmlPrettyEscape(atext.text));
+ throw new Error("mismatch error setting raw text in setDocAText");
+ }
+ }
+
+ function setDocText(text) {
+ setDocAText(Changeset.makeAText(text));
+ }
+
+ function getDocText() {
+ var alltext = rep.alltext;
+ var len = alltext.length;
+ if (len > 0) len--; // final extra newline
+ return alltext.substring(0, len);
+ }
+
+ function exportText() {
+ if (currentCallStack && ! currentCallStack.domClean) {
+ inCallStackIfNecessary("exportText", function() { fastIncorp(2); });
+ }
+ return getDocText();
+ }
+
+ function editorChangedSize() {
+ fixView();
+ }
+
+ function setOnKeyPress(handler) {
+ outsideKeyPress = handler;
+ }
+
+ function setOnKeyDown(handler) {
+ outsideKeyDown = handler;
+ }
+
+ function setNotifyDirty(handler) {
+ outsideNotifyDirty = handler;
+ }
+
+ function getFormattedCode() {
+ if (currentCallStack && ! currentCallStack.domClean) {
+ inCallStackIfNecessary("getFormattedCode", incorporateUserChanges);
+ }
+ var buf = [];
+ if (rep.lines.length() > 0) {
+ // should be the case, even for empty file
+ var entry = rep.lines.atIndex(0);
+ while (entry) {
+ var domInfo = entry.domInfo;
+ buf.push((domInfo && domInfo.getInnerHTML()) ||
+ domline.processSpaces(domline.escapeHTML(entry.text),
+ doesWrap) ||
+ '&nbsp;' /*empty line*/);
+ entry = rep.lines.next(entry);
+ }
+ }
+ return '<div class="syntax"><div>'+buf.join('</div>\n<div>')+
+ '</div></div>';
+ }
+
+ var CMDS = {
+ bold: function() { toggleAttributeOnSelection('bold'); },
+ italic: function() { toggleAttributeOnSelection('italic'); },
+ underline: function() { toggleAttributeOnSelection('underline'); },
+ strikethrough: function() { toggleAttributeOnSelection('strikethrough'); },
+ h1: function() { toggleAttributeOnSelection('h1'); },
+ h2: function() { toggleAttributeOnSelection('h2'); },
+ h3: function() { toggleAttributeOnSelection('h3'); },
+ h4: function() { toggleAttributeOnSelection('h4'); },
+ h5: function() { toggleAttributeOnSelection('h5'); },
+ h6: function() { toggleAttributeOnSelection('h6'); },
+ undo: function() { doUndoRedo('undo'); },
+ redo: function() { doUndoRedo('redo'); },
+ clearauthorship: function(prompt) {
+ if ((!(rep.selStart && rep.selEnd)) || isCaret()) {
+ if (prompt) {
+ prompt();
+ }
+ else {
+ performDocumentApplyAttributesToCharRange(0, rep.alltext.length,
+ [['author', '']]);
+ }
+ }
+ else {
+ setAttributeOnSelection('author', '');
+ }
+ },
+ insertunorderedlist: doInsertUnorderedList,
+ indent: function() {
+ if (! doIndentOutdent(false)) {
+ doInsertUnorderedList();
+ }
+ },
+ outdent: function() { doIndentOutdent(true); }
+ };
+
+ function execCommand(cmd) {
+ cmd = cmd.toLowerCase();
+ var cmdArgs = Array.prototype.slice.call(arguments, 1);
+ if (CMDS[cmd]) {
+ inCallStack(cmd, function() {
+ fastIncorp(9);
+ CMDS[cmd].apply(CMDS, cmdArgs);
+ });
+ }
+ }
+
+ editorInfo.ace_focus = focus;
+ editorInfo.ace_importText = importText;
+ editorInfo.ace_importAText = importAText;
+ editorInfo.ace_exportText = exportText;
+ editorInfo.ace_editorChangedSize = editorChangedSize;
+ editorInfo.ace_setOnKeyPress = setOnKeyPress;
+ editorInfo.ace_setOnKeyDown = setOnKeyDown;
+ editorInfo.ace_setNotifyDirty = setNotifyDirty;
+ editorInfo.ace_dispose = dispose;
+ editorInfo.ace_getFormattedCode = getFormattedCode;
+ editorInfo.ace_setEditable = setEditable;
+ editorInfo.ace_execCommand = execCommand;
+
+ editorInfo.ace_setProperty = function(key, value) {
+ var k = key.toLowerCase();
+ if (k == "wraps") {
+ setWraps(value);
+ }
+ else if (k == "showsauthorcolors") {
+ setClassPresence(root, "authorColors", !!value);
+ }
+ else if (k == "showsuserselections") {
+ setClassPresence(root, "userSelections", !!value);
+ }
+ else if (k == "showslinenumbers") {
+ hasLineNumbers = !!value;
+ setClassPresence(sideDiv, "sidedivhidden", ! hasLineNumbers);
+ fixView();
+ }
+ else if (k == "grayedout") {
+ setClassPresence(outerWin.document.body, "grayedout", !!value);
+ }
+ else if (k == "dmesg") {
+ dmesg = value;
+ window.dmesg = value;
+ }
+ else if (k == 'userauthor') {
+ thisAuthor = String(value);
+ }
+ else if (k == 'styled') {
+ setStyled(value);
+ }
+ else if (k == 'textface') {
+ setTextFace(value);
+ }
+ else if (k == 'textsize') {
+ setTextSize(value);
+ }
+ }
+
+ editorInfo.ace_setBaseText = function(txt) {
+ changesetTracker.setBaseText(txt);
+ };
+ editorInfo.ace_setBaseAttributedText = function(atxt, apoolJsonObj) {
+ setUpTrackingCSS();
+ changesetTracker.setBaseAttributedText(atxt, apoolJsonObj);
+ };
+ editorInfo.ace_applyChangesToBase = function(c, optAuthor, apoolJsonObj) {
+ changesetTracker.applyChangesToBase(c, optAuthor, apoolJsonObj);
+ };
+ editorInfo.ace_prepareUserChangeset = function() {
+ return changesetTracker.prepareUserChangeset();
+ };
+ editorInfo.ace_applyPreparedChangesetToBase = function() {
+ changesetTracker.applyPreparedChangesetToBase();
+ };
+ editorInfo.ace_setUserChangeNotificationCallback = function(f) {
+ changesetTracker.setUserChangeNotificationCallback(f);
+ };
+ editorInfo.ace_setAuthorInfo = function(author, info) {
+ setAuthorInfo(author, info);
+ };
+ editorInfo.ace_setAuthorSelectionRange = function(author, start, end) {
+ changesetTracker.setAuthorSelectionRange(author, start, end);
+ };
+
+ editorInfo.ace_getUnhandledErrors = function() {
+ return caughtErrors.slice();
+ };
+
+ editorInfo.ace_getDebugProperty = function(prop) {
+ if (prop == "debugger") {
+ // obfuscate "eval" so as not to scare yuicompressor
+ window['ev'+'al']("debugger");
+ }
+ else if (prop == "rep") {
+ return rep;
+ }
+ else if (prop == "window") {
+ return window;
+ }
+ else if (prop == "document") {
+ return document;
+ }
+ return undefined;
+ };
+
+ function now() { return (new Date()).getTime(); }
+
+ function newTimeLimit(ms) {
+ //console.debug("new time limit");
+ var startTime = now();
+ var lastElapsed = 0;
+ var exceededAlready = false;
+ var printedTrace = false;
+ var isTimeUp = function () {
+ if (exceededAlready) {
+ if ((! printedTrace)) {// && now() - startTime - ms > 300) {
+ //console.trace();
+ printedTrace = true;
+ }
+ return true;
+ }
+ var elapsed = now() - startTime;
+ if (elapsed > ms) {
+ exceededAlready = true;
+ //console.debug("time limit hit, before was %d/%d", lastElapsed, ms);
+ //console.trace();
+ return true;
+ }
+ else {
+ lastElapsed = elapsed;
+ return false;
+ }
+ }
+ isTimeUp.elapsed = function() { return now() - startTime; }
+ return isTimeUp;
+ }
+
+
+ function makeIdleAction(func) {
+ var scheduledTimeout = null;
+ var scheduledTime = 0;
+ function unschedule() {
+ if (scheduledTimeout) {
+ scheduler.clearTimeout(scheduledTimeout);
+ scheduledTimeout = null;
+ }
+ }
+ function reschedule(time) {
+ unschedule();
+ scheduledTime = time;
+ var delay = time - now();
+ if (delay < 0) delay = 0;
+ scheduledTimeout = scheduler.setTimeout(callback, delay);
+ }
+ function callback() {
+ scheduledTimeout = null;
+ // func may reschedule the action
+ func();
+ }
+ return {
+ atMost: function (ms) {
+ var latestTime = now() + ms;
+ if ((! scheduledTimeout) || scheduledTime > latestTime) {
+ reschedule(latestTime);
+ }
+ },
+ // atLeast(ms) will schedule the action if not scheduled yet.
+ // In other words, "infinity" is replaced by ms, even though
+ // it is technically larger.
+ atLeast: function (ms) {
+ var earliestTime = now()+ms;
+ if ((! scheduledTimeout) || scheduledTime < earliestTime) {
+ reschedule(earliestTime);
+ }
+ },
+ never: function() {
+ unschedule();
+ }
+ }
+ }
+
+ function fastIncorp(n) {
+ // normalize but don't do any lexing or anything
+ incorporateUserChanges(newTimeLimit(0));
+ }
+
+ function incorpIfQuick() {
+ var me = incorpIfQuick;
+ var failures = (me.failures || 0);
+ if (failures < 5) {
+ var isTimeUp = newTimeLimit(40);
+ var madeChanges = incorporateUserChanges(isTimeUp);
+ if (isTimeUp()) {
+ me.failures = failures+1;
+ }
+ return true;
+ }
+ else {
+ var skipCount = (me.skipCount || 0);
+ skipCount++;
+ if (skipCount == 20) {
+ skipCount = 0;
+ me.failures = 0;
+ }
+ me.skipCount = skipCount;
+ }
+ return false;
+ }
+
+ var idleWorkTimer = makeIdleAction(function() {
+
+ //if (! top.BEFORE) top.BEFORE = [];
+ //top.BEFORE.push(magicdom.root.dom.innerHTML);
+
+ if (! isEditable) return; // and don't reschedule
+
+ if (inInternationalComposition) {
+ // don't do idle input incorporation during international input composition
+ idleWorkTimer.atLeast(500);
+ return;
+ }
+
+ inCallStack("idleWorkTimer", function() {
+
+ var isTimeUp = newTimeLimit(250);
+
+ //console.time("idlework");
+
+ var finishedImportantWork = false;
+ var finishedWork = false;
+
+ try {
+
+ // isTimeUp() is a soft constraint for incorporateUserChanges,
+ // which always renormalizes the DOM, no matter how long it takes,
+ // but doesn't necessarily lex and highlight it
+ incorporateUserChanges(isTimeUp);
+
+ if (isTimeUp()) return;
+
+ updateLineNumbers(); // update line numbers if any time left
+
+ if (isTimeUp()) return;
+
+ var visibleRange = getVisibleCharRange();
+ var docRange = [0, rep.lines.totalWidth()];
+ //console.log("%o %o", docRange, visibleRange);
+
+ finishedImportantWork = true;
+ finishedWork = true;
+ }
+ finally {
+ //console.timeEnd("idlework");
+ if (finishedWork) {
+ idleWorkTimer.atMost(1000);
+ }
+ else if (finishedImportantWork) {
+ // if we've finished highlighting the view area,
+ // more highlighting could be counter-productive,
+ // e.g. if the user just opened a triple-quote and will soon close it.
+ idleWorkTimer.atMost(500);
+ }
+ else {
+ var timeToWait = Math.round(isTimeUp.elapsed() / 2);
+ if (timeToWait < 100) timeToWait = 100;
+ idleWorkTimer.atMost(timeToWait);
+ }
+ }
+ });
+
+ //if (! top.AFTER) top.AFTER = [];
+ //top.AFTER.push(magicdom.root.dom.innerHTML);
+
+ });
+
+ var _nextId = 1;
+ function uniqueId(n) {
+ // not actually guaranteed to be unique, e.g. if user copy-pastes
+ // nodes with ids
+ var nid = n.id;
+ if (nid) return nid;
+ return (n.id = "magicdomid"+(_nextId++));
+ }
+
+
+ function recolorLinesInRange(startChar, endChar, isTimeUp, optModFunc) {
+ if (endChar <= startChar) return;
+ if (startChar < 0 || startChar >= rep.lines.totalWidth()) return;
+ var lineEntry = rep.lines.atOffset(startChar); // rounds down to line boundary
+ var lineStart = rep.lines.offsetOfEntry(lineEntry);
+ var lineIndex = rep.lines.indexOfEntry(lineEntry);
+ var selectionNeedsResetting = false;
+ var firstLine = null;
+ var lastLine = null;
+ isTimeUp = (isTimeUp || noop);
+
+ // tokenFunc function; accesses current value of lineEntry and curDocChar,
+ // also mutates curDocChar
+ var curDocChar;
+ var tokenFunc = function(tokenText, tokenClass) {
+ lineEntry.domInfo.appendSpan(tokenText, tokenClass);
+ };
+ if (optModFunc) {
+ var f = tokenFunc;
+ tokenFunc = function(tokenText, tokenClass) {
+ optModFunc(tokenText, tokenClass, f, curDocChar);
+ curDocChar += tokenText.length;
+ };
+ }
+
+ while (lineEntry && lineStart < endChar && ! isTimeUp()) {
+ //var timer = newTimeLimit(200);
+ var lineEnd = lineStart + lineEntry.width;
+
+ curDocChar = lineStart;
+ lineEntry.domInfo.clearSpans();
+ getSpansForLine(lineEntry, tokenFunc, lineStart);
+ lineEntry.domInfo.finishUpdate();
+
+ markNodeClean(lineEntry.lineNode);
+
+ if (rep.selStart && rep.selStart[0] == lineIndex ||
+ rep.selEnd && rep.selEnd[0] == lineIndex) {
+ selectionNeedsResetting = true;
+ }
+
+ //if (timer()) console.dirxml(lineEntry.lineNode.dom);
+
+ if (firstLine === null) firstLine = lineIndex;
+ lastLine = lineIndex;
+ lineStart = lineEnd;
+ lineEntry = rep.lines.next(lineEntry);
+ lineIndex++;
+ }
+ if (selectionNeedsResetting) {
+ currentCallStack.selectionAffected = true;
+ }
+ //console.debug("Recolored line range %d-%d", firstLine, lastLine);
+ }
+
+ // like getSpansForRange, but for a line, and the func takes (text,class)
+ // instead of (width,class); excludes the trailing '\n' from
+ // consideration by func
+ function getSpansForLine(lineEntry, textAndClassFunc, lineEntryOffsetHint) {
+ var lineEntryOffset = lineEntryOffsetHint;
+ if ((typeof lineEntryOffset) != "number") {
+ lineEntryOffset = rep.lines.offsetOfEntry(lineEntry);
+ }
+ var text = lineEntry.text;
+ var width = lineEntry.width; // text.length+1
+
+ if (text.length == 0) {
+ // allow getLineStyleFilter to set line-div styles
+ var func = linestylefilter.getLineStyleFilter(
+ 0, '', textAndClassFunc, rep.apool);
+ func('', '');
+ }
+ else {
+ var offsetIntoLine = 0;
+ var filteredFunc = linestylefilter.getFilterStack(text, textAndClassFunc, browser);
+ var lineNum = rep.lines.indexOfEntry(lineEntry);
+ var aline = rep.alines[lineNum];
+ filteredFunc = linestylefilter.getLineStyleFilter(
+ text.length, aline, filteredFunc, rep.apool);
+ filteredFunc(text, '');
+ }
+ }
+
+
+ function getCharType(charIndex) {
+ return '';
+ }
+
+ var observedChanges;
+ function clearObservedChanges() {
+ observedChanges = { cleanNodesNearChanges: {} };
+ }
+ clearObservedChanges();
+
+ function getCleanNodeByKey(key) {
+ var p = PROFILER("getCleanNodeByKey", false);
+ p.extra = 0;
+ var n = doc.getElementById(key);
+ // copying and pasting can lead to duplicate ids
+ while (n && isNodeDirty(n)) {
+ p.extra++;
+ n.id = "";
+ n = doc.getElementById(key);
+ }
+ p.literal(p.extra, "extra");
+ p.end();
+ return n;
+ }
+
+ function observeChangesAroundNode(node) {
+ // Around this top-level DOM node, look for changes to the document
+ // (from how it looks in our representation) and record them in a way
+ // that can be used to "normalize" the document (apply the changes to our
+ // representation, and put the DOM in a canonical form).
+
+ //top.console.log("observeChangesAroundNode(%o)", node);
+
+ var cleanNode;
+ var hasAdjacentDirtyness;
+ if (! isNodeDirty(node)) {
+ cleanNode = node;
+ var prevSib = cleanNode.previousSibling;
+ var nextSib = cleanNode.nextSibling;
+ hasAdjacentDirtyness = ((prevSib && isNodeDirty(prevSib))
+ || (nextSib && isNodeDirty(nextSib)));
+ }
+ else {
+ // node is dirty, look for clean node above
+ var upNode = node.previousSibling;
+ while (upNode && isNodeDirty(upNode)) {
+ upNode = upNode.previousSibling;
+ }
+ if (upNode) {
+ cleanNode = upNode;
+ }
+ else {
+ var downNode = node.nextSibling;
+ while (downNode && isNodeDirty(downNode)) {
+ downNode = downNode.nextSibling;
+ }
+ if (downNode) {
+ cleanNode = downNode;
+ }
+ }
+ if (! cleanNode) {
+ // Couldn't find any adjacent clean nodes!
+ // Since top and bottom of doc is dirty, the dirty area will be detected.
+ return;
+ }
+ hasAdjacentDirtyness = true;
+ }
+
+ if (hasAdjacentDirtyness) {
+ // previous or next line is dirty
+ observedChanges.cleanNodesNearChanges['$'+uniqueId(cleanNode)] = true;
+ }
+ else {
+ // next and prev lines are clean (if they exist)
+ var lineKey = uniqueId(cleanNode);
+ var prevSib = cleanNode.previousSibling;
+ var nextSib = cleanNode.nextSibling;
+ var actualPrevKey = ((prevSib && uniqueId(prevSib)) || null);
+ var actualNextKey = ((nextSib && uniqueId(nextSib)) || null);
+ var repPrevEntry = rep.lines.prev(rep.lines.atKey(lineKey));
+ var repNextEntry = rep.lines.next(rep.lines.atKey(lineKey));
+ var repPrevKey = ((repPrevEntry && repPrevEntry.key) || null);
+ var repNextKey = ((repNextEntry && repNextEntry.key) || null);
+ if (actualPrevKey != repPrevKey || actualNextKey != repNextKey) {
+ observedChanges.cleanNodesNearChanges['$'+uniqueId(cleanNode)] = true;
+ }
+ }
+ }
+
+ function observeChangesAroundSelection() {
+ if (currentCallStack.observedSelection) return;
+ currentCallStack.observedSelection = true;
+
+ var p = PROFILER("getSelection", false);
+ var selection = getSelection();
+ p.end();
+ if (selection) {
+ function topLevel(n) {
+ if ((!n) || n == root) return null;
+ while (n.parentNode != root) {
+ n = n.parentNode;
+ }
+ return n;
+ }
+ var node1 = topLevel(selection.startPoint.node);
+ var node2 = topLevel(selection.endPoint.node);
+ if (node1) observeChangesAroundNode(node1);
+ if (node2 && node1 != node2) {
+ observeChangesAroundNode(node2);
+ }
+ }
+ }
+
+ function observeSuspiciousNodes() {
+ // inspired by Firefox bug #473255, where pasting formatted text
+ // causes the cursor to jump away, making the new HTML never found.
+ if (root.getElementsByTagName) {
+ var nds = root.getElementsByTagName("style");
+ for(var i=0;i<nds.length;i++) {
+ var n = nds[i];
+ while (n.parentNode && n.parentNode != root) {
+ n = n.parentNode;
+ }
+ if (n.parentNode == root) {
+ observeChangesAroundNode(n);
+ }
+ }
+ }
+ }
+
+ function incorporateUserChanges(isTimeUp) {
+
+ if (currentCallStack.domClean) return false;
+
+ inInternationalComposition = false; // if we need the document normalized, so be it
+
+ currentCallStack.isUserChange = true;
+
+ isTimeUp = (isTimeUp || function() { return false; });
+
+ if (DEBUG && top.DONT_INCORP || window.DEBUG_DONT_INCORP) return false;
+
+ var p = PROFILER("incorp", false);
+
+ //if (doc.body.innerHTML.indexOf("AppJet") >= 0)
+ //dmesg(htmlPrettyEscape(doc.body.innerHTML));
+ //if (top.RECORD) top.RECORD.push(doc.body.innerHTML);
+
+ // returns true if dom changes were made
+
+ if (! root.firstChild) {
+ root.innerHTML = "<div><!-- --></div>";
+ }
+
+ p.mark("obs");
+ observeChangesAroundSelection();
+ observeSuspiciousNodes();
+ p.mark("dirty");
+ var dirtyRanges = getDirtyRanges();
+ //console.log("dirtyRanges: "+toSource(dirtyRanges));
+
+ var dirtyRangesCheckOut = true;
+ var j = 0;
+ var a,b;
+ while (j < dirtyRanges.length) {
+ a = dirtyRanges[j][0];
+ b = dirtyRanges[j][1];
+ if (! ((a == 0 || getCleanNodeByKey(rep.lines.atIndex(a-1).key)) &&
+ (b == rep.lines.length() || getCleanNodeByKey(rep.lines.atIndex(b).key)))) {
+ dirtyRangesCheckOut = false;
+ break;
+ }
+ j++;
+ }
+ if (! dirtyRangesCheckOut) {
+ var numBodyNodes = root.childNodes.length;
+ for(var k=0;k<numBodyNodes;k++) {
+ var bodyNode = root.childNodes.item(k);
+ if ((bodyNode.tagName) && ((! bodyNode.id) || (! rep.lines.containsKey(bodyNode.id)))) {
+ observeChangesAroundNode(bodyNode);
+ }
+ }
+ dirtyRanges = getDirtyRanges();
+ }
+
+ clearObservedChanges();
+
+ p.mark("getsel");
+ var selection = getSelection();
+
+ //console.log(magicdom.root.dom.innerHTML);
+ //console.log("got selection: %o", selection);
+ var selStart, selEnd; // each one, if truthy, has [line,char] needed to set selection
+
+ var i = 0;
+ var splicesToDo = [];
+ var netNumLinesChangeSoFar = 0;
+ var toDeleteAtEnd = [];
+ p.mark("ranges");
+ p.literal(dirtyRanges.length, "numdirt");
+ var domInsertsNeeded = []; // each entry is [nodeToInsertAfter, [info1, info2, ...]]
+ while (i < dirtyRanges.length) {
+ var range = dirtyRanges[i];
+ a = range[0];
+ b = range[1];
+ var firstDirtyNode = (((a == 0) && root.firstChild) ||
+ getCleanNodeByKey(rep.lines.atIndex(a-1).key).nextSibling);
+ firstDirtyNode = (firstDirtyNode && isNodeDirty(firstDirtyNode) && firstDirtyNode);
+ var lastDirtyNode = (((b == rep.lines.length()) && root.lastChild) ||
+ getCleanNodeByKey(rep.lines.atIndex(b).key).previousSibling);
+ lastDirtyNode = (lastDirtyNode && isNodeDirty(lastDirtyNode) && lastDirtyNode);
+ if (firstDirtyNode && lastDirtyNode) {
+ var cc = makeContentCollector(isStyled, browser, rep.apool, null,
+ className2Author);
+ cc.notifySelection(selection);
+ var dirtyNodes = [];
+ for(var n = firstDirtyNode; n && ! (n.previousSibling &&
+ n.previousSibling == lastDirtyNode);
+ n = n.nextSibling) {
+ if (browser.msie) {
+ // try to undo IE's pesky and overzealous linkification
+ try { n.createTextRange().execCommand("unlink", false, null); }
+ catch (e) {}
+ }
+ cc.collectContent(n);
+ dirtyNodes.push(n);
+ }
+ cc.notifyNextNode(lastDirtyNode.nextSibling);
+ var lines = cc.getLines();
+ if ((lines.length <= 1 || lines[lines.length-1] !== "")
+ && lastDirtyNode.nextSibling) {
+ // dirty region doesn't currently end a line, even taking the following node
+ // (or lack of node) into account, so include the following clean node.
+ // It could be SPAN or a DIV; basically this is any case where the contentCollector
+ // decides it isn't done.
+ // Note that this clean node might need to be there for the next dirty range.
+ //console.log("inclusive of "+lastDirtyNode.next().dom.tagName);
+ b++;
+ var cleanLine = lastDirtyNode.nextSibling;
+ cc.collectContent(cleanLine);
+ toDeleteAtEnd.push(cleanLine);
+ cc.notifyNextNode(cleanLine.nextSibling);
+ }
+
+ var ccData = cc.finish();
+ var ss = ccData.selStart;
+ var se = ccData.selEnd;
+ lines = ccData.lines;
+ var lineAttribs = ccData.lineAttribs;
+ var linesWrapped = ccData.linesWrapped;
+
+ if (linesWrapped > 0) {
+ doAlert("Editor warning: "+linesWrapped+" long line"+
+ (linesWrapped == 1 ? " was" : "s were")+" hard-wrapped into "+
+ ccData.numLinesAfter
+ +" lines.");
+ }
+
+ if (ss[0] >= 0) selStart = [ss[0]+a+netNumLinesChangeSoFar, ss[1]];
+ if (se[0] >= 0) selEnd = [se[0]+a+netNumLinesChangeSoFar, se[1]];
+
+ /*var oldLines = rep.alltext.substring(rep.lines.offsetOfIndex(a),
+ rep.lines.offsetOfIndex(b));
+ var newLines = lines.join('\n')+'\n';
+ dmesg("OLD: "+htmlPrettyEscape(oldLines));
+ dmesg("NEW: "+htmlPrettyEscape(newLines));*/
+
+ var entries = [];
+ var nodeToAddAfter = lastDirtyNode;
+ var lineNodeInfos = new Array(lines.length);
+ for(var k=0;k<lines.length;k++) {
+ var lineString = lines[k];
+ var newEntry = createDomLineEntry(lineString);
+ entries.push(newEntry);
+ lineNodeInfos[k] = newEntry.domInfo;
+ }
+ //var fragment = magicdom.wrapDom(document.createDocumentFragment());
+ domInsertsNeeded.push([nodeToAddAfter, lineNodeInfos]);
+ forEach(dirtyNodes, function (n) { toDeleteAtEnd.push(n); });
+ var spliceHints = {};
+ if (selStart) spliceHints.selStart = selStart;
+ if (selEnd) spliceHints.selEnd = selEnd;
+ splicesToDo.push([a+netNumLinesChangeSoFar, b-a, entries, lineAttribs, spliceHints]);
+ netNumLinesChangeSoFar += (lines.length - (b-a));
+ }
+ else if (b > a) {
+ splicesToDo.push([a+netNumLinesChangeSoFar, b-a, [], []]);
+ }
+ i++;
+ }
+
+ var domChanges = (splicesToDo.length > 0);
+
+ // update the representation
+ p.mark("splice");
+ forEach(splicesToDo, function (splice) {
+ doIncorpLineSplice(splice[0], splice[1], splice[2], splice[3], splice[4]);
+ });
+
+ //p.mark("relex");
+ //rep.lexer.lexCharRange(getVisibleCharRange(), function() { return false; });
+ //var isTimeUp = newTimeLimit(100);
+
+ // do DOM inserts
+ p.mark("insert");
+ forEach(domInsertsNeeded, function (ins) {
+ insertDomLines(ins[0], ins[1], isTimeUp);
+ });
+
+ p.mark("del");
+ // delete old dom nodes
+ forEach(toDeleteAtEnd, function (n) {
+ //var id = n.uniqueId();
+
+ // parent of n may not be "root" in IE due to non-tree-shaped DOM (wtf)
+ n.parentNode.removeChild(n);
+
+ //dmesg(htmlPrettyEscape(htmlForRemovedChild(n)));
+ //console.log("removed: "+id);
+ });
+
+ p.mark("findsel");
+ // if the nodes that define the selection weren't encountered during
+ // content collection, figure out where those nodes are now.
+ if (selection && !selStart) {
+ //if (domChanges) dmesg("selection not collected");
+ selStart = getLineAndCharForPoint(selection.startPoint);
+ }
+ if (selection && !selEnd) {
+ selEnd = getLineAndCharForPoint(selection.endPoint);
+ }
+
+ // selection from content collection can, in various ways, extend past final
+ // BR in firefox DOM, so cap the line
+ var numLines = rep.lines.length();
+ if (selStart && selStart[0] >= numLines) {
+ selStart[0] = numLines-1;
+ selStart[1] = rep.lines.atIndex(selStart[0]).text.length;
+ }
+ if (selEnd && selEnd[0] >= numLines) {
+ selEnd[0] = numLines-1;
+ selEnd[1] = rep.lines.atIndex(selEnd[0]).text.length;
+ }
+
+ p.mark("repsel");
+ // update rep
+ repSelectionChange(selStart, selEnd, selection && selection.focusAtStart);
+ // update browser selection
+ p.mark("browsel");
+ if (selection && (domChanges || isCaret())) {
+ // if no DOM changes (not this case), want to treat range selection delicately,
+ // e.g. in IE not lose which end of the selection is the focus/anchor;
+ // on the other hand, we may have just noticed a press of PageUp/PageDown
+ currentCallStack.selectionAffected = true;
+ }
+
+ currentCallStack.domClean = true;
+
+ p.mark("fixview");
+
+ fixView();
+
+ p.end("END");
+
+ return domChanges;
+ }
+
+ function htmlForRemovedChild(n) {
+ var div = doc.createElement("DIV");
+ div.appendChild(n);
+ return div.innerHTML;
+ }
+
+ var STYLE_ATTRIBS = {bold: true, italic: true, underline: true,
+ strikethrough: true, h1: true, h2: true,
+ h3: true, h4: true, h5: true, h6: true,
+ list: true};
+ var OTHER_INCORPED_ATTRIBS = {insertorder: true, author: true};
+
+ function isStyleAttribute(aname) {
+ return !! STYLE_ATTRIBS[aname];
+ }
+ function isIncorpedAttribute(aname) {
+ return (!! STYLE_ATTRIBS[aname]) || (!! OTHER_INCORPED_ATTRIBS[aname]);
+ }
+
+ function insertDomLines(nodeToAddAfter, infoStructs, isTimeUp) {
+ isTimeUp = (isTimeUp || function() { return false; });
+
+ var lastEntry;
+ var lineStartOffset;
+ if (infoStructs.length < 1) return;
+ var startEntry = rep.lines.atKey(uniqueId(infoStructs[0].node));
+ var endEntry = rep.lines.atKey(uniqueId(infoStructs[infoStructs.length-1].node));
+ var charStart = rep.lines.offsetOfEntry(startEntry);
+ var charEnd = rep.lines.offsetOfEntry(endEntry) + endEntry.width;
+
+ //rep.lexer.lexCharRange([charStart, charEnd], isTimeUp);
+
+ forEach(infoStructs, function (info) {
+ var p2 = PROFILER("insertLine", false);
+ var node = info.node;
+ var key = uniqueId(node);
+ var entry;
+ p2.mark("findEntry");
+ if (lastEntry) {
+ // optimization to avoid recalculation
+ var next = rep.lines.next(lastEntry);
+ if (next && next.key == key) {
+ entry = next;
+ lineStartOffset += lastEntry.width;
+ }
+ }
+ if (! entry) {
+ p2.literal(1, "nonopt");
+ entry = rep.lines.atKey(key);
+ lineStartOffset = rep.lines.offsetOfKey(key);
+ }
+ else p2.literal(0, "nonopt");
+ lastEntry = entry;
+ p2.mark("spans");
+ getSpansForLine(entry, function (tokenText, tokenClass) {
+ info.appendSpan(tokenText, tokenClass);
+ }, lineStartOffset, isTimeUp());
+ //else if (entry.text.length > 0) {
+ //info.appendSpan(entry.text, 'dirty');
+ //}
+ p2.mark("addLine");
+ info.prepareForAdd();
+ entry.lineMarker = info.lineMarker;
+ if (! nodeToAddAfter) {
+ root.insertBefore(node, root.firstChild);
+ }
+ else {
+ root.insertBefore(node, nodeToAddAfter.nextSibling);
+ }
+ nodeToAddAfter = node;
+ info.notifyAdded();
+ p2.mark("markClean");
+ markNodeClean(node);
+ p2.end();
+ });
+ }
+
+ function isCaret() {
+ return (rep.selStart && rep.selEnd && rep.selStart[0] == rep.selEnd[0] &&
+ rep.selStart[1] == rep.selEnd[1]);
+ }
+
+ // prereq: isCaret()
+ function caretLine() { return rep.selStart[0]; }
+ function caretColumn() { return rep.selStart[1]; }
+ function caretDocChar() {
+ return rep.lines.offsetOfIndex(caretLine()) + caretColumn();
+ }
+
+ function handleReturnIndentation() {
+ // on return, indent to level of previous line
+ if (isCaret() && caretColumn() == 0 && caretLine() > 0) {
+ var lineNum = caretLine();
+ var thisLine = rep.lines.atIndex(lineNum);
+ var prevLine = rep.lines.prev(thisLine);
+ var prevLineText = prevLine.text;
+ var theIndent = /^ *(?:)/.exec(prevLineText)[0];
+ if (/[\[\(\{]\s*$/.exec(prevLineText)) theIndent += THE_TAB;
+ var cs = Changeset.builder(rep.lines.totalWidth()).keep(
+ rep.lines.offsetOfIndex(lineNum), lineNum).insert(
+ theIndent, [['author',thisAuthor]], rep.apool).toString();
+ performDocumentApplyChangeset(cs);
+ performSelectionChange([lineNum, theIndent.length], [lineNum, theIndent.length]);
+ }
+ }
+
+
+ function setupMozillaCaretHack(lineNum) {
+ // This is really ugly, but by god, it works!
+ // Fixes annoying Firefox caret artifact (observed in 2.0.0.12
+ // and unfixed in Firefox 2 as of now) where mutating the DOM
+ // and then moving the caret to the beginning of a line causes
+ // an image of the caret to be XORed at the top of the iframe.
+ // The previous solution involved remembering to set the selection
+ // later, in response to the next event in the queue, which was hugely
+ // annoying.
+ // This solution: add a space character (0x20) to the beginning of the line.
+ // After setting the selection, remove the space.
+ var lineNode = rep.lines.atIndex(lineNum).lineNode;
+
+ var fc = lineNode.firstChild;
+ while (isBlockElement(fc) && fc.firstChild) {
+ fc = fc.firstChild;
+ }
+ var textNode;
+ if (isNodeText(fc)) {
+ fc.nodeValue = " "+fc.nodeValue;
+ textNode = fc;
+ }
+ else {
+ textNode = doc.createTextNode(" ");
+ fc.parentNode.insertBefore(textNode, fc);
+ }
+ markNodeClean(lineNode);
+ return { unhack: function() {
+ if (textNode.nodeValue == " ") {
+ textNode.parentNode.removeChild(textNode);
+ }
+ else {
+ textNode.nodeValue = textNode.nodeValue.substring(1);
+ }
+ markNodeClean(lineNode);
+ } };
+ }
+
+
+ function getPointForLineAndChar(lineAndChar) {
+ var line = lineAndChar[0];
+ var charsLeft = lineAndChar[1];
+ //console.log("line: %d, key: %s, node: %o", line, rep.lines.atIndex(line).key,
+ //getCleanNodeByKey(rep.lines.atIndex(line).key));
+ var lineEntry = rep.lines.atIndex(line);
+ charsLeft -= lineEntry.lineMarker;
+ if (charsLeft < 0) {
+ charsLeft = 0;
+ }
+ var lineNode = lineEntry.lineNode;
+ var n = lineNode;
+ var after = false;
+ if (charsLeft == 0) {
+ var index = 0;
+ if (browser.msie && line == (rep.lines.length()-1) && lineNode.childNodes.length == 0) {
+ // best to stay at end of last empty div in IE
+ index = 1;
+ }
+ return {node: lineNode, index:index, maxIndex:1};
+ }
+ while (!(n == lineNode && after)) {
+ if (after) {
+ if (n.nextSibling) {
+ n = n.nextSibling;
+ after = false;
+ }
+ else n = n.parentNode;
+ }
+ else {
+ if (isNodeText(n)) {
+ var len = n.nodeValue.length;
+ if (charsLeft <= len) {
+ return {node: n, index:charsLeft, maxIndex:len};
+ }
+ charsLeft -= len;
+ after = true;
+ }
+ else {
+ if (n.firstChild) n = n.firstChild;
+ else after = true;
+ }
+ }
+ }
+ return {node: lineNode, index:1, maxIndex:1};
+ }
+
+ function nodeText(n) {
+ return n.innerText || n.textContent || n.nodeValue || '';
+ }
+
+ function getLineAndCharForPoint(point) {
+ // Turn DOM node selection into [line,char] selection.
+ // This method has to work when the DOM is not pristine,
+ // assuming the point is not in a dirty node.
+ if (point.node == root) {
+ if (point.index == 0) {
+ return [0, 0];
+ }
+ else {
+ var N = rep.lines.length();
+ var ln = rep.lines.atIndex(N-1);
+ return [N-1, ln.text.length];
+ }
+ }
+ else {
+ var n = point.node;
+ var col = 0;
+ // if this part fails, it probably means the selection node
+ // was dirty, and we didn't see it when collecting dirty nodes.
+ if (isNodeText(n)) {
+ col = point.index;
+ }
+ else if (point.index > 0) {
+ col = nodeText(n).length;
+ }
+ var parNode, prevSib;
+ while ((parNode = n.parentNode) != root) {
+ if ((prevSib = n.previousSibling)) {
+ n = prevSib;
+ col += nodeText(n).length;
+ }
+ else {
+ n = parNode;
+ }
+ }
+ if (n.id == "") console.debug("BAD");
+ if (n.firstChild && isBlockElement(n.firstChild)) {
+ col += 1; // lineMarker
+ }
+ var lineEntry = rep.lines.atKey(n.id);
+ var lineNum = rep.lines.indexOfEntry(lineEntry);
+ return [lineNum, col];
+ }
+ }
+
+ function createDomLineEntry(lineString) {
+ var info = doCreateDomLine(lineString.length > 0);
+ var newNode = info.node;
+ return {key: uniqueId(newNode), text: lineString, lineNode: newNode,
+ domInfo: info, lineMarker: 0};
+ }
+
+ function canApplyChangesetToDocument(changes) {
+ return Changeset.oldLen(changes) == rep.alltext.length;
+ }
+
+ function performDocumentApplyChangeset(changes, insertsAfterSelection) {
+ doRepApplyChangeset(changes, insertsAfterSelection);
+
+ var requiredSelectionSetting = null;
+ if (rep.selStart && rep.selEnd) {
+ var selStartChar = rep.lines.offsetOfIndex(rep.selStart[0]) + rep.selStart[1];
+ var selEndChar = rep.lines.offsetOfIndex(rep.selEnd[0]) + rep.selEnd[1];
+ var result = Changeset.characterRangeFollow(changes, selStartChar, selEndChar,
+ insertsAfterSelection);
+ requiredSelectionSetting = [result[0], result[1], rep.selFocusAtStart];
+ }
+
+ var linesMutatee = {
+ splice: function(start, numRemoved, newLinesVA) {
+ domAndRepSplice(start, numRemoved,
+ map(Array.prototype.slice.call(arguments, 2),
+ function(s) { return s.slice(0,-1); }),
+ null);
+ },
+ get: function(i) { return rep.lines.atIndex(i).text+'\n'; },
+ length: function() { return rep.lines.length(); },
+ slice_notused: function(start, end) {
+ return map(rep.lines.slice(start, end), function(e) { return e.text+'\n'; });
+ }
+ };
+
+ Changeset.mutateTextLines(changes, linesMutatee);
+
+ checkALines();
+
+ if (requiredSelectionSetting) {
+ performSelectionChange(lineAndColumnFromChar(requiredSelectionSetting[0]),
+ lineAndColumnFromChar(requiredSelectionSetting[1]),
+ requiredSelectionSetting[2]);
+ }
+
+ function domAndRepSplice(startLine, deleteCount, newLineStrings, isTimeUp) {
+ // dgreensp 3/2009: the spliced lines may be in the middle of a dirty region,
+ // so if no explicit time limit, don't spend a lot of time highlighting
+ isTimeUp = (isTimeUp || newTimeLimit(50));
+
+ var keysToDelete = [];
+ if (deleteCount > 0) {
+ var entryToDelete = rep.lines.atIndex(startLine);
+ for(var i=0;i<deleteCount;i++) {
+ keysToDelete.push(entryToDelete.key);
+ entryToDelete = rep.lines.next(entryToDelete);
+ }
+ }
+
+ var lineEntries = map(newLineStrings, createDomLineEntry);
+
+ doRepLineSplice(startLine, deleteCount, lineEntries);
+
+ var nodeToAddAfter;
+ if (startLine > 0) {
+ nodeToAddAfter = getCleanNodeByKey(rep.lines.atIndex(startLine-1).key);
+ }
+ else nodeToAddAfter = null;
+
+ insertDomLines(nodeToAddAfter, map(lineEntries, function (entry) { return entry.domInfo; }),
+ isTimeUp);
+
+ forEach(keysToDelete, function (k) {
+ var n = doc.getElementById(k);
+ n.parentNode.removeChild(n);
+ });
+
+ if ((rep.selStart && rep.selStart[0] >= startLine && rep.selStart[0] <= startLine+deleteCount) ||
+ (rep.selEnd && rep.selEnd[0] >= startLine && rep.selEnd[0] <= startLine+deleteCount)) {
+ currentCallStack.selectionAffected = true;
+ }
+ }
+ }
+
+ function checkChangesetLineInformationAgainstRep(changes) {
+ return true; // disable for speed
+ var opIter = Changeset.opIterator(Changeset.unpack(changes).ops);
+ var curOffset = 0;
+ var curLine = 0;
+ var curCol = 0;
+ while (opIter.hasNext()) {
+ var o = opIter.next();
+ if (o.opcode == '-' || o.opcode == '=') {
+ curOffset += o.chars;
+ if (o.lines) {
+ curLine += o.lines;
+ curCol = 0;
+ }
+ else {
+ curCol += o.chars;
+ }
+ }
+ var calcLine = rep.lines.indexOfOffset(curOffset);
+ var calcLineStart = rep.lines.offsetOfIndex(calcLine);
+ var calcCol = curOffset - calcLineStart;
+ if (calcCol != curCol || calcLine != curLine) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function doRepApplyChangeset(changes, insertsAfterSelection) {
+ Changeset.checkRep(changes);
+
+ if (Changeset.oldLen(changes) != rep.alltext.length)
+ throw new Error("doRepApplyChangeset length mismatch: "+
+ Changeset.oldLen(changes)+"/"+rep.alltext.length);
+
+ if (! checkChangesetLineInformationAgainstRep(changes)) {
+ throw new Error("doRepApplyChangeset line break mismatch");
+ }
+
+ (function doRecordUndoInformation(changes) {
+ var editEvent = currentCallStack.editEvent;
+ if (editEvent.eventType == "nonundoable") {
+ if (! editEvent.changeset) {
+ editEvent.changeset = changes;
+ }
+ else {
+ editEvent.changeset = Changeset.compose(editEvent.changeset, changes,
+ rep.apool);
+ }
+ }
+ else {
+ var inverseChangeset = Changeset.inverse(changes, {get: function(i) {
+ return rep.lines.atIndex(i).text+'\n';
+ }, length: function() { return rep.lines.length(); }},
+ rep.alines, rep.apool);
+
+ if (! editEvent.backset) {
+ editEvent.backset = inverseChangeset;
+ }
+ else {
+ editEvent.backset = Changeset.compose(inverseChangeset,
+ editEvent.backset, rep.apool);
+ }
+ }
+ })(changes);
+
+ //rep.alltext = Changeset.applyToText(changes, rep.alltext);
+ Changeset.mutateAttributionLines(changes, rep.alines, rep.apool);
+
+ if (changesetTracker.isTracking()) {
+ changesetTracker.composeUserChangeset(changes);
+ }
+
+ }
+
+ function lineAndColumnFromChar(x) {
+ var lineEntry = rep.lines.atOffset(x);
+ var lineStart = rep.lines.offsetOfEntry(lineEntry);
+ var lineNum = rep.lines.indexOfEntry(lineEntry);
+ return [lineNum, x - lineStart];
+ }
+
+ function performDocumentReplaceCharRange(startChar, endChar, newText) {
+ if (startChar == endChar && newText.length == 0) {
+ return;
+ }
+ // Requires that the replacement preserve the property that the
+ // internal document text ends in a newline. Given this, we
+ // rewrite the splice so that it doesn't touch the very last
+ // char of the document.
+ if (endChar == rep.alltext.length) {
+ if (startChar == endChar) {
+ // an insert at end
+ startChar--;
+ endChar--;
+ newText = '\n'+newText.substring(0, newText.length-1);
+ }
+ else if (newText.length == 0) {
+ // a delete at end
+ startChar--;
+ endChar--;
+ }
+ else {
+ // a replace at end
+ endChar--;
+ newText = newText.substring(0, newText.length-1);
+ }
+ }
+ performDocumentReplaceRange(lineAndColumnFromChar(startChar),
+ lineAndColumnFromChar(endChar),
+ newText);
+ }
+
+ function performDocumentReplaceRange(start, end, newText) {
+ //dmesg(String([start.toSource(),end.toSource(),newText.toSource()]));
+
+ // start[0]: <--- start[1] --->CCCCCCCCCCC\n
+ // CCCCCCCCCCCCCCCCCCCC\n
+ // CCCC\n
+ // end[0]: <CCC end[1] CCC>-------\n
+
+ var builder = Changeset.builder(rep.lines.totalWidth());
+ buildKeepToStartOfRange(builder, start);
+ buildRemoveRange(builder, start, end);
+ builder.insert(newText, [['author',thisAuthor]], rep.apool);
+ var cs = builder.toString();
+
+ performDocumentApplyChangeset(cs);
+ }
+
+ function performDocumentApplyAttributesToCharRange(start, end, attribs) {
+ if (end >= rep.alltext.length) {
+ end = rep.alltext.length-1;
+ }
+ performDocumentApplyAttributesToRange(lineAndColumnFromChar(start),
+ lineAndColumnFromChar(end), attribs);
+ }
+
+ function performDocumentApplyAttributesToRange(start, end, attribs) {
+ var builder = Changeset.builder(rep.lines.totalWidth());
+ buildKeepToStartOfRange(builder, start);
+ buildKeepRange(builder, start, end, attribs, rep.apool);
+ var cs = builder.toString();
+ performDocumentApplyChangeset(cs);
+ }
+
+ function buildKeepToStartOfRange(builder, start) {
+ var startLineOffset = rep.lines.offsetOfIndex(start[0]);
+
+ builder.keep(startLineOffset, start[0]);
+ builder.keep(start[1]);
+ }
+ function buildRemoveRange(builder, start, end) {
+ var startLineOffset = rep.lines.offsetOfIndex(start[0]);
+ var endLineOffset = rep.lines.offsetOfIndex(end[0]);
+
+ if (end[0] > start[0]) {
+ builder.remove(endLineOffset - startLineOffset - start[1], end[0] - start[0]);
+ builder.remove(end[1]);
+ }
+ else {
+ builder.remove(end[1] - start[1]);
+ }
+ }
+ function buildKeepRange(builder, start, end, attribs, pool) {
+ var startLineOffset = rep.lines.offsetOfIndex(start[0]);
+ var endLineOffset = rep.lines.offsetOfIndex(end[0]);
+
+ if (end[0] > start[0]) {
+ builder.keep(endLineOffset - startLineOffset - start[1], end[0] - start[0], attribs, pool);
+ builder.keep(end[1], 0, attribs, pool);
+ }
+ else {
+ builder.keep(end[1] - start[1], 0, attribs, pool);
+ }
+ }
+
+ function setAttributeOnSelection(attributeName, attributeValue) {
+ if (!(rep.selStart && rep.selEnd)) return;
+
+ performDocumentApplyAttributesToRange(rep.selStart, rep.selEnd,
+ [[attributeName, attributeValue]]);
+ }
+
+ function toggleAttributeOnSelection(attributeName) {
+ if (!(rep.selStart && rep.selEnd)) return;
+
+ var selectionAllHasIt = true;
+ var withIt = Changeset.makeAttribsString('+', [[attributeName, 'true']], rep.apool);
+ var withItRegex = new RegExp(withIt.replace(/\*/g,'\\*')+"(\\*|$)");
+ function hasIt(attribs) { return withItRegex.test(attribs); }
+
+ var selStartLine = rep.selStart[0];
+ var selEndLine = rep.selEnd[0];
+ for(var n=selStartLine; n<=selEndLine; n++) {
+ var opIter = Changeset.opIterator(rep.alines[n]);
+ var indexIntoLine = 0;
+ var selectionStartInLine = 0;
+ var selectionEndInLine = rep.lines.atIndex(n).text.length; // exclude newline
+ if (n == selStartLine) {
+ selectionStartInLine = rep.selStart[1];
+ }
+ if (n == selEndLine) {
+ selectionEndInLine = rep.selEnd[1];
+ }
+ while (opIter.hasNext()) {
+ var op = opIter.next();
+ var opStartInLine = indexIntoLine;
+ var opEndInLine = opStartInLine + op.chars;
+ if (! hasIt(op.attribs)) {
+ // does op overlap selection?
+ if (! (opEndInLine <= selectionStartInLine || opStartInLine >= selectionEndInLine)) {
+ selectionAllHasIt = false;
+ break;
+ }
+ }
+ indexIntoLine = opEndInLine;
+ }
+ if (! selectionAllHasIt) {
+ break;
+ }
+ }
+
+ if (selectionAllHasIt) {
+ performDocumentApplyAttributesToRange(rep.selStart, rep.selEnd,
+ [[attributeName,'']]);
+ }
+ else {
+ var settings = [[attributeName, 'true']];
+
+ if (attributeName == 'h1' || attributeName == 'h2' || attributeName == 'h3' ||
+ attributeName == 'h4' || attributeName == 'h5' || attributeName == 'h6') {
+
+ settings = [['h1',''], ['h2',''], ['h3',''],
+ ['h4',''], ['h5',''], ['h6','']];
+ if (attributeName == 'h1') {
+ settings[0] = [attributeName, 'true'];
+ }
+ else if (attributeName == 'h2') {
+ settings[1] = [attributeName, 'true'];
+ }
+ else if (attributeName == 'h3') {
+ settings[2] = [attributeName, 'true'];
+ }
+ else if (attributeName == 'h4') {
+ settings[3] = [attributeName, 'true'];
+ }
+ else if (attributeName == 'h5') {
+ settings[4] = [attributeName, 'true'];
+ }
+ else if (attributeName == 'h6') {
+ settings[5] = [attributeName, 'true'];
+ }
+ }
+
+ performDocumentApplyAttributesToRange(rep.selStart, rep.selEnd, settings);
+ }
+ }
+
+ function performDocumentReplaceSelection(newText) {
+ if (!(rep.selStart && rep.selEnd)) return;
+ performDocumentReplaceRange(rep.selStart, rep.selEnd, newText);
+ }
+
+ // Change the abstract representation of the document to have a different set of lines.
+ // Must be called after rep.alltext is set.
+ function doRepLineSplice(startLine, deleteCount, newLineEntries) {
+
+ forEach(newLineEntries, function (entry) { entry.width = entry.text.length+1; });
+
+ var startOldChar = rep.lines.offsetOfIndex(startLine);
+ var endOldChar = rep.lines.offsetOfIndex(startLine+deleteCount);
+
+ var oldRegionStart = rep.lines.offsetOfIndex(startLine);
+ var oldRegionEnd = rep.lines.offsetOfIndex(startLine+deleteCount);
+ rep.lines.splice(startLine, deleteCount, newLineEntries);
+ currentCallStack.docTextChanged = true;
+ currentCallStack.repChanged = true;
+ var newRegionEnd = rep.lines.offsetOfIndex(startLine + newLineEntries.length);
+
+ var newText = map(newLineEntries, function (e) { return e.text+'\n'; }).join('');
+
+ rep.alltext = rep.alltext.substring(0, startOldChar) + newText +
+ rep.alltext.substring(endOldChar, rep.alltext.length);
+
+ //var newTotalLength = rep.alltext.length;
+
+ //rep.lexer.updateBuffer(rep.alltext, oldRegionStart, oldRegionEnd - oldRegionStart,
+ //newRegionEnd - oldRegionStart);
+ }
+
+ function doIncorpLineSplice(startLine, deleteCount, newLineEntries, lineAttribs, hints) {
+
+ var startOldChar = rep.lines.offsetOfIndex(startLine);
+ var endOldChar = rep.lines.offsetOfIndex(startLine+deleteCount);
+
+ var oldRegionStart = rep.lines.offsetOfIndex(startLine);
+
+ var selStartHintChar, selEndHintChar;
+ if (hints && hints.selStart) {
+ selStartHintChar = rep.lines.offsetOfIndex(hints.selStart[0]) + hints.selStart[1] -
+ oldRegionStart;
+ }
+ if (hints && hints.selEnd) {
+ selEndHintChar = rep.lines.offsetOfIndex(hints.selEnd[0]) + hints.selEnd[1] -
+ oldRegionStart;
+ }
+
+ var newText = map(newLineEntries, function (e) { return e.text+'\n'; }).join('');
+ var oldText = rep.alltext.substring(startOldChar, endOldChar);
+ var oldAttribs = rep.alines.slice(startLine, startLine+deleteCount).join('');
+ var newAttribs = lineAttribs.join('|1+1')+'|1+1'; // not valid in a changeset
+ var analysis = analyzeChange(oldText, newText, oldAttribs, newAttribs,
+ selStartHintChar, selEndHintChar);
+ var commonStart = analysis[0];
+ var commonEnd = analysis[1];
+ var shortOldText = oldText.substring(commonStart, oldText.length - commonEnd);
+ var shortNewText = newText.substring(commonStart, newText.length - commonEnd);
+ var spliceStart = startOldChar+commonStart;
+ var spliceEnd = endOldChar-commonEnd;
+ var shiftFinalNewlineToBeforeNewText = false;
+
+ // adjust the splice to not involve the final newline of the document;
+ // be very defensive
+ if (shortOldText.charAt(shortOldText.length-1) == '\n' &&
+ shortNewText.charAt(shortNewText.length-1) == '\n') {
+ // replacing text that ends in newline with text that also ends in newline
+ // (still, after analysis, somehow)
+ shortOldText = shortOldText.slice(0,-1);
+ shortNewText = shortNewText.slice(0,-1);
+ spliceEnd--;
+ commonEnd++;
+ }
+ if (shortOldText.length == 0 && spliceStart == rep.alltext.length
+ && shortNewText.length > 0) {
+ // inserting after final newline, bad
+ spliceStart--;
+ spliceEnd--;
+ shortNewText = '\n'+shortNewText.slice(0,-1);
+ shiftFinalNewlineToBeforeNewText = true;
+ }
+ if (spliceEnd == rep.alltext.length && shortOldText.length > 0 &&
+ shortNewText.length == 0) {
+ // deletion at end of rep.alltext
+ if (rep.alltext.charAt(spliceStart-1) == '\n') {
+ // (if not then what the heck? it will definitely lead
+ // to a rep.alltext without a final newline)
+ spliceStart--;
+ spliceEnd--;
+ }
+ }
+
+ if (! (shortOldText.length == 0 && shortNewText.length == 0)) {
+ var oldDocText = rep.alltext;
+ var oldLen = oldDocText.length;
+
+ var spliceStartLine = rep.lines.indexOfOffset(spliceStart);
+ var spliceStartLineStart = rep.lines.offsetOfIndex(spliceStartLine);
+ function startBuilder() {
+ var builder = Changeset.builder(oldLen);
+ builder.keep(spliceStartLineStart, spliceStartLine);
+ builder.keep(spliceStart - spliceStartLineStart);
+ return builder;
+ }
+
+ function eachAttribRun(attribs, func/*(startInNewText, endInNewText, attribs)*/) {
+ var attribsIter = Changeset.opIterator(attribs);
+ var textIndex = 0;
+ var newTextStart = commonStart;
+ var newTextEnd = newText.length - commonEnd - (shiftFinalNewlineToBeforeNewText ? 1 : 0);
+ while (attribsIter.hasNext()) {
+ var op = attribsIter.next();
+ var nextIndex = textIndex + op.chars;
+ if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
+ func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);
+ }
+ textIndex = nextIndex;
+ }
+ }
+
+ var justApplyStyles = (shortNewText == shortOldText);
+ var theChangeset;
+
+ if (justApplyStyles) {
+ // create changeset that clears the incorporated styles on
+ // the existing text. we compose this with the
+ // changeset the applies the styles found in the DOM.
+ // This allows us to incorporate, e.g., Safari's native "unbold".
+
+ var incorpedAttribClearer = cachedStrFunc(function (oldAtts) {
+ return Changeset.mapAttribNumbers(oldAtts, function(n) {
+ var k = rep.apool.getAttribKey(n);
+ if (isStyleAttribute(k)) {
+ return rep.apool.putAttrib([k,'']);
+ }
+ return false;
+ });
+ });
+
+ var builder1 = startBuilder();
+ if (shiftFinalNewlineToBeforeNewText) {
+ builder1.keep(1, 1);
+ }
+ eachAttribRun(oldAttribs, function(start, end, attribs) {
+ builder1.keepText(newText.substring(start, end), incorpedAttribClearer(attribs));
+ });
+ var clearer = builder1.toString();
+
+ var builder2 = startBuilder();
+ if (shiftFinalNewlineToBeforeNewText) {
+ builder2.keep(1, 1);
+ }
+ eachAttribRun(newAttribs, function(start, end, attribs) {
+ builder2.keepText(newText.substring(start, end), attribs);
+ });
+ var styler = builder2.toString();
+
+ theChangeset = Changeset.compose(clearer, styler, rep.apool);
+ }
+ else {
+ var builder = startBuilder();
+
+ var spliceEndLine = rep.lines.indexOfOffset(spliceEnd);
+ var spliceEndLineStart = rep.lines.offsetOfIndex(spliceEndLine);
+ if (spliceEndLineStart > spliceStart) {
+ builder.remove(spliceEndLineStart - spliceStart, spliceEndLine - spliceStartLine);
+ builder.remove(spliceEnd - spliceEndLineStart);
+ }
+ else {
+ builder.remove(spliceEnd - spliceStart);
+ }
+
+ var isNewTextMultiauthor = false;
+ var authorAtt = Changeset.makeAttribsString(
+ '+', (thisAuthor ? [['author', thisAuthor]] : []), rep.apool);
+ var authorizer = cachedStrFunc(function(oldAtts) {
+ if (isNewTextMultiauthor) {
+ // prefer colors from DOM
+ return Changeset.composeAttributes(authorAtt, oldAtts, true, rep.apool);
+ }
+ else {
+ // use this author's color
+ return Changeset.composeAttributes(oldAtts, authorAtt, true, rep.apool);
+ }
+ });
+
+ var foundDomAuthor = '';
+ eachAttribRun(newAttribs, function(start, end, attribs) {
+ var a = Changeset.attribsAttributeValue(attribs, 'author', rep.apool);
+ if (a && a != foundDomAuthor) {
+ if (! foundDomAuthor) {
+ foundDomAuthor = a;
+ }
+ else {
+ isNewTextMultiauthor = true; // multiple authors in DOM!
+ }
+ }
+ });
+
+ if (shiftFinalNewlineToBeforeNewText) {
+ builder.insert('\n', authorizer(''));
+ }
+
+ eachAttribRun(newAttribs, function(start, end, attribs) {
+ builder.insert(newText.substring(start, end), authorizer(attribs));
+ });
+ theChangeset = builder.toString();
+ }
+
+ //dmesg(htmlPrettyEscape(theChangeset));
+
+ doRepApplyChangeset(theChangeset);
+ }
+
+ // do this no matter what, because we need to get the right
+ // line keys into the rep.
+ doRepLineSplice(startLine, deleteCount, newLineEntries);
+
+ checkALines();
+ }
+
+ function cachedStrFunc(func) {
+ var cache = {};
+ return function(s) {
+ if (! cache[s]) {
+ cache[s] = func(s);
+ }
+ return cache[s];
+ };
+ }
+
+ function analyzeChange(oldText, newText, oldAttribs, newAttribs, optSelStartHint, optSelEndHint) {
+ function incorpedAttribFilter(anum) {
+ return isStyleAttribute(rep.apool.getAttribKey(anum));
+ }
+ function attribRuns(attribs) {
+ var lengs = [];
+ var atts = [];
+ var iter = Changeset.opIterator(attribs);
+ while (iter.hasNext()) {
+ var op = iter.next();
+ lengs.push(op.chars);
+ atts.push(op.attribs);
+ }
+ return [lengs,atts];
+ }
+ function attribIterator(runs, backward) {
+ var lengs = runs[0];
+ var atts = runs[1];
+ var i = (backward ? lengs.length-1 : 0);
+ var j = 0;
+ return function next() {
+ while (j >= lengs[i]) {
+ if (backward) i--; else i++;
+ j = 0;
+ }
+ var a = atts[i];
+ j++;
+ return a;
+ };
+ }
+
+ var oldLen = oldText.length;
+ var newLen = newText.length;
+ var minLen = Math.min(oldLen, newLen);
+
+ var oldARuns = attribRuns(Changeset.filterAttribNumbers(oldAttribs, incorpedAttribFilter));
+ var newARuns = attribRuns(Changeset.filterAttribNumbers(newAttribs, incorpedAttribFilter));
+
+ var commonStart = 0;
+ var oldStartIter = attribIterator(oldARuns, false);
+ var newStartIter = attribIterator(newARuns, false);
+ while (commonStart < minLen) {
+ if (oldText.charAt(commonStart) == newText.charAt(commonStart) &&
+ oldStartIter() == newStartIter()) {
+ commonStart++;
+ }
+ else break;
+ }
+
+ var commonEnd = 0;
+ var oldEndIter = attribIterator(oldARuns, true);
+ var newEndIter = attribIterator(newARuns, true);
+ while (commonEnd < minLen) {
+ if (commonEnd == 0) {
+ // assume newline in common
+ oldEndIter(); newEndIter();
+ commonEnd++;
+ }
+ else if (oldText.charAt(oldLen-1-commonEnd) == newText.charAt(newLen-1-commonEnd) &&
+ oldEndIter() == newEndIter()) {
+ commonEnd++;
+ }
+ else break;
+ }
+
+ var hintedCommonEnd = -1;
+ if ((typeof optSelEndHint) == "number") {
+ hintedCommonEnd = newLen - optSelEndHint;
+ }
+
+
+ if (commonStart + commonEnd > oldLen) {
+ // ambiguous insertion
+ var minCommonEnd = oldLen - commonStart;
+ var maxCommonEnd = commonEnd;
+ if (hintedCommonEnd >= minCommonEnd && hintedCommonEnd <= maxCommonEnd) {
+ commonEnd = hintedCommonEnd;
+ }
+ else {
+ commonEnd = minCommonEnd;
+ }
+ commonStart = oldLen - commonEnd;
+ }
+ if (commonStart + commonEnd > newLen) {
+ // ambiguous deletion
+ var minCommonEnd = newLen - commonStart;
+ var maxCommonEnd = commonEnd;
+ if (hintedCommonEnd >= minCommonEnd && hintedCommonEnd <= maxCommonEnd) {
+ commonEnd = hintedCommonEnd;
+ }
+ else {
+ commonEnd = minCommonEnd;
+ }
+ commonStart = newLen - commonEnd;
+ }
+
+ return [commonStart, commonEnd];
+ }
+
+ function equalLineAndChars(a, b) {
+ if (!a) return !b;
+ if (!b) return !a;
+ return (a[0] == b[0] && a[1] == b[1]);
+ }
+
+ function performSelectionChange(selectStart, selectEnd, focusAtStart) {
+ if (repSelectionChange(selectStart, selectEnd, focusAtStart)) {
+ currentCallStack.selectionAffected = true;
+ }
+ }
+
+ // Change the abstract representation of the document to have a different selection.
+ // Should not rely on the line representation. Should not affect the DOM.
+ function repSelectionChange(selectStart, selectEnd, focusAtStart) {
+ focusAtStart = !! focusAtStart;
+
+ var newSelFocusAtStart = (focusAtStart &&
+ ((! selectStart) || (! selectEnd) ||
+ (selectStart[0] != selectEnd[0]) ||
+ (selectStart[1] != selectEnd[1])));
+
+ if ((! equalLineAndChars(rep.selStart, selectStart)) ||
+ (! equalLineAndChars(rep.selEnd, selectEnd)) ||
+ (rep.selFocusAtStart != newSelFocusAtStart)) {
+ rep.selStart = selectStart;
+ rep.selEnd = selectEnd;
+ rep.selFocusAtStart = newSelFocusAtStart;
+ if (mozillaFakeArrows) mozillaFakeArrows.notifySelectionChanged();
+ currentCallStack.repChanged = true;
+
+ return true;
+ //console.log("selStart: %o, selEnd: %o, focusAtStart: %s", rep.selStart, rep.selEnd,
+ //String(!!rep.selFocusAtStart));
+ }
+ return false;
+ //console.log("%o %o %s", rep.selStart, rep.selEnd, rep.selFocusAtStart);
+ }
+
+ /*function escapeHTML(s) {
+ var re = /[&<>'"]/g; /']/; // stupid indentation thing
+ if (! re.MAP) {
+ // persisted across function calls!
+ re.MAP = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&#34;',
+ "'": '&#39;'
+ };
+ }
+ return s.replace(re, function(c) { return re.MAP[c]; });
+ }*/
+
+ function doCreateDomLine(nonEmpty) {
+ if (browser.msie && (! nonEmpty)) {
+ var result = { node: null,
+ appendSpan: noop,
+ prepareForAdd: noop,
+ notifyAdded: noop,
+ clearSpans: noop,
+ finishUpdate: noop,
+ lineMarker: 0 };
+
+ var lineElem = doc.createElement("div");
+ result.node = lineElem;
+
+ result.notifyAdded = function() {
+ // magic -- settng an empty div's innerHTML to the empty string
+ // keeps it from collapsing. Apparently innerHTML must be set *after*
+ // adding the node to the DOM.
+ // Such a div is what IE 6 creates naturally when you make a blank line
+ // in a document of divs. However, when copy-and-pasted the div will
+ // contain a space, so we note its emptiness with a property.
+ lineElem.innerHTML = "";
+ // a primitive-valued property survives copy-and-paste
+ setAssoc(lineElem, "shouldBeEmpty", true);
+ // an object property doesn't
+ setAssoc(lineElem, "unpasted", {});
+ };
+ var lineClass = 'ace-line';
+ result.appendSpan = function(txt, cls) {
+ if ((! txt) && cls) {
+ // gain a whole-line style (currently to show insertion point in CSS)
+ lineClass = domline.addToLineClass(lineClass, cls);
+ }
+ // otherwise, ignore appendSpan, this is an empty line
+ };
+ result.clearSpans = function() {
+ lineClass = ''; // non-null to cause update
+ };
+ function writeClass() {
+ if (lineClass !== null) lineElem.className = lineClass;
+ }
+ result.prepareForAdd = writeClass;
+ result.finishUpdate = writeClass;
+ result.getInnerHTML = function() { return ""; };
+
+ return result;
+ }
+ else {
+ return domline.createDomLine(nonEmpty, doesWrap, browser, doc);
+ }
+ }
+
+ function textify(str) {
+ return str.replace(/[\n\r ]/g, ' ').replace(/\xa0/g, ' ').replace(/\t/g, ' ');
+ }
+
+ var _blockElems = { "div":1, "p":1, "pre":1, "li":1, "ol":1, "ul":1 };
+ function isBlockElement(n) {
+ return !!_blockElems[(n.tagName || "").toLowerCase()];
+ }
+
+ function getDirtyRanges() {
+ // based on observedChanges, return a list of ranges of original lines
+ // that need to be removed or replaced with new user content to incorporate
+ // the user's changes into the line representation. ranges may be zero-length,
+ // indicating inserted content. for example, [0,0] means content was inserted
+ // at the top of the document, while [3,4] means line 3 was deleted, modified,
+ // or replaced with one or more new lines of content. ranges do not touch.
+
+ var p = PROFILER("getDirtyRanges", false);
+ p.forIndices = 0;
+ p.consecutives = 0;
+ p.corrections = 0;
+
+ var cleanNodeForIndexCache = {};
+ var N = rep.lines.length(); // old number of lines
+ function cleanNodeForIndex(i) {
+ // if line (i) in the un-updated line representation maps to a clean node
+ // in the document, return that node.
+ // if (i) is out of bounds, return true. else return false.
+ if (cleanNodeForIndexCache[i] === undefined) {
+ p.forIndices++;
+ var result;
+ if (i < 0 || i >= N) {
+ result = true; // truthy, but no actual node
+ }
+ else {
+ var key = rep.lines.atIndex(i).key;
+ result = (getCleanNodeByKey(key) || false);
+ }
+ cleanNodeForIndexCache[i] = result;
+ }
+ return cleanNodeForIndexCache[i];
+ }
+ var isConsecutiveCache = {};
+ function isConsecutive(i) {
+ if (isConsecutiveCache[i] === undefined) {
+ p.consecutives++;
+ isConsecutiveCache[i] = (function() {
+ // returns whether line (i) and line (i-1), assumed to be map to clean DOM nodes,
+ // or document boundaries, are consecutive in the changed DOM
+ var a = cleanNodeForIndex(i-1);
+ var b = cleanNodeForIndex(i);
+ if ((!a) || (!b)) return false; // violates precondition
+ if ((a === true) && (b === true)) return ! root.firstChild;
+ if ((a === true) && b.previousSibling) return false;
+ if ((b === true) && a.nextSibling) return false;
+ if ((a === true) || (b === true)) return true;
+ return a.nextSibling == b;
+ })();
+ }
+ return isConsecutiveCache[i];
+ }
+ function isClean(i) {
+ // returns whether line (i) in the un-updated representation maps to a clean node,
+ // or is outside the bounds of the document
+ return !! cleanNodeForIndex(i);
+ }
+ // list of pairs, each representing a range of lines that is clean and consecutive
+ // in the changed DOM. lines (-1) and (N) are always clean, but may or may not
+ // be consecutive with lines in the document. pairs are in sorted order.
+ var cleanRanges = [[-1,N+1]];
+ function rangeForLine(i) {
+ // returns index of cleanRange containing i, or -1 if none
+ var answer = -1;
+ forEach(cleanRanges, function (r, idx) {
+ if (i >= r[1]) return false; // keep looking
+ if (i < r[0]) return true; // not found, stop looking
+ answer = idx;
+ return true; // found, stop looking
+ });
+ return answer;
+ }
+ function removeLineFromRange(rng, line) {
+ // rng is index into cleanRanges, line is line number
+ // precond: line is in rng
+ var a = cleanRanges[rng][0];
+ var b = cleanRanges[rng][1];
+ if ((a+1) == b) cleanRanges.splice(rng, 1);
+ else if (line == a) cleanRanges[rng][0]++;
+ else if (line == (b-1)) cleanRanges[rng][1]--;
+ else cleanRanges.splice(rng, 1, [a,line], [line+1,b]);
+ }
+ function splitRange(rng, pt) {
+ // precond: pt splits cleanRanges[rng] into two non-empty ranges
+ var a = cleanRanges[rng][0];
+ var b = cleanRanges[rng][1];
+ cleanRanges.splice(rng, 1, [a,pt], [pt,b]);
+ }
+ var correctedLines = {};
+ function correctlyAssignLine(line) {
+ if (correctedLines[line]) return true;
+ p.corrections++;
+ correctedLines[line] = true;
+ // "line" is an index of a line in the un-updated rep.
+ // returns whether line was already correctly assigned (i.e. correctly
+ // clean or dirty, according to cleanRanges, and if clean, correctly
+ // attached or not attached (i.e. in the same range as) the prev and next lines).
+ //console.log("correctly assigning: %d", line);
+ var rng = rangeForLine(line);
+ var lineClean = isClean(line);
+ if (rng < 0) {
+ if (lineClean) {
+ console.debug("somehow lost clean line");
+ }
+ return true;
+ }
+ if (! lineClean) {
+ // a clean-range includes this dirty line, fix it
+ removeLineFromRange(rng, line);
+ return false;
+ }
+ else {
+ // line is clean, but could be wrongly connected to a clean line
+ // above or below
+ var a = cleanRanges[rng][0];
+ var b = cleanRanges[rng][1];
+ var didSomething = false;
+ // we'll leave non-clean adjacent nodes in the clean range for the caller to
+ // detect and deal with. we deal with whether the range should be split
+ // just above or just below this line.
+ if (a < line && isClean(line-1) && ! isConsecutive(line)) {
+ splitRange(rng, line);
+ didSomething = true;
+ }
+ if (b > (line+1) && isClean(line+1) && ! isConsecutive(line+1)) {
+ splitRange(rng, line+1);
+ didSomething = true;
+ }
+ return ! didSomething;
+ }
+ }
+ function detectChangesAroundLine(line, reqInARow) {
+ // make sure cleanRanges is correct about line number "line" and the surrounding
+ // lines; only stops checking at end of document or after no changes need
+ // making for several consecutive lines. note that iteration is over old lines,
+ // so this operation takes time proportional to the number of old lines
+ // that are changed or missing, not the number of new lines inserted.
+ var correctInARow = 0;
+ var currentIndex = line;
+ while (correctInARow < reqInARow && currentIndex >= 0) {
+ if (correctlyAssignLine(currentIndex)) {
+ correctInARow++;
+ }
+ else correctInARow = 0;
+ currentIndex--;
+ }
+ correctInARow = 0;
+ currentIndex = line;
+ while (correctInARow < reqInARow && currentIndex < N) {
+ if (correctlyAssignLine(currentIndex)) {
+ correctInARow++;
+ }
+ else correctInARow = 0;
+ currentIndex++;
+ }
+ }
+
+ if (N == 0) {
+ p.cancel();
+ if (! isConsecutive(0)) {
+ splitRange(0, 0);
+ }
+ }
+ else {
+ p.mark("topbot");
+ detectChangesAroundLine(0,1);
+ detectChangesAroundLine(N-1,1);
+
+ p.mark("obs");
+ //console.log("observedChanges: "+toSource(observedChanges));
+ for (var k in observedChanges.cleanNodesNearChanges) {
+ var key = k.substring(1);
+ if (rep.lines.containsKey(key)) {
+ var line = rep.lines.indexOfKey(key);
+ detectChangesAroundLine(line,2);
+ }
+ }
+ p.mark("stats&calc");
+ p.literal(p.forIndices, "byidx");
+ p.literal(p.consecutives, "cons");
+ p.literal(p.corrections, "corr");
+ }
+
+ var dirtyRanges = [];
+ for(var r=0;r<cleanRanges.length-1;r++) {
+ dirtyRanges.push([cleanRanges[r][1], cleanRanges[r+1][0]]);
+ }
+
+ p.end();
+
+ return dirtyRanges;
+ }
+
+ function markNodeClean(n) {
+ // clean nodes have knownHTML that matches their innerHTML
+ var dirtiness = {};
+ dirtiness.nodeId = uniqueId(n);
+ dirtiness.knownHTML = n.innerHTML;
+ if (browser.msie) {
+ // adding a space to an "empty" div in IE designMode doesn't
+ // change the innerHTML of the div's parent; also, other
+ // browsers don't support innerText
+ dirtiness.knownText = n.innerText;
+ }
+ setAssoc(n, "dirtiness", dirtiness);
+ }
+
+ function isNodeDirty(n) {
+ var p = PROFILER("cleanCheck", false);
+ if (n.parentNode != root) return true;
+ var data = getAssoc(n, "dirtiness");
+ if (!data) return true;
+ if (n.id !== data.nodeId) return true;
+ if (browser.msie) {
+ if (n.innerText !== data.knownText) return true;
+ }
+ if (n.innerHTML !== data.knownHTML) return true;
+ p.end();
+ return false;
+ }
+
+ function getLineEntryTopBottom(entry, destObj) {
+ var dom = entry.lineNode;
+ var top = dom.offsetTop;
+ var height = dom.offsetHeight;
+ var obj = (destObj || {});
+ obj.top = top;
+ obj.bottom = (top+height);
+ return obj;
+ }
+
+ function getViewPortTopBottom() {
+ var theTop = getScrollY();
+ var doc = outerWin.document;
+ var height = doc.documentElement.clientHeight;
+ return {top:theTop, bottom:(theTop+height)};
+ }
+
+ function getVisibleLineRange() {
+ var viewport = getViewPortTopBottom();
+ //console.log("viewport top/bottom: %o", viewport);
+ var obj = {};
+ var start = rep.lines.search(function (e) {
+ return getLineEntryTopBottom(e, obj).bottom > viewport.top;
+ });
+ var end = rep.lines.search(function(e) {
+ return getLineEntryTopBottom(e, obj).top >= viewport.bottom;
+ });
+ if (end < start) end = start; // unlikely
+ //console.log(start+","+end);
+ return [start,end];
+ }
+
+ function getVisibleCharRange() {
+ var lineRange = getVisibleLineRange();
+ return [rep.lines.offsetOfIndex(lineRange[0]),
+ rep.lines.offsetOfIndex(lineRange[1])];
+ }
+
+ function handleClick(evt) {
+ inCallStack("handleClick", function() {
+ idleWorkTimer.atMost(200);
+ });
+
+ // only want to catch left-click
+ if ((! evt.ctrlKey) && (evt.button != 2) && (evt.button != 3)) {
+ // find A tag with HREF
+ function isLink(n) { return (n.tagName||'').toLowerCase() == "a" && n.href; }
+ var n = evt.target;
+ while (n && n.parentNode && ! isLink(n)) { n = n.parentNode; }
+ if (n && isLink(n)) {
+ try {
+ var newWindow = window.open(n.href, '_blank');
+ newWindow.focus();
+ }
+ catch (e) {
+ // absorb "user canceled" error in IE for certain prompts
+ }
+ evt.preventDefault();
+ }
+ }
+ }
+
+ function doReturnKey() {
+ if (! (rep.selStart && rep.selEnd)) {
+ return;
+ }
+ var lineNum = rep.selStart[0];
+ var listType = getLineListType(lineNum);
+
+ performDocumentReplaceSelection('\n');
+ if (listType) {
+ if (lineNum+1 < rep.lines.length()) {
+ setLineListType(lineNum+1, listType);
+ }
+ }
+ else {
+ handleReturnIndentation();
+ }
+ }
+
+ function doIndentOutdent(isOut) {
+ if (! (rep.selStart && rep.selEnd)) {
+ return false;
+ }
+
+ var firstLine, lastLine;
+ firstLine = rep.selStart[0];
+ lastLine = Math.max(firstLine,
+ rep.selEnd[0] - ((rep.selEnd[1] == 0) ? 1 : 0));
+
+ var mods = [];
+ var foundLists = false;
+ for(var n=firstLine;n<=lastLine;n++) {
+ var listType = getLineListType(n);
+ if (listType) {
+ listType = /([a-z]+)([12345678])/.exec(listType);
+ if (listType) {
+ foundLists = true;
+ var t = listType[1];
+ var level = Number(listType[2]);
+ var newLevel =
+ Math.max(1, Math.min(MAX_LIST_LEVEL,
+ level + (isOut ? -1 : 1)));
+ if (level != newLevel) {
+ mods.push([n, t+newLevel]);
+ }
+ }
+ }
+ }
+
+ if (mods.length > 0) {
+ setLineListTypes(mods);
+ }
+
+ return foundLists;
+ }
+
+ function doTabKey(shiftDown) {
+ if (! doIndentOutdent(shiftDown)) {
+ performDocumentReplaceSelection(THE_TAB);
+ }
+ }
+
+ function doDeleteKey(optEvt) {
+ var evt = optEvt || {};
+ var handled = false;
+ if (rep.selStart) {
+ if (isCaret()) {
+ var lineNum = caretLine();
+ var col = caretColumn();
+ var lineEntry = rep.lines.atIndex(lineNum);
+ var lineText = lineEntry.text;
+ var lineMarker = lineEntry.lineMarker;
+ if (/^ +$/.exec(lineText.substring(lineMarker, col))) {
+ var col2 = col - lineMarker;
+ var tabSize = THE_TAB.length;
+ var toDelete = ((col2 - 1) % tabSize)+1;
+ performDocumentReplaceRange([lineNum,col-toDelete],
+ [lineNum,col], '');
+ //scrollSelectionIntoView();
+ handled = true;
+ }
+ }
+ if (! handled) {
+ if (isCaret()) {
+ var theLine = caretLine();
+ var lineEntry = rep.lines.atIndex(theLine);
+ if (caretColumn() <= lineEntry.lineMarker) {
+ // delete at beginning of line
+ var action = 'delete_newline';
+ var prevLineListType =
+ (theLine > 0 ? getLineListType(theLine-1) : '');
+ var thisLineListType = getLineListType(theLine);
+ var prevLineEntry = (theLine > 0 &&
+ rep.lines.atIndex(theLine-1));
+ var prevLineBlank = (prevLineEntry &&
+ prevLineEntry.text.length ==
+ prevLineEntry.lineMarker);
+ if (thisLineListType) {
+ // this line is a list
+ /*if (prevLineListType) {
+ // prev line is a list too, remove this bullet
+ performDocumentReplaceRange([theLine-1, prevLineEntry.text.length],
+ [theLine, lineEntry.lineMarker], '');
+ }
+ else*/ if (prevLineBlank && ! prevLineListType) {
+ // previous line is blank, remove it
+ performDocumentReplaceRange([theLine-1, prevLineEntry.text.length],
+ [theLine, 0], '');
+ }
+ else {
+ // delistify
+ performDocumentReplaceRange([theLine, 0],
+ [theLine, lineEntry.lineMarker], '');
+ }
+ }
+ else if (theLine > 0) {
+ // remove newline
+ performDocumentReplaceRange([theLine-1, prevLineEntry.text.length],
+ [theLine, 0], '');
+ }
+ }
+ else {
+ var docChar = caretDocChar();
+ if (docChar > 0) {
+ if (evt.metaKey || evt.ctrlKey || evt.altKey) {
+ // delete as many unicode "letters or digits" in a row as possible;
+ // always delete one char, delete further even if that first char
+ // isn't actually a word char.
+ var deleteBackTo = docChar-1;
+ while (deleteBackTo > lineEntry.lineMarker &&
+ isWordChar(rep.alltext.charAt(deleteBackTo-1))) {
+ deleteBackTo--;
+ }
+ performDocumentReplaceCharRange(deleteBackTo, docChar, '');
+ }
+ else {
+ // normal delete
+ performDocumentReplaceCharRange(docChar-1, docChar, '');
+ }
+ }
+ }
+ }
+ else {
+ performDocumentReplaceSelection('');
+ }
+ }
+ }
+ }
+
+ // set of "letter or digit" chars is based on section 20.5.16 of the original Java Language Spec
+ var REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/;
+ var REGEX_SPACE = /\s/;
+
+ function isWordChar(c) {
+ return !! REGEX_WORDCHAR.exec(c);
+ }
+ function isSpaceChar(c) {
+ return !! REGEX_SPACE.exec(c);
+ }
+
+ function moveByWordInLine(lineText, initialIndex, forwardNotBack) {
+ var i = initialIndex;
+ function nextChar() {
+ if (forwardNotBack) return lineText.charAt(i);
+ else return lineText.charAt(i-1);
+ }
+ function advance() { if (forwardNotBack) i++; else i--; }
+ function isDone() {
+ if (forwardNotBack) return i >= lineText.length;
+ else return i <= 0;
+ }
+
+ // On Mac and Linux, move right moves to end of word and move left moves to start;
+ // on Windows, always move to start of word.
+ // On Windows, Firefox and IE disagree on whether to stop for punctuation (FF says no).
+ if (browser.windows && forwardNotBack) {
+ while ((! isDone()) && isWordChar(nextChar())) { advance(); }
+ while ((! isDone()) && ! isWordChar(nextChar())) { advance(); }
+ }
+ else {
+ while ((! isDone()) && ! isWordChar(nextChar())) { advance(); }
+ while ((! isDone()) && isWordChar(nextChar())) { advance(); }
+ }
+
+ return i;
+ }
+
+ function handleKeyEvent(evt) {
+ if (DEBUG && top.DONT_INCORP) return;
+
+ /*if (evt.which == 48) {
+ //setEditable(! isEditable);
+ //doAlert(getInnerWidth());
+ //doAlert(doc.documentElement.innerWidth)
+ alert(eval(prompt()));
+ evt.preventDefault();
+ return;
+ }*/
+ /*if (evt.which == 48) {
+ alert(doc.body.innerHTML);
+ }*/
+ /*if (evt.which == 48 && evt.type == "keydown") {
+ var lineHeights = [];
+ function eachChild(node, func) {
+ if (node.firstChild) {
+ var n = node.firstChild;
+ while (n) {
+ func(n);
+ n = n.nextSibling;
+ }
+ }
+ }
+ eachChild(doc.body, function (n) {
+ if (n.clientHeight) {
+ lineHeights.push(n.clientHeight);
+ }
+ });
+ alert(lineHeights.join(','));
+ }*/
+ /*if (evt.which == 48) {
+ top.DONT_INCORP = true;
+ var cmdTarget = doc;
+ if (browser.msie) {
+ if (doc.selection) {
+ cmdTarget = doc.selection.createRange();
+ }
+ else cmdTarget = null;
+ }
+ if (cmdTarget) {
+ cmdTarget.execCommand("Bold", false, null);
+ }
+ alert(doc.body.innerHTML);
+ evt.preventDefault();
+ return;
+ }*/
+ /*if (evt.which == 48) {
+ if (evt.type == "keypress") {
+ top.console.log(window.getSelection().getRangeAt(0));
+ evt.preventDefault();
+ }
+ return;
+ }*/
+ /*if (evt.which == 48) {
+ if (evt.type == "keypress") {
+ inCallStack("bold", function() {
+ fastIncorp(9);
+ toggleAttributeOnSelection('bold');
+ });
+ evt.preventDefault();
+ }
+ return;
+ }*/
+ /*if (evt.which == 48) {
+ if (evt.type == "keypress") {
+ inCallStack("insertunorderedlist", function() {
+ fastIncorp(9);
+ doInsertUnorderedList();
+ });
+ evt.preventDefault();
+ }
+ return;
+ }*/
+
+ if (! isEditable) return;
+
+ var type = evt.type;
+ var charCode = evt.charCode;
+ var keyCode = evt.keyCode;
+ var mods = "";
+ if (evt.altKey) mods = mods+"A";
+ if (evt.ctrlKey) mods = mods+"C";
+ if (evt.shiftKey) mods = mods+"S";
+ if (evt.metaKey) mods = mods+"M";
+ var modsPrfx = "";
+ if (mods) modsPrfx = mods+"-";
+ var which = evt.which;
+
+ //dmesg("keyevent type: "+type+", which: "+which);
+
+ // Don't take action based on modifier keys going up and down.
+ // Modifier keys do not generate "keypress" events.
+ // 224 is the command-key under Mac Firefox.
+ // 91 is the Windows key in IE; it is ASCII for open-bracket but isn't the keycode for that key
+ // 20 is capslock in IE.
+ var isModKey = ((!charCode) &&
+ ((type == "keyup") || (type == "keydown")) &&
+ (keyCode == 16 || keyCode == 17 || keyCode == 18 || keyCode == 20 || keyCode == 224
+ || keyCode == 91));
+ if (isModKey) return;
+
+ var specialHandled = false;
+ var isTypeForSpecialKey = ((browser.msie || browser.safari) ?
+ (type == "keydown") : (type == "keypress"));
+ var isTypeForCmdKey = ((browser.msie || browser.safari) ? (type == "keydown") : (type == "keypress"));
+
+ var stopped = false;
+
+ inCallStack("handleKeyEvent", function() {
+
+ if (type == "keypress" ||
+ (isTypeForSpecialKey && keyCode == 13/*return*/)) {
+ // in IE, special keys don't send keypress, the keydown does the action
+ if (! outsideKeyPress(evt)) {
+ evt.preventDefault();
+ stopped = true;
+ }
+ }
+ else if (type == "keydown") {
+ outsideKeyDown(evt);
+ }
+
+ if (! stopped) {
+ if (isTypeForSpecialKey && keyCode == 8) {
+ // "delete" key; in mozilla, if we're at the beginning of a line, normalize now,
+ // or else deleting a blank line can take two delete presses.
+ // --
+ // we do deletes completely customly now:
+ // - allows consistent (and better) meta-delete behavior
+ // - normalizing and then allowing default behavior confused IE
+ // - probably eliminates a few minor quirks
+ fastIncorp(3);
+ evt.preventDefault();
+ doDeleteKey(evt);
+ specialHandled = true;
+ }
+ if ((!specialHandled) && isTypeForSpecialKey && keyCode == 13) {
+ // return key, handle specially;
+ // note that in mozilla we need to do an incorporation for proper return behavior anyway.
+ fastIncorp(4);
+ evt.preventDefault();
+ doReturnKey();
+ //scrollSelectionIntoView();
+ scheduler.setTimeout(function() {outerWin.scrollBy(-100,0);}, 0);
+ specialHandled = true;
+ }
+ if ((!specialHandled) && isTypeForSpecialKey && keyCode == 9 &&
+ ! (evt.metaKey || evt.ctrlKey)) {
+ // tab
+ fastIncorp(5);
+ evt.preventDefault();
+ doTabKey(evt.shiftKey);
+ //scrollSelectionIntoView();
+ specialHandled = true;
+ }
+ if ((!specialHandled) && isTypeForCmdKey &&
+ String.fromCharCode(which).toLowerCase() == "z" &&
+ (evt.metaKey || evt.ctrlKey)) {
+ // cmd-Z (undo)
+ fastIncorp(6);
+ evt.preventDefault();
+ if (evt.shiftKey) {
+ doUndoRedo("redo");
+ }
+ else {
+ doUndoRedo("undo");
+ }
+ specialHandled = true;
+ }
+ if ((!specialHandled) && isTypeForCmdKey &&
+ String.fromCharCode(which).toLowerCase() == "y" &&
+ (evt.metaKey || evt.ctrlKey)) {
+ // cmd-Y (redo)
+ fastIncorp(10);
+ evt.preventDefault();
+ doUndoRedo("redo");
+ specialHandled = true;
+ }
+ if ((!specialHandled) && isTypeForCmdKey &&
+ String.fromCharCode(which).toLowerCase() == "b" &&
+ (evt.metaKey || evt.ctrlKey)) {
+ // cmd-B (bold)
+ fastIncorp(13);
+ evt.preventDefault();
+ toggleAttributeOnSelection('bold');
+ specialHandled = true;
+ }
+ if ((!specialHandled) && isTypeForCmdKey &&
+ String.fromCharCode(which).toLowerCase() == "i" &&
+ (evt.metaKey || evt.ctrlKey)) {
+ // cmd-I (italic)
+ fastIncorp(14);
+ evt.preventDefault();
+ toggleAttributeOnSelection('italic');
+ specialHandled = true;
+ }
+ if ((!specialHandled) && isTypeForCmdKey &&
+ String.fromCharCode(which).toLowerCase() == "u" &&
+ (evt.metaKey || evt.ctrlKey)) {
+ // cmd-U (underline)
+ fastIncorp(15);
+ evt.preventDefault();
+ toggleAttributeOnSelection('underline');
+ specialHandled = true;
+ }
+ if ((!specialHandled) && isTypeForCmdKey &&
+ String.fromCharCode(which).toLowerCase() == "h" &&
+ (evt.ctrlKey)) {
+ // cmd-H (backspace)
+ fastIncorp(20);
+ evt.preventDefault();
+ doDeleteKey();
+ specialHandled = true;
+ }
+ /*if ((!specialHandled) && isTypeForCmdKey &&
+ String.fromCharCode(which).toLowerCase() == "u" &&
+ (evt.metaKey || evt.ctrlKey)) {
+ // cmd-U
+ doc.body.innerHTML = '';
+ evt.preventDefault();
+ specialHandled = true;
+ }*/
+
+ if (mozillaFakeArrows && mozillaFakeArrows.handleKeyEvent(evt)) {
+ evt.preventDefault();
+ specialHandled = true;
+ }
+ }
+
+ if (type == "keydown") {
+ idleWorkTimer.atLeast(500);
+ }
+ else if (type == "keypress") {
+ if ((! specialHandled) && parenModule.shouldNormalizeOnChar(charCode)) {
+ idleWorkTimer.atMost(0);
+ }
+ else {
+ idleWorkTimer.atLeast(500);
+ }
+ }
+ else if (type == "keyup") {
+ var wait = 200;
+ idleWorkTimer.atLeast(wait);
+ idleWorkTimer.atMost(wait);
+ }
+
+ // Is part of multi-keystroke international character on Firefox Mac
+ var isFirefoxHalfCharacter =
+ (browser.mozilla && evt.altKey && charCode == 0 && keyCode == 0);
+
+ // Is part of multi-keystroke international character on Safari Mac
+ var isSafariHalfCharacter =
+ (browser.safari && evt.altKey && keyCode == 229);
+
+ if (thisKeyDoesntTriggerNormalize || isFirefoxHalfCharacter || isSafariHalfCharacter) {
+ idleWorkTimer.atLeast(3000); // give user time to type
+ // if this is a keydown, e.g., the keyup shouldn't trigger a normalize
+ thisKeyDoesntTriggerNormalize = true;
+ }
+
+ if ((! specialHandled) && (! thisKeyDoesntTriggerNormalize) &&
+ (! inInternationalComposition)) {
+ if (type != "keyup" || ! incorpIfQuick()) {
+ observeChangesAroundSelection();
+ }
+ }
+
+ if (type == "keyup") {
+ thisKeyDoesntTriggerNormalize = false;
+ }
+ });
+ }
+
+ var thisKeyDoesntTriggerNormalize = false;
+
+ function doUndoRedo(which) {
+ // precond: normalized DOM
+ if (undoModule.enabled) {
+ var whichMethod;
+ if (which == "undo") whichMethod = 'performUndo';
+ if (which == "redo") whichMethod = 'performRedo';
+ if (whichMethod) {
+ var oldEventType = currentCallStack.editEvent.eventType;
+ currentCallStack.startNewEvent(which);
+ undoModule[whichMethod](function(backset, selectionInfo) {
+ if (backset) {
+ performDocumentApplyChangeset(backset);
+ }
+ if (selectionInfo) {
+ performSelectionChange(lineAndColumnFromChar(selectionInfo.selStart),
+ lineAndColumnFromChar(selectionInfo.selEnd),
+ selectionInfo.selFocusAtStart);
+ }
+ var oldEvent = currentCallStack.startNewEvent(oldEventType, true);
+ return oldEvent;
+ });
+ }
+ }
+ }
+
+ /*function enforceNewTextTypedStyle() {
+ var sel = getSelection();
+ var n = (sel && sel.startPoint && sel.startPoint.node);
+ if (!n) return;
+ var isInOurNode = false;
+ while (n) {
+ if (n.tagName) {
+ var tag = n.tagName.toLowerCase();
+ if (tag == "b" || tag == "strong") {
+ isInOurNode = true;
+ break;
+ }
+ if (((typeof n.className) == "string") &&
+ n.className.toLowerCase().indexOf("Apple-style-span") >= 0) {
+ isInOurNode = true;
+ break;
+ }
+ }
+ n = n.parentNode;
+ }
+
+ if (! isInOurNode) {
+ doc.execCommand("Bold", false, null);
+ }
+
+ if (! browser.msie) {
+ var browserSelection = window.getSelection();
+ if (browserSelection && browserSelection.type != "None" &&
+ browserSelection.rangeCount !== 0) {
+ var range = browserSelection.getRangeAt(0);
+ var surrounder = doc.createElement("B");
+ range.surroundContents(surrounder);
+ range.selectNodeContents(surrounder);
+ browserSelection.removeAllRanges();
+ browserSelection.addRange(range);
+ }
+ }
+ }*/
+
+ function updateBrowserSelectionFromRep() {
+ // requires normalized DOM!
+ var selStart = rep.selStart, selEnd = rep.selEnd;
+
+ if (!(selStart && selEnd)) {
+ setSelection(null);
+ return;
+ }
+
+ var mozillaCaretHack = (false && browser.mozilla && selStart && selEnd &&
+ selStart[0] == selEnd[0]
+ && selStart[1] == rep.lines.atIndex(selStart[0]).lineMarker
+ && selEnd[1] == rep.lines.atIndex(selEnd[0]).lineMarker &&
+ setupMozillaCaretHack(selStart[0]));
+
+ var selection = {};
+
+ var ss = [selStart[0], selStart[1]];
+ if (mozillaCaretHack) ss[1] += 1;
+ selection.startPoint = getPointForLineAndChar(ss);
+
+ var se = [selEnd[0], selEnd[1]];
+ if (mozillaCaretHack) se[1] += 1;
+ selection.endPoint = getPointForLineAndChar(se);
+
+ selection.focusAtStart = !!rep.selFocusAtStart;
+
+ setSelection(selection);
+
+ if (mozillaCaretHack) {
+ mozillaCaretHack.unhack();
+ }
+ }
+
+ function getRepHTML() {
+ /*function lineWithSelection(text, lineNum) {
+ var haveSelStart = (rep.selStart && rep.selStart[0] == lineNum);
+ var haveSelEnd = (rep.selEnd && rep.selEnd[0] == lineNum);
+ var startCol = (haveSelStart && rep.selStart[1]);
+ var endCol = (haveSelEnd && rep.selEnd[1]);
+ var len = text.length;
+ if (haveSelStart && haveSelEnd && startCol == endCol) {
+ var color = "#000";
+ if (endCol == len) {
+ return '<span style="border-right: 1px solid '+color+'">'+
+ htmlEscape(text)+'</span>';
+ }
+ else {
+ return htmlEscape
+ }
+ }
+ }*/
+
+ return map(rep.lines.slice(), function (entry) {
+ var text = entry.text;
+ var content;
+ if (text.length == 0) {
+ content = '<span style="color: #aaa">--</span>';
+ }
+ else {
+ content = htmlPrettyEscape(text);
+ }
+ return '<div><code>'+content+'</div></code>';
+ }).join('');
+ }
+
+ function nodeMaxIndex(nd) {
+ if (isNodeText(nd)) return nd.nodeValue.length;
+ else return 1;
+ }
+
+ function hasIESelection() {
+ var browserSelection;
+ try { browserSelection = doc.selection; } catch (e) {}
+ if (! browserSelection) return false;
+ var origSelectionRange;
+ try { origSelectionRange = browserSelection.createRange(); } catch (e) {}
+ if (! origSelectionRange) return false;
+ var selectionParent = origSelectionRange.parentElement();
+ if (selectionParent.ownerDocument != doc) return false;
+ return true;
+ }
+
+ function getSelection() {
+ // returns null, or a structure containing startPoint and endPoint,
+ // each of which has node (a magicdom node), index, and maxIndex. If the node
+ // is a text node, maxIndex is the length of the text; else maxIndex is 1.
+ // index is between 0 and maxIndex, inclusive.
+ if (browser.msie) {
+ var browserSelection;
+ try { browserSelection = doc.selection; } catch (e) {}
+ if (! browserSelection) return null;
+ var origSelectionRange;
+ try { origSelectionRange = browserSelection.createRange(); } catch (e) {}
+ if (! origSelectionRange) return null;
+ var selectionParent = origSelectionRange.parentElement();
+ if (selectionParent.ownerDocument != doc) return null;
+ function newRange() {
+ return doc.body.createTextRange();
+ }
+ function rangeForElementNode(nd) {
+ var rng = newRange();
+ // doesn't work on text nodes
+ rng.moveToElementText(nd);
+ return rng;
+ }
+ function pointFromCollapsedRange(rng) {
+ var parNode = rng.parentElement();
+ var elemBelow = -1;
+ var elemAbove = parNode.childNodes.length;
+ var rangeWithin = rangeForElementNode(parNode);
+
+ if (rng.compareEndPoints("StartToStart", rangeWithin) == 0) {
+ return {node:parNode, index:0, maxIndex:1};
+ }
+ else if (rng.compareEndPoints("EndToEnd", rangeWithin) == 0) {
+ if (isBlockElement(parNode) && parNode.nextSibling) {
+ // caret after block is not consistent across browsers
+ // (same line vs next) so put caret before next node
+ return {node:parNode.nextSibling, index:0, maxIndex:1};
+ }
+ return {node:parNode, index:1, maxIndex:1};
+ }
+ else if (parNode.childNodes.length == 0) {
+ return {node:parNode, index:0, maxIndex:1};
+ }
+
+ for(var i=0;i<parNode.childNodes.length;i++) {
+ var n = parNode.childNodes.item(i);
+ if (! isNodeText(n)) {
+ var nodeRange = rangeForElementNode(n);
+ var startComp = rng.compareEndPoints("StartToStart", nodeRange);
+ var endComp = rng.compareEndPoints("EndToEnd", nodeRange);
+ if (startComp >= 0 && endComp <= 0) {
+ var index = 0;
+ if (startComp > 0) {
+ index = 1;
+ }
+ return {node:n, index:index, maxIndex:1};
+ }
+ else if (endComp > 0) {
+ if (i > elemBelow) {
+ elemBelow = i;
+ rangeWithin.setEndPoint("StartToEnd", nodeRange);
+ }
+ }
+ else if (startComp < 0) {
+ if (i < elemAbove) {
+ elemAbove = i;
+ rangeWithin.setEndPoint("EndToStart", nodeRange);
+ }
+ }
+ }
+ }
+ if ((elemAbove - elemBelow) == 1) {
+ if (elemBelow >= 0) {
+ return {node:parNode.childNodes.item(elemBelow), index:1, maxIndex:1};
+ }
+ else {
+ return {node:parNode.childNodes.item(elemAbove), index:0, maxIndex:1};
+ }
+ }
+ var idx = 0;
+ var r = rng.duplicate();
+ // infinite stateful binary search! call function for values 0 to inf,
+ // expecting the answer to be about 40. return index of smallest
+ // true value.
+ var indexIntoRange = binarySearchInfinite(40, function (i) {
+ // the search algorithm whips the caret back and forth,
+ // though it has to be moved relatively and may hit
+ // the end of the buffer
+ var delta = i-idx;
+ var moved = Math.abs(r.move("character", -delta));
+ // next line is work-around for fact that when moving left, the beginning
+ // of a text node is considered to be after the start of the parent element:
+ if (r.move("character", -1)) r.move("character", 1);
+ if (delta < 0) idx -= moved;
+ else idx += moved;
+ return (r.compareEndPoints("StartToStart", rangeWithin) <= 0);
+ });
+ // iterate over consecutive text nodes, point is in one of them
+ var textNode = elemBelow+1;
+ var indexLeft = indexIntoRange;
+ while (textNode < elemAbove) {
+ var tn = parNode.childNodes.item(textNode);
+ if (indexLeft <= tn.nodeValue.length) {
+ return {node:tn, index:indexLeft, maxIndex:tn.nodeValue.length};
+ }
+ indexLeft -= tn.nodeValue.length;
+ textNode++;
+ }
+ var tn = parNode.childNodes.item(textNode-1);
+ return {node:tn, index:tn.nodeValue.length, maxIndex:tn.nodeValue.length};
+ }
+ var selection = {};
+ if (origSelectionRange.compareEndPoints("StartToEnd", origSelectionRange) == 0) {
+ // collapsed
+ var pnt = pointFromCollapsedRange(origSelectionRange);
+ selection.startPoint = pnt;
+ selection.endPoint = {node:pnt.node, index:pnt.index, maxIndex:pnt.maxIndex};
+ }
+ else {
+ var start = origSelectionRange.duplicate();
+ start.collapse(true);
+ var end = origSelectionRange.duplicate();
+ end.collapse(false);
+ selection.startPoint = pointFromCollapsedRange(start);
+ selection.endPoint = pointFromCollapsedRange(end);
+ /*if ((!selection.startPoint.node.isText) && (!selection.endPoint.node.isText)) {
+ console.log(selection.startPoint.node.uniqueId()+","+
+ selection.startPoint.index+" / "+
+ selection.endPoint.node.uniqueId()+","+
+ selection.endPoint.index);
+ }*/
+ }
+ return selection;
+ }
+ else {
+ // non-IE browser
+ var browserSelection = window.getSelection();
+ if (browserSelection && browserSelection.type != "None" &&
+ browserSelection.rangeCount !== 0) {
+ var range = browserSelection.getRangeAt(0);
+ function isInBody(n) {
+ while (n && ! (n.tagName && n.tagName.toLowerCase() == "body")) {
+ n = n.parentNode;
+ }
+ return !!n;
+ }
+ function pointFromRangeBound(container, offset) {
+ if (! isInBody(container)) {
+ // command-click in Firefox selects whole document, HEAD and BODY!
+ return {node:root, index:0, maxIndex:1};
+ }
+ var n = container;
+ var childCount = n.childNodes.length;
+ if (isNodeText(n)) {
+ return {node:n, index:offset, maxIndex:n.nodeValue.length};
+ }
+ else if (childCount == 0) {
+ return {node:n, index:0, maxIndex:1};
+ }
+ // treat point between two nodes as BEFORE the second (rather than after the first)
+ // if possible; this way point at end of a line block-element is treated as
+ // at beginning of next line
+ else if (offset == childCount) {
+ var nd = n.childNodes.item(childCount-1);
+ var max = nodeMaxIndex(nd);
+ return {node:nd, index:max, maxIndex:max};
+ }
+ else {
+ var nd = n.childNodes.item(offset);
+ var max = nodeMaxIndex(nd);
+ return {node:nd, index:0, maxIndex:max};
+ }
+ }
+ var selection = {};
+ selection.startPoint = pointFromRangeBound(range.startContainer, range.startOffset);
+ selection.endPoint = pointFromRangeBound(range.endContainer, range.endOffset);
+ selection.focusAtStart = (((range.startContainer != range.endContainer) ||
+ (range.startOffset != range.endOffset)) &&
+ browserSelection.anchorNode &&
+ (browserSelection.anchorNode == range.endContainer) &&
+ (browserSelection.anchorOffset == range.endOffset));
+ return selection;
+ }
+ else return null;
+ }
+ }
+
+ function setSelection(selection) {
+ function copyPoint(pt) {
+ return {node:pt.node, index:pt.index, maxIndex:pt.maxIndex};
+ }
+ if (browser.msie) {
+ // Oddly enough, accessing scrollHeight fixes return key handling on IE 8,
+ // presumably by forcing some kind of internal DOM update.
+ doc.body.scrollHeight;
+
+ function moveToElementText(s, n) {
+ while (n.firstChild && ! isNodeText(n.firstChild)) {
+ n = n.firstChild;
+ }
+ s.moveToElementText(n);
+ }
+ function newRange() {
+ return doc.body.createTextRange();
+ }
+ function setCollapsedBefore(s, n) {
+ // s is an IE TextRange, n is a dom node
+ if (isNodeText(n)) {
+ // previous node should not also be text, but prevent inf recurs
+ if (n.previousSibling && ! isNodeText(n.previousSibling)) {
+ setCollapsedAfter(s, n.previousSibling);
+ }
+ else {
+ setCollapsedBefore(s, n.parentNode);
+ }
+ }
+ else {
+ moveToElementText(s, n);
+ // work around for issue that caret at beginning of line
+ // somehow ends up at end of previous line
+ if (s.move('character', 1)) {
+ s.move('character', -1);
+ }
+ s.collapse(true); // to start
+ }
+ }
+ function setCollapsedAfter(s, n) {
+ // s is an IE TextRange, n is a magicdom node
+ if (isNodeText(n)) {
+ // can't use end of container when no nextSibling (could be on next line),
+ // so use previousSibling or start of container and move forward.
+ setCollapsedBefore(s, n);
+ s.move("character", n.nodeValue.length);
+ }
+ else {
+ moveToElementText(s, n);
+ s.collapse(false); // to end
+ }
+ }
+ function getPointRange(point) {
+ var s = newRange();
+ var n = point.node;
+ if (isNodeText(n)) {
+ setCollapsedBefore(s, n);
+ s.move("character", point.index);
+ }
+ else if (point.index == 0) {
+ setCollapsedBefore(s, n);
+ }
+ else {
+ setCollapsedAfter(s, n);
+ }
+ return s;
+ }
+
+ if (selection) {
+ if (! hasIESelection()) {
+ return; // don't steal focus
+ }
+
+ var startPoint = copyPoint(selection.startPoint);
+ var endPoint = copyPoint(selection.endPoint);
+
+ // fix issue where selection can't be extended past end of line
+ // with shift-rightarrow or shift-downarrow
+ if (endPoint.index == endPoint.maxIndex && endPoint.node.nextSibling) {
+ endPoint.node = endPoint.node.nextSibling;
+ endPoint.index = 0;
+ endPoint.maxIndex = nodeMaxIndex(endPoint.node);
+ }
+ var range = getPointRange(startPoint);
+ range.setEndPoint("EndToEnd", getPointRange(endPoint));
+
+ // setting the selection in IE causes everything to scroll
+ // so that the selection is visible. if setting the selection
+ // definitely accomplishes nothing, don't do it.
+ function isEqualToDocumentSelection(rng) {
+ var browserSelection;
+ try { browserSelection = doc.selection; } catch (e) {}
+ if (! browserSelection) return false;
+ var rng2 = browserSelection.createRange();
+ if (rng2.parentElement().ownerDocument != doc) return false;
+ if (rng.compareEndPoints("StartToStart", rng2) !== 0) return false;
+ if (rng.compareEndPoints("EndToEnd", rng2) !== 0) return false;
+ return true;
+ }
+ if (! isEqualToDocumentSelection(range)) {
+ //dmesg(toSource(selection));
+ //dmesg(escapeHTML(doc.body.innerHTML));
+ range.select();
+ }
+ }
+ else {
+ try { doc.selection.empty(); } catch (e) {}
+ }
+ }
+ else {
+ // non-IE browser
+ var isCollapsed;
+ function pointToRangeBound(pt) {
+ var p = copyPoint(pt);
+ // Make sure Firefox cursor is deep enough; fixes cursor jumping when at top level,
+ // and also problem where cut/copy of a whole line selected with fake arrow-keys
+ // copies the next line too.
+ if (isCollapsed) {
+ function diveDeep() {
+ while (p.node.childNodes.length > 0) {
+ //&& (p.node == root || p.node.parentNode == root)) {
+ if (p.index == 0) {
+ p.node = p.node.firstChild;
+ p.maxIndex = nodeMaxIndex(p.node);
+ }
+ else if (p.index == p.maxIndex) {
+ p.node = p.node.lastChild;
+ p.maxIndex = nodeMaxIndex(p.node);
+ p.index = p.maxIndex;
+ }
+ else break;
+ }
+ }
+ // now fix problem where cursor at end of text node at end of span-like element
+ // with background doesn't seem to show up...
+ if (isNodeText(p.node) && p.index == p.maxIndex) {
+ var n = p.node;
+ while ((! n.nextSibling) && (n != root) && (n.parentNode != root)) {
+ n = n.parentNode;
+ }
+ if (n.nextSibling &&
+ (! ((typeof n.nextSibling.tagName) == "string" &&
+ n.nextSibling.tagName.toLowerCase() == "br")) &&
+ (n != p.node) && (n != root) && (n.parentNode != root)) {
+ // found a parent, go to next node and dive in
+ p.node = n.nextSibling;
+ p.maxIndex = nodeMaxIndex(p.node);
+ p.index = 0;
+ diveDeep();
+ }
+ }
+ // try to make sure insertion point is styled;
+ // also fixes other FF problems
+ if (! isNodeText(p.node)) {
+ diveDeep();
+ }
+ }
+ /*// make sure Firefox cursor is shallow enough;
+ // to fix problem where "return" between two spans doesn't move the caret to
+ // the next line
+ // (decided against)
+ while (!(p.node.isRoot || p.node.parent().isRoot || p.node.parent().parent().isRoot)) {
+ if (p.index == 0 && ! p.node.prev()) {
+ p.node = p.node.parent();
+ p.maxIndex = 1;
+ }
+ else if (p.index == p.maxIndex && ! p.node.next()) {
+ p.node = p.node.parent();
+ p.maxIndex = 1;
+ p.index = 1;
+ }
+ else break;
+ }
+ if ((! p.node.isRoot) && (!p.node.parent().isRoot) &&
+ (p.index == p.maxIndex) && p.node.next()) {
+ p.node = p.node.next();
+ p.maxIndex = nodeMaxIndex(p.node);
+ p.index = 0;
+ }*/
+ if (isNodeText(p.node)) {
+ return { container: p.node, offset: p.index };
+ }
+ else {
+ // p.index in {0,1}
+ return { container: p.node.parentNode, offset: childIndex(p.node) + p.index };
+ }
+ }
+ var browserSelection = window.getSelection();
+ if (browserSelection) {
+ browserSelection.removeAllRanges();
+ if (selection) {
+ isCollapsed = (selection.startPoint.node === selection.endPoint.node &&
+ selection.startPoint.index === selection.endPoint.index);
+ var start = pointToRangeBound(selection.startPoint);
+ var end = pointToRangeBound(selection.endPoint);
+
+ if ((!isCollapsed) && selection.focusAtStart && browserSelection.collapse && browserSelection.extend) {
+ // can handle "backwards"-oriented selection, shift-arrow-keys move start
+ // of selection
+ browserSelection.collapse(end.container, end.offset);
+ //console.trace();
+ //console.log(htmlPrettyEscape(rep.alltext));
+ //console.log("%o %o", rep.selStart, rep.selEnd);
+ //console.log("%o %d", start.container, start.offset);
+ browserSelection.extend(start.container, start.offset);
+ }
+ else {
+ var range = doc.createRange();
+ range.setStart(start.container, start.offset);
+ range.setEnd(end.container, end.offset);
+ browserSelection.removeAllRanges();
+ browserSelection.addRange(range);
+ }
+ }
+ }
+ }
+ }
+
+ function childIndex(n) {
+ var idx = 0;
+ while (n.previousSibling) {
+ idx++;
+ n = n.previousSibling;
+ }
+ return idx;
+ }
+
+ function fixView() {
+ // calling this method repeatedly should be fast
+
+ if (getInnerWidth() == 0 || getInnerHeight() == 0) {
+ return;
+ }
+
+ function setIfNecessary(obj, prop, value) {
+ if (obj[prop] != value) {
+ obj[prop] = value;
+ }
+ }
+
+ var lineNumberWidth = sideDiv.firstChild.offsetWidth;
+ var newSideDivWidth = lineNumberWidth + LINE_NUMBER_PADDING_LEFT;
+ if (newSideDivWidth < MIN_LINEDIV_WIDTH) newSideDivWidth = MIN_LINEDIV_WIDTH;
+ iframePadLeft = EDIT_BODY_PADDING_LEFT;
+ if (hasLineNumbers) iframePadLeft += newSideDivWidth + LINE_NUMBER_PADDING_RIGHT;
+ setIfNecessary(iframe.style, "left", iframePadLeft+"px");
+ setIfNecessary(sideDiv.style, "width", newSideDivWidth+"px");
+
+ for(var i=0;i<2;i++) {
+ var newHeight = root.clientHeight;
+ var newWidth = (browser.msie ? root.createTextRange().boundingWidth : root.clientWidth);
+ var viewHeight = getInnerHeight() - iframePadBottom - iframePadTop;
+ var viewWidth = getInnerWidth() - iframePadLeft - iframePadRight;
+ if (newHeight < viewHeight) {
+ newHeight = viewHeight;
+ if (browser.msie) setIfNecessary(outerWin.document.documentElement.style, 'overflowY', 'auto');
+ }
+ else {
+ if (browser.msie) setIfNecessary(outerWin.document.documentElement.style, 'overflowY', 'scroll');
+ }
+ if (doesWrap) {
+ newWidth = viewWidth;
+ }
+ else {
+ if (newWidth < viewWidth) newWidth = viewWidth;
+ }
+ if (newHeight > 32000) newHeight = 32000;
+ if (newWidth > 32000) newWidth = 32000;
+ setIfNecessary(iframe.style, "height", newHeight+"px");
+ setIfNecessary(iframe.style, "width", newWidth+"px");
+ setIfNecessary(sideDiv.style, "height", newHeight+"px");
+ }
+ if (browser.mozilla) {
+ if (! doesWrap) {
+ // the body:display:table-cell hack makes mozilla do scrolling
+ // correctly by shrinking the <body> to fit around its content,
+ // but mozilla won't act on clicks below the body. We keep the
+ // style.height property set to the viewport height (editor height
+ // not including scrollbar), so it will never shrink so that part of
+ // the editor isn't clickable.
+ var body = root;
+ var styleHeight = viewHeight+"px";
+ setIfNecessary(body.style, "height", styleHeight);
+ }
+ else {
+ setIfNecessary(root.style, "height", "");
+ }
+ }
+ // if near edge, scroll to edge
+ var scrollX = getScrollX();
+ var scrollY = getScrollY();
+ var win = outerWin;
+ var r = 20;
+ /*if (scrollX <= iframePadLeft+r) win.scrollBy(-iframePadLeft-r, 0);
+ else if (getPageWidth() - scrollX - getInnerWidth() <= iframePadRight+r)
+ scrollBy(iframePadRight+r, 0);*/
+ /*if (scrollY <= iframePadTop+r) win.scrollBy(0, -iframePadTop-r);
+ else if (getPageHeight() - scrollY - getInnerHeight() <= iframePadBottom+r)
+ scrollBy(0, iframePadBottom+r);*/
+
+ enforceEditability();
+
+ addClass(sideDiv, 'sidedivdelayed');
+ }
+
+ function getScrollXY() {
+ var win = outerWin;
+ var odoc = outerWin.document;
+ if (typeof(win.pageYOffset) == "number") {
+ return {x: win.pageXOffset, y: win.pageYOffset};
+ }
+ var docel = odoc.documentElement;
+ if (docel && typeof(docel.scrollTop) == "number") {
+ return {x:docel.scrollLeft, y:docel.scrollTop};
+ }
+ }
+
+ function getScrollX() {
+ return getScrollXY().x;
+ }
+
+ function getScrollY() {
+ return getScrollXY().y;
+ }
+
+ function setScrollX(x) {
+ outerWin.scrollTo(x, getScrollY());
+ }
+
+ function setScrollY(y) {
+ outerWin.scrollTo(getScrollX(), y);
+ }
+
+ function setScrollXY(x, y) {
+ outerWin.scrollTo(x, y);
+ }
+
+ var _teardownActions = [];
+ function teardown() {
+ forEach(_teardownActions, function (a) { a(); });
+ }
+
+ bindEventHandler(window, "load", setup);
+
+ function setDesignMode(newVal) {
+ try {
+ function setIfNecessary(target, prop, val) {
+ if (String(target[prop]).toLowerCase() != val) {
+ target[prop] = val;
+ return true;
+ }
+ return false;
+ }
+ if (browser.msie || browser.safari) {
+ setIfNecessary(root, 'contentEditable', (newVal ? 'true' : 'false'));
+ }
+ else {
+ var wasSet = setIfNecessary(doc, 'designMode', (newVal ? 'on' : 'off'));
+ if (wasSet && newVal && browser.opera) {
+ // turning on designMode clears event handlers
+ bindTheEventHandlers();
+ }
+ }
+ return true;
+ }
+ catch (e) {
+ return false;
+ }
+ }
+
+ var iePastedLines = null;
+ function handleIEPaste(evt) {
+ // Pasting in IE loses blank lines in a way that loses information;
+ // "one\n\ntwo\nthree" becomes "<p>one</p><p>two</p><p>three</p>",
+ // which becomes "one\ntwo\nthree". We can get the correct text
+ // from the clipboard directly, but we still have to let the paste
+ // happen to get the style information.
+
+ var clipText = window.clipboardData && window.clipboardData.getData("Text");
+ if (clipText && doc.selection) {
+ // this "paste" event seems to mess with the selection whether we try to
+ // stop it or not, so can't really do document-level manipulation now
+ // or in an idle call-stack. instead, use IE native manipulation
+ //function escapeLine(txt) {
+ //return processSpaces(escapeHTML(textify(txt)));
+ //}
+ //var newHTML = map(clipText.replace(/\r/g,'').split('\n'), escapeLine).join('<br>');
+ //doc.selection.createRange().pasteHTML(newHTML);
+ //evt.preventDefault();
+
+ //iePastedLines = map(clipText.replace(/\r/g,'').split('\n'), textify);
+ }
+ }
+
+ var inInternationalComposition = false;
+
+ function handleCompositionEvent(evt) {
+ // international input events, fired in FF3, at least; allow e.g. Japanese input
+ if (evt.type == "compositionstart") {
+ inInternationalComposition = true;
+ }
+ else if (evt.type == "compositionend") {
+ inInternationalComposition = false;
+ }
+ }
+
+ /*function handleTextEvent(evt) {
+ top.console.log("TEXT EVENT");
+ inCallStackIfNecessary("handleTextEvent", function() {
+ observeChangesAroundSelection();
+ });
+ }*/
+
+ function bindTheEventHandlers() {
+ bindEventHandler(window, "unload", teardown);
+ bindEventHandler(document, "keydown", handleKeyEvent);
+ bindEventHandler(document, "keypress", handleKeyEvent);
+ bindEventHandler(document, "keyup", handleKeyEvent);
+ bindEventHandler(document, "click", handleClick);
+ bindEventHandler(root, "blur", handleBlur);
+ if (browser.msie) {
+ bindEventHandler(document, "click", handleIEOuterClick);
+ }
+ if (browser.msie) bindEventHandler(root, "paste", handleIEPaste);
+ if ((! browser.msie) && document.documentElement) {
+ bindEventHandler(document.documentElement, "compositionstart", handleCompositionEvent);
+ bindEventHandler(document.documentElement, "compositionend", handleCompositionEvent);
+ }
+
+ /*bindEventHandler(window, "mousemove", function(e) {
+ if (e.pageX < 10) {
+ window.DEBUG_DONT_INCORP = (e.pageX < 2);
+ }
+ });*/
+ }
+
+ function handleIEOuterClick(evt) {
+ if ((evt.target.tagName||'').toLowerCase() != "html") {
+ return;
+ }
+ if (!(evt.pageY > root.clientHeight)) {
+ return;
+ }
+
+ // click below the body
+ inCallStack("handleOuterClick", function() {
+ // put caret at bottom of doc
+ fastIncorp(11);
+ if (isCaret()) { // don't interfere with drag
+ var lastLine = rep.lines.length()-1;
+ var lastCol = rep.lines.atIndex(lastLine).text.length;
+ performSelectionChange([lastLine,lastCol],[lastLine,lastCol]);
+ }
+ });
+ }
+
+ function getClassArray(elem, optFilter) {
+ var bodyClasses = [];
+ (elem.className || '').replace(/\S+/g, function (c) {
+ if ((! optFilter) || (optFilter(c))) {
+ bodyClasses.push(c);
+ }
+ });
+ return bodyClasses;
+ }
+ function setClassArray(elem, array) {
+ elem.className = array.join(' ');
+ }
+ function addClass(elem, className) {
+ var seen = false;
+ var cc = getClassArray(elem, function(c) { if (c == className) seen = true; return true; });
+ if (! seen) {
+ cc.push(className);
+ setClassArray(elem, cc);
+ }
+ }
+ function removeClass(elem, className) {
+ var seen = false;
+ var cc = getClassArray(elem, function(c) {
+ if (c == className) { seen = true; return false; } return true; });
+ if (seen) {
+ setClassArray(elem, cc);
+ }
+ }
+ function setClassPresence(elem, className, present) {
+ if (present) addClass(elem, className);
+ else removeClass(elem, className);
+ }
+
+ function setup() {
+ doc = document; // defined as a var in scope outside
+ inCallStack("setup", function() {
+ var body = doc.getElementById("innerdocbody");
+ root = body; // defined as a var in scope outside
+
+ if (browser.mozilla) addClass(root, "mozilla");
+ if (browser.safari) addClass(root, "safari");
+ if (browser.msie) addClass(root, "msie");
+ if (browser.msie) {
+ // cache CSS background images
+ try {
+ doc.execCommand("BackgroundImageCache", false, true);
+ }
+ catch (e) {
+ /* throws an error in some IE 6 but not others! */
+ }
+ }
+ setClassPresence(root, "authorColors", true);
+ setClassPresence(root, "doesWrap", doesWrap);
+
+ initDynamicCSS();
+
+ enforceEditability();
+
+ // set up dom and rep
+ while (root.firstChild) root.removeChild(root.firstChild);
+ var oneEntry = createDomLineEntry("");
+ doRepLineSplice(0, rep.lines.length(), [oneEntry]);
+ insertDomLines(null, [oneEntry.domInfo], null);
+ rep.alines = Changeset.splitAttributionLines(
+ Changeset.makeAttribution("\n"), "\n");
+
+ bindTheEventHandlers();
+
+ });
+
+ scheduler.setTimeout(function() {
+ parent.readyFunc(); // defined in code that sets up the inner iframe
+ }, 0);
+
+ isSetUp = true;
+ }
+
+ function focus() {
+ window.focus();
+ }
+
+ function handleBlur(evt) {
+ if (browser.msie) {
+ // a fix: in IE, clicking on a control like a button outside the
+ // iframe can "blur" the editor, causing it to stop getting
+ // events, though typing still affects it(!).
+ setSelection(null);
+ }
+ }
+
+ function bindEventHandler(target, type, func) {
+ var handler;
+ if ((typeof func._wrapper) != "function") {
+ func._wrapper = function(event) {
+ func(fixEvent(event || window.event || {}));
+ }
+ }
+ var handler = func._wrapper;
+ if (target.addEventListener)
+ target.addEventListener(type, handler, false);
+ else
+ target.attachEvent("on" + type, handler);
+ _teardownActions.push(function() {
+ unbindEventHandler(target, type, func);
+ });
+ }
+
+ function unbindEventHandler(target, type, func) {
+ var handler = func._wrapper;
+ if (target.removeEventListener)
+ target.removeEventListener(type, handler, false);
+ else
+ target.detachEvent("on" + type, handler);
+ }
+
+ /*forEach(['rep', 'getCleanNodeByKey', 'getDirtyRanges', 'isNodeDirty',
+ 'getSelection', 'setSelection', 'updateBrowserSelectionFromRep',
+ 'makeRecentSet', 'resetProfiler', 'getScrollXY', 'makeIdleAction'], function (k) {
+ top['_'+k] = eval(k);
+ });*/
+
+ function getSelectionPointX(point) {
+ // doesn't work in wrap-mode
+ var node = point.node;
+ var index = point.index;
+ function leftOf(n) { return n.offsetLeft; }
+ function rightOf(n) { return n.offsetLeft + n.offsetWidth; }
+ if (! isNodeText(node)) {
+ if (index == 0) return leftOf(node);
+ else return rightOf(node);
+ }
+ else {
+ // we can get bounds of element nodes, so look for those.
+ // allow consecutive text nodes for robustness.
+ var charsToLeft = index;
+ var charsToRight = node.nodeValue.length - index;
+ var n;
+ for(n = node.previousSibling; n && isNodeText(n); n = n.previousSibling)
+ charsToLeft += n.nodeValue;
+ var leftEdge = (n ? rightOf(n) : leftOf(node.parentNode));
+ for(n = node.nextSibling; n && isNodeText(n); n = n.nextSibling)
+ charsToRight += n.nodeValue;
+ var rightEdge = (n ? leftOf(n) : rightOf(node.parentNode));
+ var frac = (charsToLeft / (charsToLeft + charsToRight));
+ var pixLoc = leftEdge + frac*(rightEdge - leftEdge);
+ return Math.round(pixLoc);
+ }
+ }
+
+ function getPageHeight() {
+ var win = outerWin;
+ var odoc = win.document;
+ if (win.innerHeight && win.scrollMaxY) return win.innerHeight + win.scrollMaxY;
+ else if (odoc.body.scrollHeight > odoc.body.offsetHeight) return odoc.body.scrollHeight;
+ else return odoc.body.offsetHeight;
+ }
+
+ function getPageWidth() {
+ var win = outerWin;
+ var odoc = win.document;
+ if (win.innerWidth && win.scrollMaxX) return win.innerWidth + win.scrollMaxX;
+ else if (odoc.body.scrollWidth > odoc.body.offsetWidth) return odoc.body.scrollWidth;
+ else return odoc.body.offsetWidth;
+ }
+
+ function getInnerHeight() {
+ var win = outerWin;
+ var odoc = win.document;
+ var h;
+ if (browser.opera) h = win.innerHeight;
+ else h = odoc.documentElement.clientHeight;
+ if (h) return h;
+
+ // deal with case where iframe is hidden, hope that
+ // style.height of iframe container is set in px
+ return Number(editorInfo.frame.parentNode.style.height.replace(/[^0-9]/g,'')
+ || 0);
+ }
+
+ function getInnerWidth() {
+ var win = outerWin;
+ var odoc = win.document;
+ return odoc.documentElement.clientWidth;
+ }
+
+ function scrollNodeVerticallyIntoView(node) {
+ // requires element (non-text) node;
+ // if node extends above top of viewport or below bottom of viewport (or top of scrollbar),
+ // scroll it the minimum distance needed to be completely in view.
+ var win = outerWin;
+ var odoc = outerWin.document;
+ var distBelowTop = node.offsetTop + iframePadTop - win.scrollY;
+ var distAboveBottom = win.scrollY + getInnerHeight() -
+ (node.offsetTop +iframePadTop + node.offsetHeight);
+
+ if (distBelowTop < 0) {
+ win.scrollBy(0, distBelowTop);
+ }
+ else if (distAboveBottom < 0) {
+ win.scrollBy(0, -distAboveBottom);
+ }
+ }
+
+ function scrollXHorizontallyIntoView(pixelX) {
+ var win = outerWin;
+ var odoc = outerWin.document;
+ pixelX += iframePadLeft;
+ var distInsideLeft = pixelX - win.scrollX;
+ var distInsideRight = win.scrollX + getInnerWidth() - pixelX;
+ if (distInsideLeft < 0) {
+ win.scrollBy(distInsideLeft, 0);
+ }
+ else if (distInsideRight < 0) {
+ win.scrollBy(-distInsideRight+1, 0);
+ }
+ }
+
+ function scrollSelectionIntoView() {
+ if (! rep.selStart) return;
+ fixView();
+ var focusLine = (rep.selFocusAtStart ? rep.selStart[0] : rep.selEnd[0]);
+ scrollNodeVerticallyIntoView(rep.lines.atIndex(focusLine).lineNode);
+ if (! doesWrap) {
+ var browserSelection = getSelection();
+ if (browserSelection) {
+ var focusPoint = (browserSelection.focusAtStart ? browserSelection.startPoint :
+ browserSelection.endPoint);
+ var selectionPointX = getSelectionPointX(focusPoint);
+ scrollXHorizontallyIntoView(selectionPointX);
+ fixView();
+ }
+ }
+ }
+
+ function getLineListType(lineNum) {
+ // get "list" attribute of first char of line
+ var aline = rep.alines[lineNum];
+ if (aline) {
+ var opIter = Changeset.opIterator(aline);
+ if (opIter.hasNext()) {
+ return Changeset.opAttributeValue(opIter.next(), 'list', rep.apool) || '';
+ }
+ }
+ return '';
+ }
+
+ function setLineListType(lineNum, listType) {
+ setLineListTypes([[lineNum, listType]]);
+ }
+
+ function setLineListTypes(lineNumTypePairsInOrder) {
+ var loc = [0,0];
+ var builder = Changeset.builder(rep.lines.totalWidth());
+ for(var i=0;i<lineNumTypePairsInOrder.length;i++) {
+ var pair = lineNumTypePairsInOrder[i];
+ var lineNum = pair[0];
+ var listType = pair[1];
+ buildKeepRange(builder, loc, (loc = [lineNum,0]));
+ if (getLineListType(lineNum)) {
+ // already a line marker
+ if (listType) {
+ // make different list type
+ buildKeepRange(builder, loc, (loc = [lineNum,1]),
+ [['list',listType]], rep.apool);
+ }
+ else {
+ // remove list marker
+ buildRemoveRange(builder, loc, (loc = [lineNum,1]));
+ }
+ }
+ else {
+ // currently no line marker
+ if (listType) {
+ // add a line marker
+ builder.insert('*', [['author', thisAuthor],
+ ['insertorder', 'first'],
+ ['list', listType]], rep.apool);
+ }
+ }
+ }
+
+ var cs = builder.toString();
+ if (! Changeset.isIdentity(cs)) {
+ performDocumentApplyChangeset(cs);
+ }
+ }
+
+ function doInsertUnorderedList() {
+ if (! (rep.selStart && rep.selEnd)) {
+ return;
+ }
+
+ var firstLine, lastLine;
+ firstLine = rep.selStart[0];
+ lastLine = Math.max(firstLine,
+ rep.selEnd[0] - ((rep.selEnd[1] == 0) ? 1 : 0));
+
+ var allLinesAreList = true;
+ for(var n=firstLine;n<=lastLine;n++) {
+ if (! getLineListType(n)) {
+ allLinesAreList = false;
+ break;
+ }
+ }
+
+ var mods = [];
+ for(var n=firstLine;n<=lastLine;n++) {
+ var t = getLineListType(n);
+ mods.push([n, allLinesAreList ? '' : (t ? t : 'bullet1')]);
+ }
+ setLineListTypes(mods);
+ }
+
+ var mozillaFakeArrows = (browser.mozilla && (function() {
+ // In Firefox 2, arrow keys are unstable while DOM-manipulating
+ // operations are going on. Specifically, if an operation
+ // (computation that ties up the event queue) is going on (in the
+ // call-stack of some event, like a timeout) that at some point
+ // mutates nodes involved in the selection, then the arrow
+ // keypress may (randomly) move the caret to the beginning or end
+ // of the document. If the operation also mutates the selection
+ // range, the old selection or the new selection may be used, or
+ // neither.
+
+ // As long as the arrow is pressed during the busy operation, it
+ // doesn't seem to matter that the keydown and keypress events
+ // aren't generated until afterwards, or that the arrow movement
+ // can still be stopped (meaning it hasn't been performed yet);
+ // Firefox must be preserving some old information about the
+ // selection or the DOM from when the key was initially pressed.
+ // However, it also doesn't seem to matter when the key was
+ // actually pressed relative to the time of the mutation within
+ // the prolonged operation. Also, even in very controlled tests
+ // (like a mutation followed by a long period of busyWaiting), the
+ // problem shows up often but not every time, with no discernable
+ // pattern. Who knows, it could have something to do with the
+ // caret-blinking timer, or DOM changes not being applied
+ // immediately.
+
+ // This problem, mercifully, does not show up at all in IE or
+ // Safari. My solution is to have my own, full-featured arrow-key
+ // implementation for Firefox.
+
+ // Note that the problem addressed here is potentially very subtle,
+ // especially if the operation is quick and is timed to usually happen
+ // when the user is idle.
+
+ // features:
+ // - 'up' and 'down' arrows preserve column when passing through shorter lines
+ // - shift-arrows extend the "focus" point, which may be start or end of range
+ // - the focus point is kept horizontally and vertically scrolled into view
+ // - arrows without shift cause caret to move to beginning or end of selection (left,right)
+ // or move focus point up or down a line (up,down)
+ // - command-(left,right,up,down) on Mac acts like (line-start, line-end, doc-start, doc-end)
+ // - takes wrapping into account when doesWrap is true, i.e. up-arrow and down-arrow move
+ // between the virtual lines within a wrapped line; this was difficult, and unfortunately
+ // requires mutating the DOM to get the necessary information
+
+ var savedFocusColumn = 0; // a value of 0 has no effect
+ var updatingSelectionNow = false;
+
+ function getVirtualLineView(lineNum) {
+ var lineNode = rep.lines.atIndex(lineNum).lineNode;
+ while (lineNode.firstChild && isBlockElement(lineNode.firstChild)) {
+ lineNode = lineNode.firstChild;
+ }
+ return makeVirtualLineView(lineNode);
+ }
+
+ function markerlessLineAndChar(line, chr) {
+ return [line, chr - rep.lines.atIndex(line).lineMarker];
+ }
+ function markerfulLineAndChar(line, chr) {
+ return [line, chr + rep.lines.atIndex(line).lineMarker];
+ }
+
+ return {
+ notifySelectionChanged: function() {
+ if (! updatingSelectionNow) {
+ savedFocusColumn = 0;
+ }
+ },
+ handleKeyEvent: function(evt) {
+ // returns "true" if handled
+ if (evt.type != "keypress") return false;
+ var keyCode = evt.keyCode;
+ if (keyCode < 37 || keyCode > 40) return false;
+ incorporateUserChanges();
+
+ if (!(rep.selStart && rep.selEnd)) return true;
+
+ // {byWord,toEnd,normal}
+ var moveMode = (evt.altKey ? "byWord" :
+ (evt.ctrlKey ? "byWord" :
+ (evt.metaKey ? "toEnd" :
+ "normal")));
+
+ var anchorCaret =
+ markerlessLineAndChar(rep.selStart[0], rep.selStart[1]);
+ var focusCaret =
+ markerlessLineAndChar(rep.selEnd[0], rep.selEnd[1]);
+ var wasCaret = isCaret();
+ if (rep.selFocusAtStart) {
+ var tmp = anchorCaret; anchorCaret = focusCaret; focusCaret = tmp;
+ }
+ var K_UP = 38, K_DOWN = 40, K_LEFT = 37, K_RIGHT = 39;
+ var dontMove = false;
+ if (wasCaret && ! evt.shiftKey) {
+ // collapse, will mutate both together
+ anchorCaret = focusCaret;
+ }
+ else if ((! wasCaret) && (! evt.shiftKey)) {
+ if (keyCode == K_LEFT) {
+ // place caret at beginning
+ if (rep.selFocusAtStart) anchorCaret = focusCaret;
+ else focusCaret = anchorCaret;
+ if (moveMode == "normal") dontMove = true;
+ }
+ else if (keyCode == K_RIGHT) {
+ // place caret at end
+ if (rep.selFocusAtStart) focusCaret = anchorCaret;
+ else anchorCaret = focusCaret;
+ if (moveMode == "normal") dontMove = true;
+ }
+ else {
+ // collapse, will mutate both together
+ anchorCaret = focusCaret;
+ }
+ }
+ if (! dontMove) {
+ function lineLength(i) {
+ var entry = rep.lines.atIndex(i);
+ return entry.text.length - entry.lineMarker;
+ }
+ function lineText(i) {
+ var entry = rep.lines.atIndex(i);
+ return entry.text.substring(entry.lineMarker);
+ }
+
+ if (keyCode == K_UP || keyCode == K_DOWN) {
+ var up = (keyCode == K_UP);
+ var canChangeLines = ((up && focusCaret[0]) ||
+ ((!up) && focusCaret[0] < rep.lines.length()-1));
+ var virtualLineView, virtualLineSpot, canChangeVirtualLines = false;
+ if (doesWrap) {
+ virtualLineView = getVirtualLineView(focusCaret[0]);
+ virtualLineSpot = virtualLineView.getVLineAndOffsetForChar(focusCaret[1]);
+ canChangeVirtualLines = ((up && virtualLineSpot.vline > 0) ||
+ ((!up) && virtualLineSpot.vline < (
+ virtualLineView.getNumVirtualLines() - 1)));
+ }
+ var newColByVirtualLineChange;
+ if (moveMode == "toEnd") {
+ if (up) {
+ focusCaret[0] = 0;
+ focusCaret[1] = 0;
+ }
+ else {
+ focusCaret[0] = rep.lines.length()-1;
+ focusCaret[1] = lineLength(focusCaret[0]);
+ }
+ }
+ else if (moveMode == "byWord") {
+ // move by "paragraph", a feature that Firefox lacks but IE and Safari both have
+ if (up) {
+ if (focusCaret[1] == 0 && canChangeLines) {
+ focusCaret[0]--;
+ focusCaret[1] = 0;
+ }
+ else focusCaret[1] = 0;
+ }
+ else {
+ var lineLen = lineLength(focusCaret[0]);
+ if (browser.windows) {
+ if (canChangeLines) {
+ focusCaret[0]++;
+ focusCaret[1] = 0;
+ }
+ else {
+ focusCaret[1] = lineLen;
+ }
+ }
+ else {
+ if (focusCaret[1] == lineLen && canChangeLines) {
+ focusCaret[0]++;
+ focusCaret[1] = lineLength(focusCaret[0]);
+ }
+ else {
+ focusCaret[1] = lineLen;
+ }
+ }
+ }
+ savedFocusColumn = 0;
+ }
+ else if (canChangeVirtualLines) {
+ var vline = virtualLineSpot.vline;
+ var offset = virtualLineSpot.offset;
+ if (up) vline--;
+ else vline++;
+ if (savedFocusColumn > offset) offset = savedFocusColumn;
+ else {
+ savedFocusColumn = offset;
+ }
+ var newSpot = virtualLineView.getCharForVLineAndOffset(vline, offset);
+ focusCaret[1] = newSpot.lineChar;
+ }
+ else if (canChangeLines) {
+ if (up) focusCaret[0]--;
+ else focusCaret[0]++;
+ var offset = focusCaret[1];
+ if (doesWrap) {
+ offset = virtualLineSpot.offset;
+ }
+ if (savedFocusColumn > offset) offset = savedFocusColumn;
+ else {
+ savedFocusColumn = offset;
+ }
+ if (doesWrap) {
+ var newLineView = getVirtualLineView(focusCaret[0]);
+ var vline = (up ? newLineView.getNumVirtualLines()-1 : 0);
+ var newSpot = newLineView.getCharForVLineAndOffset(vline, offset);
+ focusCaret[1] = newSpot.lineChar;
+ }
+ else {
+ var lineLen = lineLength(focusCaret[0]);
+ if (offset > lineLen) offset = lineLen;
+ focusCaret[1] = offset;
+ }
+ }
+ else {
+ if (up) focusCaret[1] = 0;
+ else focusCaret[1] = lineLength(focusCaret[0]);
+ savedFocusColumn = 0;
+ }
+ }
+ else if (keyCode == K_LEFT || keyCode == K_RIGHT) {
+ var left = (keyCode == K_LEFT);
+ if (left) {
+ if (moveMode == "toEnd") focusCaret[1] = 0;
+ else if (focusCaret[1] > 0) {
+ if (moveMode == "byWord") {
+ focusCaret[1] = moveByWordInLine(lineText(focusCaret[0]), focusCaret[1], false);
+ }
+ else {
+ focusCaret[1]--;
+ }
+ }
+ else if (focusCaret[0] > 0) {
+ focusCaret[0]--;
+ focusCaret[1] = lineLength(focusCaret[0]);
+ if (moveMode == "byWord") {
+ focusCaret[1] = moveByWordInLine(lineText(focusCaret[0]), focusCaret[1], false);
+ }
+ }
+ }
+ else {
+ var lineLen = lineLength(focusCaret[0]);
+ if (moveMode == "toEnd") focusCaret[1] = lineLen;
+ else if (focusCaret[1] < lineLen) {
+ if (moveMode == "byWord") {
+ focusCaret[1] = moveByWordInLine(lineText(focusCaret[0]), focusCaret[1], true);
+ }
+ else {
+ focusCaret[1]++;
+ }
+ }
+ else if (focusCaret[0] < rep.lines.length()-1) {
+ focusCaret[0]++;
+ focusCaret[1] = 0;
+ if (moveMode == "byWord") {
+ focusCaret[1] = moveByWordInLine(lineText(focusCaret[0]), focusCaret[1], true);
+ }
+ }
+ }
+ savedFocusColumn = 0;
+ }
+ }
+
+ var newSelFocusAtStart = ((focusCaret[0] < anchorCaret[0]) ||
+ (focusCaret[0] == anchorCaret[0] &&
+ focusCaret[1] < anchorCaret[1]));
+ var newSelStart = (newSelFocusAtStart ? focusCaret : anchorCaret);
+ var newSelEnd = (newSelFocusAtStart ? anchorCaret : focusCaret);
+ updatingSelectionNow = true;
+ performSelectionChange(markerfulLineAndChar(newSelStart[0],
+ newSelStart[1]),
+ markerfulLineAndChar(newSelEnd[0],
+ newSelEnd[1]),
+ newSelFocusAtStart);
+ updatingSelectionNow = false;
+ currentCallStack.userChangedSelection = true;
+ return true;
+ }
+ };
+ })());
+
+
+ // stolen from jquery-1.2.1
+ function fixEvent(event) {
+ // store a copy of the original event object
+ // and clone to set read-only properties
+ var originalEvent = event;
+ event = extend({}, originalEvent);
+
+ // add preventDefault and stopPropagation since
+ // they will not work on the clone
+ event.preventDefault = function() {
+ // if preventDefault exists run it on the original event
+ if (originalEvent.preventDefault)
+ originalEvent.preventDefault();
+ // otherwise set the returnValue property of the original event to false (IE)
+ originalEvent.returnValue = false;
+ };
+ event.stopPropagation = function() {
+ // if stopPropagation exists run it on the original event
+ if (originalEvent.stopPropagation)
+ originalEvent.stopPropagation();
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ originalEvent.cancelBubble = true;
+ };
+
+ // Fix target property, if necessary
+ if ( !event.target && event.srcElement )
+ event.target = event.srcElement;
+
+ // check if target is a textnode (safari)
+ if (browser.safari && event.target.nodeType == 3)
+ event.target = originalEvent.target.parentNode;
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && event.fromElement )
+ event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && event.clientX != null ) {
+ var e = document.documentElement, b = document.body;
+ event.pageX = event.clientX + (e && e.scrollLeft || b.scrollLeft || 0);
+ event.pageY = event.clientY + (e && e.scrollTop || b.scrollTop || 0);
+ }
+
+ // Add which for key events
+ if ( !event.which && (event.charCode || event.keyCode) )
+ event.which = event.charCode || event.keyCode;
+
+ // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+ if ( !event.metaKey && event.ctrlKey )
+ event.metaKey = event.ctrlKey;
+
+ // Add which for click: 1 == left; 2 == middle; 3 == right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && event.button )
+ event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+
+ return event;
+ }
+
+ var lineNumbersShown;
+ var sideDivInner;
+ function initLineNumbers() {
+ lineNumbersShown = 1;
+ sideDiv.innerHTML =
+ '<table border="0" cellpadding="0" cellspacing="0" align="right">'+
+ '<tr><td id="sidedivinner"><div>1</div></td></tr></table>';
+ sideDivInner = outerWin.document.getElementById("sidedivinner");
+ }
+
+ function updateLineNumbers() {
+ var newNumLines = rep.lines.length();
+ if (newNumLines < 1) newNumLines = 1;
+ if (newNumLines != lineNumbersShown) {
+ var container = sideDivInner;
+ var odoc = outerWin.document;
+ while (lineNumbersShown < newNumLines) {
+ lineNumbersShown++;
+ var n = lineNumbersShown;
+ var div = odoc.createElement("DIV");
+ div.appendChild(odoc.createTextNode(String(n)));
+ container.appendChild(div);
+ }
+ while (lineNumbersShown > newNumLines) {
+ container.removeChild(container.lastChild);
+ lineNumbersShown--;
+ }
+ }
+
+ if (currentCallStack && currentCallStack.domClean) {
+ var a = sideDivInner.firstChild;
+ var b = doc.body.firstChild;
+ while (a && b) {
+ var h = (b.clientHeight || b.offsetHeight);
+ if (b.nextSibling) {
+ // when text is zoomed in mozilla, divs have fractional
+ // heights (though the properties are always integers)
+ // and the line-numbers don't line up unless we pay
+ // attention to where the divs are actually placed...
+ // (also: padding on TTs/SPANs in IE...)
+ h = b.nextSibling.offsetTop - b.offsetTop;
+ }
+ if (h) {
+ var hpx = h+"px";
+ if (a.style.height != hpx)
+ a.style.height = hpx;
+ }
+ a = a.nextSibling;
+ b = b.nextSibling;
+ }
+
+ // fix if first line has margin (f.e. h1 in first line)
+ sideDivInner.firstChild.style.marginTop =
+ (doc.body.firstChild.offsetTop - sideDivInner.firstChild.offsetTop +
+ parseInt(sideDivInner.firstChild.style.marginTop + "0")) + "px";
+ }
+ }
+
+};
+
+OUTER(this);
diff --git a/infrastructure/ace/www/ace2_outer.js b/infrastructure/ace/www/ace2_outer.js
new file mode 100644
index 0000000..f947534
--- /dev/null
+++ b/infrastructure/ace/www/ace2_outer.js
@@ -0,0 +1,234 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+// requires: top
+// requires: plugins
+// requires: undefined
+
+
+Ace2Editor.registry = { nextId: 1 };
+
+function Ace2Editor() {
+ var thisFunctionsName = "Ace2Editor";
+ var ace2 = Ace2Editor;
+
+ var editor = {};
+ var info = { editor: editor, id: (ace2.registry.nextId++) };
+ var loaded = false;
+
+ var actionsPendingInit = [];
+ function pendingInit(func, optDoNow) {
+ return function() {
+ var that = this;
+ var args = arguments;
+ function action() {
+ func.apply(that, args);
+ }
+ if (optDoNow) {
+ optDoNow.apply(that, args);
+ }
+ if (loaded) {
+ action();
+ }
+ else {
+ actionsPendingInit.push(action);
+ }
+ };
+ }
+ function doActionsPendingInit() {
+ for(var i=0;i<actionsPendingInit.length;i++) {
+ actionsPendingInit[i]();
+ }
+ actionsPendingInit = [];
+ }
+
+ ace2.registry[info.id] = info;
+
+ editor.importText = pendingInit(function(newCode, undoable) {
+ info.ace_importText(newCode, undoable); });
+ editor.importAText = pendingInit(function(newCode, apoolJsonObj, undoable) {
+ info.ace_importAText(newCode, apoolJsonObj, undoable); });
+ editor.exportText = function() {
+ if (! loaded) return "(awaiting init)\n";
+ return info.ace_exportText();
+ };
+ editor.getFrame = function() { return info.frame || null; };
+ editor.focus = pendingInit(function() { info.ace_focus(); });
+ editor.adjustSize = pendingInit(function() {
+ var frameParent = info.frame.parentNode;
+ var parentHeight = frameParent.clientHeight;
+ // deal with case where iframe is hidden, no clientHeight
+ info.frame.style.height = (parentHeight ? parentHeight+"px" :
+ frameParent.style.height);
+ info.ace_editorChangedSize();
+ });
+ editor.setEditable = pendingInit(function(newVal) { info.ace_setEditable(newVal); });
+ editor.getFormattedCode = function() { return info.ace_getFormattedCode(); };
+ editor.setOnKeyPress = pendingInit(function (handler) { info.ace_setOnKeyPress(handler); });
+ editor.setOnKeyDown = pendingInit(function (handler) { info.ace_setOnKeyDown(handler); });
+ editor.setNotifyDirty = pendingInit(function (handler) { info.ace_setNotifyDirty(handler); });
+
+ editor.setProperty = pendingInit(function(key, value) { info.ace_setProperty(key, value); });
+ editor.getDebugProperty = function(prop) { return info.ace_getDebugProperty(prop); };
+
+ editor.setBaseText = pendingInit(function(txt) { info.ace_setBaseText(txt); });
+ editor.setBaseAttributedText = pendingInit(function(atxt, apoolJsonObj) {
+ info.ace_setBaseAttributedText(atxt, apoolJsonObj); });
+ editor.applyChangesToBase = pendingInit(function (changes, optAuthor,apoolJsonObj) {
+ info.ace_applyChangesToBase(changes, optAuthor, apoolJsonObj); });
+ // prepareUserChangeset:
+ // Returns null if no new changes or ACE not ready. Otherwise, bundles up all user changes
+ // to the latest base text into a Changeset, which is returned (as a string if encodeAsString).
+ // If this method returns a truthy value, then applyPreparedChangesetToBase can be called
+ // at some later point to consider these changes part of the base, after which prepareUserChangeset
+ // must be called again before applyPreparedChangesetToBase. Multiple consecutive calls
+ // to prepareUserChangeset will return an updated changeset that takes into account the
+ // latest user changes, and modify the changeset to be applied by applyPreparedChangesetToBase
+ // accordingly.
+ editor.prepareUserChangeset = function() {
+ if (! loaded) return null;
+ return info.ace_prepareUserChangeset();
+ };
+ editor.applyPreparedChangesetToBase = pendingInit(
+ function() { info.ace_applyPreparedChangesetToBase(); });
+ editor.setUserChangeNotificationCallback = pendingInit(function(callback) {
+ info.ace_setUserChangeNotificationCallback(callback);
+ });
+ editor.setAuthorInfo = pendingInit(function(author, authorInfo) {
+ info.ace_setAuthorInfo(author, authorInfo);
+ });
+ editor.setAuthorSelectionRange = pendingInit(function(author, start, end) {
+ info.ace_setAuthorSelectionRange(author, start, end);
+ });
+
+ editor.getUnhandledErrors = function() {
+ if (! loaded) return [];
+ // returns array of {error: <browser Error object>, time: +new Date()}
+ return info.ace_getUnhandledErrors();
+ };
+ editor.execCommand = pendingInit(function(cmd, arg1) {
+ info.ace_execCommand(cmd, arg1);
+ });
+
+ // calls to these functions ($$INCLUDE_...) are replaced when this file is processed
+ // and compressed, putting the compressed code from the named file directly into the
+ // source here.
+
+ var $$INCLUDE_CSS = function(fileName) {
+ return '<link rel="stylesheet" type="text/css" href="'+fileName+'"/>';
+ };
+ var $$INCLUDE_JS = function(fileName) {
+ return '\x3cscript type="text/javascript" src="'+fileName+'">\x3c/script>';
+ };
+ var $$INCLUDE_JS_DEV = $$INCLUDE_JS;
+ var $$INCLUDE_CSS_DEV = $$INCLUDE_CSS;
+
+ var $$INCLUDE_CSS_Q = function(fileName) {
+ return '\'<link rel="stylesheet" type="text/css" href="'+fileName+'"/>\'';
+ };
+ var $$INCLUDE_JS_Q = function(fileName) {
+ return '\'\\x3cscript type="text/javascript" src="'+fileName+'">\\x3c/script>\'';
+ };
+ var $$INCLUDE_JS_Q_DEV = $$INCLUDE_JS_Q;
+ var $$INCLUDE_CSS_Q_DEV = $$INCLUDE_CSS_Q;
+
+ editor.destroy = pendingInit(function() {
+ info.ace_dispose();
+ info.frame.parentNode.removeChild(info.frame);
+ delete ace2.registry[info.id];
+ info = null; // prevent IE 6 closure memory leaks
+ });
+
+ editor.init = function(containerId, initialCode, doneFunc) {
+
+ editor.importText(initialCode);
+
+ info.onEditorReady = function() {
+ loaded = true;
+ doActionsPendingInit();
+ doneFunc();
+ };
+
+ (function() {
+ var doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '+
+ '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
+
+ var iframeHTML = ["'"+doctype+"<html><head>'"];
+
+ plugins.callHook(
+ "aceInitInnerdocbodyHead", {iframeHTML:iframeHTML});
+
+ // these lines must conform to a specific format because they are passed by the build script:
+ iframeHTML.push($$INCLUDE_CSS_Q("editor.css syntax.css inner.css"));
+ //iframeHTML.push(INCLUDE_JS_Q_DEV("ace2_common_dev.js"));
+ //iframeHTML.push(INCLUDE_JS_Q_DEV("profiler.js"));
+ iframeHTML.push($$INCLUDE_JS_Q("ace2_common.js skiplist.js virtual_lines.js easysync2.js cssmanager.js colorutils.js undomodule.js contentcollector.js changesettracker.js linestylefilter.js domline.js"));
+ iframeHTML.push($$INCLUDE_JS_Q("ace2_inner.js"));
+ iframeHTML.push('\'\\n<style type="text/css" title="dynamicsyntax"></style>\\n\'');
+ iframeHTML.push('\'</head><body id="innerdocbody" class="syntax" spellcheck="false">&nbsp;</body></html>\'');
+
+ var outerScript = 'editorId = "'+info.id+'"; editorInfo = parent.'+
+ thisFunctionsName+'.registry[editorId]; '+
+ 'window.onload = function() '+
+ '{ window.onload = null; setTimeout'+
+ '(function() '+
+ '{ var iframe = document.createElement("IFRAME"); '+
+ 'iframe.scrolling = "no"; var outerdocbody = document.getElementById("outerdocbody"); '+
+ 'iframe.frameBorder = 0; iframe.allowTransparency = true; '+ // for IE
+ 'outerdocbody.insertBefore(iframe, outerdocbody.firstChild); '+
+ 'iframe.ace_outerWin = window; '+
+ 'readyFunc = function() { editorInfo.onEditorReady(); readyFunc = null; editorInfo = null; }; '+
+ 'var doc = iframe.contentWindow.document; doc.open(); doc.write('+
+ iframeHTML.join('+')+'); doc.close(); '+
+ '}, 0); }';
+
+ var outerHTML = [doctype, '<html><head>',
+ $$INCLUDE_CSS("editor.css"),
+ // bizarrely, in FF2, a file with no "external" dependencies won't finish loading properly
+ // (throbs busy while typing)
+ '<link rel="stylesheet" type="text/css" href="data:text/css,"/>',
+ '\x3cscript>', outerScript, '\x3c/script>',
+ '</head><body id="outerdocbody"><div id="sidediv"><!-- --></div><div id="linemetricsdiv">x</div><div id="overlaysdiv"><!-- --></div></body></html>'];
+
+
+ if (!Array.prototype.map) Array.prototype.map = function(fun) { //needed for IE
+ if (typeof fun != "function") throw new TypeError();
+ var len = this.length;
+ var res = new Array(len);
+ var thisp = arguments[1];
+ for (var i = 0; i < len; i++) {
+ if (i in this) res[i] = fun.call(thisp, this[i], i, this);
+ }
+ return res;
+ };
+
+ var outerFrame = document.createElement("IFRAME");
+ outerFrame.frameBorder = 0; // for IE
+ info.frame = outerFrame;
+ document.getElementById(containerId).appendChild(outerFrame);
+
+ var editorDocument = outerFrame.contentWindow.document;
+
+ editorDocument.open();
+ editorDocument.write(outerHTML.join(''));
+ editorDocument.close();
+
+ editor.adjustSize();
+ })();
+ };
+
+ return editor;
+}
diff --git a/trunk/infrastructure/ace/www/ace2_wrapper.js b/infrastructure/ace/www/ace2_wrapper.js
index b62e09d..b62e09d 100644
--- a/trunk/infrastructure/ace/www/ace2_wrapper.js
+++ b/infrastructure/ace/www/ace2_wrapper.js
diff --git a/trunk/infrastructure/ace/www/bbtree.js b/infrastructure/ace/www/bbtree.js
index 70cb8c0..70cb8c0 100644
--- a/trunk/infrastructure/ace/www/bbtree.js
+++ b/infrastructure/ace/www/bbtree.js
diff --git a/trunk/infrastructure/ace/www/changesettracker.js b/infrastructure/ace/www/changesettracker.js
index d6fe018..d6fe018 100644
--- a/trunk/infrastructure/ace/www/changesettracker.js
+++ b/infrastructure/ace/www/changesettracker.js
diff --git a/trunk/infrastructure/ace/www/colorutils.js b/infrastructure/ace/www/colorutils.js
index bb61de3..bb61de3 100644
--- a/trunk/infrastructure/ace/www/colorutils.js
+++ b/infrastructure/ace/www/colorutils.js
diff --git a/trunk/infrastructure/ace/www/contentcollector.js b/infrastructure/ace/www/contentcollector.js
index 573672e..573672e 100644
--- a/trunk/infrastructure/ace/www/contentcollector.js
+++ b/infrastructure/ace/www/contentcollector.js
diff --git a/trunk/infrastructure/ace/www/cssmanager.js b/infrastructure/ace/www/cssmanager.js
index a5c549b..a5c549b 100644
--- a/trunk/infrastructure/ace/www/cssmanager.js
+++ b/infrastructure/ace/www/cssmanager.js
diff --git a/trunk/infrastructure/ace/www/dev.html b/infrastructure/ace/www/dev.html
index 0a9768e..0a9768e 100644
--- a/trunk/infrastructure/ace/www/dev.html
+++ b/infrastructure/ace/www/dev.html
diff --git a/infrastructure/ace/www/domline.js b/infrastructure/ace/www/domline.js
new file mode 100644
index 0000000..f1d19e4
--- /dev/null
+++ b/infrastructure/ace/www/domline.js
@@ -0,0 +1,232 @@
+// THIS FILE IS ALSO AN APPJET MODULE: etherpad.collab.ace.domline
+// %APPJET%: import("etherpad.admin.plugins");
+
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+// requires: top
+// requires: plugins
+// requires: undefined
+
+var domline = {};
+domline.noop = function() {};
+domline.identity = function(x) { return x; };
+
+domline.addToLineClass = function(lineClass, cls) {
+ // an "empty span" at any point can be used to add classes to
+ // the line, using line:className. otherwise, we ignore
+ // the span.
+ cls.replace(/\S+/g, function (c) {
+ if (c.indexOf("line:") == 0) {
+ // add class to line
+ lineClass = (lineClass ? lineClass+' ' : '')+c.substring(5);
+ }
+ });
+ return lineClass;
+}
+
+// if "document" is falsy we don't create a DOM node, just
+// an object with innerHTML and className
+domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument) {
+ var result = { node: null,
+ appendSpan: domline.noop,
+ prepareForAdd: domline.noop,
+ notifyAdded: domline.noop,
+ clearSpans: domline.noop,
+ finishUpdate: domline.noop,
+ lineMarker: 0 };
+
+ var browser = (optBrowser || {});
+ var document = optDocument;
+
+ if (document) {
+ result.node = document.createElement("div");
+ }
+ else {
+ result.node = {innerHTML: '', className: ''};
+ }
+
+ var html = [];
+ var preHtml, postHtml;
+ var curHTML = null;
+ function processSpaces(s) {
+ return domline.processSpaces(s, doesWrap);
+ }
+ var identity = domline.identity;
+ var perTextNodeProcess = (doesWrap ? identity : processSpaces);
+ var perHtmlLineProcess = (doesWrap ? processSpaces : identity);
+ var lineClass = 'ace-line';
+ result.appendSpan = function(txt, cls) {
+ if (cls.indexOf('list') >= 0) {
+ var listType = /(?:^| )list:(\S+)/.exec(cls);
+ if (listType) {
+ listType = listType[1];
+ if (listType) {
+ preHtml = '<ul class="list-'+listType+'"><li>';
+ postHtml = '</li></ul>';
+ }
+ result.lineMarker += txt.length;
+ return; // don't append any text
+ }
+ }
+ var href = null;
+ var simpleTags = null;
+ if (cls.indexOf('url') >= 0) {
+ cls = cls.replace(/(^| )url:(\S+)/g, function(x0, space, url) {
+ href = url;
+ return space+"url";
+ });
+ }
+ if (cls.indexOf('tag') >= 0) {
+ cls = cls.replace(/(^| )tag:(\S+)/g, function(x0, space, tag) {
+ if (! simpleTags) simpleTags = [];
+ simpleTags.push(tag.toLowerCase());
+ return space+tag;
+ });
+ }
+
+ var extraOpenTags = "";
+ var extraCloseTags = "";
+
+ var plugins_;
+ if (typeof(plugins)!='undefined') {
+ plugins_ = plugins;
+ } else {
+ plugins_ = parent.parent.plugins;
+ }
+
+ plugins_.callHook(
+ "aceCreateDomLine", {domline:domline, cls:cls}
+ ).map(function (modifier) {
+ cls = modifier.cls;
+ extraOpenTags = extraOpenTags+modifier.extraOpenTags;
+ extraCloseTags = modifier.extraCloseTags+extraCloseTags;
+ });
+
+ if ((! txt) && cls) {
+ lineClass = domline.addToLineClass(lineClass, cls);
+ }
+ else if (txt) {
+ if (href) {
+ extraOpenTags = extraOpenTags+'<a href="'+
+ href.replace(/\"/g, '&quot;')+'">';
+ extraCloseTags = '</a>'+extraCloseTags;
+ }
+ if (simpleTags) {
+ simpleTags.sort();
+ extraOpenTags = extraOpenTags+'<'+simpleTags.join('><')+'>';
+ simpleTags.reverse();
+ extraCloseTags = '</'+simpleTags.join('></')+'>'+extraCloseTags;
+ }
+ html.push('<span class="',cls||'','">',extraOpenTags,
+ perTextNodeProcess(domline.escapeHTML(txt)),
+ extraCloseTags,'</span>');
+ }
+ };
+ result.clearSpans = function() {
+ html = [];
+ lineClass = ''; // non-null to cause update
+ result.lineMarker = 0;
+ };
+ function writeHTML() {
+ var newHTML = perHtmlLineProcess(html.join(''));
+ if (! newHTML) {
+ if ((! document) || (! optBrowser)) {
+ newHTML += '&nbsp;';
+ }
+ else if (! browser.msie) {
+ newHTML += '<br/>';
+ }
+ }
+ if (nonEmpty) {
+ newHTML = (preHtml||'')+newHTML+(postHtml||'');
+ }
+ html = preHtml = postHtml = null; // free memory
+ if (newHTML !== curHTML) {
+ curHTML = newHTML;
+ result.node.innerHTML = curHTML;
+ }
+ if (lineClass !== null) result.node.className = lineClass;
+ }
+ result.prepareForAdd = writeHTML;
+ result.finishUpdate = writeHTML;
+ result.getInnerHTML = function() { return curHTML || ''; };
+
+ return result;
+};
+
+domline.escapeHTML = function(s) {
+ var re = /[&<>'"]/g; /']/; // stupid indentation thing
+ if (! re.MAP) {
+ // persisted across function calls!
+ re.MAP = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&#34;',
+ "'": '&#39;'
+ };
+ }
+ return s.replace(re, function(c) { return re.MAP[c]; });
+};
+
+domline.processSpaces = function(s, doesWrap) {
+ if (s.indexOf("<") < 0 && ! doesWrap) {
+ // short-cut
+ return s.replace(/ /g, '&nbsp;');
+ }
+ var parts = [];
+ s.replace(/<[^>]*>?| |[^ <]+/g, function(m) { parts.push(m); });
+ if (doesWrap) {
+ var endOfLine = true;
+ var beforeSpace = false;
+ // last space in a run is normal, others are nbsp,
+ // end of line is nbsp
+ for(var i=parts.length-1;i>=0;i--) {
+ var p = parts[i];
+ if (p == " ") {
+ if (endOfLine || beforeSpace)
+ parts[i] = '&nbsp;';
+ endOfLine = false;
+ beforeSpace = true;
+ }
+ else if (p.charAt(0) != "<") {
+ endOfLine = false;
+ beforeSpace = false;
+ }
+ }
+ // beginning of line is nbsp
+ for(var i=0;i<parts.length;i++) {
+ var p = parts[i];
+ if (p == " ") {
+ parts[i] = '&nbsp;';
+ break;
+ }
+ else if (p.charAt(0) != "<") {
+ break;
+ }
+ }
+ }
+ else {
+ for(var i=0;i<parts.length;i++) {
+ var p = parts[i];
+ if (p == " ") {
+ parts[i] = '&nbsp;';
+ }
+ }
+ }
+ return parts.join('');
+};
diff --git a/trunk/infrastructure/ace/www/easy_sync.js b/infrastructure/ace/www/easy_sync.js
index 86a4327..86a4327 100644
--- a/trunk/infrastructure/ace/www/easy_sync.js
+++ b/infrastructure/ace/www/easy_sync.js
diff --git a/trunk/infrastructure/ace/www/easysync2.js b/infrastructure/ace/www/easysync2.js
index efc5b99..efc5b99 100644
--- a/trunk/infrastructure/ace/www/easysync2.js
+++ b/infrastructure/ace/www/easysync2.js
diff --git a/trunk/infrastructure/ace/www/easysync2_tests.js b/infrastructure/ace/www/easysync2_tests.js
index 2fcf202..2fcf202 100644
--- a/trunk/infrastructure/ace/www/easysync2_tests.js
+++ b/infrastructure/ace/www/easysync2_tests.js
diff --git a/trunk/infrastructure/ace/www/editor.css b/infrastructure/ace/www/editor.css
index 9df127d..9df127d 100644
--- a/trunk/infrastructure/ace/www/editor.css
+++ b/infrastructure/ace/www/editor.css
diff --git a/trunk/infrastructure/ace/www/firebug/errorIcon.png b/infrastructure/ace/www/firebug/errorIcon.png
index 2d75261..2d75261 100644
--- a/trunk/infrastructure/ace/www/firebug/errorIcon.png
+++ b/infrastructure/ace/www/firebug/errorIcon.png
Binary files differ
diff --git a/trunk/infrastructure/ace/www/firebug/firebug.css b/infrastructure/ace/www/firebug/firebug.css
index 1f041c4..1f041c4 100644
--- a/trunk/infrastructure/ace/www/firebug/firebug.css
+++ b/infrastructure/ace/www/firebug/firebug.css
diff --git a/trunk/infrastructure/ace/www/firebug/firebug.html b/infrastructure/ace/www/firebug/firebug.html
index 861e639..861e639 100644
--- a/trunk/infrastructure/ace/www/firebug/firebug.html
+++ b/infrastructure/ace/www/firebug/firebug.html
diff --git a/trunk/infrastructure/ace/www/firebug/firebug.js b/infrastructure/ace/www/firebug/firebug.js
index d3c1978..d3c1978 100644
--- a/trunk/infrastructure/ace/www/firebug/firebug.js
+++ b/infrastructure/ace/www/firebug/firebug.js
diff --git a/trunk/infrastructure/ace/www/firebug/firebugx.js b/infrastructure/ace/www/firebug/firebugx.js
index b2cc49c..b2cc49c 100644
--- a/trunk/infrastructure/ace/www/firebug/firebugx.js
+++ b/infrastructure/ace/www/firebug/firebugx.js
diff --git a/trunk/infrastructure/ace/www/firebug/infoIcon.png b/infrastructure/ace/www/firebug/infoIcon.png
index da1e533..da1e533 100644
--- a/trunk/infrastructure/ace/www/firebug/infoIcon.png
+++ b/infrastructure/ace/www/firebug/infoIcon.png
Binary files differ
diff --git a/trunk/infrastructure/ace/www/firebug/warningIcon.png b/infrastructure/ace/www/firebug/warningIcon.png
index de51084..de51084 100644
--- a/trunk/infrastructure/ace/www/firebug/warningIcon.png
+++ b/infrastructure/ace/www/firebug/warningIcon.png
Binary files differ
diff --git a/trunk/infrastructure/ace/www/index.html b/infrastructure/ace/www/index.html
index a1e6e96..a1e6e96 100644
--- a/trunk/infrastructure/ace/www/index.html
+++ b/infrastructure/ace/www/index.html
diff --git a/trunk/infrastructure/ace/www/inner.css b/infrastructure/ace/www/inner.css
index 7479cfe..7479cfe 100644
--- a/trunk/infrastructure/ace/www/inner.css
+++ b/infrastructure/ace/www/inner.css
diff --git a/trunk/infrastructure/ace/www/jquery-1.2.1.js b/infrastructure/ace/www/jquery-1.2.1.js
index b4eb132..b4eb132 100644
--- a/trunk/infrastructure/ace/www/jquery-1.2.1.js
+++ b/infrastructure/ace/www/jquery-1.2.1.js
diff --git a/trunk/infrastructure/ace/www/lang_html.js b/infrastructure/ace/www/lang_html.js
index f9eff8e..f9eff8e 100644
--- a/trunk/infrastructure/ace/www/lang_html.js
+++ b/infrastructure/ace/www/lang_html.js
diff --git a/trunk/infrastructure/ace/www/lang_js.js b/infrastructure/ace/www/lang_js.js
index 4bbc5b4..4bbc5b4 100644
--- a/trunk/infrastructure/ace/www/lang_js.js
+++ b/infrastructure/ace/www/lang_js.js
diff --git a/trunk/infrastructure/ace/www/lexer_support.js b/infrastructure/ace/www/lexer_support.js
index 3d54f5c..3d54f5c 100644
--- a/trunk/infrastructure/ace/www/lexer_support.js
+++ b/infrastructure/ace/www/lexer_support.js
diff --git a/infrastructure/ace/www/linestylefilter.js b/infrastructure/ace/www/linestylefilter.js
new file mode 100644
index 0000000..f772ce3
--- /dev/null
+++ b/infrastructure/ace/www/linestylefilter.js
@@ -0,0 +1,287 @@
+// THIS FILE IS ALSO AN APPJET MODULE: etherpad.collab.ace.linestylefilter
+// %APPJET%: import("etherpad.collab.ace.easysync2.Changeset");
+// %APPJET%: import("etherpad.admin.plugins");
+
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+// requires: easysync2.Changeset
+// requires: top
+// requires: plugins
+// requires: undefined
+
+var linestylefilter = {};
+
+linestylefilter.ATTRIB_CLASSES = {
+ 'bold':'tag:b',
+ 'italic':'tag:i',
+ 'underline':'tag:u',
+ 'strikethrough':'tag:s',
+ 'h1':'tag:h1',
+ 'h2':'tag:h2',
+ 'h3':'tag:h3',
+ 'h4':'tag:h4',
+ 'h5':'tag:h5',
+ 'h6':'tag:h6'
+};
+
+linestylefilter.getAuthorClassName = function(author) {
+ return "author-"+author.replace(/[^a-y0-9]/g, function(c) {
+ if (c == ".") return "-";
+ return 'z'+c.charCodeAt(0)+'z';
+ });
+};
+
+// lineLength is without newline; aline includes newline,
+// but may be falsy if lineLength == 0
+linestylefilter.getLineStyleFilter = function(lineLength, aline,
+ textAndClassFunc, apool) {
+
+ if (lineLength == 0) return textAndClassFunc;
+
+ var nextAfterAuthorColors = textAndClassFunc;
+
+ var authorColorFunc = (function() {
+ var lineEnd = lineLength;
+ var curIndex = 0;
+ var extraClasses;
+ var leftInAuthor;
+
+ function attribsToClasses(attribs) {
+ var classes = '';
+ Changeset.eachAttribNumber(attribs, function(n) {
+ var key = apool.getAttribKey(n);
+ if (key) {
+ var value = apool.getAttribValue(n);
+ if (value) {
+ if (key == 'author') {
+ classes += ' '+linestylefilter.getAuthorClassName(value);
+ }
+ else if (key == 'list') {
+ classes += ' list:'+value;
+ }
+ else if (linestylefilter.ATTRIB_CLASSES[key]) {
+ classes += ' '+linestylefilter.ATTRIB_CLASSES[key];
+ }
+ }
+ }
+ });
+ return classes.substring(1);
+ }
+
+ var attributionIter = Changeset.opIterator(aline);
+ var nextOp, nextOpClasses;
+ function goNextOp() {
+ nextOp = attributionIter.next();
+ nextOpClasses = (nextOp.opcode && attribsToClasses(nextOp.attribs));
+ }
+ goNextOp();
+ function nextClasses() {
+ if (curIndex < lineEnd) {
+ extraClasses = nextOpClasses;
+ leftInAuthor = nextOp.chars;
+ goNextOp();
+ while (nextOp.opcode && nextOpClasses == extraClasses) {
+ leftInAuthor += nextOp.chars;
+ goNextOp();
+ }
+ }
+ }
+ nextClasses();
+
+ return function(txt, cls) {
+ while (txt.length > 0) {
+ if (leftInAuthor <= 0) {
+ // prevent infinite loop if something funny's going on
+ return nextAfterAuthorColors(txt, cls);
+ }
+ var spanSize = txt.length;
+ if (spanSize > leftInAuthor) {
+ spanSize = leftInAuthor;
+ }
+ var curTxt = txt.substring(0, spanSize);
+ txt = txt.substring(spanSize);
+ nextAfterAuthorColors(curTxt, (cls&&cls+" ")+extraClasses);
+ curIndex += spanSize;
+ leftInAuthor -= spanSize;
+ if (leftInAuthor == 0) {
+ nextClasses();
+ }
+ }
+ };
+ })();
+ return authorColorFunc;
+};
+
+linestylefilter.getAtSignSplitterFilter = function(lineText,
+ textAndClassFunc) {
+ var at = /@/g;
+ at.lastIndex = 0;
+ var splitPoints = null;
+ var execResult;
+ while ((execResult = at.exec(lineText))) {
+ if (! splitPoints) {
+ splitPoints = [];
+ }
+ splitPoints.push(execResult.index);
+ }
+
+ if (! splitPoints) return textAndClassFunc;
+
+ return linestylefilter.textAndClassFuncSplitter(textAndClassFunc,
+ splitPoints);
+};
+
+linestylefilter.getRegexpFilter = function (regExp, tag) {
+ return function (lineText, textAndClassFunc) {
+ regExp.lastIndex = 0;
+ var regExpMatchs = null;
+ var splitPoints = null;
+ var execResult;
+ while ((execResult = regExp.exec(lineText))) {
+ if (! regExpMatchs) {
+ regExpMatchs = [];
+ splitPoints = [];
+ }
+ var startIndex = execResult.index;
+ var regExpMatch = execResult[0];
+ regExpMatchs.push([startIndex, regExpMatch]);
+ splitPoints.push(startIndex, startIndex + regExpMatch.length);
+ }
+
+ if (! regExpMatchs) return textAndClassFunc;
+
+ function regExpMatchForIndex(idx) {
+ for(var k=0; k<regExpMatchs.length; k++) {
+ var u = regExpMatchs[k];
+ if (idx >= u[0] && idx < u[0]+u[1].length) {
+ return u[1];
+ }
+ }
+ return false;
+ }
+
+ var handleRegExpMatchsAfterSplit = (function() {
+ var curIndex = 0;
+ return function(txt, cls) {
+ var txtlen = txt.length;
+ var newCls = cls;
+ var regExpMatch = regExpMatchForIndex(curIndex);
+ if (regExpMatch) {
+ newCls += " "+tag+":"+regExpMatch;
+ }
+ textAndClassFunc(txt, newCls);
+ curIndex += txtlen;
+ };
+ })();
+
+ return linestylefilter.textAndClassFuncSplitter(handleRegExpMatchsAfterSplit,
+ splitPoints);
+ };
+};
+
+
+linestylefilter.REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/;
+linestylefilter.REGEX_URLCHAR = new RegExp('('+/[-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/.source+'|'+linestylefilter.REGEX_WORDCHAR.source+')');
+linestylefilter.REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:)/.source+linestylefilter.REGEX_URLCHAR.source+'*(?![:.,;])'+linestylefilter.REGEX_URLCHAR.source, 'g');
+linestylefilter.getURLFilter = linestylefilter.getRegexpFilter(
+ linestylefilter.REGEX_URL, 'url');
+
+linestylefilter.textAndClassFuncSplitter = function(func, splitPointsOpt) {
+ var nextPointIndex = 0;
+ var idx = 0;
+
+ // don't split at 0
+ while (splitPointsOpt &&
+ nextPointIndex < splitPointsOpt.length &&
+ splitPointsOpt[nextPointIndex] == 0) {
+ nextPointIndex++;
+ }
+
+ function spanHandler(txt, cls) {
+ if ((! splitPointsOpt) || nextPointIndex >= splitPointsOpt.length) {
+ func(txt, cls);
+ idx += txt.length;
+ }
+ else {
+ var splitPoints = splitPointsOpt;
+ var pointLocInSpan = splitPoints[nextPointIndex] - idx;
+ var txtlen = txt.length;
+ if (pointLocInSpan >= txtlen) {
+ func(txt, cls);
+ idx += txt.length;
+ if (pointLocInSpan == txtlen) {
+ nextPointIndex++;
+ }
+ }
+ else {
+ if (pointLocInSpan > 0) {
+ func(txt.substring(0, pointLocInSpan), cls);
+ idx += pointLocInSpan;
+ }
+ nextPointIndex++;
+ // recurse
+ spanHandler(txt.substring(pointLocInSpan), cls);
+ }
+ }
+ }
+ return spanHandler;
+};
+
+linestylefilter.getFilterStack = function(lineText, textAndClassFunc, browser) {
+ var func = linestylefilter.getURLFilter(lineText, textAndClassFunc);
+
+ var plugins_;
+ if (typeof(plugins)!='undefined') {
+ plugins_ = plugins;
+ } else {
+ plugins_ = parent.parent.plugins;
+ }
+
+ var hookFilters = plugins_.callHook(
+ "aceGetFilterStack", {linestylefilter:linestylefilter, browser:browser});
+ hookFilters.map(function (hookFilter) {
+ func = hookFilter(lineText, func);
+ });
+
+ if (browser !== undefined && browser.msie) {
+ // IE7+ will take an e-mail address like <foo@bar.com> and linkify it to foo@bar.com.
+ // We then normalize it back to text with no angle brackets. It's weird. So always
+ // break spans at an "at" sign.
+ func = linestylefilter.getAtSignSplitterFilter(
+ lineText, func);
+ }
+ return func;
+};
+
+// domLineObj is like that returned by domline.createDomLine
+linestylefilter.populateDomLine = function(textLine, aline, apool,
+ domLineObj) {
+ // remove final newline from text if any
+ var text = textLine;
+ if (text.slice(-1) == '\n') {
+ text = text.substring(0, text.length-1);
+ }
+
+ function textAndClassFunc(tokenText, tokenClass) {
+ domLineObj.appendSpan(tokenText, tokenClass);
+ }
+
+ var func = linestylefilter.getFilterStack(text, textAndClassFunc);
+ func = linestylefilter.getLineStyleFilter(text.length, aline,
+ func, apool);
+ func(text, '');
+};
diff --git a/trunk/infrastructure/ace/www/magicdom.js b/infrastructure/ace/www/magicdom.js
index 4bad3d4..4bad3d4 100644
--- a/trunk/infrastructure/ace/www/magicdom.js
+++ b/infrastructure/ace/www/magicdom.js
diff --git a/trunk/infrastructure/ace/www/multilang_lexer.js b/infrastructure/ace/www/multilang_lexer.js
index 9617981..9617981 100644
--- a/trunk/infrastructure/ace/www/multilang_lexer.js
+++ b/infrastructure/ace/www/multilang_lexer.js
diff --git a/trunk/infrastructure/ace/www/processing.js b/infrastructure/ace/www/processing.js
index 988ef76..988ef76 100644
--- a/trunk/infrastructure/ace/www/processing.js
+++ b/infrastructure/ace/www/processing.js
diff --git a/trunk/infrastructure/ace/www/profiler.js b/infrastructure/ace/www/profiler.js
index 24b68a2..24b68a2 100644
--- a/trunk/infrastructure/ace/www/profiler.js
+++ b/infrastructure/ace/www/profiler.js
diff --git a/trunk/infrastructure/ace/www/skiplist.js b/infrastructure/ace/www/skiplist.js
index e6c2e04..e6c2e04 100644
--- a/trunk/infrastructure/ace/www/skiplist.js
+++ b/infrastructure/ace/www/skiplist.js
diff --git a/trunk/infrastructure/ace/www/spanlist.js b/infrastructure/ace/www/spanlist.js
index 756a411..756a411 100644
--- a/trunk/infrastructure/ace/www/spanlist.js
+++ b/infrastructure/ace/www/spanlist.js
diff --git a/trunk/infrastructure/ace/www/syntax-new.css b/infrastructure/ace/www/syntax-new.css
index 30f1823..30f1823 100644
--- a/trunk/infrastructure/ace/www/syntax-new.css
+++ b/infrastructure/ace/www/syntax-new.css
diff --git a/trunk/infrastructure/ace/www/syntax.css b/infrastructure/ace/www/syntax.css
index e018320..e018320 100644
--- a/trunk/infrastructure/ace/www/syntax.css
+++ b/infrastructure/ace/www/syntax.css
diff --git a/trunk/infrastructure/ace/www/test.html b/infrastructure/ace/www/test.html
index 73fa45c..73fa45c 100644
--- a/trunk/infrastructure/ace/www/test.html
+++ b/infrastructure/ace/www/test.html
diff --git a/trunk/infrastructure/ace/www/testcode.js b/infrastructure/ace/www/testcode.js
index f393335..f393335 100644
--- a/trunk/infrastructure/ace/www/testcode.js
+++ b/infrastructure/ace/www/testcode.js
diff --git a/trunk/infrastructure/ace/www/toSource.js b/infrastructure/ace/www/toSource.js
index bf96df7..bf96df7 100644
--- a/trunk/infrastructure/ace/www/toSource.js
+++ b/infrastructure/ace/www/toSource.js
diff --git a/trunk/infrastructure/ace/www/undomodule.js b/infrastructure/ace/www/undomodule.js
index b8a56f9..b8a56f9 100644
--- a/trunk/infrastructure/ace/www/undomodule.js
+++ b/infrastructure/ace/www/undomodule.js
diff --git a/trunk/infrastructure/ace/www/virtual_lines.js b/infrastructure/ace/www/virtual_lines.js
index 86e3dea..86e3dea 100644
--- a/trunk/infrastructure/ace/www/virtual_lines.js
+++ b/infrastructure/ace/www/virtual_lines.js
diff --git a/trunk/infrastructure/bin/classpath.sh b/infrastructure/bin/classpath.sh
index b1d297c..b1d297c 100755
--- a/trunk/infrastructure/bin/classpath.sh
+++ b/infrastructure/bin/classpath.sh
diff --git a/trunk/infrastructure/bin/comp.sh b/infrastructure/bin/comp.sh
index 5f65c2f..5f65c2f 100755
--- a/trunk/infrastructure/bin/comp.sh
+++ b/infrastructure/bin/comp.sh
diff --git a/infrastructure/bin/compilecache.sh b/infrastructure/bin/compilecache.sh
new file mode 100755
index 0000000..6e42a50
--- /dev/null
+++ b/infrastructure/bin/compilecache.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS-IS" 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.
+
+CP_CMD="cp -R -u"
+if [ `uname` == "Darwin" ]; then
+ CP_CMD="/bin/cp -R -n"
+elif [ `uname` == "SunOS" ]; then
+ CP_CMD="cp -R" #Solaris cp does not have '-u'
+fi
+
+function cacheonfiles {
+ NAME=$1; FILES=$2; FUNC=$3; NOCOPY=1;
+ if [ -z "$4" ]; then
+ NOCOPY=0
+ fi
+ REBUILD=0
+ BPATH=buildcache/$NAME
+ FILETEST=$BPATH/t
+ if [ ! -f $FILETEST ]; then
+ REBUILD=1
+ else
+ for a in $FILES; do
+ if [ $FILETEST -ot $a ]; then
+ echo $a has changed, rebuilding $NAME
+ REBUILD=1
+ fi
+ done
+ fi
+ if [ $REBUILD -eq 1 ]; then
+ if [ -d $BPATH ]; then
+ rm -rf $BPATH
+ fi
+ mkdir -p $BPATH
+ $FUNC $BPATH
+ pushd $BPATH >> /dev/null
+ touch t
+ popd >> /dev/null
+ else
+ echo using cached $NAME...
+ fi
+ if [ $NOCOPY -ne 1 ]; then
+ for a in $BPATH/*; do
+ if [ -d $a ]; then
+ $CP_CMD $a build/
+ elif [ -f $a ]; then
+ cp $a build/
+ else
+ echo unknown file type $a
+ exit 1
+ fi
+ done
+ fi
+}
diff --git a/trunk/infrastructure/bin/jscomp.sh b/infrastructure/bin/jscomp.sh
index 3f5bc51..3f5bc51 100755
--- a/trunk/infrastructure/bin/jscomp.sh
+++ b/infrastructure/bin/jscomp.sh
diff --git a/infrastructure/bin/makejar.sh b/infrastructure/bin/makejar.sh
new file mode 100755
index 0000000..46b4609
--- /dev/null
+++ b/infrastructure/bin/makejar.sh
@@ -0,0 +1,74 @@
+#!/bin/bash -e
+
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS-IS" 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.
+
+if [ -z "$JAR" ]; then
+ JAR=jar
+else
+ echo "using JAR $JAR..."
+fi
+
+cp ${MYSQL_CONNECTOR_JAR} lib/
+
+source bin/compilecache.sh
+
+if [ "$1" == "clearcache" ]; then
+ echo "CLEARING BUILD CACHE"
+ rm -rf buildcache
+ shift;
+fi
+
+TMPSTORE=/tmp/ajbuild-tmpstore-`date +%s`
+
+JARFILES=`echo $SCALA_LIBRARY_JAR lib/*.jar lib/manifest`
+function genjar {
+ echo "unzipping JARs..."
+ pushd $1 >> /dev/null
+ $JAR xf $SCALA_LIBRARY_JAR
+ rm -rf META-INF
+ for a in ../../lib/*.jar; do
+ $JAR xf $a
+ rm -rf META-INF/{MANIFEST.MF,NOTICE{,.txt},LICENSE{,.txt},INDEX.LIST,SUN_MICR.{RSA,SF},maven}
+ done
+
+ echo "making cached JAR...."
+ $JAR -cfm appjet.jar ../../lib/manifest .
+ mv appjet.jar /tmp/appjet.jar
+ rm -rf *
+ mv /tmp/appjet.jar ./
+
+ popd >> /dev/null
+}
+cacheonfiles JAR "$JARFILES" genjar 1
+
+echo "compiling..."
+bin/comp.sh $@
+
+pushd build >> /dev/null
+
+echo "copying cached JAR..."
+cp ../buildcache/JAR/appjet.jar ./
+
+echo "making JAR..."
+mv appjet.jar /tmp/appjet.jar
+$JAR -uf /tmp/appjet.jar . #META-INF com javax org net uk v scala dojox
+mv /tmp/appjet.jar ./
+
+echo "cleaning up..."
+rm -rf $TMPSTORE
+
+popd >> /dev/null
+
+echo "done."
diff --git a/trunk/infrastructure/bin/makesars.sh b/infrastructure/bin/makesars.sh
index 541b04a..541b04a 100755
--- a/trunk/infrastructure/bin/makesars.sh
+++ b/infrastructure/bin/makesars.sh
diff --git a/trunk/infrastructure/bin/run.sh b/infrastructure/bin/run.sh
index cf918d4..cf918d4 100755
--- a/trunk/infrastructure/bin/run.sh
+++ b/infrastructure/bin/run.sh
diff --git a/infrastructure/com.etherpad.openofficeservice/importexport.scala b/infrastructure/com.etherpad.openofficeservice/importexport.scala
new file mode 100644
index 0000000..606cff9
--- /dev/null
+++ b/infrastructure/com.etherpad.openofficeservice/importexport.scala
@@ -0,0 +1,287 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+package com.etherpad.openofficeservice;
+
+import net.appjet.common.sars.{SarsServer,SarsMessageHandler};
+
+import java.io.{DataInputStream,DataOutputStream};
+import java.io.{File,FileOutputStream,ByteArrayInputStream,ByteArrayOutputStream};
+
+/* Libraries needed for OO.org Conversion */
+import com.sun.star.bridge.{XBridge,XBridgeFactory};
+import com.sun.star.beans.{PropertyValue,XPropertySet};
+import com.sun.star.connection.{NoConnectException,XConnection,XConnector};
+import com.sun.star.container.XNamed;
+import com.sun.star.document.{XExporter,XFilter};
+import com.sun.star.frame.{XComponentLoader,XStorable};
+import com.sun.star.lang.{XComponent,XMultiComponentFactory};
+import com.sun.star.uno.{UnoRuntime,XComponentContext};
+
+class OOSException(m: String) extends RuntimeException(m);
+class UnsupportedFormatException(format: String) extends OOSException("Unsupported format: "+format);
+object TemporaryFailure extends OOSException("Temporary failure");
+
+object OpenOfficeServerUtility {
+ def checkServerAvailability(host: String, port: Int): Boolean = {
+ // Assume the server is running; this is the responsibility of the user
+ return true;
+ }
+ def runOpenOfficeServer(path: String, host: String, port: Int, timeout: Int, wait: Boolean) {
+ // nothing
+ }
+}
+
+class OpenOfficeFileConverter {
+ var host: String = "localhost";
+ var port: Int = 8100;
+
+ def setOpenOfficeServerDetails(host: String, port: Int) {
+ this.host = host;
+ this.port = port;
+ }
+
+ def convertFile(src: File, dst: File, converter: String, extension: String): Boolean = {
+ try {
+ val fromFile: String = "file:///" + src.getAbsolutePath();
+ val toFile: String = "file:///" + dst.getAbsolutePath();
+
+ val cnx: String = "socket,host="+this.host+",port="+this.port+"";
+ val xRemoteContext: XComponentContext = com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null);
+ val x: Object = xRemoteContext.getServiceManager().createInstanceWithContext("com.sun.star.connection.Connector", xRemoteContext);
+ val xConnector: XConnector = UnoRuntime.queryInterface(classOf[XConnector], x).asInstanceOf[XConnector];
+ val connection: XConnection = xConnector.connect(cnx);
+
+ if(connection == null) {
+ throw new OOSException("Connection failure");
+ }
+ val x2: Object = xRemoteContext.getServiceManager().createInstanceWithContext("com.sun.star.bridge.BridgeFactory", xRemoteContext);
+ val xBridgeFactory: XBridgeFactory = UnoRuntime.queryInterface(classOf[XBridgeFactory], x2).asInstanceOf[XBridgeFactory];
+ val xBridge: XBridge = xBridgeFactory.createBridge("", "urp", connection, null);
+ val x3: Object = xBridge.getInstance("StarOffice.ServiceManager");
+ if (x3 == null) {
+ throw new OOSException("Failed to get bridge");
+ }
+
+ val xMultiComponentFactory: XMultiComponentFactory = UnoRuntime.queryInterface(classOf[XMultiComponentFactory], x3).asInstanceOf[XMultiComponentFactory];
+ val xProperySet: XPropertySet = UnoRuntime.queryInterface(classOf[XPropertySet], xMultiComponentFactory).asInstanceOf[XPropertySet];
+ val oDefaultContext: Object = xProperySet.getPropertyValue("DefaultContext");
+ val xComponentContext: XComponentContext = UnoRuntime.queryInterface(classOf[XComponentContext], oDefaultContext).asInstanceOf[XComponentContext];
+
+ val desktopObj: Object = xMultiComponentFactory.createInstanceWithContext("com.sun.star.frame.Desktop", xComponentContext);
+ val xcomponentloader: XComponentLoader = UnoRuntime.queryInterface(classOf[XComponentLoader], desktopObj).asInstanceOf[XComponentLoader];
+
+ if(xcomponentloader == null) {
+ throw new OOSException("XComponent Loader could not be loaded");
+ }
+
+ val loadProps: Array[PropertyValue] = new Array[PropertyValue](2);
+ loadProps(0) = new PropertyValue();
+ loadProps(0).Name = "Hidden";
+ loadProps(0).Value = boolean2Boolean(false);
+
+ loadProps(1) = new PropertyValue();
+ loadProps(1).Name = "UpdateDocMode";
+ loadProps(1).Value = "1";
+
+ val component: XComponent = xcomponentloader.loadComponentFromURL(fromFile,"_blank", 0, loadProps);
+
+ if (component == null) {
+ throw new OOSException("Failed to load document");
+ }
+
+ val convProps: Array[PropertyValue] = new Array[PropertyValue](2);
+ convProps(0) = new PropertyValue();
+ convProps(0).Name = "FilterName";
+ convProps(0).Value = converter;
+
+ val xstorable: XStorable = UnoRuntime.queryInterface(classOf[XStorable],component).asInstanceOf[XStorable];
+ if (xstorable == null) {
+ throw new OOSException("Storable could not be loaded");
+ }
+ xstorable.storeToURL(toFile, convProps);
+ component.dispose();
+ return true;
+ }
+ catch {
+ case e => {
+ e.printStackTrace();
+ throw new OOSException("Unknown exception occurred: "+e.getMessage());
+ }
+ }
+ }
+}
+
+object OpenOfficeService {
+ val formats = Map(
+ "pdf" -> "writer_pdf_Export",
+ "doc" -> "MS Word 97",
+ "html" -> "HTML (StarWriter)",
+ "odt" -> "writer8",
+ //"html" -> "XHTML Writer File",
+ "txt" -> "Text"
+ );
+
+ def createTempFile(bytes: Array[byte], suffix: String) = {
+ var f = File.createTempFile("ooconvert-", if (suffix == null) { null } else if (suffix == "") { "" } else { "."+suffix });
+ if (bytes != null) {
+ val fos = new FileOutputStream(f);
+ fos.write(bytes);
+ }
+ f;
+ }
+
+ var soffice = "soffice";
+ def setExecutable(exec: String) {
+ soffice = exec;
+ }
+
+ var openOfficeServerHost: String = "localhost";
+ var openOfficeServerPort: Int = 8100;
+
+ def setOpenOfficeServer(host: String, port: Int) {
+ openOfficeServerHost = host;
+ openOfficeServerPort = port;
+ }
+
+ def convertFile(from: String, to: String, bytes: Array[byte]): Array[byte] = {
+ if (from == to) {
+ return bytes;
+ }
+
+ val tempFile = createTempFile(bytes, from);
+ val outFile = createTempFile(null, to);
+
+ /*
+ Just hardcoding server and port here.
+ If you intend to use an Openoffice.org instance on a network machine,
+ do it at your risk.
+
+ Just, remember to setOpenOfficeServer from etherpad/importexport/importexport.js,
+ Also, remember that OO.org is reading and writing files over file:/// URI. So, make sure that
+ you can access the files from network machine. Hint, NFS. Not Need for Speed game, you idiot,
+ Network File System.
+
+ */
+
+ if (! OpenOfficeServerUtility.checkServerAvailability(openOfficeServerHost, openOfficeServerPort)) {
+ try {
+ OpenOfficeServerUtility.runOpenOfficeServer(soffice, openOfficeServerHost, openOfficeServerPort, 20000, true);
+ } catch {
+ case e: java.io.IOException => {
+ e.printStackTrace();
+ throw TemporaryFailure;
+ }
+ }
+ }
+ var converter = new OpenOfficeFileConverter();
+ converter.setOpenOfficeServerDetails(openOfficeServerHost, openOfficeServerPort);
+ var status = false;
+ try {
+ status = converter.convertFile(tempFile, outFile, formats(to), to);
+ } catch {
+ case e => {
+ e.printStackTrace();
+ throw new OOSException("Unknown exception occurred: "+e.getMessage());
+ }
+ }
+ if (status == false) {
+ throw new UnsupportedFormatException(from);
+ }
+ net.appjet.common.util.BetterFile.getFileBytes(outFile);
+ }
+
+ def main(args: Array[String]) {
+ if (args.length > 0) {
+ soffice = args(0);
+ if (soffice.length == 0) {
+ exit(1);
+ }
+ }
+
+ // Query format:
+ // from: String, to: String, count: Int, bytes: Array[byte]
+ // Response format:
+ // status: Int, <data>
+ // status 0 (success) - <data>: count: Int, bytes: Array[byte]
+ // status 1 (temporary failure) - <data>: <none>
+ // status 2 (permanent failure) - <data>: type: Int
+ // type - 0: unknown failure.
+ // - 1: unsupported format
+ val handler = new SarsMessageHandler {
+ override def handle(b: Array[byte]): Option[Array[byte]] = {
+ val is = new DataInputStream(new ByteArrayInputStream(b));
+ val from = is.readUTF;
+ val to = is.readUTF;
+ val len = is.readInt;
+ val bytes = new Array[byte](len);
+ is.readFully(bytes);
+ var status = 0;
+ var permfailuretype = 0;
+
+ println("Converting "+from+" -> "+to+" ("+len+" bytes)");
+
+ val output = try {
+ convertFile(from, to, bytes);
+ } catch {
+ case TemporaryFailure => {
+ status = 1;
+ null;
+ }
+ case e: UnsupportedFormatException => {
+ status = 2;
+ permfailuretype = 1;
+ null;
+ }
+ case e => {
+ status = 2;
+ permfailuretype = 0;
+ e.printStackTrace();
+ null;
+ }
+ }
+
+ val retBytes = new ByteArrayOutputStream();
+ val ret = new DataOutputStream(retBytes);
+ if (status != 0) {
+ ret.writeInt(status); // error
+ status match {
+ case 2 => {
+ ret.writeInt(permfailuretype);
+ }
+ case _ => { }
+ }
+ } else {
+ ret.writeInt(0); // success
+ ret.writeInt(output.length);
+ ret.write(output, 0, output.length);
+ }
+ Some(retBytes.toByteArray());
+ }
+ }
+
+ val server = new SarsServer("ooffice-password", handler, None, 8101);
+ server.start();
+ println("Server running...");
+ server.join();
+ println("Server quitting...");
+ }
+}
+
+
+
+
+
diff --git a/trunk/infrastructure/com.etherpad/easysync2support.scala b/infrastructure/com.etherpad/easysync2support.scala
index 9f1c527..9f1c527 100644
--- a/trunk/infrastructure/com.etherpad/easysync2support.scala
+++ b/infrastructure/com.etherpad/easysync2support.scala
diff --git a/infrastructure/com.etherpad/licensing.scala b/infrastructure/com.etherpad/licensing.scala
new file mode 100644
index 0000000..68019f5
--- /dev/null
+++ b/infrastructure/com.etherpad/licensing.scala
@@ -0,0 +1,169 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+package com.etherpad;
+
+import net.appjet.oui.{Encryptomatic, config};
+import net.appjet.common.util.BetterFile;
+
+import java.io.{FileInputStream, FileOutputStream, ByteArrayInputStream, ByteArrayOutputStream, PrintWriter}
+
+import java.security._;
+import java.security.spec._;
+
+object Licensing {
+ val publicKey = "s0dD94jKFjlSHIumgDQ4ldcyIyna1vMHmG5tsgkP987eBTW88XeEIUTo5JtWOjPzb252GURUrr7MReTqMz6NnsOupeJMqtXgjuVxcXbK8AnckxkxhRqMiFfBW39T9NzPgq09yBdH4tKGlPZQmgaBvjFI8cXTYa7a64LrDnrzrpDhDdJsZPZI2kE7G4vBCGijuhsZpyowK8zT5y2cKqIgIdLxUnXNFtayDi0oyuX1ywfBds2OEil9fEUQOQvkcHAt6kYfPXkE2XgQZFasAv0DPeWMUEtaHTbMaQn1U6BsfmsKjHlLhM3oWEzp0wEwUWxCC39iHYjxa5QKtxm5BNvUTTqJgkoEvk7Uu08j8jhFeCFosph6igDWPmyfAPKTnETXJobO2VON83bVHlX8UfKonnalMy0Hnw2C0I7c0UE0MtMIRtJxtwU62a311Ohp1EVrY4LwKIFfqRMVWKDP0cjXDkJyjJS58rC1DRU7SfPspgfuOy5YZo9sLKztXfzAPzNbXerQ24m2AjmYLV4JQked7MnaKQ6VfyZbFBK5th9NFcJwY1bGbIHW2EsKmiKUoNjPKRJ6VMC7odUCIXQyE9J";
+
+ val pkhash = "f7a3dd5940a3f79904b81e4d32a08e2efaa0b2ab";
+ val keyVersion = 2.toByte;
+
+ def thanksForStealingFromPoorHackersTryingToEkeAMeagerLivingFromThisCruelWorld =
+ Encryptomatic.bytesToAscii(MessageDigest.getInstance("SHA1").digest(publicKey.getBytes())) == pkhash;
+ def sha1(b: Array[Byte]): String = Encryptomatic.bytesToAscii(MessageDigest.getInstance("SHA1").digest(b));
+ def sha1(s: String): String = sha1(s.getBytes("UTF-8"));
+
+ def toBytes(i: Int): Array[Byte] =
+ Array((i >> 24).toByte,
+ (i >> 16).toByte,
+ (i >> 8).toByte,
+ i.toByte);
+ def toByte(i: Int): Array[Byte] =
+ Array(i.toByte);
+ def toBytes(l: Long): Array[Byte] =
+ Array((l >> 56).toByte,
+ (l >> 48).toByte,
+ (l >> 40).toByte,
+ (l >> 32).toByte,
+ (l >> 24).toByte,
+ (l >> 16).toByte,
+ (l >> 8).toByte,
+ l.toByte);
+
+ def toInt(b0: Array[Byte]): Int = {
+ val b = b0.map(_.toInt & 0x00FF);
+ (b(0) << 24) | (b(1) << 16) | (b(2) << 8) | b(3);
+ }
+ def toInt(b: Byte): Int = b.toInt & 0x00FF;
+
+ def toLong(b0: Array[Byte]): Long = {
+ val b = b0.map(_.toLong & 0x000000FF);
+ (b(0) << 56) | (b(1) << 48) | (b(2) << 40) | (b(3) << 32) | (b(4) << 24) | (b(5) << 16) | (b(6) << 8) | b(7);
+ }
+
+ def generateKey(personName: String, organizationName: String, expiresDate: Long, editionId: Int, userQuota: Int, majorVersion: Int, minorVersion: Int, patchVersion: Int) = {
+ if (config.licenseGeneratorKey == null) {
+ throw new RuntimeException("No private key available to generate license key.");
+ }
+ def privateKey = Encryptomatic.readPrivateKey("DSA", new FileInputStream(config.licenseGeneratorKey));
+ def clean(s: String) = s.replaceAll(":", "-");
+ val keyPrefix =
+ List(personName, organizationName, expiresDate.toString, editionId.toString, userQuota.toString, majorVersion.toString, minorVersion.toString, patchVersion.toString).map(clean).mkString(":");
+ val sig = Encryptomatic.sign(new ByteArrayInputStream(keyPrefix.getBytes("UTF-8")), privateKey)
+
+ List(personName, organizationName).mkString(":") + ":" +
+ Encryptomatic.bytesToAscii(
+ Array.concat[Byte](Array(keyVersion), // don't want BigInt dropping bytes, that'd be sad. :(
+ toBytes(expiresDate),
+ toBytes(editionId),
+ toBytes(userQuota),
+ toByte(majorVersion),
+ toByte(minorVersion),
+ toByte(patchVersion),
+ sig));
+ }
+
+ def decodeKey(key: String) = try {
+ val Array(personName0, organizationName0, sigAndInfo) = key.split(":");
+ val sigAndInfoBytes = Encryptomatic.asciiToBytes(sigAndInfo);
+ val thisKeyVersion = toInt(sigAndInfoBytes(0));
+ val expiresDate0 = toLong(sigAndInfoBytes.slice(1, 9));
+ val editionId0 = toInt(sigAndInfoBytes.slice(9, 13));
+ val userQuota0 = toInt(sigAndInfoBytes.slice(13, 17));
+ val (majorVersion0, minorVersion0, patchVersion0) =
+ if (thisKeyVersion >= 2) {
+ (toInt(sigAndInfoBytes(17)), toInt(sigAndInfoBytes(18)), toInt(sigAndInfoBytes(19)));
+ } else {
+ (0, 0, 0);
+ }
+ val sig = sigAndInfoBytes.drop(if (thisKeyVersion >= 2) 20 else 17);
+ val keyPrefix = {
+ var a = Seq(personName0, organizationName0, expiresDate0.toString, editionId0.toString, userQuota0.toString);
+ if (thisKeyVersion >= 2) {
+ a = a ++ Seq(majorVersion0.toString, minorVersion0.toString, patchVersion0.toString);
+ }
+ a.mkString(":");
+ }
+ if (! Encryptomatic.verify(new ByteArrayInputStream(keyPrefix.getBytes("UTF-8")),
+ Encryptomatic.readPublicKey("DSA",
+ new ByteArrayInputStream(publicKey.getBytes())), sig)) {
+ null;
+ } else {
+ new {
+ def personName = personName0;
+ def organizationName = organizationName0;
+ def expiresDate = expiresDate0;
+ def editionId = editionId0;
+ def userQuota = userQuota0;
+ def majorVersion = majorVersion0;
+ def minorVersion = minorVersion0;
+ def patchVersion = patchVersion0;
+ }
+ }
+ } catch {
+ case e => null;
+ }
+
+ def main(args: Array[String]) {
+ args(0) match {
+ case "genkeypair" => {
+ println("Generating keypair...");
+ Encryptomatic.writeKeyPair(Encryptomatic.generateKeyPair("DSA"), args(1), args(2));
+ println("Done.");
+ }
+ case "genmainkey" => {
+ println("Generating main key...");
+ config.values("licenseGeneratorKey") = args(1);
+ val out = new PrintWriter(new FileOutputStream(args(2)));
+ out.print(generateKey("etherpad", "AppJet", -1, 0, -1, 0, 0, 0))
+ out.close();
+ println("Done.");
+ }
+ case "test" => {
+ println("Testing key generation.");
+ config.values("licenseGeneratorKey") = args(1);
+ val key = generateKey("Foo Bar", "Baz, Inc.", System.currentTimeMillis() + 86400*1000, 0, 100, 1, 2, 3);
+ println("Key is: "+key);
+ val obj = decodeKey(key);
+ println(List(obj.personName, obj.organizationName, obj.expiresDate, obj.editionId, obj.userQuota, obj.majorVersion, obj.minorVersion, obj.patchVersion).mkString(", "));
+ }
+ case "parsekey" => {
+ println("Testing key decode.");
+ val obj = decodeKey(args(1));
+ println("Key: "+List(obj.personName, obj.organizationName, obj.expiresDate, obj.editionId, obj.userQuota, obj.majorVersion, obj.minorVersion, obj.patchVersion).mkString(", "));
+ }
+ case "testascii" => {
+ val one = 17;
+ val two = -1L;
+ val three = (Math.random*Math.pow(10, (Math.random*10).toInt)).toInt;
+ println(List(one, two, three).mkString(", "));
+ println(List(toInt(toBytes(one)), toLong(toBytes(two)), toInt(toBytes(three))).mkString(", "));
+ val bytes = Encryptomatic.asciiToBytes(Encryptomatic.bytesToAscii(Array.concat[Byte](Array(1.toByte), toBytes(one), toBytes(two), toBytes(three))));
+ println("I can has bytes: "+bytes.length);
+ println(List(toInt(bytes.slice(1, 5)), toLong(bytes.slice(5, 13)), toInt(bytes.slice(13, 17))).mkString(", "));
+ }
+ }
+ }
+}
diff --git a/trunk/infrastructure/com.etherpad/main.scala b/infrastructure/com.etherpad/main.scala
index 5110aba..5110aba 100644
--- a/trunk/infrastructure/com.etherpad/main.scala
+++ b/infrastructure/com.etherpad/main.scala
diff --git a/trunk/infrastructure/framework-src/modules/atomfeed.js b/infrastructure/framework-src/modules/atomfeed.js
index 4b86eeb..4b86eeb 100644
--- a/trunk/infrastructure/framework-src/modules/atomfeed.js
+++ b/infrastructure/framework-src/modules/atomfeed.js
diff --git a/trunk/infrastructure/framework-src/modules/blob.js b/infrastructure/framework-src/modules/blob.js
index af788a0..af788a0 100644
--- a/trunk/infrastructure/framework-src/modules/blob.js
+++ b/infrastructure/framework-src/modules/blob.js
diff --git a/trunk/infrastructure/framework-src/modules/cache_utils.js b/infrastructure/framework-src/modules/cache_utils.js
index f2a360c..f2a360c 100644
--- a/trunk/infrastructure/framework-src/modules/cache_utils.js
+++ b/infrastructure/framework-src/modules/cache_utils.js
diff --git a/trunk/infrastructure/framework-src/modules/comet.js b/infrastructure/framework-src/modules/comet.js
index 2331f8b..2331f8b 100644
--- a/trunk/infrastructure/framework-src/modules/comet.js
+++ b/infrastructure/framework-src/modules/comet.js
diff --git a/trunk/infrastructure/framework-src/modules/dateutils.js b/infrastructure/framework-src/modules/dateutils.js
index 72e87c8..72e87c8 100644
--- a/trunk/infrastructure/framework-src/modules/dateutils.js
+++ b/infrastructure/framework-src/modules/dateutils.js
diff --git a/trunk/infrastructure/framework-src/modules/dispatch.js b/infrastructure/framework-src/modules/dispatch.js
index e7e3ef0..e7e3ef0 100644
--- a/trunk/infrastructure/framework-src/modules/dispatch.js
+++ b/infrastructure/framework-src/modules/dispatch.js
diff --git a/infrastructure/framework-src/modules/ejs.js b/infrastructure/framework-src/modules/ejs.js
new file mode 100644
index 0000000..58c67bc
--- /dev/null
+++ b/infrastructure/framework-src/modules/ejs.js
@@ -0,0 +1,477 @@
+/*--------------------------------------------------------------------------
+ * EJS - Embedded JavaScript, version 0.1.0
+ * Copyright (c) 2007 Edward Benson
+ * http://www.edwardbenson.com/projects/ejs
+ * ------------------------------------------------------------------------
+ *
+ * EJS is freely distributable under the terms of an MIT-style license.
+ *
+ * EJS is a client-side preprocessing engine written in and for JavaScript.
+ * If you have used PHP, ASP, JSP, or ERB then you get the idea: code embedded
+ * in <% // Code here %> tags will be executed, and code embedded in <%= .. %>
+ * tags will be evaluated and appended to the output.
+ *
+ * This is essentially a direct JavaScript port of Masatoshi Seki's erb.rb
+ * from the Ruby Core, though it contains a subset of ERB's functionality.
+ *
+ * Requirements:
+ * prototype.js
+ *
+ * Usage:
+ * // source should be either a string or a DOM node whose innerHTML
+ * // contains EJB source.
+ * var source = "<% var ejb="EJB"; %><h1>Hello, <%= ejb %>!</h1>";
+ * var compiler = new EjsCompiler(source);
+ * compiler.compile();
+ * var output = eval(compiler.out);
+ * alert(output); // -> "<h1>Hello, EJB!</h1>"
+ *
+ * For a demo: see demo.html
+ * For the license: see license.txt
+ *
+ *--------------------------------------------------------------------------*/
+
+import("jsutils.*");
+import("funhtml");
+import("etherpad.log");
+
+jimport("java.lang.System.out.println");
+jimport("net.appjet.ajstdlib.execution.executeCodeInNewScope");
+
+/* Make a split function like Ruby's: "abc".split(/b/) -> ['a', 'b', 'c'] */
+function rsplit(x, regex) {
+ var item = x;
+ var result = regex.exec(item);
+ var retArr = new Array();
+ while (result != null)
+ {
+ var first_idx = result.index;
+ var last_idx = regex.lastIndex;
+ if ((first_idx) != 0)
+ {
+ var first_bit = item.substring(0,first_idx);
+ retArr.push(item.substring(0,first_idx));
+ item = item.slice(first_idx);
+ }
+ retArr.push(result[0]);
+ item = item.slice(result[0].length);
+ result = regex.exec(item);
+ }
+ if (! item == '')
+ {
+ retArr.push(item);
+ }
+ return retArr;
+};
+
+/* Chop is nice to have too */
+function chop(x) {
+ return x.substr(0, x.length - 1);
+}
+
+/* Adaptation from the Scanner of erb.rb */
+var EjsScanner = function(source, left, right) {
+ this.left_delimiter = left +'%'; //<%
+ this.right_delimiter = '%'+right; //>
+ this.double_left = left+'%%';
+ this.double_right = '%%'+right;
+ this.left_equal = left+'%=';
+ this.left_colon = left+'%:';
+ this.left_comment = left+'%#';
+ if(left=='[') {
+ this.SplitRegexp = /(\[%%)|(%%\])|(\[%:)|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/;
+ }
+ else {
+ this.SplitRegexp = new RegExp('('+this.double_left+')|(%%'+this.double_right+')|('+this.left_equal+')|('+this.left_colon+')|('+this.left_equal+')|('+this.left_comment+')|('+this.left_delimiter+')|('+this.right_delimiter+'\n)|('+this.right_delimiter+')|(\n)')
+ }
+
+ this.source = source;
+ this.stag = null;
+ this.lines = 0;
+};
+EjsView = function(data) {
+ this.data = data;
+};
+EjsView.prototype.partial = function(options, data){
+ if(!data) data = this.data;
+ return new EJS(options).render(data);
+};
+
+EjsScanner.to_text = function(input){
+ if(input == null || input === undefined)
+ return '';
+ if(input instanceof Date)
+ return input.toDateString();
+ if(input.toString)
+ return input.toString();
+ return '';
+}
+
+EjsScanner.prototype = {
+
+ /* For each line, scan! */
+ scan: function(block) {
+ scanline = this.scanline;
+ regex = this.SplitRegexp;
+ if (! this.source == '')
+ {
+ var source_split = rsplit(this.source, /\n/);
+ for(var i=0; i<source_split.length; i++) {
+ var item = source_split[i];
+ this.scanline(item, regex, block);
+ }
+ }
+ },
+
+ /* For each token, block! */
+ scanline: function(line, regex, block) {
+ this.lines++;
+ var line_split = rsplit(line, regex);
+ for(var i=0; i<line_split.length; i++) {
+ var token = line_split[i];
+ if (token != null) {
+ try{
+ block(token, this);
+ }catch(e){
+ throw {type: 'EjsScanner', line: this.lines};
+ }
+ }
+ }
+ }
+};
+
+/* Adaptation from the Buffer of erb.rb */
+var EjsBuffer = function(pre_cmd, post_cmd) {
+ this.line = new Array();
+ this.script = "";
+ this.pre_cmd = pre_cmd;
+ this.post_cmd = post_cmd;
+
+ for (var i=0; i<this.pre_cmd.length; i++)
+ {
+ this.push(pre_cmd[i]);
+ }
+}
+EjsBuffer.prototype = {
+
+ push: function(cmd) {
+ this.line.push(cmd);
+ },
+
+ cr: function() {
+ this.script = this.script + this.line.join('; ');
+ this.line = new Array();
+ this.script = this.script + "\n";
+ },
+
+ close: function() {
+ if (this.line.length > 0)
+ {
+ for (var i=0; i<this.post_cmd.length; i++)
+ {
+ this.push(pre_cmd[i]);
+ }
+ this.script = this.script + this.line.join('; ');
+ line = null;
+ }
+ }
+
+};
+
+/* Adaptation from the Compiler of erb.rb */
+EjsCompiler = function(source, left) {
+ this.pre_cmd = ['var ejs_data = "";'];
+ this.post_cmd = new Array();
+ this.source = ' ';
+ if (source != null)
+ {
+ if (typeof source == 'string')
+ {
+ source = source.replace(/\r\n/g, "\n");
+ source = source.replace(/\r/g, "\n");
+ this.source = source;
+ }
+ else if (source.innerHTML)
+ {
+ this.source = source.innerHTML;
+ }
+ if (typeof this.source != 'string')
+ {
+ this.source = "";
+ }
+ }
+ left = left || '<'
+ var right = '>'
+ switch(left) {
+ case '[':
+ right = ']'
+ break;
+ case '<':
+ break;
+ default:
+ throw left+' is not a supported deliminator'
+ break;
+ }
+ this.scanner = new EjsScanner(this.source, left, right);
+ this.out = '';
+}
+EjsCompiler.prototype = {
+ compile: function(options) {
+ options = options || {};
+ this.out = '';
+ var put_cmd = "ejs_data += ";
+ var insert_cmd = put_cmd;
+ var buff = new EjsBuffer(this.pre_cmd, this.post_cmd);
+ var content = '';
+ var clean = function(content)
+ {
+ content = content.replace(/\\/g, '\\\\');
+ content = content.replace(/\n/g, '\\n');
+ content = content.replace(/\"/g, '\\"');
+ return content;
+ };
+ this.scanner.scan(function(token, scanner) {
+ if (scanner.stag == null)
+ {
+ //alert(token+'|'+(token == "\n"))
+ switch(token) {
+ case '\n':
+ content = content + "\n";
+ buff.push(put_cmd + '"' + clean(content) + '";');
+ buff.cr();
+ content = '';
+ break;
+ case scanner.left_delimiter:
+ case scanner.left_equal:
+ case scanner.left_colon:
+ case scanner.left_comment:
+ scanner.stag = token;
+ if (content.length > 0)
+ {
+ // Chould be content.dump in Ruby
+
+ buff.push(put_cmd + '"' + clean(content) + '"');
+ }
+ content = '';
+ break;
+ case scanner.double_left:
+ content = content + scanner.left_delimiter;
+ break;
+ default:
+ content = content + token;
+ break;
+ }
+ }
+ else {
+ switch(token) {
+ case scanner.right_delimiter:
+ switch(scanner.stag) {
+ case scanner.left_delimiter:
+ if (content[content.length - 1] == '\n')
+ {
+ content = chop(content);
+ buff.push(content);
+ buff.cr();
+ }
+ else {
+ buff.push(content);
+ }
+ break;
+ case scanner.left_equal:
+ buff.push(insert_cmd + "(EjsScanner.to_text(" + content + "))");
+ break;
+ case scanner.left_colon:
+ buff.push(insert_cmd + content);
+ break;
+ }
+ scanner.stag = null;
+ content = '';
+ break;
+ case scanner.double_right:
+ content = content + scanner.right_delimiter;
+ break;
+ default:
+ content = content + token;
+ break;
+ }
+ }
+ });
+ if (content.length > 0)
+ {
+ // Chould be content.dump in Ruby
+ buff.push(put_cmd + '"' + clean(content) + '"');
+ }
+ buff.close();
+ this.out = buff.script + ";";
+ var to_be_evaled = [
+ 'var process = function(_CONTEXT,_VIEW) {',
+ ' with(_VIEW) {',
+ ' with (_CONTEXT) {',
+ this.out,
+ ' return ejs_data;',
+ ' }',
+ ' }',
+ '};'
+ ].join('');
+ // make funhtml.* available in parent scope.
+ var parentScope = {};
+ parentScope.EjsScanner = EjsScanner;
+ keys(funhtml).forEach(function(k) {
+ parentScope[k] = funhtml[k];
+ });
+ var ret = executeCodeInNewScope(
+ parentScope,
+ to_be_evaled,
+ (options.name || "template"),
+ 1
+ );
+ this.process = ret.process;
+ }
+}
+
+
+//type, cache, folder
+EJS = function( options ){
+ this.set_options(options);
+
+ if(options.url){
+ var template = EJS.get(options.url, this.cache);
+ if (template) return template;
+ if (template == EJS.INVALID_PATH) return null;
+ this.text = EJS.request(options.url);
+ if(this.text == null){
+ //EJS.update(options.url, this.INVALID_PATH);
+ throw 'There is no template at '+options.url;
+ }
+ this.name = options.url;
+ }else if(options.element)
+ {
+ if(typeof options.element == 'string'){
+ var name = options.element;
+ options.element = document.getElementById( options.element );
+ if(options.element == null) throw name+'does not exist!';
+ }
+ if(options.element.value){
+ this.text = options.element.value;
+ }else{
+ this.text = options.element.innerHTML;
+ }
+ this.name = options.element.id;
+ this.type = '[';
+ }
+ var template = new EjsCompiler(this.text, this.type);
+
+ template.compile(options);
+
+
+ EJS.update(this.name, this);
+ this.template = template;
+};
+EJS.config = function(options){
+ EJS.cache = options.cache != null ? options.cache : EJS.cache;
+ EJS.type = options.type != null ? options.type : EJS.type;
+ var templates_directory = {}; //nice and private container
+
+ EJS.get = function(path, cache){
+ if(cache == false) return null;
+ if(templates_directory[path]) return templates_directory[path];
+ return null;
+ };
+
+ EJS.update = function(path, template) {
+ if(path == null) return;
+ templates_directory[path] = template;
+ };
+
+ EJS.INVALID_PATH = -1;
+
+
+};
+EJS.config( {cache: true, type: '<' } );
+
+EJS.prototype = {
+ render : function(object){
+ var v = new EjsView(object);
+ return this.template.process.call(v, object, v);
+ },
+ out : function(){
+ return this.template.out;
+ },
+ set_options : function(options){
+ this.type = options.type != null ? options.type : EJS.type;
+ this.cache = options.cache != null ? options.cache : EJS.cache;
+ this.text = options.text != null ? options.text : null;
+ this.name = options.name != null ? options.name : null;
+ },
+ // called without options, returns a function that takes the object
+ // called with options being a string, uses that as a url
+ // called with options as an object
+ update : function(element, options){
+ if(typeof element == 'string'){
+ element = document.getElementById(element);
+ }
+ if(options == null){
+ _template = this;
+ return function(object){
+ EJS.prototype.update.call(_template, element, object);
+ };
+ }
+ if(typeof options == 'string'){
+ params = {};
+ params.url = options;
+ _template = this;
+ params.onComplete = function(request){
+ var object = eval( request.responseText );
+ EJS.prototype.update.call(_template, element, object);
+ };
+ EJS.ajax_request(params);
+ }else
+ {
+ element.innerHTML = this.render(options);
+ }
+ }
+};
+
+ EJS.newRequest = function(){
+ var factories = [function() { return new ActiveXObject("Msxml2.XMLHTTP"); },function() { return new XMLHttpRequest(); },function() { return new ActiveXObject("Microsoft.XMLHTTP"); }];
+ for(var i = 0; i < factories.length; i++) {
+ try {
+ var request = factories[i]();
+ if (request != null) return request;
+ }
+ catch(e) { continue;}
+ }
+ };
+
+ EJS.request = function(path){
+ var request = new EJS.newRequest();
+ request.open("GET", path, false);
+
+ try{request.send(null);}
+ catch(e){return null;}
+
+ if ( request.status == 404 || request.status == 2 ||(request.status == 0 && request.responseText == '') ) return null;
+
+ return request.responseText
+ };
+ EJS.ajax_request = function(params){
+ params.method = ( params.method ? params.method : 'GET');
+
+ var request = new EJS.newRequest();
+ request.onreadystatechange = function(){
+ if(request.readyState == 4){
+ if(request.status == 200){
+ params.onComplete(request);
+ }else
+ {
+ params.onComplete(request);
+ }
+ }
+ };
+ request.open(params.method, params.url);
+ request.send(null);
+ };
+
+//}
+
+
diff --git a/trunk/infrastructure/framework-src/modules/email.js b/infrastructure/framework-src/modules/email.js
index 2d81dc3..2d81dc3 100644
--- a/trunk/infrastructure/framework-src/modules/email.js
+++ b/infrastructure/framework-src/modules/email.js
diff --git a/trunk/infrastructure/framework-src/modules/exceptionutils.js b/infrastructure/framework-src/modules/exceptionutils.js
index b572a3a..b572a3a 100644
--- a/trunk/infrastructure/framework-src/modules/exceptionutils.js
+++ b/infrastructure/framework-src/modules/exceptionutils.js
diff --git a/infrastructure/framework-src/modules/execution.js b/infrastructure/framework-src/modules/execution.js
new file mode 100644
index 0000000..2f9d933
--- /dev/null
+++ b/infrastructure/framework-src/modules/execution.js
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("jsutils.{scalaF0,scalaF1}");
+
+/**
+ * Asynchronously call a function as soon as the current request completes.
+ **/
+function async(f) {
+ Packages.net.appjet.ajstdlib.execution.runAsync(appjet.context, f);
+}
+
+function initTaskThreadPool(name, poolSize) {
+ Packages.net.appjet.ajstdlib.execution.createNamedTaskThreadPool(name, poolSize);
+}
+
+function scheduleTask(poolName, taskName, delayMillis, args) {
+ return Packages.net.appjet.ajstdlib.execution.scheduleTaskInPool(poolName, taskName, delayMillis, args);
+}
+
+function shutdownAndWaitOnTaskThreadPool(poolName, timeoutMillis) {
+ return Packages.net.appjet.ajstdlib.execution.shutdownAndWaitOnTaskThreadPool(poolName, timeoutMillis);
+}
+
+function fancyAssEval(initCode, mainCode) {
+ function init(runner) {
+ Packages.net.appjet.bodylock.BodyLock.evaluateString(
+ runner.globalScope(),
+ initCode,
+ "eval'd code imports",
+ 1);
+ }
+ var runner = Packages.net.appjet.oui.ScopeReuseManager.getEmpty(scalaF1(init));
+ var requestWrapper = null;
+ if (request.underlying !== undefined)
+ requestWrapper = new Packages.net.appjet.oui.RequestWrapper(request.underlying);
+ var ec = new Packages.net.appjet.oui.ExecutionContext(
+ requestWrapper,
+ null, runner);
+ return Packages.net.appjet.oui.ExecutionContextUtils.withContext(ec,
+ scalaF0(function() {
+ return Packages.net.appjet.bodylock.BodyLock.evaluateString(
+ runner.globalScope(),
+ mainCode,
+ "eval'd code main",
+ 1);
+ }));
+} \ No newline at end of file
diff --git a/trunk/infrastructure/framework-src/modules/fastJSON.js b/infrastructure/framework-src/modules/fastJSON.js
index 3198b96..3198b96 100644
--- a/trunk/infrastructure/framework-src/modules/fastJSON.js
+++ b/infrastructure/framework-src/modules/fastJSON.js
diff --git a/infrastructure/framework-src/modules/faststatic.js b/infrastructure/framework-src/modules/faststatic.js
new file mode 100644
index 0000000..920be8c
--- /dev/null
+++ b/infrastructure/framework-src/modules/faststatic.js
@@ -0,0 +1,342 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+/**
+ * @fileOverview serving static files, including js and css, and cacheing
+ * and minifying.
+ *
+ * Terminology Note:
+ * "path" is confusing because paths can be part of URLs and part
+ * of filesystem paths, and static files have both types of paths
+ * associated with them. Therefore, in this module:
+ *
+ * LOCALDIR or LOCALFILE refers to directories or files on the filesystem.
+ *
+ * HREF is used to describe things that go in a URL.
+ */
+
+import("fileutils.{readFile,readFileBytes}");
+import("yuicompressor");
+import("stringutils");
+import("varz");
+import("ejs.EJS");
+
+jimport("java.lang.System.out.println");
+
+//----------------------------------------------------------------
+// Content Type Guessing
+//----------------------------------------------------------------
+
+var _contentTypes = {
+ 'gif': 'image/gif',
+ 'png': 'image/png',
+ 'jpg': 'image/jpeg',
+ 'jpeg': 'image/jpeg',
+ 'css': 'text/css',
+ 'js': 'application/x-javascript',
+ 'txt': 'text/plain',
+ 'html': 'text/html; charset=utf-8',
+ 'ico': 'image/x-icon',
+ 'swf': 'application/x-shockwave-flash',
+ 'zip': 'application/zip',
+ 'xml': 'application/xml'
+};
+
+var _gzipableTypes = {
+ 'text/css': true,
+ 'application/x-javascript': true,
+ 'text/html; charset=utf-8': true
+};
+
+function _guessContentType(path) {
+ var ext = path.split('.').pop().toLowerCase();
+ return _contentTypes[ext] || 'text/plain';
+}
+
+//----------------------------------------------------------------
+
+function _getCache(name) {
+ var m = 'faststatic';
+ if (!appjet.cache[m]) {
+ appjet.cache[m] = {};
+ }
+ var c = appjet.cache[m];
+ if (!c[name]) {
+ c[name] = {};
+ }
+ return c[name];
+}
+
+var _mtimeCheckInterval = 5000; // 5 seconds
+
+function _getMTime(f) {
+ var mcache = _getCache('mtimes');
+ var now = +(new Date);
+ if (appjet.config.devMode ||
+ !(mcache[f] && (now - mcache[f].lastCheck < _mtimeCheckInterval))) {
+ var jfile = new net.appjet.oui.JarVirtualFile(f);
+ if (jfile.exists() && !jfile.isDirectory()) {
+ mcache[f] = {
+ lastCheck: now,
+ mtime: jfile.lastModified()
+ };
+ } else {
+ mcache[f] = null;
+ }
+ }
+ if (mcache[f]) {
+ return +mcache[f].mtime;
+ } else {
+ return null;
+ }
+}
+
+function manglePluginPath(localFile, fileType) {
+ var prefix = '/static/' + fileType + '/plugins/';
+ if (localFile.substring(0, prefix.length) != prefix)
+ return localFile;
+ var suffix = localFile.substring(prefix.length);
+ var plugin = suffix.split('/', 1)[0];
+ suffix = suffix.substring(plugin.length + 1);
+ return '/plugins/' + plugin + '/static/' + fileType + '/' + suffix;
+}
+
+function manglePluginPaths(localFile) {
+ return manglePluginPath(
+ manglePluginPath(
+ manglePluginPath(
+ manglePluginPath(
+ manglePluginPath(
+ localFile,
+ 'js'),
+ 'css'),
+ 'swf'),
+ 'html'),
+ 'zip');
+}
+
+function _wrapFile(localFile) {
+ return {
+ getPath: function() { return localFile; },
+ getMTime: function() { return _getMTime(localFile); },
+ getContents: function() { return _readFileAndProcess(manglePluginPaths(localFile), 'string'); }
+ };
+}
+
+function _readFileAndProcess(fileName, type) {
+ if (fileName.slice(-8) == "_ejs.css") {
+ // run CSS through EJS
+ var template = readFile(fileName);
+ var ejs = new EJS({text:template, name:fileName});
+ var resultString = ejs.render({});
+ if (type == 'bytes') {
+ return new java.lang.String(resultString).getBytes("UTF-8");
+ }
+ else {
+ return resultString;
+ }
+ }
+ else if (type == 'string') {
+ return readFile(fileName);
+ }
+ else if (type == 'bytes') {
+ return readFileBytes(fileName);
+ }
+}
+
+function _cachedFileBytes(f) {
+ var mtime = _getMTime(f);
+ if (!mtime) { return null; }
+ var fcache = _getCache('file-bytes-cache');
+ if (!(fcache[f] && (fcache[f].mtime == mtime))) {
+ varz.incrementInt("faststatic-file-bytes-cache-miss");
+ var bytes = _readFileAndProcess(f, 'bytes');
+ if (bytes) {
+ fcache[f] = {mtime: mtime, bytes: bytes};
+ };
+ }
+ if (fcache[f] && fcache[f].bytes) {
+ return fcache[f].bytes;
+ } else {
+ return null;
+ }
+}
+
+function _shouldGzip(contentType) {
+ var userAgent = request.headers["User-Agent"];
+ if (! userAgent) return false;
+ if (! (/Firefox/.test(userAgent) || /webkit/i.test(userAgent))) return false;
+ if (! _gzipableTypes[contentType]) return false;
+
+ return request.acceptsGzip;
+}
+
+function _getCachedGzip(original, key) {
+ var c = _getCache("gzipped");
+ if (! c[key] || ! java.util.Arrays.equals(c[key].original, original)) {
+ c[key] = {original: original,
+ gzip: stringutils.gzip(original)};
+ }
+ return c[key].gzip;
+}
+
+function _setGzipHeader() {
+ response.setHeader("Content-Encoding", "gzip");
+}
+
+//----------------------------------------------------------------
+
+/**
+ * Function for serving a single static file.
+ */
+function singleFileServer(localPath, opts) {
+ var contentType = _guessContentType(localPath);
+
+ return function() {
+ (opts.cache ? response.alwaysCache() : response.neverCache());
+ response.setContentType(contentType);
+ var bytes = _cachedFileBytes(localPath);
+ if (bytes) {
+ if (_shouldGzip(contentType)) {
+ bytes = _getCachedGzip(bytes, "file:"+localPath);
+ _setGzipHeader();
+ }
+ response.writeBytes(bytes);
+ return true;
+ } else {
+ return false;
+ }
+ };
+}
+
+/**
+ * valid opts:
+ * alwaysCache: default false
+ */
+function directoryServer(localDir, opts) {
+ if (stringutils.endsWith(localDir, "/")) {
+ localDir = localDir.substr(0, localDir.length-1);
+ }
+ return function(relpath) {
+ if (stringutils.startsWith(relpath, "/")) {
+ relpath = relpath.substr(1);
+ }
+ if (relpath.indexOf('..') != -1) {
+ response.forbid();
+ }
+ (opts.cache ? response.alwaysCache() : response.neverCache());
+ var contentType = _guessContentType(relpath);
+ response.setContentType(contentType);
+ var fullPath = localDir + "/" + relpath;
+ var bytes = _cachedFileBytes(fullPath);
+
+ if (bytes) {
+ if (_shouldGzip(contentType)) {
+ bytes = _getCachedGzip(bytes, "file:"+fullPath);
+ _setGzipHeader();
+ }
+ response.writeBytes(bytes);
+ return true;
+ } else {
+ return false;
+ }
+ };
+}
+
+/**
+ * Serves cat files, which are concatenated versions of many files.
+ */
+function compressedFileServer(opts) {
+ var cfcache = _getCache('compressed-files');
+ return function() {
+ var key = request.path.split('/').slice(-1)[0];
+ var contentType = _guessContentType(request.path);
+ response.setContentType(contentType);
+ response.alwaysCache();
+ var data = cfcache[key];
+ if (data) {
+ if (_shouldGzip(contentType)) {
+ data = _getCachedGzip((new java.lang.String(data)).getBytes(response.getCharacterEncoding()), "comp:"+key);
+ _setGzipHeader();
+ response.writeBytes(data);
+ } else {
+ response.write(data);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ };
+}
+
+function getCompressedFilesKey(type, baseLocalDir, localFileList) {
+ if (stringutils.endsWith(baseLocalDir, '/')) {
+ baseLocalDir = baseLocalDir.substr(0, baseLocalDir.length-1);
+ }
+
+ var fileList = [];
+ // convert passed-in file list into list of our file objects
+ localFileList.forEach(function(f) {
+ if (typeof(f) == 'string') {
+ fileList.push(_wrapFile(baseLocalDir+'/'+f));
+ } else {
+ fileList.push(f);
+ }
+ });
+
+ // have we seen this exact fileset before?
+ var fsId = fileList.map(function(f) { return f.getPath(); }).join('|');
+ var fsMTime = Math.max.apply(this,
+ fileList.map(function(f) { return f.getMTime(); }));
+
+ var kdcache = _getCache('fileset-keydata-cache');
+ if (!(kdcache[fsId] && (kdcache[fsId].mtime == fsMTime))) {
+ //println("cache miss for fileset: "+fsId);
+ //println("compressing fileset...");
+ kdcache[fsId] = {
+ mtime: fsMTime,
+ keyString: _compressFilesAndMakeKey(type, fileList)
+ };
+ }
+ return kdcache[fsId].keyString;
+}
+
+function _compressFilesAndMakeKey(type, fileList) {
+ function _compress(s) {
+ if (type == 'css') {
+ varz.incrementInt("faststatic-yuicompressor-compressCSS");
+ return yuicompressor.compressCSS(s);
+ } else if (type == 'js') {
+ varz.incrementInt("faststatic-yuicompressor-compressJS");
+ return yuicompressor.compressJS(s);
+ } else {
+ throw Error('Dont know how to compress this filetype: '+type);
+ }
+ }
+
+ var fullstr = "";
+ fileList.forEach(function(f) {
+ fullstr += _compress(f.getContents());
+ });
+
+ fullstr = _compress(fullstr);
+
+ var key = stringutils.md5(fullstr) + '.' + type;
+ var cfcache = _getCache('compressed-files');
+ cfcache[key] = fullstr;
+ return key;
+}
+
diff --git a/trunk/infrastructure/framework-src/modules/fileutils.js b/infrastructure/framework-src/modules/fileutils.js
index aaf12e2..aaf12e2 100644
--- a/trunk/infrastructure/framework-src/modules/fileutils.js
+++ b/infrastructure/framework-src/modules/fileutils.js
diff --git a/trunk/infrastructure/framework-src/modules/funhtml.js b/infrastructure/framework-src/modules/funhtml.js
index c27b667..c27b667 100644
--- a/trunk/infrastructure/framework-src/modules/funhtml.js
+++ b/infrastructure/framework-src/modules/funhtml.js
diff --git a/trunk/infrastructure/framework-src/modules/global/appjet.js b/infrastructure/framework-src/modules/global/appjet.js
index 135ac44..135ac44 100644
--- a/trunk/infrastructure/framework-src/modules/global/appjet.js
+++ b/infrastructure/framework-src/modules/global/appjet.js
diff --git a/trunk/infrastructure/framework-src/modules/global/request.js b/infrastructure/framework-src/modules/global/request.js
index a4327f9..a4327f9 100644
--- a/trunk/infrastructure/framework-src/modules/global/request.js
+++ b/infrastructure/framework-src/modules/global/request.js
diff --git a/trunk/infrastructure/framework-src/modules/global/response.js b/infrastructure/framework-src/modules/global/response.js
index 7236920..7236920 100644
--- a/trunk/infrastructure/framework-src/modules/global/response.js
+++ b/infrastructure/framework-src/modules/global/response.js
diff --git a/trunk/infrastructure/framework-src/modules/image.js b/infrastructure/framework-src/modules/image.js
index 8aec74b..8aec74b 100644
--- a/trunk/infrastructure/framework-src/modules/image.js
+++ b/infrastructure/framework-src/modules/image.js
diff --git a/trunk/infrastructure/framework-src/modules/jsutils.js b/infrastructure/framework-src/modules/jsutils.js
index 02f81a2..02f81a2 100644
--- a/trunk/infrastructure/framework-src/modules/jsutils.js
+++ b/infrastructure/framework-src/modules/jsutils.js
diff --git a/trunk/infrastructure/framework-src/modules/netutils.js b/infrastructure/framework-src/modules/netutils.js
index 6616b76..6616b76 100644
--- a/trunk/infrastructure/framework-src/modules/netutils.js
+++ b/infrastructure/framework-src/modules/netutils.js
diff --git a/infrastructure/framework-src/modules/process.js b/infrastructure/framework-src/modules/process.js
new file mode 100644
index 0000000..48ab62e
--- /dev/null
+++ b/infrastructure/framework-src/modules/process.js
@@ -0,0 +1,91 @@
+/**
+ * Simple way to execute external commands through javascript
+ *
+ * @example
+ cmd = exec("cat");
+ System.out.println("First: " +cmd.write("this is a loop.").read(Process.READ_AVAILABLE)); // prints "this is a loop."
+ System.out.println("Second: " +cmd.writeAndClose(" hi there").result()); // prints "this is a loop. hi there"
+ *
+ */
+
+jimport("java.lang.Runtime");
+jimport("java.io.BufferedInputStream");
+jimport("java.io.BufferedOutputStream");
+jimport("java.lang.System");
+
+/* returns a process */
+function exec(process) {
+ return new Process(process);
+};
+
+function Process(cmd) {
+ this.cmd = cmd;
+ this.proc = Runtime.getRuntime().exec(cmd);
+ this.resultText = "";
+ this.inputStream = new BufferedInputStream(this.proc.getInputStream());
+ this.errorStream = new BufferedInputStream(this.proc.getErrorStream());
+ this.outputStream = new BufferedOutputStream(this.proc.getOutputStream());
+}
+
+Process.CHUNK_SIZE = 1024;
+Process.READ_ALL = -1;
+Process.READ_AVAILABLE = -2;
+
+Process.prototype.write = function(stdinText) {
+ this.outputStream.write(new java.lang.String(stdinText).getBytes());
+ this.outputStream.flush();
+ return this;
+};
+
+Process.prototype.writeAndClose = function(stdinText) {
+ this.write(stdinText);
+ this.outputStream.close();
+ return this;
+};
+
+/* Python file-like behavior: read specified number of bytes, else until EOF*/
+Process.prototype.read = function(nbytesToRead, stream) {
+ var inputStream = stream || this.inputStream;
+ var availBytes = inputStream.available();
+ if (!availBytes) return null;
+
+ var result = "";
+ var nbytes = nbytesToRead || Process.READ_ALL;
+ var readAll = (nbytes == Process.READ_ALL);
+ var readAvailable = (nbytes == Process.READ_AVAILABLE);
+ while (nbytes > 0 || readAll || readAvailable) {
+ var chunkSize = readAll ? Process.CHUNK_SIZE :
+ readAvailable ? Process.CHUNK_SIZE : nbytes;
+
+ // allocate a java byte array
+ var bytes = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, chunkSize);
+
+ var len = inputStream.read(bytes, 0, chunkSize);
+
+ // at end of stream, or when we run out of data, stop reading in chunks.
+ if (len == -1) break;
+ if (nbytes > 0) nbytes -= len;
+
+ result += new java.lang.String(bytes);
+
+ if (readAvailable && inputStream.available() == 0) break;
+ }
+
+ this.resultText += new String(result);
+ return new String(result);
+};
+
+Process.prototype.result = function() {
+ this.outputStream.close();
+ this.proc.waitFor();
+ this.read(Process.READ_ALL, this.inputStream);
+ return new String(this.resultText);
+};
+
+Process.prototype.resultOrError = function() {
+ this.proc.waitFor();
+ this.read(Process.READ_ALL, this.inputStream);
+ var result = this.resultText;
+ if(!result || result == "") result = this.read(Process.READ_ALL, this.errorStream);
+ return result || "";
+};
diff --git a/trunk/infrastructure/framework-src/modules/profiler.js b/infrastructure/framework-src/modules/profiler.js
index 223c197..223c197 100644
--- a/trunk/infrastructure/framework-src/modules/profiler.js
+++ b/infrastructure/framework-src/modules/profiler.js
diff --git a/trunk/infrastructure/framework-src/modules/sessions.js b/infrastructure/framework-src/modules/sessions.js
index 3d0041b..3d0041b 100644
--- a/trunk/infrastructure/framework-src/modules/sessions.js
+++ b/infrastructure/framework-src/modules/sessions.js
diff --git a/trunk/infrastructure/framework-src/modules/sqlbase/persistent_vars.js b/infrastructure/framework-src/modules/sqlbase/persistent_vars.js
index 1c4cc95..1c4cc95 100644
--- a/trunk/infrastructure/framework-src/modules/sqlbase/persistent_vars.js
+++ b/infrastructure/framework-src/modules/sqlbase/persistent_vars.js
diff --git a/trunk/infrastructure/framework-src/modules/sqlbase/sqlbase.js b/infrastructure/framework-src/modules/sqlbase/sqlbase.js
index 3df1a0f..3df1a0f 100644
--- a/trunk/infrastructure/framework-src/modules/sqlbase/sqlbase.js
+++ b/infrastructure/framework-src/modules/sqlbase/sqlbase.js
diff --git a/trunk/infrastructure/framework-src/modules/sqlbase/sqlcommon.js b/infrastructure/framework-src/modules/sqlbase/sqlcommon.js
index 360f5e2..360f5e2 100644
--- a/trunk/infrastructure/framework-src/modules/sqlbase/sqlcommon.js
+++ b/infrastructure/framework-src/modules/sqlbase/sqlcommon.js
diff --git a/infrastructure/framework-src/modules/sqlbase/sqlobj.js b/infrastructure/framework-src/modules/sqlbase/sqlobj.js
new file mode 100644
index 0000000..e599c92
--- /dev/null
+++ b/infrastructure/framework-src/modules/sqlbase/sqlobj.js
@@ -0,0 +1,551 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+import("cache_utils.syncedWithCache");
+import("sqlbase.sqlcommon.*");
+import("jsutils.*");
+import("etherpad.log");
+
+jimport("java.lang.System.out.println");
+jimport("java.sql.Statement");
+
+function _withCache(name, fn) {
+ return syncedWithCache('sqlobj.'+name, fn);
+}
+
+function getIdColspec() {
+ return ('INT NOT NULL '+autoIncrementClause()+' PRIMARY KEY');
+}
+
+function getLongtextColspec(extra) {
+ var spec = getSqlBase().longTextType();
+ if (extra) {
+ spec = (spec + " " + extra);
+ }
+ return spec;
+}
+
+function getBoolColspec(extra) {
+ var spec;
+ if (isMysql()) {
+ spec = 'TINYINT(1)';
+ } else {
+ spec = 'SMALLINT';
+ }
+ if (extra) {
+ spec = (spec + " " + extra);
+ }
+ return spec;
+}
+
+function getDateColspec(extra) {
+ var spec;
+ if (isMysql()) {
+ spec = 'DATETIME';
+ } else {
+ spec = 'TIMESTAMP';
+ }
+ if (extra) {
+ spec = (spec + " " + extra);
+ }
+ return spec;
+}
+
+function _bq(x) { return btquote(x); }
+
+/*
+ * for debugging queries
+ */
+function _qdebug(q) {
+ if (appjet.config.debugSQL) {
+ println(q);
+ }
+}
+
+/** executeFn is either "execute" or "executeUpdate" "executeQuery" */
+function _execute(stmnt, executeFn) {
+ if (!executeFn) {
+ executeFn = 'execute';
+ }
+ return withConnection(function(conn) {
+ var pstmnt = conn.prepareStatement(stmnt);
+ return closing(pstmnt, function() {
+ _qdebug(stmnt);
+ return pstmnt[executeFn]();
+ });
+ });
+}
+
+function _executeUpdate(stmnt) {
+ return _execute(stmnt, 'executeUpdate');
+}
+
+function _executeQuery(stmnt) {
+ return _execute(stmnt, 'executeQuery');
+}
+
+/*
+ * Not all SQL/JS types supported.
+ */
+function _getJsValFromResultSet(rs, type, colName) {
+ var r;
+ if (type == java.sql.Types.VARCHAR ||
+ type == java.sql.Types.LONGVARCHAR ||
+ type == java.sql.Types.CHAR) {
+ r = String(rs.getString(colName));
+ } else if (type == java.sql.Types.TIMESTAMP) {
+ var t = rs.getTimestamp(colName);
+ if (t) {
+ r = new Date(t.getTime());
+ } else {
+ r = null;
+ }
+ } else if (type == java.sql.Types.BIGINT ||
+ type == java.sql.Types.INTEGER ||
+ type == java.sql.Types.SMALLINT ||
+ type == java.sql.Types.TINYINT) {
+ r = rs.getInt(colName);
+ } else if (type == java.sql.Types.DECIMAL) {
+ r = rs.getFloat(colName);
+ } else if (type == java.sql.Types.BIT) {
+ r = rs.getBoolean(colName);
+ } else {
+ throw Error("Cannot fetch sql type ID "+type+" (columnName = "+colName+")");
+ }
+
+ if (rs.wasNull()) {
+ r = null;
+ }
+ return r;
+}
+
+function _lookupColumnType(tableName, columnName) {
+ return withConnection(function(conn) {
+ var metadata = conn.getMetaData();
+ var rs = metadata.getColumns(null, null, tableName, columnName);
+ if (!rs) {
+ throw Error("Table '"+tableName+"' does not appear to have colum '"+columnName+"'.");
+ }
+ var rsmd = rs.getMetaData();
+ var colCount = rsmd.getColumnCount();
+// rs.first();
+ rs.next();
+ var type = rs.getInt("DATA_TYPE");
+ return type;
+ });
+}
+
+/* cached, on misses calls _lookuParameterType */
+function _getParameterType(tableName, columnName) {
+ var key = [tableName, columnName].join(".");
+ return _withCache('column-types', function(cache) {
+ if (!cache[key]) {
+ cache[key] = _lookupColumnType(tableName, columnName);
+ }
+ return cache[key];
+ });
+}
+
+/*
+ * Not all SQL/JS types supported.
+ */
+function _setPreparedValues(tableName, pstmnt, keyList, obj, indexOffset) {
+ if (!indexOffset) { indexOffset = 0; }
+
+ for (var i = 1; i <= keyList.length; i++) {
+ var k = keyList[i-1];
+ var v = obj[k];
+ var j = i + indexOffset;
+
+ if (v === undefined) {
+ throw Error("value is undefined for key "+k);
+ }
+
+ if (v === null) {
+ var type = _getParameterType(tableName, k);
+ pstmnt.setNull(j, type);
+ } else if (typeof(v) == 'string') {
+ pstmnt.setString(j, v);
+ } else if (typeof(v) == 'number') {
+ pstmnt.setInt(j, v);
+ } else if (typeof(v) == 'boolean') {
+ pstmnt.setBoolean(j, v);
+ } else if (v.valueOf && v.getDate && v.getHours) {
+ pstmnt.setTimestamp(j, new java.sql.Timestamp(+v));
+ } else {
+ throw Error("Cannot insert this type of javascript object: "+typeof(v)+" (key="+k+", value = "+v+")");
+ }
+ }
+}
+
+function _resultRowToJsObj(resultSet) {
+ var resultObj = {};
+
+ var metaData = resultSet.getMetaData();
+ var colCount = metaData.getColumnCount();
+
+ for (var i = 1; i <= colCount; i++) {
+ var colName = metaData.getColumnLabel(i);
+ var type = metaData.getColumnType(i);
+ resultObj[colName] = _getJsValFromResultSet(resultSet, type, colName);
+ }
+
+ return resultObj;
+}
+
+/*
+ * Inserts the object into the given table, and returns auto-incremented ID if any.
+ */
+function insert(tableName, obj) {
+ var keyList = keys(obj);
+
+ var stmnt = "INSERT INTO "+_bq(tableName)+" (";
+ stmnt += keyList.map(function(k) { return _bq(k); }).join(', ');
+ stmnt += ") VALUES (";
+ stmnt += keyList.map(function(k) { return '?'; }).join(', ');
+ stmnt += ")";
+
+ return withConnection(function(conn) {
+ var pstmnt = conn.prepareStatement(stmnt, Statement.RETURN_GENERATED_KEYS);
+ return closing(pstmnt, function() {
+ _setPreparedValues(tableName, pstmnt, keyList, obj, 0);
+ _qdebug(stmnt);
+ pstmnt.executeUpdate();
+ var rs = pstmnt.getGeneratedKeys();
+ if (rs != null) {
+ return closing(rs, function() {
+ if (rs.next()) {
+ return rs.getInt(1);
+ }
+ });
+ }
+ });
+ });
+};
+
+/*
+ * Selects a single object given the constraintMap. If there are more
+ * than 1 objects that match, it will return a single one of them
+ * (unspecified which one). If no objects match, returns null.
+ *
+ * constraints is a javascript object of column names to values.
+ * Currently only supports string equality of constraints.
+ */
+function selectSingle(tableName, constraints) {
+ var keyList = keys(constraints);
+
+ var stmnt = "SELECT * FROM "+_bq(tableName)+" WHERE (";
+ stmnt += keyList.map(function(k) { return '('+_bq(k)+' = '+'?)'; }).join(' AND ');
+ stmnt += ')';
+ if (isMysql()) {
+ stmnt += ' LIMIT 1';
+ }
+
+ return withConnection(function(conn) {
+ var pstmnt = conn.prepareStatement(stmnt);
+ return closing(pstmnt, function() {
+ _setPreparedValues(tableName, pstmnt, keyList, constraints, 0);
+ _qdebug(stmnt);
+ var resultSet = pstmnt.executeQuery();
+ return closing(resultSet, function() {
+ if (!resultSet.next()) {
+ return null;
+ }
+ return _resultRowToJsObj(resultSet);
+ });
+ });
+ });
+}
+
+function _makeConstraintString(key, value) {
+ if (typeof(value) != 'object' || ! (value instanceof Array)) {
+ return '('+_bq(key)+' = ?)';
+ } else {
+ var comparator = value[0];
+ return '('+_bq(key)+' '+comparator+' ?)';
+ }
+}
+
+function _preparedValuesConstraints(constraints) {
+ var c = {};
+ eachProperty(constraints, function(k, v) {
+ c[k] = (typeof(v) != 'object' || ! (v instanceof Array) ? v : v[1]);
+ });
+ return c;
+}
+
+function selectMulti(tableName, constraints, options) {
+ if (!options) {
+ options = {};
+ }
+
+ var constraintKeys = keys(constraints);
+
+ var stmnt = "SELECT * FROM "+_bq(tableName)+" ";
+
+ if (constraintKeys.length > 0) {
+ stmnt += "WHERE (";
+ stmnt += constraintKeys.map(function(key) {
+ return _makeConstraintString(key, constraints[key]);
+ }).join(' AND ');
+ stmnt += ')';
+ }
+
+ if (options.orderBy) {
+ var orderEntries = [];
+ options.orderBy.split(",").forEach(function(orderBy) {
+ var asc = "ASC";
+ if (orderBy.charAt(0) == '-') {
+ orderBy = orderBy.substr(1);
+ asc = "DESC";
+ }
+ orderEntries.push(_bq(orderBy)+" "+asc);
+ });
+ stmnt += " ORDER BY "+orderEntries.join(", ");
+ }
+
+ if (options.limit) {
+ stmnt += " LIMIT "+options.limit;
+ }
+
+ return withConnection(function(conn) {
+ var pstmnt = conn.prepareStatement(stmnt);
+ return closing(pstmnt, function() {
+ _setPreparedValues(
+ tableName, pstmnt, constraintKeys,
+ _preparedValuesConstraints(constraints), 0);
+
+ _qdebug(stmnt);
+ var resultSet = pstmnt.executeQuery();
+ var resultArray = [];
+
+ return closing(resultSet, function() {
+ while (resultSet.next()) {
+ resultArray.push(_resultRowToJsObj(resultSet));
+ }
+
+ return resultArray;
+ });
+ });
+ });
+}
+
+function executeRaw(stmnt, params) {
+ return withConnection(function(conn) {
+ var pstmnt = conn.prepareStatement(stmnt);
+ return closing(pstmnt, function() {
+ for (var i = 0; i < params.length; i++) {
+ var v = params[i];
+
+ if (v === undefined) {
+ throw Error("value is undefined for key "+i);
+ }
+
+ if (typeof(v) == 'object' && v.isnull) {
+ pstmnt.setNull(i+1, v.type);
+ } else if (typeof(v) == 'string') {
+ pstmnt.setString(i+1, v);
+ } else if (typeof(v) == 'number') {
+ pstmnt.setInt(i+1, v);
+ } else if (typeof(v) == 'boolean') {
+ pstmnt.setBoolean(i+1, v);
+ } else if (v.valueOf && v.getDate && v.getHours) {
+ pstmnt.setTimestamp(i+1, new java.sql.Timestamp(+v));
+ } else {
+ throw Error("Cannot insert this type of javascript object: "+typeof(v)+" (key="+i+", value = "+v+")");
+ }
+ }
+
+ _qdebug(stmnt);
+ var resultSet = pstmnt.executeQuery();
+ var resultArray = [];
+
+ return closing(resultSet, function() {
+ while (resultSet.next()) {
+ resultArray.push(_resultRowToJsObj(resultSet));
+ }
+
+ return resultArray;
+ });
+ });
+ });
+}
+
+/* returns number of rows updated */
+function update(tableName, constraints, obj) {
+ var objKeys = keys(obj);
+ var constraintKeys = keys(constraints);
+
+ var stmnt = "UPDATE "+_bq(tableName)+" SET ";
+ stmnt += objKeys.map(function(k) { return ''+_bq(k)+' = ?'; }).join(', ');
+ stmnt += " WHERE (";
+ stmnt += constraintKeys.map(function(k) { return '('+_bq(k)+' = ?)'; }).join(' AND ');
+ stmnt += ')';
+
+ return withConnection(function(conn) {
+ var pstmnt = conn.prepareStatement(stmnt);
+ return closing(pstmnt, function() {
+ _setPreparedValues(tableName, pstmnt, objKeys, obj, 0);
+ _setPreparedValues(tableName, pstmnt, constraintKeys, constraints, objKeys.length);
+ _qdebug(stmnt);
+ return pstmnt.executeUpdate();
+ });
+ });
+}
+
+function updateSingle(tableName, constraints, obj) {
+ var count = update(tableName, constraints, obj);
+ if (count != 1) {
+ throw Error("save count != 1. instead, count = "+count);
+ }
+}
+
+function deleteRows(tableName, constraints) {
+ var constraintKeys = keys(constraints);
+ var stmnt = "DELETE FROM "+_bq(tableName)+" WHERE (";
+ stmnt += constraintKeys.map(function(k) { return '('+_bq(k)+' = ?)'; }).join(' AND ');
+ stmnt += ')';
+ withConnection(function(conn) {
+ var pstmnt = conn.prepareStatement(stmnt);
+ closing(pstmnt, function() {
+ _setPreparedValues(tableName, pstmnt, constraintKeys, constraints);
+ _qdebug(stmnt);
+ pstmnt.executeUpdate();
+ });
+ })
+}
+
+//----------------------------------------------------------------
+// table management
+//----------------------------------------------------------------
+
+/*
+ * Create a SQL table, specifying column names and types with a
+ * javascript object.
+ */
+function createTable(tableName, colspec, indices) {
+ if (doesTableExist(tableName)) {
+ return;
+ }
+
+ var stmnt = "CREATE TABLE "+_bq(tableName)+ " (";
+ stmnt += keys(colspec).map(function(k) { return (_bq(k) + ' ' + colspec[k]); }).join(', ');
+ if (indices) {
+ stmnt += ', ' + keys(indices).map(function(k) { return 'INDEX (' + _bq(k) + ')'; }).join(', ');
+ }
+ stmnt += ')'+createTableOptions();
+ _execute(stmnt);
+}
+
+function dropTable(tableName) {
+ _execute("DROP TABLE "+_bq(tableName));
+}
+
+function dropAndCreateTable(tableName, colspec, indices) {
+ if (doesTableExist(tableName)) {
+ dropTable(tableName);
+ }
+
+ return createTable(tableName, colspec, indices);
+}
+
+function renameTable(oldName, newName) {
+ _executeUpdate("RENAME TABLE "+_bq(oldName)+" TO "+_bq(newName));
+}
+
+function modifyColumn(tableName, columnName, newSpec) {
+ _executeUpdate("ALTER TABLE "+_bq(tableName)+" MODIFY "+_bq(columnName)+" "+newSpec);
+}
+
+function alterColumn(tableName, columnName, alteration) {
+ var q = "ALTER TABLE "+_bq(tableName)+" ALTER COLUMN "+_bq(columnName)+" "+alteration;
+ _executeUpdate(q);
+}
+
+function changeColumn(tableName, columnName, newSpec) {
+ var q = ("ALTER TABLE "+_bq(tableName)+" CHANGE COLUMN "+_bq(columnName)
+ +" "+newSpec);
+ _executeUpdate(q);
+}
+
+function addColumns(tableName, colspec) {
+ inTransaction(function(conn) {
+ eachProperty(colspec, function(name, definition) {
+ var stmnt = "ALTER TABLE "+_bq(tableName)+" ADD COLUMN "+_bq(name)+" "+definition;
+ _executeUpdate(stmnt);
+ });
+ });
+}
+
+function dropColumn(tableName, columnName) {
+ var stmnt = "ALTER TABLE "+_bq(tableName)+" DROP COLUMN "+_bq(columnName);
+ _executeUpdate(stmnt);
+}
+
+function listTables() {
+ return withConnection(function(conn) {
+ var metadata = conn.getMetaData();
+ var resultSet = metadata.getTables(null, null, null, null);
+ var resultArray = [];
+
+ return closing(resultSet, function() {
+ while (resultSet.next()) {
+ resultArray.push(resultSet.getString("TABLE_NAME"));
+ }
+ return resultArray;
+ });
+ });
+}
+
+function setTableEngine(tableName, engineName) {
+ var stmnt = "ALTER TABLE "+_bq(tableName)+" ENGINE="+_bq(engineName);
+ _executeUpdate(stmnt);
+}
+
+function getTableEngine(tableName) {
+ if (!isMysql()) {
+ throw Error("getTableEngine() only supported by MySQL database type.");
+ }
+
+ var tableEngines = {};
+
+ withConnection(function(conn) {
+ var stmnt = "show table status";
+ var pstmnt = conn.prepareStatement(stmnt);
+ closing(pstmnt, function() {
+ _qdebug(stmnt);
+ var resultSet = pstmnt.executeQuery();
+ closing(resultSet, function() {
+ while (resultSet.next()) {
+ var n = resultSet.getString("Name");
+ var eng = resultSet.getString("Engine");
+ tableEngines[n] = eng;
+ }
+ });
+ });
+ });
+
+ return tableEngines[tableName];
+}
+
+function createIndex(tableName, columns) {
+ var indexName = "idx_"+(columns.join("_"));
+ var stmnt = "CREATE INDEX "+_bq(indexName)+" on "+_bq(tableName)+" (";
+ stmnt += columns.map(_bq).join(", ");
+ stmnt += ")";
+ _executeUpdate(stmnt);
+}
+
diff --git a/trunk/infrastructure/framework-src/modules/stringutils.js b/infrastructure/framework-src/modules/stringutils.js
index 3fe5611..3fe5611 100644
--- a/trunk/infrastructure/framework-src/modules/stringutils.js
+++ b/infrastructure/framework-src/modules/stringutils.js
diff --git a/trunk/infrastructure/framework-src/modules/sync.js b/infrastructure/framework-src/modules/sync.js
index a222ea0..a222ea0 100644
--- a/trunk/infrastructure/framework-src/modules/sync.js
+++ b/infrastructure/framework-src/modules/sync.js
diff --git a/trunk/infrastructure/framework-src/modules/timer.js b/infrastructure/framework-src/modules/timer.js
index 01be175..01be175 100644
--- a/trunk/infrastructure/framework-src/modules/timer.js
+++ b/infrastructure/framework-src/modules/timer.js
diff --git a/trunk/infrastructure/framework-src/modules/varz.js b/infrastructure/framework-src/modules/varz.js
index 0e55d20..0e55d20 100644
--- a/trunk/infrastructure/framework-src/modules/varz.js
+++ b/infrastructure/framework-src/modules/varz.js
diff --git a/trunk/infrastructure/framework-src/modules/yuicompressor.js b/infrastructure/framework-src/modules/yuicompressor.js
index 572cc0d..572cc0d 100644
--- a/trunk/infrastructure/framework-src/modules/yuicompressor.js
+++ b/infrastructure/framework-src/modules/yuicompressor.js
diff --git a/trunk/infrastructure/framework-src/oncomet.js b/infrastructure/framework-src/oncomet.js
index b6aeda5..b6aeda5 100644
--- a/trunk/infrastructure/framework-src/oncomet.js
+++ b/infrastructure/framework-src/oncomet.js
diff --git a/trunk/infrastructure/framework-src/onerror.js b/infrastructure/framework-src/onerror.js
index f19a85f..f19a85f 100644
--- a/trunk/infrastructure/framework-src/onerror.js
+++ b/infrastructure/framework-src/onerror.js
diff --git a/trunk/infrastructure/framework-src/onprint.js b/infrastructure/framework-src/onprint.js
index 8e334fe..8e334fe 100644
--- a/trunk/infrastructure/framework-src/onprint.js
+++ b/infrastructure/framework-src/onprint.js
diff --git a/trunk/infrastructure/framework-src/onrequest.js b/infrastructure/framework-src/onrequest.js
index d76c8db..d76c8db 100644
--- a/trunk/infrastructure/framework-src/onrequest.js
+++ b/infrastructure/framework-src/onrequest.js
diff --git a/trunk/infrastructure/framework-src/onreset.js b/infrastructure/framework-src/onreset.js
index 24b000a..24b000a 100644
--- a/trunk/infrastructure/framework-src/onreset.js
+++ b/infrastructure/framework-src/onreset.js
diff --git a/trunk/infrastructure/framework-src/onsars.js b/infrastructure/framework-src/onsars.js
index 31dc8ca..31dc8ca 100644
--- a/trunk/infrastructure/framework-src/onsars.js
+++ b/infrastructure/framework-src/onsars.js
diff --git a/trunk/infrastructure/framework-src/onscheduledtask.js b/infrastructure/framework-src/onscheduledtask.js
index 810c3b5..810c3b5 100644
--- a/trunk/infrastructure/framework-src/onscheduledtask.js
+++ b/infrastructure/framework-src/onscheduledtask.js
diff --git a/trunk/infrastructure/framework-src/onshutdown.js b/infrastructure/framework-src/onshutdown.js
index 0243bf6..0243bf6 100644
--- a/trunk/infrastructure/framework-src/onshutdown.js
+++ b/infrastructure/framework-src/onshutdown.js
diff --git a/trunk/infrastructure/framework-src/onstartup.js b/infrastructure/framework-src/onstartup.js
index 61feff7..61feff7 100644
--- a/trunk/infrastructure/framework-src/onstartup.js
+++ b/infrastructure/framework-src/onstartup.js
diff --git a/trunk/infrastructure/framework-src/onsyntaxerror.js b/infrastructure/framework-src/onsyntaxerror.js
index 7129a16..7129a16 100644
--- a/trunk/infrastructure/framework-src/onsyntaxerror.js
+++ b/infrastructure/framework-src/onsyntaxerror.js
diff --git a/trunk/infrastructure/framework-src/postamble.js b/infrastructure/framework-src/postamble.js
index 76fa766..76fa766 100644
--- a/trunk/infrastructure/framework-src/postamble.js
+++ b/infrastructure/framework-src/postamble.js
diff --git a/trunk/infrastructure/framework-src/preamble.js b/infrastructure/framework-src/preamble.js
index 40f6845..40f6845 100644
--- a/trunk/infrastructure/framework-src/preamble.js
+++ b/infrastructure/framework-src/preamble.js
diff --git a/trunk/infrastructure/framework-src/syntaxerror.js b/infrastructure/framework-src/syntaxerror.js
index 801066b..801066b 100644
--- a/trunk/infrastructure/framework-src/syntaxerror.js
+++ b/infrastructure/framework-src/syntaxerror.js
diff --git a/trunk/infrastructure/lib/activation.jar b/infrastructure/lib/activation.jar
index 29a59a9..29a59a9 100644
--- a/trunk/infrastructure/lib/activation.jar
+++ b/infrastructure/lib/activation.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/c3p0-0.9.1.2.jar b/infrastructure/lib/c3p0-0.9.1.2.jar
index 0f42d60..0f42d60 100644
--- a/trunk/infrastructure/lib/c3p0-0.9.1.2.jar
+++ b/infrastructure/lib/c3p0-0.9.1.2.jar
Binary files differ
diff --git a/infrastructure/lib/commons-fileupload-1.2.1-javadoc.jar b/infrastructure/lib/commons-fileupload-1.2.1-javadoc.jar
new file mode 100644
index 0000000..86a56ac
--- /dev/null
+++ b/infrastructure/lib/commons-fileupload-1.2.1-javadoc.jar
Binary files differ
diff --git a/infrastructure/lib/commons-fileupload-1.2.1-sources.jar b/infrastructure/lib/commons-fileupload-1.2.1-sources.jar
new file mode 100644
index 0000000..8141625
--- /dev/null
+++ b/infrastructure/lib/commons-fileupload-1.2.1-sources.jar
Binary files differ
diff --git a/infrastructure/lib/commons-fileupload-1.2.1.jar b/infrastructure/lib/commons-fileupload-1.2.1.jar
new file mode 100644
index 0000000..aa209b3
--- /dev/null
+++ b/infrastructure/lib/commons-fileupload-1.2.1.jar
Binary files differ
diff --git a/infrastructure/lib/commons-io-1.4-javadoc.jar b/infrastructure/lib/commons-io-1.4-javadoc.jar
new file mode 100644
index 0000000..95731a7
--- /dev/null
+++ b/infrastructure/lib/commons-io-1.4-javadoc.jar
Binary files differ
diff --git a/infrastructure/lib/commons-io-1.4-sources.jar b/infrastructure/lib/commons-io-1.4-sources.jar
new file mode 100644
index 0000000..299708f
--- /dev/null
+++ b/infrastructure/lib/commons-io-1.4-sources.jar
Binary files differ
diff --git a/infrastructure/lib/commons-io-1.4.jar b/infrastructure/lib/commons-io-1.4.jar
new file mode 100644
index 0000000..133dc6c
--- /dev/null
+++ b/infrastructure/lib/commons-io-1.4.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/commons-lang-2.4.jar b/infrastructure/lib/commons-lang-2.4.jar
index 532939e..532939e 100644
--- a/trunk/infrastructure/lib/commons-lang-2.4.jar
+++ b/infrastructure/lib/commons-lang-2.4.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/derby-10.5.1.1.jar b/infrastructure/lib/derby-10.5.1.1.jar
index 2820dbd..2820dbd 100644
--- a/trunk/infrastructure/lib/derby-10.5.1.1.jar
+++ b/infrastructure/lib/derby-10.5.1.1.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/derbytools.jar b/infrastructure/lib/derbytools.jar
index 4aa76e1..4aa76e1 100644
--- a/trunk/infrastructure/lib/derbytools.jar
+++ b/infrastructure/lib/derbytools.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/dnsjava-2.0.6.jar b/infrastructure/lib/dnsjava-2.0.6.jar
index e41f9b0..e41f9b0 100644
--- a/trunk/infrastructure/lib/dnsjava-2.0.6.jar
+++ b/infrastructure/lib/dnsjava-2.0.6.jar
Binary files differ
diff --git a/infrastructure/lib/java_uno-3.2.0.jar b/infrastructure/lib/java_uno-3.2.0.jar
new file mode 100644
index 0000000..1f23dd0
--- /dev/null
+++ b/infrastructure/lib/java_uno-3.2.0.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/jetty-6.1.20.jar b/infrastructure/lib/jetty-6.1.20.jar
index 8f45db9..8f45db9 100644
--- a/trunk/infrastructure/lib/jetty-6.1.20.jar
+++ b/infrastructure/lib/jetty-6.1.20.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/jetty-sslengine-6.1.20.jar b/infrastructure/lib/jetty-sslengine-6.1.20.jar
index 6f7d232..6f7d232 100644
--- a/trunk/infrastructure/lib/jetty-sslengine-6.1.20.jar
+++ b/infrastructure/lib/jetty-sslengine-6.1.20.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/jetty-util-6.1.20.jar b/infrastructure/lib/jetty-util-6.1.20.jar
index 96c0979..96c0979 100644
--- a/trunk/infrastructure/lib/jetty-util-6.1.20.jar
+++ b/infrastructure/lib/jetty-util-6.1.20.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/json.jar b/infrastructure/lib/json.jar
index 5ab955c..5ab955c 100644
--- a/trunk/infrastructure/lib/json.jar
+++ b/infrastructure/lib/json.jar
Binary files differ
diff --git a/infrastructure/lib/juh-3.2.0.jar b/infrastructure/lib/juh-3.2.0.jar
new file mode 100644
index 0000000..5345fe2
--- /dev/null
+++ b/infrastructure/lib/juh-3.2.0.jar
Binary files differ
diff --git a/infrastructure/lib/jurt-3.2.0.jar b/infrastructure/lib/jurt-3.2.0.jar
new file mode 100644
index 0000000..50f2346
--- /dev/null
+++ b/infrastructure/lib/jurt-3.2.0.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/mail.jar b/infrastructure/lib/mail.jar
index e6f7083..e6f7083 100644
--- a/trunk/infrastructure/lib/mail.jar
+++ b/infrastructure/lib/mail.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/manifest b/infrastructure/lib/manifest
index b91a5a7..b91a5a7 100644
--- a/trunk/infrastructure/lib/manifest
+++ b/infrastructure/lib/manifest
diff --git a/trunk/infrastructure/lib/rhino-js-1.7r1.jar b/infrastructure/lib/rhino-js-1.7r1.jar
index 79f8529..79f8529 100644
--- a/trunk/infrastructure/lib/rhino-js-1.7r1.jar
+++ b/infrastructure/lib/rhino-js-1.7r1.jar
Binary files differ
diff --git a/infrastructure/lib/ridl-3.2.0.jar b/infrastructure/lib/ridl-3.2.0.jar
new file mode 100644
index 0000000..de46acb
--- /dev/null
+++ b/infrastructure/lib/ridl-3.2.0.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/sanselan-0.94aj.jar b/infrastructure/lib/sanselan-0.94aj.jar
index 0fd8c96..0fd8c96 100644
--- a/trunk/infrastructure/lib/sanselan-0.94aj.jar
+++ b/infrastructure/lib/sanselan-0.94aj.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/servlet-api-2.5-20081211.jar b/infrastructure/lib/servlet-api-2.5-20081211.jar
index f1bfa12..f1bfa12 100644
--- a/trunk/infrastructure/lib/servlet-api-2.5-20081211.jar
+++ b/infrastructure/lib/servlet-api-2.5-20081211.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/tagsoup-1.2.jar b/infrastructure/lib/tagsoup-1.2.jar
index af27803..af27803 100644
--- a/trunk/infrastructure/lib/tagsoup-1.2.jar
+++ b/infrastructure/lib/tagsoup-1.2.jar
Binary files differ
diff --git a/infrastructure/lib/unoil-3.2.0.jar b/infrastructure/lib/unoil-3.2.0.jar
new file mode 100644
index 0000000..b1e77aa
--- /dev/null
+++ b/infrastructure/lib/unoil-3.2.0.jar
Binary files differ
diff --git a/trunk/infrastructure/lib/yuicompressor-2.4-appjet.jar b/infrastructure/lib/yuicompressor-2.4-appjet.jar
index b5bdfc1..b5bdfc1 100644
--- a/trunk/infrastructure/lib/yuicompressor-2.4-appjet.jar
+++ b/infrastructure/lib/yuicompressor-2.4-appjet.jar
Binary files differ
diff --git a/trunk/infrastructure/net.appjet.ajstdlib/ajstdlib.scala b/infrastructure/net.appjet.ajstdlib/ajstdlib.scala
index 8d285af..8d285af 100644
--- a/trunk/infrastructure/net.appjet.ajstdlib/ajstdlib.scala
+++ b/infrastructure/net.appjet.ajstdlib/ajstdlib.scala
diff --git a/trunk/infrastructure/net.appjet.ajstdlib/sqlbase.scala b/infrastructure/net.appjet.ajstdlib/sqlbase.scala
index 047c086..047c086 100644
--- a/trunk/infrastructure/net.appjet.ajstdlib/sqlbase.scala
+++ b/infrastructure/net.appjet.ajstdlib/sqlbase.scala
diff --git a/trunk/infrastructure/net.appjet.ajstdlib/streaming-client.js b/infrastructure/net.appjet.ajstdlib/streaming-client.js
index 3bfa227..3bfa227 100644
--- a/trunk/infrastructure/net.appjet.ajstdlib/streaming-client.js
+++ b/infrastructure/net.appjet.ajstdlib/streaming-client.js
diff --git a/trunk/infrastructure/net.appjet.ajstdlib/streaming-iframe.html b/infrastructure/net.appjet.ajstdlib/streaming-iframe.html
index 3bdb5c4..3bdb5c4 100644
--- a/trunk/infrastructure/net.appjet.ajstdlib/streaming-iframe.html
+++ b/infrastructure/net.appjet.ajstdlib/streaming-iframe.html
diff --git a/trunk/infrastructure/net.appjet.ajstdlib/streaming.scala b/infrastructure/net.appjet.ajstdlib/streaming.scala
index fbff137..fbff137 100644
--- a/trunk/infrastructure/net.appjet.ajstdlib/streaming.scala
+++ b/infrastructure/net.appjet.ajstdlib/streaming.scala
diff --git a/trunk/infrastructure/net.appjet.ajstdlib/timer.scala b/infrastructure/net.appjet.ajstdlib/timer.scala
index dac8fb6..dac8fb6 100644
--- a/trunk/infrastructure/net.appjet.ajstdlib/timer.scala
+++ b/infrastructure/net.appjet.ajstdlib/timer.scala
diff --git a/trunk/infrastructure/net.appjet.bodylock/bodylock.scala b/infrastructure/net.appjet.bodylock/bodylock.scala
index e24d55c..e24d55c 100644
--- a/trunk/infrastructure/net.appjet.bodylock/bodylock.scala
+++ b/infrastructure/net.appjet.bodylock/bodylock.scala
diff --git a/trunk/infrastructure/net.appjet.bodylock/compressor.scala b/infrastructure/net.appjet.bodylock/compressor.scala
index 5041787..5041787 100644
--- a/trunk/infrastructure/net.appjet.bodylock/compressor.scala
+++ b/infrastructure/net.appjet.bodylock/compressor.scala
diff --git a/trunk/infrastructure/net.appjet.common.cli/cli.scala b/infrastructure/net.appjet.common.cli/cli.scala
index ef9223f..ef9223f 100644
--- a/trunk/infrastructure/net.appjet.common.cli/cli.scala
+++ b/infrastructure/net.appjet.common.cli/cli.scala
diff --git a/trunk/infrastructure/net.appjet.common.sars/sars.scala b/infrastructure/net.appjet.common.sars/sars.scala
index f91b292..f91b292 100644
--- a/trunk/infrastructure/net.appjet.common.sars/sars.scala
+++ b/infrastructure/net.appjet.common.sars/sars.scala
diff --git a/trunk/infrastructure/net.appjet.common.sars/sha1.scala b/infrastructure/net.appjet.common.sars/sha1.scala
index 8f9e69e..8f9e69e 100644
--- a/trunk/infrastructure/net.appjet.common.sars/sha1.scala
+++ b/infrastructure/net.appjet.common.sars/sha1.scala
diff --git a/trunk/infrastructure/net.appjet.common/rhino/rhinospect.scala b/infrastructure/net.appjet.common/rhino/rhinospect.scala
index 65f278c..65f278c 100644
--- a/trunk/infrastructure/net.appjet.common/rhino/rhinospect.scala
+++ b/infrastructure/net.appjet.common/rhino/rhinospect.scala
diff --git a/trunk/infrastructure/net.appjet.common/util/BCrypt.java b/infrastructure/net.appjet.common/util/BCrypt.java
index 818c261..818c261 100644
--- a/trunk/infrastructure/net.appjet.common/util/BCrypt.java
+++ b/infrastructure/net.appjet.common/util/BCrypt.java
diff --git a/trunk/infrastructure/net.appjet.common/util/BetterFile.java b/infrastructure/net.appjet.common/util/BetterFile.java
index c674810..c674810 100644
--- a/trunk/infrastructure/net.appjet.common/util/BetterFile.java
+++ b/infrastructure/net.appjet.common/util/BetterFile.java
diff --git a/trunk/infrastructure/net.appjet.common/util/ClassReload.java b/infrastructure/net.appjet.common/util/ClassReload.java
index 3fbc480..3fbc480 100644
--- a/trunk/infrastructure/net.appjet.common/util/ClassReload.java
+++ b/infrastructure/net.appjet.common/util/ClassReload.java
diff --git a/trunk/infrastructure/net.appjet.common/util/ExpiringMapping.java b/infrastructure/net.appjet.common/util/ExpiringMapping.java
index d4b9d5a..d4b9d5a 100644
--- a/trunk/infrastructure/net.appjet.common/util/ExpiringMapping.java
+++ b/infrastructure/net.appjet.common/util/ExpiringMapping.java
diff --git a/trunk/infrastructure/net.appjet.common/util/HttpServletRequestFactory.java b/infrastructure/net.appjet.common/util/HttpServletRequestFactory.java
index 4d7826a..4d7826a 100644
--- a/trunk/infrastructure/net.appjet.common/util/HttpServletRequestFactory.java
+++ b/infrastructure/net.appjet.common/util/HttpServletRequestFactory.java
diff --git a/trunk/infrastructure/net.appjet.common/util/LenientFormatter.java b/infrastructure/net.appjet.common/util/LenientFormatter.java
index 293dcdf..293dcdf 100644
--- a/trunk/infrastructure/net.appjet.common/util/LenientFormatter.java
+++ b/infrastructure/net.appjet.common/util/LenientFormatter.java
diff --git a/trunk/infrastructure/net.appjet.common/util/LimitedSizeMapping.java b/infrastructure/net.appjet.common/util/LimitedSizeMapping.java
index 331baca..331baca 100644
--- a/trunk/infrastructure/net.appjet.common/util/LimitedSizeMapping.java
+++ b/infrastructure/net.appjet.common/util/LimitedSizeMapping.java
diff --git a/trunk/infrastructure/net.appjet.oui/ConfigParam.java b/infrastructure/net.appjet.oui/ConfigParam.java
index 5029f28..5029f28 100644
--- a/trunk/infrastructure/net.appjet.oui/ConfigParam.java
+++ b/infrastructure/net.appjet.oui/ConfigParam.java
diff --git a/trunk/infrastructure/net.appjet.oui/FastJSON.scala b/infrastructure/net.appjet.oui/FastJSON.scala
index 60cfc48..60cfc48 100644
--- a/trunk/infrastructure/net.appjet.oui/FastJSON.scala
+++ b/infrastructure/net.appjet.oui/FastJSON.scala
diff --git a/trunk/infrastructure/net.appjet.oui/GeneratedConfigParam.java b/infrastructure/net.appjet.oui/GeneratedConfigParam.java
index 0986015..0986015 100644
--- a/trunk/infrastructure/net.appjet.oui/GeneratedConfigParam.java
+++ b/infrastructure/net.appjet.oui/GeneratedConfigParam.java
diff --git a/infrastructure/net.appjet.oui/config.scala b/infrastructure/net.appjet.oui/config.scala
new file mode 100644
index 0000000..2b0e47a
--- /dev/null
+++ b/infrastructure/net.appjet.oui/config.scala
@@ -0,0 +1,245 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+package net.appjet.oui;
+
+import scala.collection.mutable.HashMap;
+import java.util.regex.Pattern;
+import java.net.URL;
+import org.mortbay.jetty.servlet.Context;
+import org.mozilla.javascript.{Scriptable, ScriptableObject, Context => JSContext};
+
+import net.appjet.common.util.BetterFile;
+
+
+object config {
+ val values = new HashMap[String, String];
+ def stringOrElse(name: String, default: String): String = {
+ val v = values.getOrElse(name, default);
+ if (v != null) {
+ val m = propertiesPattern.matcher(v);
+ val sb = new StringBuffer();
+ while (m.find()) {
+ m.appendReplacement(sb, getClass.getDeclaredMethod(m.group(1), Array[Class[_]](): _*).invoke(this, Array[Class[_]](): _*).asInstanceOf[String]);
+ }
+ m.appendTail(sb);
+ sb.toString();
+ } else {
+ null;
+ }
+ }
+ def boolOrElse(name: String, default: Boolean) = values.get(name).map(_.matches("(?i)\\s*true\\s*")).getOrElse(default);
+ def intOrElse(name: String, default: Int) = values.get(name).map(Integer.parseInt(_)).getOrElse(default);
+ def longOrElse(name: String, default: Long) = values.get(name).map(java.lang.Long.parseLong(_)).getOrElse(default);
+
+ @ConfigParam("Read configuration options from this file before processing any command-line flags.")
+ { val argName = "file" }
+ def configFile = stringOrElse("configFile", null);
+
+ // configuation parameters
+ var specialDebug = false;
+
+ @ConfigParam("Enable additional logging output.")
+ def verbose = boolOrElse("verbose", false);
+
+ @ConfigParam("Activate \"developer\" mode.")
+ def devMode = boolOrElse("devMode", false);
+
+ @ConfigParam("Activate \"profiling\" mode.")
+ def profile = boolOrElse("profile", false);
+
+ @ConfigParam("Directory to use for storing appjet support files, logs, etc. This directory will be created if it does not exist and must be writeable by the user who runs appjet.jar. Defaults to current working directory.")
+ { val argName = "directory" }
+ def appjetHome = stringOrElse("appjetHome", "appjet");
+
+ @ConfigParam("Directory to use for storing built-in database (Apache Derby) files. Will be created if it doesn't exist. Defaults to [appjetHome]/db")
+ def derbyHome = stringOrElse("derbyHome", "[appjetHome]/derbydb");
+
+ @ConfigParam("Directory to use for storing appserver logs. Defaults to [appjetHome]/log/appserver")
+ { val argName = "directory" }
+ def logDir = stringOrElse("logDir", "[appjetHome]/log/appserver");
+
+ @ConfigParam("Optional alternative directory to load built-in libraries from. Used by AppJet platform hackers to develop and debug built-in libraries. Default: use built-in libraries.")
+ { val argName = "directory" }
+ def ajstdlibHome = stringOrElse("ajstdlibHome", null);
+
+ @ConfigParam("Optional directory to specify as the \"app home\".")
+ { val argName = "directory" }
+ def appHome = stringOrElse("appHome", "");
+
+ @ConfigParam("Whether to generate https URLs even if running locally behind HTTP (useful for Apache handling HTTPS)")
+ def useHttpsUrls = boolOrElse("useHttpsUrls", false);
+
+ @ConfigParam("Search path for modules imported via \"import\". Defaults to current working directory.")
+ { val argName = "dir1:dir2:..." }
+ def modulePath = stringOrElse("modulePath", null);
+ def moduleRoots =
+ Array.concat(Array("."), if (modulePath != null) modulePath.split(":") else Array[String](), Array(ajstdlibHome));
+
+ @ConfigParam("Where to read the static files from on the local filesystem. Don't specify this to read static files from the classpath/JAR.")
+ { val argName = "directory" }
+ def useVirtualFileRoot = stringOrElse("useVirtualFileRoot", null);
+
+ @ConfigParam("Directory to use for storing the temporary sessions file on shutdown. Will be created if it does not exist.")
+ { val argName = "directory" }
+ def sessionStoreDir = stringOrElse("sessionStoreDir", "[appjetHome]/sessions");
+
+ // performance tuning
+ @ConfigParam("Create this many runners before opening up the server.")
+ { val argName = "count" }
+ def preloadRunners = intOrElse("preloadRunners", 0);
+
+ @ConfigParam("Have this many JDBC connections available in the pool.")
+ { val argName = "count" }
+ def jdbcPoolSize = intOrElse("jdbcPoolSize", 10);
+ @ConfigParam("Max count of worker threads.")
+ { val argName = "num" }
+ def maxThreads = intOrElse("maxThreads", 250);
+
+ // specifying ports and such
+ def extractHostAndPort(s: String): (String, Int) =
+ if (s.indexOf(":") >= 0)
+ (s.split(":")(0), Integer.parseInt(s.split(":")(1)))
+ else
+ ("", Integer.parseInt(s))
+
+ @ConfigParam("Whether to show the port numbers to the outside world (false: assume ports visible from the outside are the default http/https ports)")
+ def hidePorts = boolOrElse("hidePorts", false);
+
+ @ConfigParam("[host:]port on which to serve the app. Default: 8080.")
+ { val argName = "[host:]port" }
+ def listen = stringOrElse("listen", "8080");
+ @GeneratedConfigParam
+ def listenHost = extractHostAndPort(listen)._1;
+ @GeneratedConfigParam
+ def listenPort = extractHostAndPort(listen)._2;
+
+ @ConfigParam("[host:]port on which to serve the app using SSL. Default: none.")
+ { val argName = "[host:]port" }
+ def listenSecure = stringOrElse("listenSecure", "0");
+ @GeneratedConfigParam
+ def listenSecureHost = extractHostAndPort(listenSecure)._1;
+ @GeneratedConfigParam
+ def listenSecurePort = extractHostAndPort(listenSecure)._2;
+
+ @ConfigParam("[host:]port:port on which to listen for monitoring. Default: none.")
+ { val argName = "[host:]primaryPort:secondaryPort" }
+ def listenMonitoring = stringOrElse("listenMonitoring", "0:0");
+ def extractHostAndPortPort(s: String): (String, Int, Int) = {
+ val spl = s.split(":", 3);
+ if (spl.length > 2)
+ (spl(0), Integer.parseInt(spl(1)), Integer.parseInt(spl(2)))
+ else
+ ("", Integer.parseInt(spl(0)), Integer.parseInt(spl(1)));
+ }
+ @GeneratedConfigParam
+ def listenMonitoringHost = extractHostAndPortPort(listenMonitoring)._1;
+ @GeneratedConfigParam
+ def listenMonitoringPrimaryPort = extractHostAndPortPort(listenMonitoring)._2;
+ @GeneratedConfigParam
+ def listenMonitoringSecondaryPort = extractHostAndPortPort(listenMonitoring)._3;
+
+ @ConfigParam("[host:]port on which to listen for RPCs (via SARS). Default: none.")
+ { val argName = "[host:]port" }
+ def listenSars = stringOrElse("listenSars", "0");
+ @GeneratedConfigParam
+ def listenSarsHost = extractHostAndPort(listenSars)._1;
+ @GeneratedConfigParam
+ def listenSarsPort = extractHostAndPort(listenSars)._2;
+
+ // Licensing
+ @ConfigParam("Private key for generating license keys.")
+ { val argName = "pathToKey" }
+ def licenseGeneratorKey = stringOrElse("licenseGeneratorKey", null);
+
+ // SARS
+ @ConfigParam("SARS auth key. Default: \"appjet\".")
+ { val argName = "authkey" }
+ def sarsAuthKey = stringOrElse("sarsAuthKey", "appjet");
+
+ // SSL
+ @ConfigParam("[SSL] Keystore location. Default: appjetHome/sslkeystore.")
+ { val argName = "keystore" }
+ def sslKeyStore = stringOrElse("sslKeyStore", appjetHome+"/sslkeystore");
+ def sslKeyStore_isSet = values.contains("sslKeyStore");
+ @ConfigParam("[SSL] Key password. Default: same as store password.")
+ { val argName = "password" }
+ def sslKeyPassword = stringOrElse("sslKeyPassword", "[sslStorePassword]");
+ @ConfigParam("[SSL] Store password. Default: 'appjet'.")
+ { val argName = "password" }
+ def sslStorePassword = stringOrElse("sslStorePassword", "appjet");
+
+ // email
+ @ConfigParam("host:port of mail server to use for sending email. Default: localhost:25.")
+ { val argName = "host:port" }
+ def smtpServer = stringOrElse("smtpServer", "localhost:25");
+ def smtpServerHost = extractHostAndPort(smtpServer)._1;
+ def smtpServerPort = extractHostAndPort(smtpServer)._2;
+ @ConfigParam("username for authentication to mail server. Default: no authentication.")
+ { val argName = "username" }
+ def smtpUser = stringOrElse("smtpUser", "");
+ @ConfigParam("password for authentication to mail server. Default: no authentication.")
+ { val argName = "password" }
+ def smtpPass = stringOrElse("smtpPass", "");
+
+ // comet
+ @ConfigParam("prefix for all comet requests. Required to use Comet system.")
+ { val argName = "path" }
+ def transportPrefix = stringOrElse("transportPrefix", null);
+ @ConfigParam("Use a subdomain for all comet requests.")
+ def transportUseWildcardSubdomains = boolOrElse("transportUseWildcardSubdomains", false);
+ @ConfigParam("Don't use short polling, ever.")
+ def disableShortPolling = boolOrElse("disableShortPolling", false);
+
+ // helpers
+ val allProperties =
+ for (m <- getClass.getDeclaredMethods() if (m.getAnnotation(classOf[ConfigParam]) != null || m.getAnnotation(classOf[GeneratedConfigParam]) != null))
+ yield m;
+ val configParamNames =
+ for (m <- allProperties if m.getAnnotation(classOf[ConfigParam]) != null) yield m.getName
+ lazy val allPropertiesMap =
+ Map((for (m <- allProperties) yield ((m.getName, () => m.invoke(this)))): _*);
+ val propertiesPattern = Pattern.compile("\\[("+allProperties.map(x => "(?:"+x.getName()+")").mkString("|")+")\\]");
+
+ override def toString() =
+ (allProperties.map(m => m.getName()+" -> "+m.invoke(this)) ++
+ values.keys.toList.filter(! allPropertiesMap.contains(_)).map(k => k+" -> "+values(k))).mkString("[Config ", ", ", "]");
+ def print {
+ for (m <- allProperties) {
+ println(m.getName() + " -> " + m.invoke(this));
+ }
+ for ((k, v) <- values if (! allPropertiesMap.contains(k))) {
+ println(k + " -> " + v);
+ }
+ }
+ def configObject(globalScope: Scriptable) =
+ new ScriptableAdapter {
+ val keys = (Set.empty[Object] ++ allProperties.map(m => m.getName) ++ values.keySet).toList.toArray;
+ override def get(n: String, start: Scriptable) =
+ allPropertiesMap.getOrElse(n, () => values.getOrElse(n, JSContext.getUndefinedValue()))();
+ override def put(n: String, start: Scriptable, value: Object) =
+ values(n) = value.toString();
+ override def getIds() = keys;
+ override def getPrototype() = ScriptableObject.getObjectPrototype(globalScope);
+ override def has(n: String, start: Scriptable) =
+ allPropertiesMap.contains(n) || values.contains(n);
+ override def getDefaultValue(hint: Class[_]) = config.toString();
+ }
+}
+
+object global {
+ var context: Context = null;
+}
diff --git a/trunk/infrastructure/net.appjet.oui/dynamicvar.scala b/infrastructure/net.appjet.oui/dynamicvar.scala
index b1f8c2e..b1f8c2e 100644
--- a/trunk/infrastructure/net.appjet.oui/dynamicvar.scala
+++ b/infrastructure/net.appjet.oui/dynamicvar.scala
diff --git a/trunk/infrastructure/net.appjet.oui/encryption.scala b/infrastructure/net.appjet.oui/encryption.scala
index 92d463b..92d463b 100644
--- a/trunk/infrastructure/net.appjet.oui/encryption.scala
+++ b/infrastructure/net.appjet.oui/encryption.scala
diff --git a/infrastructure/net.appjet.oui/execution.scala b/infrastructure/net.appjet.oui/execution.scala
new file mode 100644
index 0000000..dc17c29
--- /dev/null
+++ b/infrastructure/net.appjet.oui/execution.scala
@@ -0,0 +1,660 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+package net.appjet.oui;
+
+import java.net.URLDecoder;
+import java.util.Enumeration;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.servlet.http.{HttpServletRequest, HttpServletResponse, HttpServlet};
+
+import scala.collection.mutable.{ListBuffer, LinkedHashSet, HashMap, ArrayBuffer};
+import scala.collection.immutable.Map;
+import scala.collection.jcl.Conversions;
+
+import org.mozilla.javascript.{Scriptable, Context, Function, ScriptableObject, JavaScriptException};
+import org.mortbay.jetty.RetryRequest;
+
+import net.appjet.bodylock.{BodyLock, Executable, JSRuntimeException, JSCompileException};
+import net.appjet.common.util.{HttpServletRequestFactory, BetterFile};
+
+import Util.enumerationToRichEnumeration;
+
+// Removed due to licensing issues; REMOVED_COS_OF_COS
+// import com.oreilly.servlet.MultipartFilter;
+
+class RequestWrapper(val req: HttpServletRequest) {
+ req.setCharacterEncoding("UTF-8");
+// REMOVED_COS_OF_COS ... ?
+// private lazy val parameterNames =
+// (for (i <- Conversions.convertSet(req.getParameterMap.keySet().asInstanceOf[java.util.Set[String]])) yield i).toList.toArray
+// private def parameterValues(k: String) = req.getParameterValues(k);
+ def headerCapitalize(s: String) =
+ s.split("-").map(
+ s =>
+ if (s == null || s.length < 1) s
+ else s.substring(0, 1).toUpperCase()+s.substring(1).toLowerCase()
+ ).mkString("-");
+ def isFake = false;
+ lazy val path = req.getRequestURI();
+ lazy val host = {
+ val hostFromHeader = req.getHeader("Host");
+ if ((hostFromHeader ne null) && hostFromHeader.indexOf(':') >= 0) {
+ // fix the port, which may be wrong in Host header (e.g. IE 6)
+ hostFromHeader.substring(0, hostFromHeader.indexOf(':')) + ":" +
+ req.getLocalPort;
+ }
+ else {
+ hostFromHeader;
+ }
+ }
+ lazy val query = req.getQueryString();
+ lazy val method = req.getMethod();
+ lazy val scheme = req.getScheme();
+ lazy val clientAddr = req.getRemoteAddr();
+
+ def decodeWwwFormUrlencoded(content: => String): Map[String, Array[String]] = {
+ val map = new HashMap[String, ArrayBuffer[String]];
+ if (content != null) {
+ for (pair <- content.split("&").map(_.split("=", 2))) {
+ val key = URLDecoder.decode(pair(0), "UTF-8");
+ val list = map.getOrElseUpdate(key, new ArrayBuffer[String]);
+ if (pair.length > 1) {
+ list += URLDecoder.decode(pair(1), "UTF-8");
+ }
+ }
+ }
+ Map((for ((k, v) <- map) yield (k, v.toArray)).toSeq: _*);
+ }
+
+ def postParams = decodeWwwFormUrlencoded(content.asInstanceOf[String]);
+ def getParams = decodeWwwFormUrlencoded(query);
+
+ lazy val params_i = {
+ if (contentType != null && contentType.startsWith("application/x-www-form-urlencoded")) {
+ if (req.getAttribute("ajcache_parameters") == null) {
+ req.setAttribute("ajcache_parameters",
+ Map((for (k <- (postParams.keys ++ getParams.keys).toList)
+ yield (k, postParams.getOrElse(k, Array[String]()) ++
+ getParams.getOrElse(k, Array[String]()))).toSeq: _*));
+ }
+ req.getAttribute("ajcache_parameters").asInstanceOf[Map[String, Array[String]]];
+ } else {
+ Conversions.convertMap(req.getParameterMap().asInstanceOf[java.util.Map[String, Array[String]]]);
+ }
+ }
+
+ def params(globalScope: Scriptable) = new ScriptableFromMapOfStringArrays(
+ globalScope,
+ params_i.keys.toList,
+ params_i.get(_),
+ false);
+ def headers(globalScope: Scriptable) = new ScriptableFromMapOfStringArrays(
+ globalScope,
+ req.getHeaderNames().asInstanceOf[Enumeration[String]]
+ .map(headerCapitalize).toList,
+ h => h match {
+ case "Host" => Some(Array(host));
+ case hh => Some(Util.enumerationToArray(req.getHeaders(headerCapitalize(hh)).asInstanceOf[Enumeration[String]])) },
+ true);
+ lazy val protocol = req.getProtocol();
+ lazy val contentType = req.getHeader("Content-Type");
+ lazy val postParamsInBody = contentType != null && contentType.startsWith("application/x-www-form-urlencoded");
+ lazy val content =
+ if ((contentType != null && contentType.startsWith("text/")) || postParamsInBody) {
+ val reader = req.getReader();
+ if (reader != null)
+ BetterFile.getReaderString(req.getReader());
+ else
+ null;
+ } else {
+ val stream = req.getInputStream();
+ if (stream != null)
+ BetterFile.getStreamBytes(req.getInputStream());
+ else
+ null;
+ }
+
+ // Depends on cos.jar; REMOVED_COS_OF_COS
+ def files(globalScope: Scriptable): Object = {
+// if (! req.isInstanceOf[com.oreilly.servlet.MultipartWrapper]) {
+ new ScriptableAdapter();
+// } else {
+// val r = req.asInstanceOf[com.oreilly.servlet.MultipartWrapper];
+// val fileScriptables = new HashMap[String, Scriptable]();
+// val fileBytes = new HashMap[String, Array[byte]]();
+// new ScriptableFromMapOfScriptableArrays(globalScope,
+// r.getFileNames().asInstanceOf[Enumeration[String]].toList,
+// name => {
+// if (r.getFile(name) == null)
+// None
+// else
+// Some(Array(fileScriptables.getOrElseUpdate(name,
+// new ScriptableFromMapOfArrays[Object](globalScope,
+// Set("contentType", "filesystemName", "bytes").toSeq,
+// _ match {
+// case "contentType" => Some(Array(r.getContentType(name)));
+// case "filesystemName" =>
+// Some(Array(r.getFilesystemName(name)));
+// case "bytes" =>
+// Some(Array(Context.javaToJS(fileBytes.getOrElseUpdate(name,
+// BetterFile.getFileBytes(r.getFile(name))), globalScope)));
+// case _ => None;
+// },
+// true))))
+// },
+// true);
+// }
+ }
+}
+
+class ResponseWrapper(val res: HttpServletResponse) {
+ private lazy val outputStrings = new ListBuffer[String];
+ private lazy val outputBytes = new ListBuffer[Array[byte]];
+ private var statusCode = 200;
+ private var contentType = "text/html";
+ private var redirect: String = null;
+ private lazy val headers = new LinkedHashSet[(String, String, HttpServletResponse => Unit)] {
+ def removeAll(k: String) {
+ this.foreach(x => if (x._1 == k) remove(x));
+ }
+ }
+
+ private[oui] def overwriteOutputWithError(code: Int, errorStr: String) {
+ statusCode = code;
+ outputStrings.clear();
+ outputStrings += errorStr;
+ outputBytes.clear();
+ headers.clear();
+ Util.noCacheHeaders.foreach(x => headers += (x._1, x._2, res => res.setHeader(x._1, x._2)));
+ redirect = null;
+ contentType = "text/html; charset=utf-8";
+ }
+
+ def reset() {
+ outputStrings.clear();
+ outputBytes.clear();
+ redirect = null;
+ headers.clear();
+ Util.noCacheHeaders.foreach(x => headers += (x._1, x._2, res => res.setHeader(x._1, x._2)));
+ statusCode = 200;
+ contentType = "text/html; charset=utf-8";
+ }
+ def error(code: Int, errorStr: String) {
+ overwriteOutputWithError(code, errorStr);
+ stop();
+ }
+ def stop() {
+ throw AppGeneratedStopException;
+ }
+
+ def write(s: String) {
+ outputStrings += s;
+ }
+ def getOutput() = outputStrings.mkString("");
+ def writeBytes(bytes: String) {
+ val a = new Array[byte](bytes.length());
+ bytes.getBytes(0, bytes.length(), a, 0);
+ outputBytes += a;
+ }
+ def writeBytes(bytes: Array[Byte]) {
+ outputBytes += bytes;
+ }
+ def getOutputBytes() = outputBytes.flatMap(x => x).toArray
+ def setContentType(s: String) {
+ contentType = s;
+ }
+ def getCharacterEncoding() = {
+ res.setContentType(contentType);
+ res.getCharacterEncoding();
+ }
+ def setStatusCode(sc: Int) {
+ statusCode = sc;
+ }
+ def getStatusCode() = statusCode;
+ def redirect(loc: String) {
+ statusCode = 302;
+ redirect = loc;
+ stop();
+ }
+ def setHeader(name: String, value: String) {
+ headers += ((name, value, res => res.setHeader(name, value)));
+ }
+ def addHeader(name: String, value: String) {
+ headers += ((name, value, res => res.addHeader(name, value)));
+ }
+ def getHeader(name: String) = {
+ headers.filter(_._1 == name).map(_._2).toSeq.toArray;
+ }
+ def removeHeader(name: String) {
+ headers.removeAll(name);
+ }
+
+ var gzipOutput = false;
+ def setGzip(gzip: Boolean) {
+ gzipOutput = gzip;
+ }
+
+ def print() {
+ if (redirect != null && statusCode == 302) {
+ headers.foreach(_._3(res));
+ res.sendRedirect(redirect);
+ } else {
+ res.setStatus(statusCode);
+ res.setContentType(contentType);
+ headers.foreach(_._3(res));
+ if (gzipOutput) res.setHeader("Content-Encoding", "gzip");
+ if (outputStrings.length > 0) {
+ var bytes: Seq[Array[Byte]] = outputStrings.map(_.getBytes(res.getCharacterEncoding()));
+ if (gzipOutput) bytes = List(Util.gzip(Array.concat(bytes:_*)));
+ res.setContentLength((bytes :\ 0) {_.length + _});
+ bytes.foreach(res.getOutputStream.write(_));
+ } else if (outputBytes.length > 0) {
+ var bytes: Seq[Array[Byte]] = outputBytes;
+ if (gzipOutput) bytes = List(Util.gzip(Array.concat(bytes:_*)));
+ res.setContentLength((bytes :\ 0) {_.length + _});
+ bytes.foreach(res.getOutputStream.write(_));
+ }
+ }
+ }
+}
+
+class ScriptableAdapter extends Scriptable {
+ private def unsupported() = throw UnsupportedOperationException;
+ def delete(index: Int) { unsupported(); }
+ def delete(name: String) { unsupported(); }
+ def get(index: Int, start: Scriptable): Object = Context.getUndefinedValue();
+ def get(name: String, start: Scriptable): Object = Context.getUndefinedValue();
+ def getClassName() = getClass.getName();
+ def getDefaultValue(hint: Class[_]) = "[ScriptableAdapter]";
+ def getIds(): Array[Object] = Array[Object]();
+ def getParentScope: Scriptable = null;
+ def getPrototype: Scriptable = null;
+ def has(index: Int, start: Scriptable): Boolean = false;
+ def has(name: String, start: Scriptable): Boolean = false;
+ def hasInstance(instance: Scriptable): Boolean = false;
+ def put(index: Int, start: Scriptable, value: Object) { unsupported(); }
+ def put(name: String, start: Scriptable, value: Object) { unsupported(); }
+ def setParentScope(parent: Scriptable) { unsupported(); }
+ def setPrototype(prototype: Scriptable) { unsupported(); }
+}
+
+class ScriptableFromMapOfStringArrays(globalScope: Scriptable,
+ keys: Seq[String], values: String => Option[Array[String]],
+ zeroMeansNone: Boolean) extends ScriptableFromMapOfArrays[String](
+ globalScope, keys, values, zeroMeansNone);
+
+class ScriptableFromMapOfScriptableArrays(globalScope: Scriptable,
+ keys: Seq[String], values: String => Option[Array[Scriptable]],
+ zeroMeansNone: Boolean) extends ScriptableFromMapOfArrays[Scriptable](
+ globalScope, keys, values, zeroMeansNone);
+
+
+class ScriptableFromMapOfArrays[V <: Object](globalScope: Scriptable,
+ keys: Seq[String], values: String => Option[Array[V]],
+ zeroMeansNone: Boolean) extends ScriptableAdapter {
+ override def get(n: String, start: Scriptable): Object = {
+ val v = values(n);
+ if (v.isEmpty || (zeroMeansNone && v.get.length == 0)) {
+ Context.getUndefinedValue();
+ } else if (v.get.length == 1) {
+ v.get.apply(0);
+ } else {
+ Context.getCurrentContext().newArray(globalScope, v.get.map(x => x.asInstanceOf[Object]));
+ }
+ }
+ override def getIds(): Array[Object] = keys.toArray[Object];
+ override def getPrototype = ScriptableObject.getObjectPrototype(globalScope);
+ override def has(n: String, start: Scriptable): Boolean = ! (values(n).isEmpty || (zeroMeansNone && values(n).get.length == 0));
+}
+
+object AppGeneratedStopException extends JSRuntimeException("User-generated stop.", null);
+class NoHandlerException(msg: String) extends JSRuntimeException(msg, null);
+object UnsupportedOperationException extends JSRuntimeException("Unsupported operation.", null);
+
+object ExecutionContextUtils {
+ val uniqueIds = new AtomicLong(0);
+
+ val ecVar = new NoninheritedDynamicVariable[ExecutionContext](null);
+ def withContext[E](ec: ExecutionContext)(block: => E): E = {
+ ecVar.withValue(ec)(block);
+ }
+
+ def currentContext = ecVar.value;
+}
+
+case class ExecutionContext(
+ val request: RequestWrapper,
+ val response: ResponseWrapper,
+ var runner: ScopeReuseManager.Runner) {
+ val asyncs = new ListBuffer[Function];
+ lazy val attributes = new HashMap[String, Any];
+ var completed = false;
+ lazy val executionId = ""+ExecutionContextUtils.uniqueIds.incrementAndGet();
+ var result: AnyRef = null;
+}
+
+object CometSupport {
+ trait CometHandler {
+ def handleCometRequest(req: HttpServletRequest, res: HttpServletResponse);
+ }
+ var cometHandler: CometHandler = null;
+}
+
+class OuiServlet extends HttpServlet {
+ override def doGet(req: HttpServletRequest, res: HttpServletResponse) {
+ execute(req, res);
+ }
+
+ override def doPost(req: HttpServletRequest, res: HttpServletResponse) {
+ execute(req, res);
+ }
+
+ override def doHead(req: HttpServletRequest, res: HttpServletResponse) {
+ execute(req, res);
+ }
+
+ override def doPut(req: HttpServletRequest, res: HttpServletResponse) {
+ execute(req, res);
+ }
+
+ override def doDelete(req: HttpServletRequest, res: HttpServletResponse) {
+ execute(req, res);
+ }
+
+ override def doTrace(req: HttpServletRequest, res: HttpServletResponse) {
+ execute(req, res);
+ }
+
+ override def doOptions(req: HttpServletRequest, res: HttpServletResponse) {
+ execute(req, res);
+ }
+
+ def execute(req: HttpServletRequest, res: HttpServletResponse) {
+ if (req.getProtocol() == "HTTP/1.1" && req.getHeader("Host") == null) {
+ res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid HTTP/1.1 request: No \"Host\" header found.");
+ } else if (config.transportPrefix != null && req.getRequestURI().startsWith(config.transportPrefix)) {
+ val runner = ScopeReuseManager.getRunner;
+ val ec = new ExecutionContext(new RequestWrapper(req), new ResponseWrapper(res), runner);
+ req.setAttribute("executionContext", ec);
+ req.setAttribute("isServerPushConnection", true);
+ try {
+ CometSupport.cometHandler.handleCometRequest(req, res);
+ } catch {
+ case e: RetryRequest => {
+ ec.runner = null;
+ ScopeReuseManager.freeRunner(runner);
+ throw e;
+ }
+ case _ => {};
+ }
+ try {
+ ec.response.print();
+ execution.onprint(ec, BodyLock.subScope(runner.mainScope));
+ } finally {
+ ec.runner = null;
+ ScopeReuseManager.freeRunner(runner);
+ }
+ } else {
+ execution.execute(req, res);
+ }
+ }
+}
+
+object execution {
+ // maybe find a better place for this?
+ { // initialize ajstdlib
+ val c = Class.forName("net.appjet.ajstdlib.ajstdlib$");
+ val m = c.getDeclaredMethod("init");
+ val o = c.getDeclaredField("MODULE$");
+ m.invoke(o.get(null));
+ }
+
+ val requestLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onrequest.js"));
+ val errorLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onerror.js"));
+ val printLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onprint.js"));
+ val syntaxErrorLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "syntaxerror.js"));
+ val onSyntaxErrorLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onsyntaxerror.js"));
+ val sarsLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onsars.js"));
+ val scheduledTaskLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onscheduledtask.js"));
+ def requestExecutable = requestLib.executable;
+ def errorExecutable = errorLib.executable;
+ def printExecutable = printLib.executable;
+ def syntaxErrorExecutable = syntaxErrorLib.executable;
+ def onSyntaxErrorExecutable = onSyntaxErrorLib.executable;
+ def sarsExecutable = sarsLib.executable;
+ def scheduledTaskExecutable = scheduledTaskLib.executable;
+
+ def postSuccessfulRun(ec: ExecutionContext) {
+ try {
+ for (f <- ec.asyncs) {
+ BodyLock.runInContext({ cx =>
+ f.call(cx, f.getParentScope(), ec.runner.mainScope, Array[Object]());
+ });
+ }
+ } catch {
+ case e => exceptionlog(e);
+ }
+ }
+
+ def onprint(ec: ExecutionContext, scope: Scriptable) {
+ try {
+// ec.runner.globalScope.put("_appjetcontext_", ec.runner.globalScope, ec);
+ printExecutable.execute(scope);
+ } catch {
+ case e => { exceptionlog(e); } // shrug. this was best-effort anyway.
+ }
+ }
+
+ def execute(req: HttpServletRequest, res: HttpServletResponse) {
+ val runner = try {
+ ScopeReuseManager.getRunner;
+ } catch {
+ case e: JSCompileException => {
+ val r = ScopeReuseManager.getEmpty { r =>
+ syntaxErrorExecutable.execute(r.globalScope)
+ }
+ val ec = ExecutionContext(new RequestWrapper(req), new ResponseWrapper(res), r);
+// r.globalScope.put("_appjetcontext_", r.globalScope, ec);
+ ExecutionContextUtils.withContext(ec) {
+ ec.attributes("error") = e;
+ ec.result = onSyntaxErrorExecutable.execute(r.globalScope);
+ ec.response.print();
+ }
+ return;
+ }
+ }
+ val ec = ExecutionContext(new RequestWrapper(req), new ResponseWrapper(res), runner);
+ val startTime = executionlatencies.time;
+ execute(ec,
+ (sc: Int, msg: String) => {
+ ec.response.overwriteOutputWithError(sc, msg);
+ },
+ () => { executionlatencies.log(Map(
+ "time" -> (executionlatencies.time - startTime)));
+ ec.response.print() },
+ () => { ScopeReuseManager.freeRunner(runner) },
+ None);
+ }
+
+ def errorToHTML(e: Throwable) = {
+ val trace = new java.io.StringWriter();
+ e.printStackTrace(new java.io.PrintWriter(trace));
+ trace.toString().split("\n").mkString("<br>\n");
+ }
+ def execute(ec: ExecutionContext,
+ errorHandler: (Int, String) => Unit,
+ doneWritingHandler: () => Unit,
+ completedHandler: () => Unit,
+ customExecutable: Option[Executable]) =
+ ExecutionContextUtils.withContext(ec) {
+// ec.runner.globalScope.put("_appjetcontext_", ec.runner.globalScope, ec);
+ val runScope = BodyLock.subScope(ec.runner.mainScope);
+ try {
+ ec.result = customExecutable.getOrElse(requestExecutable).execute(runScope);
+ ec.completed = true;
+ } catch {
+ case AppGeneratedStopException => { ec.completed = true; }
+ case e: NoHandlerException => errorHandler(500, "No request handler is defined.");
+ case e: RetryRequest => { completedHandler(); throw e; }
+ case e => {
+ ec.attributes("error") = e;
+ try {
+ ec.result = errorExecutable.execute(runScope);
+ } catch {
+ case AppGeneratedStopException => { }
+ case nhe: NoHandlerException => {
+ exceptionlog(e);
+ e.printStackTrace();
+ errorHandler(500, "An error occurred and no error handler is defined.");
+ }
+ case e2 => {
+ exceptionlog(e); exceptionlog(e2);
+ val etext = e2 match {
+ case jse: JavaScriptException => { (jse.getValue() match {
+ case ne: org.mozilla.javascript.IdScriptableObject => ne.get("message", ne)
+ case e => e.getClass.getName
+ }) + "<br>\n" + errorToHTML(jse); }
+ case _ => errorToHTML(e2);
+ }
+ errorHandler(
+ 500,
+ "You like apples? An error occurred in the error handler while handling an error. How do you like <i>them</i> apples?<br>\n"+
+ etext+"<br>\nCaused by:<br>\n"+errorToHTML(e));
+ }
+ }
+ }
+ }
+ onprint(ec, runScope);
+ doneWritingHandler();
+ if (ec.completed && ! ec.asyncs.isEmpty) {
+ main.server.getThreadPool().dispatch(new Runnable {
+ def run() {
+ postSuccessfulRun(ec);
+ completedHandler();
+ }
+ });
+ } else {
+ completedHandler();
+ }
+ }
+
+ def runOutOfBandSimply(executable: Executable,
+ props: Option[Map[String, Any]]) = {
+ // there must be a context already.
+ val currentContext = ExecutionContextUtils.currentContext;
+ val request =
+ if (currentContext != null) {
+ currentContext.request;
+ } else {
+ val fakeHeaders = scala.collection.jcl.Conversions.convertMap(
+ new java.util.HashMap[String, String]);
+ fakeHeaders("Host") = "unknown.local";
+ new RequestWrapper(HttpServletRequestFactory.createRequest(
+ "/", fakeHeaders.underlying, "GET", null)) {
+ override val isFake = true;
+ }
+ }
+ val response =
+ if (currentContext != null && currentContext.response != null) {
+ currentContext.response;
+ } else {
+ new ResponseWrapper(null);
+ }
+ val runner =
+ if (currentContext != null) {
+ (false, currentContext.runner);
+ } else {
+ (true, ScopeReuseManager.getRunner);
+ }
+ val ec = new ExecutionContext(request, response, runner._2)
+ if (props.isDefined) {
+ for ((k, v) <- props.get) {
+ ec.attributes(k) = v;
+ }
+ }
+ try {
+ ExecutionContextUtils.withContext(ec) {
+ executable.execute(BodyLock.subScope(ec.runner.mainScope));
+ }
+ } finally {
+ if (runner._1) {
+ ScopeReuseManager.freeRunner(runner._2);
+ }
+ }
+ }
+
+ def runOutOfBand(executable: Executable, name: String,
+ props: Option[Map[String, Any]],
+ onFailure: Any => Unit) = {
+ var ec: ExecutionContext = null;
+ try {
+ val runner = ScopeReuseManager.getRunner;
+ val currentContext = ExecutionContextUtils.currentContext;
+ val request =
+ if (currentContext != null) {
+ currentContext.request;
+ } else {
+ val fakeHeaders = scala.collection.jcl.Conversions.convertMap(
+ new java.util.HashMap[String, String]);
+ fakeHeaders("Host") = "unknown.local";
+ new RequestWrapper(HttpServletRequestFactory.createRequest(
+ "/", fakeHeaders.underlying, "GET", null)) {
+ override val isFake = true;
+ }
+ }
+ val response =
+ if (currentContext != null && currentContext.response != null) {
+ new ResponseWrapper(currentContext.response.res);
+ } else {
+ new ResponseWrapper(null);
+ }
+ ec = new ExecutionContext(request, response, runner);
+ if (props.isDefined)
+ for ((k, v) <- props.get) {
+ ec.attributes(k) = v;
+ }
+ execution.execute(ec,
+ (sc: Int, msg: String) => { println(name+" execution failed with error: "+sc+"\n"+msg); onFailure((sc, msg)); },
+ () => { },
+ () => { ScopeReuseManager.freeRunner(runner) },
+ Some(executable));
+ if (ec.response != null && ec.response.getStatusCode() != 200) {
+ println(name+" execution failed with non-200 response: "+ec.response.getStatusCode());
+ onFailure((ec.response.getStatusCode, ec.response.getOutput()));
+ }
+ ec;
+ } catch {
+ case e: JSCompileException => {
+ val r = ScopeReuseManager.getEmpty { r =>
+ execution.syntaxErrorExecutable.execute(r.globalScope);
+ }
+ val ec = ExecutionContext(null, null, r);
+// r.globalScope.put("_appjetcontext_", r.globalScope, ec);
+ ExecutionContextUtils.withContext(ec) {
+ ec.attributes("error") = e;
+ ec.result = execution.onSyntaxErrorExecutable.execute(r.globalScope);
+ onFailure(e);
+ }
+ ec;
+ }
+ case e => {
+ println(name+" execution failed with error."); onFailure(e); ec;
+ }
+ }
+ }
+}
diff --git a/trunk/infrastructure/net.appjet.oui/files.scala b/infrastructure/net.appjet.oui/files.scala
index 3df5c1c..3df5c1c 100644
--- a/trunk/infrastructure/net.appjet.oui/files.scala
+++ b/infrastructure/net.appjet.oui/files.scala
diff --git a/trunk/infrastructure/net.appjet.oui/logging.scala b/infrastructure/net.appjet.oui/logging.scala
index 9c384d2..9c384d2 100644
--- a/trunk/infrastructure/net.appjet.oui/logging.scala
+++ b/infrastructure/net.appjet.oui/logging.scala
diff --git a/infrastructure/net.appjet.oui/main.scala b/infrastructure/net.appjet.oui/main.scala
new file mode 100644
index 0000000..67c1f6f
--- /dev/null
+++ b/infrastructure/net.appjet.oui/main.scala
@@ -0,0 +1,388 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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 "AS-IS" 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.
+ */
+
+package net.appjet.oui;
+
+import net.appjet.bodylock.{BodyLock, Executable};
+
+import java.io.File;
+import java.util.{Properties, Date};
+import java.lang.annotation.Annotation;
+import java.text.SimpleDateFormat;
+
+import scala.collection.mutable.{HashMap, SynchronizedMap, HashSet};
+import scala.collection.jcl.{IterableWrapper, Conversions};
+
+import org.mortbay.thread.QueuedThreadPool;
+import org.mortbay.jetty.servlet.{Context, HashSessionIdManager, FilterHolder, ServletHolder};
+import org.mortbay.jetty.handler.{HandlerCollection, RequestLogHandler, HandlerList};
+import org.mortbay.jetty.{Server, NCSARequestLog, Request, Response};
+import org.mortbay.servlet.GzipFilter;
+
+// removed due to license restrictions; REMOVED_COS_OF_COS
+// import com.oreilly.servlet.MultipartFilter;
+
+import net.appjet.common.util.{BetterFile, HttpServletRequestFactory};
+import net.appjet.common.cli._;
+import net.appjet.bodylock.JSCompileException;
+
+import Util.enumerationToRichEnumeration;
+
+object main {
+ val startTime = new java.util.Date();
+
+ def quit(status: Int) {
+ java.lang.Runtime.getRuntime().halt(status);
+ }
+
+ def setupFilesystem() {
+ val logdir = new File(config.logDir+"/backend/access");
+ if (! logdir.isDirectory())
+ if (! logdir.mkdirs())
+ quit(1);
+ }
+
+ val options =
+ for (m <- config.allProperties if (m.getAnnotation(classOf[ConfigParam]) != null)) yield {
+ val cp = m.getAnnotation(classOf[ConfigParam])
+ new CliOption(m.getName(), cp.value(), if (cp.argName().length > 0) Some(cp.argName()) else None);
+ }
+
+ def printUsage() {
+ println("\n--------------------------------------------------------------------------------");
+ println("usage:");
+ println((new CliParser(options)).usage);
+ println("--------------------------------------------------------------------------------\n");
+ }
+
+ def extractOptions(args: Array[String]) {
+ val parser = new CliParser(options);
+ val opts =
+ try {
+ parser.parseOptions(args)._1;
+ } catch {
+ case e: ParseException => {
+ println("error: "+e.getMessage());
+ printUsage();
+ System.exit(1);
+ null;
+ }
+ }
+ if (opts.contains("configFile")) {
+ val p = new Properties();
+ p.load(new java.io.FileInputStream(opts("configFile")));
+ extractOptions(p);
+ }
+ for ((k, v) <- opts) {
+ config.values(k) = v;
+ }
+ }
+
+ def extractOptions(props: Properties) {
+ for (k <- for (o <- props.propertyNames()) yield o.asInstanceOf[String]) {
+ config.values(k) = props.getProperty(k);
+ }
+ }
+
+ val startupExecutable = (new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onstartup.js"))).executable;
+ def runOnStartup() {
+ execution.runOutOfBand(startupExecutable, "Startup", None, { error =>
+ error match {
+ case e: JSCompileException => { }
+ case e: Throwable => { e.printStackTrace(); }
+ case (sc: Int, msg: String) => { println(msg); }
+ case x => println(x);
+ }
+ System.exit(1);
+ });
+ }
+
+ lazy val shutdownExecutable = (new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onshutdown.js"))).executable;
+ def runOnShutdown() {
+ execution.runOutOfBand(shutdownExecutable, "Shutdown", None, { error =>
+ error match {
+ case e: JSCompileException => { }
+ case e: Throwable => { }
+ case (sc: Int, msg: String) => { println(msg); }
+ case x => println(x);
+ }
+ });
+ }
+
+ def runOnSars(q: String) = {
+ val ec = execution.runOutOfBand(execution.sarsExecutable, "SARS", Some(Map("sarsRequest" -> q)), { error =>
+ error match {
+ case e: JSCompileException => { throw e; }
+ case e: Throwable => { exceptionlog(e); throw e; }
+ case (sc: Int, msg: String) => { println(msg); throw new RuntimeException(""+sc+": "+msg) }
+ case x => { println(x); throw new RuntimeException(x.toString()) }
+ }
+ });
+ ec.attributes.get("sarsResponse").map(_.toString());
+ }
+
+ def stfu() {
+ System.setProperty("org.mortbay.log.class", "net.appjet.oui.STFULogger");
+ System.setProperty("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
+ System.setProperty("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "OFF");
+ }
+ var server: Server = null;
+ var sarsServer: net.appjet.common.sars.SarsServer = null;
+
+ var loggers = new HashSet[GenericLogger];
+ def main(args: Array[String]) {
+ val etherpadProperties = getClass.getResource("/etherpad.properties");
+ if (etherpadProperties != null) {
+ val p = new Properties();
+ p.load(etherpadProperties.openStream);
+ extractOptions(p);
+ }
+ extractOptions(args);
+
+ if (! config.verbose)
+ stfu();
+ setupFilesystem();
+ if (config.devMode)
+ config.print;
+ if (config.profile)
+ profiler.start();
+ if (config.listenMonitoring != "0:0")
+ monitoring.startMonitoringServer();
+
+ // this needs a better place.
+ if (config.devMode)
+ BodyLock.map = Some(new HashMap[String, String] with SynchronizedMap[String, String]);
+
+ server = new Server();
+ if (config.maxThreads > 0)
+ server.setThreadPool(new QueuedThreadPool(config.maxThreads));
+ else
+ server.setThreadPool(new QueuedThreadPool());
+ // set up socket connectors
+ val nioconnector = new CometSelectChannelConnector;
+ var sslconnector: CometSslSelectChannelConnector = null;
+ nioconnector.setPort(config.listenPort);
+ if (config.listenHost.length > 0)
+ nioconnector.setHost(config.listenHost);
+ if (config.listenSecurePort == 0) {
+ server.setConnectors(Array(nioconnector));
+ } else {
+ sslconnector = new CometSslSelectChannelConnector;
+ sslconnector.setPort(config.listenSecurePort);
+ if (config.listenSecureHost.length > 0)
+ sslconnector.setHost(config.listenSecureHost);
+ if (! config.sslKeyStore_isSet) {
+ val url = getClass.getResource("/mirror/snakeoil-ssl-cert");
+ if (url != null)
+ sslconnector.setKeystore(url.toString());
+ else
+ sslconnector.setKeystore(config.sslKeyStore);
+ } else {
+ sslconnector.setKeystore(config.sslKeyStore);
+ }
+ sslconnector.setPassword(config.sslStorePassword);
+ sslconnector.setKeyPassword(config.sslKeyPassword);
+ sslconnector.setTrustPassword(config.sslStorePassword);
+ sslconnector.setExcludeCipherSuites(Array[String](
+ "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DHE_RSA_WITH_DES_CBC_SHA",
+ "SSL_DHE_DSS_WITH_DES_CBC_SHA",
+ "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+ "SSL_RSA_WITH_DES_CBC_SHA",
+ "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
+ "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_RSA_WITH_NULL_MD5",
+ "SSL_RSA_WITH_NULL_SHA",
+ "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DH_anon_WITH_DES_CBC_SHA",
+ "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
+ "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"));
+ server.setConnectors(Array(nioconnector, sslconnector));
+ }
+
+ // set up Context and Servlet
+ val handler = new Context(server, "/", Context.NO_SESSIONS | Context.NO_SECURITY);
+ handler.addServlet(new ServletHolder(new OuiServlet), "/");
+
+// removed due to license restrictions; REMOVED_COS_OF_COS
+
+// val filterHolder = new FilterHolder(new MultipartFilter());
+// filterHolder.setInitParameter("uploadDir", System.getProperty("java.io.tmpdir"));
+// handler.addFilter(filterHolder, "/*", 1);
+
+ global.context = handler;
+
+ // set up apache-style logging
+ val requestLogHandler = new RequestLogHandler();
+ val requestLog = new NCSARequestLog(config.logDir+"/backend/access/access-yyyy_mm_dd.request.log") {
+ override def log(req: Request, res: Response) {
+ try {
+ if (config.devMode || config.specialDebug)
+ super.log(req, res);
+ else if (res.getStatus() != 200 || config.transportPrefix == null || ! req.getRequestURI().startsWith(config.transportPrefix))
+ super.log(req, res);
+ val d = new Date();
+ appstats.stati.foreach(_(if (res.getStatus() < 0) 404 else res.getStatus()).hit(d));
+ } catch {
+ case e => { exceptionlog("Error writing to log?"); exceptionlog(e); }
+ }
+ }
+ };
+ requestLog.setRetainDays(365);
+ requestLog.setAppend(true);
+ requestLog.setExtended(true);
+ requestLog.setLogServer(true);
+ requestLog.setLogLatency(true);
+ requestLog.setLogTimeZone("PST");
+ requestLogHandler.setRequestLog(requestLog);
+
+ // set handlers with server
+ val businessHandlers = new HandlerList();
+ businessHandlers.setHandlers(Array(handler));
+ val allHandlers = new HandlerCollection();
+ allHandlers.setHandlers(Array(businessHandlers, requestLogHandler));
+ server.setHandler(allHandlers);
+
+ // fix slow startup bug
+ server.setSessionIdManager(new HashSessionIdManager(new java.util.Random()));
+
+ // run the onStartup script.
+ runOnStartup();
+
+ // preload some runners, if necessary.
+ if (config.preloadRunners > 0) {
+ val b = new java.util.concurrent.CountDownLatch(config.preloadRunners);
+ for (i <- 0 until config.preloadRunners)
+ (new Thread {
+ ScopeReuseManager.freeRunner(ScopeReuseManager.newRunner);
+ b.countDown();
+ }).start();
+ while (b.getCount() > 0) {
+ b.await();
+ }
+ println("Preloaded "+config.preloadRunners+" runners.");
+ }
+
+ // start SARS server.
+ if (config.listenSarsPort > 0) {
+ try {
+ import net.appjet.common.sars._;
+ sarsServer = new SarsServer(config.sarsAuthKey,
+ new SarsMessageHandler { override def handle(q: String) = runOnSars(q) },
+ if (config.listenSarsHost.length > 0) Some(config.listenSarsHost) else None,
+ config.listenSarsPort);
+ sarsServer.daemon = true;
+ sarsServer.start();
+ } catch {
+ case e: java.net.SocketException => {
+ println("SARS: A socket exception occurred: "+e.getMessage()+" on SARS server at "+config.listenSarsHost+":"+config.listenSarsPort);
+ java.lang.Runtime.getRuntime().halt(1);
+ }
+ }
+ }
+
+ // start server
+ java.lang.Runtime.getRuntime().addShutdownHook(new Thread() {
+ override def run() {
+ val df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
+ def printts(str: String) {
+ println("["+df.format(new Date())+"]: "+str);
+ }
+ printts("Shutting down...");
+ handler.setShutdown(true);
+ Thread.sleep(if (config.devMode) 500 else 3000);
+ printts("...done, running onshutdown.");
+ runOnShutdown();
+ printts("...done, stopping server.");
+ server.stop();
+ server.join();
+ printts("...done, flushing logs.");
+ for (l <- loggers) { l.flush(); l.close(); }
+ printts("...done.");
+ }
+ });
+
+ def socketError(c: org.mortbay.jetty.Connector, e: java.net.SocketException) {
+ var msg = e.getMessage();
+ println("SOCKET ERROR: "+msg+" - "+(c match {
+ case null => "(unknown socket)";
+ case x => {
+ (x.getHost() match {
+ case null => "localhost";
+ case y => y;
+ })+":"+x.getPort();
+ }
+ }));
+ if (msg.contains("Address already in use")) {
+ println("Did you make sure that ports "+config.listenPort+" and "+config.listenSecurePort+" are not in use?");
+ }
+ if (msg.contains("Permission denied")) {
+ println("Perhaps you need to run as the root user or as an Administrator?");
+ }
+ }
+
+ var c: org.mortbay.jetty.Connector = null;
+
+ try {
+ c = nioconnector;
+ c.open();
+ if (sslconnector != null) {
+ c = sslconnector;
+ c.open();
+ }
+ c = null;
+ allHandlers.start();
+ server.start();
+ } catch {
+ case e: java.net.SocketException => {
+ socketError(c, e);
+ java.lang.Runtime.getRuntime().halt(1);
+ }
+ case e: org.mortbay.util.MultiException => {
+ println("SERVER ERROR: Couldn't start server; multiple errors.");
+ for (i <- new IterableWrapper[Throwable] { override val underlying = e.getThrowables.asInstanceOf[java.util.List[Throwable]] }) {
+ i match {
+ case se: java.net.SocketException => {
+ socketError(c, se);
+ }
+ case e =>
+ println("SERVER ERROR: Couldn't start server: "+i.getMessage());
+ }
+ }
+ java.lang.Runtime.getRuntime().halt(1);
+ }
+ case e => {
+ println("SERVER ERROR: Couldn't start server: "+e.getMessage());
+ java.lang.Runtime.getRuntime().halt(1);
+ }
+ }
+
+ println("HTTP server listening on http://"+
+ (if (config.listenHost.length > 0) config.listenHost else "localhost")+
+ ":"+config.listenPort+"/");
+ if (config.listenSecurePort > 0)
+ println("HTTPS server listening on https://"+
+ (if (config.listenSecureHost.length > 0) config.listenSecureHost else "localhost")+
+ ":"+config.listenSecurePort+"/");
+ if (config.listenSarsPort > 0)
+ println("SARS server listening on "+
+ (if (config.listenSarsHost.length > 0) config.listenSarsHost else "localhost")+
+ ":"+config.listenSarsPort);
+ }
+}
diff --git a/trunk/infrastructure/net.appjet.oui/monitoring.scala b/infrastructure/net.appjet.oui/monitoring.scala
index e380b84..e380b84 100644
--- a/trunk/infrastructure/net.appjet.oui/monitoring.scala
+++ b/infrastructure/net.appjet.oui/monitoring.scala
diff --git a/trunk/infrastructure/net.appjet.oui/network.scala b/infrastructure/net.appjet.oui/network.scala
index 2965b19..2965b19 100644
--- a/trunk/infrastructure/net.appjet.oui/network.scala
+++ b/infrastructure/net.appjet.oui/network.scala
diff --git a/trunk/infrastructure/net.appjet.oui/servermodel.scala b/infrastructure/net.appjet.oui/servermodel.scala
index 1e2363f..1e2363f 100644
--- a/trunk/infrastructure/net.appjet.oui/servermodel.scala
+++ b/infrastructure/net.appjet.oui/servermodel.scala
diff --git a/trunk/infrastructure/net.appjet.oui/stats.scala b/infrastructure/net.appjet.oui/stats.scala
index 075182f..075182f 100644
--- a/trunk/infrastructure/net.appjet.oui/stats.scala
+++ b/infrastructure/net.appjet.oui/stats.scala
diff --git a/trunk/infrastructure/net.appjet.oui/synchronizer.scala b/infrastructure/net.appjet.oui/synchronizer.scala
index 2a6d9c1..2a6d9c1 100644
--- a/trunk/infrastructure/net.appjet.oui/synchronizer.scala
+++ b/infrastructure/net.appjet.oui/synchronizer.scala
diff --git a/trunk/infrastructure/net.appjet.oui/util.scala b/infrastructure/net.appjet.oui/util.scala
index ba8a736..ba8a736 100644
--- a/trunk/infrastructure/net.appjet.oui/util.scala
+++ b/infrastructure/net.appjet.oui/util.scala
diff --git a/trunk/infrastructure/rhino1_7R1/apiClasses.properties b/infrastructure/rhino1_7R1/apiClasses.properties
index d116ee4..d116ee4 100644
--- a/trunk/infrastructure/rhino1_7R1/apiClasses.properties
+++ b/infrastructure/rhino1_7R1/apiClasses.properties
diff --git a/trunk/infrastructure/rhino1_7R1/build-date b/infrastructure/rhino1_7R1/build-date
index e6132e5..e6132e5 100644
--- a/trunk/infrastructure/rhino1_7R1/build-date
+++ b/infrastructure/rhino1_7R1/build-date
diff --git a/trunk/infrastructure/rhino1_7R1/build.properties b/infrastructure/rhino1_7R1/build.properties
index 4477ee0..4477ee0 100644
--- a/trunk/infrastructure/rhino1_7R1/build.properties
+++ b/infrastructure/rhino1_7R1/build.properties
diff --git a/trunk/infrastructure/rhino1_7R1/build.xml b/infrastructure/rhino1_7R1/build.xml
index fabbffa..fabbffa 100644
--- a/trunk/infrastructure/rhino1_7R1/build.xml
+++ b/infrastructure/rhino1_7R1/build.xml
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/build.xml b/infrastructure/rhino1_7R1/deprecatedsrc/build.xml
index 4250fcf..4250fcf 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/build.xml
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/build.xml
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/ClassDefinitionException.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/ClassDefinitionException.java
index 2197063..2197063 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/ClassDefinitionException.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/ClassDefinitionException.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/NotAFunctionException.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/NotAFunctionException.java
index 3de53a8..3de53a8 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/NotAFunctionException.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/NotAFunctionException.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/PropertyException.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/PropertyException.java
index 8d786c7..8d786c7 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/PropertyException.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/PropertyException.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/LogicalEquality.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/LogicalEquality.java
index b525aff..b525aff 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/LogicalEquality.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/LogicalEquality.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/Namespace.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/Namespace.java
index 3a16320..3a16320 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/Namespace.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/Namespace.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/NamespaceHelper.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/NamespaceHelper.java
index fc99c7e..fc99c7e 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/NamespaceHelper.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/NamespaceHelper.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/QName.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/QName.java
index 247da19..247da19 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/QName.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/QName.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XML.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XML.java
index c8818a5..c8818a5 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XML.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XML.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLCtor.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLCtor.java
index 987c8ed..987c8ed 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLCtor.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLCtor.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLLibImpl.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLLibImpl.java
index 90da7d4..90da7d4 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLLibImpl.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLLibImpl.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLList.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLList.java
index b66ec96..b66ec96 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLList.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLList.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLName.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLName.java
index 8ff972e..8ff972e 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLName.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLName.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLObjectImpl.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLObjectImpl.java
index a6d47d5..a6d47d5 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLObjectImpl.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLObjectImpl.java
diff --git a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLWithScope.java b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLWithScope.java
index 67a778d..67a778d 100644
--- a/trunk/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLWithScope.java
+++ b/infrastructure/rhino1_7R1/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLWithScope.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/Control.java b/infrastructure/rhino1_7R1/examples/Control.java
index d671181..d671181 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/Control.java
+++ b/infrastructure/rhino1_7R1/examples/Control.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/Counter.java b/infrastructure/rhino1_7R1/examples/Counter.java
index 14c179a..14c179a 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/Counter.java
+++ b/infrastructure/rhino1_7R1/examples/Counter.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/CounterTest.java b/infrastructure/rhino1_7R1/examples/CounterTest.java
index 63dc74b..63dc74b 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/CounterTest.java
+++ b/infrastructure/rhino1_7R1/examples/CounterTest.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/DynamicScopes.java b/infrastructure/rhino1_7R1/examples/DynamicScopes.java
index 10d53ac..10d53ac 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/DynamicScopes.java
+++ b/infrastructure/rhino1_7R1/examples/DynamicScopes.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/E4X/e4x_example.js b/infrastructure/rhino1_7R1/examples/E4X/e4x_example.js
index 7417404..7417404 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/E4X/e4x_example.js
+++ b/infrastructure/rhino1_7R1/examples/E4X/e4x_example.js
diff --git a/trunk/infrastructure/rhino1_7R1/examples/File.java b/infrastructure/rhino1_7R1/examples/File.java
index 62bd980..62bd980 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/File.java
+++ b/infrastructure/rhino1_7R1/examples/File.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/Foo.java b/infrastructure/rhino1_7R1/examples/Foo.java
index bca1b79..bca1b79 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/Foo.java
+++ b/infrastructure/rhino1_7R1/examples/Foo.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/Matrix.java b/infrastructure/rhino1_7R1/examples/Matrix.java
index 87e4b8a..87e4b8a 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/Matrix.java
+++ b/infrastructure/rhino1_7R1/examples/Matrix.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/NervousText.html b/infrastructure/rhino1_7R1/examples/NervousText.html
index 0e3c7dd..0e3c7dd 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/NervousText.html
+++ b/infrastructure/rhino1_7R1/examples/NervousText.html
diff --git a/trunk/infrastructure/rhino1_7R1/examples/NervousText.js b/infrastructure/rhino1_7R1/examples/NervousText.js
index a2f82fe..a2f82fe 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/NervousText.js
+++ b/infrastructure/rhino1_7R1/examples/NervousText.js
diff --git a/trunk/infrastructure/rhino1_7R1/examples/PrimitiveWrapFactory.java b/infrastructure/rhino1_7R1/examples/PrimitiveWrapFactory.java
index 4157a11..4157a11 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/PrimitiveWrapFactory.java
+++ b/infrastructure/rhino1_7R1/examples/PrimitiveWrapFactory.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/RunScript.java b/infrastructure/rhino1_7R1/examples/RunScript.java
index 758ac64..758ac64 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/RunScript.java
+++ b/infrastructure/rhino1_7R1/examples/RunScript.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/RunScript2.java b/infrastructure/rhino1_7R1/examples/RunScript2.java
index cb02896..cb02896 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/RunScript2.java
+++ b/infrastructure/rhino1_7R1/examples/RunScript2.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/RunScript3.java b/infrastructure/rhino1_7R1/examples/RunScript3.java
index 7baeba8..7baeba8 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/RunScript3.java
+++ b/infrastructure/rhino1_7R1/examples/RunScript3.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/RunScript4.java b/infrastructure/rhino1_7R1/examples/RunScript4.java
index bd3d6f4..bd3d6f4 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/RunScript4.java
+++ b/infrastructure/rhino1_7R1/examples/RunScript4.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/Shell.java b/infrastructure/rhino1_7R1/examples/Shell.java
index 6316c6f..6316c6f 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/Shell.java
+++ b/infrastructure/rhino1_7R1/examples/Shell.java
diff --git a/trunk/infrastructure/rhino1_7R1/examples/SwingApplication.js b/infrastructure/rhino1_7R1/examples/SwingApplication.js
index a527aad..a527aad 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/SwingApplication.js
+++ b/infrastructure/rhino1_7R1/examples/SwingApplication.js
diff --git a/trunk/infrastructure/rhino1_7R1/examples/checkParam.js b/infrastructure/rhino1_7R1/examples/checkParam.js
index 51910d5..51910d5 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/checkParam.js
+++ b/infrastructure/rhino1_7R1/examples/checkParam.js
diff --git a/trunk/infrastructure/rhino1_7R1/examples/enum.js b/infrastructure/rhino1_7R1/examples/enum.js
index 02034bc..02034bc 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/enum.js
+++ b/infrastructure/rhino1_7R1/examples/enum.js
diff --git a/trunk/infrastructure/rhino1_7R1/examples/jsdoc.js b/infrastructure/rhino1_7R1/examples/jsdoc.js
index 3d44e48..3d44e48 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/jsdoc.js
+++ b/infrastructure/rhino1_7R1/examples/jsdoc.js
diff --git a/trunk/infrastructure/rhino1_7R1/examples/liveConnect.js b/infrastructure/rhino1_7R1/examples/liveConnect.js
index 7befc08..7befc08 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/liveConnect.js
+++ b/infrastructure/rhino1_7R1/examples/liveConnect.js
diff --git a/trunk/infrastructure/rhino1_7R1/examples/unique.js b/infrastructure/rhino1_7R1/examples/unique.js
index a4274bb..a4274bb 100644
--- a/trunk/infrastructure/rhino1_7R1/examples/unique.js
+++ b/infrastructure/rhino1_7R1/examples/unique.js
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/allclasses-frame.html b/infrastructure/rhino1_7R1/javadoc/allclasses-frame.html
index 073b251..073b251 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/allclasses-frame.html
+++ b/infrastructure/rhino1_7R1/javadoc/allclasses-frame.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/allclasses-noframe.html b/infrastructure/rhino1_7R1/javadoc/allclasses-noframe.html
index 48536b4..48536b4 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/allclasses-noframe.html
+++ b/infrastructure/rhino1_7R1/javadoc/allclasses-noframe.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/constant-values.html b/infrastructure/rhino1_7R1/javadoc/constant-values.html
index b29b7ba..b29b7ba 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/constant-values.html
+++ b/infrastructure/rhino1_7R1/javadoc/constant-values.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/deprecated-list.html b/infrastructure/rhino1_7R1/javadoc/deprecated-list.html
index 923cc54..923cc54 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/deprecated-list.html
+++ b/infrastructure/rhino1_7R1/javadoc/deprecated-list.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/help-doc.html b/infrastructure/rhino1_7R1/javadoc/help-doc.html
index 7a2e353..7a2e353 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/help-doc.html
+++ b/infrastructure/rhino1_7R1/javadoc/help-doc.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/index-all.html b/infrastructure/rhino1_7R1/javadoc/index-all.html
index 15ba433..15ba433 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/index-all.html
+++ b/infrastructure/rhino1_7R1/javadoc/index-all.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/index.html b/infrastructure/rhino1_7R1/javadoc/index.html
index fa48043..fa48043 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/index.html
+++ b/infrastructure/rhino1_7R1/javadoc/index.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Callable.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Callable.html
index 07c38c5..07c38c5 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Callable.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Callable.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassCache.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassCache.html
index 8d8b3ef..8d8b3ef 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassCache.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassCache.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassShutter.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassShutter.html
index 924cfb5..924cfb5 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassShutter.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ClassShutter.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/CompilerEnvirons.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/CompilerEnvirons.html
index 8b5e109..8b5e109 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/CompilerEnvirons.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/CompilerEnvirons.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Context.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Context.html
index 64fb637..64fb637 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Context.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Context.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextAction.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextAction.html
index 8e7116c..8e7116c 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextAction.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextAction.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.Listener.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.Listener.html
index 6290c8c..6290c8c 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.Listener.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.Listener.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.html
index ef61a6f..ef61a6f 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ContextFactory.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EcmaError.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EcmaError.html
index 71c774f..71c774f 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EcmaError.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EcmaError.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ErrorReporter.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ErrorReporter.html
index a559d25..a559d25 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ErrorReporter.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ErrorReporter.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EvaluatorException.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EvaluatorException.html
index 6f06bb5..6f06bb5 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EvaluatorException.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/EvaluatorException.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Function.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Function.html
index 55712dc..55712dc 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Function.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Function.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/FunctionObject.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/FunctionObject.html
index 4e9d011..4e9d011 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/FunctionObject.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/FunctionObject.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/GeneratedClassLoader.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/GeneratedClassLoader.html
index 2d998ac..2d998ac 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/GeneratedClassLoader.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/GeneratedClassLoader.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ImporterTopLevel.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ImporterTopLevel.html
index 78dd7a7..78dd7a7 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ImporterTopLevel.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ImporterTopLevel.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/JavaScriptException.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/JavaScriptException.html
index 6dafa13..6dafa13 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/JavaScriptException.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/JavaScriptException.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RefCallable.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RefCallable.html
index 910d0fd..910d0fd 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RefCallable.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RefCallable.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RhinoException.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RhinoException.html
index 4ad3d0f..4ad3d0f 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RhinoException.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/RhinoException.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Script.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Script.html
index 65f250f..65f250f 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Script.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Script.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Scriptable.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Scriptable.html
index 14ab7aa..14ab7aa 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Scriptable.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Scriptable.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ScriptableObject.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ScriptableObject.html
index fce83d6..fce83d6 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ScriptableObject.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/ScriptableObject.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/SecurityController.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/SecurityController.html
index 92c5c44..92c5c44 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/SecurityController.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/SecurityController.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Synchronizer.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Synchronizer.html
index 05b8fb4..05b8fb4 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Synchronizer.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Synchronizer.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrapFactory.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrapFactory.html
index 675c456..675c456 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrapFactory.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrapFactory.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrappedException.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrappedException.html
index 1109997..1109997 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrappedException.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/WrappedException.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Wrapper.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Wrapper.html
index 0d05fdc..0d05fdc 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Wrapper.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/Wrapper.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/DebuggableScript.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/DebuggableScript.html
index 1159738..1159738 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/DebuggableScript.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/DebuggableScript.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-frame.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-frame.html
index 28878a0..28878a0 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-frame.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-frame.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-summary.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-summary.html
index 1a50d7f..1a50d7f 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-summary.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-summary.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-tree.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-tree.html
index d32bdf5..d32bdf5 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-tree.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/debug/package-tree.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/ClassCompiler.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/ClassCompiler.html
index bdce431..bdce431 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/ClassCompiler.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/ClassCompiler.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-frame.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-frame.html
index 1dc284b..1dc284b 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-frame.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-frame.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-summary.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-summary.html
index 8b86a40..8b86a40 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-summary.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-summary.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-tree.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-tree.html
index 55e23d0..55e23d0 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-tree.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/optimizer/package-tree.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-frame.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-frame.html
index f40351c..f40351c 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-frame.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-frame.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-summary.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-summary.html
index c15d3c1..c15d3c1 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-summary.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-summary.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-tree.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-tree.html
index 030f3e0..030f3e0 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-tree.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/package-tree.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableInputStream.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableInputStream.html
index f0d178f..f0d178f 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableInputStream.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableInputStream.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableOutputStream.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableOutputStream.html
index fb6d1ba..fb6d1ba 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableOutputStream.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/ScriptableOutputStream.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-frame.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-frame.html
index 39d85e2..39d85e2 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-frame.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-frame.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-summary.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-summary.html
index 568f562..568f562 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-summary.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-summary.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-tree.html b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-tree.html
index e672261..e672261 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-tree.html
+++ b/infrastructure/rhino1_7R1/javadoc/org/mozilla/javascript/serialize/package-tree.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/overview-frame.html b/infrastructure/rhino1_7R1/javadoc/overview-frame.html
index 10e9be0..10e9be0 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/overview-frame.html
+++ b/infrastructure/rhino1_7R1/javadoc/overview-frame.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/overview-summary.html b/infrastructure/rhino1_7R1/javadoc/overview-summary.html
index 043bb30..043bb30 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/overview-summary.html
+++ b/infrastructure/rhino1_7R1/javadoc/overview-summary.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/overview-tree.html b/infrastructure/rhino1_7R1/javadoc/overview-tree.html
index 9c5398c..9c5398c 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/overview-tree.html
+++ b/infrastructure/rhino1_7R1/javadoc/overview-tree.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/package-list b/infrastructure/rhino1_7R1/javadoc/package-list
index 62fc06b..62fc06b 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/package-list
+++ b/infrastructure/rhino1_7R1/javadoc/package-list
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/resources/inherit.gif b/infrastructure/rhino1_7R1/javadoc/resources/inherit.gif
index c814867..c814867 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/resources/inherit.gif
+++ b/infrastructure/rhino1_7R1/javadoc/resources/inherit.gif
Binary files differ
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/serialized-form.html b/infrastructure/rhino1_7R1/javadoc/serialized-form.html
index c022624..c022624 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/serialized-form.html
+++ b/infrastructure/rhino1_7R1/javadoc/serialized-form.html
diff --git a/trunk/infrastructure/rhino1_7R1/javadoc/stylesheet.css b/infrastructure/rhino1_7R1/javadoc/stylesheet.css
index 6ea9e51..6ea9e51 100644
--- a/trunk/infrastructure/rhino1_7R1/javadoc/stylesheet.css
+++ b/infrastructure/rhino1_7R1/javadoc/stylesheet.css
diff --git a/trunk/infrastructure/rhino1_7R1/lib/jsr173_1.0_api.jar b/infrastructure/rhino1_7R1/lib/jsr173_1.0_api.jar
index fef9a9c..fef9a9c 100644
--- a/trunk/infrastructure/rhino1_7R1/lib/jsr173_1.0_api.jar
+++ b/infrastructure/rhino1_7R1/lib/jsr173_1.0_api.jar
Binary files differ
diff --git a/trunk/infrastructure/rhino1_7R1/lib/xbean.jar b/infrastructure/rhino1_7R1/lib/xbean.jar
index 8a4dff4..8a4dff4 100644
--- a/trunk/infrastructure/rhino1_7R1/lib/xbean.jar
+++ b/infrastructure/rhino1_7R1/lib/xbean.jar
Binary files differ
diff --git a/trunk/infrastructure/rhino1_7R1/src/build.xml b/infrastructure/rhino1_7R1/src/build.xml
index a0a1e13..a0a1e13 100644
--- a/trunk/infrastructure/rhino1_7R1/src/build.xml
+++ b/infrastructure/rhino1_7R1/src/build.xml
diff --git a/trunk/infrastructure/rhino1_7R1/src/manifest b/infrastructure/rhino1_7R1/src/manifest
index b7d0c06..b7d0c06 100644
--- a/trunk/infrastructure/rhino1_7R1/src/manifest
+++ b/infrastructure/rhino1_7R1/src/manifest
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ByteCode.java b/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ByteCode.java
index fa4713e..fa4713e 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ByteCode.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ByteCode.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ClassFileWriter.java b/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ClassFileWriter.java
index b9c6c96..b9c6c96 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ClassFileWriter.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/classfile/ClassFileWriter.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Arguments.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Arguments.java
index 954b078..954b078 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Arguments.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Arguments.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/BaseFunction.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/BaseFunction.java
index d7d8992..d7d8992 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/BaseFunction.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/BaseFunction.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Callable.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Callable.java
index 03e0fce..03e0fce 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Callable.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Callable.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassCache.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassCache.java
index 9047278..9047278 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassCache.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassCache.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassShutter.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassShutter.java
index d5f4cd6..d5f4cd6 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassShutter.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ClassShutter.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/CompilerEnvirons.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/CompilerEnvirons.java
index 645d098..645d098 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/CompilerEnvirons.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/CompilerEnvirons.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ConstProperties.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ConstProperties.java
index 860db79..860db79 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ConstProperties.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ConstProperties.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Context.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Context.java
index 0833883..0833883 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Context.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Context.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextAction.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextAction.java
index 1c584a9..1c584a9 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextAction.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextAction.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextFactory.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextFactory.java
index 4f9fde2..4f9fde2 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextFactory.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextFactory.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextListener.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextListener.java
index 5e17145..5e17145 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextListener.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ContextListener.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DToA.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DToA.java
index ad2a68a..ad2a68a 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DToA.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DToA.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Decompiler.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Decompiler.java
index 8547d37..8547d37 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Decompiler.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Decompiler.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefaultErrorReporter.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefaultErrorReporter.java
index c7d93d4..c7d93d4 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefaultErrorReporter.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefaultErrorReporter.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefiningClassLoader.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefiningClassLoader.java
index 5864b5d..5864b5d 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefiningClassLoader.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/DefiningClassLoader.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Delegator.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Delegator.java
index e044863..e044863 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Delegator.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Delegator.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EcmaError.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EcmaError.java
index 1fd8f03..1fd8f03 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EcmaError.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EcmaError.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ErrorReporter.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ErrorReporter.java
index 4649370..4649370 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ErrorReporter.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ErrorReporter.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Evaluator.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Evaluator.java
index e222af3..e222af3 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Evaluator.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Evaluator.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EvaluatorException.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EvaluatorException.java
index 7b4e7cc..7b4e7cc 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EvaluatorException.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/EvaluatorException.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Function.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Function.java
index a4377e6..a4377e6 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Function.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Function.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionNode.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionNode.java
index 484167e..484167e 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionNode.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionNode.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionObject.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionObject.java
index 8fa4e68..8fa4e68 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionObject.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/FunctionObject.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/GeneratedClassLoader.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/GeneratedClassLoader.java
index 0f73615..0f73615 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/GeneratedClassLoader.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/GeneratedClassLoader.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java
index 1f51cb1..1f51cb1 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionCall.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionCall.java
index 713fabf..713fabf 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionCall.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionCall.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionObject.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionObject.java
index c578dfa..c578dfa 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionObject.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdFunctionObject.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdScriptableObject.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdScriptableObject.java
index 2b3ecf3..2b3ecf3 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdScriptableObject.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IdScriptableObject.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ImporterTopLevel.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ImporterTopLevel.java
index 294deab..294deab 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ImporterTopLevel.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ImporterTopLevel.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java
index c73db34..c73db34 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterfaceAdapter.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterfaceAdapter.java
index 877e6a2..877e6a2 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterfaceAdapter.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterfaceAdapter.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpretedFunction.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpretedFunction.java
index db84299..db84299 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpretedFunction.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpretedFunction.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java
index a68c025..a68c025 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpreterData.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpreterData.java
index 7435b10..7435b10 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpreterData.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InterpreterData.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java
index 6e0a827..6e0a827 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java
index 84ef2d4..84ef2d4 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaScriptException.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaScriptException.java
index 11ebedf..11ebedf 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaScriptException.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaScriptException.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Kit.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Kit.java
index f7b4cad..f7b4cad 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Kit.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Kit.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/LazilyLoadedCtor.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/LazilyLoadedCtor.java
index 4153372..4153372 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/LazilyLoadedCtor.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/LazilyLoadedCtor.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java
index 2d3553f..2d3553f 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeArray.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeArray.java
index b170ff4..b170ff4 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeArray.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeArray.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeBoolean.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeBoolean.java
index b6a106a..b6a106a 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeBoolean.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeBoolean.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeCall.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeCall.java
index b196ac3..b196ac3 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeCall.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeCall.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeDate.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeDate.java
index 75d41ab..75d41ab 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeDate.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeDate.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeError.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeError.java
index 4aff10c..4aff10c 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeError.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeError.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeFunction.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeFunction.java
index ac70556..ac70556 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeFunction.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeFunction.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java
index 0a8da9f..0a8da9f 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGlobal.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGlobal.java
index 58faad4..58faad4 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGlobal.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGlobal.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeIterator.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeIterator.java
index c61f417..c61f417 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeIterator.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeIterator.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaArray.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaArray.java
index 2f711a0..2f711a0 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaArray.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaArray.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaClass.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaClass.java
index ab8af5c..ab8af5c 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaClass.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaClass.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaConstructor.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaConstructor.java
index 530bf81..530bf81 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaConstructor.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaConstructor.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaMethod.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaMethod.java
index eb66f40..eb66f40 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaMethod.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaMethod.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaObject.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaObject.java
index 3d27852..3d27852 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaObject.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaObject.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaPackage.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaPackage.java
index 71f09f7..71f09f7 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaPackage.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaPackage.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaTopPackage.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaTopPackage.java
index b5c9b49..b5c9b49 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaTopPackage.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeJavaTopPackage.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeMath.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeMath.java
index 36b66b4..36b66b4 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeMath.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeMath.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeNumber.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeNumber.java
index 8fc9fb0..8fc9fb0 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeNumber.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeNumber.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeObject.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeObject.java
index 19aff63..19aff63 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeObject.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeObject.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeScript.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeScript.java
index 7b5191e..7b5191e 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeScript.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeScript.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeString.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeString.java
index 972415d..972415d 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeString.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeString.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeWith.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeWith.java
index 83683b2..83683b2 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeWith.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeWith.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java
index 4298388..4298388 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NodeTransformer.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NodeTransformer.java
index 201c6f2..201c6f2 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NodeTransformer.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NodeTransformer.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjArray.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjArray.java
index a9636a3..a9636a3 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjArray.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjArray.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjToIntMap.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjToIntMap.java
index 4aa7d23..4aa7d23 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjToIntMap.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ObjToIntMap.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Parser.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Parser.java
index 80cb937..80cb937 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Parser.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Parser.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/PolicySecurityController.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/PolicySecurityController.java
index c4d3d7e..c4d3d7e 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/PolicySecurityController.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/PolicySecurityController.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Ref.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Ref.java
index 1e237bc..1e237bc 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Ref.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Ref.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RefCallable.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RefCallable.java
index 6d4b61c..6d4b61c 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RefCallable.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RefCallable.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RegExpProxy.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RegExpProxy.java
index ac29c6e..ac29c6e 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RegExpProxy.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RegExpProxy.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RhinoException.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RhinoException.java
index b7f4a4d..b7f4a4d 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RhinoException.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/RhinoException.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Script.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Script.java
index 4721ead..4721ead 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Script.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Script.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptOrFnNode.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptOrFnNode.java
index 9ea6d1f..9ea6d1f 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptOrFnNode.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptOrFnNode.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptRuntime.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptRuntime.java
index f879581..f879581 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptRuntime.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptRuntime.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Scriptable.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Scriptable.java
index 74e5ba7..74e5ba7 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Scriptable.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Scriptable.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptableObject.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptableObject.java
index 53de1fc..53de1fc 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptableObject.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/ScriptableObject.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecureCaller.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecureCaller.java
index bc8ed86..bc8ed86 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecureCaller.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecureCaller.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityController.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityController.java
index ed85dbf..ed85dbf 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityController.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityController.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityUtilities.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityUtilities.java
index 275ad92..275ad92 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityUtilities.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SecurityUtilities.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SpecialRef.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SpecialRef.java
index b037eaf..b037eaf 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SpecialRef.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/SpecialRef.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Synchronizer.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Synchronizer.java
index f2fca52..f2fca52 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Synchronizer.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Synchronizer.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Token.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Token.java
index be96487..be96487 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Token.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Token.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/TokenStream.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/TokenStream.java
index c8c3045..c8c3045 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/TokenStream.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/TokenStream.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UintMap.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UintMap.java
index 0027819..0027819 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UintMap.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UintMap.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Undefined.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Undefined.java
index 472f26c..472f26c 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Undefined.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Undefined.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UniqueTag.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UniqueTag.java
index 33f96eb..33f96eb 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UniqueTag.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/UniqueTag.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/VMBridge.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/VMBridge.java
index 5fba4a5..5fba4a5 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/VMBridge.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/VMBridge.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrapFactory.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrapFactory.java
index 3edc203..3edc203 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrapFactory.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrapFactory.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrappedException.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrappedException.java
index c749f74..c749f74 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrappedException.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/WrappedException.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Wrapper.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Wrapper.java
index cb2d2f5..cb2d2f5 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Wrapper.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Wrapper.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/continuations/Continuation.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/continuations/Continuation.java
index c6d3966..c6d3966 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/continuations/Continuation.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/continuations/Continuation.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebugFrame.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebugFrame.java
index ef15710..ef15710 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebugFrame.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebugFrame.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableObject.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableObject.java
index 23e7421..23e7421 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableObject.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableObject.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableScript.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableScript.java
index 705e442..705e442 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableScript.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/DebuggableScript.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/Debugger.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/Debugger.java
index bfac153..bfac153 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/Debugger.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/debug/Debugger.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk11/VMBridge_jdk11.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk11/VMBridge_jdk11.java
index f5d1522..f5d1522 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk11/VMBridge_jdk11.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk11/VMBridge_jdk11.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk13/VMBridge_jdk13.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk13/VMBridge_jdk13.java
index c33e9b4..c33e9b4 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk13/VMBridge_jdk13.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk13/VMBridge_jdk13.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java
index 0ffaf9d..0ffaf9d 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Block.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Block.java
index bd56714..bd56714 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Block.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Block.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/ClassCompiler.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/ClassCompiler.java
index 4a69c6a..4a69c6a 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/ClassCompiler.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/ClassCompiler.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Codegen.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Codegen.java
index 64952bf..64952bf 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Codegen.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Codegen.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/DataFlowBitSet.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/DataFlowBitSet.java
index 607e649..607e649 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/DataFlowBitSet.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/DataFlowBitSet.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptFunctionNode.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptFunctionNode.java
index e043165..e043165 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptFunctionNode.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptFunctionNode.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptRuntime.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptRuntime.java
index ba8ca03..ba8ca03 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptRuntime.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptRuntime.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptTransformer.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptTransformer.java
index 7cf679f..7cf679f 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptTransformer.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptTransformer.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Optimizer.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Optimizer.java
index 575c7e7..575c7e7 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Optimizer.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Optimizer.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExp.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExp.java
index a893841..a893841 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExp.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExp.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExpCtor.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExpCtor.java
index 808d62d..808d62d 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExpCtor.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/NativeRegExpCtor.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/RegExpImpl.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/RegExpImpl.java
index 4b0a303..4b0a303 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/RegExpImpl.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/RegExpImpl.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/SubString.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/SubString.java
index 00905ca..00905ca 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/SubString.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/regexp/SubString.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages.properties b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages.properties
index fd869c1..fd869c1 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages.properties
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages.properties
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages_fr.properties b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages_fr.properties
index fc87c97..fc87c97 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages_fr.properties
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/resources/Messages_fr.properties
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableInputStream.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableInputStream.java
index 476ff69..476ff69 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableInputStream.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableInputStream.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableOutputStream.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableOutputStream.java
index 5ba0d74..5ba0d74 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableOutputStream.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/serialize/ScriptableOutputStream.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLLib.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLLib.java
index da57ddf..da57ddf 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLLib.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLLib.java
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLObject.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLObject.java
index 5033564..5033564 100644
--- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLObject.java
+++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/xml/XMLObject.java
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/base.skip b/infrastructure/rhino1_7R1/testsrc/base.skip
index 35d6c54..35d6c54 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/base.skip
+++ b/infrastructure/rhino1_7R1/testsrc/base.skip
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/build.xml b/infrastructure/rhino1_7R1/testsrc/build.xml
index bc05516..bc05516 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/build.xml
+++ b/infrastructure/rhino1_7R1/testsrc/build.xml
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/opt1.skip b/infrastructure/rhino1_7R1/testsrc/opt1.skip
index 7006882..7006882 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/opt1.skip
+++ b/infrastructure/rhino1_7R1/testsrc/opt1.skip
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java
index 8bae79f..8bae79f 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java
+++ b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/JsDriver.java
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java
index 9acf64e..9acf64e 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java
+++ b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/ShellTest.java
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java
index 9c05df6..9c05df6 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java
+++ b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/StandardTests.java
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html
index 36bd729..36bd729 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html
+++ b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/drivers/results.html
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/Bug409702Test.java b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/Bug409702Test.java
index e9793cb..e9793cb 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/Bug409702Test.java
+++ b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/Bug409702Test.java
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/JavaAcessibilityTest.java b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/JavaAcessibilityTest.java
index b6cf3ca..b6cf3ca 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/JavaAcessibilityTest.java
+++ b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/JavaAcessibilityTest.java
diff --git a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/PrivateAccessClass.java b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/PrivateAccessClass.java
index 08f95a3..08f95a3 100644
--- a/trunk/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/PrivateAccessClass.java
+++ b/infrastructure/rhino1_7R1/testsrc/org/mozilla/javascript/tests/PrivateAccessClass.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/build.xml b/infrastructure/rhino1_7R1/toolsrc/build.xml
index be9a9b7..be9a9b7 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/build.xml
+++ b/infrastructure/rhino1_7R1/toolsrc/build.xml
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/ToolErrorReporter.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/ToolErrorReporter.java
index 938f5f2..938f5f2 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/ToolErrorReporter.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/ToolErrorReporter.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Dim.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Dim.java
index de8fcde..de8fcde 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Dim.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Dim.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/GuiCallback.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/GuiCallback.java
index f9762ec..f9762ec 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/GuiCallback.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/GuiCallback.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Main.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Main.java
index 3f90915..3f90915 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Main.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/Main.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/ScopeProvider.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/ScopeProvider.java
index d8f65b9..d8f65b9 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/ScopeProvider.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/ScopeProvider.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/SwingGui.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/SwingGui.java
index 61dc065..61dc065 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/SwingGui.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/SwingGui.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/build.xml b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/build.xml
index c35fd40..c35fd40 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/build.xml
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/debugger/build.xml
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java
index dd4f689..dd4f689 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/CodePrinter.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java
index 60bdfb4..60bdfb4 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/FileBody.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java
index 69d5065..69d5065 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/IdValuePair.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java
index ae1d038..ae1d038 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/Main.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java
index 3db99d6..3db99d6 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/idswitch/SwitchGenerator.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/jsc/Main.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/jsc/Main.java
index 2da4f2f..2da4f2f 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/jsc/Main.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/jsc/Main.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties
index 76615e9..76615e9 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java
index 08cac62..08cac62 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java
index 19904b9..19904b9 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java
index fdb8f4e..fdb8f4e 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java
index f6fe3a1..f6fe3a1 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java
index de39a5e..de39a5e 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java
index 9120892..9120892 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java
index dcad90e..dcad90e 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java
index 8f029ea..8f029ea 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java
index ba7e62c..ba7e62c 100644
--- a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java
+++ b/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/build.xml b/infrastructure/rhino1_7R1/xmlimplsrc/build.xml
index 1aedece..1aedece 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/build.xml
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/build.xml
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java
index a4cf585..a4cf585 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java
index 90a18cb..90a18cb 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java
index 090ae1a..090ae1a 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java
index fac8773..fac8773 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
index 6d45240..6d45240 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java
index 59dcca3..59dcca3 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java
index edd7525..edd7525 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java
index db918f8..db918f8 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java
index fbeb45e..fbeb45e 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java
index 06955d0..06955d0 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java
index d8ad495..d8ad495 100644
--- a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java
+++ b/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java
diff --git a/trunk/infrastructure/yuicompressor/lib/jargs-1.0.jar b/infrastructure/yuicompressor/lib/jargs-1.0.jar
index cdbc80b..cdbc80b 100644
--- a/trunk/infrastructure/yuicompressor/lib/jargs-1.0.jar
+++ b/infrastructure/yuicompressor/lib/jargs-1.0.jar
Binary files differ
diff --git a/trunk/infrastructure/yuicompressor/lib/rhino-yuicompressor.jar b/infrastructure/yuicompressor/lib/rhino-yuicompressor.jar
index b99560e..b99560e 100644
--- a/trunk/infrastructure/yuicompressor/lib/rhino-yuicompressor.jar
+++ b/infrastructure/yuicompressor/lib/rhino-yuicompressor.jar
Binary files differ
diff --git a/trunk/infrastructure/yuicompressor/make.sh b/infrastructure/yuicompressor/make.sh
index 947aafa..947aafa 100755
--- a/trunk/infrastructure/yuicompressor/make.sh
+++ b/infrastructure/yuicompressor/make.sh
diff --git a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/Bootstrap.java b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/Bootstrap.java
index 1b95aca..1b95aca 100644
--- a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/Bootstrap.java
+++ b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/Bootstrap.java
diff --git a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/CssCompressor.java b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/CssCompressor.java
index 68b4de9..68b4de9 100644
--- a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/CssCompressor.java
+++ b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/CssCompressor.java
diff --git a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JarClassLoader.java b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JarClassLoader.java
index a6d3e13..a6d3e13 100644
--- a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JarClassLoader.java
+++ b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JarClassLoader.java
diff --git a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java
index e69ae1a..e69ae1a 100644
--- a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java
+++ b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java
diff --git a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java
index 8668f49..8668f49 100644
--- a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java
+++ b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java
diff --git a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java
index fee21d9..fee21d9 100644
--- a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java
+++ b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java
diff --git a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java
index c1a2e47..c1a2e47 100644
--- a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java
+++ b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java
diff --git a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/YUICompressor.java b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/YUICompressor.java
index dcbaff4..dcbaff4 100644
--- a/trunk/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/YUICompressor.java
+++ b/infrastructure/yuicompressor/src/com/yahoo/platform/yui/compressor/YUICompressor.java
diff --git a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java b/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java
index 348c568..348c568 100644
--- a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java
+++ b/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java
diff --git a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java b/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java
index bf830a8..bf830a8 100644
--- a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java
+++ b/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java
diff --git a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java b/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java
index f082d68..f082d68 100644
--- a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java
+++ b/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java
diff --git a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java b/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java
index 5bee827..5bee827 100644
--- a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java
+++ b/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java
diff --git a/trunk/README b/trunk/README
deleted file mode 100644
index a214853..0000000
--- a/trunk/README
+++ /dev/null
@@ -1,290 +0,0 @@
-EtherPad is a web-based realtime collaborative document editor.
-
-EtherPad currently lives at http://code.google.com/p/etherpad
-
-For instructions to build and run EtherPad, see: http://code.google.com/p/etherpad/wiki/Instructions
-
-This distribution includes some code written by other organizations.
-The rest is Copyright 2007-2009 Google Inc. and licensed under the Apache License 2.0.
-
->>>>>>>>>>>>>>
-Apache Commons Lang
-Copyright 2001-2008 The Apache Software Foundation
-
-This product includes software developed by
-The Apache Software Foundation (http://www.apache.org/).
-
-=========================================================================
-== NOTICE file corresponding to section 4(d) of the Apache License, ==
-== Version 2.0, in this case for the Apache Derby distribution. ==
-=========================================================================
-
->>>>>>>>>>>>>>
-Apache Derby
-Copyright 2004-2008 The Apache Software Foundation
-
-This product includes software developed by
-The Apache Software Foundation (http://www.apache.org/).
-
-Portions of Derby were originally developed by
-International Business Machines Corporation and are
-licensed to the Apache Software Foundation under the
-"Software Grant and Corporate Contribution License Agreement",
-informally known as the "Derby CLA".
-The following copyright notice(s) were affixed to portions of the code
-with which this file is now or was at one time distributed
-and are placed here unaltered.
-
-(C) Copyright 1997,2004 International Business Machines Corporation. All rights reserved.
-
-(C) Copyright IBM Corp. 2003.
-
-The portion of the functionTests under 'nist' was originally
-developed by the National Institute of Standards and Technology (NIST),
-an agency of the United States Department of Commerce, and adapted by
-International Business Machines Corporation in accordance with the NIST
-Software Acknowledgment and Redistribution document at
-http://www.itl.nist.gov/div897/ctg/sql_form.htm
-
->>>>>>>>>>>>>>
-Apache Harmony
-Copyright 2006, 2009 The Apache Software Foundation.
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-
-Portions of Apache Harmony were originally developed by
-Intel Corporation and are licensed to the Apache Software
-Foundation under the "Software Grant and Corporate Contribution
-License Agreement" and for which the following copyright notices
-apply
- (C) Copyright 2005 Intel Corporation
- (C) Copyright 2005-2006 Intel Corporation
- (C) Copyright 2006 Intel Corporation
-
->>>>>>>>>>>>>>
-==============================================================
- Jetty Web Container
- Copyright 1995-2006 Mort Bay Consulting Pty Ltd
-==============================================================
-
-The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd
-unless otherwise noted. It is licensed under the apache 2.0
-license.
-
-The javax.servlet package used by Jetty is copyright
-Sun Microsystems, Inc and Apache Software Foundation. It is
-distributed under the Common Development and Distribution License.
-You can obtain a copy of the license at
-https://glassfish.dev.java.net/public/CDDLv1.0.html.
-
-The UnixCrypt.java code ~Implements the one way cryptography used by
-Unix systems for simple password protection. Copyright 1996 Aki Yoshida,
-modified April 2001 by Iris Van den Broeke, Daniel Deville.
-Permission to use, copy, modify and distribute UnixCrypt
-for non-commercial or commercial purposes and without fee is
-granted provided that the copyright notice appears in all copies.
-
-The default JSP implementation is provided by the Glassfish JSP engine
-from project Glassfish http://glassfish.dev.java.net. Copyright 2005
-Sun Microsystems, Inc. and portions Copyright Apache Software Foundation.
-
-Some portions of the code are Copyright:
- 2006 Tim Vernum
- 1999 Jason Gilbert.
-
-The jboss integration module contains some LGPL code.
-
-The win32 Java Service Wrapper (v3.2.3) is Copyright (c) 1999, 2006
-Tanuki Software, Inc. and 2001 Silver Egg Technology. It is
-covered by an open license which is viewable at
-http://svn.codehaus.org/jetty/jetty/branches/jetty-6.1/extras/win32service/LICENSE.txt
-
->>>>>>>>>>>>>>
-Apache Sanselan
-Copyright 2007-2009 The Apache Software Foundation.
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-
->>>>>>>>>>>>>>
-TagSoup
-Copyright 2002-2008 by John Cowan
-
->>>>>>>>>>>>>>
-dnsjava:
-
-Copyright (c) 1999-2005, Brian Wellington
-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 dnsjava project nor the names of its 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.
-
->>>>>>>>>>>>>>
-jBCrypt:
-
-Copyright (c) 2006 Damien Miller
-
-Permission to use, copy, modify, and distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
->>>>>>>>>>>>>>
-Scala:
-
-Copyright (c) 2002-2009 EPFL, Lausanne, unless otherwise specified.
-All rights reserved.
-
-This software was developed by the Programming Methods Laboratory of the
-Swiss Federal Institute of Technology (EPFL), Lausanne, Switzerland.
-
-Permission to use, copy, modify, and distribute this software in source
-or binary form for any purpose with or without fee is hereby granted,
-provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. 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.
-
- 3. Neither the name of the EPFL nor the names of its contributors
- may be used to endorse or promote products derived from this
- software without specific prior written permission.
-
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
-
->>>>>>>>>>>>>>
-YUI Compressor:
-
-Copyright (c) 2009, Yahoo! Inc.
-All rights reserved.
-
-Redistribution and use of this software 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 Yahoo! Inc. nor the names of its contributors may be
- used to endorse or promote products derived from this software without
- specific prior written permission of Yahoo! Inc.
-
-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.
-
->>>>>>>>>>>>>>
-jQuery
-Copyright (c) 2009 John Resig, http://jquery.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.
-
->>>>>>>>>>>>>>
-jQuery Pulse:
-
-Copyright (c) 2008 James Padolsey - jp(at)qd9(dot)co.uk | http://james.padolsey.com / http://enhance.qd-creative.co.uk
-
-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.
-
->>>>>>>>>>>>>>
-SWFObject v1.5
-Copyright (c) 2007 Geoff Stearns
-
-Licensed under the MIT License
-
->>>>>>>>>>>>>>
-jQuery Context Menu Plugin:
-
-Original version copyright 2008 A Beautiful Site, LLC. Modifications by AppJet, Inc. released under the same license.
-
-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.
-
->>>>>>>>>>>>>>
-c3p0
-Copyright (c) 2006 Machinery for Change, Inc.
-
-Licensed under the LGPL 2.1
-
->>>>>>>>>>>>>>
-JCommon, JFreeChart
-Copyright (c) 2007-2009 Object Refinery Limited
-
-Licensed under the LGPL 2.1
-
->>>>>>>>>>>>>>
-Mozilla Rhino
-
-Licensed under the MPL 1.1, GPL 2.0 or later
-
-
->>>>>>>>>>>>>>
-MySQL Connector
-
-Licensed uder the GPL 2.0 or later with the FOSS exception
diff --git a/trunk/etherpad/bin/rebuildjar.sh b/trunk/etherpad/bin/rebuildjar.sh
deleted file mode 100755
index 9e802c2..0000000
--- a/trunk/etherpad/bin/rebuildjar.sh
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2009 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS-IS" 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.
-
-if [ -z "$JAR" ]; then
- if [ ! -z `which fastjar` ]; then
- JAR=fastjar
- else
- JAR=jar
- fi
-fi
-
-function notify {
- if [ ! -z `which growlnotify` ]; then
- echo $0 finished | growlnotify
- fi
-}
-trap notify EXIT
-
-source ../infrastructure/bin/compilecache.sh
-
-suffix="-dev";
-if [ "$1" == "prod" ]; then
- suffix="";
- shift;
-fi
-
-OWD=`pwd`
-cd ../infrastructure
-JAR=$JAR bin/makejar.sh $@
-
-rm -rf build/etherpad-jars
-mkdir -p build/etherpad-jars
-
-echo "including etherpad JARs..."
-
-JARFILES="echo ../etherpad/lib/*.jar"
-function genjar {
- echo "unzipping JARs..."
- pushd $1 >> /dev/null
-
- for a in ../../../etherpad/lib/*.jar; do
- $JAR xf $a
- rm -rf META-INF/{MANIFEST.MF,NOTICE{,.txt},LICENSE{,.txt},INDEX.LIST,SUN_MICR.{RSA,SF},maven}
- done
-
- popd >> /dev/null
-}
-cacheonfiles JAR-etherpad "$JARFILES" genjar 1
-
-echo "updating..."
-
-pushd buildcache/JAR-etherpad >> /dev/null
-$JAR uf ../../build/appjet.jar `ls . | grep -v "^t$"`
-
-echo "done."
-
-popd >> /dev/null
-
-dst="$OWD/appjet-eth$suffix.jar"
-cp -f build/appjet.jar $dst
-cd $OWD
-echo "wrote $dst"
diff --git a/trunk/etherpad/bin/run-local.sh b/trunk/etherpad/bin/run-local.sh
deleted file mode 100755
index 72b0cc1..0000000
--- a/trunk/etherpad/bin/run-local.sh
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2009 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS-IS" 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.
-
-mkdir -p data/appjet
-
-MXRAM="1G"
-if [ ! -z $1 ]; then
- if [ ! '-' = `echo $1 | head -c 1` ]; then
- MXRAM="$1";
- shift;
- fi
-fi
-
-CP="appjet-eth-dev.jar:data"
-for f in lib/*.jar; do
- CP="$CP:$f"
-done
-
-if [ -z "$JAVA" ]; then
- JAVA=java
-fi
-
-# etherpad properties file
-cfg_file=./data/etherpad.local.properties
-if [ ! -f $cfg_file ]; then
- cfg_file=./etc/etherpad.localdev-default.properties
-fi
-if [[ $1 == "--cfg" ]]; then
- cfg_file=${2}
- shift;
- shift;
-fi
-
-echo "Using config file: ${cfg_file}"
-
-$JAVA -classpath $CP \
- -server \
- -Xmx${MXRAM} \
- -Xms${MXRAM} \
- -Djava.awt.headless=true \
- -XX:MaxGCPauseMillis=500 \
- -XX:+UseConcMarkSweepGC \
- -XX:+CMSIncrementalMode \
- -XX:CMSIncrementalSafetyFactor=50 \
- -XX:+PrintGCDetails \
- -XX:+PrintGCTimeStamps \
- -Xloggc:./data/logs/backend/jvm-gc.log \
- -Dappjet.jmxremote=true \
- $JAVA_OPTS \
- net.appjet.oui.main \
- --configFile=${cfg_file} \
- "$@"
-
diff --git a/trunk/etherpad/bin/setup-mysql-db.sh b/trunk/etherpad/bin/setup-mysql-db.sh
deleted file mode 100755
index d823a9e..0000000
--- a/trunk/etherpad/bin/setup-mysql-db.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2009 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS-IS" 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.
-
-if [ `whoami` != "root" ]; then
- echo "Must run as root, i.e., sudo $0"
- exit 1
-fi
-
-db="etherpad"
-
-echo "Creating etherpad ${db}..."
-echo "create database ${db};" | ${mysql} -u root
-
-echo "Granting priviliges..."
-echo "grant all privileges on ${db}.* to 'etherpad'@'localhost' identified by 'password';" | ${mysql} -u root
-
-echo "Success"
diff --git a/trunk/etherpad/etc/etherpad.changeme.properties b/trunk/etherpad/etc/etherpad.changeme.properties
deleted file mode 100644
index ddc0bd8..0000000
--- a/trunk/etherpad/etc/etherpad.changeme.properties
+++ /dev/null
@@ -1,16 +0,0 @@
-ajstdlibHome = ../infrastructure/framework-src/modules
-appjetHome = ./data/appjet
-devMode = false
-etherpad.adminPass = password
-etherpad.fakeProduction = false
-etherpad.isProduction = true
-etherpad.SQL_JDBC_DRIVER = com.mysql.jdbc.Driver
-etherpad.SQL_JDBC_URL = jdbc:mysql://mysql:3306/etherpad
-etherpad.SQL_PASSWORD = password
-etherpad.SQL_USERNAME = etherpad
-listen = 0.0.0.0:80
-logDir = ./data/logs
-modulePath = ./src
-transportPrefix = /comet
-transportUseWildcardSubdomains = true
-useVirtualFileRoot = ./src
diff --git a/trunk/etherpad/etc/etherpad.localdev-default.properties b/trunk/etherpad/etc/etherpad.localdev-default.properties
deleted file mode 100644
index c2a2122..0000000
--- a/trunk/etherpad/etc/etherpad.localdev-default.properties
+++ /dev/null
@@ -1,16 +0,0 @@
-ajstdlibHome = ../infrastructure/framework-src/modules
-appjetHome = ./data/appjet
-devMode = true
-etherpad.adminPass = password
-etherpad.fakeProduction = false
-etherpad.isProduction = false
-etherpad.SQL_JDBC_DRIVER = com.mysql.jdbc.Driver
-etherpad.SQL_JDBC_URL = jdbc:mysql://localhost:3306/etherpad
-etherpad.SQL_PASSWORD = password
-etherpad.SQL_USERNAME = etherpad
-listen = 9000
-logDir = ./data/logs
-modulePath = ./src
-transportPrefix = /comet
-transportUseWildcardSubdomains = true
-useVirtualFileRoot = ./src
diff --git a/trunk/etherpad/lib/jbcrypt-0.2.jar b/trunk/etherpad/lib/jbcrypt-0.2.jar
deleted file mode 100644
index 109033c..0000000
--- a/trunk/etherpad/lib/jbcrypt-0.2.jar
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/etherpad/collab/ace/domline.js b/trunk/etherpad/src/etherpad/collab/ace/domline.js
deleted file mode 100644
index de2e7d3..0000000
--- a/trunk/etherpad/src/etherpad/collab/ace/domline.js
+++ /dev/null
@@ -1,210 +0,0 @@
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/domline.js
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-var domline = {};
-domline.noop = function() {};
-domline.identity = function(x) { return x; };
-
-domline.addToLineClass = function(lineClass, cls) {
- // an "empty span" at any point can be used to add classes to
- // the line, using line:className. otherwise, we ignore
- // the span.
- cls.replace(/\S+/g, function (c) {
- if (c.indexOf("line:") == 0) {
- // add class to line
- lineClass = (lineClass ? lineClass+' ' : '')+c.substring(5);
- }
- });
- return lineClass;
-}
-
-// if "document" is falsy we don't create a DOM node, just
-// an object with innerHTML and className
-domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument) {
- var result = { node: null,
- appendSpan: domline.noop,
- prepareForAdd: domline.noop,
- notifyAdded: domline.noop,
- clearSpans: domline.noop,
- finishUpdate: domline.noop,
- lineMarker: 0 };
-
- var browser = (optBrowser || {});
- var document = optDocument;
-
- if (document) {
- result.node = document.createElement("div");
- }
- else {
- result.node = {innerHTML: '', className: ''};
- }
-
- var html = [];
- var preHtml, postHtml;
- var curHTML = null;
- function processSpaces(s) {
- return domline.processSpaces(s, doesWrap);
- }
- var identity = domline.identity;
- var perTextNodeProcess = (doesWrap ? identity : processSpaces);
- var perHtmlLineProcess = (doesWrap ? processSpaces : identity);
- var lineClass = 'ace-line';
- result.appendSpan = function(txt, cls) {
- if (cls.indexOf('list') >= 0) {
- var listType = /(?:^| )list:(\S+)/.exec(cls);
- if (listType) {
- listType = listType[1];
- if (listType) {
- preHtml = '<ul class="list-'+listType+'"><li>';
- postHtml = '</li></ul>';
- }
- result.lineMarker += txt.length;
- return; // don't append any text
- }
- }
- var href = null;
- var simpleTags = null;
- if (cls.indexOf('url') >= 0) {
- cls = cls.replace(/(^| )url:(\S+)/g, function(x0, space, url) {
- href = url;
- return space+"url";
- });
- }
- if (cls.indexOf('tag') >= 0) {
- cls = cls.replace(/(^| )tag:(\S+)/g, function(x0, space, tag) {
- if (! simpleTags) simpleTags = [];
- simpleTags.push(tag.toLowerCase());
- return space+tag;
- });
- }
- if ((! txt) && cls) {
- lineClass = domline.addToLineClass(lineClass, cls);
- }
- else if (txt) {
- var extraOpenTags = "";
- var extraCloseTags = "";
- if (href) {
- extraOpenTags = extraOpenTags+'<a href="'+
- href.replace(/\"/g, '&quot;')+'">';
- extraCloseTags = '</a>'+extraCloseTags;
- }
- if (simpleTags) {
- simpleTags.sort();
- extraOpenTags = extraOpenTags+'<'+simpleTags.join('><')+'>';
- simpleTags.reverse();
- extraCloseTags = '</'+simpleTags.join('></')+'>'+extraCloseTags;
- }
- html.push('<span class="',cls||'','">',extraOpenTags,
- perTextNodeProcess(domline.escapeHTML(txt)),
- extraCloseTags,'</span>');
- }
- };
- result.clearSpans = function() {
- html = [];
- lineClass = ''; // non-null to cause update
- result.lineMarker = 0;
- };
- function writeHTML() {
- var newHTML = perHtmlLineProcess(html.join(''));
- if (! newHTML) {
- if ((! document) || (! optBrowser)) {
- newHTML += '&nbsp;';
- }
- else if (! browser.msie) {
- newHTML += '<br/>';
- }
- }
- if (nonEmpty) {
- newHTML = (preHtml||'')+newHTML+(postHtml||'');
- }
- html = preHtml = postHtml = null; // free memory
- if (newHTML !== curHTML) {
- curHTML = newHTML;
- result.node.innerHTML = curHTML;
- }
- if (lineClass !== null) result.node.className = lineClass;
- }
- result.prepareForAdd = writeHTML;
- result.finishUpdate = writeHTML;
- result.getInnerHTML = function() { return curHTML || ''; };
-
- return result;
-};
-
-domline.escapeHTML = function(s) {
- var re = /[&<>'"]/g; /']/; // stupid indentation thing
- if (! re.MAP) {
- // persisted across function calls!
- re.MAP = {
- '&': '&amp;',
- '<': '&lt;',
- '>': '&gt;',
- '"': '&#34;',
- "'": '&#39;'
- };
- }
- return s.replace(re, function(c) { return re.MAP[c]; });
-};
-
-domline.processSpaces = function(s, doesWrap) {
- if (s.indexOf("<") < 0 && ! doesWrap) {
- // short-cut
- return s.replace(/ /g, '&nbsp;');
- }
- var parts = [];
- s.replace(/<[^>]*>?| |[^ <]+/g, function(m) { parts.push(m); });
- if (doesWrap) {
- var endOfLine = true;
- var beforeSpace = false;
- // last space in a run is normal, others are nbsp,
- // end of line is nbsp
- for(var i=parts.length-1;i>=0;i--) {
- var p = parts[i];
- if (p == " ") {
- if (endOfLine || beforeSpace)
- parts[i] = '&nbsp;';
- endOfLine = false;
- beforeSpace = true;
- }
- else if (p.charAt(0) != "<") {
- endOfLine = false;
- beforeSpace = false;
- }
- }
- // beginning of line is nbsp
- for(var i=0;i<parts.length;i++) {
- var p = parts[i];
- if (p == " ") {
- parts[i] = '&nbsp;';
- break;
- }
- else if (p.charAt(0) != "<") {
- break;
- }
- }
- }
- else {
- for(var i=0;i<parts.length;i++) {
- var p = parts[i];
- if (p == " ") {
- parts[i] = '&nbsp;';
- }
- }
- }
- return parts.join('');
-};
diff --git a/trunk/etherpad/src/etherpad/collab/ace/easysync1.js b/trunk/etherpad/src/etherpad/collab/ace/easysync1.js
deleted file mode 100644
index 4f40aa0..0000000
--- a/trunk/etherpad/src/etherpad/collab/ace/easysync1.js
+++ /dev/null
@@ -1,923 +0,0 @@
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/easy_sync.js
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-function Changeset(arg) {
-
- var array;
- if ((typeof arg) == "string") {
- // constant
- array = [Changeset.MAGIC, 0, arg.length, 0, 0, arg];
- }
- else if ((typeof arg) == "number") {
- var n = Math.round(arg);
- // delete-all on n-length text (useful for making a "builder")
- array = [Changeset.MAGIC, n, 0, 0, 0, ""];
- }
- else if (! arg) {
- // identity on 0-length text
- array = [Changeset.MAGIC, 0, 0, 0, 0, ""];
- }
- else if (arg.isChangeset) {
- return arg;
- }
- else array = arg;
-
- array.isChangeset = true;
-
- // OOP style: attach generic methods to array object, hold no state in environment
-
- //function error(msg) { top.console.error(msg); top.console.trace(); }
- function error(msg) { var e = new Error(msg); e.easysync = true; throw e; }
- function assert(b, msg) { if (! b) error("Changeset: "+String(msg)); }
- function min(x, y) { return (x < y) ? x : y; }
- Changeset._assert = assert;
-
- array.isIdentity = function() {
- return this.length == 6 && this[1] == this[2] && this[3] == 0 &&
- this[4] == this[1] && this[5] == "";
- }
-
- array.eachStrip = function(func, thisObj) {
- // inside "func", the method receiver will be "this" by default,
- // or you can pass an object.
- for(var i=0;i<this.numStrips();i++) {
- var ptr = 3 + i*3;
- if (func.call(thisObj || this, this[ptr], this[ptr+1], this[ptr+2], i))
- return true;
- }
- return false;
- }
-
- array.numStrips = function() { return (this.length-3)/3; };
- array.oldLen = function() { return this[1]; };
- array.newLen = function() { return this[2]; };
-
- array.checkRep = function() {
- assert(this[0] == Changeset.MAGIC, "bad magic");
- assert(this[1] >= 0, "bad old text length");
- assert(this[2] >= 0, "bad new text length");
- assert((this.length % 3) == 0, "bad array length");
- assert(this.length >= 6, "must be at least one strip");
- var numStrips = this.numStrips();
- var oldLen = this[1];
- var newLen = this[2];
- // iterate over the "text strips"
- var actualNewLen = 0;
- this.eachStrip(function(startIndex, numTaken, newText, i) {
- var s = startIndex, t = numTaken, n = newText;
- var isFirst = (i == 0);
- var isLast = (i == numStrips-1);
- assert(t >= 0, "can't take negative number of chars");
- assert(isFirst || t > 0, "all strips but first must take");
- assert((t > 0) || (s == 0), "if first strip doesn't take, must have 0 startIndex");
- assert(s >= 0 && s + t <= oldLen, "bad index: "+this.toString());
- assert(t > 0 || n.length > 0 || (isFirst && isLast), "empty strip must be first and only");
- if (! isLast) {
- var s2 = this[3 + i*3 + 3]; // startIndex of following strip
- var gap = s2 - (s + t);
- assert(gap >= 0, "overlapping or out-of-order strips: "+this.toString());
- assert(gap > 0 || n.length > 0, "touching strips with no added text");
- }
- actualNewLen += t + n.length;
- });
- assert(newLen == actualNewLen, "calculated new text length doesn't match");
- }
-
- array.applyToText = function(text) {
- assert(text.length == this.oldLen(), "mismatched apply: "+text.length+" / "+this.oldLen());
- var buf = [];
- this.eachStrip(function (s, t, n) {
- buf.push(text.substr(s, t), n);
- });
- return buf.join('');
- }
-
- function _makeBuilder(oldLen, supportAuthors) {
- var C = Changeset(oldLen);
- if (supportAuthors) {
- _ensureAuthors(C);
- }
- return C.builder();
- }
-
- function _getNumInserted(C) {
- var numChars = 0;
- C.eachStrip(function(s,t,n) {
- numChars += n.length;
- });
- return numChars;
- }
-
- function _ensureAuthors(C) {
- if (! C.authors) {
- C.setAuthor();
- }
- return C;
- }
-
- array.setAuthor = function(author) {
- var C = this;
- // authors array has even length >= 2;
- // alternates [numChars1, author1, numChars2, author2];
- // all numChars > 0 unless there is exactly one, in which
- // case it can be == 0.
- C.authors = [_getNumInserted(C), author || ''];
- return C;
- }
-
- array.builder = function() {
- // normal pattern is Changeset(oldLength).builder().appendOldText(...). ...
- // builder methods mutate this!
- var C = this;
- // OOP style: state in environment
- var self;
- return self = {
- appendNewText: function(str, author) {
- C[C.length-1] += str;
- C[2] += str.length;
-
- if (C.authors) {
- var a = (author || '');
- var lastAuthorPtr = C.authors.length-1;
- var lastAuthorLengthPtr = C.authors.length-2;
- if ((!a) || a == C.authors[lastAuthorPtr]) {
- C.authors[lastAuthorLengthPtr] += str.length;
- }
- else if (0 == C.authors[lastAuthorLengthPtr]) {
- C.authors[lastAuthorLengthPtr] = str.length;
- C.authors[lastAuthorPtr] = (a || C.authors[lastAuthorPtr]);
- }
- else {
- C.authors.push(str.length, a);
- }
- }
-
- return self;
- },
- appendOldText: function(startIndex, numTaken) {
- if (numTaken == 0) return self;
- // properties of last strip...
- var s = C[C.length-3], t = C[C.length-2], n = C[C.length-1];
- if (t == 0 && n == "") {
- // must be empty changeset, one strip that doesn't take old chars or add new ones
- C[C.length-3] = startIndex;
- C[C.length-2] = numTaken;
- }
- else if (n == "" && (s+t == startIndex)) {
- C[C.length-2] += numTaken; // take more
- }
- else C.push(startIndex, numTaken, ""); // add a strip
- C[2] += numTaken;
- C.checkRep();
- return self;
- },
- toChangeset: function() { return C; }
- };
- }
-
- array.authorSlicer = function(outputBuilder) {
- return _makeAuthorSlicer(this, outputBuilder);
- }
-
- function _makeAuthorSlicer(changesetOrAuthorsIn, builderOut) {
- // "builderOut" only needs to support appendNewText
- var authors; // considered immutable
- if (changesetOrAuthorsIn.isChangeset) {
- authors = changesetOrAuthorsIn.authors;
- }
- else {
- authors = changesetOrAuthorsIn;
- }
-
- // OOP style: state in environment
- var authorPtr = 0;
- var charIndex = 0;
- var charWithinAuthor = 0; // 0 <= charWithinAuthor <= authors[authorPtr]; max value iff atEnd
- var atEnd = false;
- function curAuthor() { return authors[authorPtr+1]; }
- function curAuthorWidth() { return authors[authorPtr]; }
- function assertNotAtEnd() { assert(! atEnd, "_authorSlicer: can't move past end"); }
- function forwardInAuthor(numChars) {
- charWithinAuthor += numChars;
- charIndex += numChars;
- }
- function nextAuthor() {
- assertNotAtEnd();
- assert(charWithinAuthor == curAuthorWidth(), "_authorSlicer: not at author end");
- charWithinAuthor = 0;
- authorPtr += 2;
- if (authorPtr == authors.length) {
- atEnd = true;
- }
- }
-
- var self;
- return self = {
- skipChars: function(n) {
- assert(n >= 0, "_authorSlicer: can't skip negative n");
- if (n == 0) return;
- assertNotAtEnd();
-
- var leftToSkip = n;
- while (leftToSkip > 0) {
- var leftInAuthor = curAuthorWidth() - charWithinAuthor;
- if (leftToSkip >= leftInAuthor) {
- forwardInAuthor(leftInAuthor);
- leftToSkip -= leftInAuthor;
- nextAuthor();
- }
- else {
- forwardInAuthor(leftToSkip);
- leftToSkip = 0;
- }
- }
- },
- takeChars: function(n, text) {
- assert(n >= 0, "_authorSlicer: can't take negative n");
- if (n == 0) return;
- assertNotAtEnd();
- assert(n == text.length, "_authorSlicer: bad text length");
-
- var textLeft = text;
- var leftToTake = n;
- while (leftToTake > 0) {
- if (curAuthorWidth() > 0 && charWithinAuthor < curAuthorWidth()) {
- // at least one char to take from current author
- var leftInAuthor = (curAuthorWidth() - charWithinAuthor);
- assert(leftInAuthor > 0, "_authorSlicer: should have leftInAuthor > 0");
- var toTake = min(leftInAuthor, leftToTake);
- assert(toTake > 0, "_authorSlicer: should have toTake > 0");
- builderOut.appendNewText(textLeft.substring(0, toTake), curAuthor());
- forwardInAuthor(toTake);
- leftToTake -= toTake;
- textLeft = textLeft.substring(toTake);
- }
- assert(charWithinAuthor <= curAuthorWidth(), "_authorSlicer: past end of author");
- if (charWithinAuthor == curAuthorWidth()) {
- nextAuthor();
- }
- }
- },
- setBuilder: function(builder) {
- builderOut = builder;
- }
- };
- }
-
- function _makeSlicer(C, output) {
- // C: Changeset, output: builder from _makeBuilder
- // C is considered immutable, won't change or be changed
-
- // OOP style: state in environment
- var charIndex = 0; // 0 <= charIndex <= C.newLen(); maximum value iff atEnd
- var stripIndex = 0; // 0 <= stripIndex <= C.numStrips(); maximum value iff atEnd
- var charWithinStrip = 0; // 0 <= charWithinStrip < curStripWidth()
- var atEnd = false;
-
- var authorSlicer;
- if (C.authors) {
- authorSlicer = _makeAuthorSlicer(C.authors, output);
- }
-
- var ptr = 3;
- function curStartIndex() { return C[ptr]; }
- function curNumTaken() { return C[ptr+1]; }
- function curNewText() { return C[ptr+2]; }
- function curStripWidth() { return curNumTaken() + curNewText().length; }
- function assertNotAtEnd() { assert(! atEnd, "_slicer: can't move past changeset end"); }
- function forwardInStrip(numChars) {
- charWithinStrip += numChars;
- charIndex += numChars;
- }
- function nextStrip() {
- assertNotAtEnd();
- assert(charWithinStrip == curStripWidth(), "_slicer: not at strip end");
- charWithinStrip = 0;
- stripIndex++;
- ptr += 3;
- if (stripIndex == C.numStrips()) {
- atEnd = true;
- }
- }
- function curNumNewCharsInRange(start, end) {
- // takes two indices into the current strip's combined "taken" and "new"
- // chars, and returns how many "new" chars are included in the range
- assert(start <= end, "_slicer: curNumNewCharsInRange given out-of-order indices");
- var nt = curNumTaken();
- var nn = curNewText().length;
- var s = nt;
- var e = nt+nn;
- if (s < start) s = start;
- if (e > end) e = end;
- if (e < s) return 0;
- return e-s;
- }
-
- var self;
- return self = {
- skipChars: function (n) {
- assert(n >= 0, "_slicer: can't skip negative n");
- if (n == 0) return;
- assertNotAtEnd();
-
- var leftToSkip = n;
- while (leftToSkip > 0) {
- var leftInStrip = curStripWidth() - charWithinStrip;
- if (leftToSkip >= leftInStrip) {
- forwardInStrip(leftInStrip);
-
- if (authorSlicer)
- authorSlicer.skipChars(curNumNewCharsInRange(charWithinStrip,
- charWithinStrip + leftInStrip));
-
- leftToSkip -= leftInStrip;
- nextStrip();
- }
- else {
- if (authorSlicer)
- authorSlicer.skipChars(curNumNewCharsInRange(charWithinStrip,
- charWithinStrip + leftToSkip));
-
- forwardInStrip(leftToSkip);
- leftToSkip = 0;
- }
- }
- },
- takeChars: function (n) {
- assert(n >= 0, "_slicer: can't take negative n");
- if (n == 0) return;
- assertNotAtEnd();
-
- var leftToTake = n;
- while (leftToTake > 0) {
- if (curNumTaken() > 0 && charWithinStrip < curNumTaken()) {
- // at least one char to take from current strip's numTaken
- var leftInTaken = (curNumTaken() - charWithinStrip);
- assert(leftInTaken > 0, "_slicer: should have leftInTaken > 0");
- var toTake = min(leftInTaken, leftToTake);
- assert(toTake > 0, "_slicer: should have toTake > 0");
- output.appendOldText(curStartIndex() + charWithinStrip, toTake);
- forwardInStrip(toTake);
- leftToTake -= toTake;
- }
- if (leftToTake > 0 && curNewText().length > 0 && charWithinStrip >= curNumTaken() &&
- charWithinStrip < curStripWidth()) {
- // at least one char to take from current strip's newText
- var leftInNewText = (curStripWidth() - charWithinStrip);
- assert(leftInNewText > 0, "_slicer: should have leftInNewText > 0");
- var toTake = min(leftInNewText, leftToTake);
- assert(toTake > 0, "_slicer: should have toTake > 0");
- var newText = curNewText().substr(charWithinStrip - curNumTaken(), toTake);
- if (authorSlicer) {
- authorSlicer.takeChars(newText.length, newText);
- }
- else {
- output.appendNewText(newText);
- }
- forwardInStrip(toTake);
- leftToTake -= toTake;
- }
- assert(charWithinStrip <= curStripWidth(), "_slicer: past end of strip");
- if (charWithinStrip == curStripWidth()) {
- nextStrip();
- }
- }
- },
- skipTo: function(n) {
- self.skipChars(n - charIndex);
- }
- };
- }
-
- array.slicer = function(outputBuilder) {
- return _makeSlicer(this, outputBuilder);
- }
-
- array.compose = function(next) {
- assert(next.oldLen() == this.newLen(), "mismatched composition");
-
- var builder = _makeBuilder(this.oldLen(), !!(this.authors || next.authors));
- var slicer = _makeSlicer(this, builder);
-
- var authorSlicer;
- if (next.authors) {
- authorSlicer = _makeAuthorSlicer(next.authors, builder);
- }
-
- next.eachStrip(function(s, t, n) {
- slicer.skipTo(s);
- slicer.takeChars(t);
- if (authorSlicer) {
- authorSlicer.takeChars(n.length, n);
- }
- else {
- builder.appendNewText(n);
- }
- }, this);
-
- return builder.toChangeset();
- };
-
- array.traverser = function() {
- return _makeTraverser(this);
- }
-
- function _makeTraverser(C) {
- var s = C[3], t = C[4], n = C[5];
- var nextIndex = 6;
- var indexIntoNewText = 0;
-
- var authorSlicer;
- if (C.authors) {
- authorSlicer = _makeAuthorSlicer(C.authors, null);
- }
-
- function advanceIfPossible() {
- if (t == 0 && n == "" && nextIndex < C.length) {
- s = C[nextIndex];
- t = C[nextIndex+1];
- n = C[nextIndex+2];
- nextIndex += 3;
- }
- }
-
- var self;
- return self = {
- numTakenChars: function() {
- // if starts with taken characters, then how many, else 0
- return (t > 0) ? t : 0;
- },
- numNewChars: function() {
- // if starts with new characters, then how many, else 0
- return (t == 0 && n.length > 0) ? n.length : 0;
- },
- takenCharsStart: function() {
- return (self.numTakenChars() > 0) ? s : 0;
- },
- hasMore: function() {
- return self.numTakenChars() > 0 || self.numNewChars() > 0;
- },
- curIndex: function() {
- return indexIntoNewText;
- },
- consumeTakenChars: function (x) {
- assert(self.numTakenChars() > 0, "_traverser: no taken chars");
- assert(x >= 0 && x <= self.numTakenChars(), "_traverser: bad number of taken chars");
- if (x == 0) return;
- if (t == x) { s = 0; t = 0; }
- else { s += x; t -= x; }
- indexIntoNewText += x;
- advanceIfPossible();
- },
- consumeNewChars: function(x) {
- return self.appendNewChars(x, null);
- },
- appendNewChars: function(x, builder) {
- assert(self.numNewChars() > 0, "_traverser: no new chars");
- assert(x >= 0 && x <= self.numNewChars(), "_traverser: bad number of new chars");
- if (x == 0) return "";
- var str = n.substring(0, x);
- n = n.substring(x);
- indexIntoNewText += x;
- advanceIfPossible();
-
- if (builder) {
- if (authorSlicer) {
- authorSlicer.setBuilder(builder);
- authorSlicer.takeChars(x, str);
- }
- else {
- builder.appendNewText(str);
- }
- }
- else {
- if (authorSlicer) authorSlicer.skipChars(x);
- return str;
- }
- },
- consumeAvailableTakenChars: function() {
- return self.consumeTakenChars(self.numTakenChars());
- },
- consumeAvailableNewChars: function() {
- return self.consumeNewChars(self.numNewChars());
- },
- appendAvailableNewChars: function(builder) {
- return self.appendNewChars(self.numNewChars(), builder);
- }
- };
- }
-
- array.follow = function(prev, reverseInsertOrder) {
- // prev: Changeset, reverseInsertOrder: boolean
-
- // A.compose(B.follow(A)) is the merging of Changesets A and B, which operate on the same old text.
- // It is always the same as B.compose(A.follow(B, true)).
-
- assert(prev.oldLen() == this.oldLen(), "mismatched follow: "+prev.oldLen()+"/"+this.oldLen());
- var builder = _makeBuilder(prev.newLen(), !! this.authors);
- var a = _makeTraverser(prev);
- var b = _makeTraverser(this);
- while (a.hasMore() || b.hasMore()) {
- if (a.numNewChars() > 0 && ! reverseInsertOrder) {
- builder.appendOldText(a.curIndex(), a.numNewChars());
- a.consumeAvailableNewChars();
- }
- else if (b.numNewChars() > 0) {
- b.appendAvailableNewChars(builder);
- }
- else if (a.numNewChars() > 0 && reverseInsertOrder) {
- builder.appendOldText(a.curIndex(), a.numNewChars());
- a.consumeAvailableNewChars();
- }
- else if (! b.hasMore()) a.consumeAvailableTakenChars();
- else if (! a.hasMore()) b.consumeAvailableTakenChars();
- else {
- var x = a.takenCharsStart();
- var y = b.takenCharsStart();
- if (x < y) a.consumeTakenChars(min(a.numTakenChars(), y-x));
- else if (y < x) b.consumeTakenChars(min(b.numTakenChars(), x-y));
- else {
- var takenByBoth = min(a.numTakenChars(), b.numTakenChars());
- builder.appendOldText(a.curIndex(), takenByBoth);
- a.consumeTakenChars(takenByBoth);
- b.consumeTakenChars(takenByBoth);
- }
- }
- }
- return builder.toChangeset();
- }
-
- array.encodeToString = function(asBinary) {
- var stringDataArray = [];
- var numsArray = [];
- if (! asBinary) numsArray.push(this[0]);
- numsArray.push(this[1], this[2]);
- this.eachStrip(function(s, t, n) {
- numsArray.push(s, t, n.length);
- stringDataArray.push(n);
- }, this);
- if (! asBinary) {
- return numsArray.join(',')+'|'+stringDataArray.join('');
- }
- else {
- return "A" + Changeset.numberArrayToString(numsArray)
- +escapeCrazyUnicode(stringDataArray.join(''));
- }
- }
-
- function escapeCrazyUnicode(str) {
- return str.replace(/\\/g, '\\\\').replace(/[\ud800-\udfff]/g, function (c) {
- return "\\u"+("0000"+c.charCodeAt(0).toString(16)).slice(-4);
- });
- }
-
- array.applyToAttributedText = Changeset.applyToAttributedText;
-
- function splicesFromChanges(c) {
- var splices = [];
- // get a list of splices, [startChar, endChar, newText]
- var traverser = c.traverser();
- var oldTextLength = c.oldLen();
- var indexIntoOldText = 0;
- while (traverser.hasMore() || indexIntoOldText < oldTextLength) {
- var newText = "";
- var startChar = indexIntoOldText;
- var endChar = indexIntoOldText;
- if (traverser.numNewChars() > 0) {
- newText = traverser.consumeAvailableNewChars();
- }
- if (traverser.hasMore()) {
- endChar = traverser.takenCharsStart();
- indexIntoOldText = endChar + traverser.numTakenChars();
- traverser.consumeAvailableTakenChars();
- }
- else {
- endChar = oldTextLength;
- indexIntoOldText = endChar;
- }
- if (endChar != startChar || newText.length > 0) {
- splices.push([startChar, endChar, newText]);
- }
- }
- return splices;
- }
-
- array.toSplices = function() {
- return splicesFromChanges(this);
- }
-
- array.characterRangeFollowThis = function(selStartChar, selEndChar, insertionsAfter) {
- var changeset = this;
- // represent the selection as a changeset that replaces the selection with some finite string.
- // Because insertions indicate intention, it doesn't matter what this string is, and even
- // if the selectionChangeset is made to "follow" other changes it will still be the only
- // insertion.
- var selectionChangeset =
- Changeset(changeset.oldLen()).builder().appendOldText(0, selStartChar).appendNewText(
- "X").appendOldText(selEndChar, changeset.oldLen() - selEndChar).toChangeset();
- var newSelectionChangeset = selectionChangeset.follow(changeset, insertionsAfter);
- var selectionSplices = newSelectionChangeset.toSplices();
- function includeChar(i) {
- if (! includeChar.calledYet) {
- selStartChar = i;
- selEndChar = i;
- includeChar.calledYet = true;
- }
- else {
- if (i < selStartChar) selStartChar = i;
- if (i > selEndChar) selEndChar = i;
- }
- }
- for(var i=0; i<selectionSplices.length; i++) {
- var s = selectionSplices[i];
- includeChar(s[0]);
- includeChar(s[1]);
- }
- return [selStartChar, selEndChar];
- }
-
- return array;
-}
-
-Changeset.MAGIC = "Changeset";
-Changeset.makeSplice = function(oldLength, spliceStart, numRemoved, stringInserted) {
- oldLength = (oldLength || 0);
- spliceStart = (spliceStart || 0);
- numRemoved = (numRemoved || 0);
- stringInserted = String(stringInserted || "");
-
- var builder = Changeset(oldLength).builder();
- builder.appendOldText(0, spliceStart);
- builder.appendNewText(stringInserted);
- builder.appendOldText(spliceStart + numRemoved, oldLength - numRemoved - spliceStart);
- return builder.toChangeset();
-};
-Changeset.identity = function(len) {
- return Changeset(len).builder().appendOldText(0, len).toChangeset();
-};
-Changeset.decodeFromString = function(str) {
- function error(msg) { var e = new Error(msg); e.easysync = true; throw e; }
- function toHex(str) {
- var a = [];
- a.push("length["+str.length+"]:");
- var TRUNC=20;
- for(var i=0;i<str.substring(0,TRUNC).length;i++) {
- a.push(("000"+str.charCodeAt(i).toString(16)).slice(-4));
- }
- if (str.length > TRUNC) a.push("...");
- return a.join(' ');
- }
- function unescapeCrazyUnicode(str) {
- return str.replace(/\\(u....|\\)/g, function(seq) {
- if (seq == "\\\\") return "\\";
- return String.fromCharCode(Number("0x"+seq.substring(2)));
- });
- }
-
- var numData, stringData;
- var binary = false;
- var typ = str.charAt(0);
- if (typ == "B" || typ == "A") {
- var result = Changeset.numberArrayFromString(str, 1);
- numData = result[0];
- stringData = result[1];
- if (typ == "A") {
- stringData = unescapeCrazyUnicode(stringData);
- }
- binary = true;
- }
- else if (typ == "C") {
- var barPosition = str.indexOf('|');
- numData = str.substring(0, barPosition).split(',');
- stringData = str.substring(barPosition+1);
- }
- else {
- error("Not a changeset: "+toHex(str));
- }
- var stringDataOffset = 0;
- var array = [];
- var ptr;
- if (binary) {
- array.push("Changeset", numData[0], numData[1]);
- var ptr = 2;
- }
- else {
- array.push(numData[0], Number(numData[1]), Number(numData[2]));
- var ptr = 3;
- }
- while (ptr < numData.length) {
- array.push(Number(numData[ptr++]), Number(numData[ptr++]));
- var newTextLength = Number(numData[ptr++]);
- array.push(stringData.substr(stringDataOffset, newTextLength));
- stringDataOffset += newTextLength;
- }
- if (stringDataOffset != stringData.length) {
- error("Extra character data beyond end of encoded string ("+toHex(str)+")");
- }
- return Changeset(array);
-};
-
-Changeset.numberArrayToString = function(nums) {
- var array = [];
- function writeNum(n) {
- // does not support negative numbers
- var twentyEightBit = (n & 0xfffffff);
- if (twentyEightBit <= 0x7fff) {
- array.push(String.fromCharCode(twentyEightBit));
- }
- else {
- array.push(String.fromCharCode(0xa000 | (twentyEightBit >> 15),
- twentyEightBit & 0x7fff));
- }
- }
- writeNum(nums.length);
- var len = nums.length;
- for(var i=0;i<len;i++) {
- writeNum(nums[i]);
- }
- return array.join('');
-};
-
-Changeset.numberArrayFromString = function(str, startIndex) {
- // returns [numberArray, remainingString]
- var nums = [];
- var strIndex = (startIndex || 0);
- function readNum() {
- var n = str.charCodeAt(strIndex++);
- if (n > 0x7fff) {
- if (n >= 0xa000) {
- n = (((n & 0x1fff) << 15) | str.charCodeAt(strIndex++));
- }
- else {
- // legacy format
- n = (((n & 0x1fff) << 16) | str.charCodeAt(strIndex++));
- }
- }
- return n;
- }
- var len = readNum();
- for(var i=0;i<len;i++) {
- nums.push(readNum());
- }
- return [nums, str.substring(strIndex)];
-};
-
-(function() {
- function repeatString(str, times) {
- if (times <= 0) return "";
- var s = repeatString(str, times >> 1);
- s += s;
- if (times & 1) s += str;
- return s;
- }
- function chr(n) { return String.fromCharCode(n+48); }
- function ord(c) { return c.charCodeAt(0)-48; }
- function runMatcher(c) {
- // Takes "A" and returns /\u0041+/g .
- // Avoid creating new objects unnecessarily by caching matchers
- // as properties of this function.
- var re = runMatcher[c];
- if (re) return re;
- re = runMatcher[c] = new RegExp("\\u"+("0000"+c.charCodeAt(0).toString(16)).slice(-4)+"+", 'g');
- return re;
- }
- function runLength(str, idx, c) {
- var re = runMatcher(c);
- re.lastIndex = idx;
- var result = re.exec(str);
- if (result && result[0]) {
- return result[0].length;
- }
- return 0;
- }
-
- // emptyObj may be a StorableObject
- Changeset.initAttributedText = function(emptyObj, initialString, initialAuthor) {
- var obj = emptyObj;
- obj.authorMap = { 1: (initialAuthor || '') };
- obj.text = (initialString || '');
- obj.attribs = repeatString(chr(1), obj.text.length);
- return obj;
- };
- Changeset.gcAttributedText = function(atObj) {
- // "garbage collect" the list of authors
- var removedAuthors = [];
- for(var a in atObj.authorMap) {
- if (atObj.attribs.indexOf(chr(Number(a))) < 0) {
- removedAuthors.push(atObj.authorMap[a]);
- delete atObj.authorMap[a];
- }
- }
- return removedAuthors;
- };
- Changeset.cloneAttributedText = function(emptyObj, atObj) {
- var obj = emptyObj;
- obj.text = atObj.text; // string
- if (atObj.attribs) obj.attribs = atObj.attribs; // string
- if (atObj.attribs_c) obj.attribs_c = atObj.attribs_c; // string
- obj.authorMap = {};
- for(var a in atObj.authorMap) {
- obj.authorMap[a] = atObj.authorMap[a];
- }
- return obj;
- };
- Changeset.applyToAttributedText = function(atObj, C) {
- C = (C || this);
- var oldText = atObj.text;
- var oldAttribs = atObj.attribs;
- Changeset._assert(C.isChangeset, "applyToAttributedText: 'this' is not a changeset");
- Changeset._assert(oldText.length == C.oldLen(),
- "applyToAttributedText: mismatch "+oldText.length+" / "+C.oldLen());
- var textBuf = [];
- var attribsBuf = [];
- var authorMap = atObj.authorMap;
- function authorId(author) {
- for(var a in authorMap) {
- if (authorMap[Number(a)] === author) {
- return Number(a);
- }
- }
- for(var i=1;i<=60000;i++) {
- // don't use "in" because it's currently broken on StorableObjects
- if (authorMap[i] === undefined) {
- authorMap[i] = author;
- return i;
- }
- }
- }
- var myBuilder = { appendNewText: function(txt, author) {
- // object that acts as a "builder" in that it receives requests from
- // authorSlicer to append text attributed to different authors
- attribsBuf.push(repeatString(chr(authorId(author)), txt.length));
- } };
- var authorSlicer;
- if (C.authors) {
- authorSlicer = C.authorSlicer(myBuilder);
- }
- C.eachStrip(function (s, t, n) {
- textBuf.push(oldText.substr(s, t), n);
- attribsBuf.push(oldAttribs.substr(s, t));
- if (authorSlicer) {
- authorSlicer.takeChars(n.length, n);
- }
- else {
- myBuilder.appendNewText(n, '');
- }
- });
- atObj.text = textBuf.join('');
- atObj.attribs = attribsBuf.join('');
- return atObj;
- };
- Changeset.getAttributedTextCharAuthor = function(atObj, idx) {
- return atObj.authorMap[ord(atObj.attribs.charAt(idx))];
- };
- Changeset.getAttributedTextCharRunLength = function(atObj, idx) {
- var c = atObj.attribs.charAt(idx);
- return runLength(atObj.attribs, idx, c);
- };
- Changeset.eachAuthorInAttributedText = function(atObj, func) {
- // call func(author, authorNum)
- for(var a in atObj.authorMap) {
- if (func(atObj.authorMap[a], Number(a))) break;
- }
- };
- Changeset.getAttributedTextAuthorByNum = function(atObj, n) {
- return atObj.authorMap[n];
- };
- // Compressed attributed text can be cloned, but nothing else until uncompressed!!
- Changeset.compressAttributedText = function(atObj) {
- // idempotent, mutates the object, returns it
- if (atObj.attribs) {
- atObj.attribs_c = atObj.attribs.replace(/([\s\S])\1{0,63}/g, function(run) {
- return run.charAt(0)+chr(run.length);;
- });
- delete atObj.attribs;
- }
- return atObj;
- };
- Changeset.decompressAttributedText = function(atObj) {
- // idempotent, mutates the object, returns it
- if (atObj.attribs_c) {
- atObj.attribs = atObj.attribs_c.replace(/[\s\S][\s\S]/g, function(run) {
- return repeatString(run.charAt(0), ord(run.charAt(1)));
- });
- delete atObj.attribs_c;
- }
- return atObj;
- };
-})();
diff --git a/trunk/etherpad/src/etherpad/collab/ace/easysync2.js b/trunk/etherpad/src/etherpad/collab/ace/easysync2.js
deleted file mode 100644
index 0fa1ec4..0000000
--- a/trunk/etherpad/src/etherpad/collab/ace/easysync2.js
+++ /dev/null
@@ -1,1968 +0,0 @@
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/easysync2.js
-jimport("com.etherpad.Easysync2Support");
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-//var _opt = (this.Easysync2Support || null);
-var _opt = null; // disable optimization for now
-
-function AttribPool() {
- var p = {};
- p.numToAttrib = {}; // e.g. {0: ['foo','bar']}
- p.attribToNum = {}; // e.g. {'foo,bar': 0}
- p.nextNum = 0;
-
- p.putAttrib = function(attrib, dontAddIfAbsent) {
- var str = String(attrib);
- if (str in p.attribToNum) {
- return p.attribToNum[str];
- }
- if (dontAddIfAbsent) {
- return -1;
- }
- var num = p.nextNum++;
- p.attribToNum[str] = num;
- p.numToAttrib[num] = [String(attrib[0]||''),
- String(attrib[1]||'')];
- return num;
- };
-
- p.getAttrib = function(num) {
- var pair = p.numToAttrib[num];
- if (! pair) return pair;
- return [pair[0], pair[1]]; // return a mutable copy
- };
-
- p.getAttribKey = function(num) {
- var pair = p.numToAttrib[num];
- if (! pair) return '';
- return pair[0];
- };
-
- p.getAttribValue = function(num) {
- var pair = p.numToAttrib[num];
- if (! pair) return '';
- return pair[1];
- };
-
- p.eachAttrib = function(func) {
- for(var n in p.numToAttrib) {
- var pair = p.numToAttrib[n];
- func(pair[0], pair[1]);
- }
- };
-
- p.toJsonable = function() {
- return {numToAttrib: p.numToAttrib, nextNum: p.nextNum};
- };
-
- p.fromJsonable = function(obj) {
- p.numToAttrib = obj.numToAttrib;
- p.nextNum = obj.nextNum;
- p.attribToNum = {};
- for(var n in p.numToAttrib) {
- p.attribToNum[String(p.numToAttrib[n])] = Number(n);
- }
- return p;
- };
-
- return p;
-}
-
-var Changeset = {};
-
-Changeset.error = function error(msg) { var e = new Error(msg); e.easysync = true; throw e; };
-Changeset.assert = function assert(b, msgParts) {
- if (! b) {
- var msg = Array.prototype.slice.call(arguments, 1).join('');
- Changeset.error("Changeset: "+msg);
- }
-};
-
-Changeset.parseNum = function(str) { return parseInt(str, 36); };
-Changeset.numToString = function(num) { return num.toString(36).toLowerCase(); };
-Changeset.toBaseTen = function(cs) {
- var dollarIndex = cs.indexOf('$');
- var beforeDollar = cs.substring(0, dollarIndex);
- var fromDollar = cs.substring(dollarIndex);
- return beforeDollar.replace(/[0-9a-z]+/g, function(s) {
- return String(Changeset.parseNum(s)); }) + fromDollar;
-};
-
-Changeset.oldLen = function(cs) {
- return Changeset.unpack(cs).oldLen;
-};
-Changeset.newLen = function(cs) {
- return Changeset.unpack(cs).newLen;
-};
-
-Changeset.opIterator = function(opsStr, optStartIndex) {
- //print(opsStr);
- var regex = /((?:\*[0-9a-z]+)*)(?:\|([0-9a-z]+))?([-+=])([0-9a-z]+)|\?|/g;
- var startIndex = (optStartIndex || 0);
- var curIndex = startIndex;
- var prevIndex = curIndex;
- function nextRegexMatch() {
- prevIndex = curIndex;
- var result;
- if (_opt) {
- result = _opt.nextOpInString(opsStr, curIndex);
- if (result) {
- if (result.opcode() == '?') {
- Changeset.error("Hit error opcode in op stream");
- }
- curIndex = result.lastIndex();
- }
- }
- else {
- regex.lastIndex = curIndex;
- result = regex.exec(opsStr);
- curIndex = regex.lastIndex;
- if (result[0] == '?') {
- Changeset.error("Hit error opcode in op stream");
- }
- }
- return result;
- }
- var regexResult = nextRegexMatch();
- var obj = Changeset.newOp();
- function next(optObj) {
- var op = (optObj || obj);
- if (_opt && regexResult) {
- op.attribs = regexResult.attribs();
- op.lines = regexResult.lines();
- op.chars = regexResult.chars();
- op.opcode = regexResult.opcode();
- regexResult = nextRegexMatch();
- }
- else if ((! _opt) && regexResult[0]) {
- op.attribs = regexResult[1];
- op.lines = Changeset.parseNum(regexResult[2] || 0);
- op.opcode = regexResult[3];
- op.chars = Changeset.parseNum(regexResult[4]);
- regexResult = nextRegexMatch();
- }
- else {
- Changeset.clearOp(op);
- }
- return op;
- }
- function hasNext() { return !! (_opt ? regexResult : regexResult[0]); }
- function lastIndex() { return prevIndex; }
- return {next: next, hasNext: hasNext, lastIndex: lastIndex};
-};
-
-Changeset.clearOp = function(op) {
- op.opcode = '';
- op.chars = 0;
- op.lines = 0;
- op.attribs = '';
-};
-Changeset.newOp = function(optOpcode) {
- return {opcode:(optOpcode || ''), chars:0, lines:0, attribs:''};
-};
-Changeset.cloneOp = function(op) {
- return {opcode: op.opcode, chars: op.chars, lines: op.lines, attribs: op.attribs};
-};
-Changeset.copyOp = function(op1, op2) {
- op2.opcode = op1.opcode;
- op2.chars = op1.chars;
- op2.lines = op1.lines;
- op2.attribs = op1.attribs;
-};
-Changeset.opString = function(op) {
- // just for debugging
- if (! op.opcode) return 'null';
- var assem = Changeset.opAssembler();
- assem.append(op);
- return assem.toString();
-};
-Changeset.stringOp = function(str) {
- // just for debugging
- return Changeset.opIterator(str).next();
-};
-
-Changeset.checkRep = function(cs) {
- // doesn't check things that require access to attrib pool (e.g. attribute order)
- // or original string (e.g. newline positions)
- var unpacked = Changeset.unpack(cs);
- var oldLen = unpacked.oldLen;
- var newLen = unpacked.newLen;
- var ops = unpacked.ops;
- var charBank = unpacked.charBank;
-
- var assem = Changeset.smartOpAssembler();
- var oldPos = 0;
- var calcNewLen = 0;
- var numInserted = 0;
- var iter = Changeset.opIterator(ops);
- while (iter.hasNext()) {
- var o = iter.next();
- switch (o.opcode) {
- case '=': oldPos += o.chars; calcNewLen += o.chars; break;
- case '-': oldPos += o.chars; Changeset.assert(oldPos < oldLen, oldPos," >= ",oldLen," in ",cs); break;
- case '+': {
- calcNewLen += o.chars; numInserted += o.chars;
- Changeset.assert(calcNewLen < newLen, calcNewLen," >= ",newLen," in ",cs);
- break;
- }
- }
- assem.append(o);
- }
-
- calcNewLen += oldLen - oldPos;
- charBank = charBank.substring(0, numInserted);
- while (charBank.length < numInserted) {
- charBank += "?";
- }
-
- assem.endDocument();
- var normalized = Changeset.pack(oldLen, calcNewLen, assem.toString(), charBank);
- Changeset.assert(normalized == cs, normalized,' != ',cs);
-
- return cs;
-}
-
-Changeset.smartOpAssembler = function() {
- // Like opAssembler but able to produce conforming changesets
- // from slightly looser input, at the cost of speed.
- // Specifically:
- // - merges consecutive operations that can be merged
- // - strips final "="
- // - ignores 0-length changes
- // - reorders consecutive + and - (which margingOpAssembler doesn't do)
-
- var minusAssem = Changeset.mergingOpAssembler();
- var plusAssem = Changeset.mergingOpAssembler();
- var keepAssem = Changeset.mergingOpAssembler();
- var assem = Changeset.stringAssembler();
- var lastOpcode = '';
- var lengthChange = 0;
-
- function flushKeeps() {
- assem.append(keepAssem.toString());
- keepAssem.clear();
- }
-
- function flushPlusMinus() {
- assem.append(minusAssem.toString());
- minusAssem.clear();
- assem.append(plusAssem.toString());
- plusAssem.clear();
- }
-
- function append(op) {
- if (! op.opcode) return;
- if (! op.chars) return;
-
- if (op.opcode == '-') {
- if (lastOpcode == '=') {
- flushKeeps();
- }
- minusAssem.append(op);
- lengthChange -= op.chars;
- }
- else if (op.opcode == '+') {
- if (lastOpcode == '=') {
- flushKeeps();
- }
- plusAssem.append(op);
- lengthChange += op.chars;
- }
- else if (op.opcode == '=') {
- if (lastOpcode != '=') {
- flushPlusMinus();
- }
- keepAssem.append(op);
- }
- lastOpcode = op.opcode;
- }
-
- function appendOpWithText(opcode, text, attribs, pool) {
- var op = Changeset.newOp(opcode);
- op.attribs = Changeset.makeAttribsString(opcode, attribs, pool);
- var lastNewlinePos = text.lastIndexOf('\n');
- if (lastNewlinePos < 0) {
- op.chars = text.length;
- op.lines = 0;
- append(op);
- }
- else {
- op.chars = lastNewlinePos+1;
- op.lines = text.match(/\n/g).length;
- append(op);
- op.chars = text.length - (lastNewlinePos+1);
- op.lines = 0;
- append(op);
- }
- }
-
- function toString() {
- flushPlusMinus();
- flushKeeps();
- return assem.toString();
- }
-
- function clear() {
- minusAssem.clear();
- plusAssem.clear();
- keepAssem.clear();
- assem.clear();
- lengthChange = 0;
- }
-
- function endDocument() {
- keepAssem.endDocument();
- }
-
- function getLengthChange() {
- return lengthChange;
- }
-
- return {append: append, toString: toString, clear: clear, endDocument: endDocument,
- appendOpWithText: appendOpWithText, getLengthChange: getLengthChange };
-};
-
-if (_opt) {
- Changeset.mergingOpAssembler = function() {
- var assem = _opt.mergingOpAssembler();
-
- function append(op) {
- assem.append(op.opcode, op.chars, op.lines, op.attribs);
- }
- function toString() {
- return assem.toString();
- }
- function clear() {
- assem.clear();
- }
- function endDocument() {
- assem.endDocument();
- }
-
- return {append: append, toString: toString, clear: clear, endDocument: endDocument};
- };
-}
-else {
- Changeset.mergingOpAssembler = function() {
- // This assembler can be used in production; it efficiently
- // merges consecutive operations that are mergeable, ignores
- // no-ops, and drops final pure "keeps". It does not re-order
- // operations.
- var assem = Changeset.opAssembler();
- var bufOp = Changeset.newOp();
-
- // If we get, for example, insertions [xxx\n,yyy], those don't merge,
- // but if we get [xxx\n,yyy,zzz\n], that merges to [xxx\nyyyzzz\n].
- // This variable stores the length of yyy and any other newline-less
- // ops immediately after it.
- var bufOpAdditionalCharsAfterNewline = 0;
-
- function flush(isEndDocument) {
- if (bufOp.opcode) {
- if (isEndDocument && bufOp.opcode == '=' && ! bufOp.attribs) {
- // final merged keep, leave it implicit
- }
- else {
- assem.append(bufOp);
- if (bufOpAdditionalCharsAfterNewline) {
- bufOp.chars = bufOpAdditionalCharsAfterNewline;
- bufOp.lines = 0;
- assem.append(bufOp);
- bufOpAdditionalCharsAfterNewline = 0;
- }
- }
- bufOp.opcode = '';
- }
- }
- function append(op) {
- if (op.chars > 0) {
- if (bufOp.opcode == op.opcode && bufOp.attribs == op.attribs) {
- if (op.lines > 0) {
- // bufOp and additional chars are all mergeable into a multi-line op
- bufOp.chars += bufOpAdditionalCharsAfterNewline + op.chars;
- bufOp.lines += op.lines;
- bufOpAdditionalCharsAfterNewline = 0;
- }
- else if (bufOp.lines == 0) {
- // both bufOp and op are in-line
- bufOp.chars += op.chars;
- }
- else {
- // append in-line text to multi-line bufOp
- bufOpAdditionalCharsAfterNewline += op.chars;
- }
- }
- else {
- flush();
- Changeset.copyOp(op, bufOp);
- }
- }
- }
- function endDocument() {
- flush(true);
- }
- function toString() {
- flush();
- return assem.toString();
- }
- function clear() {
- assem.clear();
- Changeset.clearOp(bufOp);
- }
- return {append: append, toString: toString, clear: clear, endDocument: endDocument};
- };
-}
-
-if (_opt) {
- Changeset.opAssembler = function() {
- var assem = _opt.opAssembler();
- // this function allows op to be mutated later (doesn't keep a ref)
- function append(op) {
- assem.append(op.opcode, op.chars, op.lines, op.attribs);
- }
- function toString() {
- return assem.toString();
- }
- function clear() {
- assem.clear();
- }
- return {append: append, toString: toString, clear: clear};
- };
-}
-else {
- Changeset.opAssembler = function() {
- var pieces = [];
- // this function allows op to be mutated later (doesn't keep a ref)
- function append(op) {
- pieces.push(op.attribs);
- if (op.lines) {
- pieces.push('|', Changeset.numToString(op.lines));
- }
- pieces.push(op.opcode);
- pieces.push(Changeset.numToString(op.chars));
- }
- function toString() {
- return pieces.join('');
- }
- function clear() {
- pieces.length = 0;
- }
- return {append: append, toString: toString, clear: clear};
- };
-}
-
-Changeset.stringIterator = function(str) {
- var curIndex = 0;
- function assertRemaining(n) {
- Changeset.assert(n <= remaining(), "!(",n," <= ",remaining(),")");
- }
- function take(n) {
- assertRemaining(n);
- var s = str.substr(curIndex, n);
- curIndex += n;
- return s;
- }
- function peek(n) {
- assertRemaining(n);
- var s = str.substr(curIndex, n);
- return s;
- }
- function skip(n) {
- assertRemaining(n);
- curIndex += n;
- }
- function remaining() {
- return str.length - curIndex;
- }
- return {take:take, skip:skip, remaining:remaining, peek:peek};
-};
-
-Changeset.stringAssembler = function() {
- var pieces = [];
- function append(x) {
- pieces.push(String(x));
- }
- function toString() {
- return pieces.join('');
- }
- return {append: append, toString: toString};
-};
-
-// "lines" need not be an array as long as it supports certain calls (lines_foo inside).
-Changeset.textLinesMutator = function(lines) {
- // Mutates lines, an array of strings, in place.
- // Mutation operations have the same constraints as changeset operations
- // with respect to newlines, but not the other additional constraints
- // (i.e. ins/del ordering, forbidden no-ops, non-mergeability, final newline).
- // Can be used to mutate lists of strings where the last char of each string
- // is not actually a newline, but for the purposes of N and L values,
- // the caller should pretend it is, and for things to work right in that case, the input
- // to insert() should be a single line with no newlines.
-
- var curSplice = [0,0];
- var inSplice = false;
- // position in document after curSplice is applied:
- var curLine = 0, curCol = 0;
- // invariant: if (inSplice) then (curLine is in curSplice[0] + curSplice.length - {2,3}) &&
- // curLine >= curSplice[0]
- // invariant: if (inSplice && (curLine >= curSplice[0] + curSplice.length - 2)) then
- // curCol == 0
-
- function lines_applySplice(s) {
- lines.splice.apply(lines, s);
- }
- function lines_toSource() {
- return lines.toSource();
- }
- function lines_get(idx) {
- if (lines.get) {
- return lines.get(idx);
- }
- else {
- return lines[idx];
- }
- }
- // can be unimplemented if removeLines's return value not needed
- function lines_slice(start, end) {
- if (lines.slice) {
- return lines.slice(start, end);
- }
- else {
- return [];
- }
- }
- function lines_length() {
- if ((typeof lines.length) == "number") {
- return lines.length;
- }
- else {
- return lines.length();
- }
- }
-
- function enterSplice() {
- curSplice[0] = curLine;
- curSplice[1] = 0;
- if (curCol > 0) {
- putCurLineInSplice();
- }
- inSplice = true;
- }
- function leaveSplice() {
- lines_applySplice(curSplice);
- curSplice.length = 2;
- curSplice[0] = curSplice[1] = 0;
- inSplice = false;
- }
- function isCurLineInSplice() {
- return (curLine - curSplice[0] < (curSplice.length - 2));
- }
- function debugPrint(typ) {
- print(typ+": "+curSplice.toSource()+" / "+curLine+","+curCol+" / "+lines_toSource());
- }
- function putCurLineInSplice() {
- if (! isCurLineInSplice()) {
- curSplice.push(lines_get(curSplice[0] + curSplice[1]));
- curSplice[1]++;
- }
- return 2 + curLine - curSplice[0];
- }
-
- function skipLines(L, includeInSplice) {
- if (L) {
- if (includeInSplice) {
- if (! inSplice) {
- enterSplice();
- }
- for(var i=0;i<L;i++) {
- curCol = 0;
- putCurLineInSplice();
- curLine++;
- }
- }
- else {
- if (inSplice) {
- if (L > 1) {
- leaveSplice();
- }
- else {
- putCurLineInSplice();
- }
- }
- curLine += L;
- curCol = 0;
- }
- //print(inSplice+" / "+isCurLineInSplice()+" / "+curSplice[0]+" / "+curSplice[1]+" / "+lines.length);
- /*if (inSplice && (! isCurLineInSplice()) && (curSplice[0] + curSplice[1] < lines.length)) {
- print("BLAH");
- putCurLineInSplice();
- }*/ // tests case foo in remove(), which isn't otherwise covered in current impl
- }
- //debugPrint("skip");
- }
-
- function skip(N, L, includeInSplice) {
- if (N) {
- if (L) {
- skipLines(L, includeInSplice);
- }
- else {
- if (includeInSplice && ! inSplice) {
- enterSplice();
- }
- if (inSplice) {
- putCurLineInSplice();
- }
- curCol += N;
- //debugPrint("skip");
- }
- }
- }
-
- function removeLines(L) {
- var removed = '';
- if (L) {
- if (! inSplice) {
- enterSplice();
- }
- function nextKLinesText(k) {
- var m = curSplice[0] + curSplice[1];
- return lines_slice(m, m+k).join('');
- }
- if (isCurLineInSplice()) {
- //print(curCol);
- if (curCol == 0) {
- removed = curSplice[curSplice.length-1];
- // print("FOO"); // case foo
- curSplice.length--;
- removed += nextKLinesText(L-1);
- curSplice[1] += L-1;
- }
- else {
- removed = nextKLinesText(L-1);
- curSplice[1] += L-1;
- var sline = curSplice.length - 1;
- removed = curSplice[sline].substring(curCol) + removed;
- curSplice[sline] = curSplice[sline].substring(0, curCol) +
- lines_get(curSplice[0] + curSplice[1]);
- curSplice[1] += 1;
- }
- }
- else {
- removed = nextKLinesText(L);
- curSplice[1] += L;
- }
- //debugPrint("remove");
- }
- return removed;
- }
-
- function remove(N, L) {
- var removed = '';
- if (N) {
- if (L) {
- return removeLines(L);
- }
- else {
- if (! inSplice) {
- enterSplice();
- }
- var sline = putCurLineInSplice();
- removed = curSplice[sline].substring(curCol, curCol+N);
- curSplice[sline] = curSplice[sline].substring(0, curCol) +
- curSplice[sline].substring(curCol+N);
- //debugPrint("remove");
- }
- }
- return removed;
- }
-
- function insert(text, L) {
- if (text) {
- if (! inSplice) {
- enterSplice();
- }
- if (L) {
- var newLines = Changeset.splitTextLines(text);
- if (isCurLineInSplice()) {
- //if (curCol == 0) {
- //curSplice.length--;
- //curSplice[1]--;
- //Array.prototype.push.apply(curSplice, newLines);
- //curLine += newLines.length;
- //}
- //else {
- var sline = curSplice.length - 1;
- var theLine = curSplice[sline];
- var lineCol = curCol;
- curSplice[sline] = theLine.substring(0, lineCol) + newLines[0];
- curLine++;
- newLines.splice(0, 1);
- Array.prototype.push.apply(curSplice, newLines);
- curLine += newLines.length;
- curSplice.push(theLine.substring(lineCol));
- curCol = 0;
- //}
- }
- else {
- Array.prototype.push.apply(curSplice, newLines);
- curLine += newLines.length;
- }
- }
- else {
- var sline = putCurLineInSplice();
- curSplice[sline] = curSplice[sline].substring(0, curCol) +
- text + curSplice[sline].substring(curCol);
- curCol += text.length;
- }
- //debugPrint("insert");
- }
- }
-
- function hasMore() {
- //print(lines.length+" / "+inSplice+" / "+(curSplice.length - 2)+" / "+curSplice[1]);
- var docLines = lines_length();
- if (inSplice) {
- docLines += curSplice.length - 2 - curSplice[1];
- }
- return curLine < docLines;
- }
-
- function close() {
- if (inSplice) {
- leaveSplice();
- }
- //debugPrint("close");
- }
-
- var self = {skip:skip, remove:remove, insert:insert, close:close, hasMore:hasMore,
- removeLines:removeLines, skipLines: skipLines};
- return self;
-};
-
-Changeset.applyZip = function(in1, idx1, in2, idx2, func) {
- var iter1 = Changeset.opIterator(in1, idx1);
- var iter2 = Changeset.opIterator(in2, idx2);
- var assem = Changeset.smartOpAssembler();
- var op1 = Changeset.newOp();
- var op2 = Changeset.newOp();
- var opOut = Changeset.newOp();
- while (op1.opcode || iter1.hasNext() || op2.opcode || iter2.hasNext()) {
- if ((! op1.opcode) && iter1.hasNext()) iter1.next(op1);
- if ((! op2.opcode) && iter2.hasNext()) iter2.next(op2);
- func(op1, op2, opOut);
- if (opOut.opcode) {
- //print(opOut.toSource());
- assem.append(opOut);
- opOut.opcode = '';
- }
- }
- assem.endDocument();
- return assem.toString();
-};
-
-Changeset.unpack = function(cs) {
- var headerRegex = /Z:([0-9a-z]+)([><])([0-9a-z]+)|/;
- var headerMatch = headerRegex.exec(cs);
- if ((! headerMatch) || (! headerMatch[0])) {
- Changeset.error("Not a changeset: "+cs);
- }
- var oldLen = Changeset.parseNum(headerMatch[1]);
- var changeSign = (headerMatch[2] == '>') ? 1 : -1;
- var changeMag = Changeset.parseNum(headerMatch[3]);
- var newLen = oldLen + changeSign*changeMag;
- var opsStart = headerMatch[0].length;
- var opsEnd = cs.indexOf("$");
- if (opsEnd < 0) opsEnd = cs.length;
- return {oldLen: oldLen, newLen: newLen, ops: cs.substring(opsStart, opsEnd),
- charBank: cs.substring(opsEnd+1)};
-};
-
-Changeset.pack = function(oldLen, newLen, opsStr, bank) {
- var lenDiff = newLen - oldLen;
- var lenDiffStr = (lenDiff >= 0 ?
- '>'+Changeset.numToString(lenDiff) :
- '<'+Changeset.numToString(-lenDiff));
- var a = [];
- a.push('Z:', Changeset.numToString(oldLen), lenDiffStr, opsStr, '$', bank);
- return a.join('');
-};
-
-Changeset.applyToText = function(cs, str) {
- var unpacked = Changeset.unpack(cs);
- Changeset.assert(str.length == unpacked.oldLen,
- "mismatched apply: ",str.length," / ",unpacked.oldLen);
- var csIter = Changeset.opIterator(unpacked.ops);
- var bankIter = Changeset.stringIterator(unpacked.charBank);
- var strIter = Changeset.stringIterator(str);
- var assem = Changeset.stringAssembler();
- while (csIter.hasNext()) {
- var op = csIter.next();
- switch(op.opcode) {
- case '+': assem.append(bankIter.take(op.chars)); break;
- case '-': strIter.skip(op.chars); break;
- case '=': assem.append(strIter.take(op.chars)); break;
- }
- }
- assem.append(strIter.take(strIter.remaining()));
- return assem.toString();
-};
-
-Changeset.mutateTextLines = function(cs, lines) {
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var bankIter = Changeset.stringIterator(unpacked.charBank);
- var mut = Changeset.textLinesMutator(lines);
- while (csIter.hasNext()) {
- var op = csIter.next();
- switch(op.opcode) {
- case '+': mut.insert(bankIter.take(op.chars), op.lines); break;
- case '-': mut.remove(op.chars, op.lines); break;
- case '=': mut.skip(op.chars, op.lines, (!! op.attribs)); break;
- }
- }
- mut.close();
-};
-
-Changeset.composeAttributes = function(att1, att2, resultIsMutation, pool) {
- // att1 and att2 are strings like "*3*f*1c", asMutation is a boolean.
-
- // Sometimes attribute (key,value) pairs are treated as attribute presence
- // information, while other times they are treated as operations that
- // mutate a set of attributes, and this affects whether an empty value
- // is a deletion or a change.
- // Examples, of the form (att1Items, att2Items, resultIsMutation) -> result
- // ([], [(bold, )], true) -> [(bold, )]
- // ([], [(bold, )], false) -> []
- // ([], [(bold, true)], true) -> [(bold, true)]
- // ([], [(bold, true)], false) -> [(bold, true)]
- // ([(bold, true)], [(bold, )], true) -> [(bold, )]
- // ([(bold, true)], [(bold, )], false) -> []
-
- // pool can be null if att2 has no attributes.
-
- if ((! att1) && resultIsMutation) {
- // In the case of a mutation (i.e. composing two changesets),
- // an att2 composed with an empy att1 is just att2. If att1
- // is part of an attribution string, then att2 may remove
- // attributes that are already gone, so don't do this optimization.
- return att2;
- }
- if (! att2) return att1;
- var atts = [];
- att1.replace(/\*([0-9a-z]+)/g, function(_, a) {
- atts.push(pool.getAttrib(Changeset.parseNum(a)));
- return '';
- });
- att2.replace(/\*([0-9a-z]+)/g, function(_, a) {
- var pair = pool.getAttrib(Changeset.parseNum(a));
- var found = false;
- for(var i=0;i<atts.length;i++) {
- var oldPair = atts[i];
- if (oldPair[0] == pair[0]) {
- if (pair[1] || resultIsMutation) {
- oldPair[1] = pair[1];
- }
- else {
- atts.splice(i, 1);
- }
- found = true;
- break;
- }
- }
- if ((! found) && (pair[1] || resultIsMutation)) {
- atts.push(pair);
- }
- return '';
- });
- atts.sort();
- var buf = Changeset.stringAssembler();
- for(var i=0;i<atts.length;i++) {
- buf.append('*');
- buf.append(Changeset.numToString(pool.putAttrib(atts[i])));
- }
- //print(att1+" / "+att2+" / "+buf.toString());
- return buf.toString();
-};
-
-Changeset._slicerZipperFunc = function(attOp, csOp, opOut, pool) {
- // attOp is the op from the sequence that is being operated on, either an
- // attribution string or the earlier of two changesets being composed.
- // pool can be null if definitely not needed.
-
- //print(csOp.toSource()+" "+attOp.toSource()+" "+opOut.toSource());
- if (attOp.opcode == '-') {
- Changeset.copyOp(attOp, opOut);
- attOp.opcode = '';
- }
- else if (! attOp.opcode) {
- Changeset.copyOp(csOp, opOut);
- csOp.opcode = '';
- }
- else {
- switch (csOp.opcode) {
- case '-': {
- if (csOp.chars <= attOp.chars) {
- // delete or delete part
- if (attOp.opcode == '=') {
- opOut.opcode = '-';
- opOut.chars = csOp.chars;
- opOut.lines = csOp.lines;
- opOut.attribs = '';
- }
- attOp.chars -= csOp.chars;
- attOp.lines -= csOp.lines;
- csOp.opcode = '';
- if (! attOp.chars) {
- attOp.opcode = '';
- }
- }
- else {
- // delete and keep going
- if (attOp.opcode == '=') {
- opOut.opcode = '-';
- opOut.chars = attOp.chars;
- opOut.lines = attOp.lines;
- opOut.attribs = '';
- }
- csOp.chars -= attOp.chars;
- csOp.lines -= attOp.lines;
- attOp.opcode = '';
- }
- break;
- }
- case '+': {
- // insert
- Changeset.copyOp(csOp, opOut);
- csOp.opcode = '';
- break;
- }
- case '=': {
- if (csOp.chars <= attOp.chars) {
- // keep or keep part
- opOut.opcode = attOp.opcode;
- opOut.chars = csOp.chars;
- opOut.lines = csOp.lines;
- opOut.attribs = Changeset.composeAttributes(attOp.attribs, csOp.attribs,
- attOp.opcode == '=', pool);
- csOp.opcode = '';
- attOp.chars -= csOp.chars;
- attOp.lines -= csOp.lines;
- if (! attOp.chars) {
- attOp.opcode = '';
- }
- }
- else {
- // keep and keep going
- opOut.opcode = attOp.opcode;
- opOut.chars = attOp.chars;
- opOut.lines = attOp.lines;
- opOut.attribs = Changeset.composeAttributes(attOp.attribs, csOp.attribs,
- attOp.opcode == '=', pool);
- attOp.opcode = '';
- csOp.chars -= attOp.chars;
- csOp.lines -= attOp.lines;
- }
- break;
- }
- case '': {
- Changeset.copyOp(attOp, opOut);
- attOp.opcode = '';
- break;
- }
- }
- }
-};
-
-Changeset.applyToAttribution = function(cs, astr, pool) {
- var unpacked = Changeset.unpack(cs);
-
- return Changeset.applyZip(astr, 0, unpacked.ops, 0, function(op1, op2, opOut) {
- return Changeset._slicerZipperFunc(op1, op2, opOut, pool);
- });
-};
-
-/*Changeset.oneInsertedLineAtATimeOpIterator = function(opsStr, optStartIndex, charBank) {
- var iter = Changeset.opIterator(opsStr, optStartIndex);
- var bankIndex = 0;
-
-};*/
-
-Changeset.mutateAttributionLines = function(cs, lines, pool) {
- //dmesg(cs);
- //dmesg(lines.toSource()+" ->");
-
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var csBank = unpacked.charBank;
- var csBankIndex = 0;
- // treat the attribution lines as text lines, mutating a line at a time
- var mut = Changeset.textLinesMutator(lines);
-
- var lineIter = null;
- function isNextMutOp() {
- return (lineIter && lineIter.hasNext()) || mut.hasMore();
- }
- function nextMutOp(destOp) {
- if ((!(lineIter && lineIter.hasNext())) && mut.hasMore()) {
- var line = mut.removeLines(1);
- lineIter = Changeset.opIterator(line);
- }
- if (lineIter && lineIter.hasNext()) {
- lineIter.next(destOp);
- }
- else {
- destOp.opcode = '';
- }
- }
- var lineAssem = null;
- function outputMutOp(op) {
- //print("outputMutOp: "+op.toSource());
- if (! lineAssem) {
- lineAssem = Changeset.mergingOpAssembler();
- }
- lineAssem.append(op);
- if (op.lines > 0) {
- Changeset.assert(op.lines == 1, "Can't have op.lines of ",op.lines," in attribution lines");
- // ship it to the mut
- mut.insert(lineAssem.toString(), 1);
- lineAssem = null;
- }
- }
-
- var csOp = Changeset.newOp();
- var attOp = Changeset.newOp();
- var opOut = Changeset.newOp();
- while (csOp.opcode || csIter.hasNext() || attOp.opcode || isNextMutOp()) {
- if ((! csOp.opcode) && csIter.hasNext()) {
- csIter.next(csOp);
- }
- //print(csOp.toSource()+" "+attOp.toSource()+" "+opOut.toSource());
- //print(csOp.opcode+"/"+csOp.lines+"/"+csOp.attribs+"/"+lineAssem+"/"+lineIter+"/"+(lineIter?lineIter.hasNext():null));
- //print("csOp: "+csOp.toSource());
- if ((! csOp.opcode) && (! attOp.opcode) &&
- (! lineAssem) && (! (lineIter && lineIter.hasNext()))) {
- break; // done
- }
- else if (csOp.opcode == '=' && csOp.lines > 0 && (! csOp.attribs) && (! attOp.opcode) &&
- (! lineAssem) && (! (lineIter && lineIter.hasNext()))) {
- // skip multiple lines; this is what makes small changes not order of the document size
- mut.skipLines(csOp.lines);
- //print("skipped: "+csOp.lines);
- csOp.opcode = '';
- }
- else if (csOp.opcode == '+') {
- if (csOp.lines > 1) {
- var firstLineLen = csBank.indexOf('\n', csBankIndex) + 1 - csBankIndex;
- Changeset.copyOp(csOp, opOut);
- csOp.chars -= firstLineLen;
- csOp.lines--;
- opOut.lines = 1;
- opOut.chars = firstLineLen;
- }
- else {
- Changeset.copyOp(csOp, opOut);
- csOp.opcode = '';
- }
- outputMutOp(opOut);
- csBankIndex += opOut.chars;
- opOut.opcode = '';
- }
- else {
- if ((! attOp.opcode) && isNextMutOp()) {
- nextMutOp(attOp);
- }
- //print("attOp: "+attOp.toSource());
- Changeset._slicerZipperFunc(attOp, csOp, opOut, pool);
- if (opOut.opcode) {
- outputMutOp(opOut);
- opOut.opcode = '';
- }
- }
- }
-
- Changeset.assert(! lineAssem, "line assembler not finished");
- mut.close();
-
- //dmesg("-> "+lines.toSource());
-};
-
-Changeset.joinAttributionLines = function(theAlines) {
- var assem = Changeset.mergingOpAssembler();
- for(var i=0;i<theAlines.length;i++) {
- var aline = theAlines[i];
- var iter = Changeset.opIterator(aline);
- while (iter.hasNext()) {
- assem.append(iter.next());
- }
- }
- return assem.toString();
-};
-
-Changeset.splitAttributionLines = function(attrOps, text) {
- var iter = Changeset.opIterator(attrOps);
- var assem = Changeset.mergingOpAssembler();
- var lines = [];
- var pos = 0;
-
- function appendOp(op) {
- assem.append(op);
- if (op.lines > 0) {
- lines.push(assem.toString());
- assem.clear();
- }
- pos += op.chars;
- }
-
- while (iter.hasNext()) {
- var op = iter.next();
- var numChars = op.chars;
- var numLines = op.lines;
- while (numLines > 1) {
- var newlineEnd = text.indexOf('\n', pos)+1;
- Changeset.assert(newlineEnd > 0, "newlineEnd <= 0 in splitAttributionLines");
- op.chars = newlineEnd - pos;
- op.lines = 1;
- appendOp(op);
- numChars -= op.chars;
- numLines -= op.lines;
- }
- if (numLines == 1) {
- op.chars = numChars;
- op.lines = 1;
- }
- appendOp(op);
- }
-
- return lines;
-};
-
-Changeset.splitTextLines = function(text) {
- return text.match(/[^\n]*(?:\n|[^\n]$)/g);
-};
-
-Changeset.compose = function(cs1, cs2, pool) {
- var unpacked1 = Changeset.unpack(cs1);
- var unpacked2 = Changeset.unpack(cs2);
- var len1 = unpacked1.oldLen;
- var len2 = unpacked1.newLen;
- Changeset.assert(len2 == unpacked2.oldLen, "mismatched composition");
- var len3 = unpacked2.newLen;
- var bankIter1 = Changeset.stringIterator(unpacked1.charBank);
- var bankIter2 = Changeset.stringIterator(unpacked2.charBank);
- var bankAssem = Changeset.stringAssembler();
-
- var newOps = Changeset.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function(op1, op2, opOut) {
- //var debugBuilder = Changeset.stringAssembler();
- //debugBuilder.append(Changeset.opString(op1));
- //debugBuilder.append(',');
- //debugBuilder.append(Changeset.opString(op2));
- //debugBuilder.append(' / ');
-
- var op1code = op1.opcode;
- var op2code = op2.opcode;
- if (op1code == '+' && op2code == '-') {
- bankIter1.skip(Math.min(op1.chars, op2.chars));
- }
- Changeset._slicerZipperFunc(op1, op2, opOut, pool);
- if (opOut.opcode == '+') {
- if (op2code == '+') {
- bankAssem.append(bankIter2.take(opOut.chars));
- }
- else {
- bankAssem.append(bankIter1.take(opOut.chars));
- }
- }
-
- //debugBuilder.append(Changeset.opString(op1));
- //debugBuilder.append(',');
- //debugBuilder.append(Changeset.opString(op2));
- //debugBuilder.append(' -> ');
- //debugBuilder.append(Changeset.opString(opOut));
- //print(debugBuilder.toString());
- });
-
- return Changeset.pack(len1, len3, newOps, bankAssem.toString());
-};
-
-Changeset.attributeTester = function(attribPair, pool) {
- // returns a function that tests if a string of attributes
- // (e.g. *3*4) contains a given attribute key,value that
- // is already present in the pool.
- if (! pool) {
- return never;
- }
- var attribNum = pool.putAttrib(attribPair, true);
- if (attribNum < 0) {
- return never;
- }
- else {
- var re = new RegExp('\\*'+Changeset.numToString(attribNum)+
- '(?!\\w)');
- return function(attribs) {
- return re.test(attribs);
- };
- }
- function never(attribs) { return false; }
-};
-
-Changeset.identity = function(N) {
- return Changeset.pack(N, N, "", "");
-};
-
-Changeset.makeSplice = function(oldFullText, spliceStart, numRemoved, newText, optNewTextAPairs, pool) {
- var oldLen = oldFullText.length;
-
- if (spliceStart >= oldLen) {
- spliceStart = oldLen - 1;
- }
- if (numRemoved > oldFullText.length - spliceStart - 1) {
- numRemoved = oldFullText.length - spliceStart - 1;
- }
- var oldText = oldFullText.substring(spliceStart, spliceStart+numRemoved);
- var newLen = oldLen + newText.length - oldText.length;
-
- var assem = Changeset.smartOpAssembler();
- assem.appendOpWithText('=', oldFullText.substring(0, spliceStart));
- assem.appendOpWithText('-', oldText);
- assem.appendOpWithText('+', newText, optNewTextAPairs, pool);
- assem.endDocument();
- return Changeset.pack(oldLen, newLen, assem.toString(), newText);
-};
-
-Changeset.toSplices = function(cs) {
- // get a list of splices, [startChar, endChar, newText]
-
- var unpacked = Changeset.unpack(cs);
- var splices = [];
-
- var oldPos = 0;
- var iter = Changeset.opIterator(unpacked.ops);
- var charIter = Changeset.stringIterator(unpacked.charBank);
- var inSplice = false;
- while (iter.hasNext()) {
- var op = iter.next();
- if (op.opcode == '=') {
- oldPos += op.chars;
- inSplice = false;
- }
- else {
- if (! inSplice) {
- splices.push([oldPos, oldPos, ""]);
- inSplice = true;
- }
- if (op.opcode == '-') {
- oldPos += op.chars;
- splices[splices.length-1][1] += op.chars;
- }
- else if (op.opcode == '+') {
- splices[splices.length-1][2] += charIter.take(op.chars);
- }
- }
- }
-
- return splices;
-};
-
-Changeset.characterRangeFollow = function(cs, startChar, endChar, insertionsAfter) {
- var newStartChar = startChar;
- var newEndChar = endChar;
- var splices = Changeset.toSplices(cs);
- var lengthChangeSoFar = 0;
- for(var i=0;i<splices.length;i++) {
- var splice = splices[i];
- var spliceStart = splice[0] + lengthChangeSoFar;
- var spliceEnd = splice[1] + lengthChangeSoFar;
- var newTextLength = splice[2].length;
- var thisLengthChange = newTextLength - (spliceEnd - spliceStart);
-
- if (spliceStart <= newStartChar && spliceEnd >= newEndChar) {
- // splice fully replaces/deletes range
- // (also case that handles insertion at a collapsed selection)
- if (insertionsAfter) {
- newStartChar = newEndChar = spliceStart;
- }
- else {
- newStartChar = newEndChar = spliceStart + newTextLength;
- }
- }
- else if (spliceEnd <= newStartChar) {
- // splice is before range
- newStartChar += thisLengthChange;
- newEndChar += thisLengthChange;
- }
- else if (spliceStart >= newEndChar) {
- // splice is after range
- }
- else if (spliceStart >= newStartChar && spliceEnd <= newEndChar) {
- // splice is inside range
- newEndChar += thisLengthChange;
- }
- else if (spliceEnd < newEndChar) {
- // splice overlaps beginning of range
- newStartChar = spliceStart + newTextLength;
- newEndChar += thisLengthChange;
- }
- else {
- // splice overlaps end of range
- newEndChar = spliceStart;
- }
-
- lengthChangeSoFar += thisLengthChange;
- }
-
- return [newStartChar, newEndChar];
-};
-
-Changeset.moveOpsToNewPool = function(cs, oldPool, newPool) {
- // works on changeset or attribution string
- var dollarPos = cs.indexOf('$');
- if (dollarPos < 0) {
- dollarPos = cs.length;
- }
- var upToDollar = cs.substring(0, dollarPos);
- var fromDollar = cs.substring(dollarPos);
- // order of attribs stays the same
- return upToDollar.replace(/\*([0-9a-z]+)/g, function(_, a) {
- var oldNum = Changeset.parseNum(a);
- var pair = oldPool.getAttrib(oldNum);
- var newNum = newPool.putAttrib(pair);
- return '*'+Changeset.numToString(newNum);
- }) + fromDollar;
-};
-
-Changeset.makeAttribution = function(text) {
- var assem = Changeset.smartOpAssembler();
- assem.appendOpWithText('+', text);
- return assem.toString();
-};
-
-// callable on a changeset, attribution string, or attribs property of an op
-Changeset.eachAttribNumber = function(cs, func) {
- var dollarPos = cs.indexOf('$');
- if (dollarPos < 0) {
- dollarPos = cs.length;
- }
- var upToDollar = cs.substring(0, dollarPos);
-
- upToDollar.replace(/\*([0-9a-z]+)/g, function(_, a) {
- func(Changeset.parseNum(a));
- return '';
- });
-};
-
-// callable on a changeset, attribution string, or attribs property of an op,
-// though it may easily create adjacent ops that can be merged.
-Changeset.filterAttribNumbers = function(cs, filter) {
- return Changeset.mapAttribNumbers(cs, filter);
-};
-
-Changeset.mapAttribNumbers = function(cs, func) {
- var dollarPos = cs.indexOf('$');
- if (dollarPos < 0) {
- dollarPos = cs.length;
- }
- var upToDollar = cs.substring(0, dollarPos);
-
- var newUpToDollar = upToDollar.replace(/\*([0-9a-z]+)/g, function(s, a) {
- var n = func(Changeset.parseNum(a));
- if (n === true) {
- return s;
- }
- else if ((typeof n) === "number") {
- return '*'+Changeset.numToString(n);
- }
- else {
- return '';
- }
- });
-
- return newUpToDollar + cs.substring(dollarPos);
-};
-
-Changeset.makeAText = function(text, attribs) {
- return { text: text, attribs: (attribs || Changeset.makeAttribution(text)) };
-};
-
-Changeset.applyToAText = function(cs, atext, pool) {
- return { text: Changeset.applyToText(cs, atext.text),
- attribs: Changeset.applyToAttribution(cs, atext.attribs, pool) };
-};
-
-Changeset.cloneAText = function(atext) {
- return { text: atext.text, attribs: atext.attribs };
-};
-
-Changeset.copyAText = function(atext1, atext2) {
- atext2.text = atext1.text;
- atext2.attribs = atext1.attribs;
-};
-
-Changeset.appendATextToAssembler = function(atext, assem) {
- // intentionally skips last newline char of atext
- var iter = Changeset.opIterator(atext.attribs);
- var op = Changeset.newOp();
- while (iter.hasNext()) {
- iter.next(op);
- if (! iter.hasNext()) {
- // last op, exclude final newline
- if (op.lines <= 1) {
- op.lines = 0;
- op.chars--;
- if (op.chars) {
- assem.append(op);
- }
- }
- else {
- var nextToLastNewlineEnd =
- atext.text.lastIndexOf('\n', atext.text.length-2) + 1;
- var lastLineLength = atext.text.length - nextToLastNewlineEnd - 1;
- op.lines--;
- op.chars -= (lastLineLength + 1);
- assem.append(op);
- op.lines = 0;
- op.chars = lastLineLength;
- if (op.chars) {
- assem.append(op);
- }
- }
- }
- else {
- assem.append(op);
- }
- }
-};
-
-Changeset.prepareForWire = function(cs, pool) {
- var newPool = new AttribPool();
- var newCs = Changeset.moveOpsToNewPool(cs, pool, newPool);
- return {translated: newCs, pool: newPool};
-};
-
-Changeset.isIdentity = function(cs) {
- var unpacked = Changeset.unpack(cs);
- return unpacked.ops == "" && unpacked.oldLen == unpacked.newLen;
-};
-
-Changeset.opAttributeValue = function(op, key, pool) {
- return Changeset.attribsAttributeValue(op.attribs, key, pool);
-};
-
-Changeset.attribsAttributeValue = function(attribs, key, pool) {
- var value = '';
- if (attribs) {
- Changeset.eachAttribNumber(attribs, function(n) {
- if (pool.getAttribKey(n) == key) {
- value = pool.getAttribValue(n);
- }
- });
- }
- return value;
-};
-
-Changeset.builder = function(oldLen) {
- var assem = Changeset.smartOpAssembler();
- var o = Changeset.newOp();
- var charBank = Changeset.stringAssembler();
-
- var self = {
- // attribs are [[key1,value1],[key2,value2],...] or '*0*1...' (no pool needed in latter case)
- keep: function(N, L, attribs, pool) {
- o.opcode = '=';
- o.attribs = (attribs &&
- Changeset.makeAttribsString('=', attribs, pool)) || '';
- o.chars = N;
- o.lines = (L || 0);
- assem.append(o);
- return self;
- },
- keepText: function(text, attribs, pool) {
- assem.appendOpWithText('=', text, attribs, pool);
- return self;
- },
- insert: function(text, attribs, pool) {
- assem.appendOpWithText('+', text, attribs, pool);
- charBank.append(text);
- return self;
- },
- remove: function(N, L) {
- o.opcode = '-';
- o.attribs = '';
- o.chars = N;
- o.lines = (L || 0);
- assem.append(o);
- return self;
- },
- toString: function() {
- assem.endDocument();
- var newLen = oldLen + assem.getLengthChange();
- return Changeset.pack(oldLen, newLen, assem.toString(),
- charBank.toString());
- }
- };
-
- return self;
-};
-
-Changeset.makeAttribsString = function(opcode, attribs, pool) {
- // makeAttribsString(opcode, '*3') or makeAttribsString(opcode, [['foo','bar']], myPool) work
- if (! attribs) {
- return '';
- }
- else if ((typeof attribs) == "string") {
- return attribs;
- }
- else if (pool && attribs && attribs.length) {
- if (attribs.length > 1) {
- attribs = attribs.slice();
- attribs.sort();
- }
- var result = [];
- for(var i=0;i<attribs.length;i++) {
- var pair = attribs[i];
- if (opcode == '=' || (opcode == '+' && pair[1])) {
- result.push('*'+Changeset.numToString(pool.putAttrib(pair)));
- }
- }
- return result.join('');
- }
-};
-
-// like "substring" but on a single-line attribution string
-Changeset.subattribution = function(astr, start, optEnd) {
- var iter = Changeset.opIterator(astr, 0);
- var assem = Changeset.smartOpAssembler();
- var attOp = Changeset.newOp();
- var csOp = Changeset.newOp();
- var opOut = Changeset.newOp();
-
- function doCsOp() {
- if (csOp.chars) {
- while (csOp.opcode && (attOp.opcode || iter.hasNext())) {
- if (! attOp.opcode) iter.next(attOp);
-
- if (csOp.opcode && attOp.opcode && csOp.chars >= attOp.chars &&
- attOp.lines > 0 && csOp.lines <= 0) {
- csOp.lines++;
- }
-
- Changeset._slicerZipperFunc(attOp, csOp, opOut, null);
- if (opOut.opcode) {
- assem.append(opOut);
- opOut.opcode = '';
- }
- }
- }
- }
-
- csOp.opcode = '-';
- csOp.chars = start;
-
- doCsOp();
-
- if (optEnd === undefined) {
- if (attOp.opcode) {
- assem.append(attOp);
- }
- while (iter.hasNext()) {
- iter.next(attOp);
- assem.append(attOp);
- }
- }
- else {
- csOp.opcode = '=';
- csOp.chars = optEnd - start;
- doCsOp();
- }
-
- return assem.toString();
-};
-
-Changeset.inverse = function(cs, lines, alines, pool) {
- // lines and alines are what the changeset is meant to apply to.
- // They may be arrays or objects with .get(i) and .length methods.
- // They include final newlines on lines.
- function lines_get(idx) {
- if (lines.get) {
- return lines.get(idx);
- }
- else {
- return lines[idx];
- }
- }
- function lines_length() {
- if ((typeof lines.length) == "number") {
- return lines.length;
- }
- else {
- return lines.length();
- }
- }
- function alines_get(idx) {
- if (alines.get) {
- return alines.get(idx);
- }
- else {
- return alines[idx];
- }
- }
- function alines_length() {
- if ((typeof alines.length) == "number") {
- return alines.length;
- }
- else {
- return alines.length();
- }
- }
-
- var curLine = 0;
- var curChar = 0;
- var curLineOpIter = null;
- var curLineOpIterLine;
- var curLineNextOp = Changeset.newOp('+');
-
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var builder = Changeset.builder(unpacked.newLen);
-
- function consumeAttribRuns(numChars, func/*(len, attribs, endsLine)*/) {
-
- if ((! curLineOpIter) || (curLineOpIterLine != curLine)) {
- // create curLineOpIter and advance it to curChar
- curLineOpIter = Changeset.opIterator(alines_get(curLine));
- curLineOpIterLine = curLine;
- var indexIntoLine = 0;
- var done = false;
- while (! done) {
- curLineOpIter.next(curLineNextOp);
- if (indexIntoLine + curLineNextOp.chars >= curChar) {
- curLineNextOp.chars -= (curChar - indexIntoLine);
- done = true;
- }
- else {
- indexIntoLine += curLineNextOp.chars;
- }
- }
- }
-
- while (numChars > 0) {
- if ((! curLineNextOp.chars) && (! curLineOpIter.hasNext())) {
- curLine++;
- curChar = 0;
- curLineOpIterLine = curLine;
- curLineNextOp.chars = 0;
- curLineOpIter = Changeset.opIterator(alines_get(curLine));
- }
- if (! curLineNextOp.chars) {
- curLineOpIter.next(curLineNextOp);
- }
- var charsToUse = Math.min(numChars, curLineNextOp.chars);
- func(charsToUse, curLineNextOp.attribs,
- charsToUse == curLineNextOp.chars && curLineNextOp.lines > 0);
- numChars -= charsToUse;
- curLineNextOp.chars -= charsToUse;
- curChar += charsToUse;
- }
-
- if ((! curLineNextOp.chars) && (! curLineOpIter.hasNext())) {
- curLine++;
- curChar = 0;
- }
- }
-
- function skip(N, L) {
- if (L) {
- curLine += L;
- curChar = 0;
- }
- else {
- if (curLineOpIter && curLineOpIterLine == curLine) {
- consumeAttribRuns(N, function() {});
- }
- else {
- curChar += N;
- }
- }
- }
-
- function nextText(numChars) {
- var len = 0;
- var assem = Changeset.stringAssembler();
- var firstString = lines_get(curLine).substring(curChar);
- len += firstString.length;
- assem.append(firstString);
-
- var lineNum = curLine+1;
- while (len < numChars) {
- var nextString = lines_get(lineNum);
- len += nextString.length;
- assem.append(nextString);
- lineNum++;
- }
-
- return assem.toString().substring(0, numChars);
- }
-
- function cachedStrFunc(func) {
- var cache = {};
- return function(s) {
- if (! cache[s]) {
- cache[s] = func(s);
- }
- return cache[s];
- };
- }
-
- var attribKeys = [];
- var attribValues = [];
- while (csIter.hasNext()) {
- var csOp = csIter.next();
- if (csOp.opcode == '=') {
- if (csOp.attribs) {
- attribKeys.length = 0;
- attribValues.length = 0;
- Changeset.eachAttribNumber(csOp.attribs, function(n) {
- attribKeys.push(pool.getAttribKey(n));
- attribValues.push(pool.getAttribValue(n));
- });
- var undoBackToAttribs = cachedStrFunc(function(attribs) {
- var backAttribs = [];
- for(var i=0;i<attribKeys.length;i++) {
- var appliedKey = attribKeys[i];
- var appliedValue = attribValues[i];
- var oldValue = Changeset.attribsAttributeValue(attribs, appliedKey, pool);
- if (appliedValue != oldValue) {
- backAttribs.push([appliedKey, oldValue]);
- }
- }
- return Changeset.makeAttribsString('=', backAttribs, pool);
- });
- consumeAttribRuns(csOp.chars, function(len, attribs, endsLine) {
- builder.keep(len, endsLine ? 1 : 0, undoBackToAttribs(attribs));
- });
- }
- else {
- skip(csOp.chars, csOp.lines);
- builder.keep(csOp.chars, csOp.lines);
- }
- }
- else if (csOp.opcode == '+') {
- builder.remove(csOp.chars, csOp.lines);
- }
- else if (csOp.opcode == '-') {
- var textBank = nextText(csOp.chars);
- var textBankIndex = 0;
- consumeAttribRuns(csOp.chars, function(len, attribs, endsLine) {
- builder.insert(textBank.substr(textBankIndex, len), attribs);
- textBankIndex += len;
- });
- }
- }
-
- return Changeset.checkRep(builder.toString());
-};
-
-// %CLIENT FILE ENDS HERE%
-
-Changeset.follow = function(cs1, cs2, reverseInsertOrder, pool) {
- var unpacked1 = Changeset.unpack(cs1);
- var unpacked2 = Changeset.unpack(cs2);
- var len1 = unpacked1.oldLen;
- var len2 = unpacked2.oldLen;
- Changeset.assert(len1 == len2, "mismatched follow");
- var chars1 = Changeset.stringIterator(unpacked1.charBank);
- var chars2 = Changeset.stringIterator(unpacked2.charBank);
-
- var oldLen = unpacked1.newLen;
- var oldPos = 0;
- var newLen = 0;
-
- var hasInsertFirst = Changeset.attributeTester(['insertorder','first'],
- pool);
-
- var newOps = Changeset.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function(op1, op2, opOut) {
- if (op1.opcode == '+' || op2.opcode == '+') {
- var whichToDo;
- if (op2.opcode != '+') {
- whichToDo = 1;
- }
- else if (op1.opcode != '+') {
- whichToDo = 2;
- }
- else {
- // both +
- var firstChar1 = chars1.peek(1);
- var firstChar2 = chars2.peek(1);
- var insertFirst1 = hasInsertFirst(op1.attribs);
- var insertFirst2 = hasInsertFirst(op2.attribs);
- if (insertFirst1 && ! insertFirst2) {
- whichToDo = 1;
- }
- else if (insertFirst2 && ! insertFirst1) {
- whichToDo = 2;
- }
- // insert string that doesn't start with a newline first so as not to break up lines
- else if (firstChar1 == '\n' && firstChar2 != '\n') {
- whichToDo = 2;
- }
- else if (firstChar1 != '\n' && firstChar2 == '\n') {
- whichToDo = 1;
- }
- // break symmetry:
- else if (reverseInsertOrder) {
- whichToDo = 2;
- }
- else {
- whichToDo = 1;
- }
- }
- if (whichToDo == 1) {
- chars1.skip(op1.chars);
- opOut.opcode = '=';
- opOut.lines = op1.lines;
- opOut.chars = op1.chars;
- opOut.attribs = '';
- op1.opcode = '';
- }
- else {
- // whichToDo == 2
- chars2.skip(op2.chars);
- Changeset.copyOp(op2, opOut);
- op2.opcode = '';
- }
- }
- else if (op1.opcode == '-') {
- if (! op2.opcode) {
- op1.opcode = '';
- }
- else {
- if (op1.chars <= op2.chars) {
- op2.chars -= op1.chars;
- op2.lines -= op1.lines;
- op1.opcode = '';
- if (! op2.chars) {
- op2.opcode = '';
- }
- }
- else {
- op1.chars -= op2.chars;
- op1.lines -= op2.lines;
- op2.opcode = '';
- }
- }
- }
- else if (op2.opcode == '-') {
- Changeset.copyOp(op2, opOut);
- if (! op1.opcode) {
- op2.opcode = '';
- }
- else if (op2.chars <= op1.chars) {
- // delete part or all of a keep
- op1.chars -= op2.chars;
- op1.lines -= op2.lines;
- op2.opcode = '';
- if (! op1.chars) {
- op1.opcode = '';
- }
- }
- else {
- // delete all of a keep, and keep going
- opOut.lines = op1.lines;
- opOut.chars = op1.chars;
- op2.lines -= op1.lines;
- op2.chars -= op1.chars;
- op1.opcode = '';
- }
- }
- else if (! op1.opcode) {
- Changeset.copyOp(op2, opOut);
- op2.opcode = '';
- }
- else if (! op2.opcode) {
- Changeset.copyOp(op1, opOut);
- op1.opcode = '';
- }
- else {
- // both keeps
- opOut.opcode = '=';
- opOut.attribs = Changeset.followAttributes(op1.attribs, op2.attribs, pool);
- if (op1.chars <= op2.chars) {
- opOut.chars = op1.chars;
- opOut.lines = op1.lines;
- op2.chars -= op1.chars;
- op2.lines -= op1.lines;
- op1.opcode = '';
- if (! op2.chars) {
- op2.opcode = '';
- }
- }
- else {
- opOut.chars = op2.chars;
- opOut.lines = op2.lines;
- op1.chars -= op2.chars;
- op1.lines -= op2.lines;
- op2.opcode = '';
- }
- }
- switch (opOut.opcode) {
- case '=': oldPos += opOut.chars; newLen += opOut.chars; break;
- case '-': oldPos += opOut.chars; break;
- case '+': newLen += opOut.chars; break;
- }
- });
- newLen += oldLen - oldPos;
-
- return Changeset.pack(oldLen, newLen, newOps, unpacked2.charBank);
-};
-
-Changeset.followAttributes = function(att1, att2, pool) {
- // The merge of two sets of attribute changes to the same text
- // takes the lexically-earlier value if there are two values
- // for the same key. Otherwise, all key/value changes from
- // both attribute sets are taken. This operation is the "follow",
- // so a set of changes is produced that can be applied to att1
- // to produce the merged set.
- if ((! att2) || (! pool)) return '';
- if (! att1) return att2;
- var atts = [];
- att2.replace(/\*([0-9a-z]+)/g, function(_, a) {
- atts.push(pool.getAttrib(Changeset.parseNum(a)));
- return '';
- });
- att1.replace(/\*([0-9a-z]+)/g, function(_, a) {
- var pair1 = pool.getAttrib(Changeset.parseNum(a));
- for(var i=0;i<atts.length;i++) {
- var pair2 = atts[i];
- if (pair1[0] == pair2[0]) {
- if (pair1[1] <= pair2[1]) {
- // winner of merge is pair1, delete this attribute
- atts.splice(i, 1);
- }
- break;
- }
- }
- return '';
- });
- // we've only removed attributes, so they're already sorted
- var buf = Changeset.stringAssembler();
- for(var i=0;i<atts.length;i++) {
- buf.append('*');
- buf.append(Changeset.numToString(pool.putAttrib(atts[i])));
- }
- return buf.toString();
-};
diff --git a/trunk/etherpad/src/etherpad/collab/ace/easysync2_tests.js b/trunk/etherpad/src/etherpad/collab/ace/easysync2_tests.js
deleted file mode 100644
index 7a23dc0..0000000
--- a/trunk/etherpad/src/etherpad/collab/ace/easysync2_tests.js
+++ /dev/null
@@ -1,877 +0,0 @@
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/easysync2_tests.js
-import("etherpad.collab.ace.easysync2.*")
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-function runTests() {
-
- function print(str) {
- java.lang.System.out.println(str);
- }
-
- function assert(code, optMsg) {
- if (! eval(code)) throw new Error("FALSE: "+(optMsg || code));
- }
- function literal(v) {
- if ((typeof v) == "string") {
- return '"'+v.replace(/[\\\"]/g, '\\$1').replace(/\n/g, '\\n')+'"';
- }
- else return v.toSource();
- }
- function assertEqualArrays(a, b) {
- assert(literal(a)+".toSource() == "+literal(b)+".toSource()");
- }
- function assertEqualStrings(a, b) {
- assert(literal(a)+" == "+literal(b));
- }
-
- function throughIterator(opsStr) {
- var iter = Changeset.opIterator(opsStr);
- var assem = Changeset.opAssembler();
- while (iter.hasNext()) {
- assem.append(iter.next());
- }
- return assem.toString();
- }
-
- function throughSmartAssembler(opsStr) {
- var iter = Changeset.opIterator(opsStr);
- var assem = Changeset.smartOpAssembler();
- while (iter.hasNext()) {
- assem.append(iter.next());
- }
- assem.endDocument();
- return assem.toString();
- }
-
- (function() {
- print("> throughIterator");
- var x = '-c*3*4+6|3=az*asdf0*1*2*3+1=1-1+1*0+1=1-1+1|c=c-1';
- assert("throughIterator("+literal(x)+") == "+literal(x));
- })();
-
- (function() {
- print("> throughSmartAssembler");
- var x = '-c*3*4+6|3=az*asdf0*1*2*3+1=1-1+1*0+1=1-1+1|c=c-1';
- assert("throughSmartAssembler("+literal(x)+") == "+literal(x));
- })();
-
- function applyMutations(mu, arrayOfArrays) {
- arrayOfArrays.forEach(function (a) {
- var result = mu[a[0]].apply(mu, a.slice(1));
- if (a[0] == 'remove' && a[3]) {
- assertEqualStrings(a[3], result);
- }
- });
- }
-
- function mutationsToChangeset(oldLen, arrayOfArrays) {
- var assem = Changeset.smartOpAssembler();
- var op = Changeset.newOp();
- var bank = Changeset.stringAssembler();
- var oldPos = 0;
- var newLen = 0;
- arrayOfArrays.forEach(function (a) {
- if (a[0] == 'skip') {
- op.opcode = '=';
- op.chars = a[1];
- op.lines = (a[2] || 0);
- assem.append(op);
- oldPos += op.chars;
- newLen += op.chars;
- }
- else if (a[0] == 'remove') {
- op.opcode = '-';
- op.chars = a[1];
- op.lines = (a[2] || 0);
- assem.append(op);
- oldPos += op.chars;
- }
- else if (a[0] == 'insert') {
- op.opcode = '+';
- bank.append(a[1]);
- op.chars = a[1].length;
- op.lines = (a[2] || 0);
- assem.append(op);
- newLen += op.chars;
- }
- });
- newLen += oldLen - oldPos;
- assem.endDocument();
- return Changeset.pack(oldLen, newLen, assem.toString(),
- bank.toString());
- }
-
- function runMutationTest(testId, origLines, muts, correct) {
- print("> runMutationTest#"+testId);
- var lines = origLines.slice();
- var mu = Changeset.textLinesMutator(lines);
- applyMutations(mu, muts);
- mu.close();
- assertEqualArrays(correct, lines);
-
- var inText = origLines.join('');
- var cs = mutationsToChangeset(inText.length, muts);
- lines = origLines.slice();
- Changeset.mutateTextLines(cs, lines);
- assertEqualArrays(correct, lines);
-
- var correctText = correct.join('');
- //print(literal(cs));
- var outText = Changeset.applyToText(cs, inText);
- assertEqualStrings(correctText, outText);
- }
-
- runMutationTest(1, ["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"],
- [['remove',1,0,"a"],['insert',"tu"],['remove',1,0,"p"],['skip',4,1],['skip',7,1],
- ['insert',"cream\npie\n",2],['skip',2],['insert',"bot"],['insert',"\n",1],
- ['insert',"bu"],['skip',3],['remove',3,1,"ge\n"],['remove',6,0,"duffle"]],
- ["tuple\n","banana\n","cream\n","pie\n", "cabot\n","bubba\n","eggplant\n"]);
-
- runMutationTest(2, ["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"],
- [['remove',1,0,"a"],['remove',1,0,"p"],['insert',"tu"],['skip',11,2],
- ['insert',"cream\npie\n",2],['skip',2],['insert',"bot"],['insert',"\n",1],
- ['insert',"bu"],['skip',3],['remove',3,1,"ge\n"],['remove',6,0,"duffle"]],
- ["tuple\n","banana\n","cream\n","pie\n", "cabot\n","bubba\n","eggplant\n"]);
-
- runMutationTest(3, ["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"],
- [['remove',6,1,"apple\n"],['skip',15,2],['skip',6],['remove',1,1,"\n"],
- ['remove',8,0,"eggplant"],['skip',1,1]],
- ["banana\n","cabbage\n","duffle\n"]);
-
- runMutationTest(4, ["15\n"],
- [['skip',1],['insert',"\n2\n3\n4\n",4],['skip',2,1]],
- ["1\n","2\n","3\n","4\n","5\n"]);
-
- runMutationTest(5, ["1\n","2\n","3\n","4\n","5\n"],
- [['skip',1],['remove',7,4,"\n2\n3\n4\n"],['skip',2,1]],
- ["15\n"]);
-
- runMutationTest(6, ["123\n","abc\n","def\n","ghi\n","xyz\n"],
- [['insert',"0"],['skip',4,1],['skip',4,1],['remove',8,2,"def\nghi\n"],['skip',4,1]],
- ["0123\n", "abc\n", "xyz\n"]);
-
- runMutationTest(7, ["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"],
- [['remove',6,1,"apple\n"],['skip',15,2,true],['skip',6,0,true],['remove',1,1,"\n"],
- ['remove',8,0,"eggplant"],['skip',1,1,true]],
- ["banana\n","cabbage\n","duffle\n"]);
-
- function poolOrArray(attribs) {
- if (attribs.getAttrib) {
- return attribs; // it's already an attrib pool
- }
- else {
- // assume it's an array of attrib strings to be split and added
- var p = new AttribPool();
- attribs.forEach(function (kv) { p.putAttrib(kv.split(',')); });
- return p;
- }
- }
-
- function runApplyToAttributionTest(testId, attribs, cs, inAttr, outCorrect) {
- print("> applyToAttribution#"+testId);
- var p = poolOrArray(attribs);
- var result = Changeset.applyToAttribution(
- Changeset.checkRep(cs), inAttr, p);
- assertEqualStrings(outCorrect, result);
- }
-
- // turn c<b>a</b>ctus\n into a<b>c</b>tusabcd\n
- runApplyToAttributionTest(1, ['bold,', 'bold,true'],
- "Z:7>3-1*0=1*1=1=3+4$abcd",
- "+1*1+1|1+5", "+1*1+1|1+8");
-
- // turn "david\ngreenspan\n" into "<b>david\ngreen</b>\n"
- runApplyToAttributionTest(2, ['bold,', 'bold,true'],
- "Z:g<4*1|1=6*1=5-4$",
- "|2+g", "*1|1+6*1+5|1+1");
-
- (function() {
- print("> mutatorHasMore");
- var lines = ["1\n", "2\n", "3\n", "4\n"];
- var mu;
-
- mu = Changeset.textLinesMutator(lines);
- assert(mu.hasMore()+' == true');
- mu.skip(8,4);
- assert(mu.hasMore()+' == false');
- mu.close();
- assert(mu.hasMore()+' == false');
-
- // still 1,2,3,4
- mu = Changeset.textLinesMutator(lines);
- assert(mu.hasMore()+' == true');
- mu.remove(2,1);
- assert(mu.hasMore()+' == true');
- mu.skip(2,1);
- assert(mu.hasMore()+' == true');
- mu.skip(2,1);
- assert(mu.hasMore()+' == true');
- mu.skip(2,1);
- assert(mu.hasMore()+' == false');
- mu.insert("5\n", 1);
- assert(mu.hasMore()+' == false');
- mu.close();
- assert(mu.hasMore()+' == false');
-
- // 2,3,4,5 now
- mu = Changeset.textLinesMutator(lines);
- assert(mu.hasMore()+' == true');
- mu.remove(6,3);
- assert(mu.hasMore()+' == true');
- mu.remove(2,1);
- assert(mu.hasMore()+' == false');
- mu.insert("hello\n", 1);
- assert(mu.hasMore()+' == false');
- mu.close();
- assert(mu.hasMore()+' == false');
-
- })();
-
- function runMutateAttributionTest(testId, attribs, cs, alines, outCorrect) {
- print("> runMutateAttributionTest#"+testId);
- var p = poolOrArray(attribs);
- var alines2 = Array.prototype.slice.call(alines);
- var result = Changeset.mutateAttributionLines(
- Changeset.checkRep(cs), alines2, p);
- assertEqualArrays(outCorrect, alines2);
-
- print("> runMutateAttributionTest#"+testId+".applyToAttribution");
- function removeQuestionMarks(a) { return a.replace(/\?/g, ''); }
- var inMerged = Changeset.joinAttributionLines(alines.map(removeQuestionMarks));
- var correctMerged = Changeset.joinAttributionLines(outCorrect.map(removeQuestionMarks));
- var mergedResult = Changeset.applyToAttribution(cs, inMerged, p);
- assertEqualStrings(correctMerged, mergedResult);
- }
-
- // turn 123\n 456\n 789\n into 123\n 4<b>5</b>6\n 789\n
- runMutateAttributionTest(1, ["bold,true"], "Z:c>0|1=4=1*0=1$", ["|1+4", "|1+4", "|1+4"],
- ["|1+4", "+1*0+1|1+2", "|1+4"]);
-
- // make a document bold
- runMutateAttributionTest(2, ["bold,true"], "Z:c>0*0|3=c$", ["|1+4", "|1+4", "|1+4"],
- ["*0|1+4", "*0|1+4", "*0|1+4"]);
-
- // clear bold on document
- runMutateAttributionTest(3, ["bold,","bold,true"], "Z:c>0*0|3=c$",
- ["*1+1+1*1+1|1+1", "+1*1+1|1+2", "*1+1+1*1+1|1+1"],
- ["|1+4", "|1+4", "|1+4"]);
-
- // add a character on line 3 of a document with 5 blank lines, and make sure
- // the optimization that skips purely-kept lines is working; if any attribution string
- // with a '?' is parsed it will cause an error.
- runMutateAttributionTest(4, ['foo,bar','line,1','line,2','line,3','line,4','line,5'],
- "Z:5>1|2=2+1$x",
- ["?*1|1+1", "?*2|1+1", "*3|1+1", "?*4|1+1", "?*5|1+1"],
- ["?*1|1+1", "?*2|1+1", "+1*3|1+1", "?*4|1+1", "?*5|1+1"]);
-
- var testPoolWithChars = (function() {
- var p = new AttribPool();
- p.putAttrib(['char','newline']);
- for(var i=1;i<36;i++) {
- p.putAttrib(['char',Changeset.numToString(i)]);
- }
- p.putAttrib(['char','']);
- return p;
- })();
-
- // based on runMutationTest#1
- runMutateAttributionTest(5, testPoolWithChars,
- "Z:11>7-2*t+1*u+1|2=b|2+a=2*b+1*o+1*t+1*0|1+1*b+1*u+1=3|1-3-6$"+
- "tucream\npie\nbot\nbu",
- ["*a+1*p+2*l+1*e+1*0|1+1",
- "*b+1*a+1*n+1*a+1*n+1*a+1*0|1+1",
- "*c+1*a+1*b+2*a+1*g+1*e+1*0|1+1",
- "*d+1*u+1*f+2*l+1*e+1*0|1+1",
- "*e+1*g+2*p+1*l+1*a+1*n+1*t+1*0|1+1"],
- ["*t+1*u+1*p+1*l+1*e+1*0|1+1",
- "*b+1*a+1*n+1*a+1*n+1*a+1*0|1+1",
- "|1+6",
- "|1+4",
- "*c+1*a+1*b+1*o+1*t+1*0|1+1",
- "*b+1*u+1*b+2*a+1*0|1+1",
- "*e+1*g+2*p+1*l+1*a+1*n+1*t+1*0|1+1"]);
-
- // based on runMutationTest#3
- runMutateAttributionTest(6, testPoolWithChars,
- "Z:11<f|1-6|2=f=6|1-1-8$",
- ["*a|1+6", "*b|1+7", "*c|1+8", "*d|1+7", "*e|1+9"],
- ["*b|1+7", "*c|1+8", "*d+6*e|1+1"]);
-
- // based on runMutationTest#4
- runMutateAttributionTest(7, testPoolWithChars,
- "Z:3>7=1|4+7$\n2\n3\n4\n",
- ["*1+1*5|1+2"],
- ["*1+1|1+1","|1+2","|1+2","|1+2","*5|1+2"]);
-
- // based on runMutationTest#5
- runMutateAttributionTest(8, testPoolWithChars,
- "Z:a<7=1|4-7$",
- ["*1|1+2","*2|1+2","*3|1+2","*4|1+2","*5|1+2"],
- ["*1+1*5|1+2"]);
-
- // based on runMutationTest#6
- runMutateAttributionTest(9, testPoolWithChars,
- "Z:k<7*0+1*10|2=8|2-8$0",
- ["*1+1*2+1*3+1|1+1","*a+1*b+1*c+1|1+1",
- "*d+1*e+1*f+1|1+1","*g+1*h+1*i+1|1+1","?*x+1*y+1*z+1|1+1"],
- ["*0+1|1+4", "|1+4", "?*x+1*y+1*z+1|1+1"]);
-
- runMutateAttributionTest(10, testPoolWithChars,
- "Z:6>4=1+1=1+1|1=1+1=1*0+1$abcd",
- ["|1+3", "|1+3"],
- ["|1+5", "+2*0+1|1+2"]);
-
-
- runMutateAttributionTest(11, testPoolWithChars,
- "Z:s>1|1=4=6|1+1$\n",
- ["*0|1+4", "*0|1+8", "*0+5|1+1", "*0|1+1", "*0|1+5", "*0|1+1", "*0|1+1", "*0|1+1", "|1+1"],
- ["*0|1+4", "*0+6|1+1", "*0|1+2", "*0+5|1+1", "*0|1+1", "*0|1+5", "*0|1+1", "*0|1+1", "*0|1+1", "|1+1"]);
-
- function randomInlineString(len, rand) {
- var assem = Changeset.stringAssembler();
- for(var i=0;i<len;i++) {
- assem.append(String.fromCharCode(rand.nextInt(26) + 97));
- }
- return assem.toString();
- }
-
- function randomMultiline(approxMaxLines, approxMaxCols, rand) {
- var numParts = rand.nextInt(approxMaxLines*2)+1;
- var txt = Changeset.stringAssembler();
- txt.append(rand.nextInt(2) ? '\n' : '');
- for(var i=0;i<numParts;i++) {
- if ((i % 2) == 0) {
- if (rand.nextInt(10)) {
- txt.append(randomInlineString(rand.nextInt(approxMaxCols)+1, rand));
- }
- else {
- txt.append('\n');
- }
- }
- else {
- txt.append('\n');
- }
- }
- return txt.toString();
- }
-
- function randomStringOperation(numCharsLeft, rand) {
- var result;
- switch(rand.nextInt(9)) {
- case 0: {
- // insert char
- result = {insert: randomInlineString(1, rand)};
- break;
- }
- case 1: {
- // delete char
- result = {remove: 1};
- break;
- }
- case 2: {
- // skip char
- result = {skip: 1};
- break;
- }
- case 3: {
- // insert small
- result = {insert: randomInlineString(rand.nextInt(4)+1, rand)};
- break;
- }
- case 4: {
- // delete small
- result = {remove: rand.nextInt(4)+1};
- break;
- }
- case 5: {
- // skip small
- result = {skip: rand.nextInt(4)+1};
- break;
- }
- case 6: {
- // insert multiline;
- result = {insert: randomMultiline(5, 20, rand)};
- break;
- }
- case 7: {
- // delete multiline
- result = {remove: Math.round(numCharsLeft * rand.nextDouble() * rand.nextDouble()) };
- break;
- }
- case 8: {
- // skip multiline
- result = {skip: Math.round(numCharsLeft * rand.nextDouble() * rand.nextDouble()) };
- break;
- }
- case 9: {
- // delete to end
- result = {remove: numCharsLeft};
- break;
- }
- case 10: {
- // skip to end
- result = {skip: numCharsLeft};
- break;
- }
- }
- var maxOrig = numCharsLeft - 1;
- if ('remove' in result) {
- result.remove = Math.min(result.remove, maxOrig);
- }
- else if ('skip' in result) {
- result.skip = Math.min(result.skip, maxOrig);
- }
- return result;
- }
-
- function randomTwoPropAttribs(opcode, rand) {
- // assumes attrib pool like ['apple,','apple,true','banana,','banana,true']
- if (opcode == '-' || rand.nextInt(3)) {
- return '';
- }
- else if (rand.nextInt(3)) {
- if (opcode == '+' || rand.nextInt(2)) {
- return '*'+Changeset.numToString(rand.nextInt(2)*2+1);
- }
- else {
- return '*'+Changeset.numToString(rand.nextInt(2)*2);
- }
- }
- else {
- if (opcode == '+' || rand.nextInt(4) == 0) {
- return '*1*3';
- }
- else {
- return ['*0*2', '*0*3', '*1*2'][rand.nextInt(3)];
- }
- }
- }
-
- function randomTestChangeset(origText, rand, withAttribs) {
- var charBank = Changeset.stringAssembler();
- var textLeft = origText; // always keep final newline
- var outTextAssem = Changeset.stringAssembler();
- var opAssem = Changeset.smartOpAssembler();
- var oldLen = origText.length;
-
- var nextOp = Changeset.newOp();
- function appendMultilineOp(opcode, txt) {
- nextOp.opcode = opcode;
- if (withAttribs) {
- nextOp.attribs = randomTwoPropAttribs(opcode, rand);
- }
- txt.replace(/\n|[^\n]+/g, function (t) {
- if (t == '\n') {
- nextOp.chars = 1;
- nextOp.lines = 1;
- opAssem.append(nextOp);
- }
- else {
- nextOp.chars = t.length;
- nextOp.lines = 0;
- opAssem.append(nextOp);
- }
- return '';
- });
- }
-
- function doOp() {
- var o = randomStringOperation(textLeft.length, rand);
- if (o.insert) {
- var txt = o.insert;
- charBank.append(txt);
- outTextAssem.append(txt);
- appendMultilineOp('+', txt);
- }
- else if (o.skip) {
- var txt = textLeft.substring(0, o.skip);
- textLeft = textLeft.substring(o.skip);
- outTextAssem.append(txt);
- appendMultilineOp('=', txt);
- }
- else if (o.remove) {
- var txt = textLeft.substring(0, o.remove);
- textLeft = textLeft.substring(o.remove);
- appendMultilineOp('-', txt);
- }
- }
-
- while (textLeft.length > 1) doOp();
- for(var i=0;i<5;i++) doOp(); // do some more (only insertions will happen)
-
- var outText = outTextAssem.toString()+'\n';
- opAssem.endDocument();
- var cs = Changeset.pack(oldLen, outText.length, opAssem.toString(), charBank.toString());
- Changeset.checkRep(cs);
- return [cs, outText];
- }
-
- function testCompose(randomSeed) {
- var rand = new java.util.Random(randomSeed);
- print("> testCompose#"+randomSeed);
-
- var p = new AttribPool();
-
- var startText = randomMultiline(10, 20, rand)+'\n';
-
- var x1 = randomTestChangeset(startText, rand);
- var change1 = x1[0];
- var text1 = x1[1];
-
- var x2 = randomTestChangeset(text1, rand);
- var change2 = x2[0];
- var text2 = x2[1];
-
- var x3 = randomTestChangeset(text2, rand);
- var change3 = x3[0];
- var text3 = x3[1];
-
- //print(literal(Changeset.toBaseTen(startText)));
- //print(literal(Changeset.toBaseTen(change1)));
- //print(literal(Changeset.toBaseTen(change2)));
- var change12 = Changeset.checkRep(Changeset.compose(change1, change2, p));
- var change23 = Changeset.checkRep(Changeset.compose(change2, change3, p));
- var change123 = Changeset.checkRep(Changeset.compose(change12, change3, p));
- var change123a = Changeset.checkRep(Changeset.compose(change1, change23, p));
- assertEqualStrings(change123, change123a);
-
- assertEqualStrings(text2, Changeset.applyToText(change12, startText));
- assertEqualStrings(text3, Changeset.applyToText(change23, text1));
- assertEqualStrings(text3, Changeset.applyToText(change123, startText));
- }
-
- for(var i=0;i<30;i++) testCompose(i);
-
- (function simpleComposeAttributesTest() {
- print("> simpleComposeAttributesTest");
- var p = new AttribPool();
- p.putAttrib(['bold','']);
- p.putAttrib(['bold','true']);
- var cs1 = Changeset.checkRep("Z:2>1*1+1*1=1$x");
- var cs2 = Changeset.checkRep("Z:3>0*0|1=3$");
- var cs12 = Changeset.checkRep(Changeset.compose(cs1, cs2, p));
- assertEqualStrings("Z:2>1+1*0|1=2$x", cs12);
- })();
-
- (function followAttributesTest() {
- var p = new AttribPool();
- p.putAttrib(['x','']);
- p.putAttrib(['x','abc']);
- p.putAttrib(['x','def']);
- p.putAttrib(['y','']);
- p.putAttrib(['y','abc']);
- p.putAttrib(['y','def']);
-
- function testFollow(a, b, afb, bfa, merge) {
- assertEqualStrings(afb, Changeset.followAttributes(a, b, p));
- assertEqualStrings(bfa, Changeset.followAttributes(b, a, p));
- assertEqualStrings(merge, Changeset.composeAttributes(a, afb, true, p));
- assertEqualStrings(merge, Changeset.composeAttributes(b, bfa, true, p));
- }
-
- testFollow('', '', '', '', '');
- testFollow('*0', '', '', '*0', '*0');
- testFollow('*0', '*0', '', '', '*0');
- testFollow('*0', '*1', '', '*0', '*0');
- testFollow('*1', '*2', '', '*1', '*1');
- testFollow('*0*1', '', '', '*0*1', '*0*1');
- testFollow('*0*4', '*2*3', '*3', '*0', '*0*3');
- testFollow('*0*4', '*2', '', '*0*4', '*0*4');
- })();
-
- function testFollow(randomSeed) {
- var rand = new java.util.Random(randomSeed + 1000);
- print("> testFollow#"+randomSeed);
-
- var p = new AttribPool();
-
- var startText = randomMultiline(10, 20, rand)+'\n';
-
- var cs1 = randomTestChangeset(startText, rand)[0];
- var cs2 = randomTestChangeset(startText, rand)[0];
-
- var afb = Changeset.checkRep(Changeset.follow(cs1, cs2, false, p));
- var bfa = Changeset.checkRep(Changeset.follow(cs2, cs1, true, p));
-
- var merge1 = Changeset.checkRep(Changeset.compose(cs1, afb));
- var merge2 = Changeset.checkRep(Changeset.compose(cs2, bfa));
-
- assertEqualStrings(merge1, merge2);
- }
-
- for(var i=0;i<30;i++) testFollow(i);
-
- function testSplitJoinAttributionLines(randomSeed) {
- var rand = new java.util.Random(randomSeed + 2000);
- print("> testSplitJoinAttributionLines#"+randomSeed);
-
- var doc = randomMultiline(10, 20, rand)+'\n';
-
- function stringToOps(str) {
- var assem = Changeset.mergingOpAssembler();
- var o = Changeset.newOp('+');
- o.chars = 1;
- for(var i=0;i<str.length;i++) {
- var c = str.charAt(i);
- o.lines = (c == '\n' ? 1 : 0);
- o.attribs = (c == 'a' || c == 'b' ? '*'+c : '');
- assem.append(o);
- }
- return assem.toString();
- }
-
- var theJoined = stringToOps(doc);
- var theSplit = doc.match(/[^\n]*\n/g).map(stringToOps);
-
- assertEqualArrays(theSplit, Changeset.splitAttributionLines(theJoined, doc));
- assertEqualStrings(theJoined, Changeset.joinAttributionLines(theSplit));
- }
-
- for(var i=0;i<10;i++) testSplitJoinAttributionLines(i);
-
- (function testMoveOpsToNewPool() {
- print("> testMoveOpsToNewPool");
-
- var pool1 = new AttribPool();
- var pool2 = new AttribPool();
-
- pool1.putAttrib(['baz','qux']);
- pool1.putAttrib(['foo','bar']);
-
- pool2.putAttrib(['foo','bar']);
-
- assertEqualStrings(Changeset.moveOpsToNewPool('Z:1>2*1+1*0+1$ab', pool1, pool2), 'Z:1>2*0+1*1+1$ab');
- assertEqualStrings(Changeset.moveOpsToNewPool('*1+1*0+1', pool1, pool2), '*0+1*1+1');
- })();
-
-
- (function testMakeSplice() {
- print("> testMakeSplice");
-
- var t = "a\nb\nc\n";
- var t2 = Changeset.applyToText(Changeset.makeSplice(t, 5, 0, "def"), t);
- assertEqualStrings("a\nb\ncdef\n", t2);
-
- })();
-
- (function testToSplices() {
- print("> testToSplices");
-
- var cs = Changeset.checkRep('Z:z>9*0=1=4-3+9=1|1-4-4+1*0+a$123456789abcdefghijk');
- var correctSplices = [[5, 8, "123456789"], [9, 17, "abcdefghijk"]];
- assertEqualArrays(correctSplices, Changeset.toSplices(cs));
- })();
-
- function testCharacterRangeFollow(testId, cs, oldRange, insertionsAfter, correctNewRange) {
- print("> testCharacterRangeFollow#"+testId);
-
- var cs = Changeset.checkRep(cs);
- assertEqualArrays(correctNewRange, Changeset.characterRangeFollow(cs, oldRange[0], oldRange[1],
- insertionsAfter));
-
- }
-
- testCharacterRangeFollow(1, 'Z:z>9*0=1=4-3+9=1|1-4-4+1*0+a$123456789abcdefghijk',
- [7, 10], false, [14, 15]);
- testCharacterRangeFollow(2, "Z:bc<6|x=b4|2-6$", [400, 407], false, [400, 401]);
- testCharacterRangeFollow(3, "Z:4>0-3+3$abc", [0,3], false, [3,3]);
- testCharacterRangeFollow(4, "Z:4>0-3+3$abc", [0,3], true, [0,0]);
- testCharacterRangeFollow(5, "Z:5>1+1=1-3+3$abcd", [1,4], false, [5,5]);
- testCharacterRangeFollow(6, "Z:5>1+1=1-3+3$abcd", [1,4], true, [2,2]);
- testCharacterRangeFollow(7, "Z:5>1+1=1-3+3$abcd", [0,6], false, [1,7]);
- testCharacterRangeFollow(8, "Z:5>1+1=1-3+3$abcd", [0,3], false, [1,2]);
- testCharacterRangeFollow(9, "Z:5>1+1=1-3+3$abcd", [2,5], false, [5,6]);
- testCharacterRangeFollow(10, "Z:2>1+1$a", [0,0], false, [1,1]);
- testCharacterRangeFollow(11, "Z:2>1+1$a", [0,0], true, [0,0]);
-
- (function testOpAttributeValue() {
- print("> testOpAttributeValue");
-
- var p = new AttribPool();
- p.putAttrib(['name','david']);
- p.putAttrib(['color','green']);
-
- assertEqualStrings("david", Changeset.opAttributeValue(Changeset.stringOp('*0*1+1'), 'name', p));
- assertEqualStrings("david", Changeset.opAttributeValue(Changeset.stringOp('*0+1'), 'name', p));
- assertEqualStrings("", Changeset.opAttributeValue(Changeset.stringOp('*1+1'), 'name', p));
- assertEqualStrings("", Changeset.opAttributeValue(Changeset.stringOp('+1'), 'name', p));
- assertEqualStrings("green", Changeset.opAttributeValue(Changeset.stringOp('*0*1+1'), 'color', p));
- assertEqualStrings("green", Changeset.opAttributeValue(Changeset.stringOp('*1+1'), 'color', p));
- assertEqualStrings("", Changeset.opAttributeValue(Changeset.stringOp('*0+1'), 'color', p));
- assertEqualStrings("", Changeset.opAttributeValue(Changeset.stringOp('+1'), 'color', p));
- })();
-
- function testAppendATextToAssembler(testId, atext, correctOps) {
- print("> testAppendATextToAssembler#"+testId);
-
- var assem = Changeset.smartOpAssembler();
- Changeset.appendATextToAssembler(atext, assem);
- assertEqualStrings(correctOps, assem.toString());
- }
-
- testAppendATextToAssembler(1, {text:"\n", attribs:"|1+1"}, "");
- testAppendATextToAssembler(2, {text:"\n\n", attribs:"|2+2"}, "|1+1");
- testAppendATextToAssembler(3, {text:"\n\n", attribs:"*x|2+2"}, "*x|1+1");
- testAppendATextToAssembler(4, {text:"\n\n", attribs:"*x|1+1|1+1"}, "*x|1+1");
- testAppendATextToAssembler(5, {text:"foo\n", attribs:"|1+4"}, "+3");
- testAppendATextToAssembler(6, {text:"\nfoo\n", attribs:"|2+5"}, "|1+1+3");
- testAppendATextToAssembler(7, {text:"\nfoo\n", attribs:"*x|2+5"}, "*x|1+1*x+3");
- testAppendATextToAssembler(8, {text:"\n\n\nfoo\n", attribs:"|2+2*x|2+5"}, "|2+2*x|1+1*x+3");
-
- function testMakeAttribsString(testId, pool, opcode, attribs, correctString) {
- print("> testMakeAttribsString#"+testId);
-
- var p = poolOrArray(pool);
- var str = Changeset.makeAttribsString(opcode, attribs, p);
- assertEqualStrings(correctString, str);
- }
-
- testMakeAttribsString(1, ['bold,'], '+', [['bold','']], '');
- testMakeAttribsString(2, ['abc,def','bold,'], '=', [['bold','']], '*1');
- testMakeAttribsString(3, ['abc,def','bold,true'], '+', [['abc','def'],['bold','true']], '*0*1');
- testMakeAttribsString(4, ['abc,def','bold,true'], '+', [['bold','true'],['abc','def']], '*0*1');
-
- function testSubattribution(testId, astr, start, end, correctOutput) {
- print("> testSubattribution#"+testId);
-
- var str = Changeset.subattribution(astr, start, end);
- assertEqualStrings(correctOutput, str);
- }
-
- testSubattribution(1, "+1", 0, 0, "");
- testSubattribution(2, "+1", 0, 1, "+1");
- testSubattribution(3, "+1", 0, undefined, "+1");
- testSubattribution(4, "|1+1", 0, 0, "");
- testSubattribution(5, "|1+1", 0, 1, "|1+1");
- testSubattribution(6, "|1+1", 0, undefined, "|1+1");
- testSubattribution(7, "*0+1", 0, 0, "");
- testSubattribution(8, "*0+1", 0, 1, "*0+1");
- testSubattribution(9, "*0+1", 0, undefined, "*0+1");
- testSubattribution(10, "*0|1+1", 0, 0, "");
- testSubattribution(11, "*0|1+1", 0, 1, "*0|1+1");
- testSubattribution(12, "*0|1+1", 0, undefined, "*0|1+1");
- testSubattribution(13, "*0+2+1*1+3", 0, 1, "*0+1");
- testSubattribution(14, "*0+2+1*1+3", 0, 2, "*0+2");
- testSubattribution(15, "*0+2+1*1+3", 0, 3, "*0+2+1");
- testSubattribution(16, "*0+2+1*1+3", 0, 4, "*0+2+1*1+1");
- testSubattribution(17, "*0+2+1*1+3", 0, 5, "*0+2+1*1+2");
- testSubattribution(18, "*0+2+1*1+3", 0, 6, "*0+2+1*1+3");
- testSubattribution(19, "*0+2+1*1+3", 0, 7, "*0+2+1*1+3");
- testSubattribution(20, "*0+2+1*1+3", 0, undefined, "*0+2+1*1+3");
- testSubattribution(21, "*0+2+1*1+3", 1, undefined, "*0+1+1*1+3");
- testSubattribution(22, "*0+2+1*1+3", 2, undefined, "+1*1+3");
- testSubattribution(23, "*0+2+1*1+3", 3, undefined, "*1+3");
- testSubattribution(24, "*0+2+1*1+3", 4, undefined, "*1+2");
- testSubattribution(25, "*0+2+1*1+3", 5, undefined, "*1+1");
- testSubattribution(26, "*0+2+1*1+3", 6, undefined, "");
- testSubattribution(27, "*0+2+1*1|1+3", 0, 1, "*0+1");
- testSubattribution(28, "*0+2+1*1|1+3", 0, 2, "*0+2");
- testSubattribution(29, "*0+2+1*1|1+3", 0, 3, "*0+2+1");
- testSubattribution(30, "*0+2+1*1|1+3", 0, 4, "*0+2+1*1+1");
- testSubattribution(31, "*0+2+1*1|1+3", 0, 5, "*0+2+1*1+2");
- testSubattribution(32, "*0+2+1*1|1+3", 0, 6, "*0+2+1*1|1+3");
- testSubattribution(33, "*0+2+1*1|1+3", 0, 7, "*0+2+1*1|1+3");
- testSubattribution(34, "*0+2+1*1|1+3", 0, undefined, "*0+2+1*1|1+3");
- testSubattribution(35, "*0+2+1*1|1+3", 1, undefined, "*0+1+1*1|1+3");
- testSubattribution(36, "*0+2+1*1|1+3", 2, undefined, "+1*1|1+3");
- testSubattribution(37, "*0+2+1*1|1+3", 3, undefined, "*1|1+3");
- testSubattribution(38, "*0+2+1*1|1+3", 4, undefined, "*1|1+2");
- testSubattribution(39, "*0+2+1*1|1+3", 5, undefined, "*1|1+1");
- testSubattribution(40, "*0+2+1*1|1+3", 1, 5, "*0+1+1*1+2");
- testSubattribution(41, "*0+2+1*1|1+3", 2, 6, "+1*1|1+3");
- testSubattribution(42, "*0+2+1*1+3", 2, 6, "+1*1+3");
-
- function testFilterAttribNumbers(testId, cs, filter, correctOutput) {
- print("> testFilterAttribNumbers#"+testId);
-
- var str = Changeset.filterAttribNumbers(cs, filter);
- assertEqualStrings(correctOutput, str);
- }
-
- testFilterAttribNumbers(1, "*0*1+1+2+3*1+4*2+5*0*2*1*b*c+6",
- function(n) { return (n%2) == 0; },
- "*0+1+2+3+4*2+5*0*2*c+6");
- testFilterAttribNumbers(2, "*0*1+1+2+3*1+4*2+5*0*2*1*b*c+6",
- function(n) { return (n%2) == 1; },
- "*1+1+2+3*1+4+5*1*b+6");
-
- function testInverse(testId, cs, lines, alines, pool, correctOutput) {
- print("> testInverse#"+testId);
-
- pool = poolOrArray(pool);
- var str = Changeset.inverse(Changeset.checkRep(cs), lines, alines, pool);
- assertEqualStrings(correctOutput, str);
- }
-
- // take "FFFFTTTTT" and apply "-FT--FFTT", the inverse of which is "--F--TT--"
- testInverse(1, "Z:9>0=1*0=1*1=1=2*0=2*1|1=2$", null, ["+4*1+5"], ['bold,','bold,true'],
- "Z:9>0=2*0=1=2*1=2$");
-
- function testMutateTextLines(testId, cs, lines, correctLines) {
- print("> testMutateTextLines#"+testId);
-
- var a = lines.slice();
- Changeset.mutateTextLines(cs, a);
- assertEqualArrays(correctLines, a);
- }
-
- testMutateTextLines(1, "Z:4<1|1-2-1|1+1+1$\nc", ["a\n", "b\n"], ["\n", "c\n"]);
- testMutateTextLines(2, "Z:4>0|1-2-1|2+3$\nc\n", ["a\n", "b\n"], ["\n", "c\n", "\n"]);
-
- function testInverseRandom(randomSeed) {
- var rand = new java.util.Random(randomSeed + 3000);
- print("> testInverseRandom#"+randomSeed);
-
- var p = poolOrArray(['apple,','apple,true','banana,','banana,true']);
-
- var startText = randomMultiline(10, 20, rand)+'\n';
- var alines = Changeset.splitAttributionLines(Changeset.makeAttribution(startText), startText);
- var lines = startText.slice(0,-1).split('\n').map(function(s) { return s+'\n'; });
-
- var stylifier = randomTestChangeset(startText, rand, true)[0];
-
- //print(alines.join('\n'));
- Changeset.mutateAttributionLines(stylifier, alines, p);
- //print(stylifier);
- //print(alines.join('\n'));
- Changeset.mutateTextLines(stylifier, lines);
-
- var changeset = randomTestChangeset(lines.join(''), rand, true)[0];
- var inverseChangeset = Changeset.inverse(changeset, lines, alines, p);
-
- var origLines = lines.slice();
- var origALines = alines.slice();
-
- Changeset.mutateTextLines(changeset, lines);
- Changeset.mutateAttributionLines(changeset, alines, p);
- //print(origALines.join('\n'));
- //print(changeset);
- //print(inverseChangeset);
- //print(origLines.map(function(s) { return '1: '+s.slice(0,-1); }).join('\n'));
- //print(lines.map(function(s) { return '2: '+s.slice(0,-1); }).join('\n'));
- //print(alines.join('\n'));
- Changeset.mutateTextLines(inverseChangeset, lines);
- Changeset.mutateAttributionLines(inverseChangeset, alines, p);
- //print(lines.map(function(s) { return '3: '+s.slice(0,-1); }).join('\n'));
-
- assertEqualArrays(origLines, lines);
- assertEqualArrays(origALines, alines);
- }
-
- for(var i=0;i<30;i++) testInverseRandom(i);
-} \ No newline at end of file
diff --git a/trunk/etherpad/src/etherpad/control/admincontrol.js b/trunk/etherpad/src/etherpad/control/admincontrol.js
deleted file mode 100644
index 02f6428..0000000
--- a/trunk/etherpad/src/etherpad/control/admincontrol.js
+++ /dev/null
@@ -1,1471 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("fastJSON");
-import("netutils");
-import("funhtml.*");
-import("stringutils.{html,sprintf,startsWith,md5}");
-import("jsutils.*");
-import("sqlbase.sqlbase");
-import("sqlbase.sqlcommon");
-import("sqlbase.sqlobj");
-import("varz");
-import("comet");
-import("dispatch.{Dispatcher,PrefixMatcher,DirMatcher,forward}");
-
-import("etherpad.billing.team_billing");
-import("etherpad.globals.*");
-import("etherpad.utils.*");
-import("etherpad.licensing");
-import("etherpad.sessions.getSession");
-import("etherpad.sessions");
-import("etherpad.statistics.statistics");
-import("etherpad.log");
-import("etherpad.admin.shell");
-import("etherpad.usage_stats.usage_stats");
-import("etherpad.control.blogcontrol");
-import("etherpad.control.pro_beta_control");
-import("etherpad.control.statscontrol");
-import("etherpad.statistics.exceptions");
-import("etherpad.store.checkout");
-
-import("etherpad.pad.activepads");
-import("etherpad.pad.model");
-import("etherpad.pad.padutils");
-import("etherpad.pad.dbwriter");
-import("etherpad.collab.collab_server");
-
-import("etherpad.pro.pro_accounts");
-import("etherpad.pro.pro_utils");
-import("etherpad.pro.domains");
-
-jimport("java.lang.System.out.println");
-
-jimport("net.appjet.oui.cometlatencies");
-jimport("net.appjet.oui.appstats");
-
-
-//----------------------------------------------------------------
-
-function _isAuthorizedAdmin() {
- if (!isProduction()) {
- return true;
- }
- return (getSession().adminAuth === true);
-}
-
-var _mainLinks = [
- ['exceptions', 'Exceptions Monitor'],
- ['usagestats/', 'Usage Stats'],
- ['padinspector', 'Pad Inspector'],
- ['dashboard', 'Dashboard'],
- ['eepnet-licenses', 'EEPNET Licenses'],
- ['config', 'appjet.config'],
- ['shell', 'Shell'],
- ['timings', 'timing data'],
- ['broadcast-message', 'Pad Broadcast'],
-// ['analytics', 'Google Analytics'],
- ['varz', 'varz'],
- ['genlicense', 'Manually generate a license key'],
- ['flows', 'Flows (warning: slow)'],
- ['diagnostics', 'Pad Connection Diagnostics'],
- ['cachebrowser', 'Cache Browser'],
- ['pne-tracker', 'PNE Tracking Stats'],
- ['reload-blog-db', 'Reload blog DB'],
- ['pro-domain-accounts', 'Pro Domain Accounts'],
- ['beta-valve', 'Beta Valve'],
- ['reset-subscription', "Reset Subscription"]
-];
-
-function onRequest(name) {
- if (name == "auth") {
- return;
- }
- if (!_isAuthorizedAdmin()) {
- getSession().cont = request.path;
- response.redirect('/ep/admin/auth');
- }
-
- var disp = new Dispatcher();
- disp.addLocations([
- [PrefixMatcher('/ep/admin/usagestats/'), forward(statscontrol)]
- ]);
-
- return disp.dispatch();
-}
-
-function _commonHead() {
- return HEAD(STYLE(
- "html {font-family:Verdana,Helvetica,sans-serif;}",
- "body {padding: 2em;}"
- ));
-}
-
-//----------------------------------------------------------------
-
-function render_auth() {
- var cont = getSession().cont;
- if (getSession().message) {
- response.write(DIV(P(B(getSession().message))));
- delete getSession().message;
- }
- if (request.method == "GET") {
- response.write(FORM({method: "POST", action: request.path},
- P("Are you an admin?"),
- LABEL("Password:"),
- INPUT({type: "password", name: "password", value: ""}),
- INPUT({type: "submit", value: "submit"})
- ));
- }
- if (request.method == "POST") {
- var pass = request.params.password;
- if (pass === appjet.config['etherpad.adminPass']) {
- getSession().adminAuth = true;
- if (cont) {
- response.redirect(cont);
- } else {
- response.redirect("/ep/admin/main");
- }
- } else {
- getSession().message = "Bad Password.";
- response.redirect(request.path);
- }
- }
-}
-
-function render_main() {
- var div = DIV();
-
- div.push(A({href: "/"}, html("&laquo;"), " home"));
- div.push(H1("Admin"));
-
- _mainLinks.forEach(function(l) {
- div.push(DIV(A({href: l[0]}, l[1])));
- });
- if (sessions.isAnEtherpadAdmin()) {
- div.push(P(A({href: "/ep/admin/setadminmode?v=false"},
- "Exit Admin Mode")));
- }
- else {
- div.push(P(A({href: "/ep/admin/setadminmode?v=true"},
- "Enter Admin Mode")));
- }
- response.write(HTML(_commonHead(), BODY(div)));
-}
-
-//----------------------------------------------------------------
-
-function render_config() {
-
- vars = [];
- eachProperty(appjet.config, function(k,v) {
- vars.push(k);
- });
-
- vars.sort();
-
- response.setContentType('text/plain; charset=utf-8');
- vars.forEach(function(v) {
- response.write("appjet.config."+v+" = "+appjet.config[v]+"\n");
- });
-}
-
-//----------------------------------------------------------------
-
-function render_test() {
- response.setContentType("text/plain");
- response.write(Packages.net.appjet.common.util.ExpiringMapping + "\n");
- var m = new Packages.net.appjet.common.util.ExpiringMapping(10 * 1000);
- response.write(m.toString() + "\n");
- m.get("test");
- return;
- response.write(m.toString());
-}
-
-function render_dashboard() {
- var body = BODY();
- body.push(A({href: '/ep/admin/'}, html("&laquo; Admin")));
- body.push(H1({style: "border-bottom: 1px solid black;"}, "Dashboard"));
-
- /*
- body.push(H2({style: "color: #226; font-size: 1em;"}, "License"));
- var license = licensing.getLicense();
- body.push(P(TT(" Licensed To (name): "+license.personName)));
- body.push(P(TT(" Licensed To (organization): "+license.organizationName)));
- body.push(P(TT(" Software Edition: "+license.editionName)));
- var quota = ((license.userQuota > 0) ? license.userQuota : 'unlimited');
- body.push(P(TT(" User Quota: "+quota)));
- var expires = (license.expiresDate ? (license.expiresDate.toString()) : 'never');
- body.push(P(TT(" Expires: "+expires)));
- */
-
- /*
- body.push(H2({style: "color: #226; font-size: 1em;"}, "Active User Quota"));
-
- var activeUserCount = licensing.getActiveUserCount();
- var activeUserQuota = licensing.getActiveUserQuota();
- var activeUserWindowStart = licensing.getActiveUserWindowStart();
-
- body.push(P(TT(" Since ", B(activeUserWindowStart.toString()), ", ",
- "you have used ", B(activeUserCount), " of ", B(activeUserQuota),
- " active users.")));
-*/
- body.push(H2({style: "color: #226; font-size: 1em;"}, "Uptime"));
- body.push(P({style: "margin-left: 25px;"}, "Server running for "+renderServerUptime()+"."))
-
- body.push(H2({style: "color: #226; font-size: 1em;"}, "Response codes"));
- body.push(renderResponseCodes());
-
- body.push(H2({style: "color: #226; font-size: 1em;"}, "Comet Connections"));
- body.push(renderPadConnections());
-
- body.push(H2({style: "color: #226; font-size: 1em;"}, "Comet Stats"));
- body.push(renderCometStats());
-
- body.push(H2({style: "color: #226; font-size: 1em;"}, "Recurring revenue, monthly"));
- body.push(renderRevenueStats());
-
- response.write(HTML(_commonHead(), body));
-}
-
-// Note: This function is called by the PNE dashboard (pro_admin_control.js)! Be careful.
-function renderPadConnections() {
- var d = DIV();
- var lastCount = cometlatencies.lastCount();
-
- if (lastCount.isDefined()) {
- var countMap = {};
- Array.prototype.map.call(lastCount.get().elements().collect().toArray().unbox(
- java.lang.Class.forName("java.lang.Object")),
- function(x) {
- countMap[x._1()] = x._2();
- });
- var totalConnected = 0;
- var ul = UL();
- eachProperty(countMap, function(k,v) {
- ul.push(LI(k+": "+v));
- if (/^\d+$/.test(v)) {
- totalConnected += Number(v);
- }
- });
- ul.push(LI(B("Total: ", totalConnected)));
- d.push(ul);
- } else {
- d.push("Still collecting data... check back in a minute.");
- }
- return d;
-}
-
-// Note: This function is called by the PNE dashboard (pro_admin_control.js)! Be careful.
-function renderCometStats() {
- var d = DIV();
- var lastStats = cometlatencies.lastStats();
- var lastCount = cometlatencies.lastCount();
-
-
- if (lastStats.isDefined()) {
- d.push(P("Realtime transport latency percentiles (microseconds):"));
- var ul = UL();
- lastStats.map(scalaF1(function(s) {
- ['50', '90', '95', '99', 'max'].forEach(function(id) {
- var fn = id;
- if (id != "max") {
- fn = ("p"+fn);
- id = id+"%";
- }
- ul.push(LI(id, ": <", s[fn](), html("&micro;"), "s"));
- });
- }));
- d.push(ul);
- } else {
- d.push(P("Still collecting data... check back in a minutes."));
- }
-
- /* ["p50", "p90", "p95", "p99", "max"].forEach(function(id) {
- ul.push(LI(B(
-
- return DIV(P(sprintf("50%% %d\t90%% %d\t95%% %d\t99%% %d\tmax %d",
- s.p50(), s.p90(), s.p95(), s.p99(), s.max())),
- P(sprintf("%d total messages", s.count())));
- }})).get();*/
-
-
- return d;
-}
-
-// Note: This function is called by the PNE dashboard (pro_admin_control.js)! Be careful.
-function renderResponseCodes() {
- var statusCodeFrequencyNames = ["minute", "hour", "day", "week"];
- var data = { };
- var statusCodes = appstats.stati();
- for (var i = 0; i < statusCodes.length; ++i) {
- var name = statusCodeFrequencyNames[i];
- var map = statusCodes[i];
- map.foreach(scalaF1(function(pair) {
- if (! (pair._1() in data)) data[pair._1()] = {};
- var scmap = data[pair._1()];
- scmap[name] = pair._2().count();
- }));
- };
- var stats = TABLE({id: "responsecodes-table", style: "margin-left: 25px;",
- border: 1, cellspacing: 0, cellpadding: 4},
- TR.apply(TR, statusCodeFrequencyNames.map(function(name) {
- return TH({colspan: 2}, "Last", html("&nbsp;"), name);
- })));
- var sortedStati = [];
- eachProperty(data, function(k) {
- sortedStati.push(k);
- });
- sortedStati.sort();
- sortedStati.forEach(function(k, i) { // k is status code.
- var row = TR();
- statusCodeFrequencyNames.forEach(function(name) {
- row.push(TD({style: 'width: 2em;'}, data[k][name] ? k+":" : ""));
- row.push(TD(data[k][name] ? data[k][name] : ""));
- });
- stats.push(row);
- });
- return stats;
-}
-
-// Note: This function is called by the PNE dashboard (pro_admin_control.js)! Be careful.
-function renderServerUptime() {
- var labels = ["seconds", "minutes", "hours", "days"];
- var ratios = [60, 60, 24];
- var time = appjet.uptime / 1000;
- var pos = 0;
- while (pos < ratios.length && time / ratios[pos] > 1.1) {
- time = time / ratios[pos];
- pos++;
- }
- return sprintf("%.1f %s", time, labels[pos]);
-}
-
-function renderRevenueStats() {
- var subs = team_billing.getAllSubscriptions();
- var total = 0;
- var totalUsers = 0;
- subs.forEach(function(sub) {
- var users = team_billing.getMaxUsers(sub.customer);
- var cost = team_billing.calculateSubscriptionCost(users, sub.coupon);
- if (cost > 0) {
- totalUsers += users;
- total += cost;
- }
- });
- return "US $"+checkout.dollars(total)+", from "+subs.length+" domains and "+totalUsers+" users.";
-}
-
-//----------------------------------------------------------------
-// Broadcasting Messages
-//----------------------------------------------------------------
-
-function render_broadcast_message_get() {
- var body = BODY(FORM({action: request.path, method: 'post'},
- H3('Broadcast Message to All Active Pad Clients:'),
- TEXTAREA({name: 'msgtext', style: 'width: 100%; height: 100px;'}),
- H3('JavaScript code to be eval()ed on client (optional, be careful!): '),
- TEXTAREA({name: 'jscode', style: 'width: 100%; height: 100px;'}),
- INPUT({type: 'submit', value: 'Broadcast Now'})));
- response.write(HTML(body));
-}
-
-function render_broadcast_message_post() {
- var msgText = request.params.msgtext;
- var jsCode = request.params.jscode;
- if (!(msgText || jsCode)) {
- response.write("No mesage text or jscode specified.");
- response.stop();
- return;
- }
- collab_server.broadcastServerMessage({
- type: 'NOTICE',
- text: msgText,
- js: jsCode
- });
- response.write(HTML(BODY(P("OK"), P(A({href: request.path}, "back")))));
-}
-
-function render_shell() {
- shell.handleRequest();
-}
-
-//----------------------------------------------------------------
-// pad inspector
-//----------------------------------------------------------------
-
-function _getPadUrl(globalPadId) {
- var superdomain = pro_utils.getRequestSuperdomain();
- var domain;
- if (padutils.isProPadId(globalPadId)) {
- var domainId = padutils.getDomainId(globalPadId);
- domain = domains.getDomainRecord(domainId).subDomain +
- '.' + superdomain;
- }
- else {
- domain = superdomain;
- }
- var localId = padutils.globalToLocalId(globalPadId);
- return "http://"+httpHost(domain)+"/"+localId;
-}
-
-function render_padinspector_get() {
- var padId = request.params.padId;
- if (!padId) {
- response.write(FORM({action: request.path, method: 'get', style: 'border: 1px solid #ccc; background-color: #eee; padding: .2em 1em;'},
- P("Pad Lookup: ",
- INPUT({name: 'padId', value: '<enter pad id>'}),
- INPUT({type: 'submit'}))));
-
- // show recently active pads; the number of them may vary; lots of
- // activity in a pad will push others off the list
- response.write(H3("Recently Active Pads:"));
- var recentlyActiveTable = TABLE({cellspacing: 0, cellpadding: 6, border: 1,
- style: 'font-family: monospace;'});
- var recentPads = activepads.getActivePads();
- recentPads.forEach(function (info) {
- var time = info.timestamp; // number
- var pid = info.padId;
- model.accessPadGlobal(pid, function(pad) {
- if (pad.exists()) {
- var numRevisions = pad.getHeadRevisionNumber();
- var connected = collab_server.getNumConnections(pad);
- recentlyActiveTable.push(
- TR(TD(B(pid)),
- TD({style: 'font-style: italic;'}, timeAgo(time)),
- TD(connected+" connected"),
- TD(numRevisions+" revisions"),
- TD(A({href: qpath({padId: pid, revtext: "HEAD"})}, "HEAD")),
- TD(A({href: qpath({padId: pid})}, "inspect")),
- TD(A({href: qpath({padId: pid, snoop: 1})}, "snoop"))
- ));
- }
- }, "r");
- });
- response.write(recentlyActiveTable);
- response.stop();
- }
- if (startsWith(padId, '/')) {
- padId = padId.substr(1);
- }
- if (request.params.snoop) {
- sessions.setIsAnEtherpadAdmin(true);
- response.redirect(_getPadUrl(padId));
- }
- if (request.params.setsupportstimeslider) {
- var v = (String(request.params.setsupportstimeslider).toLowerCase() ==
- 'true');
- model.accessPadGlobal(padId, function(pad) {
- pad.setSupportsTimeSlider(v);
- });
- response.write("on pad "+padId+": setSupportsTimeSlider("+v+")");
- response.stop();
- }
- model.accessPadGlobal(padId, function(pad) {
- if (! pad.exists()) {
- response.write("Pad not found: /"+padId);
- }
- else {
- var headRev = pad.getHeadRevisionNumber();
- var div = DIV({style: 'font-family: monospace;'});
-
- if (request.params.revtext) {
- var i;
- if (request.params.revtext == "HEAD") {
- i = headRev;
- } else {
- i = Number(request.params.revtext);
- }
- var infoObj = {};
- div.push(H2(A({href: request.path}, "PadInspector"),
- ' > ', A({href: request.path+'?padId='+padId}, "/"+padId),
- ' > ', "Revision ", i, "/", headRev,
- SPAN({style: 'color: #949;'}, ' [ ', pad.getRevisionDate(i).toString(), ' ] ')));
- div.push(H3("Browse Revisions: ",
- ((i > 0) ? A({id: 'previous', href: qpath({revtext: (i-1)})}, '<< previous') : ''),
- ' ',
- ((i < pad.getHeadRevisionNumber()) ? A({id: 'next', href: qpath({revtext:(i+1)})}, 'next >>') : '')),
- DIV({style: 'padding: 1em; border: 1px solid #ccc;'},
- pad.getRevisionText(i, infoObj)));
- if (infoObj.badLastChar) {
- div.push(P("Bad last character of text (not newline): "+infoObj.badLastChar));
- }
- } else if (request.params.dumpstorage) {
- div.push(P(collab_server.dumpStorageToString(pad)));
- } else if (request.params.showlatest) {
- div.push(P(pad.text()));
- } else {
- div.push(H2(A({href: request.path}, "PadInspector"), ' > ', "/"+padId));
- // no action
- div.push(P(A({href: qpath({revtext: 'HEAD'})}, 'HEAD='+headRev)));
- div.push(P(A({href: qpath({dumpstorage: 1})}, 'dumpstorage')));
- var supportsTimeSlider = pad.getSupportsTimeSlider();
- if (supportsTimeSlider) {
- div.push(P(A({href: qpath({setsupportstimeslider: 'false'})}, 'hide slider')));
- }
- else {
- div.push(P(A({href: qpath({setsupportstimeslider: 'true'})}, 'show slider')));
- }
- }
- }
-
- var script = SCRIPT({type: 'text/javascript'}, html([
- '$(document).keydown(function(e) {',
- ' var h = undefined;',
- ' if (e.keyCode == 37) { h = $("#previous").attr("href"); }',
- ' if (e.keyCode == 39) { h = $("#next").attr("href"); }',
- ' if (h) { window.location.href = h; }',
- '});'
- ].join('\n')));
-
- response.write(HTML(
- HEAD(SCRIPT({type: 'text/javascript', src: '/static/js/jquery-1.3.2.js?'+(+(new Date))})),
- BODY(div, script)));
- }, "r");
-}
-
-function render_analytics() {
- response.redirect("https://www.google.com/analytics/reporting/?reset=1&id=12611622");
-}
-
-//----------------------------------------------------------------
-// eepnet license display
-//----------------------------------------------------------------
-
-function render_eepnet_licenses() {
- var data = sqlobj.selectMulti('eepnet_signups', {}, {orderBy: 'date'});
- var t = TABLE({border: 1, cellspacing: 0, cellpadding: 2});
- var cols = ['date','email','orgName','firstName','lastName', 'jobTitle','phone','estUsers'];
- data.forEach(function(x) {
- var tr = TR();
- cols.forEach(function(colname) {
- tr.push(TD(x[colname]));
- });
- t.push(tr);
- });
- response.write(HTML(BODY({style: 'font-family: monospace;'}, t)));
-}
-
-//----------------------------------------------------------------
-// pad integrity
-//----------------------------------------------------------------
-
-/*function render_changesettest_get() {
- var nums = [0, 1, 2, 3, 0xfffffff, 0x02345678, 4];
- var str = Changeset.numberArrayToString(nums);
- var result = Changeset.numberArrayFromString(str);
- var resultArray = result[0];
- var remainingString = result[1];
- var bad = false;
- if (remainingString) {
- response.write(P("remaining string length is: "+remainingString.length));
- bad = true;
- }
- if (nums.length != resultArray.length) {
- response.write(P("length mismatch: "+nums.length+" / "+resultArray.length));
- bad = true;
- }
- response.write(P(nums[2]));
- for(var i=0;i<nums.length;i++) {
- var a = nums[i];
- var b = resultArray[i];
- if (a !== b) {
- response.write(P("mismatch at element "+i+": "+a+" / "+b));
- bad = true;
- }
- }
- if (! bad) {
- response.write("SUCCESS");
- }
-}*/
-
-/////////
-
-function render_appendtest() {
- var padId = request.params.padId;
- var mode = request.params.mode;
- var text = request.params.text;
-
- model.accessPadGlobal(padId, function(pad) {
- if (mode == "append") {
- collab_server.appendPadText(pad, text);
- }
- else if (mode == "replace") {
- collab_server.setPadText(pad, text);
- }
- });
-}
-
-//function render_flushall() {
-// dbwriter.writeAllToDB(null, true);
-// response.write("OK");
-//}
-
-//function render_flushpad() {
-// var padId = request.params.padId;
-// model.accessPadGlobal(padId, function(pad) {
-// dbwriter.writePad(pad, true);
-// });
-// response.write("OK");
-//}
-
-/*function render_foo() {
- locking.doWithPadLock("CAT", function() {
- sqlbase.createJSONTable("STUFF");
- sqlbase.putJSON("STUFF", "dogs", {very:"bad"});
- response.write(sqlbase.getJSON("STUFF", "dogs")); // {very:"bad"}
- response.write(',');
- response.write(sqlbase.getJSON("STUFF", "cats")); // undefined
- response.write("<br/>");
-
- sqlbase.createStringArrayTable("SEQUENCES");
- sqlbase.putStringArrayElement("SEQUENCES", "fibo", 0, "1");
- sqlbase.putStringArrayElement("SEQUENCES", "fibo", 1, "1");
- sqlbase.putStringArrayElement("SEQUENCES", "fibo", 2, "2");
- sqlbase.putStringArrayElement("SEQUENCES", "fibo", 3, "3");
- sqlbase.putStringArrayElement("SEQUENCES", "fibo", 4, "5");
- sqlbase.putStringArrayElement("SEQUENCES", "fibo", 30, "number30");
- sqlbase.putStringArrayElement("SEQUENCES", "fibo", 29, "number29");
- sqlbase.deleteStringArrayElement("SEQUENCES", "fibo", 29);
- sqlbase.putConsecutiveStringArrayElements("SEQUENCES", "fibo", 19, [19,20,21,22]);
- var a = [];
- for(var i=0;i<31;i++) {
- a.push(sqlbase.getStringArrayElement("SEQUENCES", "fibo", i));
- }
- response.write(a.join(',')); // 1,1,2,3,5,,, ... 19,20,21,22, ... ,,,number30
- });
-}*/
-
-function render_timings() {
- var timer = Packages.net.appjet.ajstdlib.timer;
- var opnames = timer.getOpNames();
-
- response.write(P(A({href: '/ep/admin/timingsreset'}, "reset all")));
-
- var t = TABLE({border: 1, cellspacing: 0, cellpadding: 3, style: 'font-family: monospace;'});
- t.push(TR(TH("operation"),
- TH("sample_count"),
- TH("total_ms"),
- TH("avg_ms")));
-
- function r(x) {
- return sprintf("%09.2f", x);
- }
- var rows = [];
- for (var i = 0; i < opnames.length; i++) {
- var stats = timer.getStats(opnames[i]);
- rows.push([String(opnames[i]),
- Math.floor(stats[0]),
- stats[1],
- stats[2]]);
- }
-
- var si = Number(request.params.sb || 0);
-
- rows.sort(function(a,b) { return cmp(b[si],a[si]); });
-
- rows.forEach(function(row) {
- t.push(TR(TD(row[0]),
- TD(row[1]),
- TD(r(row[2])),
- TD(r(row[3]))));
- });
-
- response.write(t);
-}
-
-function render_timingsreset() {
- Packages.net.appjet.ajstdlib.timer.reset();
- response.redirect('/ep/admin/timings');
-}
-
-// function render_jsontest() {
-// response.setContentType('text/plain; charset=utf-8');
-
-// var a = [];
-// a[0] = 5;
-// a[1] = 6;
-// a[9] = 8;
-// a['foo'] = "should appear";
-
-// jtest(a);
-
-// var obj1 = {
-// a: 1,
-// b: 2,
-// q: [true,true,,,,,,false,false,,,,{},{a:{a:{a:{a:{a:{a:[[{a:{a:false}}]]}}}}}}],
-// c: "foo",
-// d: {
-// nested: { obj: 'yo' },
-// bar: "baz"
-// },
-// e: 3.6,
-// 1: "numeric value",
-// 2: "anohter numeric value",
-// 2.46: "decimal numeric value",
-// foo: 3.212312310,
-// bar: 0.234242e-10,
-// baz: null,
-// ar: [{}, '1', [], [[[[]]]]],
-// n1: null,
-// n2: undefined,
-// n3: false,
-// n4: "null",
-// n5: "undefined"
-// };
-
-// jtest(obj1);
-
-// var obj2 = {
-// t1: 1232738532270
-// };
-
-// jtest(obj2);
-
-// // a javascript object plus numeric ids
-// var obj3 = {};
-// obj3["foo"] = "bar";
-// obj3[1] = "aaron";
-// obj3[2] = "iba";
-
-// jtest(obj3);
-
-// function jtest(x) {
-// response.write('----------------------------------------------------------------\n\n');
-
-// var str1 = JSON.stringify(x);
-// var str2 = fastJSON.stringify(x);
-
-// var str1_ = JSON.stringify(JSON.parse(str1));
-// var str2_ = fastJSON.stringify(fastJSON.parse(str2));
-
-// response.write([str1,str2].join('\n') + '\n\n');
-// response.write([str1_,str2_].join('\n') + '\n\n');
-// }
-// }
-
-function render_varz() {
- var varzes = varz.getSnapshot();
- response.setContentType('text/plain; charset=utf-8');
- for (var k in varzes) {
- response.write(k+': '+varzes[k]+'\n');
- }
-}
-
-function render_extest() {
- throw new Error("foo");
-}
-
-
-function _diagnosticRecordToHtml(obj) {
- function valToHtml(o, noborder) {
- if (typeof (o) != 'object') {
- return String(o);
- }
- var t = TABLE((noborder ? {} : {style: "border-left: 1px solid black; border-top: 1px solid black;"}));
- if (typeof (o.length) != 'number') {
- eachProperty(o, function(k, v) {
- var tr = TR();
- tr.push(TD({valign: "top", align: "right"}, B(k)));
- tr.push(TD(valToHtml(v)));
- t.push(tr);
- });
- } else {
- if (o.length == 0) return "(empty array)";
- for (var i = 0; i < o.length; ++i) {
- var tr = TR();
- tr.push(TD({valign: "top", align: "right"}, B(i)));
- tr.push(TD(valToHtml(o[i])));
- t.push(tr);
- }
- }
- return t;
- }
- return valToHtml(obj, true);
-}
-
-function render_diagnostics() {
- var start = Number(request.params.start || 0);
- var count = Number(request.params.count || 100);
- var diagnostic_entries = sqlbase.getAllJSON("PAD_DIAGNOSTIC", start, count);
- var expandArray = request.params.expand || [];
-
- if (typeof (expandArray) == 'string') expandArray = [expandArray];
- var expand = {};
- for (var i = 0; i < expandArray.length; ++i) {
- expand[expandArray[i]] = true;
- }
-
- function makeLink(text, expand, collapse, start0, count0) {
- start0 = (typeof(start0) == "number" ? start0 : start);
- count0 = count0 || count;
- collapse = collapse || [];
- expand = expand || [];
-
- var collapseObj = {};
- for (var i = 0; i < collapse.length; ++i) {
- collapseObj[collapse[i]] = true;
- }
- var expandString =
- expandArray.concat(expand).filter(function(x) { return ! collapseObj[x] }).map(function(x) { return "expand="+encodeURIComponent(x) }).join("&");
-
- var url = request.path + "?start="+start0+"&count="+count0+"&"+expandString+(expand.length == 1 ? "#"+md5(expand[0]) : "");
-
- return A({href: url}, text);
- }
-
- var t = TABLE({border: 1, cellpadding: 2, style: "font-family: monospace;"});
- diagnostic_entries.forEach(function(ent) {
- var tr = TR()
- tr.push(TD({valign: "top", align: "right"}, (new Date(Number(ent.id.split("-")[0]))).toString()));
- tr.push(TD({valign: "top", align: "right"}, ent.id));
- if (expand[ent.id]) {
- tr.push(TD(A({name: md5(ent.id)}, makeLink("(collapse)", false, [ent.id])), BR(),
- _diagnosticRecordToHtml(ent.value)));
- } else {
- tr.push(TD(A({name: md5(ent.id)}, makeLink(_diagnosticRecordToHtml({padId: ent.value.padId, disconnectedMessage: ent.value.disconnectedMessage}), [ent.id]))));
- }
- t.push(tr);
- });
-
- var body = BODY();
- body.push(P("Showing entries ", start, "-", start+diagnostic_entries.length, ". ",
- (start > 0 ? makeLink("Show previous "+count+".", [], [], start-count) : ""),
- (diagnostic_entries.length == count ? makeLink("Show next "+count+".", [], [], start+count) : "")));
- body.push(t);
-
- response.write(HTML(body));
-}
-
-//----------------------------------------------------------------
-import("etherpad.billing.billing");
-
-function render_testbillingdirect() {
- var invoiceId = billing.createInvoice();
- var ret = billing.directPurchase(invoiceId, 0, 'EEPNET', 500, 'DISCOUNT', {
- cardType: "Visa",
- cardNumber: "4501251685453214",
- cardExpiration: "042019",
- cardCvv: "123",
- nameSalutation: "Dr.",
- nameFirst: "John",
- nameMiddle: "D",
- nameLast: "Zamfirescu",
- nameSuffix: "none",
- addressStreet: "531 Main St. Apt. 1227",
- addressStreet2: "",
- addressCity: "New York",
- addressState: "NY",
- addressCountry: "US",
- addressZip: "10044"
- }, "https://"+request.host+"/ep/about/testbillingnotify");
- if (ret.status == 'success') {
- response.write(P("Success! Invoice id: "+ret.purchaseInfo.invoiceId+" for "+ret.purchaseInfo.cost));
- } else {
- response.write(P("Failure: "+ret.toSource()))
- }
-}
-
-function render_testbillingrecurring() {
- var invoiceId = billing.createInvoice();
- var ret = billing.directPurchase(invoiceId, 0, 'EEPNET', 1, 'DISCOUNT', {
- cardType: "Visa",
- cardNumber: "4501251685453214",
- cardExpiration: "042019",
- cardCvv: "123",
- nameSalutation: "Dr.",
- nameFirst: "John",
- nameMiddle: "D",
- nameLast: "Zamfirescu",
- nameSuffix: "none",
- addressStreet: "531 Main St. Apt. 1227",
- addressStreet2: "",
- addressCity: "New York",
- addressState: "NY",
- addressCountry: "US",
- addressZip: "10044"
- }, "https://"+request.host+"/ep/about/testbillingnotify", true);
- if (ret.status == 'success') {
- var transactionId = billing.getTransaction(ret.purchaseInfo.transactionId).txnId;
- var purchaseId = ret.purchaseInfo.purchaseId;
- response.write(P("Direct billing successful. PayPal transaction id: ", transactionId));
-
- invoiceId = billing.createInvoice();
- ret = billing.asyncRecurringPurchase(
- invoiceId, purchaseId, transactionId, 500,
- "https://"+request.host+"/ep/about/testbillingnotify");
- if (ret.status == 'success') {
- response.write(P("Woot! Recurrent billing successful! ", ret.purchaseInfo.invoiceId, " for ", ret.purchaseInfo.cost));
- } else {
- response.write(P("Failure: "+ret.toSource()));
- }
- } else {
- response.write("Direct billing failure: "+ret.toSource());
- }
-}
-
-function render_testbillingexpress() {
- var urlPrefix = "http://"+request.host+request.path;
- var session = sessions.getSession();
- var notifyUrl = "http://"+request.host+"/ep/about/testbillingnotify";
-
- switch (request.params.step) {
- case '0':
- response.write(P("You'll be charged $400 for EEPNET. Click the link below to go to paypal."));
- response.write(A({href: urlPrefix+"?step=1"}, "Link"));
- break;
- case '1':
- var ret = billing.beginExpressPurchase(1, 'EEPNET', 400, 'DISCOUNT', urlPrefix+"?step=2", urlPrefix+"?step=0", notifyUrl);
- if (ret.status != 'success') {
- response.write("Error: "+ret.debug.toSource());
- response.stop();
- }
- session.purchaseInfo = ret.purchaseInfo;
- response.redirect(paypalPurchaseUrl(ret.purchaseInfo.token));
- break;
- case '2':
- var ret = billing.continueExpressPurchase(session.purchaseInfo);
- if (! ret.status == 'success') {
- response.write("Error: "+ret.debug.toSource());
- response.stop();
- }
- session.payerInfo = ret.payerInfo;
-
- response.write(P("You approved the transaction. Click 'confirm' to confirm."));
- response.write(A({href: urlPrefix+"?step=3"}, "Confirm"));
- break;
- case '3':
- var ret = billing.completeExpressPurchase(session.purchaseInfo, session.payerInfo, notifyUrl);
- if (ret.status == 'failure') {
- response.write("Error: "+ret.debug.toSource());
- response.stop();
- }
- if (ret.status == 'pending') {
- response.write("Your charge is pending. You will be notified by email when your payment clears. Your invoice number is "+session.purchaseInfo.invoiceId);
- response.stop();
- }
-
- response.write(P("Purchase completed: invoice # is "+session.purchaseInfo.invoiceId+" for "+session.purchaseInfo.cost));
- break;
- default:
- response.redirect(request.path+"?step=0");
- }
-}
-
-//----------------------------------------------------------------
-
-function render_genlicense_get() {
-
- var t = TABLE({border: 1});
- function ti(id, label) {
- t.push(TR(TD({align: "right"}, LABEL({htmlFor: id}, label+":")),
- TD(INPUT({id: id, name: id, type: 'text', size: 40}))));
- }
-
- ti("name", "Name of Licensee");
- ti("org", "Name of Organization");
- ti("userQuota", "User Quota");
-
- t.push(TR(TD({align: "right"}, LABEL("Software Edtition:")),
- TD( SELECT({name: "edition"},
- OPTION({value: licensing.getEditionId('PRIVATE_NETWORK_EVALUATION')},
- "Private Network EVALUATION"),
- OPTION({value: licensing.getEditionId('PRIVATE_NETWORK')},
- "Private Network")))));
-
- ti("expdays", "Number of days until expiration\n(leave blank if never expires)");
-
- t.push(TR(TD({colspan: 2}, INPUT({type: "submit"}))));
-
- var f = FORM({action: request.path, method: "post"});
- f.push(t);
-
- response.write(HTML(BODY(f)));
-}
-
-function render_genlicense_post() {
- var name = request.params.name;
- var org = request.params.org;
- var editionId = +request.params.edition;
- var editionName = licensing.getEditionName(editionId);
- var userQuota = +request.params.userQuota;
-
- var expiresTime = null;
- if (request.params.expdays) {
- expiresTime = +(new Date) + 1000*60*60*24*(+request.params.expdays);
- }
-
- var licenseKey = licensing.generateNewKey(
- name,
- org,
- expiresTime,
- editionId,
- userQuota
- );
-
- // verify
- if (!licensing.isValidKey(licenseKey)) {
- throw Error("License key I just created is not valid: "+licenseKey);
- }
-
- // TODO: write to database??
- //
-
- // display
- var licenseInfo = licensing.decodeLicenseInfoFromKey(licenseKey);
- var t = TABLE({border: 1});
- function line(k, v) {
- t.push(TR(TD({align: "right"}, k+":"),
- TD(v)));
- }
-
- var key = licenseKey.split(":")[2];
- if ((key.length % 2) != 0) {
- key = key + "+";
- }
- var keyLine1 = key.substr(0, key.length/2);
- var keyLine2 = key.substr(key.length/2, key.length);
-
- line("Name", licenseInfo.personName);
- line("Organization", licenseInfo.organizationName);
- line("Key", P(keyLine1, BR(), keyLine2));
- line("Software Edition", licenseInfo.editionName);
- line("User Quota", licenseInfo.userQuota);
- line("Expires", (+licenseInfo.expiresDate > 0) ? licenseInfo.expiresDate.toString() : "(never)");
-
- response.write(HTML(BODY(t)));
-}
-
-//----------------------------------------------------------------
-
-import("etherpad.metrics.metrics");
-
-function render_flows() {
- if (request.params.imgId && getSession()[request.params.imgId]) {
- var arr = getSession()[request.params.imgId];
- metrics[arr[0]](arr[1], Array.prototype.slice.call(arr[2]));
- response.stop();
- }
-
- function drawHistogram(name, h) {
- var imgKey = Math.round(Math.random()*1e12);
- print(IMG({src: request.path+"?imgId="+imgKey}));
- getSession()[imgKey] = ["respondWithPieChart", name, h];
- }
-
- var body = BODY();
- function print() {
- for (var i = 0; i < arguments.length; ++i) {
- body.push(arguments[i]);
- }
- }
-
- var [startDate, endDate] = [7, 1].map(function(a) { return new Date(Date.now() - 86400*1000*a); });
-
- var allFlows = metrics.getFlows(startDate, endDate);
-
-/*
- print(P("All flows:"));
-
- eachProperty(allFlows, function(k, flows) {
- print(P(k, html(" &raquo; ")));
- flows.forEach(function(flow) {
- print(P(flow.toString()));
- });
- });
- response.write(HTML(body));
- return;
-*/
-
- print(P("Parsing logs from: "+startDate+" through "+endDate));
-
- var fs =
- [metrics.getFunnel(startDate, endDate, ['/ep/about/pricing', '/ep/about/pricing-eepnet', '/ep/store/eepnet-eval-signup'], true),
- metrics.getFunnel(startDate, endDate, ['/ep/about/pricing', '/ep/about/pricing-free'], true),
- metrics.getFunnel(startDate, endDate, ['/ep/about/pricing', '/ep/about/pricing-eepod'], true),
- metrics.getFunnel(startDate, endDate, ['/ep/about/pricing', '/ep/store/eepnet-eval-signup'], true),
- metrics.getFunnel(startDate, endDate, ['/', '(pad)']),
- metrics.getFunnel(startDate, endDate, ['/', '/ep/pad/newpad'], true),
- metrics.getFunnel(startDate, endDate, ['/ep/about/screencast', '(pad)'])];
-
- function vcnt(i, i2) {
- return fs[i].visitorCounts[i2];
- }
- function pct(f) {
- return ""+Math.round(f*10000)/100+"%"
- }
- function cntAndPct(i, i2) {
- if (i2 === undefined) { i2 = 1; }
- return ""+vcnt(i, i2)+" ("+pct(vcnt(i, i2)/vcnt(i, i2-1))+")";
- }
- print(P("Of ", vcnt(0, 0), " visitors to the pricing page, ",
- cntAndPct(0), " of them viewed eepnet, (", cntAndPct(0, 2), " of those downloaded), ",
- cntAndPct(1), " of them viewed free, and ",
- cntAndPct(2), " of them viewed eepod. ",
- cntAndPct(3), " of them clicked on the eval signup link straight up."
- ),
- P("Of ", vcnt(4, 0), " visitors to the home page, ",
- cntAndPct(4), " of them went to a pad page in the same flow; ",
- cntAndPct(5), " of them clicked the new pad button immediately."),
- P("Of ", vcnt(6, 0), " vistitors to the screencast page, ",
- cntAndPct(6), " of them visisted a pad page in the same flow."));
-
- var origins = metrics.getOrigins(startDate, endDate, true);
- print(P("Flow first origins: "));
- drawHistogram("first origins", origins.flowFirsts);
-
- var firstHits = metrics.getOrigins(startDate, endDate, false, true);
- var padFirstHits = 0;
- var nonPadFirstHits = 0;
- print(P("First paths hit: "));
- drawHistogram("first paths", firstHits.flowFirsts);
- firstHits.flowFirsts.filter(function(x) {
- if (x.value != '/' && ! startsWith(x.value, "/ep/")) {
- padFirstHits += x.count;
- return false;
- }
- nonPadFirstHits += x.count;
- return true;
- });
- print(P("Some pad page: "+padFirstHits),
- P("Non-pad page: "+nonPadFirstHits));
-
- var exitsFromHomepage = metrics.getExits(startDate, endDate, '/', true);
- print(P("Exits from homepage: "));
- drawHistogram("exits", exitsFromHomepage.histogram)
-
- response.write(HTML(body));
-}
-
-//----------------------------------------------------------------
-
-import("etherpad.pad.pad_migrations");
-
-function render_padmigrations() {
- var residue = (request.params.r || 0);
- var modulus = (request.params.m || 1);
- var name = (request.params.n || (residue+"%"+modulus));
- pad_migrations.runBackgroundMigration(residue, modulus, name);
- response.write("done");
- return true;
-}
-
-// TODO: add ability to delete entries?
-// TODO: show sizes?
-function render_cachebrowser() {
- var path = request.params.path;
- if (path && path.charAt(0) == ',') {
- path = path.substr(1);
- }
- var pathArg = (path || "");
- var c = appjet.cache;
- if (path) {
- path.split(",").forEach(function(part) {
- c = c[part];
- });
- }
-
- var d = DIV({style: 'font-family: monospace; text-decoration: none;'});
-
- d.push(H3("appjet.cache --> "+pathArg.split(",").join(" --> ")));
-
- var t = TABLE({border: 1});
- keys(c).sort().forEach(function(k) {
- var v = c[k];
- if (v && (typeof(v) == 'object') && (!v.getDate)) {
- t.push(TR(TD(A({style: 'text-decoration: none;',
- href: request.path+"?path="+pathArg+","+k}, k))));
- } else {
- t.push(TR(TD(k), TD(v)));
- }
- });
-
- d.push(t);
- response.write(d);
-}
-
-function render_pne_tracker_get() {
- var data = sqlobj.selectMulti('pne_tracking_data', {}, {});
- data.sort(function(x, y) { return cmp(y.date, x.date); });
-
- var t = TABLE();
-
- var headrow = TR();
- ['date', 'remote host', 'keyHash', 'name', 'value'].forEach(function(x) {
- headrow.push(TH({align: "left", style: "padding: 0 6px;"}, x));
- });
- t.push(headrow);
-
- data.forEach(function(d) {
- var tr = TR();
-
- tr.push(TD(d.date.toString().split(' ').slice(0,5).join('-')));
-
- if (d.remoteIp) {
- tr.push(TD(netutils.getHostnameFromIp(d.remoteIp) || d.remoteIp));
- } else {
- tr.push(TD("-"));
- }
-
- if (d.keyHash) {
- tr.push(TD(A({href: '/ep/admin/pne-tracker-lookup-keyhash?hash='+d.keyHash}, d.keyHash)));
- } else {
- tr.push(TD("-"));
- }
-
- tr.push(TD(d.name));
- tr.push(TD(d.value));
-
- t.push(tr);
- });
-
- response.write(HTML(HEAD(html("<style>td { border-bottom: 1px solid #ddd; border-right: 1px solid #ddd; padding: 0 6px; } \n tr:hover { background: #ffc; }</style>"),
- BODY({style: "font-family: monospace; font-size: 12px;"}, t))));
-}
-
-function render_pne_tracker_lookup_keyhash_get() {
- var hash = request.params.hash;
- // brute force it
- var allLicenses = sqlobj.selectMulti('eepnet_signups', {}, {});
- var record = null;
- var i = 0;
- while (i < allLicenses.length && record == null) {
- var d = allLicenses[i];
- if (md5(d.licenseKey).substr(0, 16) == hash) {
- record = d;
- }
- i++;
- }
- if (!record) {
- response.write("Not found. Perhaps this was a test download from local development, or a paid customer whose licenses we don't currently look through on this page.");
- } else {
- var kl = keys(record).sort();
- var t = TABLE();
- kl.forEach(function(k) {
- t.push(TR(TH({align: "right"}, k+":"),
- TD({style: "padding-left: 1em;"}, record[k])));
- });
- response.write(HTML(BODY(DIV({style: "font-family: monospace;"},
- DIV(H1("Trial Signup Record:")), t))));
- }
-}
-
-function render_reload_blog_db_get() {
- var d = DIV();
- if (request.params.ok) {
- d.push(DIV(P("OK")));
- }
- d.push(FORM({method: "post", action: request.path},
- INPUT({type: "submit", value: "Reload Blog DB Now"})));
- response.write(HTML(BODY(d)));
-}
-
-function render_reload_blog_db_post() {
- blogcontrol.reloadBlogDb();
- response.redirect(request.path+"?ok=1");
-}
-
-function render_pro_domain_accounts() {
- var accounts = sqlobj.selectMulti('pro_accounts', {}, {});
- var domains = sqlobj.selectMulti('pro_domains', {}, {});
-
- // build domain map
- var domainMap = {};
- domains.forEach(function(d) { domainMap[d.id] = d; });
- accounts.sort(function(a,b) { return cmp(b.lastLoginDate, a.lastLoginDate); });
-
- var b = BODY({style: "font-family: monospace;"});
- b.push(accounts.length + " pro accounts.");
- var t = TABLE({border: 1});
- t.push(TR(TH("email"),
- TH("domain"),
- TH("lastLogin")));
- accounts.forEach(function(u) {
- t.push(TR(TD(u.email),
- TD(domainMap[u.domainId].subDomain+"."+request.domain),
- TD(u.lastLoginDate)));
- });
-
- b.push(t);
-
- response.write(HTML(b));
-}
-
-
-function render_beta_valve_get() {
- var d = DIV(
- P("Beta Valve Status: ",
- (pro_beta_control.isValveOpen() ?
- SPAN({style: "color: green;"}, B("OPEN")) :
- SPAN({style: "color: red;"}, B("CLOSED")))),
- P(FORM({action: '/ep/admin/beta-valve-toggle', method: "post"},
- BUTTON({type: "submit"}, "Toggle"))));
-
- var t = TABLE({border: 1, cellspacing: 0, cellpadding: 4, style: "font-family: monospace;"});
- var signupList = sqlobj.selectMulti('pro_beta_signups', {}, {});
- signupList.sort(function(a, b) {
- return cmp(b.signupDate, a.signupDate);
- });
-
- d.push(HR());
-
- if (getSession().betaAdminMessage) {
- d.push(DIV({style: "border: 1px solid #ccc; padding: 1em; background: #eee;"},
- getSession().betaAdminMessage));
- delete getSession().betaAdminMessage;
- }
-
- d.push(P(signupList.length + " beta signups"));
-
- d.push(FORM({action: '/ep/admin/beta-invite-multisend', method: 'post'},
- P("Send ", INPUT({type: 'text', name: 'count', size: 3}), " invites."),
- INPUT({type: "submit"})));
-
- t.push(TR(TH("id"), TH("email"), TH("signupDate"),
- TH("activationDate"), TH("activationCode"), TH(' ')));
-
- signupList.forEach(function(s) {
- var tr = TR();
- tr.push(TD(s.id),
- TD(s.email),
- TD(s.signupDate),
- TD(s.isActivated ? s.activationDate : "-"),
- TD(s.activationCode));
- if (!s.activationCode) {
- tr.push(TD(FORM({action: '/ep/admin/beta-invite-send', method: 'post'},
- INPUT({type: 'hidden', name: 'id', value: s.id}),
- INPUT({type: 'submit', value: "Send Invite"}))));
- } else {
- tr.push(TD(' '));
- }
- t.push(tr);
- });
- d.push(t);
- response.write(d);
-}
-
-function render_beta_valve_toggle_post() {
- pro_beta_control.toggleValve();
- response.redirect('/ep/admin/beta-valve');
-}
-
-function render_beta_invite_send_post() {
- var id = request.params.id;
- pro_beta_control.sendInvite(id);
- response.redirect('/ep/admin/beta-valve');
-}
-
-function render_beta_invite_multisend_post() {
- var count = request.params.count;
- var signupList = sqlobj.selectMulti('pro_beta_signups', {}, {});
- signupList.sort(function(a, b) {
- return cmp(a.signupDate, b.signupDate);
- });
- var sent = 0;
- for (var i = 0; ((i < signupList.length) && (sent < count)); i++) {
- var record = signupList[i];
- if (!record.activationCode) {
- pro_beta_control.sendInvite(record.id);
- sent++;
- }
- }
- getSession().betaAdminMessage = (sent+" invites sent.");
- response.redirect('/ep/admin/beta-valve');
-}
-
-function render_usagestats() {
- response.redirect("/ep/admin/usagestats/");
-}
-
-function render_exceptions() {
- exceptions.render();
-}
-
-function render_setadminmode() {
- sessions.setIsAnEtherpadAdmin(
- String(request.params.v).toLowerCase() == "true");
- response.redirect("/ep/admin/");
-}
-
-// --------------------------------------------------------------
-// billing-related
-// --------------------------------------------------------------
-
-// some of these functions are only used from selenium tests, and so have no UI.
-
-function render_setdomainpaidthrough() {
- var domainName = request.params.domain;
- var when = new Date(Number(request.params.paidthrough));
- if (! domainName || ! when) {
- response.write("fail");
- response.stop();
- }
- var domain = domains.getDomainRecordFromSubdomain(domainName);
- var domainId = domain.id;
-
- var subscription = team_billing.getSubscriptionForCustomer(domainId);
- if (subscription) {
- billing.updatePurchase(subscription.id, {paidThrough: when});
- team_billing.domainCacheClear(domainId);
- response.write("OK");
- } else {
- response.write("fail");
- }
-}
-
-function render_runsubscriptions() {
- team_billing.processAllSubscriptions();
- response.write("OK");
-}
-
-function render_reset_subscription() {
- var body = BODY();
- if (request.isGet) {
- body.push(FORM({method: "POST"},
- "Subdomain: ", INPUT({type: "text", name: "subdomain"}), BUTTON({name: "clear"}, "Go")));
- } else if (request.isPost) {
- if (! request.params.confirm) {
- var domain = domains.getDomainRecordFromSubdomain(request.params.subdomain);
- var admins = pro_accounts.listAllDomainAdmins(domain.id);
- body.push(P("Domain ", domain.subDomain, ".", request.domain, "; admins:"));
- var p = UL();
- admins.forEach(function(admin) {
- p.push(LI(admin.fullName, " <", admin.email, ">"));
- });
- body.push(p);
- var subscription = team_billing.getSubscriptionForCustomer(domain.id);
- if (subscription) {
- body.push(P("Subscription is currently ", subscription.status, ", and paid through: ", checkout.formatDate(subscription.paidThrough), "."))
- body.push(FORM({method: "POST"},
- INPUT({type: "hidden", name: "subdomain", value: request.params.subdomain}),
- "Are you sure? ", BUTTON({name: "confirm", value: "yes"}, "YES")));
- } else {
- body.push(P("No current subscription"));
- }
- } else {
- var domain = domains.getDomainRecordFromSubdomain(request.params.subdomain);
- sqlcommon.inTransaction(function() {
- team_billing.resetMaxUsers(domain.id);
- sqlobj.deleteRows('billing_purchase', {customer: domain.id, type: 'subscription'});
- team_billing.domainCacheClear(domain.id);
- team_billing.clearRecurringBillingInfo(domain.id);
- });
- body.push("Done!")
- }
- }
- body.push(A({href: request.path}, html("&laquo; back")));
- response.write(HTML(body));
-} \ No newline at end of file
diff --git a/trunk/etherpad/src/etherpad/control/pad/pad_control.js b/trunk/etherpad/src/etherpad/control/pad/pad_control.js
deleted file mode 100644
index 3c32202..0000000
--- a/trunk/etherpad/src/etherpad/control/pad/pad_control.js
+++ /dev/null
@@ -1,780 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("funhtml.*");
-import("comet");
-import("email.sendEmail");
-import("fastJSON");
-import("jsutils.eachProperty");
-import("sqlbase.sqlbase");
-import("stringutils.{toHTML,md5}");
-import("stringutils");
-
-import("etherpad.collab.collab_server");
-import("etherpad.debug.dmesg");
-import("etherpad.globals.*");
-import("etherpad.helpers");
-import("etherpad.licensing");
-import("etherpad.quotas");
-import("etherpad.log");
-import("etherpad.log.{logRequest,logException}");
-import("etherpad.sessions");
-import("etherpad.sessions.getSession");
-import("etherpad.utils.*");
-import("etherpad.pro.pro_padmeta");
-import("etherpad.pro.pro_pad_db");
-import("etherpad.pro.pro_utils");
-import("etherpad.pro.pro_accounts.getSessionProAccount");
-import("etherpad.pro.domains");
-import("etherpad.pro.pro_config");
-import("etherpad.pne.pne_utils");
-import("etherpad.pro.pro_quotas");
-
-import("etherpad.pad.revisions");
-import("etherpad.pad.chatarchive");
-import("etherpad.pad.model");
-import("etherpad.pad.padutils");
-import("etherpad.pad.padusers");
-import("etherpad.control.pad.pad_view_control");
-import("etherpad.control.pad.pad_changeset_control");
-import("etherpad.control.pad.pad_importexport_control");
-import("etherpad.collab.readonly_server");
-
-import("dispatch.{Dispatcher,PrefixMatcher,DirMatcher,forward}");
-
-jimport("java.lang.System.out.println");
-
-var DISABLE_PAD_CREATION = false;
-
-function onStartup() {
- sqlbase.createJSONTable("PAD_DIAGNOSTIC");
-}
-
-function onRequest() {
-
- // TODO: take a hard look at /ep/pad/FOO/BAR/ dispatching.
- // Perhaps standardize on /ep/pad/<pad-id>/foo
- if (request.path.indexOf('/ep/pad/auth/') == 0) {
- if (request.isGet) {
- return render_auth_get();
- }
- if (request.isPost) {
- return render_auth_post();
- }
- }
-
- if (pro_utils.isProDomainRequest()) {
- pro_quotas.perRequestBillingCheck();
- }
-
- var disp = new Dispatcher();
- disp.addLocations([
- [PrefixMatcher('/ep/pad/view/'), forward(pad_view_control)],
- [PrefixMatcher('/ep/pad/changes/'), forward(pad_changeset_control)],
- [PrefixMatcher('/ep/pad/impexp/'), forward(pad_importexport_control)],
- [PrefixMatcher('/ep/pad/export/'), pad_importexport_control.renderExport]
- ]);
- return disp.dispatch();
-}
-
-//----------------------------------------------------------------
-// utils
-//----------------------------------------------------------------
-
-function getDefaultPadText() {
- if (pro_utils.isProDomainRequest()) {
- return pro_config.getConfig().defaultPadText;
- }
- return renderTemplateAsString("misc/pad_default.ejs", {padUrl: request.url.split("?", 1)[0]});
-}
-
-function assignName(pad, userId) {
- if (padusers.isGuest(userId)) {
- // use pad-specific name if possible
- var userData = pad.getAuthorData(userId);
- var nm = (userData && userData.name) || padusers.getUserName() || null;
-
- // don't let name guest typed in last once we've assigned a name
- // for this pad, so the user can change it
- delete getSession().guestDisplayName;
-
- return nm;
- }
- else {
- return padusers.getUserName();
- }
-}
-
-function assignColorId(pad, userId) {
- // use pad-specific color if possible
- var userData = pad.getAuthorData(userId);
- if (userData && ('colorId' in userData)) {
- return userData.colorId;
- }
-
- // assign random unique color
- function r(n) {
- return Math.floor(Math.random() * n);
- }
- var colorsUsed = {};
- var users = collab_server.getConnectedUsers(pad);
- var availableColors = [];
- users.forEach(function(u) {
- colorsUsed[u.colorId] = true;
- });
- for (var i = 0; i < COLOR_PALETTE.length; i++) {
- if (!colorsUsed[i]) {
- availableColors.push(i);
- }
- }
- if (availableColors.length > 0) {
- return availableColors[r(availableColors.length)];
- } else {
- return r(COLOR_PALETTE.length);
- }
-}
-
-function _getPrivs() {
- return {
- maxRevisions: quotas.getMaxSavedRevisionsPerPad()
- };
-}
-
-//----------------------------------------------------------------
-// linkfile (a file that users can save that redirects them to
-// a particular pad; auto-download)
-//----------------------------------------------------------------
-function render_linkfile() {
- var padId = request.params.padId;
-
- renderHtml("pad/pad_download_link.ejs", {
- padId: padId
- });
-
- response.setHeader("Content-Disposition", "attachment; filename=\""+padId+".html\"");
-}
-
-//----------------------------------------------------------------
-// newpad
-//----------------------------------------------------------------
-
-function render_newpad() {
- var session = getSession();
- var padId;
-
- if (pro_utils.isProDomainRequest()) {
- padId = pro_pad_db.getNextPadId();
- } else {
- padId = randomUniquePadId();
- }
-
- session.instantCreate = padId;
- response.redirect("/"+padId);
-}
-
-// Tokbox
-function render_newpad_xml_post() {
- var localPadId;
- if (pro_utils.isProDomainRequest()) {
- localPadId = pro_pad_db.getNextPadId();
- } else {
- localPadId = randomUniquePadId();
- }
- // <RAFTER>
- if (DISABLE_PAD_CREATION) {
- if (! pro_utils.isProDomainRequest()) {
- utils.render500();
- return;
- }
- }
- // </RAFTER>
-
- padutils.accessPadLocal(localPadId, function(pad) {
- if (!pad.exists()) {
- pad.create(getDefaultPadText());
- }
- });
- response.setContentType('text/plain; charset=utf-8');
- response.write([
- '<newpad>',
- '<url>http://'+request.host+'/'+localPadId+'</url>',
- '</newpad>'
- ].join('\n'));
-}
-
-//----------------------------------------------------------------
-// pad
-//----------------------------------------------------------------
-
-function _createIfNecessary(localPadId, pad) {
- if (pad.exists()) {
- delete getSession().instantCreate;
- return;
- }
- // make sure localPadId is valid.
- var validPadId = padutils.makeValidLocalPadId(localPadId);
- if (localPadId != validPadId) {
- response.redirect('/'+validPadId);
- }
- // <RAFTER>
- if (DISABLE_PAD_CREATION) {
- if (! pro_utils.isProDomainRequest()) {
- response.redirect("/ep/pad/create?padId="+encodeURIComponent(localPadId));
- return;
- }
- }
- // </RAFTER>
- // tokbox may use createImmediately
- if (request.params.createImmediately || getSession().instantCreate == localPadId) {
- pad.create(getDefaultPadText());
- delete getSession().instantCreate;
- return;
- }
- response.redirect("/ep/pad/create?padId="+encodeURIComponent(localPadId));
-}
-
-function _promptForMobileDevices(pad) {
- // TODO: also work with blackbery and windows mobile and others
- if (request.userAgent.isIPhone() && (!request.params.skipIphoneCheck)) {
- renderHtml("pad/pad_iphone_body.ejs", {padId: pad.getLocalId()});
- response.stop();
- }
-}
-
-function _checkPadQuota(pad) {
- var numConnectedUsers = collab_server.getNumConnections(pad);
- var maxUsersPerPad = quotas.getMaxSimultaneousPadEditors(pad.getId());
-
- if (numConnectedUsers >= maxUsersPerPad) {
- log.info("rendered-padfull");
- renderFramed('pad/padfull_body.ejs',
- {maxUsersPerPad: maxUsersPerPad, padId: pad.getLocalId()});
- response.stop();
- }
-
- if (pne_utils.isPNE()) {
- if (!licensing.canSessionUserJoin()) {
- renderFramed('pad/total_users_exceeded.ejs', {
- userQuota: licensing.getActiveUserQuota(),
- activeUserWindowHours: licensing.getActiveUserWindowHours()
- });
- response.stop();
- }
- }
-}
-
-function _checkIfDeleted(pad) {
- // TODO: move to access control check on access?
- if (pro_utils.isProDomainRequest()) {
- pro_padmeta.accessProPad(pad.getId(), function(propad) {
- if (propad.exists() && propad.isDeleted()) {
- renderNoticeString("This pad has been deleted.");
- response.stop();
- }
- });
- }
-}
-
-function render_pad(localPadId) {
- var proTitle = null, documentBarTitle, initialPassword = null;
- var isPro = isProDomainRequest();
- var userId = padusers.getUserId();
-
- var opts = {};
- var globalPadId;
-
- if (isPro) {
- pro_quotas.perRequestBillingCheck();
- }
-
- padutils.accessPadLocal(localPadId, function(pad) {
- globalPadId = pad.getId();
- request.cache.globalPadId = globalPadId;
- _createIfNecessary(localPadId, pad);
- _promptForMobileDevices(pad);
- _checkPadQuota(pad);
- _checkIfDeleted(pad);
-
- if (request.params.inviteTo) {
- getSession().nameGuess = request.params.inviteTo;
- response.redirect('/'+localPadId);
- }
- var displayName;
- if (request.params.displayName) { // tokbox
- displayName = String(request.params.displayName);
- }
- else {
- displayName = assignName(pad, userId);
- }
-
- if (isProDomainRequest()) {
- pro_padmeta.accessProPadLocal(localPadId, function(propad) {
- proTitle = propad.getDisplayTitle();
- initialPassword = propad.getPassword();
- });
- }
- documentBarTitle = (proTitle || "Public Pad");
-
- var specialKey = request.params.specialKey ||
- (sessions.isAnEtherpadAdmin() ? collab_server.getSpecialKey('invisible') :
- null);
- if (request.params.fullScreen) { // tokbox, embedding
- opts.fullScreen = true;
- }
- if (request.params.tokbox) {
- opts.tokbox = true;
- }
- if (request.params.sidebar) {
- opts.sidebar = Boolean(Number(request.params.sidebar));
- }
-
- helpers.addClientVars({
- padId: localPadId,
- globalPadId: globalPadId,
- userAgent: request.headers["User-Agent"],
- collab_client_vars: collab_server.getCollabClientVars(pad),
- debugEnabled: request.params.djs,
- clientIp: request.clientAddr,
- colorPalette: COLOR_PALETTE,
- nameGuess: (getSession().nameGuess || null),
- initialRevisionList: revisions.getRevisionList(pad),
- serverTimestamp: +(new Date),
- accountPrivs: _getPrivs(),
- chatHistory: chatarchive.getRecentChatBlock(pad, 30),
- numConnectedUsers: collab_server.getNumConnections(pad),
- isProPad: isPro,
- initialTitle: documentBarTitle,
- initialPassword: initialPassword,
- initialOptions: pad.getPadOptionsObj(),
- userIsGuest: padusers.isGuest(userId),
- userId: userId,
- userName: displayName,
- userColor: assignColorId(pad, userId),
- specialKey: specialKey,
- specialKeyTranslation: collab_server.translateSpecialKey(specialKey),
- opts: opts
- });
- });
-
- var isProUser = (isPro && ! padusers.isGuest(userId));
-
- var isFullWidth = false;
- var hideSidebar = false;
- var cookiePrefs = padutils.getPrefsCookieData();
- if (cookiePrefs) {
- isFullWidth = !! cookiePrefs.fullWidth;
- hideSidebar = !! cookiePrefs.hideSidebar;
- }
- if (opts.fullScreen) {
- isFullWidth = true;
- if (opts.tokbox) {
- hideSidebar = true;
- }
- }
- if ('sidebar' in opts) {
- hideSidebar = ! opts.sidebar;
- }
- var bodyClass = (isFullWidth ? "fullwidth" : "limwidth")+
- " "+(isPro ? "propad" : "nonpropad")+" "+
- (isProUser ? "prouser" : "nonprouser");
-
- var cookiePrefsToSet = {fullWidth:isFullWidth, hideSidebar:hideSidebar};
- helpers.addClientVars({cookiePrefsToSet: cookiePrefsToSet});
-
- renderHtml("pad/pad_body2.ejs",
- {localPadId:localPadId,
- pageTitle:toHTML(proTitle || localPadId),
- initialTitle:toHTML(documentBarTitle),
- bodyClass: bodyClass,
- hasOffice: hasOffice(),
- isPro: isPro,
- isProAccountHolder: isProUser,
- account: getSessionProAccount(), // may be falsy
- toHTML: toHTML,
- prefs: {isFullWidth:isFullWidth, hideSidebar:hideSidebar},
- signinUrl: '/ep/account/sign-in?cont='+
- encodeURIComponent(request.url),
- fullSuperdomain: pro_utils.getFullSuperdomainHost()
- });
- return true;
-}
-
-function render_create_get() {
- var padId = request.params.padId;
- // <RAFTER>
- var template = (DISABLE_PAD_CREATION && ! pro_utils.isProDomainRequest()) ?
- "pad/create_body_rafter.ejs" :
- "pad/create_body.ejs";
- // </RAFTER>
- renderFramed(template, {padId: padId,
- fullSuperdomain: pro_utils.getFullSuperdomainHost()});
-}
-
-function render_create_post() {
- var padId = request.params.padId;
- getSession().instantCreate = padId;
- response.redirect("/"+padId);
-}
-
-//----------------------------------------------------------------
-// saverevision
-//----------------------------------------------------------------
-
-function render_saverevision_post() {
- var padId = request.params.padId;
- var savedBy = request.params.savedBy;
- var savedById = request.params.savedById;
- var revNum = request.params.revNum;
- var privs = _getPrivs();
- padutils.accessPadLocal(padId, function(pad) {
- if (! pad.exists()) { response.notFound(); }
- var currentRevs = revisions.getRevisionList(pad);
- if (currentRevs.length >= privs.maxRevisions) {
- response.forbid();
- }
- var savedRev = revisions.saveNewRevision(pad, savedBy, savedById,
- revNum);
- readonly_server.broadcastNewRevision(pad, savedRev);
- response.setContentType('text/x-json');
- response.write(fastJSON.stringify(revisions.getRevisionList(pad)));
- });
-}
-
-function render_saverevisionlabel_post() {
- var userId = request.params.userId;
- var padId = request.params.padId;
- var revId = request.params.revId;
- var newLabel = request.params.newLabel;
- padutils.accessPadLocal(padId, function(pad) {
- revisions.setLabel(pad, revId, userId, newLabel);
- response.setContentType('text/x-json');
- response.write(fastJSON.stringify(revisions.getRevisionList(pad)));
- });
-}
-
-function render_getrevisionatext_get() {
- var padId = request.params.padId;
- var revId = request.params.revId;
- var result = null;
-
- var rev = padutils.accessPadLocal(padId, function(pad) {
- var r = revisions.getStoredRevision(pad, revId);
- var forWire = collab_server.getATextForWire(pad, r.revNum);
- result = {atext:forWire.atext, apool:forWire.apool,
- historicalAuthorData:forWire.historicalAuthorData};
- return r;
- }, "r");
-
- response.setContentType('text/plain; charset=utf-8');
- response.write(fastJSON.stringify(result));
-}
-
-//----------------------------------------------------------------
-// reconnect
-//----------------------------------------------------------------
-
-function _recordDiagnosticInfo(padId, diagnosticInfoJson) {
-
- var diagnosticInfo = {};
- try {
- diagnosticInfo = fastJSON.parse(diagnosticInfoJson);
- } catch (ex) {
- log.warn("Error parsing diagnosticInfoJson: "+ex);
- diagnosticInfo = {error: "error parsing JSON"};
- }
-
- // ignore userdups, unauth
- if (diagnosticInfo.disconnectedMessage == "userdup" ||
- diagnosticInfo.disconnectedMessage == "unauth") {
- return;
- }
-
- var d = new Date();
-
- diagnosticInfo.date = +d;
- diagnosticInfo.strDate = String(d);
- diagnosticInfo.clientAddr = request.clientAddr;
- diagnosticInfo.padId = padId;
- diagnosticInfo.headers = {};
- eachProperty(request.headers, function(k,v) {
- diagnosticInfo.headers[k] = v;
- });
-
- var uid = diagnosticInfo.uniqueId;
-
- sqlbase.putJSON("PAD_DIAGNOSTIC", (diagnosticInfo.date)+"-"+uid, diagnosticInfo);
-
-}
-
-function recordMigratedDiagnosticInfo(objArray) {
- objArray.forEach(function(obj) {
- sqlbase.putJSON("PAD_DIAGNOSTIC", (obj.date)+"-"+obj.uniqueId, obj);
- });
-}
-
-function render_reconnect() {
- var localPadId = request.params.padId;
- var globalPadId = padutils.getGlobalPadId(localPadId);
- var userId = (padutils.getPrefsCookieUserId() || undefined);
- var hasClientErrors = false;
- var uniqueId;
- try {
- var obj = fastJSON.parse(request.params.diagnosticInfo);
- uniqueId = obj.uniqueId;
- errorMessage = obj.disconnectedMessage;
- hasClientErrors = obj.collabDiagnosticInfo.errors.length > 0;
- } catch (e) {
- // guess it doesn't have errors.
- }
-
- log.custom("reconnect", {globalPadId: globalPadId, userId: userId,
- uniqueId: uniqueId,
- hasClientErrors: hasClientErrors,
- errorMessage: errorMessage });
-
- try {
- _recordDiagnosticInfo(globalPadId, request.params.diagnosticInfo);
- } catch (ex) {
- log.warn("Error recording diagnostic info: "+ex+" / "+request.params.diagnosticInfo);
- }
-
- try {
- _applyMissedChanges(localPadId, request.params.missedChanges);
- } catch (ex) {
- log.warn("Error applying missed changes: "+ex+" / "+request.params.missedChanges);
- }
-
- response.redirect('/'+localPadId);
-}
-
-/* posted asynchronously by the client as soon as reconnect dialogue appears. */
-function render_connection_diagnostic_info_post() {
- var localPadId = request.params.padId;
- var globalPadId = padutils.getGlobalPadId(localPadId);
- var userId = (padutils.getPrefsCookieUserId() || undefined);
- var hasClientErrors = false;
- var uniqueId;
- var errorMessage;
- try {
- var obj = fastJSON.parse(request.params.diagnosticInfo);
- uniqueId = obj.uniqueId;
- errorMessage = obj.disconnectedMessage;
- hasClientErrors = obj.collabDiagnosticInfo.errors.length > 0;
- } catch (e) {
- // guess it doesn't have errors.
- }
- log.custom("disconnected_autopost", {globalPadId: globalPadId, userId: userId,
- uniqueId: uniqueId,
- hasClientErrors: hasClientErrors,
- errorMessage: errorMessage});
-
- try {
- _recordDiagnosticInfo(globalPadId, request.params.diagnosticInfo);
- } catch (ex) {
- log.warn("Error recording diagnostic info: "+ex+" / "+request.params.diagnosticInfo);
- }
- response.setContentType('text/plain; charset=utf-8');
- response.write("OK");
-}
-
-function _applyMissedChanges(localPadId, missedChangesJson) {
- var missedChanges;
- try {
- missedChanges = fastJSON.parse(missedChangesJson);
- } catch (ex) {
- log.warn("Error parsing missedChangesJson: "+ex);
- return;
- }
-
- padutils.accessPadLocal(localPadId, function(pad) {
- if (pad.exists()) {
- collab_server.applyMissedChanges(pad, missedChanges);
- }
- });
-}
-
-//----------------------------------------------------------------
-// feedback
-//----------------------------------------------------------------
-
-function render_feedback_post() {
- var feedback = request.params.feedback;
- var localPadId = request.params.padId;
- var globalPadId = padutils.getGlobalPadId(localPadId);
- var username = request.params.username;
- var email = request.params.email;
- var subject = 'EtherPad Feedback from '+request.clientAddr+' / '+globalPadId+' / '+username;
-
- if (feedback.indexOf("@") > 0) {
- subject = "@ "+subject;
- }
-
- feedback += "\n\n--\n";
- feedback += ("User Agent: "+request.headers['User-Agent'] + "\n");
- feedback += ("Session Referer: "+getSession().initialReferer + "\n");
- feedback += ("Email: "+email+"\n");
-
- // log feedback
- var userId = padutils.getPrefsCookieUserId();
- log.custom("feedback", {
- globalPadId: globalPadId,
- userId: userId,
- email: email,
- username: username,
- feedback: request.params.feedback});
-
- sendEmail(
- 'feedback@pad.spline.inf.fu-berlin.de',
- 'feedback@pad.spline.inf.fu-berlin.de',
- subject,
- {},
- feedback
- );
- response.write("OK");
-}
-
-//----------------------------------------------------------------
-// emailinvite
-//----------------------------------------------------------------
-
-function render_emailinvite_post() {
- var toEmails = String(request.params.toEmails).split(',');
- var padId = String(request.params.padId);
- var username = String(request.params.username);
- var subject = String(request.params.subject);
- var message = String(request.params.message);
-
- log.custom("padinvite",
- {toEmails: toEmails, padId: padId, username: username,
- subject: subject, message: message});
-
- var fromAddr = '"EtherPad" <noreply@pad.spline.inf.fu-berlin.de>';
- // client enforces non-empty subject and message
- var subj = '[EtherPad] '+subject;
- var body = renderTemplateAsString('email/padinvite.ejs',
- {body: message});
- var headers = {};
- var proAccount = getSessionProAccount();
- if (proAccount) {
- headers['Reply-To'] = proAccount.email;
- }
-
- response.setContentType('text/plain; charset=utf-8');
- try {
- sendEmail(toEmails, fromAddr, subj, headers, body);
- response.write("OK");
- } catch (e) {
- logException(e);
- response.setStatusCode(500);
- response.write("Error");
- }
-}
-
-//----------------------------------------------------------------
-// time-slider
-//----------------------------------------------------------------
-function render_slider() {
- var parts = request.path.split('/');
- var padOpaqueRef = parts[4];
-
- helpers.addClientVars({padOpaqueRef:padOpaqueRef});
-
- renderHtml("pad/padslider_body.ejs", {
- // properties go here
- });
-
- return true;
-}
-
-//----------------------------------------------------------------
-// auth
-//----------------------------------------------------------------
-
-function render_auth_get() {
- var parts = request.path.split('/');
- var localPadId = parts[4];
- var errDiv;
- if (getSession().padPassErr) {
- errDiv = DIV({style: "border: 1px solid #fcc; background: #ffeeee; padding: 1em; margin: 1em 0;"},
- B(getSession().padPassErr));
- delete getSession().padPassErr;
- } else {
- errDiv = DIV();
- }
- renderFramedHtml(function() {
- return DIV({className: "fpcontent"},
- DIV({style: "margin: 1em;"},
- errDiv,
- FORM({style: "border: 1px solid #ccc; padding: 1em; background: #fff6cc;",
- action: request.path+'?'+request.query,
- method: "post"},
- LABEL(B("Please enter the password required to access this pad:")),
- BR(), BR(),
- INPUT({type: "text", name: "password"}), INPUT({type: "submit", value: "Submit"})
- /*DIV(BR(), "Or ", A({href: '/ep/account/sign-in'}, "sign in"), ".")*/
- )),
- DIV({style: "padding: 0 1em;"},
- P({style: "color: #444;"},
- "If you have forgotten a pad's password, contact your site administrator.",
- " Site administrators can recover lost pad text through the \"Admin\" tab.")
- )
- );
- });
- return true;
-}
-
-function render_auth_post() {
- var parts = request.path.split('/');
- var localPadId = parts[4];
- var domainId = domains.getRequestDomainId();
- if (!getSession().padPasswordAuth) {
- getSession().padPasswordAuth = {};
- }
- var currentPassword = pro_padmeta.accessProPadLocal(localPadId, function(propad) {
- return propad.getPassword();
- });
- if (request.params.password == currentPassword) {
- var globalPadId = padutils.getGlobalPadId(localPadId);
- getSession().padPasswordAuth[globalPadId] = true;
- } else {
- getSession().padPasswordAuth[globalPadId] = false;
- getSession().padPassErr = "Incorrect password.";
- }
- var cont = request.params.cont;
- if (!cont) {
- cont = '/'+localPadId;
- }
- response.redirect(cont);
-}
-
-//----------------------------------------------------------------
-// chathistory
-//----------------------------------------------------------------
-
-function render_chathistory_get() {
- var padId = request.params.padId;
- var start = Number(request.params.start || 0);
- var end = Number(request.params.end || 0);
- var result = null;
-
- var rev = padutils.accessPadLocal(padId, function(pad) {
- result = chatarchive.getChatBlock(pad, start, end);
- }, "r");
-
- response.setContentType('text/plain; charset=utf-8');
- response.write(fastJSON.stringify(result));
-}
-
diff --git a/trunk/etherpad/src/etherpad/control/pro/admin/pro_admin_control.js b/trunk/etherpad/src/etherpad/control/pro/admin/pro_admin_control.js
deleted file mode 100644
index f9ce179..0000000
--- a/trunk/etherpad/src/etherpad/control/pro/admin/pro_admin_control.js
+++ /dev/null
@@ -1,283 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("stringutils");
-import("funhtml.*");
-import("dispatch.{Dispatcher,DirMatcher,forward}");
-
-import("etherpad.licensing");
-import("etherpad.control.admincontrol");
-import("etherpad.control.pro.admin.license_manager_control");
-import("etherpad.control.pro.admin.account_manager_control");
-import("etherpad.control.pro.admin.pro_config_control");
-import("etherpad.control.pro.admin.team_billing_control");
-
-import("etherpad.pad.padutils");
-
-import("etherpad.admin.shell");
-import("etherpad.sessions");
-import("etherpad.sessions.getSession");
-
-import("etherpad.pne.pne_utils");
-import("etherpad.pro.pro_accounts");
-import("etherpad.utils.*");
-
-//----------------------------------------------------------------
-
-var _pathPrefix = '/ep/admin/';
-
-var _PRO = 1;
-var _PNE_ONLY = 2;
-var _ONDEMAND_ONLY = 3;
-
-function _getLeftnavItems() {
- var nav = [
- _PRO, [
- [_PRO, null, "Admin"],
- [_PNE_ONLY, "pne-dashboard", "Server Dashboard"],
- [_PNE_ONLY, "pne-license-manager/", "Manage License"],
- [_PRO, "account-manager/", "Manage Accounts"],
- [_PRO, "recover-padtext", "Recover Pad Text"],
- [_PRO, null, "Configuration"],
- [_PRO, [[_PNE_ONLY, "pne-config", "Private Server Configuration"],
- [_PRO, "pro-config", "Application Configuration"]]],
- [_PNE_ONLY, null, "Documentation"],
- [_PNE_ONLY, "/ep/pne-manual/", "Administrator's Manual"],
- ]
- ];
- return nav;
-}
-
-function renderAdminLeftNav() {
- function _make(x) {
- if ((x[0] == _PNE_ONLY) && !pne_utils.isPNE()) {
- return null;
- }
- if ((x[0] == _ONDEMAND_ONLY) && pne_utils.isPNE()) {
- return null;
- }
-
- if (x[1] instanceof Array) {
- return _makelist(x[1]);
- } else {
- return _makeitem(x);
- }
- }
- var selected;
- function _makeitem(x) {
- if (x[1]) {
- var p = x[1];
- if (x[1].charAt(0) != '/') {
- p = _pathPrefix+p;
- }
- var li = LI(A({href: p}, x[2]));
- if (stringutils.startsWith(request.path, p)) {
- // select the longest prefix match.
- if (! selected || p.length > selected.path.length) {
- selected = {path: p, li: li};
- }
- }
- return li;
- } else {
- return LI(DIV({className: 'leftnav-title'}, x[2]));
- }
- }
- function _makelist(x) {
- var ul = UL();
- x.forEach(function(y) {
- var t = _make(y);
- if (t) { ul.push(t); }
- });
- return ul;
- }
- var d = DIV(_make(_getLeftnavItems()));
- if (selected) {
- selected.li.attribs.className = "selected";
- }
- // leftnav looks stupid when it's not very tall.
- for (var i = 0; i < 10; i++) { d.push(BR()); }
- return d;
-}
-
-function renderAdminPage(p, data) {
- appjet.requestCache.proTopNavSelection = 'admin';
- function getAdminContent() {
- if (typeof(p) == 'function') {
- return p();
- } else {
- return renderTemplateAsString('pro/admin/'+p+'.ejs', data);
- }
- }
- renderFramed('pro/admin/admin-template.ejs', {
- getAdminContent: getAdminContent,
- renderAdminLeftNav: renderAdminLeftNav,
- validLicense: pne_utils.isServerLicensed(),
- });
-}
-
-//----------------------------------------------------------------
-
-function onRequest() {
- var disp = new Dispatcher();
- disp.addLocations([
- [DirMatcher(license_manager_control.getPath()), forward(license_manager_control)],
- [DirMatcher('/ep/admin/account-manager/'), forward(account_manager_control)],
- [DirMatcher('/ep/admin/pro-config/'), forward(pro_config_control)],
- [DirMatcher('/ep/admin/billing/'), forward(team_billing_control)],
- ]);
-
- if (disp.dispatch()) {
- return true;
- }
-
- // request will be handled by this module.
- pro_accounts.requireAdminAccount();
-}
-
-function render_main() {
-// renderAdminPage('admin');
- response.redirect('/ep/admin/account-manager/')
-}
-
-function render_pne_dashboard() {
- renderAdminPage('pne-dashboard', {
- renderUptime: admincontrol.renderServerUptime,
- renderResponseCodes: admincontrol.renderResponseCodes,
- renderPadConnections: admincontrol.renderPadConnections,
- renderTransportStats: admincontrol.renderCometStats,
- todayActiveUsers: licensing.getActiveUserCount(),
- userQuota: licensing.getActiveUserQuota()
- });
-}
-
-var _documentedServerOptions = [
- 'listen',
- 'listenSecure',
- 'transportUseWildcardSubdomains',
- 'sslKeyStore',
- 'sslKeyPassword',
- 'etherpad.soffice',
- 'etherpad.adminPass',
- 'etherpad.SQL_JDBC_DRIVER',
- 'etherpad.SQL_JDBC_URL',
- 'etherpad.SQL_USERNAME',
- 'etherpad.SQL_PASSWORD',
- 'smtpServer',
- 'smtpUser',
- 'smtpPass',
- 'configFile',
- 'etherpad.licenseKey',
- 'verbose'
-];
-
-function render_pne_config_get() {
- renderAdminPage('pne-config', {
- propKeys: _documentedServerOptions,
- appjetConfig: appjet.config
- });
-}
-
-function render_pne_advanced_get() {
- response.redirect("/ep/admin/shell");
-}
-
-function render_shell_get() {
- if (!(pne_utils.isPNE() || sessions.isAnEtherpadAdmin())) {
- return false;
- }
- appjet.requestCache.proTopNavSelection = 'admin';
- renderAdminPage('pne-shell', {
- oldCmd: getSession().pneAdminShellCmd,
- result: getSession().pneAdminShellResult,
- elapsedMs: getSession().pneAdminShellElapsed
- });
- delete getSession().pneAdminShellResult;
- delete getSession().pneAdminShellElapsed;
-}
-
-function render_shell_post() {
- if (!(pne_utils.isPNE() || sessions.isAnEtherpadAdmin())) {
- return false;
- }
- var cmd = request.params.cmd;
- var start = +(new Date);
- getSession().pneAdminShellCmd = cmd;
- getSession().pneAdminShellResult = shell.getResult(cmd);
- getSession().pneAdminShellElapsed = +(new Date) - start;
- response.redirect(request.path);
-}
-
-function render_recover_padtext_get() {
- function getNumRevisions(localPadId) {
- return padutils.accessPadLocal(localPadId, function(pad) {
- if (!pad.exists()) { return null; }
- return 1+pad.getHeadRevisionNumber();
- });
- }
- function getPadText(localPadId, revNum) {
- return padutils.accessPadLocal(localPadId, function(pad) {
- if (!pad.exists()) { return null; }
- return pad.getRevisionText(revNum);
- });
- }
-
- var localPadId = request.params.localPadId;
- var revNum = request.params.revNum;
-
- var d = DIV({style: "font-size: .8em;"});
-
- d.push(FORM({action: request.path, method: "get"},
- P({style: "margin-top: 0;"}, LABEL("Pad ID: "),
- INPUT({type: "text", name: "localPadId", value: localPadId || ""}),
- INPUT({type: "submit", value: "Submit"}))));
-
- var showPadHelp = false;
- var revisions = null;
-
- if (!localPadId) {
- showPadHelp = true;
- } else {
- revisions = getNumRevisions(localPadId);
- if (!revisions) {
- d.push(P("Pad not found: "+localPadId));
- } else {
- d.push(P(B(localPadId), " has ", revisions, " revisions."));
- d.push(P("Enter a revision number (0-"+revisions+") to recover the pad text for that revision:"));
- d.push(FORM({action: request.path, method: "get"},
- P(LABEL("Revision number:"),
- INPUT({type: "hidden", name: "localPadId", value: localPadId}),
- INPUT({type: "text", name: "revNum", value: revNum || (revisions - 1)}),
- INPUT({type: "submit", value: "Submit"}))));
- }
- }
-
- if (showPadHelp) {
- d.push(P({style: "font-size: 1em; color: #555;"},
- 'The pad ID is the same as the URL to the pad, without the leading "/".',
- ' For example, if the pad lives at http://pad.spline.inf.fu-berlin.de/foobar,',
- ' then the pad ID is "foobar" (without the quotes).'))
- }
-
- if (revisions && revNum && (revNum < revisions)) {
- var padText = getPadText(localPadId, revNum);
- d.push(P(B("Pad text for ["+localPadId+"] revision #"+revNum)));
- d.push(DIV({style: "font-family: monospace; border: 1px solid #ccc; background: #ffe; padding: 1em;"}, padText));
- }
-
- renderAdminPage(function() { return d; });
-}
-
-
diff --git a/trunk/etherpad/src/etherpad/control/static_control.js b/trunk/etherpad/src/etherpad/control/static_control.js
deleted file mode 100644
index 5c087b6..0000000
--- a/trunk/etherpad/src/etherpad/control/static_control.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("faststatic");
-import("dispatch.{Dispatcher,PrefixMatcher,forward}");
-
-import("etherpad.utils.*");
-import("etherpad.globals.*");
-
-function onRequest() {
- var staticBase = '/static';
-
- var opts = {cache: isProduction()};
-
- var serveFavicon = faststatic.singleFileServer(staticBase + '/favicon.ico', opts);
- var serveCrossDomain = faststatic.singleFileServer(staticBase + '/crossdomain.xml', opts);
- var serveStaticDir = faststatic.directoryServer(staticBase, opts);
- var serveCompressed = faststatic.compressedFileServer(opts);
- var serveJs = faststatic.directoryServer(staticBase+'/js/', opts);
- var serveCss = faststatic.directoryServer(staticBase+'/css/', opts);
- var serveSwf = faststatic.directoryServer(staticBase+'/swf/', opts);
- var serveHtml = faststatic.directoryServer(staticBase+'/html/', opts);
- var serveZip = faststatic.directoryServer(staticBase+'/zip/', opts);
-
- var disp = new Dispatcher();
-
- disp.addLocations([
- ['/favicon.ico', serveFavicon],
- ['/robots.txt', serveRobotsTxt],
- ['/crossdomain.xml', serveCrossDomain],
- [PrefixMatcher('/static/html/'), serveHtml],
- [PrefixMatcher('/static/js/'), serveJs],
- [PrefixMatcher('/static/css/'), serveCss],
- [PrefixMatcher('/static/swf/'), serveSwf],
- [PrefixMatcher('/static/zip/'), serveZip],
- [PrefixMatcher('/static/compressed/'), serveCompressed],
- [PrefixMatcher('/static/'), serveStaticDir]
- ]);
-
- return disp.dispatch();
-}
-
-function serveRobotsTxt(name) {
- response.neverCache();
- response.setContentType('text/plain');
- response.write('User-agent: *\n');
- if (!isProduction()) {
- response.write('Disallow: /\n');
- }
- response.stop();
- return true;
-}
diff --git a/trunk/etherpad/src/etherpad/db_migrations/migration_runner.js b/trunk/etherpad/src/etherpad/db_migrations/migration_runner.js
deleted file mode 100644
index ddf201d..0000000
--- a/trunk/etherpad/src/etherpad/db_migrations/migration_runner.js
+++ /dev/null
@@ -1,147 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-// Database migrations.
-
-import("sqlbase.sqlcommon");
-import("sqlbase.sqlobj");
-
-import("etherpad.globals.*");
-import("etherpad.utils.*");
-import("etherpad.log");
-import("etherpad.pne.pne_utils");
-
-jimport("java.lang.System.out.println");
-
-//----------------------------------------------------------------
-// 1 migration per file
-//----------------------------------------------------------------
-
-var migrations = [
- "m0000_test",
- "m0001_eepnet_signups_init",
- "m0002_eepnet_signups_2",
- "m0003_create_tests_table_v2",
- "m0004_convert_all_tables_to_innodb",
- "m0005_create_billing_tables",
- "m0006_eepnet_signups_3",
- "m0007_create_pro_tables_v4",
- "m0008_persistent_vars",
- "m0009_pad_tables",
- "m0010_pad_sqlmeta",
- "m0011_pro_users_temppass",
- "m0012_pro_users_auto_signin",
- "m0013_pne_padv2_upgrade",
- "m0014_pne_globalpadids",
- "m0015_padmeta_passwords",
- "m0016_pne_tracking_data",
- "m0017_pne_tracking_data_v2",
- "m0018_eepnet_checkout_tables",
- "m0019_padmeta_deleted",
- "m0020_padmeta_archived",
- "m0021_pro_padmeta_json",
- "m0022_create_userids_table",
- "m0023_create_usagestats_table",
- "m0024_statistics_table",
- "m0025_rename_pro_users_table",
- "m0026_create_guests_table",
- "m0027_pro_config",
- "m0028_ondemand_beta_emails",
- "m0029_lowercase_subdomains",
- "m0030_fix_statistics_values",
- "m0031_deleted_pro_users",
- "m0032_reduce_topvalues_counts",
- "m0033_pro_account_usage",
- "m0034_create_recurring_billing_table",
- "m0035_add_email_to_paymentinfo",
- "m0036_create_missing_subscription_records",
- "m0037_create_pro_referral_table",
- "m0038_pad_coarse_revs"
-];
-
-var mscope = this;
-migrations.forEach(function(m) {
- import.call(mscope, "etherpad.db_migrations."+m);
-});
-
-//----------------------------------------------------------------
-
-function dmesg(m) {
- if ((!isProduction()) || appjet.cache.db_migrations_print_debug) {
- log.info(m);
- println(m);
- }
-}
-
-function onStartup() {
- appjet.cache.db_migrations_print_debug = true;
- if (!sqlcommon.doesTableExist("db_migrations")) {
- appjet.cache.db_migrations_print_debug = false;
- sqlobj.createTable('db_migrations', {
- id: 'INT NOT NULL '+sqlcommon.autoIncrementClause()+' PRIMARY KEY',
- name: 'VARCHAR(255) NOT NULL UNIQUE',
- completed: 'TIMESTAMP'
- });
- }
-
- if (pne_utils.isPNE()) { pne_utils.checkDbVersionUpgrade(); }
- runMigrations();
- if (pne_utils.isPNE()) { pne_utils.saveDbVersion(); }
-}
-
-function _migrationName(m) {
- m = m.replace(/^m\d+\_/, '');
- m = m.replace(/\_/g, '-');
- return m;
-}
-
-function getCompletedMigrations() {
- var completedMigrationsList = sqlobj.selectMulti('db_migrations', {}, {});
- var completedMigrations = {};
-
- completedMigrationsList.forEach(function(c) {
- completedMigrations[c.name] = true;
- });
-
- return completedMigrations;
-}
-
-function runMigrations() {
- var completedMigrations = getCompletedMigrations();
-
- dmesg("Checking for database migrations...");
- migrations.forEach(function(m) {
- var name = _migrationName(m);
- if (!completedMigrations[name]) {
- sqlcommon.inTransaction(function() {
- dmesg("performing database migration: ["+name+"]");
- var startTime = +(new Date);
-
- mscope[m].run();
-
- var elapsedMs = +(new Date) - startTime;
- dmesg("migration completed in "+elapsedMs+"ms");
-
- sqlobj.insert('db_migrations', {
- name: name,
- completed: new Date()
- });
- });
- }
- });
-}
-
-
diff --git a/trunk/etherpad/src/etherpad/globals.js b/trunk/etherpad/src/etherpad/globals.js
deleted file mode 100644
index 2bae776..0000000
--- a/trunk/etherpad/src/etherpad/globals.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-//----------------------------------------------------------------
-// global variabls
-//----------------------------------------------------------------
-
-var COMETPATH = "/comet";
-
-var COLOR_PALETTE = ['#ffc6c6','#ffe2bf','#fffcbf','#cbffb3','#b3fff1','#c6e7ff','#dcccff','#ffd9fb'];
-
-function isProduction() {
- return (appjet.config['etherpad.isProduction'] == "true");
-}
-
-var SUPERDOMAINS = {
- 'localhost': true,
- 'pad.spline.inf.fu-berlin.de': true,
- 'pad.spline.de': true,
- 'pad.spline.nomad': true
-};
-
-var PNE_RELEASE_VERSION = "1.1.3";
-var PNE_RELEASE_DATE = "June 15, 2009";
-
-var PRO_FREE_ACCOUNTS = 1e9;
-
-
diff --git a/trunk/etherpad/src/etherpad/helpers.js b/trunk/etherpad/src/etherpad/helpers.js
deleted file mode 100644
index cafa201..0000000
--- a/trunk/etherpad/src/etherpad/helpers.js
+++ /dev/null
@@ -1,276 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("fastJSON");
-import("jsutils.eachProperty");
-import("faststatic");
-import("comet");
-import("funhtml.META");
-
-import("etherpad.globals.*");
-import("etherpad.debug.dmesg");
-
-import("etherpad.pro.pro_utils");
-
-jimport("java.lang.System.out.println");
-
-//----------------------------------------------------------------
-// array that supports contains() in O(1)
-
-var _UniqueArray = function() {
- this._a = [];
- this._m = {};
-};
-_UniqueArray.prototype.add = function(x) {
- if (!this._m[x]) {
- this._a.push(x);
- this._m[x] = true;
- }
-};
-_UniqueArray.prototype.asArray = function() {
- return this._a;
-};
-
-//----------------------------------------------------------------
-// EJS template helpers
-//----------------------------------------------------------------
-
-function _hd() {
- if (!appjet.requestCache.helperData) {
- appjet.requestCache.helperData = {
- clientVars: {},
- htmlTitle: "",
- headExtra: "",
- bodyId: "",
- bodyClasses: new _UniqueArray(),
- cssIncludes: new _UniqueArray(),
- jsIncludes: new _UniqueArray(),
- includeCometJs: false,
- suppressGA: false,
- showHeader: true,
- robotsPolicy: null
- };
- }
- return appjet.requestCache.helperData;
-}
-
-function addBodyClass(c) {
- _hd().bodyClasses.add(c);
-}
-
-function addClientVars(vars) {
- eachProperty(vars, function(k,v) {
- _hd().clientVars[k] = v;
- });
-}
-
-function addToHead(stuff) {
- _hd().headExtra += stuff;
-}
-
-function setHtmlTitle(t) {
- _hd().htmlTitle = t;
-}
-
-function setBodyId(id) {
- _hd().bodyId = id;
-}
-
-function includeJs(relpath) {
- _hd().jsIncludes.add(relpath);
-}
-
-function includeJQuery() {
- includeJs("jquery-1.3.2.js");
-}
-
-function includeCss(relpath) {
- _hd().cssIncludes.add(relpath);
-}
-
-function includeCometJs() {
- _hd().includeCometJs = true;
-}
-
-function suppressGA() {
- _hd().suppressGA = true;
-}
-
-function hideHeader() {
- _hd().showHeader = false;
-}
-
-//----------------------------------------------------------------
-// for rendering HTML
-//----------------------------------------------------------------
-
-function bodyClasses() {
- return _hd().bodyClasses.asArray().join(' ');
-}
-
-function clientVarsScript() {
- var x = _hd().clientVars;
- x = fastJSON.stringify(x);
- if (x == '{}') {
- return '<!-- no client vars -->';
- }
- x = x.replace(/</g, '\\x3c');
- return [
- '<script type="text/javascript">',
- ' // <![CDATA[',
- 'var clientVars = '+x+';',
- ' // ]]>',
- '</script>'
- ].join('\n');
-}
-
-function htmlTitle() {
- return _hd().htmlTitle;
-}
-
-function bodyId() {
- return _hd().bodyId;
-}
-
-function baseHref() {
- return request.scheme + "://"+ request.host + "/";
-}
-
-function headExtra() {
- return _hd().headExtra;
-}
-
-function jsIncludes() {
- if (isProduction()) {
- var jsincludes = _hd().jsIncludes.asArray();
- if (_hd().includeCometJs) {
- jsincludes.splice(0, 0, {
- getPath: function() { return 'comet-client.js'; },
- getContents: function() { return comet.clientCode(); },
- getMTime: function() { return comet.clientMTime(); }
- });
- }
- if (jsincludes.length < 1) { return ''; }
- var key = faststatic.getCompressedFilesKey('js', '/static/js', jsincludes);
- return '<script type="text/javascript" src="/static/compressed/'+key+'"></script>';
- } else {
- var ts = +(new Date);
- var r = [];
- if (_hd().includeCometJs) {
- r.push('<script type="text/javascript" src="'+COMETPATH+'/js/client.js?'+ts+'"></script>');
- }
- _hd().jsIncludes.asArray().forEach(function(relpath) {
- r.push('<script type="text/javascript" src="/static/js/'+relpath+'?'+ts+'"></script>');
- });
- return r.join('\n');
- }
-}
-
-function cssIncludes() {
- if (isProduction()) {
- var key = faststatic.getCompressedFilesKey('css', '/static/css', _hd().cssIncludes.asArray());
- return '<link href="/static/compressed/'+key+'" rel="stylesheet" type="text/css" />';
- } else {
- var ts = +(new Date);
- var r = [];
- _hd().cssIncludes.asArray().forEach(function(relpath) {
- r.push('<link href="/static/css/'+relpath+'?'+ts+'" rel="stylesheet" type="text/css" />');
- });
- return r.join('\n');
- }
-}
-
-function oemail(username) {
- return '&lt;<a class="obfuscemail" href="mailto:'+username+'@p*d.sp***e.inf.fu-berlin.de">'+
- username+'@p*d.sp***e.inf.fu-berlin.de</a>&gt;';
-}
-
-function googleAnalytics() {
- // GA disabled always now.
- return '';
-
- if (!isProduction()) { return ''; }
- if (_hd().suppressGA) { return ''; }
- return [
- '<script type="text/javascript">',
- ' var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");',
- ' document.write(unescape("%3Cscript src=\'" + gaJsHost + "google-analytics.com/ga.js\' type=\'text/javascript\'%3E%3C/script%3E"));',
- '</script>',
- '<script type="text/javascript">',
- 'try {',
- ' var pageTracker = _gat._getTracker("UA-6236278-1");',
- ' pageTracker._trackPageview();',
- '} catch(err) {}</script>'
- ].join('\n');
-}
-
-function isHeaderVisible() {
- return _hd().showHeader;
-}
-
-function setRobotsPolicy(policy) {
- _hd().robotsPolicy = policy;
-}
-function robotsMeta() {
- if (!_hd().robotsPolicy) { return ''; }
- var content = "";
- content += (_hd().robotsPolicy.index ? 'INDEX' : 'NOINDEX');
- content += ", ";
- content += (_hd().robotsPolicy.follow ? 'FOLLOW' : 'NOFOLLOW');
- return META({name: "ROBOTS", content: content});
-}
-
-function thawteSiteSeal() {
- return [
- '<div>',
- '<table width="10" border="0" cellspacing="0" align="center">',
- '<tr>',
- '<td>',
- '<script src="https://siteseal.thawte.com/cgi/server/thawte_seal_generator.exe"></script>',
- '</td>',
- '</tr>',
- '<tr>',
- '<td height="0" align="center">',
- '<a style="color:#AD0034" target="_new"',
- 'href="http://www.thawte.com/digital-certificates/">',
- '<span style="font-family:arial; font-size:8px; color:#AD0034">',
- 'ABOUT SSL CERTIFICATES</span>',
- '</a>',
- '</td>',
- '</tr>',
- '</table>',
- '</div>'
- ].join('\n');
-}
-
-function clearFloats() {
- return '<div style="clear: both;"><!-- --></div>';
-}
-
-function rafterBlogUrl() {
- return '/ep/blog/posts/google-acquires-appjet';
-}
-
-function rafterNote() {
- return """<div style='border: 1px solid #ccc; background: #fee; padding: 1em; margin: 1em 0;'>
- <b>Note: </b>We are no longer accepting new accounts. <a href='"""+rafterBlogUrl()+"""'>Read more</a>.
- </div>""";
-}
-
-function rafterTerminationDate() {
- return "March 31, 2010";
-}
-
diff --git a/trunk/etherpad/src/etherpad/legacy_urls.js b/trunk/etherpad/src/etherpad/legacy_urls.js
deleted file mode 100644
index 80f6f77..0000000
--- a/trunk/etherpad/src/etherpad/legacy_urls.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-/* legacy URLs only apply to the public pad.spline.inf.fu-berlin.de site. (not Pro or PNE). */
-
-var _legacyURLs = {
- '/ep/beta-signup': '/',
- '/ep/talktostrangers': '/',
- '/ep/about/pricing-eepod': '/ep/about/pricing-pro',
- '/static/html/enterprise-etherpad-installguide.html': '/ep/pne-manual/',
- '/static/html/eepnet/eepnet-changelog.html': '/ep/pne-manual/changelog',
- '/static/html/eepnet/eepnet-installguide.html': '/ep/pne-manual/',
- '/ep/blog/posts/back-online-until-open-sourced': '/ep/blog/posts/etherpad-back-online-until-open-sourced'
-};
-
-function checkPath() {
- var p = request.path;
- var match = _legacyURLs[p];
-
- if (match) {
- response.redirect(match);
- }
-}
-
diff --git a/trunk/etherpad/src/etherpad/pad/model.js b/trunk/etherpad/src/etherpad/pad/model.js
deleted file mode 100644
index 9424f10..0000000
--- a/trunk/etherpad/src/etherpad/pad/model.js
+++ /dev/null
@@ -1,651 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("fastJSON");
-import("sqlbase.sqlbase");
-import("sqlbase.sqlcommon");
-import("sqlbase.sqlobj");
-import("timer");
-import("sync");
-
-import("etherpad.collab.ace.easysync2.{Changeset,AttribPool}");
-import("etherpad.log");
-import("etherpad.pad.padevents");
-import("etherpad.pad.padutils");
-import("etherpad.pad.dbwriter");
-import("etherpad.pad.pad_migrations");
-import("etherpad.pad.pad_security");
-import("etherpad.collab.collab_server");
-import("cache_utils.syncedWithCache");
-jimport("net.appjet.common.util.LimitedSizeMapping");
-
-jimport("java.lang.System.out.println");
-
-jimport("java.util.concurrent.ConcurrentHashMap");
-jimport("net.appjet.oui.GlobalSynchronizer");
-jimport("net.appjet.oui.exceptionlog");
-
-function onStartup() {
- appjet.cache.pads = {};
- appjet.cache.pads.meta = new ConcurrentHashMap();
- appjet.cache.pads.temp = new ConcurrentHashMap();
- appjet.cache.pads.revs = new ConcurrentHashMap();
- appjet.cache.pads.revs10 = new ConcurrentHashMap();
- appjet.cache.pads.revs100 = new ConcurrentHashMap();
- appjet.cache.pads.revs1000 = new ConcurrentHashMap();
- appjet.cache.pads.chat = new ConcurrentHashMap();
- appjet.cache.pads.revmeta = new ConcurrentHashMap();
- appjet.cache.pads.authors = new ConcurrentHashMap();
- appjet.cache.pads.apool = new ConcurrentHashMap();
-}
-
-var _JSON_CACHE_SIZE = 10000;
-
-// to clear: appjet.cache.padmodel.modelcache.map.clear()
-function _getModelCache() {
- return syncedWithCache('padmodel.modelcache', function(cache) {
- if (! cache.map) {
- cache.map = new LimitedSizeMapping(_JSON_CACHE_SIZE);
- }
- return cache.map;
- });
-}
-
-function cleanText(txt) {
- return txt.replace(/\r\n/g,'\n').replace(/\r/g,'\n').replace(/\t/g, ' ').replace(/\xa0/g, ' ');
-}
-
-/**
- * Access a pad object, which is passed as an argument to
- * the given padFunc, which is executed inside an exclusive lock,
- * and return the result. If the pad doesn't exist, a wrapper
- * object is still created and passed to padFunc, and it can
- * be used to check whether the pad exists and create it.
- *
- * Note: padId is a GLOBAL id.
- */
-function accessPadGlobal(padId, padFunc, rwMode) {
- // this may make a nested call to accessPadGlobal, so do it first
- pad_security.checkAccessControl(padId, rwMode);
-
- // pad is never loaded into memory (made "active") unless it has been migrated.
- // Migrations do not use accessPad, but instead access the database directly.
- pad_migrations.ensureMigrated(padId);
-
- var mode = (rwMode || "rw").toLowerCase();
-
- if (! appjet.requestCache.padsAccessing) {
- appjet.requestCache.padsAccessing = {};
- }
- if (appjet.requestCache.padsAccessing[padId]) {
- // nested access to same pad
- var p = appjet.requestCache.padsAccessing[padId];
- var m = p._meta;
- if (m && mode != "r") {
- m.status.lastAccess = +new Date();
- m.status.dirty = true;
- }
- return padFunc(p);
- }
-
- return doWithPadLock(padId, function() {
- return sqlcommon.inTransaction(function() {
- var meta = _getPadMetaData(padId); // null if pad doesn't exist yet
-
- if (meta && ! meta.status) {
- meta.status = { validated: false };
- }
-
- if (meta && mode != "r") {
- meta.status.lastAccess = +new Date();
- }
-
- function getCurrentAText() {
- var tempObj = pad.tempObj();
- if (! tempObj.atext) {
- tempObj.atext = pad.getInternalRevisionAText(meta.head);
- }
- return tempObj.atext;
- }
- function addRevision(theChangeset, author, optDatestamp) {
- var atext = getCurrentAText();
- var newAText = Changeset.applyToAText(theChangeset, atext, pad.pool());
- Changeset.copyAText(newAText, atext); // updates pad.tempObj().atext!
-
- var newRev = ++meta.head;
-
- var revs = _getPadStringArray(padId, "revs");
- revs.setEntry(newRev, theChangeset);
-
- var revmeta = _getPadStringArray(padId, "revmeta");
- var thisRevMeta = {t: (optDatestamp || (+new Date())),
- a: getNumForAuthor(author)};
- if ((newRev % meta.keyRevInterval) == 0) {
- thisRevMeta.atext = atext;
- }
- revmeta.setJSONEntry(newRev, thisRevMeta);
-
- updateCoarseChangesets(true);
- }
- function getNumForAuthor(author, dontAddIfAbsent) {
- return pad.pool().putAttrib(['author',author||''], dontAddIfAbsent);
- }
- function getAuthorForNum(n) {
- // must return null if n is an attrib number that isn't an author
- var pair = pad.pool().getAttrib(n);
- if (pair && pair[0] == 'author') {
- return pair[1];
- }
- return null;
- }
-
- function updateCoarseChangesets(onlyIfPresent) {
- // this is fast to run if the coarse changesets
- // are up-to-date or almost up-to-date;
- // if there's no coarse changeset data,
- // it may take a while.
-
- if (! meta.coarseHeads) {
- if (onlyIfPresent) {
- return;
- }
- else {
- meta.coarseHeads = {10:-1, 100:-1, 1000:-1};
- }
- }
- var head = meta.head;
- // once we reach head==9, coarseHeads[10] moves
- // from -1 up to 0; at head==19 it moves up to 1
- var desiredCoarseHeads = {
- 10: Math.floor((head-9)/10),
- 100: Math.floor((head-99)/100),
- 1000: Math.floor((head-999)/1000)
- };
- var revs = _getPadStringArray(padId, "revs");
- var revs10 = _getPadStringArray(padId, "revs10");
- var revs100 = _getPadStringArray(padId, "revs100");
- var revs1000 = _getPadStringArray(padId, "revs1000");
- var fineArrays = [revs, revs10, revs100];
- var coarseArrays = [revs10, revs100, revs1000];
- var levels = [10, 100, 1000];
- var dirty = false;
- for(var z=0;z<3;z++) {
- var level = levels[z];
- var coarseArray = coarseArrays[z];
- var fineArray = fineArrays[z];
- while (meta.coarseHeads[level] < desiredCoarseHeads[level]) {
- dirty = true;
- // for example, if the current coarse head is -1,
- // compose 0-9 inclusive of the finer level and call it 0
- var x = meta.coarseHeads[level] + 1;
- var cs = fineArray.getEntry(10 * x);
- for(var i=1;i<=9;i++) {
- cs = Changeset.compose(cs, fineArray.getEntry(10*x + i),
- pad.pool());
- }
- coarseArray.setEntry(x, cs);
- meta.coarseHeads[level] = x;
- }
- }
- if (dirty) {
- meta.status.dirty = true;
- }
- }
-
- /////////////////// "Public" API starts here (functions used by collab_server or other modules)
- var pad = {
- // Operations that write to the data structure should
- // set meta.dirty = true. Any pad access that isn't
- // done in "read" mode also sets dirty = true.
- getId: function() { return padId; },
- exists: function() { return !!meta; },
- create: function(optText) {
- meta = {};
- meta.head = -1; // incremented below by addRevision
- pad.tempObj().atext = Changeset.makeAText("\n");
- meta.padId = padId,
- meta.keyRevInterval = 100;
- meta.numChatMessages = 0;
- var t = +new Date();
- meta.status = { validated: true };
- meta.status.lastAccess = t;
- meta.status.dirty = true;
- meta.supportsTimeSlider = true;
-
- var firstChangeset = Changeset.makeSplice("\n", 0, 0,
- cleanText(optText || ''));
- addRevision(firstChangeset, '');
-
- _insertPadMetaData(padId, meta);
-
- sqlobj.insert("PAD_SQLMETA", {
- id: padId, version: 2, creationTime: new Date(t), lastWriteTime: new Date(),
- headRev: meta.head }); // headRev is not authoritative, just for info
-
- padevents.onNewPad(pad);
- },
- destroy: function() { // you may want to collab_server.bootAllUsers first
- padevents.onDestroyPad(pad);
-
- _destroyPadStringArray(padId, "revs");
- _destroyPadStringArray(padId, "revs10");
- _destroyPadStringArray(padId, "revs100");
- _destroyPadStringArray(padId, "revs1000");
- _destroyPadStringArray(padId, "revmeta");
- _destroyPadStringArray(padId, "chat");
- _destroyPadStringArray(padId, "authors");
- _removePadMetaData(padId);
- _removePadAPool(padId);
- sqlobj.deleteRows("PAD_SQLMETA", { id: padId });
- meta = null;
- },
- writeToDB: function() {
- var meta2 = {};
- for(var k in meta) meta2[k] = meta[k];
- delete meta2.status;
- sqlbase.putJSON("PAD_META", padId, meta2);
-
- _getPadStringArray(padId, "revs").writeToDB();
- _getPadStringArray(padId, "revs10").writeToDB();
- _getPadStringArray(padId, "revs100").writeToDB();
- _getPadStringArray(padId, "revs1000").writeToDB();
- _getPadStringArray(padId, "revmeta").writeToDB();
- _getPadStringArray(padId, "chat").writeToDB();
- _getPadStringArray(padId, "authors").writeToDB();
- sqlbase.putJSON("PAD_APOOL", padId, pad.pool().toJsonable());
-
- var props = { headRev: meta.head, lastWriteTime: new Date() };
- _writePadSqlMeta(padId, props);
- },
- pool: function() {
- return _getPadAPool(padId);
- },
- getHeadRevisionNumber: function() { return meta.head; },
- getRevisionAuthor: function(r) {
- var n = _getPadStringArray(padId, "revmeta").getJSONEntry(r).a;
- return getAuthorForNum(Number(n));
- },
- getRevisionChangeset: function(r) {
- return _getPadStringArray(padId, "revs").getEntry(r);
- },
- tempObj: function() { return _getPadTemp(padId); },
- getKeyRevisionNumber: function(r) {
- return Math.floor(r / meta.keyRevInterval) * meta.keyRevInterval;
- },
- getInternalRevisionAText: function(r) {
- var cacheKey = "atext/C/"+r+"/"+padId;
- var modelCache = _getModelCache();
- var cachedValue = modelCache.get(cacheKey);
- if (cachedValue) {
- modelCache.touch(cacheKey);
- //java.lang.System.out.println("HIT! "+cacheKey);
- return Changeset.cloneAText(cachedValue);
- }
- //java.lang.System.out.println("MISS! "+cacheKey);
-
- var revs = _getPadStringArray(padId, "revs");
- var keyRev = pad.getKeyRevisionNumber(r);
- var revmeta = _getPadStringArray(padId, "revmeta");
- var atext = revmeta.getJSONEntry(keyRev).atext;
- var curRev = keyRev;
- var targetRev = r;
- var apool = pad.pool();
- while (curRev < targetRev) {
- curRev++;
- var cs = pad.getRevisionChangeset(curRev);
- atext = Changeset.applyToAText(cs, atext, apool);
- }
- modelCache.put(cacheKey, Changeset.cloneAText(atext));
- return atext;
- },
- getInternalRevisionText: function(r, optInfoObj) {
- var atext = pad.getInternalRevisionAText(r);
- var text = atext.text;
- if (optInfoObj) {
- if (text.slice(-1) != "\n") {
- optInfoObj.badLastChar = text.slice(-1);
- }
- }
- return text;
- },
- getRevisionText: function(r, optInfoObj) {
- var internalText = pad.getInternalRevisionText(r, optInfoObj);
- return internalText.slice(0, -1);
- },
- atext: function() { return Changeset.cloneAText(getCurrentAText()); },
- text: function() { return pad.atext().text; },
- getRevisionDate: function(r) {
- var revmeta = _getPadStringArray(padId, "revmeta");
- return new Date(revmeta.getJSONEntry(r).t);
- },
- // note: calls like appendRevision will NOT notify clients of the change!
- // you must go through collab_server.
- // Also, be sure to run cleanText() on any text to strip out carriage returns
- // and other stuff.
- appendRevision: function(theChangeset, author, optDatestamp) {
- addRevision(theChangeset, author || '', optDatestamp);
- },
- appendChatMessage: function(obj) {
- var index = meta.numChatMessages;
- meta.numChatMessages++;
- var chat = _getPadStringArray(padId, "chat");
- chat.setJSONEntry(index, obj);
- },
- getNumChatMessages: function() {
- return meta.numChatMessages;
- },
- getChatMessage: function(i) {
- var chat = _getPadStringArray(padId, "chat");
- return chat.getJSONEntry(i);
- },
- getPadOptionsObj: function() {
- var data = pad.getDataRoot();
- if (! data.padOptions) {
- data.padOptions = {};
- }
- if ((! data.padOptions.guestPolicy) ||
- (data.padOptions.guestPolicy == 'ask')) {
- data.padOptions.guestPolicy = 'deny';
- }
- return data.padOptions;
- },
- getGuestPolicy: function() {
- // allow/ask/deny
- return pad.getPadOptionsObj().guestPolicy;
- },
- setGuestPolicy: function(policy) {
- pad.getPadOptionsObj().guestPolicy = policy;
- },
- getDataRoot: function() {
- var dataRoot = meta.dataRoot;
- if (! dataRoot) {
- dataRoot = {};
- meta.dataRoot = dataRoot;
- }
- return dataRoot;
- },
- // returns an object, changes to which are not reflected
- // in the DB; use setAuthorData for mutation
- getAuthorData: function(author) {
- var authors = _getPadStringArray(padId, "authors");
- var n = getNumForAuthor(author, true);
- if (n < 0) {
- return null;
- }
- else {
- return authors.getJSONEntry(n);
- }
- },
- setAuthorData: function(author, data) {
- var authors = _getPadStringArray(padId, "authors");
- var n = getNumForAuthor(author);
- authors.setJSONEntry(n, data);
- },
- adoptChangesetAttribs: function(cs, oldPool) {
- return Changeset.moveOpsToNewPool(cs, oldPool, pad.pool());
- },
- eachATextAuthor: function(atext, func) {
- var seenNums = {};
- Changeset.eachAttribNumber(atext.attribs, function(n) {
- if (! seenNums[n]) {
- seenNums[n] = true;
- var author = getAuthorForNum(n);
- if (author) {
- func(author, n);
- }
- }
- });
- },
- getCoarseChangeset: function(start, numChangesets) {
- updateCoarseChangesets();
-
- if (!(numChangesets == 10 || numChangesets == 100 ||
- numChangesets == 1000)) {
- return null;
- }
- var level = numChangesets;
- var x = Math.floor(start / level);
- if (!(x >= 0 && x*level == start)) {
- return null;
- }
-
- var cs = _getPadStringArray(padId, "revs"+level).getEntry(x);
-
- if (! cs) {
- return null;
- }
-
- return cs;
- },
- getSupportsTimeSlider: function() {
- if (! ('supportsTimeSlider' in meta)) {
- if (padutils.isProPadId(padId)) {
- return true;
- }
- else {
- return false;
- }
- }
- else {
- return !! meta.supportsTimeSlider;
- }
- },
- setSupportsTimeSlider: function(v) {
- meta.supportsTimeSlider = v;
- },
- get _meta() { return meta; }
- };
-
- try {
- padutils.setCurrentPad(padId);
- appjet.requestCache.padsAccessing[padId] = pad;
- return padFunc(pad);
- }
- finally {
- padutils.clearCurrentPad();
- delete appjet.requestCache.padsAccessing[padId];
- if (meta) {
- if (mode != "r") {
- meta.status.dirty = true;
- }
- if (meta.status.dirty) {
- dbwriter.notifyPadDirty(padId);
- }
- }
- }
- });
- });
-}
-
-/**
- * Call an arbitrary function with no arguments inside an exclusive
- * lock on a padId, and return the result.
- */
-function doWithPadLock(padId, func) {
- var lockName = "document/"+padId;
- return sync.doWithStringLock(lockName, func);
-}
-
-function isPadLockHeld(padId) {
- var lockName = "document/"+padId;
- return GlobalSynchronizer.isHeld(lockName);
-}
-
-/**
- * Get pad meta-data object, which is stored in SQL as JSON
- * but cached in appjet.cache. Returns null if pad doesn't
- * exist at all (does NOT create it). Requires pad lock.
- */
-function _getPadMetaData(padId) {
- var padMeta = appjet.cache.pads.meta.get(padId);
- if (! padMeta) {
- // not in cache
- padMeta = sqlbase.getJSON("PAD_META", padId);
- if (! padMeta) {
- // not in SQL
- padMeta = null;
- }
- else {
- appjet.cache.pads.meta.put(padId, padMeta);
- }
- }
- return padMeta;
-}
-
-/**
- * Sets a pad's meta-data object, such as when creating
- * a pad for the first time. Requires pad lock.
- */
-function _insertPadMetaData(padId, obj) {
- appjet.cache.pads.meta.put(padId, obj);
-}
-
-/**
- * Removes a pad's meta data, writing through to the database.
- * Used for the rare case of deleting a pad.
- */
-function _removePadMetaData(padId) {
- appjet.cache.pads.meta.remove(padId);
- sqlbase.deleteJSON("PAD_META", padId);
-}
-
-function _getPadAPool(padId) {
- var padAPool = appjet.cache.pads.apool.get(padId);
- if (! padAPool) {
- // not in cache
- padAPool = new AttribPool();
- padAPoolJson = sqlbase.getJSON("PAD_APOOL", padId);
- if (padAPoolJson) {
- // in SQL
- padAPool.fromJsonable(padAPoolJson);
- }
- appjet.cache.pads.apool.put(padId, padAPool);
- }
- return padAPool;
-}
-
-/**
- * Removes a pad's apool data, writing through to the database.
- * Used for the rare case of deleting a pad.
- */
-function _removePadAPool(padId) {
- appjet.cache.pads.apool.remove(padId);
- sqlbase.deleteJSON("PAD_APOOL", padId);
-}
-
-/**
- * Get an object for a pad that's not persisted in storage,
- * e.g. for tracking open connections. Creates object
- * if necessary. Requires pad lock.
- */
-function _getPadTemp(padId) {
- var padTemp = appjet.cache.pads.temp.get(padId);
- if (! padTemp) {
- padTemp = {};
- appjet.cache.pads.temp.put(padId, padTemp);
- }
- return padTemp;
-}
-
-/**
- * Returns an object with methods for manipulating a string array, where name
- * is something like "revs" or "chat". The object must be acquired and used
- * all within a pad lock.
- */
-function _getPadStringArray(padId, name) {
- var padFoo = appjet.cache.pads[name].get(padId);
- if (! padFoo) {
- padFoo = {};
- // writes go into writeCache, which is authoritative for reads;
- // reads cause pages to be read into readCache
- padFoo.readCache = {};
- padFoo.writeCache = {};
- appjet.cache.pads[name].put(padId, padFoo);
- }
- var tableName = "PAD_"+name.toUpperCase();
- var self = {
- getEntry: function(idx) {
- var n = Number(idx);
- if (padFoo.writeCache[n]) return padFoo.writeCache[n];
- if (padFoo.readCache[n]) return padFoo.readCache[n];
- sqlbase.getPageStringArrayElements(tableName, padId, n, padFoo.readCache);
- return padFoo.readCache[n]; // null if not present in SQL
- },
- setEntry: function(idx, value) {
- var n = Number(idx);
- var v = String(value);
- padFoo.writeCache[n] = v;
- },
- getJSONEntry: function(idx) {
- var result = self.getEntry(idx);
- if (! result) return result;
- return fastJSON.parse(String(result));
- },
- setJSONEntry: function(idx, valueObj) {
- self.setEntry(idx, fastJSON.stringify(valueObj));
- },
- writeToDB: function() {
- sqlbase.putDictStringArrayElements(tableName, padId, padFoo.writeCache);
- // copy key-vals of writeCache into readCache
- var readCache = padFoo.readCache;
- var writeCache = padFoo.writeCache;
- for(var p in writeCache) {
- readCache[p] = writeCache[p];
- }
- padFoo.writeCache = {};
- }
- };
- return self;
-}
-
-/**
- * Destroy a string array; writes through to the database. Must be
- * called within a pad lock.
- */
-function _destroyPadStringArray(padId, name) {
- appjet.cache.pads[name].remove(padId);
- var tableName = "PAD_"+name.toUpperCase();
- sqlbase.clearStringArray(tableName, padId);
-}
-
-/**
- * SELECT the row of PAD_SQLMETA for the given pad. Requires pad lock.
- */
-function _getPadSqlMeta(padId) {
- return sqlobj.selectSingle("PAD_SQLMETA", { id: padId });
-}
-
-function _writePadSqlMeta(padId, updates) {
- sqlobj.update("PAD_SQLMETA", { id: padId }, updates);
-}
-
-
-// called from dbwriter
-function removeFromMemory(pad) {
- // safe to call if all data is written to SQL, otherwise will lose data;
- var padId = pad.getId();
- appjet.cache.pads.meta.remove(padId);
- appjet.cache.pads.revs.remove(padId);
- appjet.cache.pads.revs10.remove(padId);
- appjet.cache.pads.revs100.remove(padId);
- appjet.cache.pads.revs1000.remove(padId);
- appjet.cache.pads.chat.remove(padId);
- appjet.cache.pads.revmeta.remove(padId);
- appjet.cache.pads.apool.remove(padId);
- collab_server.removeFromMemory(pad);
-}
-
-
diff --git a/trunk/etherpad/src/etherpad/pad/padutils.js b/trunk/etherpad/src/etherpad/pad/padutils.js
deleted file mode 100644
index 3ffe70c..0000000
--- a/trunk/etherpad/src/etherpad/pad/padutils.js
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("fastJSON");
-import("stringutils");
-
-import("etherpad.control.pro.account_control");
-
-import("etherpad.pro.pro_utils");
-import("etherpad.pro.domains");
-import("etherpad.pro.pro_accounts");
-import("etherpad.pro.pro_padmeta");
-import("etherpad.pad.model");
-import("etherpad.sessions.getSession");
-
-jimport("java.lang.System.out.println");
-
-
-function setCurrentPad(p) {
- appjet.context.attributes().update("currentPadId", p);
-}
-
-function clearCurrentPad() {
- appjet.context.attributes()['$minus$eq']("currentPadId");
-}
-
-function getCurrentPad() {
- var padOpt = appjet.context.attributes().get("currentPadId");
- if (padOpt.isEmpty()) return null;
- return padOpt.get();
-}
-
-function _parseCookie(text) {
- try {
- var cookieData = fastJSON.parse(unescape(text));
- return cookieData;
- }
- catch (e) {
- return null;
- }
-}
-
-function getPrefsCookieData() {
- var prefsCookie = request.cookies['prefs'];
- if (!prefsCookie) {
- return null;
- }
-
- return _parseCookie(prefsCookie);
-}
-
-function getPrefsCookieUserId() {
- var cookieData = getPrefsCookieData();
- if (! cookieData) {
- return null;
- }
- return cookieData.userId || null;
-}
-
-/**
- * Not valid to call this function outisde a HTTP request.
- */
-function accessPadLocal(localPadId, fn, rwMode) {
- if (!request.isDefined) {
- throw Error("accessPadLocal() cannot run outside an HTTP request.");
- }
- var globalPadId = getGlobalPadId(localPadId);
- var fnwrap = function(pad) {
- pad.getLocalId = function() {
- return getLocalPadId(pad);
- };
- return fn(pad);
- }
- return model.accessPadGlobal(globalPadId, fnwrap, rwMode);
-}
-
-/**
- * Not valid to call this function outisde a HTTP request.
- */
-function getGlobalPadId(localPadId) {
- if (!request.isDefined) {
- throw Error("getGlobalPadId() cannot run outside an HTTP request.");
- }
- if (pro_utils.isProDomainRequest()) {
- return makeGlobalId(domains.getRequestDomainId(), localPadId);
- } else {
- // pad.spline.inf.fu-berlin.de pads
- return localPadId;
- }
-}
-
-function makeGlobalId(domainId, localPadId) {
- return [domainId, localPadId].map(String).join('$');
-}
-
-function globalToLocalId(globalId) {
- var parts = globalId.split('$');
- if (parts.length == 1) {
- return parts[0];
- } else {
- return parts[1];
- }
-}
-
-function getLocalPadId(pad) {
- var globalId = pad.getId();
- return globalToLocalId(globalId);
-}
-
-function isProPadId(globalPadId) {
- return (globalPadId.indexOf("$") > 0);
-}
-
-function isProPad(pad) {
- return isProPadId(pad.getId());
-}
-
-function getDomainId(globalPadId) {
- var parts = globalPadId.split("$");
- if (parts.length < 2) {
- return null;
- } else {
- return Number(parts[0]);
- }
-}
-
-function makeValidLocalPadId(str) {
- return str.replace(/[^a-zA-Z0-9\-]/g, '-');
-}
-
-function getProDisplayTitle(localPadId, title) {
- if (title) {
- return title;
- }
- if (stringutils.isNumeric(localPadId)) {
- return ("Untitled "+localPadId);
- } else {
- return (localPadId);
- }
-}
-
diff --git a/trunk/etherpad/src/etherpad/pne/pne_utils.js b/trunk/etherpad/src/etherpad/pne/pne_utils.js
deleted file mode 100644
index 74e0598..0000000
--- a/trunk/etherpad/src/etherpad/pne/pne_utils.js
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("funhtml.*");
-import("stringutils.md5");
-import("sqlbase.persistent_vars");
-
-import("etherpad.licensing");
-
-jimport("java.lang.System.out.println");
-jimport("java.lang.System");
-
-
-function isPNE() {
- if (appjet.cache.fakePNE || appjet.config['etherpad.fakePNE']) {
- return true;
- }
- if (getVersionString()) {
- return true;
- }
- return false;
-}
-
-/**
- * Versioning scheme: we basically just use the apache scheme of MAJOR.MINOR.PATCH:
- *
- * Versions are denoted using a standard triplet of integers: MAJOR.MINOR.PATCH. The
- * basic intent is that MAJOR versions are incompatible, large-scale upgrades of the API.
- * MINOR versions retain source and binary compatibility with older minor versions, and
- * changes in the PATCH level are perfectly compatible, forwards and backwards.
- */
-
-function getVersionString() {
- return appjet.config['etherpad.pneVersion'];
-}
-
-function parseVersionString(x) {
- var parts = x.split('.');
- return {
- major: Number(parts[0] || 0),
- minor: Number(parts[1] || 0),
- patch: Number(parts[2] || 0)
- };
-}
-
-/* returns {major: int, minor: int, patch: int} */
-function getVersionNumbers() {
- return parseVersionString(getVersionString());
-}
-
-function checkDbVersionUpgrade() {
- var dbVersionString = persistent_vars.get("db_pne_version");
- var runningVersionString = getVersionString();
-
- if (!dbVersionString) {
- println("Upgrading to Private Network Edition, version: "+runningVersionString);
- return;
- }
-
- var dbVersion = parseVersionString(dbVersionString);
- var runningVersion = getVersionNumbers();
- var force = (appjet.config['etherpad.forceDbUpgrade'] == "true");
-
- if (!force && (runningVersion.major != dbVersion.major)) {
- println("Error: you are attempting to update an EtherPad["+dbVersionString+
- "] database to version ["+runningVersionString+"]. This is not possible.");
- println("Exiting...");
- System.exit(1);
- }
- if (!force && (runningVersion.minor < dbVersion.minor)) {
- println("Error: your etherpad database is at a newer version ["+dbVersionString+"] than"+
- " the current running etherpad ["+runningVersionString+"]. Please upgrade to the "+
- " latest version.");
- println("Exiting...");
- System.exit(1);
- }
- if (!force && (runningVersion.minor > (dbVersion.minor + 1))) {
- println("\n\nWARNING: you are attempting to upgrade from version "+dbVersionString+" to version "+
- runningVersionString+". It is recommended that you upgrade one minor version at a time."+
- " (The \"minor\" version number is the second number separated by dots. For example,"+
- " if you are running version 1.2, it is recommended that you upgrade to 1.3 and then 1.4 "+
- " instead of going directly from 1.2 to 1.4.");
- println("\n\nIf you really want to do this, you can force us to attempt the upgrade with "+
- " the --etherpad.forceDbUpgrade=true flag.");
- println("\n\nExiting...");
- System.exit(1);
- }
- if (runningVersion.minor > dbVersion.minor) {
- println("Upgrading database to version "+runningVersionString);
- }
-}
-
-function saveDbVersion() {
- var dbVersionString = persistent_vars.get("db_pne_version");
- if (getVersionString() != dbVersionString) {
- persistent_vars.put('db_pne_version', getVersionString());
- println("Upgraded Private Network Edition version to ["+getVersionString()+"]");
- }
-}
-
-// These are a list of some of the config vars documented in the PNE manual. They are here
-// temporarily, until we move them to the PNE config UI.
-
-var _eepneAllowedConfigVars = [
- 'configFile',
- 'etherpad.useMySQL',
- 'etherpad.SQL_JDBC_DRIVER',
- 'etherpad.SQL_JDBC_URL',
- 'etherpad.SQL_PASSWORD',
- 'etherpad.SQL_USERNAME',
- 'etherpad.adminPass',
- 'etherpad.licenseKey',
- 'listen',
- 'listenSecure',
- 'smtpPass',
- 'smtpServer',
- 'smtpUser',
- 'sslKeyPassword',
- 'sslKeyStore'
-];
-
-function isServerLicensed() {
- var licenseInfo = licensing.getLicense();
- if (!licenseInfo) {
- return false;
- }
- if (licensing.isVersionTooOld()) {
- return false;
- }
- if (licensing.isExpired()) {
- return false;
- }
- return true;
-}
-
-function enableTrackingAgain() {
- delete appjet.cache.noMorePneTracking;
-}
-
-function pneTrackerHtml() {
- if (!isPNE()) {
- return "";
- }
- if (appjet.cache.noMorePneTracking) {
- return "";
- }
-
- var div = DIV({style: "height: 1px; width: 1px; overflow: hidden;"});
-
- var licenseInfo = licensing.getLicense();
- var key = null;
- if (licenseInfo) {
- key = md5(licenseInfo.key).substr(0, 16);
- }
-
- function trackData(name, value) {
- var imgurl = "http://pad.spline.inf.fu-berlin.de/ep/tpne/t?";
- if (key) {
- imgurl += ("k="+key+"&");
- }
- imgurl += (encodeURIComponent(name) + "=" + encodeURIComponent(value));
- div.push(IMG({src: imgurl}));
- }
-
- trackData("ping", "1");
- trackData("dbdriver", appjet.config['etherpad.SQL_JDBC_DRIVER']);
- trackData("request.url", request.url);
-
- appjet.cache.noMorePneTracking = true;
- return div;
-}
-
-
-
diff --git a/trunk/etherpad/src/etherpad/pro/pro_accounts.js b/trunk/etherpad/src/etherpad/pro/pro_accounts.js
deleted file mode 100644
index 2024970..0000000
--- a/trunk/etherpad/src/etherpad/pro/pro_accounts.js
+++ /dev/null
@@ -1,496 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-// library for pro accounts
-
-import("funhtml.*");
-import("sqlbase.sqlobj");
-import("sqlbase.sqlcommon.inTransaction");
-import("email.sendEmail");
-import("cache_utils.syncedWithCache");
-import("stringutils.*");
-
-import("etherpad.globals.*");
-import("etherpad.sessions");
-import("etherpad.sessions.getSession");
-import("etherpad.utils.*");
-import("etherpad.pro.domains");
-import("etherpad.control.pro.account_control");
-import("etherpad.pro.pro_utils");
-import("etherpad.pro.pro_quotas");
-import("etherpad.pad.padusers");
-import("etherpad.log");
-import("etherpad.billing.team_billing");
-
-jimport("org.mindrot.BCrypt");
-jimport("java.lang.System.out.println");
-
-function _dmesg(m) {
- if (!isProduction()) {
- println(m);
- }
-}
-
-function _computePasswordHash(p) {
- var pwh;
- pwh = BCrypt.hashpw(p, BCrypt.gensalt(10));
- return pwh;
-}
-
-function _withCache(name, fn) {
- return syncedWithCache('pro_accounts.'+name, fn);
-}
-
-//----------------------------------------------------------------
-// validation
-//----------------------------------------------------------------
-
-function validateEmail(email) {
- if (!email) { return "Email is required."; }
- if (!isValidEmail(email)) { return "\""+email+"\" does not look like a valid email address."; }
- return null;
-}
-
-function validateFullName(name) {
- if (!name) { return "Full name is required."; }
- if (name.length < 2) { return "Full name must be at least 2 characters."; }
- return null;
-}
-
-function validatePassword(p) {
- if (!p) { return "Password is required."; }
- if (p.length < 6) { return "Passwords must be at least 6 characters."; }
- return null;
-}
-
-function validateEmailDomainPair(email, domainId) {
- // TODO: make sure the same email address cannot exist more than once within
- // the same domainid.
-}
-
-/* if domainId is null, then use domainId of current request. */
-function createNewAccount(domainId, fullName, email, password, isAdmin) {
- if (!domainId) {
- domainId = domains.getRequestDomainId();
- }
- email = trim(email);
- isAdmin = !!isAdmin; // convert to bool
-
- // validation
- var e;
- e = validateEmail(email); if (e) { throw Error(e); }
- e = validateFullName(fullName); if (e) { throw Error(e); }
- e = validatePassword(password); if (e) { throw Error(e); }
-
- // xss normalization
- fullName = toHTML(fullName);
-
- // make sure account does not already exist on this domain.
- var ret = inTransaction(function() {
- var existingAccount = getAccountByEmail(email, domainId);
- if (existingAccount) {
- throw Error("There is already an account with that email address.");
- }
- // No existing account. Proceed.
- var now = new Date();
- var account = {
- domainId: domainId,
- fullName: fullName,
- email: email,
- passwordHash: _computePasswordHash(password),
- createdDate: now,
- isAdmin: isAdmin
- };
- return sqlobj.insert('pro_accounts', account);
- });
-
- _withCache('does-domain-admin-exist', function(cache) {
- delete cache[domainId];
- });
-
- pro_quotas.updateAccountUsageCount(domainId);
- updateCachedActiveCount(domainId);
-
- if (ret) {
- log.custom('pro-accounts',
- {type: "account-created",
- accountId: ret,
- domainId: domainId,
- name: fullName,
- email: email,
- admin: isAdmin});
- }
-
- return ret;
-}
-
-function _checkAccess(account) {
- if (sessions.isAnEtherpadAdmin()) {
- return;
- }
- if (account.domainId != domains.getRequestDomainId()) {
- throw Error("access denied");
- }
-}
-
-function setPassword(account, newPass) {
- _checkAccess(account);
- var passHash = _computePasswordHash(newPass);
- sqlobj.update('pro_accounts', {id: account.id}, {passwordHash: passHash});
- markDirtySessionAccount(account.id);
-}
-
-function setTempPassword(account, tempPass) {
- _checkAccess(account);
- var tempPassHash = _computePasswordHash(tempPass);
- sqlobj.update('pro_accounts', {id: account.id}, {tempPassHash: tempPassHash});
- markDirtySessionAccount(account.id);
-}
-
-function setEmail(account, newEmail) {
- _checkAccess(account);
- sqlobj.update('pro_accounts', {id: account.id}, {email: newEmail});
- markDirtySessionAccount(account.id);
-}
-
-function setFullName(account, newName) {
- _checkAccess(account);
- sqlobj.update('pro_accounts', {id: account.id}, {fullName: newName});
- markDirtySessionAccount(account.id);
-}
-
-function setIsAdmin(account, newVal) {
- _checkAccess(account);
- sqlobj.update('pro_accounts', {id: account.id}, {isAdmin: newVal});
- markDirtySessionAccount(account.id);
-}
-
-function setDeleted(account) {
- _checkAccess(account);
- if (!isNumeric(account.id)) {
- throw new Error("Invalid account id: "+account.id);
- }
- sqlobj.update('pro_accounts', {id: account.id}, {isDeleted: true});
- markDirtySessionAccount(account.id);
- pro_quotas.updateAccountUsageCount(account.domainId);
- updateCachedActiveCount(account.domainId);
-
- log.custom('pro-accounts',
- {type: "account-deleted",
- accountId: account.id,
- domainId: account.domainId,
- name: account.fullName,
- email: account.email,
- admin: account.isAdmin,
- createdDate: account.createdDate.getTime()});
-}
-
-//----------------------------------------------------------------
-
-function doesAdminExist() {
- var domainId = domains.getRequestDomainId();
- return _withCache('does-domain-admin-exist', function(cache) {
- if (cache[domainId] === undefined) {
- _dmesg("cache miss for doesAdminExist (domainId="+domainId+")");
- var admins = sqlobj.selectMulti('pro_accounts', {domainId: domainId, isAdmin: true}, {});
- cache[domainId] = (admins.length > 0);
- }
- return cache[domainId]
- });
-}
-
-function getSessionProAccount() {
- if (sessions.isAnEtherpadAdmin()) {
- return getEtherpadAdminAccount();
- }
- var account = getSession().proAccount;
- if (!account) {
- return null;
- }
- if (account.isDeleted) {
- delete getSession().proAccount;
- return null;
- }
- return account;
-}
-
-function isAccountSignedIn() {
- if (getSessionProAccount()) {
- return true;
- } else {
- return false;
- }
-}
-
-function isAdminSignedIn() {
- return isAccountSignedIn() && getSessionProAccount().isAdmin;
-}
-
-function requireAccount(message) {
- if ((request.path == "/ep/account/sign-in") ||
- (request.path == "/ep/account/sign-out") ||
- (request.path == "/ep/account/guest-sign-in") ||
- (request.path == "/ep/account/guest-knock") ||
- (request.path == "/ep/account/forgot-password")) {
- return;
- }
-
- function checkSessionAccount() {
- if (!getSessionProAccount()) {
- if (message) {
- account_control.setSigninNotice(message);
- }
- response.redirect('/ep/account/sign-in?cont='+encodeURIComponent(request.url));
- }
- }
-
- checkSessionAccount();
-
- if (getSessionProAccount().domainId != domains.getRequestDomainId()) {
- // This should theoretically never happen unless the account is spoofing cookies / trying to
- // hack the site.
- pro_utils.renderFramedMessage("Permission denied.");
- response.stop();
- }
- // update dirty session account if necessary
- _withCache('dirty-session-accounts', function(cache) {
- var uid = getSessionProAccount().id;
- if (cache[uid]) {
- reloadSessionAccountData(uid);
- cache[uid] = false;
- }
- });
-
- // need to check again in case dirty update caused account to be marked
- // deleted.
- checkSessionAccount();
-}
-
-function requireAdminAccount() {
- requireAccount();
- if (!getSessionProAccount().isAdmin) {
- pro_utils.renderFramedMessage("Permission denied.");
- response.stop();
- }
-}
-
-/* returns undefined on success, error string otherise. */
-function authenticateSignIn(email, password) {
- var accountRecord = getAccountByEmail(email, null);
- if (!accountRecord) {
- return "Account not found: "+email;
- }
-
- if (BCrypt.checkpw(password, accountRecord.passwordHash) != true) {
- return "Incorrect password. Please try again.";
- }
-
- signInSession(accountRecord);
-
- return undefined; // success
-}
-
-function signOut() {
- delete getSession().proAccount;
-}
-
-function authenticateTempSignIn(uid, tempPass) {
- var emsg = "That password reset link that is no longer valid.";
-
- var account = getAccountById(uid);
- if (!account) {
- return emsg+" (Account not found.)";
- }
- if (account.domainId != domains.getRequestDomainId()) {
- return emsg+" (Wrong domain.)";
- }
- if (!account.tempPassHash) {
- return emsg+" (Expired.)";
- }
- if (BCrypt.checkpw(tempPass, account.tempPassHash) != true) {
- return emsg+" (Bad temp pass.)";
- }
-
- signInSession(account);
-
- getSession().accountMessage = "Please choose a new password";
- getSession().changePass = true;
-
- response.redirect("/ep/account/");
-}
-
-function signInSession(account) {
- account.lastLoginDate = new Date();
- account.tempPassHash = null;
- sqlobj.updateSingle('pro_accounts', {id: account.id}, account);
- reloadSessionAccountData(account.id);
- padusers.notifySignIn();
-}
-
-function listAllDomainAccounts(domainId) {
- if (domainId === undefined) {
- domainId = domains.getRequestDomainId();
- }
- var records = sqlobj.selectMulti('pro_accounts',
- {domainId: domainId, isDeleted: false}, {});
- return records;
-}
-
-function listAllDomainAdmins(domainId) {
- if (domainId === undefined) {
- domainId = domains.getRequestDomainId();
- }
- var records = sqlobj.selectMulti('pro_accounts',
- {domainId: domainId, isDeleted: false, isAdmin: true},
- {});
- return records;
-}
-
-function getActiveCount(domainId) {
- var records = sqlobj.selectMulti('pro_accounts',
- {domainId: domainId, isDeleted: false}, {});
- return records.length;
-}
-
-/* getAccountById works for deleted and non-deleted accounts.
- * The assumption is that cases whewre you look up an account by ID, you
- * want the account info even if the account has been deleted. For
- * example, when asking who created a pad.
- */
-function getAccountById(accountId) {
- var r = sqlobj.selectSingle('pro_accounts', {id: accountId});
- if (r) {
- return r;
- } else {
- return undefined;
- }
-}
-
-/* getting an account by email only returns the account if it is
- * not deleted. The assumption is that when you look up an account by
- * email address, you only want active accounts. Furthermore, some
- * deleted accounts may match a given email, but only one non-deleted
- * account should ever match a single (email,domainId) pair.
- */
-function getAccountByEmail(email, domainId) {
- if (!domainId) {
- domainId = domains.getRequestDomainId();
- }
- var r = sqlobj.selectSingle('pro_accounts', {domainId: domainId, email: email, isDeleted: false});
- if (r) {
- return r;
- } else {
- return undefined;
- }
-}
-
-function getFullNameById(id) {
- if (!id) {
- return null;
- }
-
- return _withCache('names-by-id', function(cache) {
- if (cache[id] === undefined) {
- _dmesg("cache miss for getFullNameById (accountId="+id+")");
- var r = getAccountById(id);
- if (r) {
- cache[id] = r.fullName;
- } else {
- cache[id] = false;
- }
- }
- if (cache[id]) {
- return cache[id];
- } else {
- return null;
- }
- });
-}
-
-function getTempSigninUrl(account, tempPass) {
- return [
- 'https://', httpsHost(pro_utils.getFullProHost()), '/ep/account/sign-in?',
- 'uid=', account.id, '&tp=', tempPass
- ].join('');
-}
-
-
-// TODO: this session account object storage / dirty cache is a
-// ridiculous hack. What we should really do is have a caching/access
-// layer for accounts similar to accessPad() and accessProPadMeta(), and
-// have that abstraction take care of caching and marking accounts as
-// dirty. This can be incorporated into getSessionProAccount(), and we
-// should actually refactor that into accessSessionProAccount().
-
-/* will force session data for this account to be updated next time that
- * account requests a page. */
-function markDirtySessionAccount(uid) {
- var domainId = domains.getRequestDomainId();
-
- _withCache('dirty-session-accounts', function(cache) {
- cache[uid] = true;
- });
- _withCache('names-by-id', function(cache) {
- delete cache[uid];
- });
- _withCache('does-domain-admin-exist', function(cache) {
- delete cache[domainId];
- });
-}
-
-function reloadSessionAccountData(uid) {
- if (!uid) {
- uid = getSessionProAccount().id;
- }
- getSession().proAccount = getAccountById(uid);
-}
-
-function getAllAccountsWithEmail(email) {
- var accountRecords = sqlobj.selectMulti('pro_accounts', {email: email, isDeleted: false}, {});
- return accountRecords;
-}
-
-function getEtherpadAdminAccount() {
- return {
- id: 0,
- isAdmin: true,
- fullName: "ETHERPAD ADMIN",
- email: "support@pad.spline.inf.fu-berlin.de",
- domainId: domains.getRequestDomainId(),
- isDeleted: false
- };
-}
-
-function getCachedActiveCount(domainId) {
- return _withCache('user-counts.'+domainId, function(c) {
- if (!c.count) {
- c.count = getActiveCount(domainId);
- }
- return c.count;
- });
-}
-
-function updateCachedActiveCount(domainId) {
- _withCache('user-counts.'+domainId, function(c) {
- c.count = getActiveCount(domainId);
- });
-}
-
-
-
-
-
-
diff --git a/trunk/etherpad/src/etherpad/pro/pro_utils.js b/trunk/etherpad/src/etherpad/pro/pro_utils.js
deleted file mode 100644
index 1dc2468..0000000
--- a/trunk/etherpad/src/etherpad/pro/pro_utils.js
+++ /dev/null
@@ -1,165 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("funhtml.*");
-import("stringutils.startsWith");
-
-import("etherpad.utils.*");
-import("etherpad.globals.*");
-import("etherpad.log");
-import("etherpad.pne.pne_utils");
-import("etherpad.pro.pro_accounts");
-import("etherpad.pro.pro_accounts.getSessionProAccount");
-import("etherpad.pro.domains");
-import("etherpad.pro.pro_quotas");
-import("etherpad.sessions");
-import("etherpad.sessions.getSession");
-
-import("etherpad.control.pro.pro_main_control");
-
-jimport("java.lang.System.out.println");
-
-function _stripComet(x) {
- if (x.indexOf('.comet.') > 0) {
- x = x.split('.comet.')[1];
- }
- return x;
-}
-
-function getProRequestSubdomain() {
- var d = _stripComet(request.domain);
- return d.split('.')[0];
-}
-
-function getRequestSuperdomain() {
- var parts = request.domain.split('.');
- while (parts.length > 0) {
- var domain = parts.join('.');
- if (SUPERDOMAINS[domain]) {
- return domain;
- }
- parts.shift(); // Remove next level
- }
-}
-
-function isProDomainRequest() {
- // the result of this function never changes within the same request.
- var c = appjet.requestCache;
- if (c.isProDomainRequest === undefined) {
- c.isProDomainRequest = _computeIsProDomainRequest();
- }
- return c.isProDomainRequest;
-}
-
-function _computeIsProDomainRequest() {
- if (pne_utils.isPNE()) {
- return true;
- }
-
- var domain = _stripComet(request.domain);
-
- if (SUPERDOMAINS[domain]) {
- return false;
- }
-
- var requestSuperdomain = getRequestSuperdomain();
-
- if (SUPERDOMAINS[requestSuperdomain]) {
- // now see if this subdomain is actually in our database.
- if (domains.getRequestDomainRecord()) {
- return true;
- } else {
- return false;
- }
- }
-
- return false;
-}
-
-function preDispatchAccountCheck() {
- // if account is not logged in, redirect to /ep/account/login
- //
- // if it's PNE and there is no admin account, allow them to create an admin
- // account.
-
- if (pro_main_control.isActivationAllowed()) {
- return;
- }
-
- if (!pro_accounts.doesAdminExist()) {
- if (request.path != '/ep/account/create-admin-account') {
- // should only happen for eepnet installs
- response.redirect('/ep/account/create-admin-account');
- }
- } else {
- pro_accounts.requireAccount();
- }
-
- pro_quotas.perRequestBillingCheck();
-}
-
-function renderFramedMessage(m) {
- renderFramedHtml(
- DIV(
- {style: "font-size: 2em; padding: 2em; margin: 4em; border: 1px solid #ccc; background: #e6e6e6;"},
- m));
-}
-
-function getFullProDomain() {
- // TODO: have a special config param for this? --etherpad.canonicalDomain
- return request.domain;
-}
-
-// domain, including port if necessary
-function getFullProHost() {
- var h = getFullProDomain();
- var parts = request.host.split(':');
- if (parts.length > 1) {
- h += (':' + parts[1]);
- }
- return h;
-}
-
-function getFullSuperdomainHost() {
- if (isProDomainRequest()) {
- var h = getRequestSuperdomain()
- var parts = request.host.split(':');
- if (parts.length > 1) {
- h += (':' + parts[1]);
- }
- return h;
- } else {
- return request.host;
- }
-}
-
-function getEmailFromAddr() {
- var fromDomain = 'pad.spline.inf.fu-berlin.de';
- if (pne_utils.isPNE()) {
- fromDomain = getFullProDomain();
- }
- return ('"EtherPad" <noreply@'+fromDomain+'>');
-}
-
-function renderGlobalProNotice() {
- if (request.cache.globalProNotice) {
- return DIV({className: 'global-pro-notice'},
- request.cache.globalProNotice);
- } else {
- return "";
- }
-}
-
diff --git a/trunk/etherpad/src/etherpad/sessions.js b/trunk/etherpad/src/etherpad/sessions.js
deleted file mode 100644
index c218da8..0000000
--- a/trunk/etherpad/src/etherpad/sessions.js
+++ /dev/null
@@ -1,203 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("sessions");
-import("stringutils.randomHash");
-import("funhtml.*");
-
-import("etherpad.log");
-import("etherpad.globals.*");
-import("etherpad.pro.pro_utils");
-import("etherpad.utils.*");
-import("cache_utils.syncedWithCache");
-
-jimport("java.lang.System.out.println");
-
-var _TRACKING_COOKIE_NAME = "ET";
-var _SESSION_COOKIE_NAME = "ES";
-
-function _updateInitialReferrer(data) {
-
- if (data.initialReferer) {
- return;
- }
-
- var ref = request.headers["Referer"];
-
- if (!ref) {
- return;
- }
- if (ref.indexOf('http://'+request.host) == 0) {
- return;
- }
- if (ref.indexOf('https://'+request.host) == 0) {
- return;
- }
-
- data.initialReferer = ref;
- log.custom("referers", {referer: ref});
-}
-
-function _getScopedDomain(subDomain) {
- var d = request.domain;
- if (d.indexOf(".") == -1) {
- // special case for "localhost". For some reason, firefox does not like cookie domains
- // to be ".localhost".
- return undefined;
- }
- if (subDomain) {
- d = subDomain + "." + d;
- }
- return "." + d;
-}
-//--------------------------------------------------------------------------------
-
-// pass in subDomain to get the session data for a particular subdomain --
-// intended for debugging.
-function getSession(subDomain) {
- var sessionData = sessions.getSession({
- cookieName: _SESSION_COOKIE_NAME,
- domain: _getScopedDomain(subDomain)
- });
- _updateInitialReferrer(sessionData);
- return sessionData;
-}
-
-function getSessionId() {
- return sessions.getSessionId(_SESSION_COOKIE_NAME, false, _getScopedDomain());
-}
-
-function _getGlobalSessionId() {
- return (request.isDefined && request.cookies[_SESSION_COOKIE_NAME]) || null;
-}
-
-function isAnEtherpadAdmin() {
- var sessionId = _getGlobalSessionId();
- if (! sessionId) {
- return false;
- }
-
- return syncedWithCache("isAnEtherpadAdmin", function(c) {
- return !! c[sessionId];
- });
-}
-
-function setIsAnEtherpadAdmin(v) {
- var sessionId = _getGlobalSessionId();
- if (! sessionId) {
- return;
- }
-
- syncedWithCache("isAnEtherpadAdmin", function(c) {
- if (v) {
- c[sessionId] = true;
- }
- else {
- delete c[sessionId];
- }
- });
-}
-
-//--------------------------------------------------------------------------------
-
-function setTrackingCookie() {
- if (request.cookies[_TRACKING_COOKIE_NAME]) {
- return;
- }
-
- var trackingVal = randomHash(16);
- var expires = new Date(32503708800000); // year 3000
-
- response.setCookie({
- name: _TRACKING_COOKIE_NAME,
- value: trackingVal,
- path: "/",
- domain: _getScopedDomain(),
- expires: expires
- });
-}
-
-function getTrackingId() {
- // returns '-' if no tracking ID (caller can assume)
- return (request.cookies[_TRACKING_COOKIE_NAME] || response.getCookie(_TRACKING_COOKIE_NAME) || '-');
-}
-
-//--------------------------------------------------------------------------------
-
-function preRequestCookieCheck() {
- if (isStaticRequest()) {
- return;
- }
-
- // If this function completes without redirecting, then it means
- // there is a valid session cookie and tracking cookie.
-
- if (request.cookies[_SESSION_COOKIE_NAME] &&
- request.cookies[_TRACKING_COOKIE_NAME]) {
-
- if (request.params.cookieShouldBeSet) {
- response.redirect(qpath({cookieShouldBeSet: null}));
- }
- return;
- }
-
- // Only superdomains can set cookies.
- var isSuperdomain = SUPERDOMAINS[request.domain];
-
- if (isSuperdomain) {
- // superdomain without cookies
-
- getSession();
- setTrackingCookie();
-
- // check if we need to redirect back to a subdomain.
- if ((request.path == "/") &&
- (request.params.setCookie) &&
- (request.params.contUrl)) {
-
- var contUrl = request.params.contUrl;
- if (contUrl.indexOf("?") == -1) {
- contUrl += "?";
- }
- contUrl += "&cookieShouldBeSet=1";
- response.redirect(contUrl);
- }
- } else {
- var parts = request.domain.split(".");
- if (parts.length < 3) {
- // invalid superdomain
- response.write("invalid superdomain");
- response.stop();
- }
- // subdomain without cookies
- if (request.params.cookieShouldBeSet) {
- log.warn("Cookie failure!");
- renderFramedHtml(DIV({style: "border: 1px solid #ccc; padding: 1em; width: 600px; margin: 1em auto; font-size: 1.4em;"},
- P("Please enable cookies in your browser in order to access this site."),
- BR(),
- P(A({href: "/"}, "Continue"))));
- response.stop();
- } else {
- var contUrl = request.url;
- var p = request.host.split(':')[1];
- p = (p ? (":"+p) : "");
- response.redirect(request.scheme+"://"+pro_utils.getRequestSuperdomain()+p+
- "/?setCookie=1&contUrl="+encodeURIComponent(contUrl));
- }
- }
-}
-
-
diff --git a/trunk/etherpad/src/etherpad/utils.js b/trunk/etherpad/src/etherpad/utils.js
deleted file mode 100644
index da9972f..0000000
--- a/trunk/etherpad/src/etherpad/utils.js
+++ /dev/null
@@ -1,396 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("exceptionutils");
-import("fileutils.{readFile,fileLastModified}");
-import("ejs.EJS");
-import("funhtml.*");
-import("stringutils");
-import("stringutils.startsWith");
-import("jsutils.*");
-
-import("etherpad.sessions");
-import("etherpad.sessions.getSession");
-import("etherpad.globals.*");
-import("etherpad.helpers");
-import("etherpad.collab.collab_server");
-import("etherpad.pad.model");
-import("etherpad.pro.domains");
-import("etherpad.pne.pne_utils");
-import("etherpad.pro.pro_utils");
-import("etherpad.pro.pro_config");
-import("etherpad.pro.pro_accounts");
-import("etherpad.pro.pro_accounts.getSessionProAccount");
-
-jimport("java.lang.System.out.print");
-jimport("java.lang.System.out.println");
-
-//----------------------------------------------------------------
-// utilities
-//----------------------------------------------------------------
-
-// returns globally-unique padId
-function randomUniquePadId() {
- var id = stringutils.randomString(10);
- while (model.accessPadGlobal(id, function(p) { return p.exists(); }, "r")) {
- id = stringutils.randomString(10);
- }
- return id;
-}
-
-//----------------------------------------------------------------
-// template rendering
-//----------------------------------------------------------------
-
-function renderTemplateAsString(filename, data) {
- data = data || {};
- data.helpers = helpers; // global helpers
-
- var f = "/templates/"+filename;
- if (! appjet.scopeCache.ejs) {
- appjet.scopeCache.ejs = {};
- }
- var cacheObj = appjet.scopeCache.ejs[filename];
- if (cacheObj === undefined || fileLastModified(f) > cacheObj.mtime) {
- var templateText = readFile(f);
- cacheObj = {};
- cacheObj.tmpl = new EJS({text: templateText, name: filename});
- cacheObj.mtime = fileLastModified(f);
- appjet.scopeCache.ejs[filename] = cacheObj;
- }
- var html = cacheObj.tmpl.render(data);
- return html;
-}
-
-function renderTemplate(filename, data) {
- response.write(renderTemplateAsString(filename, data));
- if (request.acceptsGzip) {
- response.setGzip(true);
- }
-}
-
-function renderHtml(bodyFileName, data) {
- var bodyHtml = renderTemplateAsString(bodyFileName, data);
- response.write(renderTemplateAsString("html.ejs", {bodyHtml: bodyHtml}));
- if (request.acceptsGzip) {
- response.setGzip(true);
- }
-}
-
-function renderFramedHtml(contentHtml) {
- var getContentHtml;
- if (typeof(contentHtml) == 'function') {
- getContentHtml = contentHtml;
- } else {
- getContentHtml = function() { return contentHtml; }
- }
-
- var template = "framed/framedpage.ejs";
- if (isProDomainRequest()) {
- template = "framed/framedpage-pro.ejs";
- }
-
- renderHtml(template, {
- renderHeader: renderMainHeader,
- renderFooter: renderMainFooter,
- getContentHtml: getContentHtml,
- isProDomainRequest: isProDomainRequest(),
- renderGlobalProNotice: pro_utils.renderGlobalProNotice
- });
-}
-
-function renderFramed(bodyFileName, data) {
- function _getContentHtml() {
- return renderTemplateAsString(bodyFileName, data);
- }
- renderFramedHtml(_getContentHtml);
-}
-
-function renderFramedError(error) {
- var content = DIV({className: 'fpcontent'},
- DIV({style: "padding: 2em 1em;"},
- DIV({style: "padding: 1em; border: 1px solid #faa; background: #fdd;"},
- B("Error: "), error)));
- renderFramedHtml(content);
-}
-
-function renderNotice(bodyFileName, data) {
- renderNoticeString(renderTemplateAsString(bodyFileName, data));
-}
-
-function renderNoticeString(contentHtml) {
- renderFramed("notice.ejs", {content: contentHtml});
-}
-
-function render404(noStop) {
- response.reset();
- response.setStatusCode(404);
- renderFramedHtml(DIV({className: "fpcontent"},
- DIV({style: "padding: 2em 1em;"},
- DIV({style: "border: 1px solid #aaf; background: #def; padding: 1em; font-size: 150%;"},
- "404 not found: "+request.path))));
- if (! noStop) {
- response.stop();
- }
-}
-
-function render500(ex) {
- response.reset();
- response.setStatusCode(500);
- var trace = null;
- if (ex && (!isProduction())) {
- trace = exceptionutils.getStackTracePlain(ex);
- }
- renderFramed("500_body.ejs", {trace: trace});
-}
-
-function _renderEtherpadDotComHeader(data) {
- if (!data) {
- data = {selected: ''};
- }
- data.html = stringutils.html;
- data.UL = UL;
- data.LI = LI;
- data.A = A;
- data.isPNE = isPrivateNetworkEdition();
- return renderTemplateAsString("framed/framedheader.ejs", data);
-}
-
-function _renderProHeader(data) {
- if (!pro_accounts.isAccountSignedIn()) {
- return '<div style="height: 140px;">&nbsp;</div>';
- }
-
- var r = domains.getRequestDomainRecord();
- if (!data) { data = {}; }
- data.navSelection = (data.navSelection || appjet.requestCache.proTopNavSelection || '');
- data.proDomainOrgName = pro_config.getConfig().siteName;
- data.isPNE = isPrivateNetworkEdition();
- data.account = getSessionProAccount();
- data.validLicense = pne_utils.isServerLicensed();
- data.pneTrackerHtml = pne_utils.pneTrackerHtml();
- data.isAnEtherpadAdmin = sessions.isAnEtherpadAdmin();
- data.fullSuperdomain = pro_utils.getFullSuperdomainHost();
- return renderTemplateAsString("framed/framedheader-pro.ejs", data);
-}
-
-function renderMainHeader(data) {
- if (isProDomainRequest()) {
- return _renderProHeader(data);
- } else {
- return _renderEtherpadDotComHeader(data);
- }
-}
-
-function renderMainFooter() {
- return renderTemplateAsString("framed/framedfooter.ejs", {
- isProDomainRequest: isProDomainRequest()
- });
-}
-
-//----------------------------------------------------------------
-// isValidEmail
-//----------------------------------------------------------------
-
-// TODO: make better and use the better version on the client in
-// various places as well (pad.js and etherpad.js)
-function isValidEmail(x) {
- return (x &&
- ((x.length > 0) &&
- (x.match(/^[\w\.\_\+\-]+\@[\w\_\-]+\.[\w\_\-\.]+$/))));
-}
-
-//----------------------------------------------------------------
-
-function timeAgo(d, now) {
- if (!now) { now = new Date(); }
-
- function format(n, word) {
- n = Math.round(n);
- return ('' + n + ' ' + word + (n != 1 ? 's' : '') + ' ago');
- }
-
- d = (+now - (+d)) / 1000;
- if (d < 60) { return format(d, 'second'); }
- d /= 60;
- if (d < 60) { return format(d, 'minute'); }
- d /= 60;
- if (d < 24) { return format(d, 'hour'); }
- d /= 24;
- return format(d, 'day');
-};
-
-
-//----------------------------------------------------------------
-// linking to a set of new CGI parameters
-//----------------------------------------------------------------
-function qpath(m) {
- var q = {};
- if (request.query) {
- request.query.split('&').forEach(function(kv) {
- if (kv) {
- var parts = kv.split('=');
- q[parts[0]] = parts[1];
- }
- });
- }
- eachProperty(m, function(k,v) {
- q[k] = v;
- });
- var r = request.path + '?';
- eachProperty(q, function(k,v) {
- if (v !== undefined && v !== null) {
- r += ('&' + k + '=' + v);
- }
- });
- return r;
-}
-
-//----------------------------------------------------------------
-
-function ipToHostname(ip) {
- var DNS = Packages.org.xbill.DNS;
-
- if (!DNS.Address.isDottedQuad(ip)) {
- return null
- }
-
- try {
- var addr = DNS.Address.getByAddress(ip);
- return DNS.Address.getHostName(addr);
- } catch (ex) {
- return null;
- }
-}
-
-function extractGoogleQuery(ref) {
- ref = String(ref);
- ref = ref.toLowerCase();
- if (!(ref.indexOf("google") >= 0)) {
- return "";
- }
-
- ref = ref.split('?')[1];
-
- var q = "";
- ref.split("&").forEach(function(x) {
- var parts = x.split("=");
- if (parts[0] == "q") {
- q = parts[1];
- }
- });
-
- q = decodeURIComponent(q);
- q = q.replace(/\+/g, " ");
-
- return q;
-}
-
-function isTestEmail(x) {
- return (x.indexOf("+appjetseleniumtest+") >= 0);
-}
-
-function isPrivateNetworkEdition() {
- return pne_utils.isPNE();
-}
-
-function isProDomainRequest() {
- return pro_utils.isProDomainRequest();
-}
-
-function hasOffice() {
- return appjet.config["etherpad.soffice"] || appjet.config["etherpad.sofficeConversionServer"];
-}
-
-////////// console progress bar
-
-function startConsoleProgressBar(barWidth, updateIntervalSeconds) {
- barWidth = barWidth || 40;
- updateIntervalSeconds = ((typeof updateIntervalSeconds) == "number" ? updateIntervalSeconds : 1.0);
-
- var unseenStatus = null;
- var lastPrintTime = 0;
- var column = 0;
-
- function replaceLineWith(str) {
- //print((new Array(column+1)).join('\b')+str);
- print('\r'+str);
- column = str.length;
- }
-
- var bar = {
- update: function(frac, msg, force) {
- var t = +new Date();
- if ((!force) && ((t - lastPrintTime)/1000 < updateIntervalSeconds)) {
- unseenStatus = {frac:frac, msg:msg};
- }
- else {
- var pieces = [];
- pieces.push(' ', (' '+Math.round(frac*100)).slice(-3), '%', ' [');
- var barEndLoc = Math.max(0, Math.min(barWidth-1, Math.floor(frac*barWidth)));
- for(var i=0;i<barWidth;i++) {
- if (i < barEndLoc) pieces.push('=');
- else if (i == barEndLoc) pieces.push('>');
- else pieces.push(' ');
- }
- pieces.push('] ', msg || '');
- replaceLineWith(pieces.join(''));
-
- unseenStatus = null;
- lastPrintTime = t;
- }
- },
- finish: function() {
- if (unseenStatus) {
- bar.update(unseenStatus.frac, unseenStatus.msg, true);
- }
- println();
- }
- };
-
- println();
- bar.update(0, null, true);
-
- return bar;
-}
-
-function isStaticRequest() {
- return (startsWith(request.path, '/static/') ||
- startsWith(request.path, '/favicon.ico') ||
- startsWith(request.path, '/robots.txt'));
-}
-
-function httpsHost(h) {
- h = h.split(":")[0]; // strip any existing port
- if (appjet.config.listenSecurePort != "443") {
- h = (h + ":" + appjet.config.listenSecurePort);
- }
- return h;
-}
-
-function httpHost(h) {
- h = h.split(":")[0]; // strip any existing port
- if (appjet.config.listenPort != "80") {
- h = (h + ":" + appjet.config.listenPort);
- }
- return h;
-}
-
-function toJavaException(e) {
- var exc = ((e instanceof java.lang.Throwable) && e) || e.rhinoException || e.javaException ||
- new java.lang.Throwable(e.message+"/"+e.fileName+"/"+e.lineNumber);
- return exc;
-}
diff --git a/trunk/etherpad/src/main.js b/trunk/etherpad/src/main.js
deleted file mode 100644
index 503bf9d..0000000
--- a/trunk/etherpad/src/main.js
+++ /dev/null
@@ -1,418 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("dispatch.{Dispatcher,PrefixMatcher,DirMatcher,forward}");
-import("exceptionutils");
-import("fastJSON");
-import("jsutils.*");
-import("sqlbase.sqlcommon");
-import("stringutils");
-import("sessions.{readLatestSessionsFromDisk,writeSessionsToDisk}");
-
-import("etherpad.billing.team_billing");
-import("etherpad.globals.*");
-import("etherpad.log.{logRequest,logException}");
-import("etherpad.log");
-import("etherpad.utils.*");
-import("etherpad.statistics.statistics");
-import("etherpad.sessions");
-import("etherpad.db_migrations.migration_runner");
-import("etherpad.importexport.importexport");
-import("etherpad.legacy_urls");
-
-import("etherpad.control.aboutcontrol");
-import("etherpad.control.admincontrol");
-import("etherpad.control.blogcontrol");
-import("etherpad.control.connection_diagnostics_control");
-import("etherpad.control.global_pro_account_control");
-import("etherpad.control.historycontrol");
-import("etherpad.control.loadtestcontrol");
-import("etherpad.control.maincontrol");
-import("etherpad.control.pad.pad_control");
-import("etherpad.control.pne_manual_control");
-import("etherpad.control.pne_tracker_control");
-import("etherpad.control.pro.admin.license_manager_control");
-import("etherpad.control.pro_beta_control");
-import("etherpad.control.pro.pro_main_control");
-import("etherpad.control.pro_signup_control");
-import("etherpad.control.scriptcontrol");
-import("etherpad.control.static_control");
-import("etherpad.control.store.storecontrol");
-import("etherpad.control.testcontrol");
-
-import("etherpad.pne.pne_utils");
-import("etherpad.pro.pro_pad_editors");
-import("etherpad.pro.pro_utils");
-import("etherpad.pro.pro_config");
-
-import("etherpad.collab.collabroom_server");
-import("etherpad.collab.collab_server");
-import("etherpad.collab.readonly_server");
-import("etherpad.collab.genimg");
-import("etherpad.pad.model");
-import("etherpad.pad.dbwriter");
-import("etherpad.pad.pad_migrations");
-import("etherpad.pad.noprowatcher");
-
-jimport("java.lang.System.out.println");
-
-serverhandlers.startupHandler = function() {
- // Order matters.
- checkSystemRequirements();
-
- var sp = function(k) { return appjet.config['etherpad.SQL_'+k] || null; };
- sqlcommon.init(sp('JDBC_DRIVER'), sp('JDBC_URL'), sp('USERNAME'), sp('PASSWORD'));
-
- log.onStartup();
- statistics.onStartup();
- migration_runner.onStartup();
- pad_migrations.onStartup();
- model.onStartup();
- collab_server.onStartup();
- pad_control.onStartup();
- dbwriter.onStartup();
- blogcontrol.onStartup();
- importexport.onStartup();
- pro_pad_editors.onStartup();
- noprowatcher.onStartup();
- team_billing.onStartup();
- collabroom_server.onStartup();
- readLatestSessionsFromDisk();
-};
-
-serverhandlers.resetHandler = function() {
- statistics.onReset();
-}
-
-serverhandlers.shutdownHandler = function() {
- appjet.cache.shutdownHandlerIsRunning = true;
-
- log.callCatchingExceptions(writeSessionsToDisk);
- log.callCatchingExceptions(dbwriter.onShutdown);
- log.callCatchingExceptions(sqlcommon.onShutdown);
- log.callCatchingExceptions(pro_pad_editors.onShutdown);
-};
-
-//----------------------------------------------------------------
-// request handling
-//----------------------------------------------------------------
-
-serverhandlers.requestHandler = function() {
- checkRequestIsWellFormed();
- sessions.preRequestCookieCheck();
- checkHost();
- checkHTTPS();
- handlePath();
-};
-
-// In theory, this should never get called.
-// Exceptions that are thrown in frontend etherpad javascript should
-// always be caught and treated specially.
-// If serverhandlers.errorHandler gets called, then it's a bug in the frontend.
-serverhandlers.errorHandler = function(ex) {
- logException(ex);
- response.setStatusCode(500);
- if (request.isDefined) {
- render500(ex);
- } else {
- if (! isProduction()) {
- response.write(exceptionutils.getStackTracePlain(ex));
- } else {
- response.write(ex.getMessage());
- }
- }
-};
-
-serverhandlers.postRequestHandler = function() {
- logRequest();
-};
-
-//----------------------------------------------------------------
-// Scheduled tasks
-//----------------------------------------------------------------
-
-serverhandlers.tasks.writePad = function(globalPadId) {
- dbwriter.taskWritePad(globalPadId);
-};
-serverhandlers.tasks.flushPad = function(globalPadId, reason) {
- dbwriter.taskFlushPad(globalPadId, reason);
-};
-serverhandlers.tasks.checkForStalePads = function() {
- dbwriter.taskCheckForStalePads();
-};
-serverhandlers.tasks.statisticsDailyUpdate = function() {
- //statistics.dailyUpdate();
-};
-serverhandlers.tasks.doSlowFileConversion = function(from, to, bytes, cont) {
- return importexport.doSlowFileConversion(from, to, bytes, cont);
-};
-serverhandlers.tasks.proPadmetaFlushEdits = function(domainId) {
- pro_pad_editors.flushEditsNow(domainId);
-};
-serverhandlers.tasks.noProWatcherCheckPad = function(globalPadId) {
- noprowatcher.checkPad(globalPadId);
-};
-serverhandlers.tasks.collabRoomDisconnectSocket = function(connectionId, socketId) {
- collabroom_server.disconnectDefunctSocket(connectionId, socketId);
-};
-
-//----------------------------------------------------------------
-// cometHandler()
-//----------------------------------------------------------------
-
-serverhandlers.cometHandler = function(op, id, data) {
- checkRequestIsWellFormed();
- if (!data) {
- // connect/disconnect message, notify all comet receivers
- collabroom_server.handleComet(op, id, data);
- return;
- }
-
- while (data[data.length-1] == '\u0000') {
- data = data.substr(0, data.length-1);
- }
-
- var wrapper;
- try {
- wrapper = fastJSON.parse(data);
- } catch (err) {
- try {
- // after removing \u0000 might have to add '}'
- wrapper = fastJSON.parse(data+'}');
- }
- catch (err) {
- log.custom("invalid-json", {data: data});
- throw err;
- }
- }
- if(wrapper.type == "COLLABROOM") {
- collabroom_server.handleComet(op, id, wrapper.data);
- } else {
- //println("incorrectly wrapped data: " + wrapper['type']);
- }
-};
-
-//----------------------------------------------------------------
-// sarsHandler()
-//----------------------------------------------------------------
-
-serverhandlers.sarsHandler = function(str) {
- str = String(str);
- println("sarsHandler: parsing JSON string (length="+str.length+")");
- var message = fastJSON.parse(str);
- println("dispatching SARS message of type "+message.type);
- if (message.type == "migrateDiagnosticRecords") {
- pad_control.recordMigratedDiagnosticInfo(message.records);
- return 'OK';
- }
- return 'UNKNOWN_MESSAGE_TYPE';
-};
-
-//----------------------------------------------------------------
-// checkSystemRequirements()
-//----------------------------------------------------------------
-function checkSystemRequirements() {
- var jv = Packages.java.lang.System.getProperty("java.version");
- jv = +(String(jv).split(".").slice(0,2).join("."));
- if (jv < 1.6) {
- println("Error: EtherPad requires JVM 1.6 or greater.");
- println("Your version of the JVM is: "+jv);
- println("Aborting...");
- Packages.java.lang.System.exit(1);
- }
-}
-
-function checkRequestIsWellFormed() {
- // We require the "host" field to be present.
- // This should always be true, as long as the protocl is HTTP/1.1
- // TODO: check (request.protocol != "HTTP/1.1")
- if (request.isDefined && !request.host) {
- response.setStatusCode(505);
- response.setContentType('text/plain');
- response.write('Protocol not supported. HTTP/1.1 required.');
- response.stop();
- }
-}
-
-//----------------------------------------------------------------
-// checkHost()
-//----------------------------------------------------------------
-function checkHost() {
- if (appjet.config['etherpad.skipHostnameCheck'] == "true") {
- return;
- }
-
- if (isPrivateNetworkEdition()) {
- return;
- }
-
- // we require the domain to either be <superdomain> or a pro domain request.
- if (SUPERDOMAINS[request.domain]) {
- return;
- }
- if (pro_utils.isProDomainRequest()) {
- return;
- }
-
- // redirect to pad.spline.inf.fu-berlin.de
- var newurl = "http://pad.spline.inf.fu-berlin.de/"+request.path;
- if (request.query) { newurl += "?"+request.query; }
- response.redirect(newurl);
-}
-
-//----------------------------------------------------------------
-// checkHTTPS()
-//----------------------------------------------------------------
-
-// Check for HTTPS
-function checkHTTPS() {
- /* Open-source note: this function used to check the protocol and make
- * sure that pages that needed to be secure went over HTTPS, and pages
- * that didn't go over HTTP. However, when we open-sourced the code,
- * we disabled HTTPS because we didn't want to ship the pad.spline.inf.fu-berlin.de
- * private crypto keys. --aiba */
- return;
-
-
- if (stringutils.startsWith(request.path, "/static/")) { return; }
-
- if (sessions.getSession().disableHttps || request.params.disableHttps) {
- sessions.getSession().disableHttps = true;
- println("setting session diableHttps");
- return;
- }
-
- var _ports = {
- http: appjet.config.listenPort,
- https: appjet.config.listenSecurePort
- };
- var _defaultPorts = {
- http: 80,
- https: 443
- };
- var _requiredHttpsPrefixes = [
- '/ep/admin', // pro and etherpad
- '/ep/account', // pro only
- ];
-
- var httpsRequired = false;
- _requiredHttpsPrefixes.forEach(function(p) {
- if (stringutils.startsWith(request.path, p)) {
- httpsRequired = true;
- }
- });
-
- if (isProDomainRequest() && pro_config.getConfig().alwaysHttps) {
- httpsRequired = true;
- }
-
- if (httpsRequired && !request.isSSL) {
- _redirectToScheme("https");
- }
- if (!httpsRequired && request.isSSL) {
- _redirectToScheme("http");
- }
-
- function _redirectToScheme(scheme) {
- var url = scheme + "://";
- url += request.host.split(':')[0]; // server
-
- if (_ports[scheme] != _defaultPorts[scheme]) {
- url += ':'+_ports[scheme];
- }
-
- url += request.path;
- if (request.query) {
- url += "?"+request.query;
- }
- response.redirect(url);
- }
-}
-
-//----------------------------------------------------------------
-// dispatching
-//----------------------------------------------------------------
-
-function handlePath() {
- // Default. Can be overridden in case of static files.
- response.neverCache();
-
- // these paths are handled identically on all sites/subdomains.
- var commonDispatcher = new Dispatcher();
- commonDispatcher.addLocations([
- ['/favicon.ico', forward(static_control)],
- ['/robots.txt', forward(static_control)],
- ['/crossdomain.xml', forward(static_control)],
- [PrefixMatcher('/static/'), forward(static_control)],
- [PrefixMatcher('/ep/genimg/'), genimg.renderPath],
- [PrefixMatcher('/ep/pad/'), forward(pad_control)],
- [PrefixMatcher('/ep/script/'), forward(scriptcontrol)],
- [/^\/([^\/]+)$/, pad_control.render_pad],
- [DirMatcher('/ep/unit-tests/'), forward(testcontrol)],
- [DirMatcher('/ep/pne-manual/'), forward(pne_manual_control)],
- ]);
-
- var etherpadDotComDispatcher = new Dispatcher();
- etherpadDotComDispatcher.addLocations([
- ['/', maincontrol.render_main],
- [DirMatcher('/ep/beta-account/'), forward(pro_beta_control)],
- [DirMatcher('/ep/pro-signup/'), forward(pro_signup_control)],
- [DirMatcher('/ep/about/'), forward(aboutcontrol)],
- [DirMatcher('/ep/admin/'), forward(admincontrol)],
- [DirMatcher('/ep/blog/posts/'), blogcontrol.render_post],
- [DirMatcher('/ep/blog/'), forward(blogcontrol)],
- [DirMatcher('/ep/connection-diagnostics/'), forward(connection_diagnostics_control)],
- [DirMatcher('/ep/loadtest/'), forward(loadtestcontrol)],
- [DirMatcher('/ep/tpne/'), forward(pne_tracker_control)],
- [DirMatcher('/ep/pro-account/'), forward(global_pro_account_control)],
- [/^\/ep\/pad\/history\/(\w+)\/(.*)$/, historycontrol.render_history],
- [PrefixMatcher('/ep/pad/slider/'), pad_control.render_slider],
- [DirMatcher('/ep/store/'), forward(storecontrol)],
- [PrefixMatcher('/ep/'), forward(maincontrol)]
- ]);
-
- var proDispatcher = new Dispatcher();
- proDispatcher.addLocations([
- ['/', pro_main_control.render_main],
- [PrefixMatcher('/ep/'), forward(pro_main_control)],
- ]);
-
- // dispatching logic: first try common, then dispatch to
- // pad.spline.inf.fu-berlin.de or pro.
-
- if (commonDispatcher.dispatch()) {
- return;
- }
-
- // Check if there is a pro domain associated with this request.
- if (isProDomainRequest()) {
- pro_utils.preDispatchAccountCheck();
- if (proDispatcher.dispatch()) {
- return;
- }
- } else {
- if (etherpadDotComDispatcher.dispatch()) {
- return;
- }
- }
-
- if (!isProDomainRequest()) {
- legacy_urls.checkPath();
- }
-
- render404();
-}
-
diff --git a/trunk/etherpad/src/static/css/beta.css b/trunk/etherpad/src/static/css/beta.css
deleted file mode 100644
index afba271..0000000
--- a/trunk/etherpad/src/static/css/beta.css
+++ /dev/null
@@ -1,49 +0,0 @@
-div.beta-signup { }
-
-div.right {
- float: right;
- width: 500px;
-}
-div.left {
- width: 224x;
- float: left;
- text-align: center;
- padding: 60px 0 0 80px;
-}
-
-form#beta-signup-form {
- border: 1px solid #ccc;
- margin: 2em 0;
- padding: 1em;
- background: #eee;
-}
-
-form#beta-signup-form p { margin: 0; }
-
-form input {
- border: 1px solid #3773c6;
- font-size: 14pt;
-}
-
-form button {
- border: 0;
- cursor: pointer;
- color: #fff;
- font-weight: bold;
- overflow: visible;
- padding: 0;
- background: #70a4ec;
- border: 1px solid #3773c6;
- padding: 4px 6px;
- margin-top: 4px;
-}
-
-#error-msg {
- margin: 0;
- padding: .5em;
- margin-bottom: .5em;
- border: 1px solid red;
- background: #fee;
- font-weight: bold;
-}
-
diff --git a/trunk/etherpad/src/static/css/connection_diagnostics.css b/trunk/etherpad/src/static/css/connection_diagnostics.css
deleted file mode 100644
index fc040d0..0000000
--- a/trunk/etherpad/src/static/css/connection_diagnostics.css
+++ /dev/null
@@ -1,13 +0,0 @@
-#content {
- text-align: center;
-}
-
-#statusmsg {
- font-size: 200%;
- color: #444;
-}
-
-#emailform { margin: 2em; padding: 1em; background: #eee; border: 1px solid #999; }
-#emailform p { font-size: 200%; color: #444; }
-#emailform input { font-size: 200%; margin-bottom: 1em; }
-#emailform #email { color: #555; }
diff --git a/trunk/etherpad/src/static/css/fluxbb.css b/trunk/etherpad/src/static/css/fluxbb.css
deleted file mode 100644
index 844ceca..0000000
--- a/trunk/etherpad/src/static/css/fluxbb.css
+++ /dev/null
@@ -1,55 +0,0 @@
-/* fluxbb-specific CSS rules go here. */
-
-/*----------------------------------------------------------------*/
-/* Etherpad overriding shit */
-/*----------------------------------------------------------------*/
-
-div.epforum {
- width: 780px;
- padding-top: 1em;
- margin-left: auto;
- margin-right: auto;
-}
-
-div#punwrap div.pun {
- font-size: 120%;
-}
-
-div#idx1 h2 { display: none; }
-
-div#punwrap div.pun h2 {
- color: white;
- font-style: normal;
- font-weight: normal;
- font-family: sans-serif;
- font-size: 1.2em;
-}
-
-div#punwrap div.pun p { margin: 0; }
-
-.pun div.box {
- border: 1px solid #ccc;
-}
-
-div#brdheader div.box {
- background: #fff;
- border: 0;
- padding: 0;
- margin: 0;
-}
-
-div#brdheader div#brdtitle {
- padding: 0;
-}
-div#brdheader h1 {
- font-family: "Lucida Grande","Lucida Sans Unicode",sans-serif;
- color: #666;
- border-bottom: 1px solid #666;
- font-size: 1.8em;
-}
-
-div#brdwelcome {
- margin-top: 1em;
- border: 1px solid #ccc;
- background: #f1f1f1;
-}
diff --git a/trunk/etherpad/src/static/css/home.css b/trunk/etherpad/src/static/css/home.css
deleted file mode 100644
index 797a8a7..0000000
--- a/trunk/etherpad/src/static/css/home.css
+++ /dev/null
@@ -1,264 +0,0 @@
-/*--------
- Homepage
- --------*/
-
-/* Top */
-
-#top {
- height: 349px;
- position: relative;
- background: url(/static/img/davy/gfx/screenshot.gif) no-repeat bottom right;
-}
-
-#homepage-notice {
- margin: 10px auto;
- width: 888px;
- background: #ffc;
- color: #000;
- border: 2px solid #550;
- font-size: 1.4em;
- padding: 8px;
-}
-
-#intro-left {
- width: 340px;
- float: left;
- font-family: Arial, Helvetica, sans-serif;
- text-shadow: 0 0 1px #18487F;
- padding-top: 10px;
-}
- #intro-left h1 {
- width: 210px;
- position: relative;
- padding: 57px 0 0 0;
- overflow: hidden;
- background: transparent url(/static/img/davy/gfx/home-logo2.gif) no-repeat top left;
- height: 0px;
- margin: 0 0 5px -8px;
- }
- #intro-left h2 {
- color: #d1e5ff;
- font-size: 1.5em;
- font-weight: bold;
- line-height: 1.2;
- }
- #intro-left h2 a {
- color: #9ac6ff;
- font-style: italic;
- border-bottom: 2px solid;
- }
- #intro-left h2 a:hover {
- text-decoration: none;
- color: #4A91EE;
- }
- #intro-left p {
- color: #fff;
- font-size: 1.167em;
- line-height: 1.3;
- margin: 10px 0;
- }
- #intro-links {
- position: absolute;
- bottom: 17px;
- left: -1px;
- width: 500px;
- }
- #intro-links a {
- display: block;
- float: left;
- position: relative;
- padding: 64px 0 0 0;
- overflow: hidden;
- background-repeat: no-repeat;
- background-position: top left;
- height: 0;
- }
- #newpadbutton {
- width: 212px;
- background-image: url(/static/img/davy/btn/createpad-home.gif);
- margin-right: 11px;
- }
- #betabutton {
- width: 220px;
- background-image: url(/static/img/davy/btn/signup-home-4.gif);
- }
-
-/* Bottom */
-
-#bottom {
- padding-top: 28px;
-}
-
-#quote {
- border-bottom: 1px solid #e0e0e0;
- padding-bottom: 24px;
- text-shadow: 0 0 1px #F7F7F7;
-}
- #quote q {
- width: 680px;
- float: left;
- font-size: 1.33em;
- height: 1.5em;
- }
- #quote #quote-right {
- width: 200px;
- float: right;
- text-align: right;
- }
- #quote #quote-right cite {
- display: block;
- font-size: 1.33em;
- font-style: italic;
- margin-bottom: 8px;
- }
-
-#features {
- border-top: 1px solid #fff;
- padding-top: 22px;
- text-shadow: 0 0 1px #F7F7F7;
-}
- #features li {
- width: 213px;
- float: left;
- margin-left: 12px;
- }
- #features li.first {
- margin-left: 0;
- }
- #features li img {
- float: left;
- margin-right: 8px;
- }
- #features li strong,
- #features li span {
- display: block;
- margin-left: 40px;
- }
- #features li strong {
- font-size: 16px;
- font-weight: normal;
- margin-bottom: 6px;
- }
- #features li span {
- line-height: 17px;
- }
-
-#uses {
-width: 675px;
-float: left;
- margin-bottom: 28px;
- margin-right: -12px;
-position: relative;
-}
-#uses li {
-width: 213px;
-float: left;
- margin-right: 12px;
-}
-#uses li a {
- font-size: 1.5em;
- font-family: Calibri, Arial, Helvetica, sans-serif;
- text-shadow: 0 1px 0 #fff;
-color: #214b7e;
-}
-#uses li a:hover {
- text-decoration: none;
-color: #30619c;
-}
-#uses li .thumb {
-display: block;
-width: 213px;
-position: relative;
-padding: 123px 0 0 0;
-overflow: hidden;
- background-repeat: no-repeat;
- background-position: top left;
-height: 0px;
- margin-top: 10px;
-}
-#uses #use-meetings .thumb { background-image: url(/static/img/davy/gfx/use-meetings.png); }
-#uses #use-programming .thumb { background-image: url(/static/img/davy/gfx/use-programming.png); }
-#uses #use-writing .thumb { background-image: url(/static/img/davy/gfx/use-writing.png); }
-#uses .more {
-display: block;
-position: absolute;
-padding: 21px 0 0 0;
-overflow: hidden;
-background: transparent url(/static/img/davy/btn/uses-more.gif) no-repeat top left;
-height: 0px;
-width: 58px;
-top: 0;
-right: 12px;
- z-index: 10;
-}
-* html #uses .more {
-right: 24px;
-}
-
-#blog {
-width: 213px;
-float: left;
- margin-right: 12px;
-clear: left;
-}
-#blog h3 {
- font-family: Calibri, "Trebuchet MS", Trebuchet, Arial, Helvetica, sans-serif;
-color: #666;
- text-transform: uppercase;
- text-shadow: 0 1px 0 #fff;
- letter-spacing: 1px;
-}
-#blog li {
-margin: 1.25em 0;
-}
-#blog li strong a {
- font-size: 1.33em;
- font-family: Calibri, Arial, Helvetica, sans-serif;
- font-weight: bold;
-}
-#blog li small {
-display: block;
- font-size: .917em;
- font-family: Calibri, Arial, Helvetica, sans-serif;
-color: #666;
-margin: 2px 0;
-}
-#blog li small a {
-color: #4182c2;
-}
-#blog li span {
- line-height: 1.3;
-}
-
-#quotes {
-width: 406px;
-float: left;
-background: #e0ecf9;
-border: 1px solid #8ba9cc;
- border-left: 0;
- border-right: 0;
-color: #334050;
- font-family: Calibri, Arial, Helvetica, sans-serif;
-padding: 12px 16px 0;
- text-shadow: 0 0 1px #e0ecf9;
-}
-#quotes q {
- font-size: 1.5em;
- line-height: 1.22;
-display: block;
- text-indent: -.45em;
-}
-#quotes cite {
- font-size: 1.33em;
-display: block;
- font-style: italic;
- text-align: right;
-margin: .5em 0 1em;;
-}
-#quotes .more {
- text-align: right;
- margin-bottom: 1em;
- position: relative;
- right: -.75em;
- font-size: 1.167em;
-}
diff --git a/trunk/etherpad/src/static/css/pad.css b/trunk/etherpad/src/static/css/pad.css
deleted file mode 100644
index 02c341f..0000000
--- a/trunk/etherpad/src/static/css/pad.css
+++ /dev/null
@@ -1,1000 +0,0 @@
-*,html.body,p { margin: 0; padding: 0; }
-html {
- font-size: 62.5%;
-}
-div.hidden { display: none; }
-
-/*----------------------------------------------------------------*/
-/* pad */
-/*----------------------------------------------------------------*/
-body#padbody {
- font-family: verdana, helvetica, sans-serif;
- background: white;
- color: black;
-}
-
-body#padbody.limwidth {
- background: #d2d2d2 url(/static/img/apr09/backgrad.png) repeat-x left top;
-}
-
-body #padoutertable { width: 100%; }
-body.limwidth #padoutertable { width: 940px; margin-left: auto; margin-right: auto; }
-#padoutertable td#pot_main, #padoutertable td#pot_top, #padoutertable td.potshad {
- vertical-align: top; zoom: 1; position: relative; }
-#padoutertable #pot_main { background: white; padding-left: 12px; padding-right: 12px;
- padding-top: 2px;
-}
-
-body.fullwidth #padoutertable .potshad { display: none; }
-
-/* Achieve side drop shadows on top of background gradient using two drop shadow
- images for each side (one with gradient in background, one to repeat down the
- page). Each side drop shadow gets a column of the padoutertable, but split into
- two cells, because if a single cell is used on each side with rowspan=2 with a
- tall image in it, IE 6 chooses an unsightly initial height for the top bar.
-*/
-body.limwidth #padoutertable .potshad { width: 4px; }
-body.limwidth #padoutertable .potshad div { height: 200px; }
-body.limwidth #padoutertable #pot_shadleft {
- background: url(/static/img/apr09/shadleft.png) repeat-y right top; }
-body.limwidth #padoutertable #pot_shadleft div,
-body.limwidth #padoutertable #pot_shadlefttopseg {
- background: url(/static/img/apr09/shadlefttop.png) no-repeat right top; }
-body.limwidth #padoutertable #pot_shadright {
- background: url(/static/img/apr09/shadright.png) repeat-y left top; }
-body.limwidth #padoutertable #pot_shadright div,
-body.limwidth #padoutertable #pot_shadrighttopseg {
- background: url(/static/img/apr09/shadrighttop.png) no-repeat left top; }
-body.limwidth #padoutertable #pot_main, body.limwidth #padoutertable #pot_top {
- border-left: 1px solid #333;
- border-right: 1px solid #333;
-}
-body.limwidth #padoutertable #pot_main { border-bottom: 1px solid #333; }
-
-#padoutertable #pot_top { background: #2e609e url(/static/img/apr09/topbar.gif) repeat-x left top;
- height: 28px; vertical-align: middle;
- border-bottom: 1px solid #333;
- padding-left: 1px; padding-right: 1px; /* a little padding helps "active" rects not extend outside */
-}
-
-#padpage #pot_top a#headhomelink {
- display: block; float: left;
- height: 0; width: 88px;
- padding-top: 28px;
- overflow: hidden;
- text-decoration: none;
- background: url(/static/img/apr09/topbarlogo.gif) no-repeat left top;
-}
-#padpage #pot_top a#widthlink {
- display: block; float: right;
- height: 0; width: 28px;
- padding-top: 28px;
- overflow: hidden;
- text-decoration: none;
-}
-
-#padpage #pot_top, #padpage #pot_top a { color: #cbd7e7; }
-#padpage #pot_top a:focus { outline: 0; } /* for firefox */
-
-body.limwidth #padpage #pot_top a#widthlink {
- background: url(/static/img/apr09/widthfull.gif) no-repeat center 8px; }
-body.fullwidth #padpage #pot_top a#widthlink {
- background: url(/static/img/apr09/widthlim.gif) no-repeat center 8px; }
-body.limwidth #padpage #pot_top a#widthlink:hover {
- background: url(/static/img/apr09/widthfullactive.gif) no-repeat center 8px; }
-body.fullwidth #padpage #pot_top a#widthlink:hover {
- background: url(/static/img/apr09/widthlimactive.gif) no-repeat center 8px; }
-
-#padpage #pot_top #headurl {
- margin-left: 30px;
- margin-top: 5px;
- float: left;
- margin-right: 20px;
- padding: 2px;
- height: 15px;
- line-height: 14px;
- font-size: 1.1em;
-}
-
-#padpage #pot_top #shareurl { font-weight: bold; }
-
-#padpage #pot_top #newpadlink {
- display: block; float: right; margin-right: 30px; font-size: 1.0em;
- font-weight: bold; text-decoration: none;
- height: 0;
- padding-top: 8px;
- padding-bottom: 20px;
- padding-left: 20px;
- padding-right: 6px;
- overflow: hidden;
- background: url(/static/img/apr09/newpadicon.gif) no-repeat 2px 8px;
-}
-#padpage #pot_top a#newpadlink:hover {
- text-decoration: underline; color: white;
-}
-
-/*
-body#padbody.fullwidth {
- background: #ddd;
-}
-#padpage {
-
-}
-body.limwidth #padcontent {
- width: 940px;
- margin-left: auto;
- margin-right: auto;
-}
-#padpage #padhead {
- height: 38px;
- text-align: center;
- margin-bottom: 4px;
-}
-#padpage #padhead_inner {
- width: 938px;
- margin-left: auto;
- margin-right: auto;
- padding: 0 1px;
- background: url(/static/img/oct/minitopback2.gif) repeat center top;
- border: 1px solid #666;
- border-top: 0;
-}
-#padpage #padhead a#headhomelink {
- display: block;
- float: left;
- height: 0;
- width: 154px;
- padding-top: 37px;
- overflow: hidden;
- text-decoration: none;
- background: url(/static/img/oct/minitoplogo2.gif) no-repeat left top;
-}
-#padpage #headnewpad {
- float: right;
-}
-#padpage #headnewpad #newbutton {
- margin-top: 5px;
- margin-right: 20px;
-}
-#padpage #headurl {
- margin-left: 70px;
- margin-top: 5px;
- float: left;
- font-size: 1.4em;
- margin-right: 20px;
- padding: 5px 5px 5px 5px;
- height: 17px;
- line-height: 17px;
-}
-#padpage #headurl label {
- font-weight: bold;
- font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
- font-size:1em;
- position: relative;
- top: 1px;
-}
-#padpage #headurl #shareurl {
- border: 1px solid #999;
- padding: 3px;
-}
-#padpage #padtablediv {
- margin: 0;
-}
-body.limwidth #padpage #padtablediv {
- margin: 0 20px;
-}
-*/
-
-#padpage #padtable {
- width: 100%;
-}
-#padpage #padtable td#topbar {
- height: 16px;
-}
-#padpage #padtable div#topbarmsg {
- display: none;
- float: left;
- color: #642;
- font-size: 1.0em;
- padding-top: 2px;
- padding-left: 4px;
- border-left: 1px solid #ccc;
-}
-
-#padpage #topbar #connectionstatus {
- float: left;
- padding-top: 2px;
- padding-right: 4px;
- padding-left: 16px;
- height: 16px;
- font-size: 1.0em;
- color: #666;
-}
-#padpage #topbar .connecting {
- background: url(/static/img/pad/animated-orb-orange-12.gif) no-repeat left center;
-}
-#padpage #topbar .connected {
- background: url(/static/img/pad/orb-greenred-12.gif) no-repeat left 3px;
-}
-#padpage #topbar .disconnected {
- background: url(/static/img/pad/orb-greenred-12.gif) no-repeat left -17px;
-}
-#padpage #padtable a.showhide {
- display: block;
- margin: 0;
- font-size: 1em;
- text-decoration: none;
-}
-#padpage #padtable a.showhide:hover {
- text-decoration: underline;
-}
-#padpage #padtable a.showhide, #padpage #padtable a.showhide:visited {
- color: #66f;
-}
-#padpage #padtable a#showsidebar {
- float: right;
- display: none;
- position: relative;
- top: 2px;
-}
-#padpage #padtable a#hidesidebar {
- float: left;
- display: none;
-}
-/*#padpage #editorcontainer {
- display: none;
-}*/
-/*#padpage #toptoolbar {
- display: none;
-}*/
-#padpage .editorcell_loaded #editorcontainer {
- background: #fff;
- overflow: hidden;
- display: block;
-}
-#padpage #toptoolbar {
- border-bottom: 1px solid #666;
- height: 30px;
- background: #eee;
- display: block;
- position: relative; /* make it an offsetParent for padtitle stuff */
- overflow: hidden;
-}
-#padpage #bottoolbar {
- border-top: 1px solid #666;
- height: 30px;
- background: #eee;
- display: none; /* set in pad.js */
-}
-#padpage #bottoolbar #viewzoom {
- padding-left: 5px;
- padding-top: 5px;
- padding-right: 5px;
- float: left;
-}
-#padpage #bottoolbar #viewfont {
- padding-left: 5px;
- padding-top: 5px;
- padding-right: 5px;
- float: left;
-}
-#padpage #editorcell {
- border: 1px solid #666;
-}
-#padpage #toptoolbar a.toptoolbarbutton {
- float: left;
- height: 20px;
- width: 20px;
- border: 1px solid #999;
- background-color: #eee;
- background-repeat: no-repeat;
- background-position: center center;
- margin-top: 5px;
- text-decoration: none;
-}
-#padpage #toptoolbar.disabledtoolbar a.toptoolbarbutton {
- opacity: 0.5;
- filter: alpha(opacity = 50); /* IE */
- zoom: 1;
- cursor: auto;
-}
-#padpage #toptoolbar #padtitle {
- float: left;
- margin-top: 5px;
- margin-left: 20px;
- line-height: 20px;
- width: 400px;
- height: 20px;
- overflow: hidden;
- display: none;
-}
-#padpage #toptoolbar .padtitlepad {
- font-style: italic;
- color: #666;
- font-size: 1.2em;
-}
-#padpage #toptoolbar #padtitletitle {
- font-weight: bold;
- font-size: 1.2em;
-}
-#padpage #toptoolbar .editlink {
- font-size: 1em;
- color: #666;
-}
-#padpage #toptoolbar .oklink {
- display: none;
- z-index: 2;
- position: absolute;
- line-height: 20px;
- font-size: 1em;
-}
-#padpage #toptoolbar #padtitleedit {
- z-index: 2;
- position: absolute;
- left: 0;
- top: 0;
- display: none;
-}
-#padpage #toptoolbar a:focus {
- outline: 0;
-}
-#padpage #toptoolbar .bold { background-image: url(/static/img/may09/bold.gif); }
-#padpage #toptoolbar .italic { background-image: url(/static/img/may09/italic.gif); }
-#padpage #toptoolbar .underline { background-image: url(/static/img/may09/underline.gif); }
-#padpage #toptoolbar .undo { background-image: url(/static/img/may09/undo.gif); }
-#padpage #toptoolbar .redo { background-image: url(/static/img/may09/redo.gif); }
-#padpage #toptoolbar .bold, #padpage #toptoolbar .undo {
- margin-left: 5px;
-}
-#padpage #toptoolbar #passwordlock {
- float: right;
- margin-top: 5px;
- margin-right: 5px;
- width: 22px;
- height: 22px;
- text-decoration: none;
-}
-#padpage #toptoolbar a#passwordlock:hover {
- background-color: #ffffee;
-}
-#padpage #toptoolbar .passwordhidden { display: none; }
-#padpage #toptoolbar .passwordlocked {
- display: block;
- background: url(/static/img/may09/passwordlocked.gif) no-repeat center center;
-}
-#padpage #toptoolbar .passwordnone {
- display: block;
- background: url(/static/img/may09/passwordnone.gif) no-repeat center center;
-}
-#padpage #sidebarcell {}
-#padpage #sidebar {
- width: 300px;
- border-top: 1px solid #666;
- border-right: 1px solid #666;
- border-bottom: 1px solid #666;
- background: #fff;
- overflow: auto;
-}
-#padpage div.sidebar_loading {
- border-left: 1px solid #666;
-}
-#padpage #editorcontainer iframe {
- width: 100%;
- padding:0;
- margin:0;
-}
-#padpage #appjetfooter {
- padding: 3px 3px;
- font-family: Verdana, Helvetica, sans-serif;
- font-size: 1em;
- text-align: right;
-}
-div#djs {
- font-family: monospace;
- font-size: 10pt;
- height: 300px;
- overflow: scroll;
- border: 1px solid #ccc;
- background: #fee;
- margin: 5px 0;
- padding: 6px;
-}
-div#djs p { margin: 0; padding: 0; display: block; }
-#padpage a.small_link {
- font-style: normal;
- color: #66f;
- text-decoration: none;
- font-size: 1.1em;
-}
-#padpage a.small_link:hover { text-decoration: underline; }
-#padpage .editorcell_loading #editorcellinner {
- height: 400px; /* make #sizedcontent stretch the outer table for height calc */
-}
-#padpage #editorcellinner {
- position: relative;
- zoom: 1;
-}
-#padpage #loadingbox {
- padding-top: 100px;
- padding-bottom: 100px;
- font-size: 2.5em;
- color: #aaa;
- text-align: center;
- position: absolute;
- width: 100%;
- height: 30px;
- z-index: 100;
-}
-/*----------------------------------------------------------------*/
-/* userlist */
-/*----------------------------------------------------------------*/
-#sidebar div.sideheadwrap {
- font-weight: normal;
- font-size: 1.2em;
- text-align: center;
- padding: 3px 6px;
- background: #eee url(/static/img/pad/sidehead-grad.gif) repeat-x bottom left;
- border-bottom: 1px solid #666;
- cursor: pointer;
- zoom: 1;
-}
-#sidebar div.sh_hilited {
- background-image: url(/static/img/oct/sidehead-gradhilite.gif);
-}
-#sidebar div.sideheadwrap p.sidehead {
- display: block;
- text-align: left;
- padding: 0 0 0 18px;
- margin: 0;
-}
-#sidebar div.sh_uncollapsed p.sidehead {
- background: url(/static/img/pad/expandy-arrow6-down.gif) no-repeat center left;
-}
-#sidebar div.sh_collapsed p.sidehead {
- background: url(/static/img/pad/expandy-arrow6-right.gif) no-repeat center left;
-}
-#sidebar div.sideheadwrap:hover {
- cursor: pointer;
- background: #bbb;
-}
-#sidebar div.sh_uncollapsed:hover p.sidehead {
- background: url(/static/img/pad/expandy-arrow6-down-active.gif) no-repeat center left;
-}
-#sidebar div.sh_collapsed:hover p.sidehead {
- background: url(/static/img/pad/expandy-arrow6-right-active.gif) no-repeat center left;
-}
-#sidebar div.sidebox { margin-bottom: 10px; }
-#sidebar div#chatbox { margin-bottom: 2px; }
-#sidebar div.sidebox_last { margin-bottom: 0; }
-#sidebar #userlist div.userbox {
- border-bottom: 1px solid #ccc;
-}
-#sidebar #userlist div.lastuser {
- border-bottom: 0;
-}
-#sidebar #userlist div.userbox div.userinfo {
- font-style: italic;
- margin-top: 3px;
-}
-#sidebar #userlist div.userbox div.userinfo span.username {
- padding-bottom: 4px;
- font-size: 1.2em;
-}
-#sidebar #userlist div.userbox div.userinfo div.ip {
- color: #999;
- font-size: 1em;
- margin-bottom: 3px;
-}
-#sidebar #userlist div.userbox div.usercolor {
- border: 1px solid black;
- width: 12px;
- height: 12px;
- float: left;
- margin: 6px;
- margin-top: 3px;
- margin-left: 0;
-}
-#sidebar #userlist div.userbox div#rightuserlink {
- float: right;
- text-align: right;
- width: 120px;
-}
-#sidebar #userlist a#changenamelink {
- padding-right: 18px;
- background: url(/static/img/pad/pencil-icon-small-blue.gif) no-repeat top right;
-}
-#sidebar #userlist div.userinfowrap {
- padding: 6px 0 6px 6px;
-}
-#sidebar #userlist div.myuserwrap:hover {
- cursor: pointer;
- background: #eee;
-}
-/*----------------------------------------------------------------*/
-/* editing my user info */
-/*----------------------------------------------------------------*/
-#userlist div.edituserinfo {
- color: black;
- padding: 6px 0 12px 12px;
-}
-#userlist div.edituserinfo p {
- font-size: 1.2em;
- margin: 8px 4px;
-}
-#userlist div.edituserinfo h4 {
- margin-top: 1em;
- margin-left: 4px;
- font-size: 1.3em;
- color: black;
- font-weight: bold;
-}
-#userlist div.edituserinfo input {
- width: 260px;
-}
-#userlist div.edituserinfo button {
- margin: 8px 4px;
-}
-#colorpicker a {
- border: 3px solid #ccc;
- text-decoration: none;
- display: block;
- width: 12px;
- height: 12px;
- float: left;
- margin: 4px;
- cursor: pointer;
-}
-#colorpicker a.selectedcolor {
- border: 3px solid black;
-}
-#colorpicker a:hover {
- border: 3px solid black;
-}
-/*----------------------------------------------------------------*/
-/* invitemore */
-/*----------------------------------------------------------------*/
-#sidebar #invitemore {
- display: none;
- text-align: center;
- margin-top: 10px;
- font-size: 1.1em;
-}
-#sidebar #invitemore input {
- font-size: 1.1em;
-}
-#sidebar #invitemore a {}
-#sidebar #invitemore #inviteinstructions {
- background-color: #efe;
- border: 1px solid #ccc;
-}
-#sidebar #invitemore #inviteinstructions p {
- text-align: justify;
- padding: .4em 1em;
-}
-#sidebar #invitemore #inviteinstructions p#hideinstructions {
- text-align: center;
-}
-#sidebar #invitemore #inviteinstructions p#emailinviteleadin {
- margin-top: .6em;
-}
-#sidebar #invite_email { width: 160px; }
-#sidebar #invitemore #inviteinstructions #invite_email_submit {}
-#sidebar #invitemore #invite_email_status { color: #642; }
-/*----------------------------------------------------------------*/
-/* prefs */
-/*----------------------------------------------------------------*/
-#sidebar div#headprefs { border-top: 1px solid #666; }
-#sidebar div#headfeedback { border-top: 1px solid #666; }
-#sidebar div#headrevisions { border-top: 1px solid #666; }
-#sidebar div#headchatbox { border-top: 1px solid #666; }
-#sidebar div#headimportexport { border-top: 1px solid #666; }
-#sidebar #prefs div.prefcheckbox {
- margin: 0;
- cursor: pointer;
- border: 1px solid #fff;
- font-size: 1em;
-}
-#sidebar #prefs div.prefcheckbox td.checkboxcell {
- padding: 0 4px;
-}
-#sidebar #prefs div.prefcheckbox td.labelcell {
- padding: 3px 4px;
-}
-#sidebar #prefs div.prefcheckbox:hover {
- cursor: pointer;
- background-color: #def;
- border: 1px solid #aaa;
-}
-/*----------------------------------------------------------------*/
-/* revisions */
-/*----------------------------------------------------------------*/
-#sidebar #revisions {
- text-align: center;
-}
-#sidebar #revisionlist {}
-#sidebar #revisions input#savenow {
- width: 260px;
- margin-left: auto; margin-right: auto;
- margin-top: 6px; margin-bottom: 6px;
-}
-#sidebar #revisions .revisioninfo {
- text-align: left;
- font-size: 1.1em;
- border-top: 1px solid #ccc;
- padding: 3px 2px 3px 6px;
-}
-#sidebar #revisions .revisioninfo .ractions {
- color: #aaa;
- font-size: 1em;
-}
-#sidebar #revisions .revisioninfo .rleft {
- width: 96px;
- float: left;
-}
-#sidebar #revisions .revisioninfo .editrlabel {
- padding-left: 16px;
- background: url(/static/img/pad/pencil-icon-small-blue.gif) no-repeat center left;
-}
-#sidebar #revisions .revisioninfo .rright {
- margin-left: 18px;
- color: #777;
- font-style: italic;
-}
-#sidebar #revisions .revisionbottomlinks {
- border-top: 1px solid #eee;
- padding-top: 5px;
- color: #888;
- font-size: 1.1em;
-}
-#sidebar #revisions #nosaveprivs {
- display: none;
- color: #282;
- font-size: 1.2em;
- padding: 1em;
-}
-#sidebar #revisions p.revlabelprompt {
- color: #444;
- padding: 2px;
-}
-#sidebar #revisions input.inputrevlabel {
- display: block;
- width: 260px;
- margin-left: auto; margin-right: auto;
- margin-top: 6px; margin-bottom: 6px;
- border: 1px solid #ccf;
-}
-
-/*----------------------------------------------------------------*/
-/* feedback */
-/*----------------------------------------------------------------*/
-#sidebar #feedback {
- background: #eee;
- padding: 1px 8px; /* non-zero padding so that background extends */
- border-bottom: 1px solid #bbb;
- text-align: center;
- padding-bottom: 12px;
-}
-#sidebar #feedback p {
- font-size: 1.1em;
- margin: 10px 0;
- color: #333;
- text-align: justify;
-}
-#sidebar #feedback p em {
- font-weight: bold;
- font-style: italic;
-}
-#sidebar #feedback #formbox {
- width: 260px;
- margin-left: auto;
- margin-right: auto;
- zoom: 1;
- positive: relative;
-}
-#sidebar #feedback textarea {
- width: 100%;
- margin-left: auto;
- margin-right: auto;
- height: 100px;
-}
-#sidebar #feedbacksubmit {
- width: 100%;
- text-align: center;
- margin-left: auto;
- margin-right: auto;
-}
-#sidebar #feedbackresult {
- display: none;
-}
-/*----------------------------------------------------------------*/
-/* other */
-/*----------------------------------------------------------------*/
-a#newbutton {
- font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
- font-size:1.2em;
- line-height:1.0;
- margin:0 0 0 0;
- text-decoration:none;
-
- background-color:#eee;
- border:1px solid #999;
- border-top: 1px solid #bbb;
- border-bottom: 1px solid #666;
-
- padding:5px 5px 3px 5px;
-
- cursor:pointer;
- font-weight:bold;
- color:#555;
- display: block;
-}
-a#newbutton:hover {
- background-color: #ddd;
- border: 1px solid #999;
- color: #333;
-}
-a#newbutton img {
- padding:0;
- padding-bottom: 2px;
- border:none;
- width: 16px;
- height: 16px;
- vertical-align: middle;
-}
-
-#framedpage #notice {
- padding: 40px 20px;
-}
-#framedpage #notice p {
- margin: 16px 0;
-}
-
-img#plane { border: 0; vertical-align: middle; }
-
-/*----------------------------------------------------------------*/
-/* top msgs */
-/*----------------------------------------------------------------*/
-
-div.topmsg {
- zoom: 1;
- margin: 5px 0;
- position: relative;
-}
-div.topmsg a#hidetopmsg {
- position: absolute;
- right: 5px;
- bottom: 5px;
-}
-
-div#bigtoperror_wrap {
- border: 1px solid #a66;
- background: #fdd;
- font-size: 1.2em;
- padding: 1em;
- padding-bottom: .5em;
-}
-div#bigtoperror_wrap p {
- margin-bottom: 6px;
- color: #222;
-}
-div#bigtoperror_wrap p.whynote {
- color: #444;
-}
-div#bigtoperror_wrap p.whynote a {
- color: #33f;
-}
-div#bigtoperror_wrap button.forcereconnect {
- margin-top: 6px;
-}
-div#bigtoperror_wrap a { color: #00a; }
-div#bigtoperror_wrap a:visited { color: #00a; }
-
-div#servermsg {
- position: relative;
- border: 1px solid #992;
- background: #ffc;
- padding: 1em;
-}
-
-/*----------------------------------------------------------------*/
-/* chat */
-/*----------------------------------------------------------------*/
-#chatbox {}
-#chatbox #chatmessages {
- margin: 0;
- margin-bottom: 2px;
- height: 160px;
- border: 1px solid #ccc;
- overflow: auto;
-}
-#chatbox div.chatmessage { padding: 2px 0; }
-#chatbox div.chatusermessage0 { background-color: #eee; }
-#chatbox span.chatname { font-style: italic; }
-#chatbox span.chattime { font-style: italic; color: #444; }
-#chatbox span.chatline { color: #222; }
-#chatbox input#chatinput { width: 100%; }
-#chatbox #chatsaytable {
- width: 270px;
- margin-left: auto;
- margin-right: auto;
- padding: 0;
- border-spacing: 0;
-}
-#chatbox #chatsaytable td { padding: 0 2px; }
-
-/*----------------------------------------------------------------*/
-/* import/export */
-/*----------------------------------------------------------------*/
-
-#importexport td.exportpic a img {
- border: 0;
-}
-
-#importexport .exportspinner {
- display: none;
-}
-
-#importexport .exportspinner img {
- margin-left: 7px;
-}
-
-#importexport a.disabledexport {
- color: gray;
-}
-
-#importexport {
- font-size: 1em;
- font-family: verdana, helvetica, sans-serif;
-}
-
-#importexport .exportlink {
- margin: 2px 0;
-}
-
-#importexport td.labelcell {
- padding-left: 4px;
-}
-
-#importexport td.firsttd {
- padding-left: 10px;
-}
-
-#importexport td.secondtd {
- padding-left: 50px;
-}
-
-#importexport #headexport {
- font-size: 1.1em;
- margin: 7px;
- margin-top: 10px;
-}
-
-#importexport #importsection {
- border-top: 1px solid #ccc;
- margin-top: 5px;
- padding-top: 3px;
-}
-
-#importexport .importformdiv {
- padding: 5px 15px;
-}
-
-#importexport #importformsubmitdiv {
- margin-top: 5px;
-}
-
-.importformenabled {
- background: #cfc;
- border-top: 1px solid #292;
- border-bottom: 1px solid #292;
-}
-
-#importexport #headimport {
- font-size: 1.1em;
- margin: 7px;
-}
-
-#importexport .importmessage {
- display: none;
- border: 1px solid #992;
- background: #ffc;
- padding: 5px;
-}
-
-#importexport #exportmessage {
- display: none;
- border: 1px solid #992;
- background: #ffc;
- padding: 5px;
- margin: 10px 15px;
-}
-
-#importexport #importmessagefail {
- margin-top: 10px;
- margin-bottom: 5px;
-}
-
-#importexport #importmessagesuccess {
- margin: 0 20px;
-}
-
-#importexport #importstatusball {
- display: none;
- padding-bottom: 3px;
-}
-
-#importexport #importarrow {
- display: none;
- margin-left: 5px;
-}
-
-span.nowrap {
- white-space: nowrap;
-}
-
-#sidebar #prefs div.prefcheckbox {
- margin: 0;
- cursor: pointer;
- border: 1px solid #fff;
- font-size: 1em;
-}
-#sidebar #prefs div.prefcheckbox td.checkboxcell {
- padding: 0 4px;
-}
-#sidebar #prefs div.prefcheckbox td.labelcell {
- padding: 3px 4px;
-}
-#sidebar #prefs div.prefcheckbox:hover {
- cursor: pointer;
- background-color: #def;
- border: 1px solid #aaa;
-}
-
-/*----------------------------------------------------------------*/
-/* modal dialogs */
-/*----------------------------------------------------------------*/
-
-#modaloverlay {
- position: absolute;
- z-index: 100;
- background-image: url(/static/img/apr09/black35.png);
- zoom: 1;
- display: none;
- left: 0; top: 0;
- width: 100%;
-}
-
-* html #modaloverlay { /* for IE 6+ */
- background-color: transparent;
- background-image: url(/static/img/apr09/blank.gif);
- filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/static/img/apr09/black35.png", sizingMethod="scale");
-}
-
-#modaldialog {
- border: 1px solid #333;
- background: #ddd;
- width: 400px;
- margin-left: auto;
- margin-right: auto;
- position: relative;
-}
-
-#dialogtopbar {
- height: 18px;
- border-bottom: 1px solid #333;
- background: #2e609e url(/static/img/apr09/modalbar.gif) repeat-x left top;
- color: #cbd7e7;
- font-size: 1.0em;
- font-weight: bold;
- line-height: 18px;
- padding-left: 10px;
- cursor: default;
-}
-
-td#dialogcontent {
- padding: 10px;
- height: 100px;
- vertical-align: top;
-}
-
-table#dialogcontenttable { width: 100%; }
diff --git a/trunk/etherpad/src/static/css/pad2_ejs.css b/trunk/etherpad/src/static/css/pad2_ejs.css
deleted file mode 100644
index 253b8e2..0000000
--- a/trunk/etherpad/src/static/css/pad2_ejs.css
+++ /dev/null
@@ -1,889 +0,0 @@
-
-*,html.body { margin: 0; padding: 0; }
-
-h1, h2, h3, h4, h5, h6 { display: inline; line-height: 2em; }
-
-.clear { clear: both; }
-
-html { font-size: 62.5%; }
-
-body { background: #ebebeb url(/static/img/jun09/pad/backgrad.gif) repeat-x left top; }
-body, textarea { font-family: Arial, sans-serif; }
-
-#padpage { margin-left: auto; margin-right: auto; width: 900px; }
-
-body.fullwidth #padpage { width: auto; margin-left: 6px; margin-right: 6px; min-width: 800px; }
-body.squish1width #padpage { width: 900px; }
-body.squish2width #padpage { width: 800px; }
-
-#topbar { height: 25px; background: #326cbd url(/static/img/jun09/pad/padtopback2.gif) repeat-x left top;
- position: relative; }
-
-#topbarleft { float: left; height: 100%; overflow: hidden;
- background: url(/static/img/jun09/pad/padtop5.png) no-repeat left top; width: 5px; }
-#topbarright { float: right; height: 100%; overflow: hidden;
- background: url(/static/img/jun09/pad/padtop5.png) no-repeat right top; width: 5px; }
-
-.propad #topbar { background: #2c2c2c url(/static/img/jun09/pad/protop.png) repeat-x 0 -25px; }
-.propad #topbarleft { background: url(/static/img/jun09/pad/protop.png) no-repeat left top; }
-.propad #topbarright { background: url(/static/img/jun09/pad/protop.png) no-repeat right top; }
-
-/*
-a#topbarnewpad { display: block; float: left; position: relative; top: 4px; width: 94px;
- height: 0; padding-top: 26px; overflow: hidden;
- background: url(/static/img/jun09/pad/padtop5.png) no-repeat -5px -4px; }
-a#topbarnewpad:focus { outline: 0; }
-
-a#topbarfullwidth { display: block; float: right; position: relative; top: 2px; width: 107px;
- height: 0; padding-top: 27px; overflow: hidden;
- background: url(/static/img/jun09/pad/padtop5.png) no-repeat -788px -2px; }
-a#topbarfullwidth:focus { outline: 0; }
-*/
-
-a#backtoprosite, #accountnav {
- display: block; position: absolute; height: 15px; line-height: 15px;
- width: auto; top: 5px; font-size: 1.2em;
-}
-a#backtoprosite, #accountnav a { color: #cde7ff; text-decoration: underline; }
-
-a#backtoprosite { padding-left: 20px; left: 6px;
- background: url(/static/img/jun09/pad/protop.png) no-repeat -5px -6px; }
-#accountnav { right: 10px; color: #fff; }
-
-#topbarcenter { margin-left: 150px; margin-right: 150px; }
-a#topbaretherpad { margin-left: auto; margin-right: auto; display: block; width: 127px;
- position: relative; top: 0px; height: 0; padding-top: 25px;
- background: url(/static/img/jun09/pad/padtop5.png) no-repeat -397px 0px; overflow: hidden; }
-
-.propad a#topbaretherpad { background: url(/static/img/jun09/pad/protop.png) no-repeat -397px 0px; }
-
-#specialkeyarea { top: 5px; left: 250px; color: yellow; font-weight: bold;
- font-size: 1.5em; position: absolute; }
-
-#alertbar { margin-top: 6px;
-opacity: 0; filter: alpha(opacity = 0); /* IE */
-display: none;
-}
-
-#servermsg { position: relative; zoom: 1; border: 1px solid #992;
- background: #ffc; padding: 0.8em; font-size: 1.2em; }
-#servermsg h3 { font-weight: bold; margin-right: 10px;
- margin-bottom: 1em; float: left; width: auto; }
-#servermsg #servermsgdate { font-style: italic; font-weight: normal; color: #666; }
-a#hidetopmsg { position: absolute; right: 5px; bottom: 5px; }
-
-#shuttingdown { position: relative; zoom: 1; border: 1px solid #992;
- background: #ffc; padding: 0.6em; font-size: 1.2em; margin-top: 6px; }
-
-#docbar { margin-top: 6px; height: 30px; position: relative; zoom: 1;
- background: #fbfbfb url(/static/img/jun09/pad/padtopback2.gif) repeat-x 0 -31px; }
-
-#docbarleft { position: absolute; left: 0; top: 0; height: 100%;
- overflow: hidden;
- background: url(/static/img/jun09/pad/padtop5.png) no-repeat left -31px; width: 7px; }
-
-<% function docbarButton(name, width, imgleft, posright, hoverimgleft, openimgleft) {
- return ("#docbar$name$-outer { width: "+width+"px; position: absolute; height: 30px; top: 0; right: "+posright+"px; "+
- "background: url(/static/img/jun09/pad/padtop5.png) no-repeat "+(-imgleft)+"px -31px; "+
- "/* avoid IE flicker using double background */ }"+
- "a#docbar$name$ { display: block; height: 0; padding-top: 30px; position: absolute; width: 100%; "+
- "overflow: hidden; background: url(/static/img/jun09/pad/padtop5.png) no-repeat "+(-imgleft)+"px -31px; "+
- "z-index: 53; /* > .dbpanel-wrapper */} "+
- "a#docbar$name$:focus { outline: 0; } "+
- "a#docbar$name$:hover { background: url(/static/img/jun09/pad/docbarstates3.png) no-repeat "+(-hoverimgleft)+"px 0; } "+
- ".docbar$name$-opening a#docbar$name$, .docbar$name$-opening a#docbar$name$:hover, .docbar$name$-closing a#docbar$name$, .docbar$name$-closing a#docbar$name$:hover, .docbar$name$-open a#docbar$name$, .docbar$name$-open a#docbar$name$:hover { "+
- "background: url(/static/img/jun09/pad/docbarstates3.png) no-repeat "+(-openimgleft)+"px 0; } "+
- "a#docbar$name$:hover, .docbar$name$-closing a#docbar$name$ { padding-top: 29px; } "+
- ".docbar$name$-opening a#docbar$name$, .docbar$name$-opening a#docbar$name$:hover { "+
- "/* opening or closing: link covers gray line below it */ "+
- "padding-top: 30px; }"+
- ".docbar$name$-open a#docbar$name$, .docbar$name$-open a#docbar$name$:hover { "+
- "/* link covers gray line below it, and also top highlight of panel */ "+
- "padding-top: 30px; }").replace(/\$name\$/g, name);
-} %>
-
-<% // include left border, not right %>
-<%= docbarButton("savedrevs", 128, 669, 103, 123, 123) %>
-<%= docbarButton("impexp", 122, 547, 231, 0, 0) %>
-<%= docbarButton("options", 109, 438, 353, 379, 379) %>
-<%= docbarButton("security", 85, 353, 462, 489, 489) %>
-
-#docbarslider-outer { width: 104px; position: absolute; height: 30px; top: 0; right: 0;
- background: url(/static/img/jun09/pad/padtop5.png) no-repeat -796px -31px;
- /* avoid IE flicker using double background */ }
-a#docbarslider { display: block; height: 0; padding-top: 30px; position: absolute; width: 100%;
- overflow: hidden; background: url(/static/img/jun09/pad/padtop5.png) no-repeat -796px -31px; z-index: 53; /* > .dbpanel-wrapper */}
-
-<% /* changing the size of the title / rename area means adjusting
- the #docbarpadtitle.width, #padtitlebuttons.left,
- and #padtitleedit.width */ %>
-
-#docbarpadtitle { position: absolute; height: auto; left: 9px;
- width: 280px; font-size: 1.6em; color: #444; font-weight: normal;
- line-height: 22px; margin-left: 2px; height: 22px; top: 4px;
- overflow: hidden; text-overflow: ellipsis /*not supported in FF*/;
- white-space:nowrap; }
-.docbar-public #docbarpadtitle { padding-left: 22px;
- background: url(/static/img/jun09/pad/public.gif) no-repeat left center; }
-
-#docbarrenamelink { position: absolute; top: 9px;
- font-size: 1.1em; display: none; }
-#docbarrenamelink a { color: #999; }
-#docbarrenamelink a:hover { color: #48d; }
-#padtitlebuttons { position: absolute; width: 120px; zoom: 1;
- height: 22px; top: 4px; left: 223px; display: none;
- background: url(/static/img/jun09/pad/padtop5.png) -19px -35px; }
-#padtitlesave { position: absolute; display: block;
- height: 0; padding-top: 22px; overflow: hidden;
- width: 49px; left: 0; top: 0; }
-#padtitlecancel { position: absolute; display: block;
- height: 0; padding-top: 22px; overflow: hidden;
- width: 49px; right: 0; top: 0; }
-#padtitleedit { position: absolute; top: 4px; left: 5px;
- height: 17px; padding: 2px; font-size: 1.4em;
- background: white; border-left: 1px solid #c3c3c3;
- border-top: 1px solid #c3c3c3;
- border-right: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;
- width: 207px; display: none;
-}
-
-#padmain { margin-top: 6px; position: relative; zoom: 1; }
-
-#padeditor { margin-right: 300px; zoom: 1; }
-.hidesidebar #padeditor { margin-right: 0; }
-
-#editbar { height: 36px;
- background: #a5bfe2 url(/static/img/jun09/pad/editbar3.png) repeat-x left -36px; position: relative; }
-
-#editbarleft { float: left; height: 100%; overflow: hidden;
- background: url(/static/img/jun09/pad/editbar3.png) no-repeat left top; width: 3px; }
-#editbarright { float: right; height: 100%; overflow: hidden;
- background: url(/static/img/jun09/pad/editbar3.png) no-repeat right top; width: 3px; }
-
-#editbar a.editbarbutton {
- display: block;
- position: absolute;
- height: 26px;
- width: 26px;
- background-image: url(/static/img/jun09/pad/editbar3.png);
- background-color: transparent;
- background-repeat: no-repeat;
- text-decoration: none;
- top: 5px;
-}
-#editbar.disabledtoolbar a.editbarbutton {
- opacity: 0.5;
- filter: alpha(opacity = 50); /* IE */
- zoom: 1;
- cursor: auto;
-}
-/*#editbar .divider { position: absolute; width: 4px; height: 15px;
- background-image: url(/static/img/jun09/pad/editbar3.png);
- background-color: transparent; background-repeat: no-repeat; }
-#editbar .divider1 { left: 137px; top: 11px; background-position: -137px -11px; }
-#editbar .divider2 { left: 188px; top: 11px; background-position: -188px -11px; }*/
-#editbar a:focus { outline: 0; }
-
-<% function editbarButton(name, pos, width, fromRight) {
- width = width || 26;
- var bposX = - (fromRight ? 600-width-pos : pos);
- return "div#editbar a."+name+" { "+
- (fromRight?'right':'left')+": "+pos+"px; background-position: "+
- bposX+"px -5px; width: "+width+"px; }\n"+
- "div#padeditor div.enabledtoolbar a."+name+":active { background-position: "+
- bposX+"px -77px; }";
-} %>
-<%= editbarButton('bold', 7, 25) %>
-<%= editbarButton('italic', 32, 23) %>
-<%= editbarButton('underline', 55, 23) %>
-<%= editbarButton('strikethrough', 78, 24) %>
-<%= editbarButton('h1', 108, 25) %>
-<%= editbarButton('h2', 133, 23) %>
-<%= editbarButton('h3', 156, 23) %>
-<%= editbarButton('h4', 179, 23) %>
-<%= editbarButton('h5', 202, 23) %>
-<%= editbarButton('h6', 225, 24) %>
-<%= editbarButton('clearauthorship', 342) %>
-<%= editbarButton('undo', 374, 25) %>
-<%= editbarButton('redo', 399, 24) %>
-<%= editbarButton('insertunorderedlist', 255) %>
-<%= editbarButton('indent', 287, 25) %>
-<%= editbarButton('outdent', 312, 24) %>
-<%= editbarButton('save', 6, null, true) %>
-
-#editbar #syncstatussyncing { position: absolute; height: 26px; width: 26px;
- background: url(/static/img/jun09/pad/syncing2.gif) no-repeat center center;
- right: 38px; top: 5px; display: none; }
-#editbar #syncstatusdone { position: absolute; height: 26px; width: 26px;
- background: url(/static/img/jun09/pad/syncdone.gif) no-repeat center center;
- right: 38px; top: 5px; display: none; }
-
-#editorcontainerbox {
- border-left: 1px solid #c4c4c4; border-right: 1px solid #c4c4c4;
- border-bottom: 1px solid #c4c4c4;
- background: #fff; overflow: hidden; position: relative;
- zoom: 1; height: 397px; /*...initially*/ }
-
-#editorcontainer { height: 100%; }
-
-#editorcontainer iframe { width: 100%; padding: 0; margin: 0; }
-
-#editorloadingbox { padding-top: 100px; padding-bottom: 100px; font-size: 2.5em; color: #aaa;
- text-align: center; position: absolute; width: 100%; height: 30px; z-index: 100; }
-
-#padsidebar { float: right; width: 290px; }
-.hidesidebar #padsidebar { width: 0; overflow: hidden; }
-
-#padusers { border: 1px solid #c4c4c4; background: #fafafa; position: relative; zoom: 1; }
-
-#myuser { background: #d9e7f9; padding: 5px; height: 53px; position: relative; }
-#myswatchbox { position: absolute; left: 5px; top: 5px; width: 22px; height: 22px;
- /*border-top: 1px solid #c3cfe0; border-left: 1px solid #c3cfe0;
- border-right: 1px solid #ecf3fc; border-bottom: 1px solid #ecf3fc;*/
- border: 1px solid #bbb;
- padding: 1px; background: transparent; cursor: pointer; }
-#myuser .myswatchboxhoverable, #myuser .myswatchboxunhoverable {
- background: white;
-}
-#myuser .myswatchboxhoverable:hover {
- background: #bbb;
-}
-#myswatch { width: 100%; height: 100%; background: transparent;/*...initially*/ }
-#mycolorpicker {
- background: url(/static/img/jun09/pad/colorpicker.gif) no-repeat left top;
- width: 232px; height: 76px;
- position: absolute;
- left: 13px; top: 13px; z-index: 101;
- display: none;/*...initially*/
-}
-#mycolorpicker .n1 { left: 13px; }
-#mycolorpicker .n2 { left: 40px; }
-#mycolorpicker .n3 { left: 67px; }
-#mycolorpicker .n4 { left: 94px; }
-#mycolorpicker .n5 { left: 121px; }
-#mycolorpicker .n6 { left: 148px; }
-#mycolorpicker .n7 { left: 175px; }
-#mycolorpicker .n8 { left: 202px; }
-#mycolorpicker .pickerswatchouter {
- border: 1px solid white;
- width: 15px; height: 15px; position: absolute;
- top: 12px;
-}
-#mycolorpicker .pickerswatch {
- border: 1px solid #999;
- width: 13px;
- height: 13px;
- position: absolute;
- left: 0; top: 0;
-}
-#mycolorpicker .picked { border: 1px solid #666 !important; }
-#mycolorpicker .picked .pickerswatch { border: 1px solid #666; }
-#mycolorpickersave { position: absolute; left: 14px; top: 42px;
- width: 47px; height: 0; padding-top: 20px; overflow: hidden;
- cursor: pointer; }
-#mycolorpickercancel { position: absolute; left: 87px; top: 42px;
- width: 44px; height: 0; padding-top: 20px; overflow: hidden;
- cursor: pointer; }
-#myusernameform { margin-left: 35px; }
-#myusernameedit { font-size: 1.6em; color: #444;
- padding: 3px; height: 18px; margin: 0; border: 0;
- width: 197px; background: transparent; }
-#myusernameform input.editable { border: 1px solid #bbb; }
-#myuser .myusernameedithoverable:hover { background: white; }
-#mystatusform { margin-left: 35px; margin-top: 5px; }
-#mystatusedit { font-size: 1.2em; color: #777;
- font-style: italic; display: none;
- padding: 2px; height: 14px; margin: 0; border: 1px solid #bbb;
- width: 199px; background: transparent; }
-#myusernameform .editactive, #myusernameform .editempty {
- background: white; border-left: 1px solid #c3c3c3;
- border-top: 1px solid #c3c3c3;
- border-right: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;
-}
-#myusernameform .editempty { color: #ef641e; }
-
-#otherusers {
- height: 100px;/*...initially*/
- overflow: auto;
-}
-
-table#otheruserstable { display: none; }
-#nootherusers { padding: 10px; font-size: 1.2em; color: #999; font-weight: bold;}
-#nootherusers a { color: #48d; }
-
-#otheruserstable td {
- border-bottom: 1px solid #e1e1e1;
- height: 26px;
- vertical-align: middle;
- padding: 0 2px;
-}
-
-#otheruserstable .swatch {
- border: 1px solid #999; width: 13px; height: 13px; overflow: hidden;
- margin: 0 4px;
-}
-
-.usertdswatch { width: 1%; }
-.usertdname { font-size: 1.3em; color: #444; }
-.usertdstatus { font-size: 1.1em; font-style: italic; color: #999; }
-.usertdactivity { font-size: 1.1em; color: #777; }
-
-.usertdname input { border: 1px solid #bbb; width: 80px; padding: 2px; }
-.usertdname input.editactive, .usertdname input.editempty {
- background: white; border-left: 1px solid #c3c3c3;
- border-top: 1px solid #c3c3c3;
- border-right: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;
-}
-.usertdname input.editempty { color: #888; font-style: italic;}
-
-#userlistbuttonarea { height: 28px; position: relative;
- background: url(/static/img/jun09/pad/inviteshare2.gif) repeat-x 0 0; }
-#sharebutton {
- background: url(/static/img/jun09/pad/inviteshare2.gif) no-repeat 0 -31px;
- position: absolute; display: block; top: 3px; padding-top: 23px;
- height: 0; overflow: hidden; width: 96px; left: 96px; }
-
- /*#guestslabel { font-size: 1.2em; position: absolute; width: auto;
- height: 22px; line-height: 22px; top: 4px; left: 8px; }
-#guestsmenu { font-size: 1.2em; position: absolute; left: 100px;
- top: 5px; width: 95px; }
-.guestpolicystuff { display: none; }*/
-
-.guestprompt { border: 1px solid #ccc; font-size: 1.2em;
- padding: 5px; color: #222; background: #ffc; }
-.guestprompt .choices { float: right; }
-.guestprompt a { margin: 0 0.5em; }
-
-#hdraggie {
- background: url(/static/img/jun09/pad/hdraggie.gif) repeat-x center top;
- height: 10px; cursor: S-resize; }
-
-#padchat { border: 1px solid #c4c4c4; }
-
-#chattop { background: #ecf2fa; padding: 5px; font-size: 1.2em; border-bottom: 1px solid #ddd; }
-#chattop a { color: #36b; }
-#chatlines { height: 198px;/*...initially*/ overflow: auto; background: #fafafa; position: relative; }
-#chatlines .chatline { color: #444; padding-left: 5px; padding-top: 2px; padding-bottom: 2px;
- background: #ddd; overflow: hidden; }
-#chatlines .chatlinetime { display: block; font-size: 1em; color: #666; float: right; width: auto;
- padding-right: 5px; }
-#chatlines .chatlinename, #chatlines .chatlinetext { font-size: 1.2em; }
-#chatlines h2 { margin: 0; padding-left: 5px; padding-top: 2px; padding-bottom: 2px; color: #999; font-style: italic; font-weight: bold; font-size: 1.2em; }
-#chatbottom { background: #ecf2fa; padding: 4px; }
-#chatprompt { font-size: 1.2em; color: #444; float: left; line-height: 22px; width: 35px; text-align: right; }
-#chatentryform { margin-left: 40px; }
-#chatentrybox { font-size: 1.2em; color: #444;
- padding: 2px; height: 16px; margin: 0; border-left: 1px solid #c3c3c3;
- border-top: 1px solid #c3c3c3;
- border-right: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;
- width: 230px; }
-#padchat a#chatloadmore { display: none; font-size: 1.2em; padding: 2px 5px; font-style: italic; }
-#padchat #chatloadingmore { display: none; font-size: 1.2em; padding: 2px 5px; font-style: italic;
- color: #999; }
-#padchat a#chatloadmore:focus { outline: 0; }
-
-#djs { font-family: monospace; font-size: 10pt;
- height: 200px; overflow: auto; border: 1px solid #ccc;
- background: #fee; margin: 0; padding: 6px;
-}
-#djs p { margin: 0; padding: 0; display: block; }
-
-#connectionbox {
- position: absolute; left: 0; top: 0; width: 100%;
- height: 191px;/*...initially; #padusers height */
- z-index: 10; zoom: 1; overflow: hidden;
-}
-#connectionboxinner {
- position: relative; width: 100%; height: 100%; overflow: hidden;
-}
-.cboxconnecting #connectionboxinner {
- background: #ffd url(/static/img/jun09/pad/connectingbar.gif) no-repeat center 60px;
-}
-.cboxreconnecting #connectionboxinner {
- background: #fed url(/static/img/jun09/pad/connectingbar.gif) no-repeat center 60px;
-}
-.cboxdisconnected #connectionboxinner {
- background: #fdd;
-}
-.cboxdisconnected #connectionboxinner div { display: none; }
-.cboxdisconnected_userdup #connectionboxinner #disconnected_userdup { display: block; }
-.cboxdisconnected_initsocketfail #connectionboxinner #disconnected_initsocketfail { display: block; }
-.cboxdisconnected_looping #connectionboxinner #disconnected_looping { display: block; }
-.cboxdisconnected_slowcommit #connectionboxinner #disconnected_slowcommit { display: block; }
-.cboxdisconnected_unauth #connectionboxinner #disconnected_unauth { display: block; }
-.cboxdisconnected_unknown #connectionboxinner #disconnected_unknown { display: block; }
-.cboxdisconnected_initsocketfail #connectionboxinner #reconnect_advise,
-.cboxdisconnected_looping #connectionboxinner #reconnect_advise,
-.cboxdisconnected_slowcommit #connectionboxinner #reconnect_advise,
-.cboxdisconnected_unknown #connectionboxinner #reconnect_advise { display: block; }
-.cboxdisconnected div#reconnect_form { display: block; }
-.cboxdisconnected .disconnected h2 { display: none; }
-.cboxdisconnected .disconnected .h2_disconnect { display: block; }
-.cboxdisconnected_userdup .disconnected h2.h2_disconnect { display: none; }
-.cboxdisconnected_userdup .disconnected h2.h2_userdup { display: block; }
-.cboxdisconnected_unauth .disconnected h2.h2_disconnect { display: none; }
-.cboxdisconnected_unauth .disconnected h2.h2_unauth { display: block; }
-
-#connectionstatus {
- position: absolute; width: 37px; height: 32px; overflow: hidden;
- right: 0;
- z-index: 11;
-}
-#connectionboxinner .connecting {
- margin-top: 20px;
- font-size: 2.0em; color: #555;
- text-align: center; display: none;
-}
-.cboxconnecting #connectionboxinner .connecting { display: block; }
-
-#connectionboxinner .disconnected h2 {
- font-size: 1.8em; color: #333;
- text-align: left;
- margin-top: 10px; margin-left: 10px; margin-right: 10px;
- margin-bottom: 10px;
-}
-#connectionboxinner .disconnected p {
- margin: 10px 10px;
- font-size: 1.2em;
- line-height: 1.1;
- color: #333;
-}
-#connectionboxinner .disconnected { display: none; }
-.cboxdisconnected #connectionboxinner .disconnected { display: block; }
-
-#connectionboxinner .reconnecting {
- margin-top: 20px;
- font-size: 1.6em; color: #555;
- text-align: center; display: none;
-}
-.cboxreconnecting #connectionboxinner .reconnecting { display: block; }
-
-#reconnect_form button {
- position: relative; width: 268px; height: 28px; left: 10px;
- font-size: 12pt;
-}
-
-/* We give docbar a higher z-index than its descendant impexp-wrapper in
- order to allow the Import/Export panel to be on top of stuff lower
- down on the page in IE. Strange but it works! */
-#docbar { z-index: 52; }
-
-#impexp-wrapper { width: 500px; right: 10px; }
-#impexp-panel { height: 160px; }
-.docbarimpexp-closing #impexp-wrapper { z-index: 50; }
-
-#savedrevs-wrapper { width: 100%; left: 0; }
-#savedrevs-panel { height: 79px; }
-.docbarsavedrevs-closing #savedrevs-wrapper { z-index: 50; }
-#savedrevs-wrapper .dbpanel-rightedge { background-position: 0 -10px; }
-
-#options-wrapper { width: 340px; right: 200px; }
-#options-panel { height: 114px; }
-.docbaroptions-closing #options-wrapper { z-index: 50; }
-
-#security-wrapper { width: 320px; right: 300px; }
-#security-panel { height: 130px; }
-.docbarsecurity-closing #security-wrapper { z-index: 50; }
-
-#revision-notifier { position: absolute; right: 8px; top: 25px;
- width: auto; height: auto; font-size: 1.2em; background: #ffc;
- border: 1px solid #aaa; color: #444; padding: 3px 5px;
- display: none; z-index: 55; }
-#revision-notifier .label { color: #777; font-weight: bold; }
-
-/* We don't ever actually hide the wrapper, even when the panel is
- cloased, so that its contents can always be manipulated accurately. */
-.dbpanel-wrapper { position: absolute;
- overflow: hidden; /* animated: */ height: 0; top: 30px; /* /animated */
- z-index: 51; zoom: 1; }
-.dbpanel-panel { position: absolute; bottom: 0; width: 100%; }
-
-.dbpanel-middle { margin-left: 7px; margin-right: 7px;
- position: relative; height: 100%; overflow: hidden; zoom: 1; }
-.dbpanel-inner { background: #f7f7f7 /* covered up by images */;
- width: 100%; height: 100%; position: absolute; overflow: hidden; top: -10px; }
-
-.dbpanel-top { position: absolute; top: 0; width: 100%;
- height: 400px; background-image: url(/static/img/jun09/pad/docpanelmiddle2.png);
- background-position: left top; }
-
-.dbpanel-bottom { position: absolute; height: 400px;
- bottom: -390px; width: 100%;
- background-image: url(/static/img/jun09/pad/docpanelmiddle2.png);
- background-position: left top;
-}
-
-* html .dbpanel-top, * html .dbpanel-bottom { /* for IE 6+ */
- background-color: transparent;
- background-image: url(/static/img/apr09/blank.gif);
- /* scale the image instead of repeating, but it amounts to the same */
- filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/static/img/jun09/pad/docpanelmiddle2.png", sizingMethod="scale");
-}
-
-.dbpanel-leftedge, .dbpanel-rightedge, .dbpanel-botleftcorner, .dbpanel-botrightcorner {
- position: absolute;
- background-repeat: no-repeat;
- background-color: transparent;
- background-image: url(/static/img/jun09/pad/docpaneledge2.png);
-}
-
-.dbpanel-leftedge, .dbpanel-rightedge { height: 100%; width: 7px; bottom: 11px; }
-.dbpanel-botleftcorner, .dbpanel-botrightcorner { height: 11px; width: 7px; bottom: 0; }
-
-.dbpanel-leftedge, .dbpanel-botleftcorner { left: 0; background-position: -7px 0; }
-.dbpanel-rightedge, .dbpanel-botrightcorner { right: 0; background-position: 0 0; }
-
-#importexport { position: absolute; top: 5px; left: 0; font-size: 1.2em; color: #444;
- height: 100%; width: 100%; }
-
-* html .dbpanel-leftedge, * html .dbpanel-rightedge, * html .dbpanel-botleftcorner, * html .dbpanel-botrightcorner {
- background-color: transparent;
- background-image: url(/static/img/apr09/blank.gif);
- /* crop the image */
- filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/static/img/jun09/pad/docpaneledge2.png", sizingMethod="crop");
-}
-* html .dbpanel-leftedge, * html .dbpanel-botleftcorner { left: -7px; width: 14px; }
-
-#impexp-importlabel { position: absolute; top: 5px; left: 10px; width: 300px; }
-
-#importform { position: absolute; top: 24px; left: 5px; width: 300px; height: 60px; }
-#importformsubmitdiv, #importformfilediv { padding: 5px 5px; }
-#importexport .importformenabled {
- background: #cfc;
- border: 1px solid #292;
-}
-#importexport span.nowrap { white-space: nowrap; }
-#importexport #importstatusball { margin-left: 3px; padding-top: 1px; display: none; }
-#importexport #importarrow { margin-left: 5px; padding-top: 1px; display: none; }
-#importexport .importmessage { border: 1px solid #992;
- background: #ffc; padding: 5px; font-size: 85%; display: none; }
-#importexport #importmessagefail { margin-top: 5px; }
-#importexport #importmessagesuccess { margin: 0 20px; }
-#importexport a.disabledexport {
- color: #333; text-decoration: none;
- opacity: 0.5; filter: alpha(opacity = 50) /*IE*/;
-}
-#importexport #importfileinput { padding: 2px 0; }
-#importexport #importsubmitinput { padding: 2px; }
-
-#impexp-divider { position: absolute; left: 320px; top: 5px; height: 135px; width: 2px;
- background: #ddd; }
-#impexp-close { display: block; position: absolute; right: 2px; bottom: 15px;
- width: auto; height: auto; font-size: 85%; color: #444;
- z-index: 61 /* > clickcatcher */}
-#impexp-disabled-clickcatcher {
- display: none;
- position: absolute; width: 100%; height: 100%;
- z-index: 60;
-}
-
-#impexp-exportlabel { position: absolute; top: 5px; left: 350px;
- width: 300px; }
-#exportlinks .exportlink {
- display: block; position: absolute; height: 22px; width: auto;
- background-repeat: no-repeat;
- background-image: url(/static/img/jun09/pad/fileicons.gif);
- line-height: 22px; padding-left: 22px; padding-right: 2px;
-}
-#exportlinks .n1 { left: 350px; top: 30px; }
-#exportlinks .n2 { left: 350px; top: 57px; }
-#exportlinks .n3 { left: 350px; top: 84px; }
-#exportlinks .n4 { left: 485px; top: 30px; }
-#exportlinks .n5 { left: 485px; top: 57px; }
-#exportlinks .n6 { left: 485px; top: 84px; }
-#exportlinks .exporthrefdoc { background-position: 2px -1px; }
-#exportlinks .exporthrefhtml { background-position: 2px -25px; }
-#exportlinks .exporthreflink { background-position: 2px -49px; }
-#exportlinks .exporthrefodt { background-position: 2px -73px; }
-#exportlinks .exporthrefpdf { background-position: 2px -97px; }
-#exportlinks .exporthreftxt { background-position: 2px -121px; }
-
-#savedrevisions { position: absolute; top: 0; left: 0; font-size: 1.2em;
- color: #444; height: 100%; width: 100%; }
-#savedrevs-scrolly { height: 75px; width: auto; margin-right: 136px;
- overflow: hidden; position: relative; top: 1px;
-}
-#savedrevs-scrollleft { height: 100%; width: 14px; position: absolute;
- left: 0; top: 0; cursor: pointer;
- background: url(/static/img/jun09/pad/savedrevarrows.gif) no-repeat right top;
-}
-#savedrevs-scrollright { height: 100%; width: 14px; position: absolute;
- right: 0; top: 0; cursor: pointer;
- background: url(/static/img/jun09/pad/savedrevarrows.gif) no-repeat left top;
-}
-#savedrevs-scrolly .disabledscrollleft { background-position: right bottom; }
-#savedrevs-scrolly .disabledscrollright { background-position: left bottom; }
-#savedrevs-scrollouter { margin-left: 14px; margin-right: 14px;
- width: auto; height: 100%; overflow: hidden; position: relative;
-}
-#savedrevs-scrollinner { position: absolute; width: 1px; height: 100%;
- overflow: visible; right: 0/*...initially*/; top: 0; }
-#savedrevisions .srouterbox { width: 120px; height: 100%;
- position: absolute; top: 0;
-}
-#savedrevisions .srinnerbox { position: relative; top: 8px;
- height: 59px; width: auto; border-left: 1px solid #ddd;
- padding: 0 8px 0 8px; }
-#savedrevisions a.srname { display: block; white-space: nowrap;
- text-overflow: ellipsis /*no FF support*/; overflow: hidden;
- text-decoration: none; color: #444; cursor: text;
- padding: 1px; height: 14px; position: relative; left: -1px;
- width: 100px /*specify for proper overflow in IE*/;
-}
-#savedrevisions a.srname:hover { text-decoration: none; color: #444;
- border: 1px solid #ccc; padding: 0; }
-#savedrevisions .sractions { font-size: 85%; color: #ccc;
- margin-top: 1px; height: 12px; }
-#savedrevisions .sractions a { text-decoration: none;
- color: #06c; }
-#savedrevisions .sractions a:hover { text-decoration: underline; }
-#savedrevisions .srtime { color: #666; font-size: 90%;
- white-space: nowrap; margin-top: 3px; }
-#savedrevisions .srauthor { color: #666; font-size: 90%;
- white-space: nowrap; overflow: hidden; text-overflow: ellipsis /*no FF*/;
-}
-#savedrevisions .srtwirly { position: absolute; display: block;
- bottom: 0; right: 10px; display: none; }
-#savedrevisions .srnameedit {
- position: absolute;
-}
-#savedrevs-savenow { display: block; position: absolute;
- overflow: hidden; height: 0; padding-top: 24px; width: 81px;
- top: 22px; right: 27px;
- background: url(/static/img/jun09/pad/savedrevsgfx2.gif) no-repeat 0 0;
-}
-#savedrevs-savenow:active { background-position: 0 -24px; }
-#savedrevs-close { display: block; position: absolute; right: 7px; bottom: 8px;
- width: auto; height: auto; font-size: 85%; color: #444; }
-form#reconnectform { display: none; }
-
-#padoptions { position: absolute; top: 0; left: 0; font-size: 1.2em;
- color: #444; height: 100%; width: 100%; line-height: 15px; }
-#options-viewhead { font-weight: bold; position: absolute; top: 10px; left: 15px;
- width: auto; height: auto; }
-#padoptions label { display: block; }
-#padoptions input { padding: 0; margin: 0; }
-#options-colorscheck { position: absolute; left: 15px; top: 34px; width: 15px; height: 15px; }
-#options-colorslabel { position: absolute; left: 35px; top: 34px; }
-#options-linenoscheck { position: absolute; left: 15px; top: 57px; width: 15px; height: 15px; }
-#options-linenoslabel { position: absolute; left: 35px; top: 57px; }
-#options-fontlabel { position: absolute; left: 15px; top: 82px; }
-#viewfontmenu { position: absolute; top: 80px; left: 90px; width: 110px; }
-#options-viewexplain { position: absolute; left: 215px; top: 15px; width: 100px; height: 70px;
- padding-left: 10px; padding-top: 10px; border-left: 1px solid #ccc;
- line-height: 20px; font-weight: bold; color: #999; }
-#options-close { display: block; position: absolute; right: 7px; bottom: 8px;
- width: auto; height: auto; font-size: 85%; color: #444; }
-
-#padsecurity { position: absolute; top: 0; left: 0; font-size: 1.2em;
- color: #444; height: 100%; width: 100%; line-height: 15px; }
-#security-close { display: block; position: absolute; right: 7px; bottom: 8px;
- width: auto; height: auto; font-size: 85%; color: #444; }
-#security-passhead { font-weight: bold; position: absolute; top: 90px; left: 15px;
- width: auto; height: auto; }
-#security-passbody { position: absolute; left: 75px; top: 90px; }
-#security-passwordedit { height: 15px; border: 1px solid #bbb;
- position: absolute; top: 0; left: 15px; width: 120px; }
-#security-password a { text-decoration: none; display: block;
- width: auto; height: auto; }
-#password-savelink, #password-cancellink {position: absolute; top: 0; }
-#security-password a:hover { text-decoration: underline; }
-#password-savelink { left: 144px; color: #06c; }
-#password-cancellink { left: 180px; color: #666; }
-#password-nonedit { left: 15px; position: absolute;
- width: 220px; top: 0; }
-#password-setlink { color: #06c; }
-#password-clearlink { color: #06c; }
-#password-display { height: 15px; width: auto; }
-#password-inedit { display: none; }
-#password-display, #password-setlink, #password-clearlink {
- float: left; margin-right: 10px;
-}
-#password-display { font-size: 18px; }
-#security-password .nopassword #password-display { font-size: 100%; }
-#security-password .nopassword #password-clearlink { display: none; }
-#security-password .nopassword #password-setlink { left: 60px; }
-
-#security-access { position: absolute; left: 15px; width: 200px; }
-#security-accesshead { font-weight: bold; position: absolute; top: 10px;
- left: 0; width: auto; height: auto; }
-#security-access input, #security-access label { position: absolute; }
-#security-access input { left: 10px; }
-#security-access label { left: 30px; width: 250px; }
-#access-private, #access-private-label { top: 35px; }
-#access-public, #access-public-label { top: 60px; }
-#security-access label { color: #999; }
-#security-access label strong { font-weight: normal; padding-right: 10px;
- color: #444; }
-
-#mainmodals { z-index: 600; /* higher than the modals themselves
- so that modals are on top in IE */ }
-
-.modalfield { font-size: 1.2em; padding: 1px; border: 1px solid #bbb;
- position: absolute;}
-#mainmodals .editempty { color: #aaa; }
-
-<% feedbackbox = {width:400, height:270}; %>
-#feedbackbox {
- position: absolute; display: none;
- width: <%=feedbackbox.width%>px; height: <%=feedbackbox.height%>px;
- left: 100px/*set in code*/; bottom: 50px;
- z-index: 501; zoom: 1;
-}
-#feedbackbox-tl, #feedbackbox-tr, #feedbackbox-bl, #feedbackbox-br,
-#feedbackbox-hide, #feedbackbox-send, #feedbackbox-back {
- position: absolute; display: block;
- background-repeat: no-repeat;
- background-image: url(/static/img/jun09/pad/feedbackbox2.gif);
-}
-#feedbackbox-tl { width: <%=feedbackbox.width-8%>px;
- height: <%=feedbackbox.height-8%>px; left: 0; top: 0;
- background-position: left top; }
-#feedbackbox-tr { width: 8px; height: <%=feedbackbox.height-8%>px;
- right: 0; top: 0; background-position: right top; }
-#feedbackbox-bl { width: <%=feedbackbox.width-8%>px;
- height: 8px; left: 0; bottom: 0;
- background-position: left bottom; }
-#feedbackbox-br { width: 8px; height: 8px; bottom: 0; right: 0;
- background-position: right bottom; }
-#feedbackbox-hide { width: 22px; height: 22px; right: 9px; top: 7px;
- background-position: -569px -6px;
-}
-#feedbackbox-back { width: <%=feedbackbox.width-16%>px;
- height: <%=feedbackbox.height-16%>px; left: 8px; top: 8px;
- background-position: -8px -8px;
- background-color: white; }
-#feedbackbox-contents { width: <%=feedbackbox.width-16%>px;
- height: <%=feedbackbox.height-16%>px; left: 8px; top: 8px;
- position: absolute; font-size: 1.4em; color: #444; }
-#feedbackbox-contentsinner { padding: 10px; }
-#feedbackbox-send { width: 50px; height: 22px; right: 15px; bottom: 15px;
- background-position: -535px -363px;
-}
-#feedbackbox-email { left: 90px; top: 48px; width: 356px; height: auto; }
-#feedbackbox-message { left: 90px; top: 84px; width: 358px; height: 100px; }
-#feedbackbox-response { position: absolute; bottom: 15px; left: 15px;
- width: 390px; height: auto; font-size: 1.2em; display: none; }
-#feedbackbox .goodresponse { font-weight: bold; color: green; }
-#feedbackbox .badresponse { font-weight: bold; color: red; }
-#feedbackbox p { margin-bottom: 1em; }
-#feedbackbox ul { margin: 1em 0 1em 2em }
-#feedbackbox li { padding: 0.3em 0; }
-#feedbackbox li a { display: block; font-weight: bold; }
-#feedbackbox li a:hover { background: #ffe; }
-#feedbackbox a, #feedbackbox li a:visited { color: #47b; }
-#feedbackbox tt { font-size: 110%; }
-
-<% var shareboxfull = {width:485, height:326}; %>
-#sharebox {
- position: absolute;
- width: 485px;
- left: 300px/*set in code*/; top: 100px; display: none;
- z-index: 501; zoom: 1;
- overflow: hidden;
- background: white; border: 1px solid #999;
-}
-#sharebox { height: 160px/*set in code*/; }
-.nonprouser #sharebox { height: 110px/*set in code*/; }
-#sharebox-inner { width: 100%; }
-#sharebox-forms { position: absolute; top: 50px; width: 100%; }
-#sharebox-hide, #sharebox-send {
- position: absolute; background-repeat: no-repeat;
- background-image: url(/static/img/jun09/pad/sharebox4.gif);
-}
-#sharebox-hide, #sharebox-send { display: block; }
-#sharebox-hide { width: 22px; height: 22px; right: 9px; top: 7px;
- background-position: <%= -(shareboxfull.width-31) %>px -6px;
-}
-#sharebox-send { width: 87px; height: 22px; right: 15px; top: <%= shareboxfull.height-22-15 %>px;
- background-position: <%= -(shareboxfull.width-87-15) %>px <%= -(shareboxfull.height-22-15) %>px;
-}
-#sharebox-url { position: absolute; left: 20px; top: 42px; width: 440px; height: 18px;
- text-align: left; font-size: 1.3em; line-height: 18px; padding: 2px; }
-
-#sharebox-to { left: 90px; top: 117px; height: auto; width: 378px; background: #ffe; }
-#sharebox-subject { left: 90px; top: 150px; height: auto; width: 378px; font-weight: bold; }
-#sharebox-message { left: 90px; top: 182px; width: 380px; height: 90px; }
-#sharebox-response { position: absolute; bottom: 15px; left: 15px;
- width: 350px; height: auto; font-size: 1.2em; display: none; }
-#sharebox .goodresponse { font-weight: bold; color: green; }
-#sharebox .badresponse { font-weight: bold; color: red; }
-#sharebox-dislink { position: absolute; left: 12px; top: 78px;
- height: 22px; width: 220px; cursor: pointer;
- background-image: url(/static/img/jun09/pad/sharedistri.gif);
- background-repeat: no-repeat;
- background-position: 0 5px;
-}
-.sharebox-open #sharebox-dislink { background-position: 0 -28px; }
-#sharebox-shownwhenexpanded { display: none; }
-.sharebox-open #sharebox-shownwhenexpanded { display: block; }
-
-#sharebox-pastelink { font-size: 155%; font-weight: bold;
- top: 13px; left: 17px; position: absolute; color: #444; }
-#sharebox-orsend { font-size: 145%; font-weight: bold;
- top: 80px; left: 31px; position: absolute; color: #444; }
-#sharebox-fieldname-to, #sharebox-fieldname-subject, #sharebox-fieldname-message {
- position: absolute; font-weight: bold; font-size: 125%;
- left: 15px; color: #222;
-}
-#sharebox-fieldname-to { top: 119px; }
-#sharebox-fieldname-subject { top: 152px; }
-#sharebox-fieldname-message { top: 183px; }
-
-#sharebox-stripe { position: absolute; left: 10px;
- width: 436px; top: 8px; height: 45px; line-height: 1.2; }
-#sharebox-stripe div { padding: 5px; font-size: 130%; }
-#sharebox-stripe strong { font-weight: bold; }
-.sharebox-stripe-public { background: #cfc; }
-.sharebox-stripe-private { background: #fec; }
-.sharebox-stripe-public .private { display: none; }
-.sharebox-stripe-private .public { display: none; }
-#sharebox-stripe a { color: #06c; }
-
-.nonprouser #sharebox-stripe { display: none; }
-.nonprouser #sharebox-forms { top: 0; }
-
-#viewbarcontents { display: none; }
-#viewzoomtitle {
- position: absolute; left: 10px; top: 4px; height: 20px; line-height: 20px;
- width: auto;
-}
-#viewzoommenu {
- position: absolute; top: 3px; left: 50px;
- width: 65px;
-}
-#bottomarea { height: 28px; overflow: hidden; position: relative;
- font-size: 1.2em; color: #444; }
-#widthprefcheck { position: absolute;
- background-image: url(/static/img/jun09/pad/layoutbuttons.gif);
- background-repeat: no-repeat; cursor: pointer;
- width: 86px; height: 20px; top: 4px; right: 2px; }
-.widthprefunchecked { background-position: -1px -1px; }
-.widthprefchecked { background-position: -1px -23px; }
-#sidebarcheck { position: absolute;
- background-image: url(/static/img/jun09/pad/layoutbuttons.gif);
- background-repeat: no-repeat; cursor: pointer;
- width: 86px; height: 20px; top: 4px; right: 90px; }
-.sidebarunchecked { background-position: -1px -45px; }
-.sidebarchecked { background-position: -1px -67px; }
-#feedbackbutton { display: block; position: absolute; width: 68px;
- height: 0; padding-top: 17px; overflow: hidden;
- background: url(/static/img/jun09/pad/bottomareagfx.gif);
- top: 5px; right: 220px;
-}
-
-#modaloverlay {
- z-index: 500; display: none;
- background-image: url(/static/img/jun09/pad/overlay2.png);
- background-repeat: repeat-both;
- width: 100%; position: absolute;
- height: 400px; left: 0; top: 0;
-}
-
-* html #modaloverlay { /* for IE 6+ */
- opacity: 1; /* in case this is looked at */
- background-image: none;
- background-repeat: no-repeat;
- /* scale the image */
- filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/static/img/jun09/pad/overlay2.png", sizingMethod="scale");
-}
diff --git a/trunk/etherpad/src/static/css/pne-manual.css b/trunk/etherpad/src/static/css/pne-manual.css
deleted file mode 100644
index 19f1ba0..0000000
--- a/trunk/etherpad/src/static/css/pne-manual.css
+++ /dev/null
@@ -1,143 +0,0 @@
-/* global */
-
-div.pne-manpage {
- font-size: 1.1em;
-}
-
-.pne-manual-topnav {
- border-bottom: 1px solid #ccc;
- margin-bottom: 1em;
- padding-bottom: 4px;
-}
-
-div.pne-manpage h2 {
- color: #111;
- border-bottom: 1px solid #111;
-}
-
-div.pne-manpage ul,ol {
- padding-left: 2em;
-}
-div.pne-manpage li {
- margin-top: .4em;
-}
-div.pne-manpage ol li {
- list-style: decimal;
- margin-top: 1em;
-}
-
-
-div.pne-manpage tt {
- font-family: monospace;
- font-size: 1.1em;
- color: #040;
- font-style: italic;
-}
-
-div.pne-manpage div.code {
- font-family: monospace;
- font-size: 1.0em;
- padding: 0 1em;
- border: 1px solid #ccc;
- background: #eee;
- margin: 0;
-}
-
-div.pne-manpage div.code span.prompt {
- color: #609;
-}
-
-div.pne-manpage div.code tt {
- font-style: normal;
- font-size: 1.0em;
- color: #00f;
-}
-
-div.pne-manpage div.code p {
- line-height: 125%;
- margin: 1em 0;
- padding: 0;
-}
-
-/* main */
-
-div#pne-main h2 {
- font-size: 1.4em;
- color: black;
- font-weight: bold;
- border: 0;
- margin: 0;
- padding: 0;
-}
-div#pne-main h3 {
- font-size: 1.1em;
- color: #555;
- font-style: italic;
-}
-div#pne-main h4 {
- color: #888;
- margin-top: 2em;
- font-weight: bold;
-}
-div#pne-main ul {
- padding-left: 2em;
-}
-div#pne-main ul li {
- list-style: square;
-}
-div#pne-main p#version-notice {
- font-size: 88%;
- color: #333;
- margin-top: 2em;
- border-top: 1px solid #ccc;
-}
-
-/* configuration-guide */
-
-table#opts {
- width: 100%;
- border-top: 1px solid #ccc;
- border-left: 1px solid #ccc;
- border-right: 0;
- border-bottom: 0;
- margin: 2em 0 1em 0;
-}
-table#opts td, table#opts th {
- padding: 4px 0;
- border-right: 1px solid #ccc;
- border-bottom: 1px solid #ccc;
-}
-table#opts td {
- font-family: monospace;
-}
-table#opts td.desc {
- font-family: Verdana, sans-serif;
-}
-table#opts th {
- text-align: left;
- font-weight: bold;
-}
-table#opts td.rowhead {
- padding-top: 1em;
- font-style: italic;
- color: #222;
- border-bottom: 1px solid #222;
-}
-
-/* changelog */
-
-div#pne-changelog h2 {
- margin-top: 2em;
-}
-
-div#pne-changelog h3 {
- font-weight: bold;
- padding-left: 1em;
- margin: 1em 0;
-}
-
-div#pne-changelog ul {
- padding-left: 3em;
-}
-
-
diff --git a/trunk/etherpad/src/static/css/pricing.css b/trunk/etherpad/src/static/css/pricing.css
deleted file mode 100644
index 0b7c9d5..0000000
--- a/trunk/etherpad/src/static/css/pricing.css
+++ /dev/null
@@ -1,153 +0,0 @@
-/*----------------------------------------------------------------*/
-/* pricing */
-/*----------------------------------------------------------------*/
-
-div.pricingpage {
-}
-
-.pricingpage form#pricingcontact {
- display: block;
- margin: 1em 0;
- background: #eee;
- border: 1px solid #ccc;
- padding: 1em;
-}
-.pricingpage form#pricingcontact p { margin: .75em 0; font-weight: bold; }
-.pricingpage form#pricingcontact ul li { list-style: none; margin: 0;}
-
-.pricingpage .eepnet-inquiry label {
- display: block;
- float: left;
- width: 140px;
- text-align: right;
- font-weight: normal;
- color: #444;
-}
-.pricingpage .eepnet-inquiry input.ti,
-.pricingpage .eepnet-inquiry select {
- width: 240px;
- margin-left: 12px;
-}
-.pricingpage .eepnet-inquiry button {
- width: 100px;
- margin-left: 160px;
-}
-.pricingpage div.inquiryhead {
- font-weight: bold;
- color: #000;
- margin-bottom: 1em;
- border-bottom: 2px solid #aaa;
-}
-
-.pricingpage div#errorbox, .pricingpage div#confirmbox {
- color: #222;
- font-weight: bold;
- padding: 1em .5em;
-}
-.pricingpage div#errorbox {
- background: #fee;
- border: 1px solid #f66;
-}
-.pricingpage div#confirmbox {
- background: #efe;
- border: 1px solid #ccc;
-}
-
-a.pricingbox {
- display: block;
- height: 280px;
- border: 1px solid #777;
- background: #fcfcfc;
- cursor: pointer;
- text-align: center;
- text-decoration: none;
-}
-
-a.pricingbox span {
- display: block;
-}
-
-a.pricingbox span#buylink {
- display: inline;
- color: #004ca8;
-}
-
-a.pricingbox span#buylink:hover {
- text-decoration: underline;
-}
-
-a.pricingbox:hover {
- background: #e2f2ff;
- border: 1px solid #000;
- text-decoration: none;
-}
-
-a.pricingbox img {
- margin: 10px 0;
- border: 0;
-}
-
-a.pricingbox span.pricingtitle {
- display: block;
- margin-top: 5px;
- margin-left: 10px;
- font-size: 1.2em;
- color: #119;
- text-decoration: underline;
-}
-
-a.pricingbox span.pricingdesc {
- display: block;
- color: #555;
- margin: 10px;
- height: 4.25em;
-}
-
-a.pricingbox span.pricingcost {
- top: 10px;
- display: block;
- color: #000;
- margin: 10px;
- font-weight: bold;
-}
-
-a.pricingbox span.pricingcost p {
- font-weight: normal;
-}
-
-#freetrialwrap a.freetrialbox {
- padding-top: 4px;
- display: block;
- border: 1px solid #ccc;
- background: #eee;
- cursor: pointer;
- color: #000;
- text-decoration: underline;
-}
-#freetrialwrap a.freetrialbox:hover {
- background: #def;
-}
-#freetrialwrap a.freetrialbox span.freetrialtext {
- margin-top: 7px;
- float: left;
-}
-a.freetrialbox img {
- border: 0;
- float: left;
- margin: 5px 10px;
-}
-
-a.pro-signup-button {
- display: block
- border: 0;
- cursor: pointer;
- color: #fff;
- font-weight: bold;
- overflow: visible;
- padding: 0;
- background: #70a4ec;
- border: 1px solid #3773c6;
- padding: 4px 6px;
- margin-top: 4px;
-}
-
diff --git a/trunk/etherpad/src/static/css/pro/payment-required.css b/trunk/etherpad/src/static/css/pro/payment-required.css
deleted file mode 100644
index 44d55b2..0000000
--- a/trunk/etherpad/src/static/css/pro/payment-required.css
+++ /dev/null
@@ -1,39 +0,0 @@
-
-#outside{
- padding: 0 0 0 266px;
- background: url(/static/img/pro/billing/cards-button.gif) 50px 25px no-repeat;
-}
-
-#inside {
- margin: 0;
- padding: 1em;
- border-left: 1px solid #ccc;
- background: #fff;
-}
-
-h1 {
- font-weight: bold;
- font-size: 1.33em;
- border-bottom: 1px solid #ccc;
-}
-
-#message {
- border: 1px solid #b97;
- background: #ffe;
- padding: 1em;
- margin: 1em 0;
-}
-
-a.manage-billing-button {
- display: block
- border: 0;
- cursor: pointer;
- color: #fff;
- font-weight: bold;
- overflow: visible;
- background: #70a4ec;
- border: 1px solid #3773c6;
- padding: 8px 12px;
- margin-top: 4px;
-}
-
diff --git a/trunk/etherpad/src/static/css/stats.css b/trunk/etherpad/src/static/css/stats.css
deleted file mode 100644
index 25dd074..0000000
--- a/trunk/etherpad/src/static/css/stats.css
+++ /dev/null
@@ -1,71 +0,0 @@
-div.statentry {
- width: 600px;
- border: 1px solid #060;
- background: #afa;
- margin: 1em;
-}
-
-body {
- margin: 0;
-}
-
-div.warning {
- background: #ffa;
- border: 1px solid #630;
-}
-
-div.error {
- background: #faa;
- border: 1px solid #600;
-}
-
-.statentry h2 {
- font-size: 13pt;
- font-family: sans-serif;
- background: #0a0;
- color: white;
- padding: 5px;
- margin: 0;
- cursor: pointer;
-}
-
-.statentry h2:hover {
- text-decoration: underline;
-}
-
-.warning h2 {
- background: #ea0;
-}
-
-.error h2 {
- background: #a00;
-}
-
-.statentry th {
- padding: 3px;
- font-weight: normal;
-}
-
-.statentry td {
- text-align: left;
- padding: 3px;
- width: 400px;
- font-size: 24px;
-}
-
-.statentry table {
- width: 100%;
-}
-
-.statbody {
- display: none;
-}
-
-/*div.categorywrapper {
- -moz-column-width: 500px;
- -moz-column-gap: 20px;
- -webkit-column-width: 500px;
- -webkit-column-gap: 20px;
- column-width: 500px;
- column-gap: 20px;
-}*/ \ No newline at end of file
diff --git a/trunk/etherpad/src/static/css/store/eepnet-checkout.css b/trunk/etherpad/src/static/css/store/eepnet-checkout.css
deleted file mode 100644
index 20254af..0000000
--- a/trunk/etherpad/src/static/css/store/eepnet-checkout.css
+++ /dev/null
@@ -1,284 +0,0 @@
-#shoppingmain dt {
- margin: 0.5em;
- margin-left: 0.5em;
- font-weight: bold;
- line-height: 120%;
-}
-
-#shoppingmain dd {
- margin: 0.5em;
- margin-top: 1em;
- margin-bottom: 2em;
- line-height: 120%;
-}
-
-#shoppingmain dd:first-letter,
-#shoppingmain dt:first-letter {
- font-weight: bold;
-}
-
-#shoppingmain table {
- background: #eef;
- width: 100%;
-}
-
-#shoppingmain table tr {}
-#shoppingmain > table td,
-#shoppingmain > table th {
- padding: 6px 8px;
-}
-
-#shoppingmain {
- width: 100%;
- border: 1px solid #ccc;
-}
-
-#shoppingmain p {
- margin: 1em;
-}
-
-#shoppingmain a {
- text-decoration: underline;
-}
-
-#shoppingmain ul,
-#shoppingmain ol {
- margin-right: 1em;
-}
-
-#shoppingmain h3 {
- background: #eee;
- padding: 0.5em 1em;
- border-bottom: 1px solid #ccc;
- font-weight: bold;
- font-size: 110%;
-}
-
-#shoppingwrapper {
- width: 580px;
-}
-
-.shoppingcart table td.pcell, table th.pcell {
- text-align: right;
- white-space: nowrap;
-}
-
-#shoppingcart {
- border: 1px solid #ccc;
- background: white;
-}
-
-.shoppingcart table {
- width: 100%;
-}
-
-.shoppingcart table th {
- font-weight: bold;
- background: #eee;
- border-bottom: 1px solid #ccc;
-}
-
-.shoppingcart table td {
- padding: 0 3px;
-}
-
-.shoppingcart table th {
- padding: 5px;
-}
-
-div.checkoutnav {
- padding-top: 10px;
- clear: both;
- display: block;
- text-align: center;
-}
-
-.center,
-.center td {
- text-align: center;
-}
-
-div.errormsg {
- border: 1px solid #caa;
- padding: 1em;
- margin: 1em 0;
-}
-
-div.errormsg,
-table tr.error,
-p.error,
-div.error {
- background: #fdd;
-}
-
-div.innererrormsg {
- margin: 1em;
- border: 1px solid #aca;
- padding: 1em;
- background: #dfd;
-}
-
-a#cschelp {
- font-size: 7pt;
- color: blue;
- border-bottom: 1px dashed blue;
-}
-
-table tr.total td {
- font-weight: bold;
-}
-
-#shoppingcart {
- width: 250px;
- float: right;
- font-size: 85%;
-}
-
-.shoppingcart span.desc {
- display: block;
- padding-top: 4px;
- padding-left: 10px;
- font-style: italic;
-}
-
-table tr.withoutsubtotal td,
-table tr.subtotal td {
- border-top: 1px solid #ccc;
-}
-
-#backbutton {
- float: right;
- padding: 5px;
-}
-
-#continuebutton {
- float: right;
- padding: 5px;
-}
-
-.shoppingcart tr.base td {
- padding-top: 5px;
-}
-
-.shoppingcart tr.refer td {
- color: green;
- font-weight: bold;
-}
-
-.shoppingcart tr.support td {
- padding-top: 10px;
-}
-
-.shoppingcart tr.referralbonus td {
- padding-top: 10px;
-}
-
-.shoppingcart tr.spacer td {
- padding-top: 10px;
-}
-
-.shoppingcart tr.subtotal td {
- padding-top: 5px;
-}
-
-.shoppingcart tr.referraldiscount td {
- padding-top: 5px;
-}
-
-.shoppingcart tr.total td {
- padding-top: 5px;
- padding-bottom: 5px;
-}
-
-.shoppingcart td.noitems {
- text-align: center;
- padding-top: 15px;
-}
-
-.paymentbutton label {
- cursor: pointer;
-}
-
-.billingtable td.pcell {
- width: 300px;
-}
-
-.billingtable tr.intonly {
- display: none;
-}
-
-.billingtable #ccimages img.ccimageselected {
- border: 3px solid #0f0;
- opacity: 1;
-}
-
-.billingtable #ccimages img {
- border: 3px solid #eef;
- opacity: 0.5;
-}
-
-input[type="text"].greenborder {
- border: 1px solid #0f0;
-}
-
-input[type="text"].redborder {
- border: 1px solid #f00;
-}
-
-input[type="text"] {
- border: 1px solid black;
- padding: 2px;
-}
-
-td.tcell {
- width: 200px;
-}
-
-#shoppingmain td {
- font-weight: bold;
-}
-
-#shoppingmain input,
-#shoppingmain p,
-#shoppingmain td,
-#shoppingmain li {
- font-size: 85%;
-}
-
-h4 {
- font-weight: bold;
- font-size: 100%;
- margin: 10px;
- margin-top: 20px;
-}
-
-h4 .editlink {
- font-size: 75%;
-}
-
-span.item .editlink {
- font-size: 75%;
-}
-
-span.desc .editlink {
- font-size: 75%;
- font-style: normal;
-}
-
-.paymentbutton {
- padding-left: 1.5em;
-}
-
-div.position {
- font-size: 80%;
- color: #999;
- padding-bottom: 10px;
-}
-
-div.position .current {
- color: #f93;
-}
-
-span.poslabel {
- padding: 0 1em;
-}
diff --git a/trunk/etherpad/src/static/css/store/ondemand-billing.css b/trunk/etherpad/src/static/css/store/ondemand-billing.css
deleted file mode 100644
index 7c4afe3..0000000
--- a/trunk/etherpad/src/static/css/store/ondemand-billing.css
+++ /dev/null
@@ -1,170 +0,0 @@
-input[type="text"].greenborder {
- border: 1px solid #0f0;
-}
-
-input[type="text"].redborder {
- border: 1px solid #f00;
-}
-
-input[type="text"] {
- border: 1px solid black;
- padding: 2px;
-}
-
-h4 {
- font-weight: bold;
- margin-bottom: 0.75em;
- margin-top: 1em;
- margin-left: 15px;
-}
-
-div.billinginfo {
- margin-left: 65px;
- border-left: 1px solid gray;
- border-right: 1px solid gray;
- border-top: 1px solid gray;
- border-bottom: 1px solid gray;
- width: 600px;
-}
-
-.billinginfo table.billingtable {
- width: 100%;
- margin: 0;
- background: #eef;
-}
-
-.billinginfo table.billingtable td,
-.billinginfo table.billingtable th {
- padding: 5px;
-}
-
-.billinginfo table.billingtable td.pcell,
-.billinginfo table.billingtable td.firstcell {
- padding-left: 35px;
-}
-
-.billinginfo table.billingtable td.pcell {
- width: 200px;
-}
-
-.billinginfo div {
- padding-left: 35px;
-}
-
-.billinginfo div#billingselect {
- padding-left: 0;
-}
-
-.billinginfo div#billingselect p {
- padding: 3px;
- padding-left: 35px;
-}
-
-.billingtable #ccimages img.ccimageselected {
- border: 3px solid #0f0;
- opacity: 1;
-}
-
-.billingtable #ccimages img {
- border: 3px solid #eef;
- opacity: 0.5;
-}
-
-a#cschelp {
- font-size: 7pt;
- color: blue;
- border-bottom: 1px dashed blue;
-}
-
-div#contbutton {
- margin-top: 1em;
- margin-right: 45px;
- float: right;
-}
-
-div#backbutton {
- margin-top: 1em;
- float: right;
-}
-
-div.errormsg {
- border: 1px solid #caa;
- padding: 1em;
- margin: 1em 0;
-}
-
-div.errormsg,
-table tr.error,
-p.error,
-div.error {
- background: #fdd;
-}
-
-table.billingsummary {
- width: 100%;
- border-top: 1px solid gray;
- border-left: 1px solid gray;
-}
-
-table.billingsummary th,
-table.billingsummary td {
- padding: 5px;
- border-bottom: 1px solid gray;
- border-right: 1px solid gray;
-}
-
-table.billingsummary th {
- font-weight: bold;
-}
-
-span#editpaymentslink {
- text-align: right;
- font-size: 80%;
- margin-left: 0.5em;
-}
-
-#editpaymentslink a {
- text-decoration: underline;
-}
-
-
-.paymentbutton label {
- cursor: pointer;
-}
-.paymentbutton {
- padding-left: 1.5em;
-}
-
-/* invoice list */
-
-.informational {
- font-style: italic;
-}
-
-table.invoicelist {
- border-left: 1px solid #ccc;
- border-top: 1px solid #ccc;
- border-right: 1px solid #ccc;
- width: 100%;
- font-size: 10pt;
-}
-
-table.invoicelist tr:hover {
- background: #ffc;
-}
-
-table.invoicelist td,
-table.invoicelist th {
- border-bottom: 1px solid #ccc;
- padding: 5px;
-}
-
-table.invoicelist th {
- font-weight: bold;
- background: #eef;
-}
-
-.returnlink {
- font-size: 10pt;
- font-style: italic;
-} \ No newline at end of file
diff --git a/trunk/etherpad/src/static/css/store/store.css b/trunk/etherpad/src/static/css/store/store.css
deleted file mode 100644
index f228698..0000000
--- a/trunk/etherpad/src/static/css/store/store.css
+++ /dev/null
@@ -1,90 +0,0 @@
-div.storepage a.downloadbutton_disabled {
- text-decoration: none;
- display: block;
- padding: .4em;
- margin: 1em;
- font-size: 1.4em;
- width: 270px;
- margin-left: auto;
- margin-right: auto;
- border: 2px solid #ccc;
- background: #eee;
- color: #888;
-}
-
-div.storepage a.downloadbutton {
- text-decoration: none;
- display: block;
- padding: .4em;
- margin: 1em;
- font-size: 1.4em;
- width: 270px;
- margin-left: auto;
- margin-right: auto;
- border: 2px solid #333;
- background: #ccc;
-}
-div.storepage a.downloadbutton:hover {
- background: #ddf;
- cursor: pointer;
-}
-
-div.storepage label:hover {
- cursor: pointer;
-}
-
-div.storepage div#topmsg {
- border: 1px solid #999;
- background: #dfd;
- font-weight: bold;
- padding: 1em;
-}
-
-div.storepage div#errormsg {
- border: 1px solid #f00;
- background: #fee;
- font-weight: bold;
- padding: 1em 2em;
- magin-top: 1em;
- margin-bottom: 1em;
-}
-
-#dlsignup {
- border: 1px solid #ccc;
-/* background: #ffefdf; */
- background: #efe;
- padding: 1em 2em;
-}
-
-#dlsignup, div#errormsg {
- display: block;
-}
-
-#dlsignup p {
- margin: 0;
-}
-
-#dlsignup p label {
- display: block;
- margin-top: .7em;
- color: #444;
-}
-
-#dlsignup input,
-#dlsignup select {
- width: 400px;
-}
-
-#dlsignup button {
- margin-top: 1em;
- width: 200px;
- margin-left: 100px;
-}
-
-div#processingmsg {
- border: 1px solid #ccc;
- background: #efe;
- padding: 1em 2em;
- font-weight: bold;
- font-size: 1.4em;
-}
diff --git a/trunk/etherpad/src/static/img/about/appjet-logo-large.gif b/trunk/etherpad/src/static/img/about/appjet-logo-large.gif
deleted file mode 100644
index 11351b2..0000000
--- a/trunk/etherpad/src/static/img/about/appjet-logo-large.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/appjet-logo-medium.png b/trunk/etherpad/src/static/img/about/appjet-logo-medium.png
deleted file mode 100644
index f6297e1..0000000
--- a/trunk/etherpad/src/static/img/about/appjet-logo-medium.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/investors/mitchkapor.jpg b/trunk/etherpad/src/static/img/about/investors/mitchkapor.jpg
deleted file mode 100644
index 5a65938..0000000
--- a/trunk/etherpad/src/static/img/about/investors/mitchkapor.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/investors/pb.jpg b/trunk/etherpad/src/static/img/about/investors/pb.jpg
deleted file mode 100644
index bd59c5c..0000000
--- a/trunk/etherpad/src/static/img/about/investors/pb.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/investors/pg.jpg b/trunk/etherpad/src/static/img/about/investors/pg.jpg
deleted file mode 100644
index 184155d..0000000
--- a/trunk/etherpad/src/static/img/about/investors/pg.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/investors/sanjeev.jpg b/trunk/etherpad/src/static/img/about/investors/sanjeev.jpg
deleted file mode 100644
index 9073b50..0000000
--- a/trunk/etherpad/src/static/img/about/investors/sanjeev.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/investors/seth.jpg b/trunk/etherpad/src/static/img/about/investors/seth.jpg
deleted file mode 100644
index 00f2aa9..0000000
--- a/trunk/etherpad/src/static/img/about/investors/seth.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/aaron-david-iphones-thumb.jpg b/trunk/etherpad/src/static/img/about/people/aaron-david-iphones-thumb.jpg
deleted file mode 100644
index 70c17db..0000000
--- a/trunk/etherpad/src/static/img/about/people/aaron-david-iphones-thumb.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/aaron-david-iphones.jpg b/trunk/etherpad/src/static/img/about/people/aaron-david-iphones.jpg
deleted file mode 100644
index 70c17db..0000000
--- a/trunk/etherpad/src/static/img/about/people/aaron-david-iphones.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/aaron-google-air.jpg b/trunk/etherpad/src/static/img/about/people/aaron-google-air.jpg
deleted file mode 100644
index 5948454..0000000
--- a/trunk/etherpad/src/static/img/about/people/aaron-google-air.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/aaron-headshot-thumb.jpg b/trunk/etherpad/src/static/img/about/people/aaron-headshot-thumb.jpg
deleted file mode 100644
index b0cffcd..0000000
--- a/trunk/etherpad/src/static/img/about/people/aaron-headshot-thumb.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/aaron-headshot.jpg b/trunk/etherpad/src/static/img/about/people/aaron-headshot.jpg
deleted file mode 100644
index 2b88437..0000000
--- a/trunk/etherpad/src/static/img/about/people/aaron-headshot.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/aaron-headshot2-thumb.jpg b/trunk/etherpad/src/static/img/about/people/aaron-headshot2-thumb.jpg
deleted file mode 100644
index d6c1a97..0000000
--- a/trunk/etherpad/src/static/img/about/people/aaron-headshot2-thumb.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/aaron-headshot2.jpg b/trunk/etherpad/src/static/img/about/people/aaron-headshot2.jpg
deleted file mode 100644
index e4b2a77..0000000
--- a/trunk/etherpad/src/static/img/about/people/aaron-headshot2.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/aaron-headshot3-thumb.jpg b/trunk/etherpad/src/static/img/about/people/aaron-headshot3-thumb.jpg
deleted file mode 100644
index cca1b68..0000000
--- a/trunk/etherpad/src/static/img/about/people/aaron-headshot3-thumb.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/aaron-headshot3.jpg b/trunk/etherpad/src/static/img/about/people/aaron-headshot3.jpg
deleted file mode 100644
index 13c433d..0000000
--- a/trunk/etherpad/src/static/img/about/people/aaron-headshot3.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/daniel-headshot-thumb.jpg b/trunk/etherpad/src/static/img/about/people/daniel-headshot-thumb.jpg
deleted file mode 100644
index 567316c..0000000
--- a/trunk/etherpad/src/static/img/about/people/daniel-headshot-thumb.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/david-headshot-thumb.jpg b/trunk/etherpad/src/static/img/about/people/david-headshot-thumb.jpg
deleted file mode 100644
index 5f9da44..0000000
--- a/trunk/etherpad/src/static/img/about/people/david-headshot-thumb.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/david-headshot.jpg b/trunk/etherpad/src/static/img/about/people/david-headshot.jpg
deleted file mode 100644
index 89ab3ea..0000000
--- a/trunk/etherpad/src/static/img/about/people/david-headshot.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/davy-headshot.jpg b/trunk/etherpad/src/static/img/about/people/davy-headshot.jpg
deleted file mode 100644
index 9430186..0000000
--- a/trunk/etherpad/src/static/img/about/people/davy-headshot.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/jd-headshot-thumb.jpg b/trunk/etherpad/src/static/img/about/people/jd-headshot-thumb.jpg
deleted file mode 100644
index b399a57..0000000
--- a/trunk/etherpad/src/static/img/about/people/jd-headshot-thumb.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/jd-headshot.jpg b/trunk/etherpad/src/static/img/about/people/jd-headshot.jpg
deleted file mode 100644
index 182d534..0000000
--- a/trunk/etherpad/src/static/img/about/people/jd-headshot.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/rhonda-headshot-thumb.jpg b/trunk/etherpad/src/static/img/about/people/rhonda-headshot-thumb.jpg
deleted file mode 100644
index 8d9358b..0000000
--- a/trunk/etherpad/src/static/img/about/people/rhonda-headshot-thumb.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/people/rhonda-headshot.jpg b/trunk/etherpad/src/static/img/about/people/rhonda-headshot.jpg
deleted file mode 100644
index b4c4ec8..0000000
--- a/trunk/etherpad/src/static/img/about/people/rhonda-headshot.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/pier38.png b/trunk/etherpad/src/static/img/about/pier38.png
deleted file mode 100644
index d15b3a8..0000000
--- a/trunk/etherpad/src/static/img/about/pier38.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/quote-close.png b/trunk/etherpad/src/static/img/about/quote-close.png
deleted file mode 100644
index de4b18b..0000000
--- a/trunk/etherpad/src/static/img/about/quote-close.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/quote-open.png b/trunk/etherpad/src/static/img/about/quote-open.png
deleted file mode 100644
index e637705..0000000
--- a/trunk/etherpad/src/static/img/about/quote-open.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/about/screencastpreview800x600.jpg b/trunk/etherpad/src/static/img/about/screencastpreview800x600.jpg
deleted file mode 100644
index 2a4ed39..0000000
--- a/trunk/etherpad/src/static/img/about/screencastpreview800x600.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/account/betawarn.jpg b/trunk/etherpad/src/static/img/account/betawarn.jpg
deleted file mode 100644
index c3cec1b..0000000
--- a/trunk/etherpad/src/static/img/account/betawarn.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/acecarets/000000.gif b/trunk/etherpad/src/static/img/acecarets/000000.gif
deleted file mode 100644
index f67bd3d..0000000
--- a/trunk/etherpad/src/static/img/acecarets/000000.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/acecarets/666666.gif b/trunk/etherpad/src/static/img/acecarets/666666.gif
deleted file mode 100644
index cd8e264..0000000
--- a/trunk/etherpad/src/static/img/acecarets/666666.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/acecarets/999999.gif b/trunk/etherpad/src/static/img/acecarets/999999.gif
deleted file mode 100644
index fa75d25..0000000
--- a/trunk/etherpad/src/static/img/acecarets/999999.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/acecarets/default.gif b/trunk/etherpad/src/static/img/acecarets/default.gif
deleted file mode 100644
index 196d9ff..0000000
--- a/trunk/etherpad/src/static/img/acecarets/default.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/backgrad.png b/trunk/etherpad/src/static/img/apr09/backgrad.png
deleted file mode 100644
index c61d830..0000000
--- a/trunk/etherpad/src/static/img/apr09/backgrad.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/black35.png b/trunk/etherpad/src/static/img/apr09/black35.png
deleted file mode 100644
index 9d82846..0000000
--- a/trunk/etherpad/src/static/img/apr09/black35.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/blank.gif b/trunk/etherpad/src/static/img/apr09/blank.gif
deleted file mode 100644
index 8fb6fb0..0000000
--- a/trunk/etherpad/src/static/img/apr09/blank.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/modalbar.gif b/trunk/etherpad/src/static/img/apr09/modalbar.gif
deleted file mode 100644
index 3e86759..0000000
--- a/trunk/etherpad/src/static/img/apr09/modalbar.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/newpadicon.gif b/trunk/etherpad/src/static/img/apr09/newpadicon.gif
deleted file mode 100644
index a282728..0000000
--- a/trunk/etherpad/src/static/img/apr09/newpadicon.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/shadbot.png b/trunk/etherpad/src/static/img/apr09/shadbot.png
deleted file mode 100644
index 9506058..0000000
--- a/trunk/etherpad/src/static/img/apr09/shadbot.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/shadleft.png b/trunk/etherpad/src/static/img/apr09/shadleft.png
deleted file mode 100644
index 72049e0..0000000
--- a/trunk/etherpad/src/static/img/apr09/shadleft.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/shadleftbot.png b/trunk/etherpad/src/static/img/apr09/shadleftbot.png
deleted file mode 100644
index 7d3fb5b..0000000
--- a/trunk/etherpad/src/static/img/apr09/shadleftbot.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/shadlefttop.png b/trunk/etherpad/src/static/img/apr09/shadlefttop.png
deleted file mode 100644
index 9af4e90..0000000
--- a/trunk/etherpad/src/static/img/apr09/shadlefttop.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/shadright.png b/trunk/etherpad/src/static/img/apr09/shadright.png
deleted file mode 100644
index 41d099c..0000000
--- a/trunk/etherpad/src/static/img/apr09/shadright.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/shadrightbot.png b/trunk/etherpad/src/static/img/apr09/shadrightbot.png
deleted file mode 100644
index 6770ec5..0000000
--- a/trunk/etherpad/src/static/img/apr09/shadrightbot.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/shadrighttop.png b/trunk/etherpad/src/static/img/apr09/shadrighttop.png
deleted file mode 100644
index 0f7a0ba..0000000
--- a/trunk/etherpad/src/static/img/apr09/shadrighttop.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/topbar.gif b/trunk/etherpad/src/static/img/apr09/topbar.gif
deleted file mode 100644
index 65ed7c8..0000000
--- a/trunk/etherpad/src/static/img/apr09/topbar.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/topbarlogo.gif b/trunk/etherpad/src/static/img/apr09/topbarlogo.gif
deleted file mode 100644
index 9a3aa77..0000000
--- a/trunk/etherpad/src/static/img/apr09/topbarlogo.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/widthfull.gif b/trunk/etherpad/src/static/img/apr09/widthfull.gif
deleted file mode 100644
index 8850ec2..0000000
--- a/trunk/etherpad/src/static/img/apr09/widthfull.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/widthfullactive.gif b/trunk/etherpad/src/static/img/apr09/widthfullactive.gif
deleted file mode 100644
index 36b566f..0000000
--- a/trunk/etherpad/src/static/img/apr09/widthfullactive.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/widthlim.gif b/trunk/etherpad/src/static/img/apr09/widthlim.gif
deleted file mode 100644
index 551e741..0000000
--- a/trunk/etherpad/src/static/img/apr09/widthlim.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/apr09/widthlimactive.gif b/trunk/etherpad/src/static/img/apr09/widthlimactive.gif
deleted file mode 100644
index 8cf0194..0000000
--- a/trunk/etherpad/src/static/img/apr09/widthlimactive.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/billing/amex.gif b/trunk/etherpad/src/static/img/billing/amex.gif
deleted file mode 100644
index 96e2cbb..0000000
--- a/trunk/etherpad/src/static/img/billing/amex.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/billing/creditcard.gif b/trunk/etherpad/src/static/img/billing/creditcard.gif
deleted file mode 100644
index ac2353e..0000000
--- a/trunk/etherpad/src/static/img/billing/creditcard.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/billing/csc-help.gif b/trunk/etherpad/src/static/img/billing/csc-help.gif
deleted file mode 100644
index 1afb6b7..0000000
--- a/trunk/etherpad/src/static/img/billing/csc-help.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/billing/disc.gif b/trunk/etherpad/src/static/img/billing/disc.gif
deleted file mode 100644
index a5e3a90..0000000
--- a/trunk/etherpad/src/static/img/billing/disc.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/billing/invoice.gif b/trunk/etherpad/src/static/img/billing/invoice.gif
deleted file mode 100644
index cee681a..0000000
--- a/trunk/etherpad/src/static/img/billing/invoice.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/billing/mc.gif b/trunk/etherpad/src/static/img/billing/mc.gif
deleted file mode 100644
index 2331849..0000000
--- a/trunk/etherpad/src/static/img/billing/mc.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/billing/paypal.gif b/trunk/etherpad/src/static/img/billing/paypal.gif
deleted file mode 100644
index 25333b1..0000000
--- a/trunk/etherpad/src/static/img/billing/paypal.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/billing/visa.gif b/trunk/etherpad/src/static/img/billing/visa.gif
deleted file mode 100644
index 4769f0c..0000000
--- a/trunk/etherpad/src/static/img/billing/visa.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/blog/posts/new-features/fullwidth.gif b/trunk/etherpad/src/static/img/blog/posts/new-features/fullwidth.gif
deleted file mode 100644
index 73f427d..0000000
--- a/trunk/etherpad/src/static/img/blog/posts/new-features/fullwidth.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/blog/posts/new-features/importexport.gif b/trunk/etherpad/src/static/img/blog/posts/new-features/importexport.gif
deleted file mode 100644
index f0d2bac..0000000
--- a/trunk/etherpad/src/static/img/blog/posts/new-features/importexport.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/blog/posts/new-features/richtext.gif b/trunk/etherpad/src/static/img/blog/posts/new-features/richtext.gif
deleted file mode 100644
index 5d03bdc..0000000
--- a/trunk/etherpad/src/static/img/blog/posts/new-features/richtext.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/blog/posts/new-features/viewzoom.gif b/trunk/etherpad/src/static/img/blog/posts/new-features/viewzoom.gif
deleted file mode 100644
index 47e1caa..0000000
--- a/trunk/etherpad/src/static/img/blog/posts/new-features/viewzoom.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/blog/posts/pricing-survey-results.png b/trunk/etherpad/src/static/img/blog/posts/pricing-survey-results.png
deleted file mode 100644
index 668dd72..0000000
--- a/trunk/etherpad/src/static/img/blog/posts/pricing-survey-results.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/blog/posts/pricing-survey.png b/trunk/etherpad/src/static/img/blog/posts/pricing-survey.png
deleted file mode 100644
index 7289aa8..0000000
--- a/trunk/etherpad/src/static/img/blog/posts/pricing-survey.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/blog/posts/time-slider-screenshot.gif b/trunk/etherpad/src/static/img/blog/posts/time-slider-screenshot.gif
deleted file mode 100644
index 782ac15..0000000
--- a/trunk/etherpad/src/static/img/blog/posts/time-slider-screenshot.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/home-features-bottom.gif b/trunk/etherpad/src/static/img/davy/bg/home-features-bottom.gif
deleted file mode 100644
index 7dc7644..0000000
--- a/trunk/etherpad/src/static/img/davy/bg/home-features-bottom.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/home-features-free-bottom.gif b/trunk/etherpad/src/static/img/davy/bg/home-features-free-bottom.gif
deleted file mode 100644
index 3bd7ba8..0000000
--- a/trunk/etherpad/src/static/img/davy/bg/home-features-free-bottom.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/home-features-paid-top.gif b/trunk/etherpad/src/static/img/davy/bg/home-features-paid-top.gif
deleted file mode 100644
index faed96c..0000000
--- a/trunk/etherpad/src/static/img/davy/bg/home-features-paid-top.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/home-features-top.gif b/trunk/etherpad/src/static/img/davy/bg/home-features-top.gif
deleted file mode 100644
index 2db70a6..0000000
--- a/trunk/etherpad/src/static/img/davy/bg/home-features-top.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/home-nav-selected.png b/trunk/etherpad/src/static/img/davy/bg/home-nav-selected.png
deleted file mode 100644
index 01c0a99..0000000
--- a/trunk/etherpad/src/static/img/davy/bg/home-nav-selected.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/home-screencast.png b/trunk/etherpad/src/static/img/davy/bg/home-screencast.png
deleted file mode 100644
index e03b83d..0000000
--- a/trunk/etherpad/src/static/img/davy/bg/home-screencast.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/home2.png b/trunk/etherpad/src/static/img/davy/bg/home2.png
deleted file mode 100644
index 814c339..0000000
--- a/trunk/etherpad/src/static/img/davy/bg/home2.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/product-nav-selected-white.png b/trunk/etherpad/src/static/img/davy/bg/product-nav-selected-white.png
deleted file mode 100644
index 4365d4a..0000000
--- a/trunk/etherpad/src/static/img/davy/bg/product-nav-selected-white.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/bg/product-nav-selected.png b/trunk/etherpad/src/static/img/davy/bg/product-nav-selected.png
deleted file mode 100644
index a3094d0..0000000
--- a/trunk/etherpad/src/static/img/davy/bg/product-nav-selected.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/createpad-home.gif b/trunk/etherpad/src/static/img/davy/btn/createpad-home.gif
deleted file mode 100644
index 5a46f02..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/createpad-home.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/createpad-large.gif b/trunk/etherpad/src/static/img/davy/btn/createpad-large.gif
deleted file mode 100644
index 9e37808..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/createpad-large.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/intro-screencast.png b/trunk/etherpad/src/static/img/davy/btn/intro-screencast.png
deleted file mode 100644
index 8343ddf..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/intro-screencast.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/intro-testimonials.png b/trunk/etherpad/src/static/img/davy/btn/intro-testimonials.png
deleted file mode 100644
index b1df4f2..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/intro-testimonials.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/learnmore.gif b/trunk/etherpad/src/static/img/davy/btn/learnmore.gif
deleted file mode 100644
index 9f0f612..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/learnmore.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/signup-home-2.gif b/trunk/etherpad/src/static/img/davy/btn/signup-home-2.gif
deleted file mode 100644
index 1aea6ff..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/signup-home-2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/signup-home-3.gif b/trunk/etherpad/src/static/img/davy/btn/signup-home-3.gif
deleted file mode 100644
index a237242..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/signup-home-3.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/signup-home-4.gif b/trunk/etherpad/src/static/img/davy/btn/signup-home-4.gif
deleted file mode 100644
index 966371e..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/signup-home-4.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/signup-home.gif b/trunk/etherpad/src/static/img/davy/btn/signup-home.gif
deleted file mode 100644
index 0a83858..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/signup-home.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/btn/uses-more.gif b/trunk/etherpad/src/static/img/davy/btn/uses-more.gif
deleted file mode 100644
index 6a73bbc..0000000
--- a/trunk/etherpad/src/static/img/davy/btn/uses-more.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/32/114.png b/trunk/etherpad/src/static/img/davy/gfx/32/114.png
deleted file mode 100644
index cbab795..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/32/114.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/32/15.png b/trunk/etherpad/src/static/img/davy/gfx/32/15.png
deleted file mode 100644
index 596fd0f..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/32/15.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/32/65.png b/trunk/etherpad/src/static/img/davy/gfx/32/65.png
deleted file mode 100644
index c331ee1..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/32/65.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/32/78.png b/trunk/etherpad/src/static/img/davy/gfx/32/78.png
deleted file mode 100644
index fae3f29..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/32/78.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/bullet.gif b/trunk/etherpad/src/static/img/davy/gfx/bullet.gif
deleted file mode 100644
index cb2e123..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/bullet.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/home-logo2.gif b/trunk/etherpad/src/static/img/davy/gfx/home-logo2.gif
deleted file mode 100644
index 24b67bd..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/home-logo2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/home-screencast.png b/trunk/etherpad/src/static/img/davy/gfx/home-screencast.png
deleted file mode 100644
index b5516d3..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/home-screencast.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/plane.gif b/trunk/etherpad/src/static/img/davy/gfx/plane.gif
deleted file mode 100644
index cf3226e..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/plane.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/product-logo.gif b/trunk/etherpad/src/static/img/davy/gfx/product-logo.gif
deleted file mode 100644
index 72975bb..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/product-logo.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/screenshot.gif b/trunk/etherpad/src/static/img/davy/gfx/screenshot.gif
deleted file mode 100644
index ba87f99..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/screenshot.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/use-meetings.gif b/trunk/etherpad/src/static/img/davy/gfx/use-meetings.gif
deleted file mode 100644
index 3451969..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/use-meetings.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/use-meetings.png b/trunk/etherpad/src/static/img/davy/gfx/use-meetings.png
deleted file mode 100644
index 4e41581..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/use-meetings.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/use-programming.gif b/trunk/etherpad/src/static/img/davy/gfx/use-programming.gif
deleted file mode 100644
index 795e7fd..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/use-programming.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/use-programming.png b/trunk/etherpad/src/static/img/davy/gfx/use-programming.png
deleted file mode 100644
index 825095d..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/use-programming.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/use-writing.gif b/trunk/etherpad/src/static/img/davy/gfx/use-writing.gif
deleted file mode 100644
index 0e2d11b..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/use-writing.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/gfx/use-writing.png b/trunk/etherpad/src/static/img/davy/gfx/use-writing.png
deleted file mode 100644
index c6e267c..0000000
--- a/trunk/etherpad/src/static/img/davy/gfx/use-writing.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/davy/txt/home-button.gif b/trunk/etherpad/src/static/img/davy/txt/home-button.gif
deleted file mode 100644
index bdf4945..0000000
--- a/trunk/etherpad/src/static/img/davy/txt/home-button.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/featuretour/code.gif b/trunk/etherpad/src/static/img/featuretour/code.gif
deleted file mode 100644
index abff862..0000000
--- a/trunk/etherpad/src/static/img/featuretour/code.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/featuretour/edits.gif b/trunk/etherpad/src/static/img/featuretour/edits.gif
deleted file mode 100644
index d38f83a..0000000
--- a/trunk/etherpad/src/static/img/featuretour/edits.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/featuretour/editsandusers.gif b/trunk/etherpad/src/static/img/featuretour/editsandusers.gif
deleted file mode 100644
index 90c36f8..0000000
--- a/trunk/etherpad/src/static/img/featuretour/editsandusers.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/featuretour/padlock.png b/trunk/etherpad/src/static/img/featuretour/padlock.png
deleted file mode 100644
index f6d6c05..0000000
--- a/trunk/etherpad/src/static/img/featuretour/padlock.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/featuretour/revisions.gif b/trunk/etherpad/src/static/img/featuretour/revisions.gif
deleted file mode 100644
index a0d8220..0000000
--- a/trunk/etherpad/src/static/img/featuretour/revisions.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/featuretour/users.gif b/trunk/etherpad/src/static/img/featuretour/users.gif
deleted file mode 100644
index 48b4470..0000000
--- a/trunk/etherpad/src/static/img/featuretour/users.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/framedheaderback.gif b/trunk/etherpad/src/static/img/feb09/framedheaderback.gif
deleted file mode 100644
index 5b17b9f..0000000
--- a/trunk/etherpad/src/static/img/feb09/framedheaderback.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/framedheaderlogo.gif b/trunk/etherpad/src/static/img/feb09/framedheaderlogo.gif
deleted file mode 100644
index 01de8cd..0000000
--- a/trunk/etherpad/src/static/img/feb09/framedheaderlogo.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/home_firstp.gif b/trunk/etherpad/src/static/img/feb09/home_firstp.gif
deleted file mode 100644
index af0a2cd..0000000
--- a/trunk/etherpad/src/static/img/feb09/home_firstp.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/home_firstp.png b/trunk/etherpad/src/static/img/feb09/home_firstp.png
deleted file mode 100644
index cb7fc8c..0000000
--- a/trunk/etherpad/src/static/img/feb09/home_firstp.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/home_firstp2.gif b/trunk/etherpad/src/static/img/feb09/home_firstp2.gif
deleted file mode 100644
index 9e0ed1e..0000000
--- a/trunk/etherpad/src/static/img/feb09/home_firstp2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/home_h1.gif b/trunk/etherpad/src/static/img/feb09/home_h1.gif
deleted file mode 100644
index 1fe08cb..0000000
--- a/trunk/etherpad/src/static/img/feb09/home_h1.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/home_h1.png b/trunk/etherpad/src/static/img/feb09/home_h1.png
deleted file mode 100644
index 1b5784d..0000000
--- a/trunk/etherpad/src/static/img/feb09/home_h1.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/home_newpadbutton.gif b/trunk/etherpad/src/static/img/feb09/home_newpadbutton.gif
deleted file mode 100644
index 8706407..0000000
--- a/trunk/etherpad/src/static/img/feb09/home_newpadbutton.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/home_newpadbutton.png b/trunk/etherpad/src/static/img/feb09/home_newpadbutton.png
deleted file mode 100644
index ead253c..0000000
--- a/trunk/etherpad/src/static/img/feb09/home_newpadbutton.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/home_newpadbutton2.gif b/trunk/etherpad/src/static/img/feb09/home_newpadbutton2.gif
deleted file mode 100644
index ba5d478..0000000
--- a/trunk/etherpad/src/static/img/feb09/home_newpadbutton2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/home_newpadbutton_eepnet.gif b/trunk/etherpad/src/static/img/feb09/home_newpadbutton_eepnet.gif
deleted file mode 100644
index a365351..0000000
--- a/trunk/etherpad/src/static/img/feb09/home_newpadbutton_eepnet.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/hometop_back.gif b/trunk/etherpad/src/static/img/feb09/hometop_back.gif
deleted file mode 100644
index 7cdd406..0000000
--- a/trunk/etherpad/src/static/img/feb09/hometop_back.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/nav1.gif b/trunk/etherpad/src/static/img/feb09/nav1.gif
deleted file mode 100644
index 4af4869..0000000
--- a/trunk/etherpad/src/static/img/feb09/nav1.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/nav1_back.gif b/trunk/etherpad/src/static/img/feb09/nav1_back.gif
deleted file mode 100644
index d2db7ee..0000000
--- a/trunk/etherpad/src/static/img/feb09/nav1_back.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/nav2.gif b/trunk/etherpad/src/static/img/feb09/nav2.gif
deleted file mode 100644
index f43a40e..0000000
--- a/trunk/etherpad/src/static/img/feb09/nav2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/feb09/screencast.gif b/trunk/etherpad/src/static/img/feb09/screencast.gif
deleted file mode 100644
index 3819082..0000000
--- a/trunk/etherpad/src/static/img/feb09/screencast.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/home/etherpad-mainheader1.jpg b/trunk/etherpad/src/static/img/home/etherpad-mainheader1.jpg
deleted file mode 100644
index ed7e830..0000000
--- a/trunk/etherpad/src/static/img/home/etherpad-mainheader1.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/home/headergradient.gif b/trunk/etherpad/src/static/img/home/headergradient.gif
deleted file mode 100644
index d6526dc..0000000
--- a/trunk/etherpad/src/static/img/home/headergradient.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/home/homeheader1.jpg b/trunk/etherpad/src/static/img/home/homeheader1.jpg
deleted file mode 100644
index 3436158..0000000
--- a/trunk/etherpad/src/static/img/home/homeheader1.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/home/homeheader2.jpg b/trunk/etherpad/src/static/img/home/homeheader2.jpg
deleted file mode 100644
index e19ba41..0000000
--- a/trunk/etherpad/src/static/img/home/homeheader2.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/home/leftgrad.gif b/trunk/etherpad/src/static/img/home/leftgrad.gif
deleted file mode 100644
index ff3931a..0000000
--- a/trunk/etherpad/src/static/img/home/leftgrad.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/home/pencilpaperback.png b/trunk/etherpad/src/static/img/home/pencilpaperback.png
deleted file mode 100644
index e0d2f9d..0000000
--- a/trunk/etherpad/src/static/img/home/pencilpaperback.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/home/screencapture1.gif b/trunk/etherpad/src/static/img/home/screencapture1.gif
deleted file mode 100644
index 7c3ce5a..0000000
--- a/trunk/etherpad/src/static/img/home/screencapture1.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/home/underdevicon.gif b/trunk/etherpad/src/static/img/home/underdevicon.gif
deleted file mode 100644
index 5b75fd1..0000000
--- a/trunk/etherpad/src/static/img/home/underdevicon.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/icon/downarrow.gif b/trunk/etherpad/src/static/img/icon/downarrow.gif
deleted file mode 100644
index 6389439..0000000
--- a/trunk/etherpad/src/static/img/icon/downarrow.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/icon/feed.gif b/trunk/etherpad/src/static/img/icon/feed.gif
deleted file mode 100644
index fb9b66c..0000000
--- a/trunk/etherpad/src/static/img/icon/feed.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/bottomareagfx.gif b/trunk/etherpad/src/static/img/jun09/pad/bottomareagfx.gif
deleted file mode 100644
index c499a62..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/bottomareagfx.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/colorpicker.gif b/trunk/etherpad/src/static/img/jun09/pad/colorpicker.gif
deleted file mode 100644
index 602e7e6..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/colorpicker.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/connectionindicator.gif b/trunk/etherpad/src/static/img/jun09/pad/connectionindicator.gif
deleted file mode 100644
index ecc270d..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/connectionindicator.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/docbarstates.png b/trunk/etherpad/src/static/img/jun09/pad/docbarstates.png
deleted file mode 100644
index 13a5913..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/docbarstates.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/docbarstates2.png b/trunk/etherpad/src/static/img/jun09/pad/docbarstates2.png
deleted file mode 100644
index 9e26b1d..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/docbarstates2.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/docbarstates3.png b/trunk/etherpad/src/static/img/jun09/pad/docbarstates3.png
deleted file mode 100644
index cdc6a45..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/docbarstates3.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/docpaneledge.png b/trunk/etherpad/src/static/img/jun09/pad/docpaneledge.png
deleted file mode 100644
index de22d6a..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/docpaneledge.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/docpanelmiddle.png b/trunk/etherpad/src/static/img/jun09/pad/docpanelmiddle.png
deleted file mode 100644
index 9290e86..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/docpanelmiddle.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/editbar.gif b/trunk/etherpad/src/static/img/jun09/pad/editbar.gif
deleted file mode 100644
index eb7100c..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/editbar.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/editbar2.gif b/trunk/etherpad/src/static/img/jun09/pad/editbar2.gif
deleted file mode 100644
index d222fb8..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/editbar2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/overlay.png b/trunk/etherpad/src/static/img/jun09/pad/overlay.png
deleted file mode 100644
index 46abff3..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/overlay.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/padtop.gif b/trunk/etherpad/src/static/img/jun09/pad/padtop.gif
deleted file mode 100644
index 9e77b07..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/padtop.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/padtop2.gif b/trunk/etherpad/src/static/img/jun09/pad/padtop2.gif
deleted file mode 100644
index 1e3d8c2..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/padtop2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/padtop3.gif b/trunk/etherpad/src/static/img/jun09/pad/padtop3.gif
deleted file mode 100644
index b6bc589..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/padtop3.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/padtop4.gif b/trunk/etherpad/src/static/img/jun09/pad/padtop4.gif
deleted file mode 100644
index d896250..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/padtop4.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/padtop5.png b/trunk/etherpad/src/static/img/jun09/pad/padtop5.png
deleted file mode 100644
index 6546509..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/padtop5.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/padtop5.xcf b/trunk/etherpad/src/static/img/jun09/pad/padtop5.xcf
deleted file mode 100644
index 4abbd02..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/padtop5.xcf
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/padtopback.gif b/trunk/etherpad/src/static/img/jun09/pad/padtopback.gif
deleted file mode 100644
index 335979b..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/padtopback.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/padtopback2.gif b/trunk/etherpad/src/static/img/jun09/pad/padtopback2.gif
deleted file mode 100644
index eb92358..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/padtopback2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/public.gif b/trunk/etherpad/src/static/img/jun09/pad/public.gif
deleted file mode 100644
index e6f09c7..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/public.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/sharebox2.gif b/trunk/etherpad/src/static/img/jun09/pad/sharebox2.gif
deleted file mode 100644
index 8e89925..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/sharebox2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/sharebox3.gif b/trunk/etherpad/src/static/img/jun09/pad/sharebox3.gif
deleted file mode 100644
index 6f8f03c..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/sharebox3.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/jun09/pad/syncing2.gif b/trunk/etherpad/src/static/img/jun09/pad/syncing2.gif
deleted file mode 100644
index 29470e3..0000000
--- a/trunk/etherpad/src/static/img/jun09/pad/syncing2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/bold.gif b/trunk/etherpad/src/static/img/may09/bold.gif
deleted file mode 100644
index 49e0d17..0000000
--- a/trunk/etherpad/src/static/img/may09/bold.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/doc.png b/trunk/etherpad/src/static/img/may09/doc.png
deleted file mode 100644
index b374d0d..0000000
--- a/trunk/etherpad/src/static/img/may09/doc.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/html.png b/trunk/etherpad/src/static/img/may09/html.png
deleted file mode 100644
index 917f1a4..0000000
--- a/trunk/etherpad/src/static/img/may09/html.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/italic.gif b/trunk/etherpad/src/static/img/may09/italic.gif
deleted file mode 100644
index 2876ed9..0000000
--- a/trunk/etherpad/src/static/img/may09/italic.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/leftarrow.gif b/trunk/etherpad/src/static/img/may09/leftarrow.gif
deleted file mode 100644
index c26475f..0000000
--- a/trunk/etherpad/src/static/img/may09/leftarrow.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/leftarrow2.gif b/trunk/etherpad/src/static/img/may09/leftarrow2.gif
deleted file mode 100644
index 63bbddc..0000000
--- a/trunk/etherpad/src/static/img/may09/leftarrow2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/link.gif b/trunk/etherpad/src/static/img/may09/link.gif
deleted file mode 100644
index 44ffdd2..0000000
--- a/trunk/etherpad/src/static/img/may09/link.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/link.png b/trunk/etherpad/src/static/img/may09/link.png
deleted file mode 100644
index 4e46fcb..0000000
--- a/trunk/etherpad/src/static/img/may09/link.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/odt.gif b/trunk/etherpad/src/static/img/may09/odt.gif
deleted file mode 100644
index be42352..0000000
--- a/trunk/etherpad/src/static/img/may09/odt.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/odt.png b/trunk/etherpad/src/static/img/may09/odt.png
deleted file mode 100644
index 5d630db..0000000
--- a/trunk/etherpad/src/static/img/may09/odt.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/padlock.gif b/trunk/etherpad/src/static/img/may09/padlock.gif
deleted file mode 100644
index 167bf75..0000000
--- a/trunk/etherpad/src/static/img/may09/padlock.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/padlockopen.gif b/trunk/etherpad/src/static/img/may09/padlockopen.gif
deleted file mode 100644
index 0aaf413..0000000
--- a/trunk/etherpad/src/static/img/may09/padlockopen.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/passwordlocked.gif b/trunk/etherpad/src/static/img/may09/passwordlocked.gif
deleted file mode 100644
index 167bf75..0000000
--- a/trunk/etherpad/src/static/img/may09/passwordlocked.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/passwordlocked_cropped.gif b/trunk/etherpad/src/static/img/may09/passwordlocked_cropped.gif
deleted file mode 100644
index 969a8bd..0000000
--- a/trunk/etherpad/src/static/img/may09/passwordlocked_cropped.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/passwordnone.gif b/trunk/etherpad/src/static/img/may09/passwordnone.gif
deleted file mode 100644
index 61e38d9..0000000
--- a/trunk/etherpad/src/static/img/may09/passwordnone.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/paypal.gif b/trunk/etherpad/src/static/img/may09/paypal.gif
deleted file mode 100644
index add5454..0000000
--- a/trunk/etherpad/src/static/img/may09/paypal.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/pdf.png b/trunk/etherpad/src/static/img/may09/pdf.png
deleted file mode 100644
index ac4fa75..0000000
--- a/trunk/etherpad/src/static/img/may09/pdf.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/redo.gif b/trunk/etherpad/src/static/img/may09/redo.gif
deleted file mode 100644
index bb07b8e..0000000
--- a/trunk/etherpad/src/static/img/may09/redo.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/txt.png b/trunk/etherpad/src/static/img/may09/txt.png
deleted file mode 100644
index f830cc6..0000000
--- a/trunk/etherpad/src/static/img/may09/txt.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/underline.gif b/trunk/etherpad/src/static/img/may09/underline.gif
deleted file mode 100644
index 1d1f573..0000000
--- a/trunk/etherpad/src/static/img/may09/underline.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/may09/undo.gif b/trunk/etherpad/src/static/img/may09/undo.gif
deleted file mode 100644
index 273e9e6..0000000
--- a/trunk/etherpad/src/static/img/may09/undo.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/miniplane.gif b/trunk/etherpad/src/static/img/miniplane.gif
deleted file mode 100644
index aeaacb0..0000000
--- a/trunk/etherpad/src/static/img/miniplane.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/misc/diagnostic-links.gif b/trunk/etherpad/src/static/img/misc/diagnostic-links.gif
deleted file mode 100644
index f76669a..0000000
--- a/trunk/etherpad/src/static/img/misc/diagnostic-links.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/misc/traclogo.gif b/trunk/etherpad/src/static/img/misc/traclogo.gif
deleted file mode 100644
index 7ee31d1..0000000
--- a/trunk/etherpad/src/static/img/misc/traclogo.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/atlonglast.gif b/trunk/etherpad/src/static/img/oct/atlonglast.gif
deleted file mode 100644
index 88e1c98..0000000
--- a/trunk/etherpad/src/static/img/oct/atlonglast.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/banner1.jpg b/trunk/etherpad/src/static/img/oct/banner1.jpg
deleted file mode 100644
index 431d2ba..0000000
--- a/trunk/etherpad/src/static/img/oct/banner1.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/banner2.jpg b/trunk/etherpad/src/static/img/oct/banner2.jpg
deleted file mode 100644
index 50570a8..0000000
--- a/trunk/etherpad/src/static/img/oct/banner2.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/banner3.jpg b/trunk/etherpad/src/static/img/oct/banner3.jpg
deleted file mode 100644
index c0260a3..0000000
--- a/trunk/etherpad/src/static/img/oct/banner3.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/banner4.jpg b/trunk/etherpad/src/static/img/oct/banner4.jpg
deleted file mode 100644
index e1593b7..0000000
--- a/trunk/etherpad/src/static/img/oct/banner4.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/banner5.gif b/trunk/etherpad/src/static/img/oct/banner5.gif
deleted file mode 100644
index 82c8eee..0000000
--- a/trunk/etherpad/src/static/img/oct/banner5.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/banner6.gif b/trunk/etherpad/src/static/img/oct/banner6.gif
deleted file mode 100644
index 9016ed8..0000000
--- a/trunk/etherpad/src/static/img/oct/banner6.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/banner7.gif b/trunk/etherpad/src/static/img/oct/banner7.gif
deleted file mode 100644
index a999f93..0000000
--- a/trunk/etherpad/src/static/img/oct/banner7.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/banner8.gif b/trunk/etherpad/src/static/img/oct/banner8.gif
deleted file mode 100644
index cc2c436..0000000
--- a/trunk/etherpad/src/static/img/oct/banner8.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/banner9.gif b/trunk/etherpad/src/static/img/oct/banner9.gif
deleted file mode 100644
index e7d9043..0000000
--- a/trunk/etherpad/src/static/img/oct/banner9.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/bannerback5.gif b/trunk/etherpad/src/static/img/oct/bannerback5.gif
deleted file mode 100644
index d748357..0000000
--- a/trunk/etherpad/src/static/img/oct/bannerback5.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/bannerback6.gif b/trunk/etherpad/src/static/img/oct/bannerback6.gif
deleted file mode 100644
index 416314f..0000000
--- a/trunk/etherpad/src/static/img/oct/bannerback6.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/bodyback1.gif b/trunk/etherpad/src/static/img/oct/bodyback1.gif
deleted file mode 100644
index 39d3fd7..0000000
--- a/trunk/etherpad/src/static/img/oct/bodyback1.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/bodyback2.gif b/trunk/etherpad/src/static/img/oct/bodyback2.gif
deleted file mode 100644
index 5bbdad8..0000000
--- a/trunk/etherpad/src/static/img/oct/bodyback2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/bodyback3.gif b/trunk/etherpad/src/static/img/oct/bodyback3.gif
deleted file mode 100644
index a04faf4..0000000
--- a/trunk/etherpad/src/static/img/oct/bodyback3.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/bodyback4.gif b/trunk/etherpad/src/static/img/oct/bodyback4.gif
deleted file mode 100644
index a875cd6..0000000
--- a/trunk/etherpad/src/static/img/oct/bodyback4.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/bodyback5.gif b/trunk/etherpad/src/static/img/oct/bodyback5.gif
deleted file mode 100644
index 66f67ce..0000000
--- a/trunk/etherpad/src/static/img/oct/bodyback5.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/bodybacktop1.gif b/trunk/etherpad/src/static/img/oct/bodybacktop1.gif
deleted file mode 100644
index 20a9261..0000000
--- a/trunk/etherpad/src/static/img/oct/bodybacktop1.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/computers.gif b/trunk/etherpad/src/static/img/oct/computers.gif
deleted file mode 100644
index c8f2aff..0000000
--- a/trunk/etherpad/src/static/img/oct/computers.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/computers2.gif b/trunk/etherpad/src/static/img/oct/computers2.gif
deleted file mode 100644
index bd8d133..0000000
--- a/trunk/etherpad/src/static/img/oct/computers2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/glossyblue.gif b/trunk/etherpad/src/static/img/oct/glossyblue.gif
deleted file mode 100644
index eed77e7..0000000
--- a/trunk/etherpad/src/static/img/oct/glossyblue.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/glossyblue2.gif b/trunk/etherpad/src/static/img/oct/glossyblue2.gif
deleted file mode 100644
index c323ebb..0000000
--- a/trunk/etherpad/src/static/img/oct/glossyblue2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/glossyblueh.gif b/trunk/etherpad/src/static/img/oct/glossyblueh.gif
deleted file mode 100644
index e56ceeb..0000000
--- a/trunk/etherpad/src/static/img/oct/glossyblueh.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/insetrect.gif b/trunk/etherpad/src/static/img/oct/insetrect.gif
deleted file mode 100644
index 1d8124d..0000000
--- a/trunk/etherpad/src/static/img/oct/insetrect.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minilogo1-05e.gif b/trunk/etherpad/src/static/img/oct/minilogo1-05e.gif
deleted file mode 100644
index a09ef16..0000000
--- a/trunk/etherpad/src/static/img/oct/minilogo1-05e.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minilogo1-07f.gif b/trunk/etherpad/src/static/img/oct/minilogo1-07f.gif
deleted file mode 100644
index 8565272..0000000
--- a/trunk/etherpad/src/static/img/oct/minilogo1-07f.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minilogo3.jpg b/trunk/etherpad/src/static/img/oct/minilogo3.jpg
deleted file mode 100644
index d0cd89b..0000000
--- a/trunk/etherpad/src/static/img/oct/minilogo3.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minitopback1.gif b/trunk/etherpad/src/static/img/oct/minitopback1.gif
deleted file mode 100644
index da8f575..0000000
--- a/trunk/etherpad/src/static/img/oct/minitopback1.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minitopback2.gif b/trunk/etherpad/src/static/img/oct/minitopback2.gif
deleted file mode 100644
index a1f43ab..0000000
--- a/trunk/etherpad/src/static/img/oct/minitopback2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minitopbar1-05e.gif b/trunk/etherpad/src/static/img/oct/minitopbar1-05e.gif
deleted file mode 100644
index 1115749..0000000
--- a/trunk/etherpad/src/static/img/oct/minitopbar1-05e.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minitopbar2-05e.gif b/trunk/etherpad/src/static/img/oct/minitopbar2-05e.gif
deleted file mode 100644
index 2c5d10f..0000000
--- a/trunk/etherpad/src/static/img/oct/minitopbar2-05e.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minitopbar2-07f.gif b/trunk/etherpad/src/static/img/oct/minitopbar2-07f.gif
deleted file mode 100644
index 5687aed..0000000
--- a/trunk/etherpad/src/static/img/oct/minitopbar2-07f.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minitopbar3.jpg b/trunk/etherpad/src/static/img/oct/minitopbar3.jpg
deleted file mode 100644
index d0cd89b..0000000
--- a/trunk/etherpad/src/static/img/oct/minitopbar3.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minitopbar4.gif b/trunk/etherpad/src/static/img/oct/minitopbar4.gif
deleted file mode 100644
index bf7aec9..0000000
--- a/trunk/etherpad/src/static/img/oct/minitopbar4.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minitoplogo1.gif b/trunk/etherpad/src/static/img/oct/minitoplogo1.gif
deleted file mode 100644
index 6317c0f..0000000
--- a/trunk/etherpad/src/static/img/oct/minitoplogo1.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/minitoplogo2.gif b/trunk/etherpad/src/static/img/oct/minitoplogo2.gif
deleted file mode 100644
index bbb5e21..0000000
--- a/trunk/etherpad/src/static/img/oct/minitoplogo2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/newpadmain.gif b/trunk/etherpad/src/static/img/oct/newpadmain.gif
deleted file mode 100644
index 6427037..0000000
--- a/trunk/etherpad/src/static/img/oct/newpadmain.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/newpadmainback.gif b/trunk/etherpad/src/static/img/oct/newpadmainback.gif
deleted file mode 100644
index 2016864..0000000
--- a/trunk/etherpad/src/static/img/oct/newpadmainback.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/newpadmainbackh.gif b/trunk/etherpad/src/static/img/oct/newpadmainbackh.gif
deleted file mode 100644
index 3060634..0000000
--- a/trunk/etherpad/src/static/img/oct/newpadmainbackh.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/pageshot.png b/trunk/etherpad/src/static/img/oct/pageshot.png
deleted file mode 100644
index cb86428..0000000
--- a/trunk/etherpad/src/static/img/oct/pageshot.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/pageshotmini.png b/trunk/etherpad/src/static/img/oct/pageshotmini.png
deleted file mode 100644
index 0f8a9d0..0000000
--- a/trunk/etherpad/src/static/img/oct/pageshotmini.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/sidehead-gradhilite.gif b/trunk/etherpad/src/static/img/oct/sidehead-gradhilite.gif
deleted file mode 100644
index 5469d87..0000000
--- a/trunk/etherpad/src/static/img/oct/sidehead-gradhilite.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/tinytriangle.gif b/trunk/etherpad/src/static/img/oct/tinytriangle.gif
deleted file mode 100644
index 1821e3b..0000000
--- a/trunk/etherpad/src/static/img/oct/tinytriangle.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/topnav1.gif b/trunk/etherpad/src/static/img/oct/topnav1.gif
deleted file mode 100644
index d801c59..0000000
--- a/trunk/etherpad/src/static/img/oct/topnav1.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/topnav2.gif b/trunk/etherpad/src/static/img/oct/topnav2.gif
deleted file mode 100644
index c1ab5c5..0000000
--- a/trunk/etherpad/src/static/img/oct/topnav2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/topnav3.gif b/trunk/etherpad/src/static/img/oct/topnav3.gif
deleted file mode 100644
index fa25e75..0000000
--- a/trunk/etherpad/src/static/img/oct/topnav3.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/topnav4.gif b/trunk/etherpad/src/static/img/oct/topnav4.gif
deleted file mode 100644
index 1f4c714..0000000
--- a/trunk/etherpad/src/static/img/oct/topnav4.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/topnav5.gif b/trunk/etherpad/src/static/img/oct/topnav5.gif
deleted file mode 100644
index fa8b737..0000000
--- a/trunk/etherpad/src/static/img/oct/topnav5.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/topnav6.gif b/trunk/etherpad/src/static/img/oct/topnav6.gif
deleted file mode 100644
index e0e6815..0000000
--- a/trunk/etherpad/src/static/img/oct/topnav6.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/topnavback1.gif b/trunk/etherpad/src/static/img/oct/topnavback1.gif
deleted file mode 100644
index 55103a3..0000000
--- a/trunk/etherpad/src/static/img/oct/topnavback1.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/topnavback2.gif b/trunk/etherpad/src/static/img/oct/topnavback2.gif
deleted file mode 100644
index 9b4bdca..0000000
--- a/trunk/etherpad/src/static/img/oct/topnavback2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/topnavback3.gif b/trunk/etherpad/src/static/img/oct/topnavback3.gif
deleted file mode 100644
index 327cba1..0000000
--- a/trunk/etherpad/src/static/img/oct/topnavback3.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/usecasesnavdown.gif b/trunk/etherpad/src/static/img/oct/usecasesnavdown.gif
deleted file mode 100644
index c8fc7df..0000000
--- a/trunk/etherpad/src/static/img/oct/usecasesnavdown.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/usecasesnavdownh.gif b/trunk/etherpad/src/static/img/oct/usecasesnavdownh.gif
deleted file mode 100644
index e1fa3a5..0000000
--- a/trunk/etherpad/src/static/img/oct/usecasesnavdownh.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/usecasesnavup.gif b/trunk/etherpad/src/static/img/oct/usecasesnavup.gif
deleted file mode 100644
index 470dcbe..0000000
--- a/trunk/etherpad/src/static/img/oct/usecasesnavup.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/usecasesnavuph.gif b/trunk/etherpad/src/static/img/oct/usecasesnavuph.gif
deleted file mode 100644
index 4207386..0000000
--- a/trunk/etherpad/src/static/img/oct/usecasesnavuph.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/oct/watchscreencast.gif b/trunk/etherpad/src/static/img/oct/watchscreencast.gif
deleted file mode 100644
index f52ed17..0000000
--- a/trunk/etherpad/src/static/img/oct/watchscreencast.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/animated-orb-orange-12.gif b/trunk/etherpad/src/static/img/pad/animated-orb-orange-12.gif
deleted file mode 100644
index 9db02c6..0000000
--- a/trunk/etherpad/src/static/img/pad/animated-orb-orange-12.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/backgrad.png b/trunk/etherpad/src/static/img/pad/backgrad.png
deleted file mode 100644
index d85f73c..0000000
--- a/trunk/etherpad/src/static/img/pad/backgrad.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-eee-20.gif b/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-eee-20.gif
deleted file mode 100644
index bc3088b..0000000
--- a/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-eee-20.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-20.gif b/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-20.gif
deleted file mode 100644
index 8a87283..0000000
--- a/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-20.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-40.gif b/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-40.gif
deleted file mode 100644
index 695ecbe..0000000
--- a/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-40.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-60.gif b/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-60.gif
deleted file mode 100644
index 0005405..0000000
--- a/trunk/etherpad/src/static/img/pad/backshadow/backshadow-940-20-fff-60.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/backshadow/botshadow-940-20-eee-20.gif b/trunk/etherpad/src/static/img/pad/backshadow/botshadow-940-20-eee-20.gif
deleted file mode 100644
index 92fb5dc..0000000
--- a/trunk/etherpad/src/static/img/pad/backshadow/botshadow-940-20-eee-20.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/etherpad-logo-small-grad.gif b/trunk/etherpad/src/static/img/pad/etherpad-logo-small-grad.gif
deleted file mode 100644
index a65aa15..0000000
--- a/trunk/etherpad/src/static/img/pad/etherpad-logo-small-grad.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/etherpad-logo-small.gif b/trunk/etherpad/src/static/img/pad/etherpad-logo-small.gif
deleted file mode 100644
index 6669f39..0000000
--- a/trunk/etherpad/src/static/img/pad/etherpad-logo-small.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/etherpad-logo-small2.gif b/trunk/etherpad/src/static/img/pad/etherpad-logo-small2.gif
deleted file mode 100644
index 6e33392..0000000
--- a/trunk/etherpad/src/static/img/pad/etherpad-logo-small2.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/expandy-arrow-down.gif b/trunk/etherpad/src/static/img/pad/expandy-arrow-down.gif
deleted file mode 100644
index 4b67c17..0000000
--- a/trunk/etherpad/src/static/img/pad/expandy-arrow-down.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/expandy-arrow-right.gif b/trunk/etherpad/src/static/img/pad/expandy-arrow-right.gif
deleted file mode 100644
index 61303e6..0000000
--- a/trunk/etherpad/src/static/img/pad/expandy-arrow-right.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/expandy-arrow6-down-active.gif b/trunk/etherpad/src/static/img/pad/expandy-arrow6-down-active.gif
deleted file mode 100644
index 5f530b7..0000000
--- a/trunk/etherpad/src/static/img/pad/expandy-arrow6-down-active.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/expandy-arrow6-down.gif b/trunk/etherpad/src/static/img/pad/expandy-arrow6-down.gif
deleted file mode 100644
index 42fa9af..0000000
--- a/trunk/etherpad/src/static/img/pad/expandy-arrow6-down.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/expandy-arrow6-right-active.gif b/trunk/etherpad/src/static/img/pad/expandy-arrow6-right-active.gif
deleted file mode 100644
index 4496fad..0000000
--- a/trunk/etherpad/src/static/img/pad/expandy-arrow6-right-active.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/expandy-arrow6-right.gif b/trunk/etherpad/src/static/img/pad/expandy-arrow6-right.gif
deleted file mode 100644
index 9a8274c..0000000
--- a/trunk/etherpad/src/static/img/pad/expandy-arrow6-right.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/header-revgrad.gif b/trunk/etherpad/src/static/img/pad/header-revgrad.gif
deleted file mode 100644
index e803e2a..0000000
--- a/trunk/etherpad/src/static/img/pad/header-revgrad.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/newpad.gif b/trunk/etherpad/src/static/img/pad/newpad.gif
deleted file mode 100644
index c631cc4..0000000
--- a/trunk/etherpad/src/static/img/pad/newpad.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/orb-greenred-12.gif b/trunk/etherpad/src/static/img/pad/orb-greenred-12.gif
deleted file mode 100644
index d722168..0000000
--- a/trunk/etherpad/src/static/img/pad/orb-greenred-12.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/padbg1.jpg b/trunk/etherpad/src/static/img/pad/padbg1.jpg
deleted file mode 100644
index 8e640fd..0000000
--- a/trunk/etherpad/src/static/img/pad/padbg1.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/padbg2.jpg b/trunk/etherpad/src/static/img/pad/padbg2.jpg
deleted file mode 100644
index 1248bc0..0000000
--- a/trunk/etherpad/src/static/img/pad/padbg2.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/padbg3.jpg b/trunk/etherpad/src/static/img/pad/padbg3.jpg
deleted file mode 100644
index 99bba32..0000000
--- a/trunk/etherpad/src/static/img/pad/padbg3.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/padbg4.jpg b/trunk/etherpad/src/static/img/pad/padbg4.jpg
deleted file mode 100644
index 2497360..0000000
--- a/trunk/etherpad/src/static/img/pad/padbg4.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/padbg5.jpg b/trunk/etherpad/src/static/img/pad/padbg5.jpg
deleted file mode 100644
index bc3953c..0000000
--- a/trunk/etherpad/src/static/img/pad/padbg5.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/padhead1.jpg b/trunk/etherpad/src/static/img/pad/padhead1.jpg
deleted file mode 100644
index e263cf4..0000000
--- a/trunk/etherpad/src/static/img/pad/padhead1.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/padhead2.jpg b/trunk/etherpad/src/static/img/pad/padhead2.jpg
deleted file mode 100644
index a2f247d..0000000
--- a/trunk/etherpad/src/static/img/pad/padhead2.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/padhead3.jpg b/trunk/etherpad/src/static/img/pad/padhead3.jpg
deleted file mode 100644
index 101432f..0000000
--- a/trunk/etherpad/src/static/img/pad/padhead3.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/pencil-icon-small-blue.gif b/trunk/etherpad/src/static/img/pad/pencil-icon-small-blue.gif
deleted file mode 100644
index f60b0f2..0000000
--- a/trunk/etherpad/src/static/img/pad/pencil-icon-small-blue.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/sidehead-grad.gif b/trunk/etherpad/src/static/img/pad/sidehead-grad.gif
deleted file mode 100644
index 32bac92..0000000
--- a/trunk/etherpad/src/static/img/pad/sidehead-grad.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/button_depressed.png b/trunk/etherpad/src/static/img/pad/timeslider/button_depressed.png
deleted file mode 100644
index 1e96692..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/button_depressed.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/button_undepressed.png b/trunk/etherpad/src/static/img/pad/timeslider/button_undepressed.png
deleted file mode 100644
index cd2d7a8..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/button_undepressed.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/crushed_pause.png b/trunk/etherpad/src/static/img/pad/timeslider/crushed_pause.png
deleted file mode 100644
index 437b384..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/crushed_pause.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/crushed_play.png b/trunk/etherpad/src/static/img/pad/timeslider/crushed_play.png
deleted file mode 100644
index c5b754b..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/crushed_play.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/crushed_play_button.png b/trunk/etherpad/src/static/img/pad/timeslider/crushed_play_button.png
deleted file mode 100644
index 3b112f6..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/crushed_play_button.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/current_location.gif b/trunk/etherpad/src/static/img/pad/timeslider/current_location.gif
deleted file mode 100644
index 5d5062f..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/current_location.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/pause.gif b/trunk/etherpad/src/static/img/pad/timeslider/pause.gif
deleted file mode 100644
index 0fa105b..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/pause.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/play.gif b/trunk/etherpad/src/static/img/pad/timeslider/play.gif
deleted file mode 100644
index ae308c2..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/play.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/star.gif b/trunk/etherpad/src/static/img/pad/timeslider/star.gif
deleted file mode 100644
index f6a2c70..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/star.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pad/timeslider/timeslider_mockup.png b/trunk/etherpad/src/static/img/pad/timeslider/timeslider_mockup.png
deleted file mode 100644
index bc93914..0000000
--- a/trunk/etherpad/src/static/img/pad/timeslider/timeslider_mockup.png
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pricing/free.gif b/trunk/etherpad/src/static/img/pricing/free.gif
deleted file mode 100644
index bce2a0b..0000000
--- a/trunk/etherpad/src/static/img/pricing/free.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pricing/group.gif b/trunk/etherpad/src/static/img/pricing/group.gif
deleted file mode 100644
index b839d3e..0000000
--- a/trunk/etherpad/src/static/img/pricing/group.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pricing/on-demand.gif b/trunk/etherpad/src/static/img/pricing/on-demand.gif
deleted file mode 100644
index 19d2e57..0000000
--- a/trunk/etherpad/src/static/img/pricing/on-demand.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pricing/private-network.gif b/trunk/etherpad/src/static/img/pricing/private-network.gif
deleted file mode 100644
index 70d197f..0000000
--- a/trunk/etherpad/src/static/img/pricing/private-network.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pricing/support.gif b/trunk/etherpad/src/static/img/pricing/support.gif
deleted file mode 100644
index 7f42f76..0000000
--- a/trunk/etherpad/src/static/img/pricing/support.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/billing/cards-button.gif b/trunk/etherpad/src/static/img/pro/billing/cards-button.gif
deleted file mode 100644
index 2f9c8cf..0000000
--- a/trunk/etherpad/src/static/img/pro/billing/cards-button.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/pro/header/pro-header-back.gif b/trunk/etherpad/src/static/img/pro/header/pro-header-back.gif
deleted file mode 100644
index 9514dbf..0000000
--- a/trunk/etherpad/src/static/img/pro/header/pro-header-back.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/tinyplane.gif b/trunk/etherpad/src/static/img/tinyplane.gif
deleted file mode 100644
index 5aaa223..0000000
--- a/trunk/etherpad/src/static/img/tinyplane.gif
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/img/wavejet.jpg b/trunk/etherpad/src/static/img/wavejet.jpg
deleted file mode 100644
index 8d10fd0..0000000
--- a/trunk/etherpad/src/static/img/wavejet.jpg
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/static/js/broadcast.js b/trunk/etherpad/src/static/js/broadcast.js
deleted file mode 100644
index 9fa8141..0000000
--- a/trunk/etherpad/src/static/js/broadcast.js
+++ /dev/null
@@ -1,607 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-// just in case... (todo: this must be somewhere else in the client code.)
-if (!Array.prototype.map)
-{
- Array.prototype.map = function(fun /*, thisp*/)
- {
- var len = this.length >>> 0;
- if (typeof fun != "function")
- throw new TypeError();
-
- var res = new Array(len);
- var thisp = arguments[1];
- for (var i = 0; i < len; i++)
- {
- if (i in this)
- res[i] = fun.call(thisp, this[i], i, this);
- }
-
- return res;
- };
-}
-
-if (!Array.prototype.forEach)
-{
- Array.prototype.forEach = function(fun /*, thisp*/)
- {
- var len = this.length >>> 0;
- if (typeof fun != "function")
- throw new TypeError();
-
- var thisp = arguments[1];
- for (var i = 0; i < len; i++)
- {
- if (i in this)
- fun.call(thisp, this[i], i, this);
- }
- };
-}
-
-if (!Array.prototype.indexOf)
-{
- Array.prototype.indexOf = function(elt /*, from*/)
- {
- var len = this.length >>> 0;
-
- var from = Number(arguments[1]) || 0;
- from = (from < 0)
- ? Math.ceil(from)
- : Math.floor(from);
- if (from < 0)
- from += len;
-
- for (; from < len; from++)
- {
- if (from in this &&
- this[from] === elt)
- return from;
- }
- return -1;
- };
-}
-
-function debugLog() {
- try {
- // console.log.apply(console, arguments);
- } catch (e) {console.log("error printing: ",e);}
-}
-
-function randomString() {
- return "_"+Math.floor(Math.random() * 1000000);
-}
-
-// for IE
-if ($.browser.msie) {
- try {
- document.execCommand("BackgroundImageCache", false, true);
- } catch (e) {}
-}
-
-var userId = "hiddenUser" + randomString();
-var socketId;
-var socket;
-
-var channelState = "DISCONNECTED";
-
-var appLevelDisconnectReason = null;
-
-var padContents = {
- currentRevision: clientVars.revNum,
- currentTime : clientVars.currentTime,
- currentLines: Changeset.splitTextLines(clientVars.initialStyledContents.atext.text),
- currentDivs : null, // to be filled in once the dom loads
- apool: (new AttribPool()).fromJsonable(clientVars.initialStyledContents.apool),
- alines: Changeset.splitAttributionLines(
- clientVars.initialStyledContents.atext.attribs,
- clientVars.initialStyledContents.atext.text),
-
- // generates a jquery element containing HTML for a line
- lineToElement: function(line, aline) {
- var element = document.createElement("div");
- var emptyLine = (line == '\n');
- var domInfo = domline.createDomLine(! emptyLine, true);
- linestylefilter.populateDomLine(line, aline, this.apool,
- domInfo);
- domInfo.prepareForAdd();
- element.className = domInfo.node.className;
- element.innerHTML = domInfo.node.innerHTML;
- element.id = Math.random();
- return $(element);
- },
-
- applySpliceToDivs: function(start, numRemoved, newLines) {
- // remove spliced-out lines from DOM
- for(var i=start; i<start+numRemoved && i<this.currentDivs.length; i++) {
- debugLog("removing", this.currentDivs[i].attr('id'));
- this.currentDivs[i].remove();
- }
-
- // remove spliced-out line divs from currentDivs array
- this.currentDivs.splice(start, numRemoved);
-
- var newDivs = [];
- for(var i=0;i<newLines.length;i++) {
- newDivs.push(this.lineToElement(newLines[i],
- this.alines[start+i]));
- }
-
- // grab the div just before the first one
- var startDiv = this.currentDivs[start-1] || null;
-
- // insert the div elements into the correct place, in the correct order
- for(var i=0; i<newDivs.length; i++) {
- if (startDiv) {
- startDiv.after(newDivs[i]);
- }
- else {
- $("#padcontent").prepend(newDivs[i]);
- }
- startDiv = newDivs[i];
- }
-
- // insert new divs into currentDivs array
- newDivs.unshift(0); // remove 0 elements
- newDivs.unshift(start);
- this.currentDivs.splice.apply(this.currentDivs, newDivs);
- return this;
- },
-
- // splice the lines
- splice: function(start, numRemoved, newLinesVA) {
- var newLines = Array.prototype.slice.call(arguments, 2).map(
- function(s) { return s; });
-
- // apply this splice to the divs
- this.applySpliceToDivs(start, numRemoved, newLines);
-
- // call currentLines.splice, to keep the currentLines array up to date
- newLines.unshift(numRemoved);
- newLines.unshift(start);
- this.currentLines.splice.apply(this.currentLines, arguments);
- },
- // returns the contents of the specified line I
- get: function(i) {
- return this.currentLines[i];
- },
- // returns the number of lines in the document
- length: function() {
- return this.currentLines.length;
- },
-
- getActiveAuthors: function() {
- var self = this;
- var authors = [];
- var seenNums = {};
- var alines = self.alines;
- for(var i=0;i<alines.length;i++) {
- Changeset.eachAttribNumber(alines[i], function(n) {
- if (! seenNums[n]) {
- seenNums[n] = true;
- if (self.apool.getAttribKey(n) == 'author') {
- var a = self.apool.getAttribValue(n);
- if (a) {
- authors.push(a);
- }
- }
- }
- });
- }
- authors.sort();
- return authors;
- }
-};
-
-function callCatchingErrors(catcher, func) {
- try {
- wrapRecordingErrors(catcher, func)();
- }
- catch (e) { /*absorb*/ }
-}
-
-function wrapRecordingErrors(catcher, func) {
- return function() {
- try {
- return func.apply(this, Array.prototype.slice.call(arguments));
- }
- catch (e) {
- // caughtErrors.push(e);
- // caughtErrorCatchers.push(catcher);
- // caughtErrorTimes.push(+new Date());
- // console.dir({catcher: catcher, e: e});
- debugLog(e); // TODO(kroo): added temporary, to catch errors
- throw e;
- }
- };
-}
-
-function loadedNewChangeset(changesetForward, changesetBackward, revision, timeDelta) {
- var broadcasting = (BroadcastSlider.getSliderPosition() == revisionInfo.latest);
- debugLog("broadcasting:", broadcasting, BroadcastSlider.getSliderPosition(), revisionInfo.latest, revision);
- revisionInfo.addChangeset(revision, revision+1, changesetForward, changesetBackward, timeDelta);
- BroadcastSlider.setSliderLength(revisionInfo.latest);
- if(broadcasting)
- applyChangeset(changesetForward, revision+1, false, timeDelta);
-}
-
-/*
- At this point, we must be certain that the changeset really does map from
- the current revision to the specified revision. Any mistakes here will
- cause the whole slider to get out of sync.
- */
-function applyChangeset(changeset, revision, preventSliderMovement, timeDelta) {
- // disable the next 'gotorevision' call handled by a timeslider update
- if(!preventSliderMovement) {
- goToRevisionIfEnabledCount ++;
- BroadcastSlider.setSliderPosition(revision);
- }
-
- try {
- // must mutate attribution lines before text lines
- Changeset.mutateAttributionLines(changeset, padContents.alines, padContents.apool);
- }catch(e) { debugLog(e); }
-
- Changeset.mutateTextLines(changeset, padContents);
- padContents.currentRevision = revision;
- padContents.currentTime += timeDelta * 1000;
- debugLog('Time Delta: ',timeDelta)
- updateTimer();
- BroadcastSlider.setAuthors(padContents.getActiveAuthors().map(function(name) {return authorData[name];}));
-}
-
-function updateTimer() {
- var zpad = function(str, length) {
- str = str+"";
- while(str.length < length)
- str = '0'+str;
- return str;
- }
- var date = new Date(padContents.currentTime);
- var dateFormat = function() {
- var month = zpad(date.getMonth()+1,2);
- var day = zpad(date.getDate(),2);
- var year = (date.getFullYear());
- var hours = zpad(date.getHours(),2);
- var minutes = zpad(date.getMinutes(),2);
- var seconds = zpad(date.getSeconds(),2);
- return ([month,'/',day,'/',year,' ',hours,':',minutes,':',seconds].join(""));
- }
-
- $('#timer').html(dateFormat());
-
- var revisionDate = [
- "Saved",
- [
- "Jan", "Feb", "March", "April", "May", "June",
- "July", "Aug", "Sept", "Oct", "Nov", "Dec"
- ][date.getMonth()],
- date.getDate()+",",
- date.getFullYear()
- ].join(" ")
- $('#revision_date').html(revisionDate)
-
-}
-
-function goToRevision(newRevision) {
- padContents.targetRevision = newRevision;
- var self = this;
- var path = revisionInfo.getPath(padContents.currentRevision, newRevision);
- debugLog('newRev: ', padContents.currentRevision, path);
- if( path.status == 'complete') {
- var cs = path.changesets;
- debugLog("status: complete, changesets: ",cs, "path:", path);
- var changeset = cs[0];
- var timeDelta = path.times[0];
- for(var i=1; i<cs.length; i++) {
- changeset = Changeset.compose(changeset, cs[i], padContents.apool);
- timeDelta += path.times[i];
- }
- if(changeset)
- applyChangeset(changeset, path.rev, true, timeDelta);
- } else if(path.status == "partial") {
- debugLog('partial');
- var sliderLocation = padContents.currentRevision;
- // callback is called after changeset information is pulled from server
- // this may never get called, if the changeset has already been loaded
- var update = function(start, end) {
- // if we've called goToRevision in the time since, don't goToRevision
- goToRevision(padContents.targetRevision);
- };
-
- // do our best with what we have...
- var cs = path.changesets;
-
- var changeset = cs[0];
- var timeDelta = path.times[0];
- for(var i=1; i<cs.length; i++) {
- changeset = Changeset.compose(changeset, cs[i], padContents.apool);
- timeDelta += path.times[i];
- }
- if(changeset)
- applyChangeset(changeset, path.rev, true, timeDelta);
-
-
- if(BroadcastSlider.getSliderLength() > 10000) {
- var start = (Math.floor((newRevision) / 10000) * 10000); // revision 0 to 10
- changesetLoader.queueUp(start, 100);
- }
-
- if(BroadcastSlider.getSliderLength() > 1000) {
- var start = (Math.floor((newRevision) / 1000) * 1000); // (start from -1, go to 19) + 1
- changesetLoader.queueUp(start, 10);
- }
-
- start = (Math.floor((newRevision) / 100) * 100);
-
- changesetLoader.queueUp(start, 1, update);
- }
- BroadcastSlider.setAuthors(padContents.getActiveAuthors().map(function(name) {return authorData[name];}));
-}
-
-var changesetLoader = {
- running: false,
- resolved: [],
- requestQueue1: [],
- requestQueue2: [],
- requestQueue3: [],
- queueUp: function(revision, width, callback) {
- if(revision < 0) revision = 0;
- // if(changesetLoader.requestQueue.indexOf(revision) != -1)
- // return; // already in the queue.
- if(changesetLoader.resolved.indexOf(revision+"_"+width) != -1)
- return; // already loaded from the server
- changesetLoader.resolved.push(revision+"_"+width);
-
- var requestQueue = width == 1 ? changesetLoader.requestQueue3 :
- width == 10 ? changesetLoader.requestQueue2 :
- changesetLoader.requestQueue1;
- requestQueue.push({'rev': revision, 'res': width, 'callback': callback});
- if(!changesetLoader.running) {
- changesetLoader.running = true;
- setTimeout(changesetLoader.loadFromQueue, 10);
- }
- },
- loadFromQueue: function() {
- var self = changesetLoader;
- var requestQueue = self.requestQueue1.length > 0 ? self.requestQueue1 :
- self.requestQueue2.length > 0 ? self.requestQueue2 :
- self.requestQueue3.length > 0 ? self.requestQueue3 : null;
-
- if(!requestQueue) {
- self.running = false;
- return;
- }
-
- var request = requestQueue.pop();
- var granularity = request.res;
- var callback = request.callback;
- var start = request.rev;
- debugLog("loadinging revision", start, "through ajax");
- $.getJSON(
- "/ep/pad/changes/"+clientVars.padIdForUrl+"?s="+start + "&g="+granularity,
- function(data, textStatus) {
- if(textStatus !== "success") {
- console.log(textStatus);
- BroadcastSlider.showReconnectUI();
- }
- self.handleResponse(data, start, granularity, callback);
-
- setTimeout(self.loadFromQueue, 10); // load the next ajax function
- }
- );
- },
- handleResponse: function(data, start, granularity, callback) {
- debugLog("response: ", data);
- var pool = (new AttribPool()).fromJsonable(data.apool);
- for(var i=0; i<data.forwardsChangesets.length; i++) {
- var astart = start + i * granularity - 1; // rev -1 is a blank single line
- var aend = start + (i+1) * granularity - 1;// totalRevs is the most recent revision
- if(aend > data.actualEndNum - 1) aend = data.actualEndNum - 1;
- debugLog("adding changeset:", astart, aend);
- var forwardcs = Changeset.moveOpsToNewPool(data.forwardsChangesets[i], pool, padContents.apool);
- var backwardcs = Changeset.moveOpsToNewPool(data.backwardsChangesets[i], pool, padContents.apool);
- revisionInfo.addChangeset(astart, aend, forwardcs, backwardcs, data.timeDeltas[i]);
- }
- if(callback)callback(start - 1, start + data.forwardsChangesets.length * granularity - 1);
- }
-};
-
-function handleMessageFromServer() {
- debugLog("handleMessage:", arguments);
- var obj = arguments[0]['data'];
- var expectedType = "COLLABROOM";
-
- obj = JSON.parse(obj);
- if (obj['type'] == expectedType) {
- obj = obj['data'];
-
- if (obj['type'] == "NEW_CHANGES") {
- debugLog(obj);
- var changeset = Changeset.moveOpsToNewPool(
- obj.changeset, (new AttribPool()).fromJsonable(obj.apool),
- padContents.apool);
-
- var changesetBack = Changeset.moveOpsToNewPool(
- obj.changesetBack, (new AttribPool()).fromJsonable(obj.apool),
- padContents.apool);
-
- loadedNewChangeset(changeset, changesetBack, obj.newRev-1, obj.timeDelta);
- }
- else if (obj['type'] == "NEW_AUTHORDATA") {
- var authorMap = {};
- authorMap[obj.author] = obj.data;
- receiveAuthorData(authorMap);
- BroadcastSlider.setAuthors(padContents.getActiveAuthors().map(function(name) {return authorData[name];}));
- } else if (obj['type'] == "NEW_SAVEDREV") {
- var savedRev = obj.savedRev;
- BroadcastSlider.addSavedRevision(savedRev.revNum, savedRev);
- }
- } else {
- debugLog("incorrect message type: " + obj['type'] + ", expected " + expectedType);
- }
-}
-
-function handleSocketClosed(params) {
- debugLog("socket closed!", params);
- socket = null;
-
- BroadcastSlider.showReconnectUI();
- // var reason = appLevelDisconnectReason || params.reason;
- // var shouldReconnect = params.reconnect;
- // if (shouldReconnect) {
- // // determine if this is a tight reconnect loop due to weird connectivity problems
- // // reconnectTimes.push(+new Date());
- // var TOO_MANY_RECONNECTS = 8;
- // var TOO_SHORT_A_TIME_MS = 10000;
- // if (reconnectTimes.length >= TOO_MANY_RECONNECTS &&
- // ((+new Date()) - reconnectTimes[reconnectTimes.length-TOO_MANY_RECONNECTS]) <
- // TOO_SHORT_A_TIME_MS) {
- // setChannelState("DISCONNECTED", "looping");
- // }
- // else {
- // setChannelState("RECONNECTING", reason);
- // setUpSocket();
- // }
- // }
- // else {
- // BroadcastSlider.showReconnectUI();
- // setChannelState("DISCONNECTED", reason);
- // }
-}
-
-function sendMessage(msg) {
- socket.postMessage(JSON.stringify({type: "COLLABROOM", data: msg}));
-}
-
-function setUpSocket() {
- // required for Comet
- if ((! $.browser.msie) &&
- (! ($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0))) {
- document.domain = document.domain; // for comet
- }
-
- var success = false;
- callCatchingErrors("setUpSocket", function() {
- appLevelDisconnectReason = null;
-
- socketId = String(Math.floor(Math.random()*1e12));
- socket = new WebSocket(socketId);
- socket.onmessage = wrapRecordingErrors("socket.onmessage", handleMessageFromServer);
- socket.onclosed = wrapRecordingErrors("socket.onclosed", handleSocketClosed);
- socket.onopen = wrapRecordingErrors("socket.onopen", function() {
- setChannelState("CONNECTED");
- var msg = { type:"CLIENT_READY", roomType:'padview',
- roomName:'padview/'+clientVars.viewId,
- data: { lastRev:clientVars.revNum,
- userInfo:{userId: userId} } };
- sendMessage(msg);
- });
- // socket.onhiccup = wrapRecordingErrors("socket.onhiccup", handleCometHiccup);
- // socket.onlogmessage = function(x) {debugLog(x); };
- socket.connect();
- success = true;
- });
- if (success) {
- //initialStartConnectTime = +new Date();
- }
- else {
- abandonConnection("initsocketfail");
- }
-}
-
-function setChannelState(newChannelState, moreInfo) {
- if (newChannelState != channelState) {
- channelState = newChannelState;
- // callbacks.onChannelStateChange(channelState, moreInfo);
- }
-}
-
-function abandonConnection(reason) {
- if (socket) {
- socket.onclosed = function() {};
- socket.onhiccup = function() {};
- socket.disconnect();
- }
- socket = null;
- setChannelState("DISCONNECTED", reason);
-}
-
-window['onloadFuncts'] = [];
-window.onload = function() {
- window['isloaded'] = true;
- window['onloadFuncts'].forEach(function(funct) {
- funct();
- });
-};
-
-// to start upon window load, just push a function onto this array
-window['onloadFuncts'].push(setUpSocket);
-window['onloadFuncts'].push(function() {
- // set up the currentDivs and DOM
- padContents.currentDivs = [];
- $("#padcontent").html("");
- for(var i=0; i<padContents.currentLines.length; i++) {
- var div = padContents.lineToElement(padContents.currentLines[i],
- padContents.alines[i]);
- padContents.currentDivs.push(div);
- $("#padcontent").append(div);
- }
- debugLog(padContents.currentDivs);
-});
-
-// this is necessary to keep infinite loops of events firing,
-// since goToRevision changes the slider position
-var goToRevisionIfEnabledCount = 0;
-var goToRevisionIfEnabled = function() {
- if(goToRevisionIfEnabledCount > 0) {
- goToRevisionIfEnabledCount --;
- } else {
- goToRevision.apply(goToRevision, arguments);
- }
-}
-
-BroadcastSlider.onSlider(goToRevisionIfEnabled);
-
-(function() {
- for(var i=0; i<clientVars.initialChangesets.length; i++) {
- var csgroup = clientVars.initialChangesets[i];
- var start = clientVars.initialChangesets[i].start;
- var granularity = clientVars.initialChangesets[i].granularity;
- debugLog("loading changest on startup: ", start, granularity, csgroup);
- changesetLoader.handleResponse(csgroup, start, granularity, null);
- }
-})();
-
-var dynamicCSS = makeCSSManager('dynamicsyntax');
-var authorData = {};
-
-function receiveAuthorData(newAuthorData) {
- for(var author in newAuthorData) {
- var data = newAuthorData[author];
- if ((typeof data.colorId) == 'number') {
- var bgcolor = clientVars.colorPalette[data.colorId];
- if (bgcolor && dynamicCSS) {
- dynamicCSS.selectorStyle(
- '.'+linestylefilter.getAuthorClassName(author)).backgroundColor =
- bgcolor;
- }
- }
- authorData[author] = data;
- }
-}
-
-receiveAuthorData(clientVars.historicalAuthorData);
diff --git a/trunk/etherpad/src/static/js/colorutils.js b/trunk/etherpad/src/static/js/colorutils.js
deleted file mode 100644
index e745f8e..0000000
--- a/trunk/etherpad/src/static/js/colorutils.js
+++ /dev/null
@@ -1,91 +0,0 @@
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/colorutils.js
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-var colorutils = {};
-
-// "#ffffff" or "#fff" or "ffffff" or "fff" to [1.0, 1.0, 1.0]
-colorutils.css2triple = function(cssColor) {
- var sixHex = colorutils.css2sixhex(cssColor);
- function hexToFloat(hh) {
- return Number("0x"+hh)/255;
- }
- return [hexToFloat(sixHex.substr(0,2)),
- hexToFloat(sixHex.substr(2,2)),
- hexToFloat(sixHex.substr(4,2))];
-}
-
-// "#ffffff" or "#fff" or "ffffff" or "fff" to "ffffff"
-colorutils.css2sixhex = function(cssColor) {
- var h = /[0-9a-fA-F]+/.exec(cssColor)[0];
- if (h.length != 6) {
- var a = h.charAt(0);
- var b = h.charAt(1);
- var c = h.charAt(2);
- h = a+a+b+b+c+c;
- }
- return h;
-}
-
-// [1.0, 1.0, 1.0] -> "#ffffff"
-colorutils.triple2css = function(triple) {
- function floatToHex(n) {
- var n2 = colorutils.clamp(Math.round(n*255), 0, 255);
- return ("0"+n2.toString(16)).slice(-2);
- }
- return "#" + floatToHex(triple[0]) +
- floatToHex(triple[1]) + floatToHex(triple[2]);
-}
-
-
-colorutils.clamp = function(v,bot,top) { return v < bot ? bot : (v > top ? top : v); };
-colorutils.min3 = function(a,b,c) { return (a < b) ? (a < c ? a : c) : (b < c ? b : c); };
-colorutils.max3 = function(a,b,c) { return (a > b) ? (a > c ? a : c) : (b > c ? b : c); };
-colorutils.colorMin = function(c) { return colorutils.min3(c[0], c[1], c[2]); };
-colorutils.colorMax = function(c) { return colorutils.max3(c[0], c[1], c[2]); };
-colorutils.scale = function(v, bot, top) { return colorutils.clamp(bot + v*(top-bot), 0, 1); };
-colorutils.unscale = function(v, bot, top) { return colorutils.clamp((v-bot)/(top-bot), 0, 1); };
-
-colorutils.scaleColor = function(c, bot, top) {
- return [colorutils.scale(c[0], bot, top),
- colorutils.scale(c[1], bot, top),
- colorutils.scale(c[2], bot, top)];
-}
-
-colorutils.unscaleColor = function(c, bot, top) {
- return [colorutils.unscale(c[0], bot, top),
- colorutils.unscale(c[1], bot, top),
- colorutils.unscale(c[2], bot, top)];
-}
-
-colorutils.luminosity = function(c) {
- // rule of thumb for RGB brightness; 1.0 is white
- return c[0]*0.30 + c[1]*0.59 + c[2]*0.11;
-}
-
-colorutils.saturate = function(c) {
- var min = colorutils.colorMin(c);
- var max = colorutils.colorMax(c);
- if (max - min <= 0) return [1.0, 1.0, 1.0];
- return colorutils.unscaleColor(c, min, max);
-}
-
-colorutils.blend = function(c1, c2, t) {
- return [colorutils.scale(t, c1[0], c2[0]),
- colorutils.scale(t, c1[1], c2[1]),
- colorutils.scale(t, c1[2], c2[2])];
-}
diff --git a/trunk/etherpad/src/static/js/cssmanager_client.js b/trunk/etherpad/src/static/js/cssmanager_client.js
deleted file mode 100644
index 04ed641..0000000
--- a/trunk/etherpad/src/static/js/cssmanager_client.js
+++ /dev/null
@@ -1,88 +0,0 @@
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/cssmanager.js
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-function makeCSSManager(emptyStylesheetTitle) {
-
- function getSheetByTitle(title) {
- var allSheets = document.styleSheets;
- for(var i=0;i<allSheets.length;i++) {
- var s = allSheets[i];
- if (s.title == title) {
- return s;
- }
- }
- return null;
- }
-
- /*function getSheetTagByTitle(title) {
- var allStyleTags = document.getElementsByTagName("style");
- for(var i=0;i<allStyleTags.length;i++) {
- var t = allStyleTags[i];
- if (t.title == title) {
- return t;
- }
- }
- return null;
- }*/
-
- var browserSheet = getSheetByTitle(emptyStylesheetTitle);
- //var browserTag = getSheetTagByTitle(emptyStylesheetTitle);
- function browserRules() { return (browserSheet.cssRules || browserSheet.rules); }
- function browserDeleteRule(i) {
- if (browserSheet.deleteRule) browserSheet.deleteRule(i);
- else browserSheet.removeRule(i);
- }
- function browserInsertRule(i, selector) {
- if (browserSheet.insertRule) browserSheet.insertRule(selector+' {}', i);
- else browserSheet.addRule(selector, null, i);
- }
- var selectorList = [];
-
- function indexOfSelector(selector) {
- for(var i=0;i<selectorList.length;i++) {
- if (selectorList[i] == selector) {
- return i;
- }
- }
- return -1;
- }
-
- function selectorStyle(selector) {
- var i = indexOfSelector(selector);
- if (i < 0) {
- // add selector
- browserInsertRule(0, selector);
- selectorList.splice(0, 0, selector);
- i = 0;
- }
- return browserRules().item(i).style;
- }
-
- function removeSelectorStyle(selector) {
- var i = indexOfSelector(selector);
- if (i >= 0) {
- browserDeleteRule(i);
- selectorList.splice(i, 1);
- }
- }
-
- return {selectorStyle:selectorStyle, removeSelectorStyle:removeSelectorStyle,
- info: function() {
- return selectorList.length+":"+browserRules().length;
- }};
-}
diff --git a/trunk/etherpad/src/static/js/domline_client.js b/trunk/etherpad/src/static/js/domline_client.js
deleted file mode 100644
index de2e7d3..0000000
--- a/trunk/etherpad/src/static/js/domline_client.js
+++ /dev/null
@@ -1,210 +0,0 @@
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/domline.js
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-var domline = {};
-domline.noop = function() {};
-domline.identity = function(x) { return x; };
-
-domline.addToLineClass = function(lineClass, cls) {
- // an "empty span" at any point can be used to add classes to
- // the line, using line:className. otherwise, we ignore
- // the span.
- cls.replace(/\S+/g, function (c) {
- if (c.indexOf("line:") == 0) {
- // add class to line
- lineClass = (lineClass ? lineClass+' ' : '')+c.substring(5);
- }
- });
- return lineClass;
-}
-
-// if "document" is falsy we don't create a DOM node, just
-// an object with innerHTML and className
-domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument) {
- var result = { node: null,
- appendSpan: domline.noop,
- prepareForAdd: domline.noop,
- notifyAdded: domline.noop,
- clearSpans: domline.noop,
- finishUpdate: domline.noop,
- lineMarker: 0 };
-
- var browser = (optBrowser || {});
- var document = optDocument;
-
- if (document) {
- result.node = document.createElement("div");
- }
- else {
- result.node = {innerHTML: '', className: ''};
- }
-
- var html = [];
- var preHtml, postHtml;
- var curHTML = null;
- function processSpaces(s) {
- return domline.processSpaces(s, doesWrap);
- }
- var identity = domline.identity;
- var perTextNodeProcess = (doesWrap ? identity : processSpaces);
- var perHtmlLineProcess = (doesWrap ? processSpaces : identity);
- var lineClass = 'ace-line';
- result.appendSpan = function(txt, cls) {
- if (cls.indexOf('list') >= 0) {
- var listType = /(?:^| )list:(\S+)/.exec(cls);
- if (listType) {
- listType = listType[1];
- if (listType) {
- preHtml = '<ul class="list-'+listType+'"><li>';
- postHtml = '</li></ul>';
- }
- result.lineMarker += txt.length;
- return; // don't append any text
- }
- }
- var href = null;
- var simpleTags = null;
- if (cls.indexOf('url') >= 0) {
- cls = cls.replace(/(^| )url:(\S+)/g, function(x0, space, url) {
- href = url;
- return space+"url";
- });
- }
- if (cls.indexOf('tag') >= 0) {
- cls = cls.replace(/(^| )tag:(\S+)/g, function(x0, space, tag) {
- if (! simpleTags) simpleTags = [];
- simpleTags.push(tag.toLowerCase());
- return space+tag;
- });
- }
- if ((! txt) && cls) {
- lineClass = domline.addToLineClass(lineClass, cls);
- }
- else if (txt) {
- var extraOpenTags = "";
- var extraCloseTags = "";
- if (href) {
- extraOpenTags = extraOpenTags+'<a href="'+
- href.replace(/\"/g, '&quot;')+'">';
- extraCloseTags = '</a>'+extraCloseTags;
- }
- if (simpleTags) {
- simpleTags.sort();
- extraOpenTags = extraOpenTags+'<'+simpleTags.join('><')+'>';
- simpleTags.reverse();
- extraCloseTags = '</'+simpleTags.join('></')+'>'+extraCloseTags;
- }
- html.push('<span class="',cls||'','">',extraOpenTags,
- perTextNodeProcess(domline.escapeHTML(txt)),
- extraCloseTags,'</span>');
- }
- };
- result.clearSpans = function() {
- html = [];
- lineClass = ''; // non-null to cause update
- result.lineMarker = 0;
- };
- function writeHTML() {
- var newHTML = perHtmlLineProcess(html.join(''));
- if (! newHTML) {
- if ((! document) || (! optBrowser)) {
- newHTML += '&nbsp;';
- }
- else if (! browser.msie) {
- newHTML += '<br/>';
- }
- }
- if (nonEmpty) {
- newHTML = (preHtml||'')+newHTML+(postHtml||'');
- }
- html = preHtml = postHtml = null; // free memory
- if (newHTML !== curHTML) {
- curHTML = newHTML;
- result.node.innerHTML = curHTML;
- }
- if (lineClass !== null) result.node.className = lineClass;
- }
- result.prepareForAdd = writeHTML;
- result.finishUpdate = writeHTML;
- result.getInnerHTML = function() { return curHTML || ''; };
-
- return result;
-};
-
-domline.escapeHTML = function(s) {
- var re = /[&<>'"]/g; /']/; // stupid indentation thing
- if (! re.MAP) {
- // persisted across function calls!
- re.MAP = {
- '&': '&amp;',
- '<': '&lt;',
- '>': '&gt;',
- '"': '&#34;',
- "'": '&#39;'
- };
- }
- return s.replace(re, function(c) { return re.MAP[c]; });
-};
-
-domline.processSpaces = function(s, doesWrap) {
- if (s.indexOf("<") < 0 && ! doesWrap) {
- // short-cut
- return s.replace(/ /g, '&nbsp;');
- }
- var parts = [];
- s.replace(/<[^>]*>?| |[^ <]+/g, function(m) { parts.push(m); });
- if (doesWrap) {
- var endOfLine = true;
- var beforeSpace = false;
- // last space in a run is normal, others are nbsp,
- // end of line is nbsp
- for(var i=parts.length-1;i>=0;i--) {
- var p = parts[i];
- if (p == " ") {
- if (endOfLine || beforeSpace)
- parts[i] = '&nbsp;';
- endOfLine = false;
- beforeSpace = true;
- }
- else if (p.charAt(0) != "<") {
- endOfLine = false;
- beforeSpace = false;
- }
- }
- // beginning of line is nbsp
- for(var i=0;i<parts.length;i++) {
- var p = parts[i];
- if (p == " ") {
- parts[i] = '&nbsp;';
- break;
- }
- else if (p.charAt(0) != "<") {
- break;
- }
- }
- }
- else {
- for(var i=0;i<parts.length;i++) {
- var p = parts[i];
- if (p == " ") {
- parts[i] = '&nbsp;';
- }
- }
- }
- return parts.join('');
-};
diff --git a/trunk/etherpad/src/static/js/easysync2_client.js b/trunk/etherpad/src/static/js/easysync2_client.js
deleted file mode 100644
index 043099c..0000000
--- a/trunk/etherpad/src/static/js/easysync2_client.js
+++ /dev/null
@@ -1,1777 +0,0 @@
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/easysync2.js
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-//var _opt = (this.Easysync2Support || null);
-var _opt = null; // disable optimization for now
-
-function AttribPool() {
- var p = {};
- p.numToAttrib = {}; // e.g. {0: ['foo','bar']}
- p.attribToNum = {}; // e.g. {'foo,bar': 0}
- p.nextNum = 0;
-
- p.putAttrib = function(attrib, dontAddIfAbsent) {
- var str = String(attrib);
- if (str in p.attribToNum) {
- return p.attribToNum[str];
- }
- if (dontAddIfAbsent) {
- return -1;
- }
- var num = p.nextNum++;
- p.attribToNum[str] = num;
- p.numToAttrib[num] = [String(attrib[0]||''),
- String(attrib[1]||'')];
- return num;
- };
-
- p.getAttrib = function(num) {
- var pair = p.numToAttrib[num];
- if (! pair) return pair;
- return [pair[0], pair[1]]; // return a mutable copy
- };
-
- p.getAttribKey = function(num) {
- var pair = p.numToAttrib[num];
- if (! pair) return '';
- return pair[0];
- };
-
- p.getAttribValue = function(num) {
- var pair = p.numToAttrib[num];
- if (! pair) return '';
- return pair[1];
- };
-
- p.eachAttrib = function(func) {
- for(var n in p.numToAttrib) {
- var pair = p.numToAttrib[n];
- func(pair[0], pair[1]);
- }
- };
-
- p.toJsonable = function() {
- return {numToAttrib: p.numToAttrib, nextNum: p.nextNum};
- };
-
- p.fromJsonable = function(obj) {
- p.numToAttrib = obj.numToAttrib;
- p.nextNum = obj.nextNum;
- p.attribToNum = {};
- for(var n in p.numToAttrib) {
- p.attribToNum[String(p.numToAttrib[n])] = Number(n);
- }
- return p;
- };
-
- return p;
-}
-
-var Changeset = {};
-
-Changeset.error = function error(msg) { var e = new Error(msg); e.easysync = true; throw e; };
-Changeset.assert = function assert(b, msgParts) {
- if (! b) {
- var msg = Array.prototype.slice.call(arguments, 1).join('');
- Changeset.error("Changeset: "+msg);
- }
-};
-
-Changeset.parseNum = function(str) { return parseInt(str, 36); };
-Changeset.numToString = function(num) { return num.toString(36).toLowerCase(); };
-Changeset.toBaseTen = function(cs) {
- var dollarIndex = cs.indexOf('$');
- var beforeDollar = cs.substring(0, dollarIndex);
- var fromDollar = cs.substring(dollarIndex);
- return beforeDollar.replace(/[0-9a-z]+/g, function(s) {
- return String(Changeset.parseNum(s)); }) + fromDollar;
-};
-
-Changeset.oldLen = function(cs) {
- return Changeset.unpack(cs).oldLen;
-};
-Changeset.newLen = function(cs) {
- return Changeset.unpack(cs).newLen;
-};
-
-Changeset.opIterator = function(opsStr, optStartIndex) {
- //print(opsStr);
- var regex = /((?:\*[0-9a-z]+)*)(?:\|([0-9a-z]+))?([-+=])([0-9a-z]+)|\?|/g;
- var startIndex = (optStartIndex || 0);
- var curIndex = startIndex;
- var prevIndex = curIndex;
- function nextRegexMatch() {
- prevIndex = curIndex;
- var result;
- if (_opt) {
- result = _opt.nextOpInString(opsStr, curIndex);
- if (result) {
- if (result.opcode() == '?') {
- Changeset.error("Hit error opcode in op stream");
- }
- curIndex = result.lastIndex();
- }
- }
- else {
- regex.lastIndex = curIndex;
- result = regex.exec(opsStr);
- curIndex = regex.lastIndex;
- if (result[0] == '?') {
- Changeset.error("Hit error opcode in op stream");
- }
- }
- return result;
- }
- var regexResult = nextRegexMatch();
- var obj = Changeset.newOp();
- function next(optObj) {
- var op = (optObj || obj);
- if (_opt && regexResult) {
- op.attribs = regexResult.attribs();
- op.lines = regexResult.lines();
- op.chars = regexResult.chars();
- op.opcode = regexResult.opcode();
- regexResult = nextRegexMatch();
- }
- else if ((! _opt) && regexResult[0]) {
- op.attribs = regexResult[1];
- op.lines = Changeset.parseNum(regexResult[2] || 0);
- op.opcode = regexResult[3];
- op.chars = Changeset.parseNum(regexResult[4]);
- regexResult = nextRegexMatch();
- }
- else {
- Changeset.clearOp(op);
- }
- return op;
- }
- function hasNext() { return !! (_opt ? regexResult : regexResult[0]); }
- function lastIndex() { return prevIndex; }
- return {next: next, hasNext: hasNext, lastIndex: lastIndex};
-};
-
-Changeset.clearOp = function(op) {
- op.opcode = '';
- op.chars = 0;
- op.lines = 0;
- op.attribs = '';
-};
-Changeset.newOp = function(optOpcode) {
- return {opcode:(optOpcode || ''), chars:0, lines:0, attribs:''};
-};
-Changeset.cloneOp = function(op) {
- return {opcode: op.opcode, chars: op.chars, lines: op.lines, attribs: op.attribs};
-};
-Changeset.copyOp = function(op1, op2) {
- op2.opcode = op1.opcode;
- op2.chars = op1.chars;
- op2.lines = op1.lines;
- op2.attribs = op1.attribs;
-};
-Changeset.opString = function(op) {
- // just for debugging
- if (! op.opcode) return 'null';
- var assem = Changeset.opAssembler();
- assem.append(op);
- return assem.toString();
-};
-Changeset.stringOp = function(str) {
- // just for debugging
- return Changeset.opIterator(str).next();
-};
-
-Changeset.checkRep = function(cs) {
- // doesn't check things that require access to attrib pool (e.g. attribute order)
- // or original string (e.g. newline positions)
- var unpacked = Changeset.unpack(cs);
- var oldLen = unpacked.oldLen;
- var newLen = unpacked.newLen;
- var ops = unpacked.ops;
- var charBank = unpacked.charBank;
-
- var assem = Changeset.smartOpAssembler();
- var oldPos = 0;
- var calcNewLen = 0;
- var numInserted = 0;
- var iter = Changeset.opIterator(ops);
- while (iter.hasNext()) {
- var o = iter.next();
- switch (o.opcode) {
- case '=': oldPos += o.chars; calcNewLen += o.chars; break;
- case '-': oldPos += o.chars; Changeset.assert(oldPos < oldLen, oldPos," >= ",oldLen," in ",cs); break;
- case '+': {
- calcNewLen += o.chars; numInserted += o.chars;
- Changeset.assert(calcNewLen < newLen, calcNewLen," >= ",newLen," in ",cs);
- break;
- }
- }
- assem.append(o);
- }
-
- calcNewLen += oldLen - oldPos;
- charBank = charBank.substring(0, numInserted);
- while (charBank.length < numInserted) {
- charBank += "?";
- }
-
- assem.endDocument();
- var normalized = Changeset.pack(oldLen, calcNewLen, assem.toString(), charBank);
- Changeset.assert(normalized == cs, normalized,' != ',cs);
-
- return cs;
-}
-
-Changeset.smartOpAssembler = function() {
- // Like opAssembler but able to produce conforming changesets
- // from slightly looser input, at the cost of speed.
- // Specifically:
- // - merges consecutive operations that can be merged
- // - strips final "="
- // - ignores 0-length changes
- // - reorders consecutive + and - (which margingOpAssembler doesn't do)
-
- var minusAssem = Changeset.mergingOpAssembler();
- var plusAssem = Changeset.mergingOpAssembler();
- var keepAssem = Changeset.mergingOpAssembler();
- var assem = Changeset.stringAssembler();
- var lastOpcode = '';
- var lengthChange = 0;
-
- function flushKeeps() {
- assem.append(keepAssem.toString());
- keepAssem.clear();
- }
-
- function flushPlusMinus() {
- assem.append(minusAssem.toString());
- minusAssem.clear();
- assem.append(plusAssem.toString());
- plusAssem.clear();
- }
-
- function append(op) {
- if (! op.opcode) return;
- if (! op.chars) return;
-
- if (op.opcode == '-') {
- if (lastOpcode == '=') {
- flushKeeps();
- }
- minusAssem.append(op);
- lengthChange -= op.chars;
- }
- else if (op.opcode == '+') {
- if (lastOpcode == '=') {
- flushKeeps();
- }
- plusAssem.append(op);
- lengthChange += op.chars;
- }
- else if (op.opcode == '=') {
- if (lastOpcode != '=') {
- flushPlusMinus();
- }
- keepAssem.append(op);
- }
- lastOpcode = op.opcode;
- }
-
- function appendOpWithText(opcode, text, attribs, pool) {
- var op = Changeset.newOp(opcode);
- op.attribs = Changeset.makeAttribsString(opcode, attribs, pool);
- var lastNewlinePos = text.lastIndexOf('\n');
- if (lastNewlinePos < 0) {
- op.chars = text.length;
- op.lines = 0;
- append(op);
- }
- else {
- op.chars = lastNewlinePos+1;
- op.lines = text.match(/\n/g).length;
- append(op);
- op.chars = text.length - (lastNewlinePos+1);
- op.lines = 0;
- append(op);
- }
- }
-
- function toString() {
- flushPlusMinus();
- flushKeeps();
- return assem.toString();
- }
-
- function clear() {
- minusAssem.clear();
- plusAssem.clear();
- keepAssem.clear();
- assem.clear();
- lengthChange = 0;
- }
-
- function endDocument() {
- keepAssem.endDocument();
- }
-
- function getLengthChange() {
- return lengthChange;
- }
-
- return {append: append, toString: toString, clear: clear, endDocument: endDocument,
- appendOpWithText: appendOpWithText, getLengthChange: getLengthChange };
-};
-
-if (_opt) {
- Changeset.mergingOpAssembler = function() {
- var assem = _opt.mergingOpAssembler();
-
- function append(op) {
- assem.append(op.opcode, op.chars, op.lines, op.attribs);
- }
- function toString() {
- return assem.toString();
- }
- function clear() {
- assem.clear();
- }
- function endDocument() {
- assem.endDocument();
- }
-
- return {append: append, toString: toString, clear: clear, endDocument: endDocument};
- };
-}
-else {
- Changeset.mergingOpAssembler = function() {
- // This assembler can be used in production; it efficiently
- // merges consecutive operations that are mergeable, ignores
- // no-ops, and drops final pure "keeps". It does not re-order
- // operations.
- var assem = Changeset.opAssembler();
- var bufOp = Changeset.newOp();
-
- // If we get, for example, insertions [xxx\n,yyy], those don't merge,
- // but if we get [xxx\n,yyy,zzz\n], that merges to [xxx\nyyyzzz\n].
- // This variable stores the length of yyy and any other newline-less
- // ops immediately after it.
- var bufOpAdditionalCharsAfterNewline = 0;
-
- function flush(isEndDocument) {
- if (bufOp.opcode) {
- if (isEndDocument && bufOp.opcode == '=' && ! bufOp.attribs) {
- // final merged keep, leave it implicit
- }
- else {
- assem.append(bufOp);
- if (bufOpAdditionalCharsAfterNewline) {
- bufOp.chars = bufOpAdditionalCharsAfterNewline;
- bufOp.lines = 0;
- assem.append(bufOp);
- bufOpAdditionalCharsAfterNewline = 0;
- }
- }
- bufOp.opcode = '';
- }
- }
- function append(op) {
- if (op.chars > 0) {
- if (bufOp.opcode == op.opcode && bufOp.attribs == op.attribs) {
- if (op.lines > 0) {
- // bufOp and additional chars are all mergeable into a multi-line op
- bufOp.chars += bufOpAdditionalCharsAfterNewline + op.chars;
- bufOp.lines += op.lines;
- bufOpAdditionalCharsAfterNewline = 0;
- }
- else if (bufOp.lines == 0) {
- // both bufOp and op are in-line
- bufOp.chars += op.chars;
- }
- else {
- // append in-line text to multi-line bufOp
- bufOpAdditionalCharsAfterNewline += op.chars;
- }
- }
- else {
- flush();
- Changeset.copyOp(op, bufOp);
- }
- }
- }
- function endDocument() {
- flush(true);
- }
- function toString() {
- flush();
- return assem.toString();
- }
- function clear() {
- assem.clear();
- Changeset.clearOp(bufOp);
- }
- return {append: append, toString: toString, clear: clear, endDocument: endDocument};
- };
-}
-
-if (_opt) {
- Changeset.opAssembler = function() {
- var assem = _opt.opAssembler();
- // this function allows op to be mutated later (doesn't keep a ref)
- function append(op) {
- assem.append(op.opcode, op.chars, op.lines, op.attribs);
- }
- function toString() {
- return assem.toString();
- }
- function clear() {
- assem.clear();
- }
- return {append: append, toString: toString, clear: clear};
- };
-}
-else {
- Changeset.opAssembler = function() {
- var pieces = [];
- // this function allows op to be mutated later (doesn't keep a ref)
- function append(op) {
- pieces.push(op.attribs);
- if (op.lines) {
- pieces.push('|', Changeset.numToString(op.lines));
- }
- pieces.push(op.opcode);
- pieces.push(Changeset.numToString(op.chars));
- }
- function toString() {
- return pieces.join('');
- }
- function clear() {
- pieces.length = 0;
- }
- return {append: append, toString: toString, clear: clear};
- };
-}
-
-Changeset.stringIterator = function(str) {
- var curIndex = 0;
- function assertRemaining(n) {
- Changeset.assert(n <= remaining(), "!(",n," <= ",remaining(),")");
- }
- function take(n) {
- assertRemaining(n);
- var s = str.substr(curIndex, n);
- curIndex += n;
- return s;
- }
- function peek(n) {
- assertRemaining(n);
- var s = str.substr(curIndex, n);
- return s;
- }
- function skip(n) {
- assertRemaining(n);
- curIndex += n;
- }
- function remaining() {
- return str.length - curIndex;
- }
- return {take:take, skip:skip, remaining:remaining, peek:peek};
-};
-
-Changeset.stringAssembler = function() {
- var pieces = [];
- function append(x) {
- pieces.push(String(x));
- }
- function toString() {
- return pieces.join('');
- }
- return {append: append, toString: toString};
-};
-
-// "lines" need not be an array as long as it supports certain calls (lines_foo inside).
-Changeset.textLinesMutator = function(lines) {
- // Mutates lines, an array of strings, in place.
- // Mutation operations have the same constraints as changeset operations
- // with respect to newlines, but not the other additional constraints
- // (i.e. ins/del ordering, forbidden no-ops, non-mergeability, final newline).
- // Can be used to mutate lists of strings where the last char of each string
- // is not actually a newline, but for the purposes of N and L values,
- // the caller should pretend it is, and for things to work right in that case, the input
- // to insert() should be a single line with no newlines.
-
- var curSplice = [0,0];
- var inSplice = false;
- // position in document after curSplice is applied:
- var curLine = 0, curCol = 0;
- // invariant: if (inSplice) then (curLine is in curSplice[0] + curSplice.length - {2,3}) &&
- // curLine >= curSplice[0]
- // invariant: if (inSplice && (curLine >= curSplice[0] + curSplice.length - 2)) then
- // curCol == 0
-
- function lines_applySplice(s) {
- lines.splice.apply(lines, s);
- }
- function lines_toSource() {
- return lines.toSource();
- }
- function lines_get(idx) {
- if (lines.get) {
- return lines.get(idx);
- }
- else {
- return lines[idx];
- }
- }
- // can be unimplemented if removeLines's return value not needed
- function lines_slice(start, end) {
- if (lines.slice) {
- return lines.slice(start, end);
- }
- else {
- return [];
- }
- }
- function lines_length() {
- if ((typeof lines.length) == "number") {
- return lines.length;
- }
- else {
- return lines.length();
- }
- }
-
- function enterSplice() {
- curSplice[0] = curLine;
- curSplice[1] = 0;
- if (curCol > 0) {
- putCurLineInSplice();
- }
- inSplice = true;
- }
- function leaveSplice() {
- lines_applySplice(curSplice);
- curSplice.length = 2;
- curSplice[0] = curSplice[1] = 0;
- inSplice = false;
- }
- function isCurLineInSplice() {
- return (curLine - curSplice[0] < (curSplice.length - 2));
- }
- function debugPrint(typ) {
- print(typ+": "+curSplice.toSource()+" / "+curLine+","+curCol+" / "+lines_toSource());
- }
- function putCurLineInSplice() {
- if (! isCurLineInSplice()) {
- curSplice.push(lines_get(curSplice[0] + curSplice[1]));
- curSplice[1]++;
- }
- return 2 + curLine - curSplice[0];
- }
-
- function skipLines(L, includeInSplice) {
- if (L) {
- if (includeInSplice) {
- if (! inSplice) {
- enterSplice();
- }
- for(var i=0;i<L;i++) {
- curCol = 0;
- putCurLineInSplice();
- curLine++;
- }
- }
- else {
- if (inSplice) {
- if (L > 1) {
- leaveSplice();
- }
- else {
- putCurLineInSplice();
- }
- }
- curLine += L;
- curCol = 0;
- }
- //print(inSplice+" / "+isCurLineInSplice()+" / "+curSplice[0]+" / "+curSplice[1]+" / "+lines.length);
- /*if (inSplice && (! isCurLineInSplice()) && (curSplice[0] + curSplice[1] < lines.length)) {
- print("BLAH");
- putCurLineInSplice();
- }*/ // tests case foo in remove(), which isn't otherwise covered in current impl
- }
- //debugPrint("skip");
- }
-
- function skip(N, L, includeInSplice) {
- if (N) {
- if (L) {
- skipLines(L, includeInSplice);
- }
- else {
- if (includeInSplice && ! inSplice) {
- enterSplice();
- }
- if (inSplice) {
- putCurLineInSplice();
- }
- curCol += N;
- //debugPrint("skip");
- }
- }
- }
-
- function removeLines(L) {
- var removed = '';
- if (L) {
- if (! inSplice) {
- enterSplice();
- }
- function nextKLinesText(k) {
- var m = curSplice[0] + curSplice[1];
- return lines_slice(m, m+k).join('');
- }
- if (isCurLineInSplice()) {
- //print(curCol);
- if (curCol == 0) {
- removed = curSplice[curSplice.length-1];
- // print("FOO"); // case foo
- curSplice.length--;
- removed += nextKLinesText(L-1);
- curSplice[1] += L-1;
- }
- else {
- removed = nextKLinesText(L-1);
- curSplice[1] += L-1;
- var sline = curSplice.length - 1;
- removed = curSplice[sline].substring(curCol) + removed;
- curSplice[sline] = curSplice[sline].substring(0, curCol) +
- lines_get(curSplice[0] + curSplice[1]);
- curSplice[1] += 1;
- }
- }
- else {
- removed = nextKLinesText(L);
- curSplice[1] += L;
- }
- //debugPrint("remove");
- }
- return removed;
- }
-
- function remove(N, L) {
- var removed = '';
- if (N) {
- if (L) {
- return removeLines(L);
- }
- else {
- if (! inSplice) {
- enterSplice();
- }
- var sline = putCurLineInSplice();
- removed = curSplice[sline].substring(curCol, curCol+N);
- curSplice[sline] = curSplice[sline].substring(0, curCol) +
- curSplice[sline].substring(curCol+N);
- //debugPrint("remove");
- }
- }
- return removed;
- }
-
- function insert(text, L) {
- if (text) {
- if (! inSplice) {
- enterSplice();
- }
- if (L) {
- var newLines = Changeset.splitTextLines(text);
- if (isCurLineInSplice()) {
- //if (curCol == 0) {
- //curSplice.length--;
- //curSplice[1]--;
- //Array.prototype.push.apply(curSplice, newLines);
- //curLine += newLines.length;
- //}
- //else {
- var sline = curSplice.length - 1;
- var theLine = curSplice[sline];
- var lineCol = curCol;
- curSplice[sline] = theLine.substring(0, lineCol) + newLines[0];
- curLine++;
- newLines.splice(0, 1);
- Array.prototype.push.apply(curSplice, newLines);
- curLine += newLines.length;
- curSplice.push(theLine.substring(lineCol));
- curCol = 0;
- //}
- }
- else {
- Array.prototype.push.apply(curSplice, newLines);
- curLine += newLines.length;
- }
- }
- else {
- var sline = putCurLineInSplice();
- curSplice[sline] = curSplice[sline].substring(0, curCol) +
- text + curSplice[sline].substring(curCol);
- curCol += text.length;
- }
- //debugPrint("insert");
- }
- }
-
- function hasMore() {
- //print(lines.length+" / "+inSplice+" / "+(curSplice.length - 2)+" / "+curSplice[1]);
- var docLines = lines_length();
- if (inSplice) {
- docLines += curSplice.length - 2 - curSplice[1];
- }
- return curLine < docLines;
- }
-
- function close() {
- if (inSplice) {
- leaveSplice();
- }
- //debugPrint("close");
- }
-
- var self = {skip:skip, remove:remove, insert:insert, close:close, hasMore:hasMore,
- removeLines:removeLines, skipLines: skipLines};
- return self;
-};
-
-Changeset.applyZip = function(in1, idx1, in2, idx2, func) {
- var iter1 = Changeset.opIterator(in1, idx1);
- var iter2 = Changeset.opIterator(in2, idx2);
- var assem = Changeset.smartOpAssembler();
- var op1 = Changeset.newOp();
- var op2 = Changeset.newOp();
- var opOut = Changeset.newOp();
- while (op1.opcode || iter1.hasNext() || op2.opcode || iter2.hasNext()) {
- if ((! op1.opcode) && iter1.hasNext()) iter1.next(op1);
- if ((! op2.opcode) && iter2.hasNext()) iter2.next(op2);
- func(op1, op2, opOut);
- if (opOut.opcode) {
- //print(opOut.toSource());
- assem.append(opOut);
- opOut.opcode = '';
- }
- }
- assem.endDocument();
- return assem.toString();
-};
-
-Changeset.unpack = function(cs) {
- var headerRegex = /Z:([0-9a-z]+)([><])([0-9a-z]+)|/;
- var headerMatch = headerRegex.exec(cs);
- if ((! headerMatch) || (! headerMatch[0])) {
- Changeset.error("Not a changeset: "+cs);
- }
- var oldLen = Changeset.parseNum(headerMatch[1]);
- var changeSign = (headerMatch[2] == '>') ? 1 : -1;
- var changeMag = Changeset.parseNum(headerMatch[3]);
- var newLen = oldLen + changeSign*changeMag;
- var opsStart = headerMatch[0].length;
- var opsEnd = cs.indexOf("$");
- if (opsEnd < 0) opsEnd = cs.length;
- return {oldLen: oldLen, newLen: newLen, ops: cs.substring(opsStart, opsEnd),
- charBank: cs.substring(opsEnd+1)};
-};
-
-Changeset.pack = function(oldLen, newLen, opsStr, bank) {
- var lenDiff = newLen - oldLen;
- var lenDiffStr = (lenDiff >= 0 ?
- '>'+Changeset.numToString(lenDiff) :
- '<'+Changeset.numToString(-lenDiff));
- var a = [];
- a.push('Z:', Changeset.numToString(oldLen), lenDiffStr, opsStr, '$', bank);
- return a.join('');
-};
-
-Changeset.applyToText = function(cs, str) {
- var unpacked = Changeset.unpack(cs);
- Changeset.assert(str.length == unpacked.oldLen,
- "mismatched apply: ",str.length," / ",unpacked.oldLen);
- var csIter = Changeset.opIterator(unpacked.ops);
- var bankIter = Changeset.stringIterator(unpacked.charBank);
- var strIter = Changeset.stringIterator(str);
- var assem = Changeset.stringAssembler();
- while (csIter.hasNext()) {
- var op = csIter.next();
- switch(op.opcode) {
- case '+': assem.append(bankIter.take(op.chars)); break;
- case '-': strIter.skip(op.chars); break;
- case '=': assem.append(strIter.take(op.chars)); break;
- }
- }
- assem.append(strIter.take(strIter.remaining()));
- return assem.toString();
-};
-
-Changeset.mutateTextLines = function(cs, lines) {
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var bankIter = Changeset.stringIterator(unpacked.charBank);
- var mut = Changeset.textLinesMutator(lines);
- while (csIter.hasNext()) {
- var op = csIter.next();
- switch(op.opcode) {
- case '+': mut.insert(bankIter.take(op.chars), op.lines); break;
- case '-': mut.remove(op.chars, op.lines); break;
- case '=': mut.skip(op.chars, op.lines, (!! op.attribs)); break;
- }
- }
- mut.close();
-};
-
-Changeset.composeAttributes = function(att1, att2, resultIsMutation, pool) {
- // att1 and att2 are strings like "*3*f*1c", asMutation is a boolean.
-
- // Sometimes attribute (key,value) pairs are treated as attribute presence
- // information, while other times they are treated as operations that
- // mutate a set of attributes, and this affects whether an empty value
- // is a deletion or a change.
- // Examples, of the form (att1Items, att2Items, resultIsMutation) -> result
- // ([], [(bold, )], true) -> [(bold, )]
- // ([], [(bold, )], false) -> []
- // ([], [(bold, true)], true) -> [(bold, true)]
- // ([], [(bold, true)], false) -> [(bold, true)]
- // ([(bold, true)], [(bold, )], true) -> [(bold, )]
- // ([(bold, true)], [(bold, )], false) -> []
-
- // pool can be null if att2 has no attributes.
-
- if ((! att1) && resultIsMutation) {
- // In the case of a mutation (i.e. composing two changesets),
- // an att2 composed with an empy att1 is just att2. If att1
- // is part of an attribution string, then att2 may remove
- // attributes that are already gone, so don't do this optimization.
- return att2;
- }
- if (! att2) return att1;
- var atts = [];
- att1.replace(/\*([0-9a-z]+)/g, function(_, a) {
- atts.push(pool.getAttrib(Changeset.parseNum(a)));
- return '';
- });
- att2.replace(/\*([0-9a-z]+)/g, function(_, a) {
- var pair = pool.getAttrib(Changeset.parseNum(a));
- var found = false;
- for(var i=0;i<atts.length;i++) {
- var oldPair = atts[i];
- if (oldPair[0] == pair[0]) {
- if (pair[1] || resultIsMutation) {
- oldPair[1] = pair[1];
- }
- else {
- atts.splice(i, 1);
- }
- found = true;
- break;
- }
- }
- if ((! found) && (pair[1] || resultIsMutation)) {
- atts.push(pair);
- }
- return '';
- });
- atts.sort();
- var buf = Changeset.stringAssembler();
- for(var i=0;i<atts.length;i++) {
- buf.append('*');
- buf.append(Changeset.numToString(pool.putAttrib(atts[i])));
- }
- //print(att1+" / "+att2+" / "+buf.toString());
- return buf.toString();
-};
-
-Changeset._slicerZipperFunc = function(attOp, csOp, opOut, pool) {
- // attOp is the op from the sequence that is being operated on, either an
- // attribution string or the earlier of two changesets being composed.
- // pool can be null if definitely not needed.
-
- //print(csOp.toSource()+" "+attOp.toSource()+" "+opOut.toSource());
- if (attOp.opcode == '-') {
- Changeset.copyOp(attOp, opOut);
- attOp.opcode = '';
- }
- else if (! attOp.opcode) {
- Changeset.copyOp(csOp, opOut);
- csOp.opcode = '';
- }
- else {
- switch (csOp.opcode) {
- case '-': {
- if (csOp.chars <= attOp.chars) {
- // delete or delete part
- if (attOp.opcode == '=') {
- opOut.opcode = '-';
- opOut.chars = csOp.chars;
- opOut.lines = csOp.lines;
- opOut.attribs = '';
- }
- attOp.chars -= csOp.chars;
- attOp.lines -= csOp.lines;
- csOp.opcode = '';
- if (! attOp.chars) {
- attOp.opcode = '';
- }
- }
- else {
- // delete and keep going
- if (attOp.opcode == '=') {
- opOut.opcode = '-';
- opOut.chars = attOp.chars;
- opOut.lines = attOp.lines;
- opOut.attribs = '';
- }
- csOp.chars -= attOp.chars;
- csOp.lines -= attOp.lines;
- attOp.opcode = '';
- }
- break;
- }
- case '+': {
- // insert
- Changeset.copyOp(csOp, opOut);
- csOp.opcode = '';
- break;
- }
- case '=': {
- if (csOp.chars <= attOp.chars) {
- // keep or keep part
- opOut.opcode = attOp.opcode;
- opOut.chars = csOp.chars;
- opOut.lines = csOp.lines;
- opOut.attribs = Changeset.composeAttributes(attOp.attribs, csOp.attribs,
- attOp.opcode == '=', pool);
- csOp.opcode = '';
- attOp.chars -= csOp.chars;
- attOp.lines -= csOp.lines;
- if (! attOp.chars) {
- attOp.opcode = '';
- }
- }
- else {
- // keep and keep going
- opOut.opcode = attOp.opcode;
- opOut.chars = attOp.chars;
- opOut.lines = attOp.lines;
- opOut.attribs = Changeset.composeAttributes(attOp.attribs, csOp.attribs,
- attOp.opcode == '=', pool);
- attOp.opcode = '';
- csOp.chars -= attOp.chars;
- csOp.lines -= attOp.lines;
- }
- break;
- }
- case '': {
- Changeset.copyOp(attOp, opOut);
- attOp.opcode = '';
- break;
- }
- }
- }
-};
-
-Changeset.applyToAttribution = function(cs, astr, pool) {
- var unpacked = Changeset.unpack(cs);
-
- return Changeset.applyZip(astr, 0, unpacked.ops, 0, function(op1, op2, opOut) {
- return Changeset._slicerZipperFunc(op1, op2, opOut, pool);
- });
-};
-
-/*Changeset.oneInsertedLineAtATimeOpIterator = function(opsStr, optStartIndex, charBank) {
- var iter = Changeset.opIterator(opsStr, optStartIndex);
- var bankIndex = 0;
-
-};*/
-
-Changeset.mutateAttributionLines = function(cs, lines, pool) {
- //dmesg(cs);
- //dmesg(lines.toSource()+" ->");
-
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var csBank = unpacked.charBank;
- var csBankIndex = 0;
- // treat the attribution lines as text lines, mutating a line at a time
- var mut = Changeset.textLinesMutator(lines);
-
- var lineIter = null;
- function isNextMutOp() {
- return (lineIter && lineIter.hasNext()) || mut.hasMore();
- }
- function nextMutOp(destOp) {
- if ((!(lineIter && lineIter.hasNext())) && mut.hasMore()) {
- var line = mut.removeLines(1);
- lineIter = Changeset.opIterator(line);
- }
- if (lineIter && lineIter.hasNext()) {
- lineIter.next(destOp);
- }
- else {
- destOp.opcode = '';
- }
- }
- var lineAssem = null;
- function outputMutOp(op) {
- //print("outputMutOp: "+op.toSource());
- if (! lineAssem) {
- lineAssem = Changeset.mergingOpAssembler();
- }
- lineAssem.append(op);
- if (op.lines > 0) {
- Changeset.assert(op.lines == 1, "Can't have op.lines of ",op.lines," in attribution lines");
- // ship it to the mut
- mut.insert(lineAssem.toString(), 1);
- lineAssem = null;
- }
- }
-
- var csOp = Changeset.newOp();
- var attOp = Changeset.newOp();
- var opOut = Changeset.newOp();
- while (csOp.opcode || csIter.hasNext() || attOp.opcode || isNextMutOp()) {
- if ((! csOp.opcode) && csIter.hasNext()) {
- csIter.next(csOp);
- }
- //print(csOp.toSource()+" "+attOp.toSource()+" "+opOut.toSource());
- //print(csOp.opcode+"/"+csOp.lines+"/"+csOp.attribs+"/"+lineAssem+"/"+lineIter+"/"+(lineIter?lineIter.hasNext():null));
- //print("csOp: "+csOp.toSource());
- if ((! csOp.opcode) && (! attOp.opcode) &&
- (! lineAssem) && (! (lineIter && lineIter.hasNext()))) {
- break; // done
- }
- else if (csOp.opcode == '=' && csOp.lines > 0 && (! csOp.attribs) && (! attOp.opcode) &&
- (! lineAssem) && (! (lineIter && lineIter.hasNext()))) {
- // skip multiple lines; this is what makes small changes not order of the document size
- mut.skipLines(csOp.lines);
- //print("skipped: "+csOp.lines);
- csOp.opcode = '';
- }
- else if (csOp.opcode == '+') {
- if (csOp.lines > 1) {
- var firstLineLen = csBank.indexOf('\n', csBankIndex) + 1 - csBankIndex;
- Changeset.copyOp(csOp, opOut);
- csOp.chars -= firstLineLen;
- csOp.lines--;
- opOut.lines = 1;
- opOut.chars = firstLineLen;
- }
- else {
- Changeset.copyOp(csOp, opOut);
- csOp.opcode = '';
- }
- outputMutOp(opOut);
- csBankIndex += opOut.chars;
- opOut.opcode = '';
- }
- else {
- if ((! attOp.opcode) && isNextMutOp()) {
- nextMutOp(attOp);
- }
- //print("attOp: "+attOp.toSource());
- Changeset._slicerZipperFunc(attOp, csOp, opOut, pool);
- if (opOut.opcode) {
- outputMutOp(opOut);
- opOut.opcode = '';
- }
- }
- }
-
- Changeset.assert(! lineAssem, "line assembler not finished");
- mut.close();
-
- //dmesg("-> "+lines.toSource());
-};
-
-Changeset.joinAttributionLines = function(theAlines) {
- var assem = Changeset.mergingOpAssembler();
- for(var i=0;i<theAlines.length;i++) {
- var aline = theAlines[i];
- var iter = Changeset.opIterator(aline);
- while (iter.hasNext()) {
- assem.append(iter.next());
- }
- }
- return assem.toString();
-};
-
-Changeset.splitAttributionLines = function(attrOps, text) {
- var iter = Changeset.opIterator(attrOps);
- var assem = Changeset.mergingOpAssembler();
- var lines = [];
- var pos = 0;
-
- function appendOp(op) {
- assem.append(op);
- if (op.lines > 0) {
- lines.push(assem.toString());
- assem.clear();
- }
- pos += op.chars;
- }
-
- while (iter.hasNext()) {
- var op = iter.next();
- var numChars = op.chars;
- var numLines = op.lines;
- while (numLines > 1) {
- var newlineEnd = text.indexOf('\n', pos)+1;
- Changeset.assert(newlineEnd > 0, "newlineEnd <= 0 in splitAttributionLines");
- op.chars = newlineEnd - pos;
- op.lines = 1;
- appendOp(op);
- numChars -= op.chars;
- numLines -= op.lines;
- }
- if (numLines == 1) {
- op.chars = numChars;
- op.lines = 1;
- }
- appendOp(op);
- }
-
- return lines;
-};
-
-Changeset.splitTextLines = function(text) {
- return text.match(/[^\n]*(?:\n|[^\n]$)/g);
-};
-
-Changeset.compose = function(cs1, cs2, pool) {
- var unpacked1 = Changeset.unpack(cs1);
- var unpacked2 = Changeset.unpack(cs2);
- var len1 = unpacked1.oldLen;
- var len2 = unpacked1.newLen;
- Changeset.assert(len2 == unpacked2.oldLen, "mismatched composition");
- var len3 = unpacked2.newLen;
- var bankIter1 = Changeset.stringIterator(unpacked1.charBank);
- var bankIter2 = Changeset.stringIterator(unpacked2.charBank);
- var bankAssem = Changeset.stringAssembler();
-
- var newOps = Changeset.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function(op1, op2, opOut) {
- //var debugBuilder = Changeset.stringAssembler();
- //debugBuilder.append(Changeset.opString(op1));
- //debugBuilder.append(',');
- //debugBuilder.append(Changeset.opString(op2));
- //debugBuilder.append(' / ');
-
- var op1code = op1.opcode;
- var op2code = op2.opcode;
- if (op1code == '+' && op2code == '-') {
- bankIter1.skip(Math.min(op1.chars, op2.chars));
- }
- Changeset._slicerZipperFunc(op1, op2, opOut, pool);
- if (opOut.opcode == '+') {
- if (op2code == '+') {
- bankAssem.append(bankIter2.take(opOut.chars));
- }
- else {
- bankAssem.append(bankIter1.take(opOut.chars));
- }
- }
-
- //debugBuilder.append(Changeset.opString(op1));
- //debugBuilder.append(',');
- //debugBuilder.append(Changeset.opString(op2));
- //debugBuilder.append(' -> ');
- //debugBuilder.append(Changeset.opString(opOut));
- //print(debugBuilder.toString());
- });
-
- return Changeset.pack(len1, len3, newOps, bankAssem.toString());
-};
-
-Changeset.attributeTester = function(attribPair, pool) {
- // returns a function that tests if a string of attributes
- // (e.g. *3*4) contains a given attribute key,value that
- // is already present in the pool.
- if (! pool) {
- return never;
- }
- var attribNum = pool.putAttrib(attribPair, true);
- if (attribNum < 0) {
- return never;
- }
- else {
- var re = new RegExp('\\*'+Changeset.numToString(attribNum)+
- '(?!\\w)');
- return function(attribs) {
- return re.test(attribs);
- };
- }
- function never(attribs) { return false; }
-};
-
-Changeset.identity = function(N) {
- return Changeset.pack(N, N, "", "");
-};
-
-Changeset.makeSplice = function(oldFullText, spliceStart, numRemoved, newText, optNewTextAPairs, pool) {
- var oldLen = oldFullText.length;
-
- if (spliceStart >= oldLen) {
- spliceStart = oldLen - 1;
- }
- if (numRemoved > oldFullText.length - spliceStart - 1) {
- numRemoved = oldFullText.length - spliceStart - 1;
- }
- var oldText = oldFullText.substring(spliceStart, spliceStart+numRemoved);
- var newLen = oldLen + newText.length - oldText.length;
-
- var assem = Changeset.smartOpAssembler();
- assem.appendOpWithText('=', oldFullText.substring(0, spliceStart));
- assem.appendOpWithText('-', oldText);
- assem.appendOpWithText('+', newText, optNewTextAPairs, pool);
- assem.endDocument();
- return Changeset.pack(oldLen, newLen, assem.toString(), newText);
-};
-
-Changeset.toSplices = function(cs) {
- // get a list of splices, [startChar, endChar, newText]
-
- var unpacked = Changeset.unpack(cs);
- var splices = [];
-
- var oldPos = 0;
- var iter = Changeset.opIterator(unpacked.ops);
- var charIter = Changeset.stringIterator(unpacked.charBank);
- var inSplice = false;
- while (iter.hasNext()) {
- var op = iter.next();
- if (op.opcode == '=') {
- oldPos += op.chars;
- inSplice = false;
- }
- else {
- if (! inSplice) {
- splices.push([oldPos, oldPos, ""]);
- inSplice = true;
- }
- if (op.opcode == '-') {
- oldPos += op.chars;
- splices[splices.length-1][1] += op.chars;
- }
- else if (op.opcode == '+') {
- splices[splices.length-1][2] += charIter.take(op.chars);
- }
- }
- }
-
- return splices;
-};
-
-Changeset.characterRangeFollow = function(cs, startChar, endChar, insertionsAfter) {
- var newStartChar = startChar;
- var newEndChar = endChar;
- var splices = Changeset.toSplices(cs);
- var lengthChangeSoFar = 0;
- for(var i=0;i<splices.length;i++) {
- var splice = splices[i];
- var spliceStart = splice[0] + lengthChangeSoFar;
- var spliceEnd = splice[1] + lengthChangeSoFar;
- var newTextLength = splice[2].length;
- var thisLengthChange = newTextLength - (spliceEnd - spliceStart);
-
- if (spliceStart <= newStartChar && spliceEnd >= newEndChar) {
- // splice fully replaces/deletes range
- // (also case that handles insertion at a collapsed selection)
- if (insertionsAfter) {
- newStartChar = newEndChar = spliceStart;
- }
- else {
- newStartChar = newEndChar = spliceStart + newTextLength;
- }
- }
- else if (spliceEnd <= newStartChar) {
- // splice is before range
- newStartChar += thisLengthChange;
- newEndChar += thisLengthChange;
- }
- else if (spliceStart >= newEndChar) {
- // splice is after range
- }
- else if (spliceStart >= newStartChar && spliceEnd <= newEndChar) {
- // splice is inside range
- newEndChar += thisLengthChange;
- }
- else if (spliceEnd < newEndChar) {
- // splice overlaps beginning of range
- newStartChar = spliceStart + newTextLength;
- newEndChar += thisLengthChange;
- }
- else {
- // splice overlaps end of range
- newEndChar = spliceStart;
- }
-
- lengthChangeSoFar += thisLengthChange;
- }
-
- return [newStartChar, newEndChar];
-};
-
-Changeset.moveOpsToNewPool = function(cs, oldPool, newPool) {
- // works on changeset or attribution string
- var dollarPos = cs.indexOf('$');
- if (dollarPos < 0) {
- dollarPos = cs.length;
- }
- var upToDollar = cs.substring(0, dollarPos);
- var fromDollar = cs.substring(dollarPos);
- // order of attribs stays the same
- return upToDollar.replace(/\*([0-9a-z]+)/g, function(_, a) {
- var oldNum = Changeset.parseNum(a);
- var pair = oldPool.getAttrib(oldNum);
- var newNum = newPool.putAttrib(pair);
- return '*'+Changeset.numToString(newNum);
- }) + fromDollar;
-};
-
-Changeset.makeAttribution = function(text) {
- var assem = Changeset.smartOpAssembler();
- assem.appendOpWithText('+', text);
- return assem.toString();
-};
-
-// callable on a changeset, attribution string, or attribs property of an op
-Changeset.eachAttribNumber = function(cs, func) {
- var dollarPos = cs.indexOf('$');
- if (dollarPos < 0) {
- dollarPos = cs.length;
- }
- var upToDollar = cs.substring(0, dollarPos);
-
- upToDollar.replace(/\*([0-9a-z]+)/g, function(_, a) {
- func(Changeset.parseNum(a));
- return '';
- });
-};
-
-// callable on a changeset, attribution string, or attribs property of an op,
-// though it may easily create adjacent ops that can be merged.
-Changeset.filterAttribNumbers = function(cs, filter) {
- return Changeset.mapAttribNumbers(cs, filter);
-};
-
-Changeset.mapAttribNumbers = function(cs, func) {
- var dollarPos = cs.indexOf('$');
- if (dollarPos < 0) {
- dollarPos = cs.length;
- }
- var upToDollar = cs.substring(0, dollarPos);
-
- var newUpToDollar = upToDollar.replace(/\*([0-9a-z]+)/g, function(s, a) {
- var n = func(Changeset.parseNum(a));
- if (n === true) {
- return s;
- }
- else if ((typeof n) === "number") {
- return '*'+Changeset.numToString(n);
- }
- else {
- return '';
- }
- });
-
- return newUpToDollar + cs.substring(dollarPos);
-};
-
-Changeset.makeAText = function(text, attribs) {
- return { text: text, attribs: (attribs || Changeset.makeAttribution(text)) };
-};
-
-Changeset.applyToAText = function(cs, atext, pool) {
- return { text: Changeset.applyToText(cs, atext.text),
- attribs: Changeset.applyToAttribution(cs, atext.attribs, pool) };
-};
-
-Changeset.cloneAText = function(atext) {
- return { text: atext.text, attribs: atext.attribs };
-};
-
-Changeset.copyAText = function(atext1, atext2) {
- atext2.text = atext1.text;
- atext2.attribs = atext1.attribs;
-};
-
-Changeset.appendATextToAssembler = function(atext, assem) {
- // intentionally skips last newline char of atext
- var iter = Changeset.opIterator(atext.attribs);
- var op = Changeset.newOp();
- while (iter.hasNext()) {
- iter.next(op);
- if (! iter.hasNext()) {
- // last op, exclude final newline
- if (op.lines <= 1) {
- op.lines = 0;
- op.chars--;
- if (op.chars) {
- assem.append(op);
- }
- }
- else {
- var nextToLastNewlineEnd =
- atext.text.lastIndexOf('\n', atext.text.length-2) + 1;
- var lastLineLength = atext.text.length - nextToLastNewlineEnd - 1;
- op.lines--;
- op.chars -= (lastLineLength + 1);
- assem.append(op);
- op.lines = 0;
- op.chars = lastLineLength;
- if (op.chars) {
- assem.append(op);
- }
- }
- }
- else {
- assem.append(op);
- }
- }
-};
-
-Changeset.prepareForWire = function(cs, pool) {
- var newPool = new AttribPool();
- var newCs = Changeset.moveOpsToNewPool(cs, pool, newPool);
- return {translated: newCs, pool: newPool};
-};
-
-Changeset.isIdentity = function(cs) {
- var unpacked = Changeset.unpack(cs);
- return unpacked.ops == "" && unpacked.oldLen == unpacked.newLen;
-};
-
-Changeset.opAttributeValue = function(op, key, pool) {
- return Changeset.attribsAttributeValue(op.attribs, key, pool);
-};
-
-Changeset.attribsAttributeValue = function(attribs, key, pool) {
- var value = '';
- if (attribs) {
- Changeset.eachAttribNumber(attribs, function(n) {
- if (pool.getAttribKey(n) == key) {
- value = pool.getAttribValue(n);
- }
- });
- }
- return value;
-};
-
-Changeset.builder = function(oldLen) {
- var assem = Changeset.smartOpAssembler();
- var o = Changeset.newOp();
- var charBank = Changeset.stringAssembler();
-
- var self = {
- // attribs are [[key1,value1],[key2,value2],...] or '*0*1...' (no pool needed in latter case)
- keep: function(N, L, attribs, pool) {
- o.opcode = '=';
- o.attribs = (attribs &&
- Changeset.makeAttribsString('=', attribs, pool)) || '';
- o.chars = N;
- o.lines = (L || 0);
- assem.append(o);
- return self;
- },
- keepText: function(text, attribs, pool) {
- assem.appendOpWithText('=', text, attribs, pool);
- return self;
- },
- insert: function(text, attribs, pool) {
- assem.appendOpWithText('+', text, attribs, pool);
- charBank.append(text);
- return self;
- },
- remove: function(N, L) {
- o.opcode = '-';
- o.attribs = '';
- o.chars = N;
- o.lines = (L || 0);
- assem.append(o);
- return self;
- },
- toString: function() {
- assem.endDocument();
- var newLen = oldLen + assem.getLengthChange();
- return Changeset.pack(oldLen, newLen, assem.toString(),
- charBank.toString());
- }
- };
-
- return self;
-};
-
-Changeset.makeAttribsString = function(opcode, attribs, pool) {
- // makeAttribsString(opcode, '*3') or makeAttribsString(opcode, [['foo','bar']], myPool) work
- if (! attribs) {
- return '';
- }
- else if ((typeof attribs) == "string") {
- return attribs;
- }
- else if (pool && attribs && attribs.length) {
- if (attribs.length > 1) {
- attribs = attribs.slice();
- attribs.sort();
- }
- var result = [];
- for(var i=0;i<attribs.length;i++) {
- var pair = attribs[i];
- if (opcode == '=' || (opcode == '+' && pair[1])) {
- result.push('*'+Changeset.numToString(pool.putAttrib(pair)));
- }
- }
- return result.join('');
- }
-};
-
-// like "substring" but on a single-line attribution string
-Changeset.subattribution = function(astr, start, optEnd) {
- var iter = Changeset.opIterator(astr, 0);
- var assem = Changeset.smartOpAssembler();
- var attOp = Changeset.newOp();
- var csOp = Changeset.newOp();
- var opOut = Changeset.newOp();
-
- function doCsOp() {
- if (csOp.chars) {
- while (csOp.opcode && (attOp.opcode || iter.hasNext())) {
- if (! attOp.opcode) iter.next(attOp);
-
- if (csOp.opcode && attOp.opcode && csOp.chars >= attOp.chars &&
- attOp.lines > 0 && csOp.lines <= 0) {
- csOp.lines++;
- }
-
- Changeset._slicerZipperFunc(attOp, csOp, opOut, null);
- if (opOut.opcode) {
- assem.append(opOut);
- opOut.opcode = '';
- }
- }
- }
- }
-
- csOp.opcode = '-';
- csOp.chars = start;
-
- doCsOp();
-
- if (optEnd === undefined) {
- if (attOp.opcode) {
- assem.append(attOp);
- }
- while (iter.hasNext()) {
- iter.next(attOp);
- assem.append(attOp);
- }
- }
- else {
- csOp.opcode = '=';
- csOp.chars = optEnd - start;
- doCsOp();
- }
-
- return assem.toString();
-};
-
-Changeset.inverse = function(cs, lines, alines, pool) {
- // lines and alines are what the changeset is meant to apply to.
- // They may be arrays or objects with .get(i) and .length methods.
- // They include final newlines on lines.
- function lines_get(idx) {
- if (lines.get) {
- return lines.get(idx);
- }
- else {
- return lines[idx];
- }
- }
- function lines_length() {
- if ((typeof lines.length) == "number") {
- return lines.length;
- }
- else {
- return lines.length();
- }
- }
- function alines_get(idx) {
- if (alines.get) {
- return alines.get(idx);
- }
- else {
- return alines[idx];
- }
- }
- function alines_length() {
- if ((typeof alines.length) == "number") {
- return alines.length;
- }
- else {
- return alines.length();
- }
- }
-
- var curLine = 0;
- var curChar = 0;
- var curLineOpIter = null;
- var curLineOpIterLine;
- var curLineNextOp = Changeset.newOp('+');
-
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var builder = Changeset.builder(unpacked.newLen);
-
- function consumeAttribRuns(numChars, func/*(len, attribs, endsLine)*/) {
-
- if ((! curLineOpIter) || (curLineOpIterLine != curLine)) {
- // create curLineOpIter and advance it to curChar
- curLineOpIter = Changeset.opIterator(alines_get(curLine));
- curLineOpIterLine = curLine;
- var indexIntoLine = 0;
- var done = false;
- while (! done) {
- curLineOpIter.next(curLineNextOp);
- if (indexIntoLine + curLineNextOp.chars >= curChar) {
- curLineNextOp.chars -= (curChar - indexIntoLine);
- done = true;
- }
- else {
- indexIntoLine += curLineNextOp.chars;
- }
- }
- }
-
- while (numChars > 0) {
- if ((! curLineNextOp.chars) && (! curLineOpIter.hasNext())) {
- curLine++;
- curChar = 0;
- curLineOpIterLine = curLine;
- curLineNextOp.chars = 0;
- curLineOpIter = Changeset.opIterator(alines_get(curLine));
- }
- if (! curLineNextOp.chars) {
- curLineOpIter.next(curLineNextOp);
- }
- var charsToUse = Math.min(numChars, curLineNextOp.chars);
- func(charsToUse, curLineNextOp.attribs,
- charsToUse == curLineNextOp.chars && curLineNextOp.lines > 0);
- numChars -= charsToUse;
- curLineNextOp.chars -= charsToUse;
- curChar += charsToUse;
- }
-
- if ((! curLineNextOp.chars) && (! curLineOpIter.hasNext())) {
- curLine++;
- curChar = 0;
- }
- }
-
- function skip(N, L) {
- if (L) {
- curLine += L;
- curChar = 0;
- }
- else {
- if (curLineOpIter && curLineOpIterLine == curLine) {
- consumeAttribRuns(N, function() {});
- }
- else {
- curChar += N;
- }
- }
- }
-
- function nextText(numChars) {
- var len = 0;
- var assem = Changeset.stringAssembler();
- var firstString = lines_get(curLine).substring(curChar);
- len += firstString.length;
- assem.append(firstString);
-
- var lineNum = curLine+1;
- while (len < numChars) {
- var nextString = lines_get(lineNum);
- len += nextString.length;
- assem.append(nextString);
- lineNum++;
- }
-
- return assem.toString().substring(0, numChars);
- }
-
- function cachedStrFunc(func) {
- var cache = {};
- return function(s) {
- if (! cache[s]) {
- cache[s] = func(s);
- }
- return cache[s];
- };
- }
-
- var attribKeys = [];
- var attribValues = [];
- while (csIter.hasNext()) {
- var csOp = csIter.next();
- if (csOp.opcode == '=') {
- if (csOp.attribs) {
- attribKeys.length = 0;
- attribValues.length = 0;
- Changeset.eachAttribNumber(csOp.attribs, function(n) {
- attribKeys.push(pool.getAttribKey(n));
- attribValues.push(pool.getAttribValue(n));
- });
- var undoBackToAttribs = cachedStrFunc(function(attribs) {
- var backAttribs = [];
- for(var i=0;i<attribKeys.length;i++) {
- var appliedKey = attribKeys[i];
- var appliedValue = attribValues[i];
- var oldValue = Changeset.attribsAttributeValue(attribs, appliedKey, pool);
- if (appliedValue != oldValue) {
- backAttribs.push([appliedKey, oldValue]);
- }
- }
- return Changeset.makeAttribsString('=', backAttribs, pool);
- });
- consumeAttribRuns(csOp.chars, function(len, attribs, endsLine) {
- builder.keep(len, endsLine ? 1 : 0, undoBackToAttribs(attribs));
- });
- }
- else {
- skip(csOp.chars, csOp.lines);
- builder.keep(csOp.chars, csOp.lines);
- }
- }
- else if (csOp.opcode == '+') {
- builder.remove(csOp.chars, csOp.lines);
- }
- else if (csOp.opcode == '-') {
- var textBank = nextText(csOp.chars);
- var textBankIndex = 0;
- consumeAttribRuns(csOp.chars, function(len, attribs, endsLine) {
- builder.insert(textBank.substr(textBankIndex, len), attribs);
- textBankIndex += len;
- });
- }
- }
-
- return Changeset.checkRep(builder.toString());
-};
diff --git a/trunk/etherpad/src/static/js/pad.js.old b/trunk/etherpad/src/static/js/pad.js.old
deleted file mode 100644
index 6191b31..0000000
--- a/trunk/etherpad/src/static/js/pad.js.old
+++ /dev/null
@@ -1,1984 +0,0 @@
-//----------------------------------------------------------------
-// initialization
-//----------------------------------------------------------------
-
-$(document).ready(function() {
- if (!pad.initialized) {
- pad.init();
- }
-});
-
-$(window).unload(function() {
- if (pad.ace) {
- pad.ace.destroy();
- }
-});
-
-pad = {
- initTime: 0,
- initialized: false,
- myUserInfo: null, /* userInfo for this client's user */
- debugEnabled: false,
- userBoxIds: {},
- lastBoxId: 0,
- connectionState: 'DISCONNECTED',
- notifyQueue: [],
- lastNotify: 0,
- persistLastNotify: false,
- collabClient: null,
- users: {},
- ace: null,
- padId: null,
- wrapLines: true,
- initialCookiePrefs: {},
- revisionList: [],
- clientTimeOffset: (+new Date()) - clientVars.serverTimestamp,
- REVISIONCOUNT_STEP: 5,
- shownRevisions: 5,
- sideBarVisible: true,
- sideBoxVisibility: {},
- diagnosticInfo: {},
- experiencingConnectionTrouble: false,
- padHasFocus: true,
- isFreshCookie: false,
- viewZoom: 100,
- title: null,
- password: null,
- isEditingTitle: false
-};
-
-pad.initCookie = function() {
- pad.initialCookiePrefs = pad.getInitialCookiePrefs();
-};
-
-pad.initPrefsPane = function() {
- // Setup checkbox prefs.
- function scbp(n, v) {
- var t = pad.initialCookiePrefs[v];
- pad.markPref(n, t);
- }
- scbp('wrap', 'wrapLines');
- scbp('showcolors', 'showAuthorColors');
- scbp('linenums', 'showLineNumbers');
- scbp('fullwidth', 'fullWidth');
-
- pad.setFullWidth(pad.initialCookiePrefs.fullWidth);
-
- // events
- function prefclick(elt) {
- var d = $(elt);
- var name = d.attr('id').substr("checkpref".length);
- var t = !pad.isPrefMarked(name);
- pad.markPref(name, t);
- pad.updatePref(name, t);
- pad.saveCookie();
- }
- $('div.prefcheckbox').mousedown(function(e) {
- prefclick(this);
- e.preventDefault();
- return false;
- });
- $('div.prefcheckbox').mouseup(pad.handlerPreventDefault);
- $('div.prefcheckbox').click(pad.handlerPreventDefault);
-};
-
-pad.initAce = function(donefunc) {
-
- // ACE functions.
- function editorReady() {
- $('#editorcell').removeClass('editorcell_loading').addClass('editorcell_loaded');
- $('#sidebar').removeClass('sidebar_loading');
- $('#loadingbox').remove();
- $(window).bind("resize", pad.resizePage);
- setTimeout(function() { ace.focus(); pad.resizePage(); }, 0);
- donefunc();
- }
-
- // Setup ace.
- pad.dmesg("pad.init(): loading Ace2Editor");
- var ace = new Ace2Editor();
- ace.init("editorcontainer", "", editorReady);
- ace.setProperty("wraps", pad.initialCookiePrefs.wrapLines);
- ace.setProperty("showsAuthorColors", pad.initialCookiePrefs.showAuthorColors);
- ace.setProperty("lineNumbers", pad.initialCookiePrefs.showLineNumbers);
- if (pad.initialCookiePrefs.highlightJs === true) {
- ace.setProperty("lexer", "js");
- pad.markPref('jshighlight', true);
- } else {
- ace.setProperty("lexer", "txt");
- pad.markPref('jshighlight', false);
- }
- // star window title on dirty
- ace.setNotifyDirty(function() {
- if (!pad.padHasFocus) {
- var currentTitle = $(document).attr('title');
- if (currentTitle.charAt(0) != '*') {
- $(document).attr('title', '* '+currentTitle);
- }
- }
- });
- if (pad.debugEnabled) {
- ace.setProperty("dmesg", pad.dmesg);
- }
-
- pad.ace = ace;
-};
-
-pad.initMyUserInfo = function() {
- // assigned colorId
- var colorId = clientVars.assignedColorId;
- if (!clientVars.colorPalette[colorId]) {
- colorId = Math.floor((Math.random() * clientVars.colorPalette.length));
- }
-
- // Populate user info.
- pad.dmesg("clientVars: "+JSON.stringify(clientVars));
- pad.myUserInfo = {
- userId: (pad.initialCookiePrefs.userId || pad.uniqueId()),
- name: pad.getDefaultUsername(),
- ip: clientVars.clientIp,
- colorId: colorId,
- userAgent: pad.uaDisplay(clientVars.userAgent)
- };
-
- pad.userJoin(pad.myUserInfo);
- pad.dmesg("myUserInfo: "+JSON.stringify(pad.myUserInfo));
-};
-
-pad.initSideBoxes = function() {
- // expand side-bars if cookie indicates
- for (paneName in pad.initialCookiePrefs.sideBoxVisibility) {
- if (pad.initialCookiePrefs.sideBoxVisibility[paneName]) {
- pad.showSideBox(paneName);
- }
- }
-};
-
-pad.initCollab = function() {
- var collabOptions = {
- colorPalette: clientVars.colorPalette
- };
- pad.collabClient = getCollabClient(pad.ace,
- clientVars.collab_client_vars,
- pad.myUserInfo,
- collabOptions);
-
- pad.collabClient.setOnClientMessage(pad.onClientMessage);
- pad.collabClient.setOnServerMessage(pad.onServerMessage);
- pad.collabClient.setOnUserJoin(pad.userJoin);
- pad.collabClient.setOnUserLeave(pad.userLeave);
- pad.collabClient.setOnUpdateUserInfo(pad.updateUserInfo);
- pad.collabClient.setOnChannelStateChange(pad.channelStateChange);
- pad.collabClient.setOnConnectionTrouble(pad.onConnectionTrouble);
-};
-
-pad.initRevisions = function() {
- // Render revision list.
- pad.revisionList = clientVars.initialRevisionList;
- pad.renderRevisionList();
-
- // Events
- $('#savenow').click(function(e) {
- pad.saveRevision();
- e.preventDefault();
- return false;
- });
- setInterval(function() {
- pad.renderRevisionList(true);
- }, (2*60*1000)); // to update times correctly
-};
-
-pad.initEvents = function() {
- // shareurl click
- $("#headurl").click(function() { selectElementContents($("#shareurl").get(0)); });
-
- // feedback form
- $('#feedbacksubmit').click(function(e) {
- pad.submitfeedback();
- e.preventDefault();
- return false;
- });
-
- // sidepane expand/collapse events
- $('#sidebar div.sideheadwrap').mousedown(function(e) {
- var paneName = $(this).attr('id').substr("head".length);
- if (pad.isSideBoxVisible(paneName)) {
- pad.hideSideBox(paneName);
- } else {
- pad.showSideBox(paneName);
- }
- e.preventDefault();
- return false;
- });
- $('#sidebar div.sideheadwrap').mouseup(pad.handlerPreventDefault);
- $('#sidebar div.sideheadwrap').click(pad.handlerPreventDefault);
-
- // ---- share link ----
- $('#invitemore').show();
- $('#invite_email_submit').click(pad.invitemoreSendEmail);
- pad.setOnEnterKey('#invite_email, #invite_email_submit', pad.invitemoreSendEmail);
-
- // ---- force reconnect ----
- $('button.forcereconnect').click(function() {
- pad.forceReconnect();
- });
-};
-
-pad.initFocusTracker = function() {
- var myFrames = [];
- function walkframes(frame, depth) {
- try {
- if (depth > 4) { return; }
- myFrames.push(frame);
- $(frame).contents().find('iframe').each(function() {
- walkframes(this, depth+1);
- });
- } catch (ex) {/*swallow*/}
- }
- myFrames.push($(window));
- $('iframe').each(function() { walkframes(this, 1); });
-
- function onFocus() { pad.padHasFocus = true; }
- function onBlur() { pad.padHasFocus = false; }
-
- for (var i = 0; i < myFrames.length; i++) {
- var f = myFrames[i];
- $(f).focus(onFocus).blur(onBlur);
- /*
- if (f.contentDocument) {
- $(f.contentDocument).click(onFocus);
- }*/
- }
- /* $(document).click(onFocus); */
-
- // Reclaim the title periodically
- var focusedLastCheck = true;
- setInterval(function() {
- if (!focusedLastCheck && pad.padHasFocus) {
- $(document).attr('title', 'EtherPad: '+pad.padId);
- }
- focusedLastCheck = pad.padHasFocus;
- }, 1000);
-};
-
-pad.initWelcomeMessage = function() {
- if (pad.isFreshCookie && (clientVars.numConnectedUsers == 0)) {
- pad.invitemoreShow();
- }
-};
-
-pad.initResizeTimer = function() {
- pad.resizePage(true);
- setInterval(function() { pad.resizePage(true); }, 2000);
-}
-
-pad.initModalDialogs = function() {
- pad.swallowAllMouseEvents($("#dialogtopbar"));
-}
-
-pad.initImportExport = function() {
- // pad.addExportFrames();
- pad.addImportFrames();
- $('#importfileinput').change(pad.fileInputUpdated);
- $('#importform').submit(pad.fileInputSubmit);
- $('.disabledexport').click(pad.cantExport)
- // $('.requiresoffice').click(pad.exportDoLongClick);
- // $('.exportlink').click(pad.exportHideMessages);
-}
-
-pad.initRichText = function() {
- $(".toptoolbarbutton").attr("unselectable", "on"); // for IE
- $("#toptoolbar").removeClass("disabledtoolbar");
-}
-
-pad.initViewBar = function() {
-
- pad.setViewFont(pad.initialCookiePrefs.viewFont || 'normal'); // sets pad.viewFont
- pad.setViewZoom(pad.initialCookiePrefs.viewZoom || 100); // sets pad.viewZoom
-
- $("#bottoolbar").css('display', 'block'); // show it
- $("#bottoolbar").removeClass("disabledtoolbar");
-
- $("#viewzoommenu").change(function(evt) {
- pad.setViewZoom(Number($("#viewzoommenu").val().substring(1))); // remove 'z' from val
- });
- $("#viewfontmenu").change(function(evt) {
- pad.setViewFont($("#viewfontmenu").val());
- });
-}
-
-pad.initPadTitle = function() {
- pad.title = clientVars.initialTitle;
- pad.password = clientVars.initialPassword;
-
- $("#padtitle").submit(function(evt) {
- pad.submitTitle(true);
- evt.preventDefault();
- return false;
- });
- $("#padtitleedit").keyup(function(evt) {
- if (evt.which == 27) {
- // "escape" key
- pad.submitTitle(false);
- }
- });
- pad.renderPadTitle();
-}
-
-pad.init = function() {
- // note: order of init calls is important.
-
- pad.debugEnabled = clientVars.debugEnabled;
- pad.padId = clientVars.padId;
- pad.diagnosticInfo.uniqueId = pad.uniqueId();
-
- pad.dmesg("pad.init()");
-
- pad.initCookie();
- pad.initResizeTimer();
- pad.initAce(function() {
- document.domain = document.domain; // for comet, set after ACE creates its frames
- pad.initMyUserInfo();
- pad.initSideBoxes();
- pad.initCollab();
- pad.initRichText();
- pad.initViewBar();
- pad.initRevisions();
- pad.initPrefsPane();
- pad.initChat();
- pad.initEvents();
- pad.initFocusTracker();
- pad.initPadTitle();
- $('a#hidesidebar').show();
- pad.initTime = +(new Date());
- pad.initialized = true;
- pad.saveCookie(); // must happen after pad.initialized = true.
- pad.initModalDialogs();
- pad.initImportExport();
- pad.initWelcomeMessage();
- pad.dmesg("pad.init(): done!");
- });
-};
-
-//----------------------------------------------------------------
-
-pad.getDefaultUsername = function() {
- var cookieName = pad.initialCookiePrefs.name;
- if (cookieName) {
- return cookieName;
- }
- var nameGuess = clientVars.nameGuess;
- if (nameGuess) { return nameGuess; }
- return null;
-};
-
-pad.getCurrentPageHeight = function() {
- return $("#padcontent").offset().top + $("#padcontent").height() + 1;
-}
-
-pad.resizePage = function(dontReschedule) {
- // this method should not require any init to have happened
-
- var visibleHeight = document.documentElement.clientHeight;
- var sizedContentHeight = $("#sizedcontent").height() - 2; // subtract 2 for border
- var pageHeight = pad.getCurrentPageHeight();
-
- var newHeight = visibleHeight - (pageHeight - sizedContentHeight);
- var totalToolbarHeight = $("#toptoolbar").outerHeight() + $("#bottoolbar").outerHeight();
-
- // editor (left column, 1)
- var oldHeight1 = $("#editorcontainer").height() - totalToolbarHeight;
- var newHeight1 = newHeight - totalToolbarHeight;
-
- // sidebar (right column, 2)
- var oldHeight2 = $("#sidebar").height();
- var newHeight2 = newHeight;
-
- if (newHeight1 != oldHeight1) {
- $("#editorcontainer").css('height', newHeight1+"px");
- if (pad.ace) {
- pad.ace.adjustSize();
- }
- }
- if (newHeight2 != oldHeight2) {
- $("#sidebar").css('height', newHeight2+"px");
- }
-
- pad.repositionModals();
- if (pad.initialized) {
- pad.renderPadTitle();
- }
-
- if (! dontReschedule) {
- // try again in a bit in case we missed the correct size,
- // but don't let that call cause another setTimeout
- setTimeout(function() { pad.resizePage(true); }, 100);
- }
-};
-
-pad.setOnEnterKey = function(eltpath, f) {
- $(eltpath).keydown(function(e) {
- if (e.keyCode == 13) {
- f(e);
- e.preventDefault();
- return false;
- }
- return true; //continue event
- });
-};
-
-//----------------------------------------------------------------
-// New pad button.
-//----------------------------------------------------------------
-
-pad.newPad = function() {
- $('#newpad').submit();
-};
-
-//----------------------------------------------------------------
-// UI Preferences
-//----------------------------------------------------------------
-
-pad.isPrefMarked = function(n) {
- var v = !!$('#checkpref'+n+' input').attr('checked');
- pad.dmesg("isPrefMarked("+n+") = "+v);
- return v;
-};
-
-pad.markPref = function(n, t) {
- var i = $('#checkpref'+n+' input');
- if (t) {
- i.attr('checked', 'checked');
- } else {
- i.removeAttr('checked');
- }
-};
-
-pad.updatePref = function(name, val) {
- var ace = pad.ace;
- if (name == "showcolors") {
- ace.setProperty("showsAuthorColors", val);
- }
- if (name == "wrap") {
- ace.setProperty("wraps", val);
- }
- if (name == "linenums") {
- ace.setProperty("lineNumbers", val);
- }
- if (name == "jshighlight") {
- if (val) {
- ace.setProperty("lexer", "js");
- } else {
- ace.setProperty("lexer", "txt");
- }
- }
- if (name == "fullwidth") {
- pad.setFullWidth(val);
- }
-};
-
-//----------------------------------------------------------------
-
-pad.uniqueId = function() {
- return [
- clientVars.clientIp,
- String(+(new Date())),
- String(Math.floor(Math.random()*100000))
- ].join('.');
-};
-
-pad.getUserDisplayName = function(userInfo) {
- // strip HTML from newName.
- // TODO: better HTML escaping?
- var name = userInfo.name;
- if (!(typeof(name) == "string")) {
- name = "unnamed";
- if (userInfo.userId == pad.myUserInfo.userId) {
- name += ' (me)';
- }
- }
- return name;
-};
-
-//----------------------------------------------------------------
-// userJoin
-//----------------------------------------------------------------
-
-pad.userJoin = function(userInfo) {
- pad.dmesg("pad.userJoin: "+userInfo.name+"/"+userInfo.userId);
- pad.users[userInfo.userId] = userInfo;
-
- var name = pad.escapeHtml(pad.getUserDisplayName(userInfo));
- if (userInfo.userId != pad.myUserInfo.userId) {
- var currentTime = +(new Date());
- if ((currentTime - pad.initTime) > 1000*2) {
- pad.notify('<i>'+name+'</i> has joined the pad.');
- }
- }
-
- // assign an ID for the userbox div
- var boxId = pad.userBoxIds[userInfo.userId];
- if (!boxId) {
- pad.lastBoxId++;
- boxId = "userbox"+pad.lastBoxId;
- pad.userBoxIds[userInfo.userId] = boxId;
- var classNames = "userbox";
- if (userInfo.userId == pad.myUserInfo.userId) { classNames += " me"; }
- var userbox = '<div class="'+classNames+'" id="'+boxId+'"><!-- --></div>';
- $('#userlist').append(userbox);
- }
-
- $('#userlist div.lastuser').removeClass('lastuser');
- $('#'+boxId).addClass('lastuser').hide();
-
- pad.updateUserBox(userInfo);
- pad.updateChatHistoryForUser(userInfo);
-
- // show
- $('#'+boxId).fadeIn('slow');
-};
-
-pad.updateUserBox = function(userInfo) {
- var nameHtml = '<span class="username">' + pad.escapeHtml(pad.getUserDisplayName(userInfo)) + '</span>';
- var changeLink = '';
- var isMe = (userInfo.userId == pad.myUserInfo.userId);
- if (isMe) {
- changeLink = '<div id="rightuserlink">'+
- '<a id="changenamelink" href="javascript: void;" class="small_link">edit name/color</a>'+
- '</div>';
- }
- var displayIp = userInfo.ip + '/' + userInfo.userAgent;
- var boxId = pad.userBoxIds[userInfo.userId];
- var box = $('#'+boxId);
- if (box.size() != 1) {
- pad.notify("Warning: spurious user update for user &lt;"+userInfo.userId+"&gt;");
- return;
- }
- var bgcolor = clientVars.colorPalette[userInfo.colorId];
- box.empty().html([
- '<div class="userinfowrap' + (isMe ? ' myuserwrap' : '') + '">',
- '<div class="usercolor" style="background-color: ',bgcolor, '">',
- '&nbsp;</div>',
- '<div class="userinfo">',
- changeLink,
- ' <div>',
- nameHtml,
- ' </div>',
- ' <div class="ip">',
- displayIp,
- ' </div>',
- '</div>',
- '<div style="clear: both;"><!-- --></div>',
- '</div>'
- ].join(''));
- if (isMe) {
- $('#userlist div.myuserwrap').click(pad.myUserInfoClick);
- }
-};
-
-pad.myUserInfoClick = function(e) {
- if (pad.isEditingUserInfo) {
- return true;
- }
- pad.oldColorId = pad.myUserInfo.colorId;
- pad.isEditingUserInfo = true;
- $('#userlist div.me').hide().html([
- '<div class="edituserinfo">',
- '<h4>Name:</h4>',
- '<p><input type="text" id="mynewname" /></p>',
- '<h4>Color:</h4>',
- pad.renderColorPicker(),
- '<button id="savemyuserinfo">Save</button>',
- '<button id="canceleditmyuserinfo">Cancel</button>',
- '</div>'
- ].join('')).fadeIn('fast', function() {});
-
- $('input#mynewname').val(pad.getUserDisplayName(pad.myUserInfo)).focus().select();
- pad.setOnEnterKey('input#mynewname', pad.saveMyNewUserInfo);
-
- $('#canceleditmyuserinfo').click(pad.cancelEditMyUserInfo);
- $('#savemyuserinfo').click(pad.saveMyNewUserInfo);
-
- e.preventDefault();
- return false;
-};
-
-pad.cancelEditMyUserInfo = function(e) {
- if (pad.oldColorId != pad.myUserInfo.colorId) {
- pad.myUserInfo.colorId = pad.oldColorId;
- pad.collabClient.updateUserInfo(pad.myUserInfo);
- }
- $('#userlist div.me').fadeOut('fast', function() {
- pad.updateUserBox(pad.myUserInfo);
- $('#userlist div.me').fadeIn('fast');
- pad.isEditingUserInfo = false;
- });
- e.preventDefault();
- return false;
-};
-
-pad.saveMyNewUserInfo = function(e) {
- var newName = $('#mynewname').val();
- if (newName != "unnamed (me)") {
- pad.myUserInfo.name = newName;
- }
- $('#userlist div.me').fadeOut('fast', function() {
- $('#userlist div.me').html('Saving...');
- pad.collabClient.updateUserInfo(pad.myUserInfo);
- pad.saveCookie();
- pad.updateUserBox(pad.myUserInfo);
- $('#userlist div.me').fadeIn('fast');
- pad.isEditingUserInfo = false;
- pad.updateChatHistoryForUser(pad.myUserInfo);
- });
- e.preventDefault();
- return false;
-};
-
-pad.renderColorPicker = function() {
- function renderColorSquare(i) {
- var classNames = "";
- if (i == pad.myUserInfo.colorId) {
- classNames += " selectedcolor";
- }
- var html = [
- '<a class="'+classNames+'"',
- ' id="colorchoice'+i+'"',
- ' style="background: '+clientVars.colorPalette[i], ';"',
- ' href="javascript:void pad.chooseNewColor('+i+');">',
- '&nbsp;</a>'
- ].join('');
- return html;
- }
- var r = '<div id="colorpicker">';
- for (var i = 0; i < clientVars.colorPalette.length; i++) {
- r += renderColorSquare(i);
- }
- r += '<div style="clear: both;"><!-- --></div></div>';
- return r;
-};
-
-pad.chooseNewColor = function(colorId) {
- pad.myUserInfo.colorId = colorId;
- pad.collabClient.updateUserInfo(pad.myUserInfo);
- $('#colorpicker a').removeClass('selectedcolor');
- $('#colorpicker a#colorchoice'+colorId).addClass('selectedcolor');
-};
-
-//----------------------------------------------------------------
-// userLeave
-//----------------------------------------------------------------
-
-pad.userLeave = function(userInfo) {
- pad.dmesg("pad.userLeave: "+userInfo.name+"/"+userInfo.userId);
-
- var box = $('#'+pad.userBoxIds[userInfo.userId]);
- box.attr('id', ('oldbox'+(+(new Date()))));
-
- delete pad.users[userInfo.userId];
- delete pad.userBoxIds[userInfo.userId];
-
- box.fadeOut('slow', function() {
- box.remove();
- var boxes = $('#userlist').children();
- if (boxes.size() > 0) {
- $(boxes.get(boxes.size()-1)).addClass('lastuser');
- }
- });
-
- pad.updateChatHistoryForUser(userInfo);
-};
-
-//----------------------------------------------------------------
-// updateUserInfo
-//----------------------------------------------------------------
-
-pad.updateUserInfo = function(userInfo) {
- pad.updateUserBox(userInfo);
- pad.updateChatHistoryForUser(userInfo);
- // TODO: draw attention to the updated userbox somehow? flash it?
- var oldInfo = pad.users[userInfo.userId];
- if (oldInfo.name != userInfo.name) {
- var oldName = pad.escapeHtml(pad.getUserDisplayName(oldInfo));
- var newName = pad.escapeHtml(pad.getUserDisplayName(userInfo));
- pad.notify("<i>"+oldName+"</i> is now known as <i>"+newName+"</i>.");
- }
- if (oldInfo.colorId != userInfo.colorId) {
- pad.notify("<i>"+pad.escapeHtml(pad.getUserDisplayName(userInfo))+"</i> has a new background color.");
- }
- pad.users[userInfo.userId] = userInfo;
-};
-
-//----------------------------------------------------------------
-// channelStateChange
-//----------------------------------------------------------------
-
-pad.channelStateChange = function(newState, message) {
- pad.connectionState = newState;
- if (newState == "CONNECTED") {
- $('#savenow').removeAttr('disabled');
- pad.displayConnectionStatus('connected');
- pad.notify("Connected to EtherPad synchronization server.");
- }
- if (newState == "RECONNECTING") {
- $('#savenow').attr('disabled', true);
- pad.displayConnectionStatus('connecting');
- pad.notify("Lost connection with server. Attempting to reconnect...", true);
- }
- if (newState == "DISCONNECTED") {
- pad.diagnosticInfo.disconnectedMessage = message;
- pad.diagnosticInfo.padInitTime = pad.initTime;
- pad.asyncSendDiagnosticInfo();
-
- $('#savenow').attr('disabled', true);
-
- pad.displayConnectionStatus('disconnected');
- if (typeof top.ajlog == "string") { top.ajlog += ("Disconnected: "+message+'\n'); }
-
- $('div#bigtoperror_wrap').addClass('hidden');
- $('div.bigtoperror').hide();
- pad.clearNotificationQueue();
- if (pad.ace) {
- pad.ace.setProperty("grayedOut", true);
- pad.ace.setEditable(false);
- }
- if (message == "userdup") {
- $('div#disconnected_userdup').show();
- } else if (message == "looping") {
- $('div#disconnected_looping').show();
- $('div#reconnect_advise').show();
- } else if (message == "slowcommit") {
- $('div#disconnected_slowcommit').show();
- $('div#reconnect_advise').show();
- } else if (message == "initsocketfail") {
- $('div#disconnected_initsocketfail').show();
- $('div#reconnect_advise').show();
- } else {
- $('div#disconnected_unknown').show();
- $('div#reconnect_advise').show();
- }
- pad.notify("Lost connection with server.");
- $('div#bigtoperror_wrap').html();
- $('div#bigtoperror_wrap').removeClass('hidden').fadeIn('fast', function() {
- pad.resizePage();
- });
- $('div#userlist div.userbox').remove();
- }
-};
-
-//----------------------------------------------------------------
-// Notification system
-//----------------------------------------------------------------
-
-pad.notify = function(message, persist) {
- pad.notifyQueue.push([message, persist]);
- setTimeout(pad.processNotifyQueue, 50);
-};
-
-pad.clearNotificationQueue = function() {
- delete pad.notifyQueue;
- pad.notifyQueue = [];
-};
-
-pad.processNotifyQueue = function() {
- if (pad.notifyQueue.length == 0) {
- return;
- }
- var msSinceLast = (+(new Date()) - pad.lastNotify);
- if (msSinceLast < 1000) {
- setTimeout(pad.processNotifyQueue, 1050-msSinceLast);
- return;
- }
- var msg = pad.notifyQueue.shift();
- $('#topbarmsg').fadeOut('fast', function() {
- $('#topbarmsg').html(msg[0]).fadeIn('slow');
- });
- pad.lastNotify = +(new Date());
-
- // set window title if blurred
- function striptags(x) {
- return x.replace(/<[^\>]+>/g, '');
- }
- if (!pad.padHasFocus) {
- $(document).attr('title', '* '+striptags(msg[0]));
- }
-
- // clear it after 5 seconds unless "persist" was specified
- pad.persistLastNotify = msg[1];
- setTimeout(function() {
- if (!pad.persistLastNotify) {
- $('#topbarmsg').fadeOut('slow');
- }
- }, 5000);
-};
-
-//----------------------------------------------------------------
-// Cookies
-//----------------------------------------------------------------
-
-pad.saveCookie = function() {
- if (!pad.initialized) { return; }
- var prefs = {
- userId: pad.myUserInfo.userId,
- name: pad.myUserInfo.name,
- colorId: pad.myUserInfo.colorId,
- wrapLines: pad.isPrefMarked('wrap'),
- showAuthorColors: pad.isPrefMarked('showcolors'),
- showLineNumbers: pad.isPrefMarked('linenums'),
- highlightJs: pad.isPrefMarked('jshighlight'),
- fullWidth: pad.isPrefMarked('fullwidth'),
- sideBoxVisibility: pad.sideBoxVisibility,
- viewZoom: pad.viewZoom,
- viewFont: pad.viewFont
- };
- var expiresDate = new Date();
- expiresDate.setFullYear(3000);
- document.cookie = ('prefs='+escape(JSON.stringify(prefs))+
- ';expires='+expiresDate.toGMTString());
-
- // If the browser rejects the cookie, then show an error message.
- if (clientVars.isProPad &&
- !(document.cookie &&
- (document.cookie.length > 0) &&
- (document.cookie.indexOf('prefs') >= 0))) {
-
- if (!pad.alreadyWarnedAboutNoCookies) {
- alert("Warning: it appears that your browser does not have cookies enabled."+
- " EtherPad uses cookies to keep track of unique users for the purpose"+
- " of putting a quota on the number of active users. Using EtherPad without "+
- " cookies may fill up your server's user quota faster than expected.");
- pad.alreadyWarnedAboutNoCookies = true;
- }
- }
-};
-
-pad.getInitialCookiePrefs = function() {
-
- function _getExistingCookie() {
- if (document.cookie.length < 1) {
- pad.isFreshCookie = true;
- return {};
- }
- var name = "prefs";
- var start = document.cookie.indexOf(name + "=");
- if (start == -1) {
- pad.isFreshCookie = true;
- return {};
- }
- start = start + name.length + 1;
- var end = document.cookie.indexOf(";", start);
- if (end == -1) {
- end = document.cookie.length;
- }
- try {
- return JSON.parse(unescape(document.cookie.substring(start, end)));
- } catch (ex) {
- pad.isFreshCookie = true;
- return {};
- }
- }
-
- var cp = _getExistingCookie();
-
- // required cookie fields & defaults
- function _setDefault(name, val) {
- if (cp[name] === undefined) {
- cp[name] = val;
- }
- }
- _setDefault('sideBoxVisibility', {});
- _setDefault('wrapLines', true);
- _setDefault('showAuthorColors', true);
- _setDefault('showLineNumbers', false);
- _setDefault('fullWidth', false);
-
- return cp;
-};
-
-//----------------------------------------------------------------
-
-pad.forceReconnect = function(diagnosticInfo) {
- $('form#reconnect input#padId').val(pad.padId);
- pad.diagnosticInfo.collabDiagnosticInfo = pad.collabClient.getDiagnosticInfo();
- $('form#reconnect input#diagnosticInfo').val(JSON.stringify(pad.diagnosticInfo));
- $('form#reconnect input#missedChanges').val(JSON.stringify(pad.collabClient.getMissedChanges()));
- $('form#reconnect').submit();
-};
-
-pad.dmesg = function(m) {
- if (pad.debugEnabled) {
- $('#djs').append('<p>'+m+'</p>');
- var djs = $('#djs').get(0);
- djs.scrollTop = djs.scrollHeight;
- }
-};
-
-pad.showSideBar = function() {
- $('#sidebarcell').show().addClass('visible');
- $('a#showsidebar').hide();
- $('a#hidesidebar').show();
- pad.sideBarVisible = true;
- pad.saveCookie();
- return false;
-};
-
-pad.hideSideBar = function() {
- $('#sidebarcell').hide().removeClass('visible');
- $('a#showsidebar').show();
- $('a#hidesidebar').hide();
- pad.sideBarVisible = false;
- pad.saveCookie();
- return false;
-};
-
-pad.setFullWidth = function(fullWidth) {
- if (fullWidth) {
- //$('#padhead, #appjetfooter').fadeOut('fast').addClass('hidden');
- $('body').removeClass('limwidth').addClass('fullwidth');
- $('#widthlink').attr('title', "Use fixed pad width");
- } else {
- // hack:
- $("#padtitle").css('width', '400px');
-
- //$('#padhead, #appjetfooter').removeClass('hidden').fadeIn('fast');
- $('body').removeClass('fullwidth').addClass('limwidth');
- $('#widthlink').attr('title', "Use full window width");
- }
- if (pad.initialized) {
- pad.resizePage();
- }
-};
-
-pad.toggleFullWidth = function() {
- // fires when user clicks icon in corner; updates preferences
- var oldValue = pad.isPrefMarked("fullwidth");
- var newValue = ! oldValue;
-
- pad.markPref("fullwidth", newValue);
- pad.updatePref("fullwidth", newValue);
-
- pad.saveCookie();
-}
-
-pad.handlerPreventDefault = function(e) {
- e.preventDefault();
- return false;
-}
-
-pad.swallowAllMouseEvents = function(jqueryNodes) {
- jqueryNodes.click(pad.handlerPreventDefault);
- jqueryNodes.mousedown(pad.handlerPreventDefault);
- jqueryNodes.mouseup(pad.handlerPreventDefault);
-}
-
-//----------------------------------------------------------------
-// Saved Revisions
-//----------------------------------------------------------------
-
-pad.renderRevisionList = function(fast) {
- var rlis = pad.revisionList;
- var content = "";
- for (var i = 0; (i < rlis.length) && (i < pad.shownRevisions); i++) {
- var rnum = rlis.length - i;
- var name = pad.escapeHtml(rlis[i].savedBy);
- name += " ("+rlis[i].ip+")";
- var when = pad.timediff(new Date(rlis[i].timestamp));
- var viewLink = '/ep/pad/view/'+pad.padId+'/'+rlis[i].id;
- var restoreLink = 'javascript:void pad.restoreRevision('+rnum+');';
- var label = pad.escapeHtml(rlis[i].label || ('Revision '+rnum));
- if (rlis[i].savedById == pad.myUserInfo.userId &&
- ((+(new Date()) - rlis[i].timestamp) < (24*60*60*1000))) {
- label = ('<a class="editrlabel small_link" href="javascript: void pad.editRevisionLabel('+rnum+');">'+
- label + '</a>');
- }
- content += ('<div class="revisioninfo" id="revisioninfo_'+rnum+'">'+
- ' <div class="rleft">'+
- ' <div id="rlabel'+rnum+'">'+label+'</div>'+
- ' <div class="ractions">'+
- ' <a class="small_link" target="_blank" href="'+viewLink+'">view</a>&nbsp;|&nbsp;<a class="small_link" href="'+restoreLink+'">restore</a>'+
- ' </div>'+
- ' </div>'+
- ' <div class="rright">saved '+when+' by '+name+'</div>'+
- ' <div style="clear: both;"><!-- --></div>'+
- '</div>');
- }
- var areMore = (pad.shownRevisions < pad.revisionList.length);
- var areFewer = (pad.shownRevisions > pad.REVISIONCOUNT_STEP);
- content += '<div class="revisionbottomlinks">';
- if (areMore || areFewer) {
- content += 'show:&nbsp;';
- }
- if (areFewer) {
- content += '<a class="small_link" href="javascript:void pad.fewerRevisions();">fewer</a>';
- }
- if (areMore && areFewer) {
- content += '&nbsp;|&nbsp;';
- }
- if (areMore) {
- content += '<a class="small_link" href="javascript:void pad.moreRevisions();">more</a>';
- }
- content += '</div>';
-
- if (fast) {
- $('#revisionlist').html(content);
- } else {
- $('#revisionlist').hide().html(content).fadeIn('fast');
- }
-};
-
-pad.fewerRevisions = function() {
- pad.shownRevisions -= pad.REVISIONCOUNT_STEP;
- pad.renderRevisionList();
-};
-
-pad.moreRevisions = function() {
- pad.shownRevisions += pad.REVISIONCOUNT_STEP;
- pad.renderRevisionList();
-};
-
-pad.saveRevision = function() {
- var mv = clientVars.accountPrivs.maxRevisions;
- if ((mv != -1) && (pad.revisionList.length >= mv)) {
- $('#savenow').hide();
- $('#nosaveprivs').fadeIn('fast');
- return;
- }
- $('#savenow').attr('disabled', true).val("Saving...");
- var savedBy = pad.myUserInfo.name || "unnamed";
- pad.collabClient.callWhenNotCommitting(doAjax);
- function doAjax() {
- $.ajax({
- type: 'post',
- url: '/ep/pad/saverevision',
- data: {
- padId: pad.padId,
- savedBy: savedBy,
- savedById: pad.myUserInfo.userId,
- revNum: pad.collabClient.getCurrentRevisionNumber()
- },
- success: success,
- error: error
- });
- }
- function success(text) {
- pad.revisionList = JSON.parse(text);
- if (pad.revisionList.length > 0) {
- pad.clientTimeOffset = +(new Date) - pad.revisionList[0].timestamp;
- }
- pad.renderRevisionList();
- pad.collabClient.sendClientMessage({
- type: 'newRevisionList',
- revisionList: pad.revisionList,
- savedBy: savedBy
- });
- $('#savenow').val("Save Now").removeAttr('disabled');
- }
- function error(e) {
- alert("Oops! The server failed to save the revision. Please try again later.");
- $('#savenow').val("Save Now").removeAttr('disabled');
- }
-};
-
-pad.restoreRevision = function(rnum) {
- var i = pad.revisionList.length - rnum;
- var rev = pad.revisionList[i];
- var warning = ("Restoring this revision will replace the current"
- + "pad with the text saved in revision \""
- + ""+rev.label+"\". Are you sure you want to continue?");
-
- if (confirm(warning)) {
- $.ajax({
- type: 'get',
- url: '/ep/pad/getrevisionatext',
- data: {padId: pad.padId, revId: rev.id},
- success: success,
- error: error
- });
- }
- function success(resultJson) {
- var result = JSON.parse(resultJson);
- pad.collabClient.addHistoricalAuthors(result.historicalAuthorData);
- pad.ace.importAText(result.atext, result.apool, true);
- }
- function error(e) {
- alert("Oops! There was an error retreiving the text (revNum= "+
- rev.revNum+"; padId="+pad.padId);
- }
-};
-
-pad.editRevisionLabel = function(rnum) {
- var i = pad.revisionList.length - rnum;
- var rev = pad.revisionList[i];
- $('#revisioninfo_'+rnum).html(
- '<p class="revlabelprompt">Enter a label for revision #'+rnum+' and press return.</p>'+
- '<input class="inputrevlabel"'+
- ' id="inputrevlabel'+rnum+'" type="text" />'
- );
- $('input#inputrevlabel'+rnum).val(rev.label).focus().select();
- pad.setOnEnterKey('#inputrevlabel'+rnum, function() {
- pad.saveRevisionLabel(rnum);
- });
-};
-
-pad.saveRevisionLabel = function(rnum) {
- var i = pad.revisionList.length - rnum;
- var rev = pad.revisionList[i];
- var newLabel = $('#inputrevlabel'+rnum).val();
- $.ajax({
- type: 'post',
- url: '/ep/pad/saverevisionlabel',
- data: {userId: pad.myUserInfo.userId,
- padId: pad.padId,
- revId: rev.id,
- newLabel: newLabel},
- success: success,
- error: error
- });
- function success(text) {
- pad.revisionList = JSON.parse(text);
- pad.renderRevisionList();
- pad.collabClient.sendClientMessage({
- type: 'revisionLabel',
- revisionList: pad.revisionList,
- savedBy: pad.myUserInfo.name,
- newLabel: newLabel
- });
- }
- function error(e) {
- alert("Oops! There was an error saving that revision label. Please try again later.");
- }
-};
-
-//----------------------------------------------------------------
-// Feedback form.
-//----------------------------------------------------------------
-pad.submitfeedback = function() {
- var feedback = $('#feedbackarea').val();
- $('#feedbackarea').val('');
- $.ajax({
- type: 'post',
- url: '/ep/pad/feedback',
- data: {feedback: feedback, padId: pad.padId, username: pad.myUserInfo.name},
- success: success,
- error: error
- });
-
- $('#feedbackresult #feedbackemail').html('feedback'+'@'+'etherpad'+'.com');
- $('#feedbackbox').fadeOut('fast', function() {
- $('#feedbackresult').fadeIn('slow', function() {
- setTimeout(function() {
- $('#feedbackresult').fadeOut('slow', function() {
- $('#feedbackbox').fadeIn('fast');
- });
- }, 10000);
- });
- });
-
- function success(msg) {};
- function error(e) {
- alert("Oops! There was an error submitting the feedback. Please try again later.");
- }
-};
-
-//----------------------------------------------------------------
-// UA Display
-//----------------------------------------------------------------
-
-pad.uaDisplay = function(ua) {
- var m;
-
- function clean(a) {
- var maxlen = 16;
- a = a.replace(/[^a-zA-Z0-9\.]/g, '');
- if (a.length > maxlen) {
- a = a.substr(0,maxlen);
- }
- return a;
- }
-
- function checkver(name) {
- var m = ua.match(RegExp(name + '\\/([\\d\\.]+)'));
- if (m && m.length > 1) {
- return clean(name+m[1]);
- }
- return null;
- }
-
- // firefox
- if (checkver('Firefox')) { return checkver('Firefox'); }
-
- // misc browsers, including IE
- m = ua.match(/compatible; ([^;]+);/);
- if (m && m.length > 1) {
- return clean(m[1]);
- }
-
- // iphone
- if (ua.match(/\(iPhone;/)) {
- return 'iPhone';
- }
-
- // chrome
- if (checkver('Chrome')) { return checkver('Chrome'); }
-
- // safari
- m = ua.match(/Safari\/[\d\.]+/);
- if (m) {
- var v = '?';
- m = ua.match(/Version\/([\d\.]+)/);
- if (m && m.length > 1) {
- v = m[1];
- }
- return clean('Safari'+v);
- }
-
- // everything else
- var x = ua.split(' ')[0];
- return clean(x);
-};
-
-//----------------------------------------------------------------
-// invitemoreClick
-//----------------------------------------------------------------
-
-pad.invitemoreShow = function() {
- $('#invitemorelink').hide();
- $('#inviteinstructions').fadeIn('fast');
- $('#invite_email').focus();
-};
-
-pad.invitemoreHide = function() {
- $('#inviteinstructions').fadeOut('fast');
- $('#invitemorelink').show();
-};
-
-pad.invitemoreSendEmail = function() {
- function msg(m) {
- $('#invite_email_status').hide().html(m).fadeIn('fast');
- }
- var email = $('#invite_email').val();
- if (!pad.validEmail(email)) {
- msg("That doesn't look like a valid email address.");
- return;
- }
- $('#invite_email_submit').attr('disabled', true).val('Sending...');
- $.ajax({
- type: 'post',
- url: '/ep/pad/emailinvite',
- data: {email: email,
- padId: pad.padId,
- username: (pad.myUserInfo.name || "someone")
- },
- success: function() {
- $('#invite_email').val('');
- msg("Email sent to "+email+".");
- $('#invite_email_submit').val('Send').removeAttr('disabled');
- },
- error: function() {
- msg("Oops! There was an error sending the invite. Please try again later.");
- $('#invite_email_submit').val('Send').removeAttr('disabled');
- }
- });
-};
-
-pad.validEmail = function(x) {
- return (x.length > 0 &&
- x.match(/^[\w\.\_\+\-]+\@[\w\_\-]+\.[\w\_\-\.]+$/));
-};
-
-/*
-pad.getQueryParam = function(name) {
- var params = {};
- var query = window.location.search.substr(1);
- var parts = query.split('&');
- for (var i = 0; i < parts.length; i++) {
- var subparts = parts[i].split('=');
- if (subparts.length == 2) {
- params[subparts[0]] = subparts[1];
- }
- }
- return params[name];
-};
-*/
-
-pad.timediff = function(d) {
- function format(n, word) {
- n = Math.round(n);
- return ('' + n + ' ' + word + (n != 1 ? 's' : '') + ' ago');
- }
- d = (+(new Date) - (+d) - pad.clientTimeOffset) / 1000;
- if (d < 60) { return format(d, 'second'); }
- d /= 60;
- if (d < 60) { return format(d, 'minute'); }
- d /= 60;
- if (d < 24) { return format(d, 'hour'); }
- d /= 24;
- return format(d, 'day');
-};
-
-//----------------------------------------------------------------
-
-pad.onClientMessage = function(m) {
- if (m.type == 'newRevisionList') {
- pad.revisionList = m.revisionList;
- pad.notify(pad.escapeHtml(m.savedBy) + " saved a new revision.");
- pad.renderRevisionList();
- }
- if (m.type == 'revisionLabel') {
- pad.revisionList = m.revisionList;
- pad.notify(pad.escapeHtml(m.savedBy) + ' labeled a revision, "'+pad.escapeHtml(m.newLabel)+'".');
- pad.renderRevisionList();
- }
- if (m.type == 'chat') {
- pad.receiveChat(m);
- }
- if (m.type == 'padtitle') {
- pad.title = m.title;
- pad.renderPadTitle();
- if (m.changedBy) {
- pad.notify(pad.escapeHtml(m.changedBy) + ' changed the pad title.');
- }
- }
- if (m.type == 'padpassword') {
- pad.password = m.password;
- pad.renderPadTitle();
- if (m.changedBy) {
- pad.notify(pad.escapeHtml(m.changedBy) + (
- m.password ? ' changed the pad password.' : ' removed password protection from this pad.'));
- }
- }
-};
-
-pad.onServerMessage = function(m) {
- if (m.type == 'NOTICE') {
- if (m.text) {
- $('#servermsg').hide().addClass('hidden');
- $('#servermsgdate').html((new Date()).toString());
- $('#servermsgtext').html(m.text);
- $('#servermsg').removeClass('hidden').fadeIn('fast', function() { pad.resizePage(); });
- pad.notify("Server Notice");
- }
- if (m.js) {
- eval(m.js);
- }
- }
-};
-
-pad.hideTopMsg = function(mn) {
- var x = $('#'+mn+'msg');
- x.fadeOut('fast', function() {
- x.addClass('hidden');
- pad.resizePage();
- });
-};
-
-//----------------------------------------------------------------
-
-pad.isSideBoxVisible = function(paneName) {
- var head = $('#head'+paneName);
- var box = $('#'+paneName);
- return head.hasClass('sh_uncollapsed');
-};
-
-pad.showSideBox = function(paneName) {
- var head = $('#head'+paneName);
- var box = $('#'+paneName);
- head.removeClass('sh_collapsed').addClass('sh_uncollapsed');
- box.fadeIn('fast', function() {});
- pad.sideBoxVisibility[paneName] = true;
- pad.saveCookie();
- if (paneName == "chatbox") {
- pad.onShowChatBox();
- }
-};
-
-pad.hideSideBox = function(paneName) {
- var head = $('#head'+paneName);
- var box = $('#'+paneName);
- box.fadeOut('fast', function() {
- head.removeClass('sh_uncollapsed').addClass('sh_collapsed');
- pad.sideBoxVisibility[paneName] = false;
- pad.saveCookie();
- });
-};
-
-//----------------------------------------------------------------
-
-pad.escapeHtml = function(x) {
- return x.replace(/\</g, '&lt;').replace(/\>/g, '&gt;');
-};
-
-//----------------------------------------------------------------
-// Chat
-//----------------------------------------------------------------
-
-pad.initChat = function() {
- pad.setOnEnterKey('#chatinput', function() {
- pad.sendChat();
- });
- pad.chatUserNums = {};
- pad.lastChatUserNum = 0;
- pad.numUnreadChatMessages = 0;
- pad.initChatHistory();
-};
-
-pad.sendChat = function() {
- var lineText = $('#chatinput').val();
- $('#chatinput').val('').focus();
- var msg = {
- type: 'chat',
- userId: pad.myUserInfo.userId,
- lineText: lineText
- };
- pad.collabClient.sendClientMessage(msg);
- pad.receiveChat(msg);
-};
-
-pad.updateChatHistoryForUser = function(userInfo) {
- if (!(pad.chatUserNums && pad.users)) {
- return;
- }
- var userNum = pad.chatUserNums[userInfo.userId];
- var bgcolor = '#fff';
- if (pad.users[userInfo.userId]) {
- // only color the chat if user is on the pad.
- bgcolor = clientVars.colorPalette[userInfo.colorId];
- }
- var name = pad.escapeHtml(pad.getUserDisplayName(userInfo));
- $('.chatusermessage'+userNum).css('background-color', bgcolor);
- $('.chatusername'+userNum).html(name);
-};
-
-pad.receiveChat = function(msg, quick) {
- var userInfo = pad.users[msg.userId];
- if (!userInfo) { return; }
-
- if (!pad.chatUserNums[userInfo.userId]) {
- pad.lastChatUserNum++;
- pad.chatUserNums[userInfo.userId] = pad.lastChatUserNum;
- userNum = pad.lastChatUserNum;
- }
- var userNum = pad.chatUserNums[userInfo.userId];
-
- pad.renderChatLine(userNum, '.', +(new Date), msg.lineText);
- pad.updateChatHistoryForUser(userInfo);
- pad.notifyNewChatMessage(userInfo, msg);
-};
-
-pad.renderChatLine = function(userNum, name, t, lineText) {
- function chatTime() {
- var x = '';
- var d = new Date(t);
- x += (d.getHours() < 10) ? ('0'+d.getHours()) : d.getHours();
- x += ':';
- x += (d.getMinutes() < 10) ? ('0'+d.getMinutes()) : d.getMinutes();
- return x;
- }
- var displayName;
- if (!name) {
- name = "unnamed";
- }
- $('#chatmessages').append([
- '<div class="chatmessage chatusermessage'+userNum+'">',
- '<span class="chatname chatusername'+userNum+'">'+pad.escapeHtml(name)+'</span>',
- '<span class="chattime">&nbsp;(', chatTime(t), ')</span>:&nbsp;',
- '<span class="chatline">', pad.escapeHtml(lineText), '</span>',
- '</div>'
- ].join(''));
-};
-
-pad.initChatHistory = function() {
- var chatHistory = clientVars.chatHistory;
- if (!chatHistory) { return; }
- for (var i = 0; i < chatHistory.length; i++) {
- var l = chatHistory[i];
- pad.renderChatLine(0, l.name, l.time, l.lineText);
- }
- pad.scrollChatBox();
-};
-
-pad.onShowChatBox = function() {
- $('#chatheadname').html('Chat');
- $('#headchatbox').removeClass('sh_hilited');
- pad.numUnreadChatMessages = 0;
- pad.scrollChatBox();
-};
-
-pad.scrollChatBox = function() {
- var messageBox = $('#chatmessages').get(0);
- messageBox.scrollTop = messageBox.scrollHeight;
-};
-
-pad.notifyNewChatMessage = function(userInfo, msg) {
- if (userInfo.userId != pad.myUserInfo.userId) {
- var name = pad.escapeHtml(pad.getUserDisplayName(userInfo));
- var text;
- if (msg.lineText.length <= 40) {
- text = msg.lineText;
- } else {
- text = (msg.lineText.substr(0, 37) + '...');
- }
- text = pad.escapeHtml(text);
- pad.notify("<i>"+name+" says</i>: "+text);
- }
- if ($('#headchatbox').hasClass('sh_collapsed')) {
- pad.numUnreadChatMessages++;
- var pluralS = (pad.numUnreadChatMessages > 1 ? 's' : '');
- $('#chatheadname').html('Chat <b>('+pad.numUnreadChatMessages+' unread message'+pluralS+')</b>');
- if (!$('#headchatbox').hasClass('sh_hilited')) {
- $('#headchatbox').addClass('sh_hilited');
- }
- }
- pad.scrollChatBox();
-};
-
-//----------------------------------------------------------------
-// Connection trouble
-//----------------------------------------------------------------
-
-pad.onConnectionTrouble = function(troubleStatus) {
- if (troubleStatus == "OK") {
- $('#savenow').removeAttr('disabled');
- pad.displayConnectionStatus('connected');
- if (pad.experiencingConnectionTrouble) {
- pad.notify("Connection re-established!");
- pad.experiencingConnectionTrouble = false;
- }
- } else if (troubleStatus == "SLOW") {
- $('#savenow').attr('disabled', true);
- pad.displayConnectionStatus('connecting');
- if (!pad.experiencingConnectionTrouble) {
- pad.experiencingConnectionTrouble = true;
- pad.notify("The network seems slow. Waiting to hear back from the server...", true);
- }
- }
-};
-
-//----------------------------------------------------------------
-// Connection Status Display
-//----------------------------------------------------------------
-
-pad.displayConnectionStatus = function(status) {
- var cs = $('#connectionstatus');
- cs.attr('class', status);
- if (status == "connecting") { cs.html("Connecting..."); }
- else if (status == "connected") { cs.html("Connected"); }
- else if (status == "disconnected") { cs.html("Disconnected"); }
- else { cs.html(status+'?'); }
-};
-
-//----------------------------------------------------------------
-
-pad.asyncSendDiagnosticInfo = function() {
- pad.diagnosticInfo.collabDiagnosticInfo = pad.collabClient.getDiagnosticInfo();
- setTimeout(function() {
- $.ajax({
- type: 'post',
- url: '/ep/pad/connection-diagnostic-info',
- data: {padId: pad.padId, diagnosticInfo: JSON.stringify(pad.diagnosticInfo)},
- success: function() {},
- error: function() {}
- });
- });
-};
-
-//----------------------------------------------------------------
-// Modal Dialogs
-//----------------------------------------------------------------
-
-pad.repositionModals = function() {
- var overlayNode = $("#modaloverlay");
- var pageHeight = pad.getCurrentPageHeight();
- overlayNode.height(pageHeight);
-
- var dialogNode = $("#modaldialog");
- var dialogHeight = dialogNode.outerHeight();
- dialogNode.css('top', Math.round((pageHeight - dialogHeight)/2)+"px");
-}
-
-//----------------------------------------------------------------
-// Import/Export
-//----------------------------------------------------------------
-
-pad.importClearTimeout = function() {
- if (pad.currentImport) {
- clearTimeout(pad.currentImport);
- delete pad.currentImport;
- }
-}
-
-pad.importApplicationSuccessful = function(data, textStatus) {
- if (data.substr(0, 2) == "ok") {
- if ($('.importmessage').is(':visible')) {
- $('.importmessage').hide();
- }
- $('#importmessagesuccess').html('<strong style="color: green">Import successful!</strong>').show();
- $('#importformfilediv').hide();
- setTimeout(function() {
- $('#importmessagesuccess').fadeOut("slow", function() { $('#importformfilediv').show() });
- }, 4000);
- } else if (data.substr(0, 4) == "fail") {
- pad.importErrorMessage("Couldn't update pad contents. Do you have \"cookies\" enabled in your web browser?");
- } else if (data.substr(0, 4) == "msg:") {
- pad.importErrorMessage(data.substr(4));
- }
- pad.importDone();
-}
-
-pad.importSuccessful = function(token) {
- $.ajax({
- type: 'post',
- url: '/ep/pad/impexp/import2',
- data: {token: token, padId: pad.padId},
- success: pad.importApplicationSuccessful,
- error: pad.importApplicationFailed,
- timeout: 25000 // 20 second timeout.
- });
- pad.addImportFrames();
-}
-
-pad.importApplicationFailed = function(xhr, textStatus, errorThrown) {
- pad.importErrorMessage("Error during conversion.");
- pad.importDone();
-}
-
-pad.importFailed = function(msg) {
- pad.importErrorMessage(msg);
- pad.importDone();
- pad.addImportFrames();
-}
-
-pad.importErrorMessage = function(msg) {
- function showError(fade) {
- $('#importmessagefail').html('<strong style="color: red">Import failed:</strong> '+
- (msg || 'Please try a different file.'))[(fade?"fadeIn":"show")]();
- }
-
- if ($('.importmessage').is(':visible')) {
- $('#importmessagesuccess').fadeOut("fast");
- $('#importmessagefail').fadeOut("fast", function() { showError(true) });
- } else {
- showError();
- }
-}
-
-pad.fileInputUpdated = function() {
- $('#importformfilediv').addClass('importformenabled');
- $('#importsubmitinput').removeAttr('disabled');
- $('#importmessagefail').fadeOut("fast");
- $('#importarrow').show();
- $('#importarrow').animate({paddingLeft:"0px"}, 500)
- .animate({paddingLeft:"10px"}, 150, 'swing')
- .animate({paddingLeft:"0px"}, 150, 'swing')
- .animate({paddingLeft:"10px"}, 150, 'swing')
- .animate({paddingLeft:"0px"}, 150, 'swing')
- .animate({paddingLeft:"10px"}, 150, 'swing')
- .animate({paddingLeft:"0px"}, 150, 'swing');
-}
-
-pad.importDone = function() {
- $('#importsubmitinput').removeAttr('disabled').val("Import Now");
- setTimeout(function() { $('#importfileinput').removeAttr('disabled'); }, 0);
- $('#importstatusball').hide();
- pad.importClearTimeout();
-}
-
-pad.fileInputSubmit = function() {
- $('#importmessagefail').fadeOut("fast");
- var ret = confirm("Importing a file will overwrite your existing document,"+
- " and cannot be undone. If you want to keep your current"+
- " document, download it or save a revision.\n\n"+
- "Are you sure you want to proceed?");
- if (ret) {
- pad.currentImport = setTimeout(function() {
- if (! pad.currentImport) {
- return;
- }
- delete pad.currentImport;
- pad.importFailed("Request timed out.");
- }, 25000); // 20 second timeout.
- $('#importsubmitinput').attr({disabled: true}).val("Importing...");
- setTimeout(function() { $('#importfileinput').attr({disabled: true}) }, 0);
- $('#importarrow').stop(true, true).hide();
- $('#importstatusball').show();
- }
- return ret;
-}
-
-pad.cantExport = function() {
- var type = $(this);
- if (type.hasClass("exporthrefpdf")) {
- type = "PDF";
- } else if (type.hasClass("exporthrefdoc")) {
- type = "Microsoft Word";
- } else if (type.hasClass("exporthrefodt")) {
- type = "OpenDocument";
- } else {
- type = "this file";
- }
- alert("Exporting as "+type+" format is disabled. Please contact your"+
- " system administrator for details.");
- return false;
-}
-
-// pad.exportDoNothingClickHandler = function() { return false; }
-// pad.exportDoLongClick = function() {
-// if ($(this).hasClass('exporthrefdoc')) {
-// pad.exportStartLong('doc');
-// } else if ($(this).hasClass('exporthrefpdf')) {
-// pad.exportStartLong('pdf');
-// } else {
-// return false;
-// }
-// setTimeout(pad.exportDisableOffice, 0);
-// return true;
-// }
-//
-// pad.exportDisableOffice = function() {
-// $('.requiresoffice').unbind('click', pad.exportDoLongClick);
-// $('.requiresoffice').click(pad.exportDoNothingClickHandler);
-// $('.requiresoffice').addClass('disabledexport');
-// }
-//
-// pad.exportEnableOffice = function() {
-// $('.exportspinner').hide();
-// $('.requiresoffice').removeClass('disabledexport');
-// $('.requiresoffice').unbind('click', pad.exportDoNothingClickHandler);
-// $('.requiresoffice').click(pad.exportDoLongClick);
-// }
-//
-// pad.exportMessage = function(msg, head) {
-// function showMessage(fade) {
-// head = head || '<strong style="color: red">Export failed:</strong> ';
-// msg = msg || 'Please try a different file type or try again later.';
-// $('#exportmessage').html(head+msg)[(fade?"fadeIn":"show")]();
-// }
-// if ($('#exportmessage').is(":visible")) {
-// $('#exportmessage').fadeOut("fast", function() { showMessage(true) });
-// } else {
-// showMessage();
-// }
-// }
-//
-// pad.exportDone = function(message) {
-// if (message == "ok") {
-// pad.exportMessage("downloading...", '<strong style="color: green">Conversion successful;</strong> ');
-// setTimeout(function() {
-// $('#exportmessage').fadeOut();
-// }, 4000);
-// } else if (message == "timeout") {
-// pad.exportMessage("Request timed out; please try a different file type or try again later.");
-// } else if (message == "nocookie") {
-// pad.exportMessage("Conversion in progress, please wait...", " ");
-// setTimeout(function() {
-// pad.exportDone("nocookie-delay");
-// }, 25000);
-// } else if (message == "nocookie-delay") {
-// pad.exportMessage("If your download hasn't started yet, then an error occurred; please try a different file type or try again later.", " ");
-// setTimeout(function() {
-// $('#exportmessage').fadeOut();
-// }, 10000);
-// } else {
-// pad.exportMessage("Error converting; please try a different file type or try again later.");
-// }
-// pad.exportEnableOffice();
-// if (! $.browser.opera) {
-// pad.addExportFrames();
-// }
-// }
-//
-// pad.exportHideMessages = function() {
-// $('#exportmessage').fadeOut();
-// }
-//
-// pad.exportStartLong = function(format) {
-// $('#exportspinner'+format).show();
-// $.ajax({
-// type: 'post',
-// url: '/ep/pad/impexp/exportsync',
-// data: { waiter: pad.exportSetCookie() },
-// success: function(data) { pad.exportDone(data); },
-// error: function(xhr, textStatus) { pad.exportDone(textStatus); },
-// timeout: 25000
-// });
-// }
-//
-// pad.exportSetCookie = function() {
-// var cookieValue = Math.round(Math.random()*1e20);
-// document.cookie = "EPexport="+cookieValue;
-//
-// if (!(document.cookie &&
-// (document.cookie.length > 0) &&
-// (document.cookie.indexOf('EPexport') >= 0))) {
-// return false;
-// }
-// return cookieValue;
-// }
-//
-// pad.addExportFrames = function() {
-// $('.exportframe').remove();
-// $('#importexport').append(
-// $('<iframe style="display: none;" name="exportofficeiframe" class="exportframe"></iframe>'));
-// $('#importexport').append(
-// $('<iframe style="display: none;" name="exportiframe" class="exportframe"></iframe>'));
-// }
-
-pad.addImportFrames = function() {
- $('.importframe').remove();
- $('#importexport').append(
- $('<iframe style="display: none;" name="importiframe" class="importframe"></iframe>'));
-}
-
-//----------------------------------------------------------------
-// Rich text
-//----------------------------------------------------------------
-
-pad.isTopToolbarEnabled = function() {
- return ! $("#toptoolbar").hasClass('disabledtoolbar');
-}
-
-pad.isBotToolbarEnabled = function() {
- return ! $("#bottoolbar").hasClass('disabledtoolbar');
-}
-
-pad.toolbarClick = function(which) {
- if (pad.isTopToolbarEnabled()) {
- pad.ace.execCommand(which);
- }
- pad.ace.focus();
-}
-
-//----------------------------------------------------------------
-// View bar
-//----------------------------------------------------------------
-
-pad.setViewZoom = function(percent) {
- if (! (percent >= 50 && percent <= 1000)) {
- // percent is out of sane range or NaN (which fails comparisons)
- return;
- }
-
- pad.viewZoom = percent;
- $("#viewzoommenu").val('z'+percent);
- pad.updateAceFontAndSize();
- pad.saveCookie(); // does nothing if we were called from init > initViewBar
-}
-
-pad.setViewFont = function(font) {
- pad.viewFont = font;
- $("#viewfontmenu").val(font);
- pad.updateAceFontAndSize();
- pad.saveCookie();
-}
-
-pad.updateAceFontAndSize = function() {
- var baseSize = 12;
- pad.ace.setProperty('textsize', Math.round(baseSize * pad.viewZoom / 100));
-
- var face = "sans-serif";
- if (pad.viewFont == 'code') {
- face = "monospace";
- }
- pad.ace.setProperty('textface', face);
-}
-
-//----------------------------------------------------------------
-// Pad title
-//----------------------------------------------------------------
-
-pad.renderPadTitle = function() {
- if (pad.title) {
- var theTitle = (pad.isEditingTitle ? "-" : pad.title);
-
- $("#padtitle").css('display', 'block');
-
- var padtitleWidth = $("#toptoolbar").width() - $("#toptoolbar .toptoolbarbutton:last").position().left - 80;
- $("#padtitle").css('width', padtitleWidth+"px");
-
- var shownLength = theTitle.length;
- $("#padtitletitle").html(pad.escapeHtml(theTitle));
-
- // while it wraps, shorten the displayed title
- while ($("#padtitle .editlink").offset().top > $("#padtitle .padtitlepad").offset().top +
- $("#padtitle .padtitlepad").height()) {
- shownLength--;
- $("#padtitletitle").html(pad.escapeHtml(theTitle.substring(0, shownLength)+"..."));
- }
-
- var titlePos = $("#padtitletitle").position();
- var titleHeight = $("#padtitletitle").height();
- var inputBox = $("#padtitleedit");
- var inputWidth = $("#toptoolbar").width() - titlePos.left - 70;
- inputBox.css({left: titlePos.left, top: titlePos.top, height: titleHeight,
- width: inputWidth});
- $("#toptoolbar .oklink").css({ top: 5, left: titlePos.left + inputWidth + 15 });
- }
- else {
- $("#padtitle").css('display', 'none');
- }
-
- if (clientVars.isProPad) {
- if (pad.password) {
- $("#passwordlock").attr('title','Change password...').get(0).className = 'passwordlocked';
- }
- else {
- $("#passwordlock").attr('title','Password protect...').get(0).className = 'passwordnone';
- }
- }
-};
-
-pad.editTitle = function() {
- $("#padtitleedit").val(pad.title).show().focus().select();
- $("#padtitle .oklink").show();
- $("#padtitle .editlink").hide();
-
- pad.isEditingTitle = true;
- pad.renderPadTitle();
-}
-
-pad.submitTitle = function(acceptChanges) {
- if (acceptChanges) {
- var newTitle = $("#padtitleedit").val();
- if (newTitle) {
- newTitle = newTitle.substring(0, 80);
- pad.title = newTitle;
-
- pad.collabClient.sendClientMessage({
- type: 'padtitle',
- title: newTitle,
- changedBy: pad.myUserInfo.name || "unnamed"
- });
- }
- }
-
- $("#padtitleedit").hide();
- $("#padtitle .oklink").hide();
- $("#padtitle .editlink").show();
-
- pad.isEditingTitle = false;
- pad.renderPadTitle();
-};
-
-pad.passwordClick = function() {
- var oldPassword = pad.password;
-
- var msg = (oldPassword ? "Enter a new password for this pad, or "+
- "make blank to remove password protection:" :
- "Choose a password that will be required to view this pad:");
-
- var result = window.prompt(msg, oldPassword || '');
- if ((typeof result) == "string") {
- pad.password = (result || null); // empty string --> null
- if (pad.password !== oldPassword) {
- pad.collabClient.sendClientMessage({
- type: 'padpassword',
- password: pad.password,
- changedBy: pad.myUserInfo.name || "unnamed"
- });
- pad.renderPadTitle();
- }
- }
- else {
- // user canceled
- }
-}; \ No newline at end of file
diff --git a/trunk/etherpad/src/static/js/store.js b/trunk/etherpad/src/static/js/store.js
deleted file mode 100644
index 549e52d..0000000
--- a/trunk/etherpad/src/static/js/store.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-
-store = {};
-
-$(document).ready(function() {
- if ($('#downloadpage').size() > 0) {
- $("#license_agree, #license_agree_label").click(function() {
- if ($("#license_agree").attr("checked")) {
- $("a.downloadbutton_disabled").removeClass("downloadbutton_disabled")
- .addClass("downloadbutton")
- .attr('href', '/ep/store/eepnet-download-nextsteps');
- } else {
- $("a.downloadbutton").removeClass("downloadbutton")
- .addClass("downloadbutton_disabled")
- .attr('href', 'javascript:void store.mustAgree()');
- }
- });
- }
-
- if ($('#eepnet_trial_signup_page').size() > 0) {
- store.eepnetTrial.init();
- }
-
-});
-
-store.mustAgree = function() {
- alert("You must first click 'Accept License' before downloading this software.");
-};
-
-//----------------------------------------------------------------
-// trial download page
-//----------------------------------------------------------------
-
-store.eepnetTrial = {};
-
-store.eepnetTrial.init = function() {
- $("#submit").attr("disabled", false);
- $("input.signupData").keydown(function() {
- $("#submit").attr("disabled", false);
- });
- $("input.signupData").change(function() {
- $("#submit").attr("disabled", false);
- });
-};
-
-store.eepnetTrial.handleError = function(msg) {
- $('#processingmsg').hide();
- $('#dlsignup').show();
- $("#errormsg").hide().html(msg).fadeIn("fast");
- var href = window.location.href;
- href = href.split("#")[0];
- window.location.href = (href + "#toph2");
- $('#submit').attr('disabled', false);
-};
-
-store.eepnetTrial.submit = function() {
-
- $("#errormsg").hide();
- $('#dlsignup').hide();
- $('#processingmsg').fadeIn('fast');
-
- // first stubmit to pad.spline.inf.fu-berlin.de...
- var data = {};
- $(".signupData").each(function() {
- data[$(this).attr("id")] = $(this).val();
- });
- data.industry = $('#industry').val();
-
- $('#submit').attr('disabled', true);
-
- $.ajax({
- type: 'post',
- url: '/ep/store/eepnet-eval-signup',
- data: data,
- success: success,
- error: error
- });
-
- function success(text) {
- var responseData = eval("("+text+")");
- if (responseData.error) {
- store.eepnetTrial.handleError(responseData.error);
- return;
- }
-
- store.eepnetTrial.submitWebToLead(responseData);
- }
-
- function error(e) {
- store.eepnetTrial.handleError("Oops! There was an error processing your request.");
- }
-};
-
-store.eepnetTrial.submitWebToLead = function(data) {
- for (k in data) {
- $('#wl_'+k).val(data[k]);
- }
- setTimeout(function() { $('#wlform').submit(); }, 50);
-};
-
-
diff --git a/trunk/etherpad/src/static/swf/vidplayer.swf b/trunk/etherpad/src/static/swf/vidplayer.swf
deleted file mode 100755
index a38a94e..0000000
--- a/trunk/etherpad/src/static/swf/vidplayer.swf
+++ /dev/null
Binary files differ
diff --git a/trunk/etherpad/src/templates/beta/signup.ejs b/trunk/etherpad/src/templates/beta/signup.ejs
deleted file mode 100644
index 5268a29..0000000
--- a/trunk/etherpad/src/templates/beta/signup.ejs
+++ /dev/null
@@ -1,63 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.includeJQuery() %>
-<% helpers.includeJs("etherpad.js") %>
-<% helpers.includeCss("beta.css") %>
-
-<div class="fpcontent">
- <div class="beta-signup">
-
- <h1 style="border: 0;">EtherPad Professional Edition</h1>
-
- <div class="right">
- <br/>
-
- <p>Want an account to keep track of all your team's pads?
- EtherPad Professional Edition
- gives you your own site to keep track
- of pads and control who gets to access what.</p>
-
-
- <form id="beta-signup-form" action="/ep/beta-account/signup"
- method="post">
-
- <% if (errorMsg) { %>
- <div id="error-msg">
- <%= errorMsg %>
- </div>
- <% } %>
-
- <p>Your Email:</p>
- <input type="text" name="email" id="email" />
- <br/>
- <button type="submit">Submit</button>
-
- </form>
-
- <p>Email <%= helpers.oemail("support") %> with questions or
- concerns.</p>
- </div>
-
- <div class="left">
-
- <img src="/static/img/account/betawarn.jpg"
- />
-
- </div>
-
- <%= helpers.clearFloats() %>
-
- </div>
-</div>
-
-
diff --git a/trunk/etherpad/src/templates/email/eepnet_purchase_receipt.ejs b/trunk/etherpad/src/templates/email/eepnet_purchase_receipt.ejs
deleted file mode 100644
index a83cd58..0000000
--- a/trunk/etherpad/src/templates/email/eepnet_purchase_receipt.ejs
+++ /dev/null
@@ -1,93 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %>Dear <%= cart.ownerName %>,
-
-Thank you for your purchase of EtherPad Private Network Edition. This is your receipt. Please keep this email for your records.
-
--- The EtherPad Staff
-
-<%
-function row(key, value) {
-%><%= key %>:
- <%= String(value).split("\n").join("\n ") %>
-<%
-}
-
-function $(cost) {
- return "US $"+dollars(cost);
-}
-%>
-
-License Information:
-
-<%
-row("Administrator Name", cart.ownerName)
-row("Organization Name", cart.orgName)
-row("Total Users", cart.userCount)
-%>
-
-Billing Information:
-
-<%
-var isUs = cart.billingCountry == "US";
-switch(cart.billingPurchaseType) {
- case "creditcard":
- row("Credit Card Number", obfuscateCC(cart.billingCCNumber));
- row("Expiration Date", cart.billingExpirationMonth+" / 20"+cart.billingExpirationYear);
- // falling through here intentional.
- case "invoice":
- row("Purchaser Name", cart.billingFirstName + " " + cart.billingLastName);
- row("Purchaser Address", cart.billingAddressLine1 + "\n" +
- (cart.billingAddressLine2 ? cart.billingAddressLine2 + "\n" : "") +
- cart.billingCity + ", " +
- (isUs?cart.billingState:cart.billingProvince) + "\n" +
- (isUs?cart.billingZipCode:cart.billingPostalCode)+
- (isUs?'':', '+cart.billingCountry));
- row("Invoice Number", cart.invoiceId);
- break;
- case "paypal":
- row("Paid Using", "PayPal");
- row("Invoice Number", cart.invoiceId);
-}
-%>
-
-Summary of Charges:
-
-<%
-row("Etherpad Private Network, "+cart.numUsers+" users", $(cart.baseCost));
-if (cart.couponProductPctDiscount) {
- row("Referral - "+cart.couponProductPctDiscount+"% savings",
- "-"+$(cart.productReferralDiscount));
-}
-if (cart.supportCost) {
- row("Support Contract, 1 year", $(cart.supportCost));
- if (cart.couponSupportPctDiscount) {
- row("Referral - "+cart.couponSupportPctDiscount+"% savings",
- "-"+$(cart.supportReferralDiscount));
- }
-}
-if (cart.freeUserCount) {
- row("Referral Bonus - "+cart.freeUserCount+" free user"+(cart.freeUserCount == 1 ? '' : "s"),
- "US$0.00");
-}
-%>-------------------------------------------------------------------------------
-<%
-var pctDiscount = cart.couponTotalPctDiscount;
-var hasSubtotal = pctDiscount > 0;
-
-if (hasSubtotal) {
- row("Subtotal", $(cart.subTotal));
- row("Referral - "+pctDiscount+"% savings", "-"+$(cart.totalReferralDiscount));
-}
-row("Total", $(cart.total));
-%> \ No newline at end of file
diff --git a/trunk/etherpad/src/templates/email/pro_beta_invite.ejs b/trunk/etherpad/src/templates/email/pro_beta_invite.ejs
deleted file mode 100644
index 162b443..0000000
--- a/trunk/etherpad/src/templates/email/pro_beta_invite.ejs
+++ /dev/null
@@ -1,23 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %>Dear <%= toAddr.split('@')[0] %>,
-
-<%= signupAgo %> you signed up for the EtherPad Beta. Now here's a link to activate your account immediately:
-
-<%= activationUrl %>
-
-Any problems or questions? Just respond to this email for help.
-
-Happy Collaborating!
-
-The EtherPad Team
diff --git a/trunk/etherpad/src/templates/email/pro_payment_failure.ejs b/trunk/etherpad/src/templates/email/pro_payment_failure.ejs
deleted file mode 100644
index 248a3dd..0000000
--- a/trunk/etherpad/src/templates/email/pro_payment_failure.ejs
+++ /dev/null
@@ -1,26 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %>Dear <%= fullName %>,
-
-Thank you for using EtherPad Professional. Your monthly billing cycle has ended, but we were unsuccessful in charging your account on file.
-
-<% if (billingError && billingError.length > 0) { %>
- The following error occurred:
-
- <%= billingError %>
-
-<% } %>If you do not update your payment information and pay the remaining balance of <%= balance %>, your account will be suspended on <%= suspensionDate %>.
-
-You may update your payment information here: <%= billingAdminLink %>
-
--- The EtherPad Staff
diff --git a/trunk/etherpad/src/templates/email/pro_payment_receipt.ejs b/trunk/etherpad/src/templates/email/pro_payment_receipt.ejs
deleted file mode 100644
index 175b06a..0000000
--- a/trunk/etherpad/src/templates/email/pro_payment_receipt.ejs
+++ /dev/null
@@ -1,55 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %>Dear <%= fullName %>,
-
-Thank you for using EtherPad Professional. Your monthly billing cycle has ended, and your account has been charged; this is your receipt. Please keep this email for your records.
-
--- The EtherPad Staff
-
-<%
-function row(key, value) {
-%><%= key %>:
- <%= String(value).split("\n").join("\n ") %>
-<%
-}
-
-function $(cost) {
- return "US $"+dollars(cost);
-}
-%>
-
-Billing Information:
-
-<%
-row("Name", fullName);
-row("Paid Using", paymentSummary);
-row("Expiration", expiration);
-row("Invoice Number", invoiceNumber);
-%>
-
-Summary of Charges:
-
-<%
-row("EtherPad Professional, "+numUsers+" users", $(cost));
-if (coupon) {
- var discount = [];
- if (coupon.pctDiscount) {
- discount.push(coupon.pctDiscount+"% savings");
- }
- if (coupon.freeUsers) {
- discount.push((coupon.freeUsers)+" free users");
- }
- discount = discount.join(" and ");
- %>
-This charge reflects your referral bonus of <%= discount %>.
-<% } %> \ No newline at end of file
diff --git a/trunk/etherpad/src/templates/framed/framedheader-pro.ejs b/trunk/etherpad/src/templates/framed/framedheader-pro.ejs
deleted file mode 100644
index fac9eee..0000000
--- a/trunk/etherpad/src/templates/framed/framedheader-pro.ejs
+++ /dev/null
@@ -1,76 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.addBodyClass("pro-withtopbar"); %>
-
-<div id="pro-topbar">
-
- <div id="pro-topbar-inner">
-
- <% if (account) { %>
- <div id="accountnav">
- <%= toHTML(account.email) %>
- <a href="/ep/account/sign-out">(sign out)</a>
- </div>
- <% } else { %>
- <% // TODO: eventually have sign-in link here. %>
- <% } %>
-
- <div id="org-name">
- <a href="/">
- <%= proDomainOrgName %>
- </a>
-
- <% if (isAnEtherpadAdmin) { %>
- <span style="color: #ff0; padding-left: 2em; font-weight: bold;">INVISIBLE ADMIN MODE</span>
- <% } %>
- </div>
-
- <div style="clear: both;"><!-- --></div>
-
- </div>
-</div>
-
-<% function renderProTopNav() {
- var links = [
- ['/', 'Home', 'home'],
- ['/ep/padlist/', 'Pads', 'padlist'],
- ['/ep/account/', 'My Account', 'account'],
- ];
- if (account && account.isAdmin) {
- links.push(['/ep/admin/', 'Admin', 'admin']);
- }
- var ul = UL();
- links.forEach(function(l) {
- var c = l[2];
- var selc = (request.path == l[0] || navSelection == c) ? " selected" : "";
- ul.push(LI({className: 'topnav_'+c+selc},
- A({href: request.scheme + '://'+request.host+l[0]}, l[1])));
- });
- return ul;
-} %>
-
- <%= pneTrackerHtml %>
-
-<div id="pro-topnav">
- <div id="pro-topnav-inner">
- <%= renderProTopNav() %>
- <%= helpers.clearFloats() %>
- </div>
-</div>
-
-<!--
-<div id="shuttingdown">
- <strong style="color:red">Note: EtherPad.com is shutting down March 31, 2010.</strong>
- <a href="http://<%= fullSuperdomain %>/ep/blog/posts/google-acquires-appjet">(more info)</a>
-</div>
--->
diff --git a/trunk/etherpad/src/templates/main/home.ejs b/trunk/etherpad/src/templates/main/home.ejs
deleted file mode 100644
index 495cf77..0000000
--- a/trunk/etherpad/src/templates/main/home.ejs
+++ /dev/null
@@ -1,58 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.setHtmlTitle("SplinePad [beta]: Open-Sourced!"); %>
-
-<% helpers.includeCss("home-opensource.css"); %>
-
-<div id="home">
- <div id="title">
- SplinePad
- </div>
-
- <div id="buttons">
- <a id="home-newpad" href="/ep/pad/newpad">
- Create new pad
- </a>
- <a id="home-newsite" href="ep/pro-signup/">
- Create team site
- </a>
- </div>
-
- <div id="tos">
- <h1>
- <b>Terms of service and Privacy notice</b>
- </h1>
-
- <p>
- <b>Privacy:</b> We guarantee that we will not intentionally hand
- over your data to any third party.
- </p>
-
- <p>
- <b>Terms:</b> By using splinepad, you certify to agree to the
- following terms of service: We are not responsible, and cannot
- be held liable for any loss or damages that may be caused by the
- result of our service.
- </p>
-
- <p>
- <b>In short:</b> We love the "Datenschutzgesetz" and if
- something is wrong, we didn't do it.
- </p>
-
- Have fun with splinepad.
- </div>
-
-</div>
-
-
diff --git a/trunk/etherpad/src/templates/pad/create_body_rafter.ejs b/trunk/etherpad/src/templates/pad/create_body_rafter.ejs
deleted file mode 100644
index 28252c7..0000000
--- a/trunk/etherpad/src/templates/pad/create_body_rafter.ejs
+++ /dev/null
@@ -1,23 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.setHtmlTitle("EtherPad: Create a new pad?"); %>
-
-<div id="createpadpage" class="fpcontent">
-
- <p><tt>http://<%= request.host %>/<%= toHTML(padId) %></tt></p>
-
- <p><strong>There is no EtherPad document here.</strong></p>
-
- <p style="color:red">Creation of new free pads is permanently disabled as part of EtherPad's acquisition by Google. <a href="http://<%= fullSuperdomain %>/ep/blog/posts/google-acquires-appjet">Read more.</a></p>
-
-</div>
diff --git a/trunk/etherpad/src/templates/pad/pad_body.ejs b/trunk/etherpad/src/templates/pad/pad_body.ejs
deleted file mode 100644
index d932cd6..0000000
--- a/trunk/etherpad/src/templates/pad/pad_body.ejs
+++ /dev/null
@@ -1,69 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><%
- var padIdHtml = toHTML(request.url.split("?", 1)[0]);
-%>
-
-<% helpers.setHtmlTitle("EtherPad: "+toHTML(proTitle || request.path.substr(1))); %>
-<% helpers.setBodyId("padbody") %>
-<% helpers.addBodyClass(bodyClass) %>
-<% helpers.includeCss("pad.css") %>
-<% helpers.includeJs("undo-xpopup.js") %>
-<% helpers.includeCometJs() %>
-<% helpers.includeJQuery(); %>
-<% helpers.includeJs("json2.js") %>
-<% helpers.includeJs("ace.js") %>
-<% helpers.includeJs("collab_client.js") %>
-<% helpers.includeJs("pad.js") %>
-<% helpers.suppressGA() %>
-<% helpers.setRobotsPolicy({index: false, follow: false}) %>
-
-<div id="padpage">
-
-<div id="modaloverlay">
- <div id="modaldialog">
- <div id="dialogtopbar">Foo.</div>
- <table id="dialogcontenttable" cellpadding="0" cellspacing="0" border="0"><tr>
- <td id="dialogcontent">This is a modal dialog!</td>
- </tr></table>
- </div>
-</div>
-<table id="padoutertable" cellpadding="0" cellspacing="0" border="0">
-<tr id="pot_toptr">
- <td id="pot_shadlefttopseg" class="potshad">&nbsp;</td>
- <td id="pot_top">
- <a id="headhomelink" href="/">EtherPad</a>
- <div id="headurl">
- <label for="shareurl">Share this URL:</label>
- &nbsp;<span id="shareurl"><%= padIdHtml %></span>
- </div>
- <a id="widthlink" href="javascript: void pad.toggleFullWidth()">M</a>
- <a id="newpadlink" href="javascript:void pad.newPad()"
- title="Create and open a new pad in a new window">New Pad</a>
- </td>
- <td id="pot_shadrighttopseg" class="potshad">&nbsp;</td>
-</tr>
-
-<tr>
- <td id="pot_shadleft" class="potshad"><div><!-- --></div></td>
- <td id="pot_main">
- <div id="padcontent">
- <%= contentHtml %>
- </div><!-- /padcontent -->
- </td>
- <td id="pot_shadright" class="potshad"><div><!-- --></div></td>
-</tr>
-
-</table><!-- /padoutertable -->
-
-</div><!-- /padpage -->
diff --git a/trunk/etherpad/src/templates/pad/pad_download_link.ejs b/trunk/etherpad/src/templates/pad/pad_download_link.ejs
deleted file mode 100644
index e05d7d0..0000000
--- a/trunk/etherpad/src/templates/pad/pad_download_link.ejs
+++ /dev/null
@@ -1,27 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><%
-
-var host = request.host;
-helpers.addToHead('<meta http-equiv="refresh" content="0;url=http://'+host+'/'+padId+'" />');
-
-%>
-
-<div id="refreshpage">
- <h1>Etherpad</h1>
-
- <p>This pad document, <a href="http://<%= host %>/<%= padId %>"><%= padId %></a>, is stored on <a href="http://<%= host %>"><%= host %></a>. Please click the link below to access this pad.</p>
-
- <a style="size: 200%; text-align: center;" href="http://<%= host %>/<%= padId %>">http://<%= host %>/<%= padId %></a>
-
-</div> \ No newline at end of file
diff --git a/trunk/etherpad/src/templates/pad/padslider_body.ejs b/trunk/etherpad/src/templates/pad/padslider_body.ejs
deleted file mode 100644
index 51a9e84..0000000
--- a/trunk/etherpad/src/templates/pad/padslider_body.ejs
+++ /dev/null
@@ -1,41 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><%
- helpers.setHtmlTitle(toHTML("Time Slider"));
- helpers.setBodyId("padsliderbody");
- helpers.includeCss("etherpad.css");
- //helpers.includeCss("jqueryui/theme/ui.all.css");
- helpers.setRobotsPolicy({index: false, follow: false});
- helpers.includeJQuery();
- //helpers.includeJs("jquery-ui-slider-1.5.3.js");
- helpers.includeJs("json2.js");
- helpers.includeJs("timeslider.js");
-
- function dfmt(t) {
- var d = new Date(t);
- return d.toString();
- }
-%>
-
-<!-- <div id="sliderui"></div> -->
-<p>Powered by <a href="/">EtherPad</a>.</p><br />
-<div id="controls">
-<a href="<%= request.url %>#" class="prev">prev</a> /
-<a href="<%= request.url %>#" class="next">next</a> &nbsp; &nbsp;
-<a href="<%= request.url %>#" class="play">play</a> /
-<a href="<%= request.url %>#" class="stop">stop</a> &nbsp; &nbsp;
-seek to #<input class="entry" type="text" size="6"/>
-<div id="currevdisplay"><span class="min">0</span> --- <span class="cur">0</span> --- <span class="max">0</span></div>
-</div>
-
-<div id="stuff">Loading...</div>
diff --git a/trunk/etherpad/src/templates/pad/total_users_exceeded.ejs b/trunk/etherpad/src/templates/pad/total_users_exceeded.ejs
deleted file mode 100644
index 7ac7e1b..0000000
--- a/trunk/etherpad/src/templates/pad/total_users_exceeded.ejs
+++ /dev/null
@@ -1,29 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><div class="fpcontent"
- style="font-family: Verdana, sans-serif; margin-top: 2em; border: 1px solid #ccc; padding: 1em; background: #eee;">
-
- <h1>EtherPad Server Is Full</h1>
-
- <p>Sorry, this EtherPad server is only licensed to service
- <%= userQuota %> active users
- within a <%= activeUserWindowHours %>-hour period,
- and that quota is currently full.</p>
-
- <p>Please contact your server administrator and ask him or her to
- purchase a license with additional users.</p>
-
- <a href="/">&laquo; Home</a>
-
-</div>
-
diff --git a/trunk/etherpad/src/templates/pro/account/create-admin-account.ejs b/trunk/etherpad/src/templates/pro/account/create-admin-account.ejs
deleted file mode 100644
index 2a6c9f8..0000000
--- a/trunk/etherpad/src/templates/pro/account/create-admin-account.ejs
+++ /dev/null
@@ -1,37 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.includeCss("pro/account.css") %>
-
-<div class="fpcontent">
- <div class="account-container">
-
- <h3>Welcome to your own EtherPad server!</h3>
-
- <p>To get started, please create an administrator account. This
- account will also be the primary admin contact for this
- system.</p>
-
- <%= errorDiv() %>
-
- <%= renderAccountForm('create-admin-account', [
- {title: "Create Admin Account"},
- {text: "fullName", label: "Full Name:"},
- {text: "email", label: "Email:"},
- {password: "password", label: "Password:"},
- {password: "passwordConfirm", label: "Confirm Password:"},
- {submit: "Create Account"}
- ]) %>
-
- </div>
-</div>
-
diff --git a/trunk/etherpad/src/templates/pro/account/global-multi-domain-recover-email.ejs b/trunk/etherpad/src/templates/pro/account/global-multi-domain-recover-email.ejs
deleted file mode 100644
index d2eb4de..0000000
--- a/trunk/etherpad/src/templates/pro/account/global-multi-domain-recover-email.ejs
+++ /dev/null
@@ -1,27 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %>
-Dear <%= accountList[0].fullName %>,
-
-We received a request to recover the EtherPad password for "<%=
-email %>. We found multiple accounts linked to this email address.
-Please choose one of the following URLs to proceed with recovering the
-password for that EtherPad site:
-
-<% for (var i = 0; i < accountList.length; i++) { %>
-<%= recoverLink(accountList[i], domainList[i]) %>
-<% } %>
-
---
-If you did not request a password reset, simply ignore this email.
-
diff --git a/trunk/etherpad/src/templates/pro/account/guest-knock.ejs b/trunk/etherpad/src/templates/pro/account/guest-knock.ejs
deleted file mode 100644
index 44c69c0..0000000
--- a/trunk/etherpad/src/templates/pro/account/guest-knock.ejs
+++ /dev/null
@@ -1,27 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.includeJQuery() %>
-<% helpers.includeJs("pro/guest-knock-client.js") %>
-<% helpers.includeCss("pro/account.css") %>
-
-<div id="guest-knock-box">
- <p>
- <img src="/static/img/misc/status-ball.gif">
- Waiting for approval...
- </p>
-</div>
-
-<div id="guest-knock-denied">
- Access Denied.
-</div>
-
diff --git a/trunk/etherpad/src/templates/pro/account/signin-guest.ejs b/trunk/etherpad/src/templates/pro/account/signin-guest.ejs
deleted file mode 100644
index 621c381..0000000
--- a/trunk/etherpad/src/templates/pro/account/signin-guest.ejs
+++ /dev/null
@@ -1,51 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.includeCss("pro/account.css") %>
-<% helpers.includeJQuery() %>
-<% helpers.includeJs("pro/signin-client.js") %>
-<% helpers.setHtmlTitle("EtherPad: Sign In") %>
-
-<div class="fpcontent">
- <div class="account-container">
-
- <form id="guest-signin-form"
- action="<%= request.path + '?' + request.query %>" method="post"
- style="border: 1px solid #5a5; background: #efe; padding: 1em;">
-
- <div style="font-weight: bold;">Guest Sign In:</div>
-
- <% if (errorMessage) { %>
- <div style="margin: 1em 0; padding: 1em; border: 1px solid red; background: #fee;">
- <%= errorMessage %>
- </div>
- <% } %>
-
- <p>Enter your name to be displayed to other users:</p>
- <input id="guestDisplayName" type="text" name="guestDisplayName" value="<%= guestName
- %>" />
- <input type="hidden" name="localPadId" value="<%= localPadId %>" />
-
- <input type="submit" value="Request Access" />
-
- </form>
-
- <form id="account-signin-choice"
- method="get"
- action="/ep/account/sign-in">
- <input type="hidden" name="guest" value="1" />
- <input type="hidden" name="padId" value="<%= toHTML(localPadId) %>" />
- Account holders: <button>Sign in</button>
- </form>
- </div>
-</div>
-
diff --git a/trunk/etherpad/src/templates/pro/admin/admin.ejs b/trunk/etherpad/src/templates/pro/admin/admin.ejs
deleted file mode 100644
index f8e1562..0000000
--- a/trunk/etherpad/src/templates/pro/admin/admin.ejs
+++ /dev/null
@@ -1,15 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %>
-Please select an option from the left.
-
diff --git a/trunk/etherpad/src/templates/pro/admin/billing-invoices.ejs b/trunk/etherpad/src/templates/pro/admin/billing-invoices.ejs
deleted file mode 100644
index a3a17d8..0000000
--- a/trunk/etherpad/src/templates/pro/admin/billing-invoices.ejs
+++ /dev/null
@@ -1,45 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><%
- helpers.includeCss('store/ondemand-billing.css');
-%>
-
-<%
-function displayInvoice(invoice) { %>
- <tr>
- <td><%= formatDate(invoice.time) %></td>
- <td><%= invoice.id %></td>
- <td><%= invoice.status == 'paid' ? "Paid" : (invoice.status == 'pending' ? "<strong>Pending</strong>" : (invoice.status == 'refunded' ? "<em>Refunded</em>" : invoice.status)) %></td>
- <td><%= invoice.users %></td>
- <td>US $<%= dollars(centsToDollars(invoice.amt)) %></td>
- <td><a href="<%= request.path %>?id=<%= invoice.id %>">View</a></td>
- </tr>
-<% } %>
-
-<h3 class="top">Past Invoices</h3>
-
-<% if (invoices.length == 0) { %>
- <p class="informational">No old invoices.</p>
-<% } else { %>
- <table class="invoicelist">
- <tr>
- <th>Date</th>
- <th>Invoice Number</th>
- <th>Status</th>
- <th>Number of users</th>
- <th>Cost</th>
- <th>&nbsp;</th>
- </tr>
- <% invoices.forEach(displayInvoice); %>
- </table>
-<% } %> \ No newline at end of file
diff --git a/trunk/etherpad/src/templates/pro/admin/manage-billing.ejs b/trunk/etherpad/src/templates/pro/admin/manage-billing.ejs
deleted file mode 100644
index 514d943..0000000
--- a/trunk/etherpad/src/templates/pro/admin/manage-billing.ejs
+++ /dev/null
@@ -1,35 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %>
-<%
- helpers.includeCss('store/ondemand-billing.css');
-%>
-
-<% function fmtdate(d) {
- if (!d) {
- return "Never";
- } else {
- return d.toString().split(' ').slice(0,5).join(' ');
- }
-}
-
-function plural(amt) {
- return (amt == 1 ? "" : "s");
-}
-
-%>
-
-<h3 class="top">Payment Information</h3>
-
-<p>EtherPad Professional will be discontinued on <%= helpers.rafterTerminationDate() %>. No further payments will be collected.</p>
-<p><a href="http://pad.spline.inf.fu-berlin.de<%= helpers.rafterBlogUrl() %>">Read more</a>.</p>
diff --git a/trunk/etherpad/src/templates/pro/admin/pne-config.ejs b/trunk/etherpad/src/templates/pro/admin/pne-config.ejs
deleted file mode 100644
index 56fe68d..0000000
--- a/trunk/etherpad/src/templates/pro/admin/pne-config.ejs
+++ /dev/null
@@ -1,33 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><h3 class="top">Private Server Configuration</h3>
-
-<p>Your private EtherPad server can be configured using either command-line arguments (of the
-form --<i>argName</i>=<i>value</i>), or by adding the options to the file
-<tt>data/etherpad.properties</tt>.</p>
-
-<p>Learn more about server options in the <a href="/ep/pne-server-manual/">PNE Server Manual</a>.</p>
-
-<h3>Current Config Values</h3>
-
-<table id="pne-config">
-<tr><th with="1%">Option Name</th><th width="99%">Current Value</th></tr>
-<% propKeys.forEach(function(k) { %>
-<tr><td class="key"><%= k %></td><td class="val"><%= appjetConfig[k] %></td></tr>
-<% }) %>
-</table>
-
-
-
-
-
diff --git a/trunk/etherpad/src/templates/pro/admin/pne-dashboard.ejs b/trunk/etherpad/src/templates/pro/admin/pne-dashboard.ejs
deleted file mode 100644
index 6b9b456..0000000
--- a/trunk/etherpad/src/templates/pro/admin/pne-dashboard.ejs
+++ /dev/null
@@ -1,40 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.setHtmlTitle("EtherPad Private Server Dashboard") %>
-
-<h3 class="top">User Quota</h3>
-
-<p>Your maximum daily unique user quota is: <b><%= userQuota %></b></p>
-<p>So far today, there have been <b><%= todayActiveUsers %></b> applied against this quota.</p>
-
-<h3>Uptime</h3>
-
-This server has been running for <b><%= renderUptime() %></b>.
-
-<h3>HTTP Response Codes</h3>
-
-<%= renderResponseCodes() %>
-
-<h3>Current Realtime Pad Connections</h3>
-
-<%= renderPadConnections() %>
-
-<h3>Realtime Transport Performance</h3>
-
-<%= renderTransportStats() %>
-
-<div style="font-size: 12px; text-align: right;">
- <a style="color: #ccc;" href="/ep/admin/pne-advanced">*</a>
-</div>
-
-
diff --git a/trunk/etherpad/src/templates/pro/admin/pne-shell.ejs b/trunk/etherpad/src/templates/pro/admin/pne-shell.ejs
deleted file mode 100644
index f398b15..0000000
--- a/trunk/etherpad/src/templates/pro/admin/pne-shell.ejs
+++ /dev/null
@@ -1,33 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.setHtmlTitle("Shell") %>
-
-<p style="margin-top: 0; color: red;">Warning! Be careful with this page.</p>
-
-<h3 class="top">Shell</h3>
-
-<p>Enter command:</p>
-
-<form action="<%= request.path %>" method="post">
- <textarea name="cmd" style="width: 100%; height: 140px;"><%= oldCmd %></textarea>
- <input type="submit" value="Run" />
-</form>
-
-<% if (result) { %>
- <h3>Result</h3>
- <div style="font-family: monospace; border: 1px solid #66f; padding: 1em;">
- <%= result %>
- </div>
- <p style="color: #888; font-family: monospace; font-size: .7em;">Computed in <%= elapsedMs %>ms.</p>
-<% } %>
-
diff --git a/trunk/etherpad/src/templates/pro/admin/single-invoice.ejs b/trunk/etherpad/src/templates/pro/admin/single-invoice.ejs
deleted file mode 100644
index aeab184..0000000
--- a/trunk/etherpad/src/templates/pro/admin/single-invoice.ejs
+++ /dev/null
@@ -1,47 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><%
- helpers.includeCss('store/ondemand-billing.css');
-%>
-
-<h3 class="top">Past Invoices</h3>
-
-<p>Invoice #<%= invoice.id %>, dated <%= formatDate(invoice.time) %>.</p>
-
-<table class="billingsummary">
- <tr>
- <th>Invoice status</th>
- <td><%= invoice.status == 'paid' ? "Paid" : (invoice.status == 'pending' ? "<strong>Pending</strong>" : (invoice.status == 'refunded' ? "<em>Refunded</em>" : invoice.status)) %></td>
- </tr>
- <tr>
- <th>Number of users</th>
- <td><%= invoice.users %></td>
- </tr>
- <tr>
- <th>Cost</th>
- <td>US $<%= dollars(centsToDollars(invoice.amt)) %></td>
- </tr>
- <% if (transaction) { %>
- <tr>
- <th>Paid on</th>
- <td><%= formatDate(transaction.time) %></td>
- </tr>
- <tr>
- <th>Paid using</th>
- <td><%= transaction.payInfo %></td>
- </tr>
- <% } %>
-</table>
-
-<p class="returnlink"><a href="<%= request.path %>">&laquo; back to invoice list</a></p>
-
diff --git a/trunk/etherpad/src/templates/pro/pro-payment-required.ejs b/trunk/etherpad/src/templates/pro/pro-payment-required.ejs
deleted file mode 100644
index 3649990..0000000
--- a/trunk/etherpad/src/templates/pro/pro-payment-required.ejs
+++ /dev/null
@@ -1,51 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.includeJQuery() %>
-<% helpers.includeJs("etherpad.js") %>
-<% helpers.includeCss("pro/payment-required.css") %>
-
-<div class="fpcontent payment-required">
-
-
-<div id="outside">
-<div id="inside">
-
- <h1>Payment Required</h1>
-
- <div id="message"><%= message %></div>
- <br/>
-
- <% if (isAdmin) { %>
- <a class="manage-billing-button" href="/ep/admin/billing/">
- Manage Billing Info
- </a>
- <% } else { %>
- <p>Please contact one of the following site administrator to
- set up a billing profile on <%= request.domain %>:</p>
-
- <ul>
- <% adminList.forEach(function(a) { %>
- <li><%= a.fullName %>&nbsp;&nbsp;&lt;<%= TT(a.email)
- %>&gt;</li>
- <% }); %>
- </ul>
-
- <% } %>
-
- <br/><br/>
- <p>Questions? Contact <%= helpers.oemail("support") %>.</p>
-
-</div>
-</div>
-
-
diff --git a/trunk/etherpad/src/templates/statistics/stat_page.ejs b/trunk/etherpad/src/templates/statistics/stat_page.ejs
deleted file mode 100644
index 22277b3..0000000
--- a/trunk/etherpad/src/templates/statistics/stat_page.ejs
+++ /dev/null
@@ -1,89 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><%
-
-helpers.includeCss('admin/admin-stats.css');
-helpers.includeJQuery();
-helpers.includeJs('statpage.js');
-
-%>
-
-<a id="backtoadmin" href="/ep/admin/">&laquo; back to admin</a>
-
-<div id="topnav">
- <ul>
- <% statCategoryNames.forEach(function(catName) {
- %> <li>
- <a class="navlink" id="link<%= catName %>" href="<%= request.path %>#<%= catName %>"><%= catName %></a>
- </li> <%
- }); %>
- </ul>
-</div>
-
-<div>&nbsp;</div>
-
-<%= helpers.clearFloats() %>
-
-<%= optionsForm %>
-
-<% function formatLatest(latest) {
- if (typeof(latest) == 'string') {
- return latest;
- } else {
- return '<table class="latesttable" border="0" cellpadding="0" cellspacing="0">'+
- latest.map(function(x) { return "<tr><td>"+x.value+"</td><td>"+x.description+"</td></tr>"; }).join("\n")+
- "</table>";
- }
-}
-%>
-
-<%
-function displayStat(statObject) {
- %>
- <div class="statentry <%= statObject.specialState %>" id="<%= statObject.id %>">
- <h2 class="title"><%= statObject.name %></h2>
- <div class="statbody">
- <h3><%= statObject.displayName %></h3>
- <table>
- <tr>
- <td class="graph">
- <%= statObject.graph %>
- <% if (statObject.dataLinks) { %>
- <div class="datalinks">(data for <%= statObject.dataLinks.join(", ") %>)</div>
- <% } %>
- </td>
- <td class="latest">
- <h4>Latest values:</h4>
- <%= formatLatest(statObject.latest) %>
- </td>
- </tr>
- </table>
- </div>
- </div>
- <%
-}
-
-function displayCategory(categoryName) {
- %>
- <div class="categorywrapper" id="box<%= categoryName %>">
- <%
- categoriesToStats[categoryName].forEach(displayStat);
- %>
- </div>
- <%
-}
-
-statCategoryNames.forEach(displayCategory);
-
-%>
-
diff --git a/trunk/etherpad/src/templates/store/csc-help.ejs b/trunk/etherpad/src/templates/store/csc-help.ejs
deleted file mode 100644
index 3623fac..0000000
--- a/trunk/etherpad/src/templates/store/csc-help.ejs
+++ /dev/null
@@ -1,23 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><html>
-<body>
-
-<p>The CSC (or CVC) is the 3-digit number printed on the back of your card.
-For American Express, it's the 4-digit number on the front.</p>
-
-<img src="/static/img/billing/csc-help.gif" alt="cc back" />
-
-</body>
-</html>
-
diff --git a/trunk/etherpad/src/templates/store/eepnet-checkout/billing-info.ejs b/trunk/etherpad/src/templates/store/eepnet-checkout/billing-info.ejs
deleted file mode 100644
index 69e0ead..0000000
--- a/trunk/etherpad/src/templates/store/eepnet-checkout/billing-info.ejs
+++ /dev/null
@@ -1,183 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><%
- if (!cart.billingCountry) {
- cart.billingCountry = "US";
- }
- helpers.includeJQuery();
- helpers.includeJs("billing_shared.js");
- helpers.includeJs("billing.js");
-
- function classesPlusError(classes, id) {
- return (classes || []).concat(errorIfInvalid(id) || []).join(' ');
- }
-%>
-
-<% function textRow(id, label, classes, notBillingField) {
- var val = (cart[id] || "");
- var maxlen=60;
- var border;
- if (id == "billingCCNumber") {
- if (billing.validateCcNumber(val)) {
- border = "greenborder";
- } else if (billing.validateCcLength(val)) {
- border = "redborder";
- }
- val = obfuscateCC(val);
- maxlen = 16;
- }
- var classString = classesPlusError((notBillingField?[]:['billingfield']).concat(classes), id);
- return TR({className: classString},
- TD({className: 'pcell'},
- LABEL({htmlFor: id}, label+(label.length > 0 ? ":" : ''))),
- TD({className: 'tcell'},
- INPUT({type: 'text', name: id, size:35, maxlength:maxlen,
- value: val,
- className: border})));
- } %>
-
-<h4>Your name:</h4>
-<table class="billingtable">
- <%= textRow("billingFirstName", "First Name", [], true) %>
- <%= textRow("billingLastName", "Last Name", [], true) %>
-</table>
-
-<h4>Payment information:</h4>
-
-<% if (request.scheme == 'https') { %>
- <div class='secure'>
- <p>Your payment information will be sent securely.</p>
- </div>
-<% } %>
-
-<%
- function purchaseType(id, title) {
- var sel;
- if (! cart.billingPurchaseType) {
- sel = (id == 'creditcard');
- } else {
- sel = (cart.billingPurchaseType == id);
- }
- %>
- <span class="paymentbutton">
- <input type="radio" value="<%= id %>" name="billingPurchaseType" id="purchase<%= id %>" <%= sel ? 'checked="checked"' : "" %> style="display: inline-block; vertical-align: middle;"/>
- <label for="purchase<%= id %>">
- <img src="/static/img/billing/<%= id %>.gif" style="display: inline-block; vertical-align: middle;" /> <span style="display: inline-block; vertical-align: middle;"><%= title %></span>
- </label>
- </span>
- <%
- }
-%>
-
-<div id="billingselect">
-<p class="<%= errorIfInvalid("billingPurchaseType") %>">Pay using:
-<% purchaseType('creditcard', 'Credit Card'); %>
-<% purchaseType('invoice', 'Invoice'); %>
-<% purchaseType('paypal', 'PayPal'); %>
-</p>
-</div>
-
-<table class="billingtable">
- <%= textRow("billingCCNumber", "Credit Card Number", ['creditcardreq']) %>
-
-<% function cardInput(cctype) {
- var classes = [];
- if (cart.billingCCNumber) {
- if (cctype == billing.getCcType(cart.billingCCNumber)) {
- classes.push("ccimageselected");
- }
- }
- classes.push("ccimage");
- var img = IMG({
- src: "/static/img/billing/"+cctype+".gif",
- alt: cctype,
- className: classes.join(" "),
- style: "vertical-align: middle",
- id: "img"+cctype});
- return img;
- } %>
-
- <tr class="billingfield creditcardreq">
- <td class="pcell">&nbsp;</td>
- <td valign="center">
- <div id="ccimages">
- <% ["visa", "mc", "disc", "amex"].forEach(function(t) { %>
- <%= cardInput(t) %>
- <% }); %>
- </div>
- </td>
- </tr>
-
- <tr class="billingfield creditcardreq <%= errorIfInvalid("billingMeta") %>">
- <td class="pcell">Expiration (MM/YY):</td>
- <td>
- <input type="text" name="billingExpirationMonth" size="2" maxlength="2"
- value="<%= (cart.billingExpirationMonth || '') %>" />
- /
- <input type="text" name="billingExpirationYear" size="2" maxlength="2"
- value="<%= (cart.billingExpirationYear || '') %>" />
- &nbsp;&nbsp;&nbsp;&nbsp;CSC/CVC:
- <input type="text" name="billingCSC" size="4" maxlength="4"
- value="<%= (cart.billingCSC || '') %>"/>
- <a target="_blank" href="//<%= getFullSuperdomainHost() %>/ep/store/csc-help" id="cschelp">what's this?</a>
- </td>
- </tr>
-
- <tr class="billingfield creditcardreq">
- <td colspan=2 style="text-align: center; font-weight: normal;">(Be sure to enter your <strong>credit card billing address</strong> below.)</td>
- </tr>
-
- <tr class="<%= classesPlusError(['billingfield', 'creditcardreq', 'invoicereq'], 'billingCountry') %>">
- <td class="pcell">Country:</td>
- <td>
- <select id="billingCountry" name="billingCountry">
- <% countryList.forEach(function(c) { %>
- <%= ((c[0] == cart.billingCountry) ?
- OPTION({value: c[0], selected: true}, c[1]) :
- OPTION({value: c[0]}, c[1])) %>
- <% }); %>
- </select>
- </td>
- </tr>
-
- <%= textRow("billingAddressLine1", "Address", ['creditcardreq', 'invoicereq']) %>
- <%= textRow("billingAddressLine2", "", ['creditcardreq', 'invoicereq']) %>
- <%= textRow("billingCity", "City", ['creditcardreq', 'invoicereq']) %>
-
- <tr class="<%= classesPlusError(['billingfield', 'creditcardreq', 'invoicereq', 'usonly'], 'billingState') %>">
- <td class="pcell">State:</td>
- <td>
- <select id="billingState" name="billingState">
- <% usaStateList.forEach(function(s) { %>
- <%= ((s == cart.billingState) ?
- OPTION({value: s, selected: true}, s) :
- OPTION({value: s}, s)) %>
- <% }); %>
- </select>
- </td>
- </tr>
- <%= textRow("billingProvince", "Province", ['creditcardreq', 'invoicereq', 'intonly'])%>
- <%= textRow("billingZipCode", "Zip Code", ['creditcardreq', 'invoicereq', 'usonly']) %>
- <%= textRow("billingPostalCode", "Postal Code", ['creditcardreq', 'invoicereq', 'intonly'])%>
- <tr class="billingfield paypalreq"><td colspan=2 class="firstcell">Click "<%= billingButtonName %>" below to continue with PayPal.</td></tr>
-</table>
-
-<% if (showCouponCode) { %>
- <h4>Optional information:</h4>
- <table class="billingtable">
- <%= textRow("billingReferralCode", "Referral Code", [], true) %>
- </table>
-<% } %>
-
-
-<%= billingFinalPhrase %> \ No newline at end of file
diff --git a/trunk/etherpad/src/templates/store/eepnet-checkout/cart.ejs b/trunk/etherpad/src/templates/store/eepnet-checkout/cart.ejs
deleted file mode 100644
index 147ff1b..0000000
--- a/trunk/etherpad/src/templates/store/eepnet-checkout/cart.ejs
+++ /dev/null
@@ -1,119 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %>
-<div id="<%= shoppingcartid %>" class="shoppingcart">
- <table cellspacing="0" cellpadding="0">
- <tr>
- <th>Item</th>
- <th class="pcell">Cost</th>
- </tr>
-
- <% if (! ('baseCost' in cart) && ! ('supportCost' in cart)) { %>
- <tr>
- <td colspan="2" class="noitems">
- <em>Nothing selected.</em>
- </td>
- </tr>
- <% } %>
-
- <% if (cart.baseCost) { %>
- <tr class="base">
- <td>
- <span class="item">Etherpad Private Network</span><br />
- <span class="desc"><%= cart.numUsers %> users
- <% if (editable) { %>
- <span class="editlink">(<a href="<%= pathTo("purchase") %>">edit</a>)</span>
- <% } %>
- </span>
- </td>
- <td class="pcell">US$<%= dollars(cart.baseCost) %></td>
- </tr>
- <% if (cart.couponProductPctDiscount) { %>
- <tr class="basediscount refer">
- <td>
- <span class="desc">Referral - <%= cart.couponProductPctDiscount %>% savings</span>
- </td>
- <td class="pcell">-US$<%= dollars(cart.productReferralDiscount) %></td>
- </tr>
- <% } %>
- <% } %>
-
- <% if (cart.supportCost) { %>
- <tr class="support">
- <td>
- <span class="item">Support Contract
- <% if (editable) { %>
- <span class="editlink">(<a href="<%= pathTo("support-contract") %>">edit</a>)</span>
- <% } %>
- </span>
- <br />
- <span class="desc">1 year</span>
- </td>
- <td class="pcell">US$<%= dollars(cart.supportCost) %></td>
- </tr>
- <% if (cart.couponSupportPctDiscount) { %>
- <tr class="supportdiscount refer">
- <td>
- <span class="desc">Referral - <%= cart.couponSupportPctDiscount %>% savings</span>
- </td>
- <td class="pcell">-US$<%= dollars(cart.supportReferralDiscount) %></td>
- </tr>
- <% } %>
- <% } else if (cart.baseCost) { %>
- <tr class="support">
- <td>
- <span class="item">No Support Contract
- <% if (editable) { %>
- <span class="editlink">(<a href="<%= pathTo("support-contract") %>">edit</a>)</span>
- <% } %>
- </span>
- </td>
- <td class="pcell">US$0.00</td>
- </tr>
- <% } %>
-
- <% if (cart.freeUserCount) { %>
- <tr class="referralbonus refer">
- <td>
- <span class="item">Bonus Users</span><br />
- <span class="desc">
- Referral - <%= cart.freeUserCount %> free
- user<%= (cart.freeUserCount == 1 ? '' : "s") %>
- </span>
- </td>
- <td class="pcell">US$0.00</td>
- </tr>
- <% } %>
-
- <tr class="spacer"><td>&nbsp;</td></tr>
-
- <%
- var pctDiscount = cart.couponTotalPctDiscount;
- var hasSubtotal = pctDiscount > 0;
- %>
- <% if (hasSubtotal) { %>
- <tr class="subtotal">
- <td>Subtotal</td>
- <td class="pcell">US$<%= dollars(cart.subTotal) %></td>
- </tr>
- <tr class="referraldiscount refer">
- <td>Referral - <%= pctDiscount %>% savings</td>
- <td class="pcell">-US$<%= dollars(cart.totalReferralDiscount) %></td>
- </tr>
- <% } %>
- <tr class="total<%= (hasSubtotal ? '' : ' withoutsubtotal') %>">
- <td>Total</td>
- <td class="pcell">US$<%= dollars(cart.total) %></td>
- </tr>
- </table>
-</div> \ No newline at end of file
diff --git a/trunk/etherpad/src/templates/store/eepnet-checkout/checkout-template.ejs b/trunk/etherpad/src/templates/store/eepnet-checkout/checkout-template.ejs
deleted file mode 100644
index 817f0eb..0000000
--- a/trunk/etherpad/src/templates/store/eepnet-checkout/checkout-template.ejs
+++ /dev/null
@@ -1,38 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.includeCss("store/eepnet-checkout.css"); %>
-<% helpers.includeJQuery() %>
-<% helpers.includeJs("etherpad.js") %>
-<% helpers.setHtmlTitle(title); %>
-
-<%
-var selectCount = 0;
-function select(id, title) {
- var className = 'poslabel';
- if (pageId == id) {
- className += ' current';
- }
- selectCount++;
- return SPAN({className: className}, selectCount+". "+title);
-}
-%>
-
-<div class="fpcontent">
-<div id="<%= pageId %>">
-
- <h2>Private Network Edition: Purchase Online</h2>
-
- <%= helpers.rafterNote() %>
-
-</div><!-- /pageId -->
-</div><!-- /fpcontent -->
diff --git a/trunk/etherpad/src/templates/store/eepnet-checkout/confirmation.ejs b/trunk/etherpad/src/templates/store/eepnet-checkout/confirmation.ejs
deleted file mode 100644
index 3b38775..0000000
--- a/trunk/etherpad/src/templates/store/eepnet-checkout/confirmation.ejs
+++ /dev/null
@@ -1,33 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><%
-helpers.includeJs('confirmation.js');
-%>
-
-<% if (request.params.frompaypal) {
- handlePayPalRedirect();
-} %>
-
-<%= displaySummary(true) %>
-
-<% switch(cart.billingPurchaseType) {
- case 'creditcard': case 'paypal': %>
- <p>If this looks good, click "Purchase" below to complete your purchase.</p>
- <% break;
- case 'invoice': %>
- <p>If this looks good, print this page and mail it along with a check or other
- prearranged payment to:</p><p><strong>AppJet, Inc.<br>Pier 38 - Suite 210<br>The Embarcadero<br>San Francisco, CA 94107</strong></p>
- <% break;
-}
- %>
-
diff --git a/trunk/etherpad/src/templates/store/eepnet-checkout/license-info.ejs b/trunk/etherpad/src/templates/store/eepnet-checkout/license-info.ejs
deleted file mode 100644
index 4d710f2..0000000
--- a/trunk/etherpad/src/templates/store/eepnet-checkout/license-info.ejs
+++ /dev/null
@@ -1,40 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><p>Your license key will be issued to a particular individual at your organization, and will be delivered to the email address you specify below.</p>
-
-<table border="1">
- <tr class="<%= errorIfInvalid('email') %>">
- <td>Email address to receive license key:</td>
- <td><input name="email" type="text"
- value="<%= cart.email %>" /></td>
- </tr>
-
- <tr class="<%= errorIfInvalid('ownerName') %>">
- <td>Name of license owner (your name):</td>
- <td><input name="ownerName" type="text"
- value="<%= cart.ownerName %>" /></td>
- </tr>
-
- <tr class="<%= errorIfInvalid('orgName') %>">
- <td>Organization or company name:</td>
- <td><input name="orgName" type="text"
- value="<%= cart.orgName %>" /></td>
- </tr>
-
- <tr class="<%= errorIfInvalid('licenseAgreement') %> center">
- <td colspan=2>
- <input id="c1" type="checkbox" name="licenseAgreement" <%= (cart.licenseAgreement ? 'checked="checked"' : '') %> />
- <label for="c1">I agree to the <a target="_blank" href="/static/html/eepnet/eepnet-license.html">License</a>.</label>
- </td>
- </tr>
-</table> \ No newline at end of file
diff --git a/trunk/etherpad/src/templates/store/eepnet-checkout/purchase.ejs b/trunk/etherpad/src/templates/store/eepnet-checkout/purchase.ejs
deleted file mode 100644
index 49cb3bb..0000000
--- a/trunk/etherpad/src/templates/store/eepnet-checkout/purchase.ejs
+++ /dev/null
@@ -1,33 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><p>Thank you for choosing to purchase <strong>Enterprise EtherPad Private Network Edition.</strong></p>
-
-<p>A license allows a certain number of concurrent users, at a one-time cost of US $<%= dollars(costPerUser) %> per user with no recurring costs. <a target="_blank" href="/ep/about/pricing-eepnet-users">Learn more about how we count users</a>.</p>
-
-<p>How many users should your license support?</p>
-
-<table>
- <tr class="<%= errorIfInvalid('numUsers') %>">
- <td class="pcell">Number of Users at US $<%= dollars(costPerUser) %>/user:</td>
- <td class="tcell"><input name="numUsers" type="text"
- value="<%= cart.numUsers %>" /></td>
- </tr>
-</table>
-
-<table>
- <tr class="<%= errorIfInvalid('couponCode') %>">
- <td colspan="2" class="pcell">Referral Code (optional):</td>
- <td class="tcell"><input id="couponCode" name="couponCode" type="text"
- maxlength="8" value="<%= cart.couponCode %>" /></td>
- </tr>
-</table>
diff --git a/trunk/etherpad/src/templates/store/eepnet-checkout/receipt.ejs b/trunk/etherpad/src/templates/store/eepnet-checkout/receipt.ejs
deleted file mode 100644
index 8d3a2a5..0000000
--- a/trunk/etherpad/src/templates/store/eepnet-checkout/receipt.ejs
+++ /dev/null
@@ -1,43 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% if (cart.showStartOverMessage) { %>
- <div class="innererrormsg">
- Your purchase is complete! To purchase another item, please return to the <a href="<%= pathTo('purchase') %>?clearcart=1">purchase page</a>.
- </div>
-<% }
-
-switch(cart.status) {
- case 'success':
- %><p><strong>Thank you for your purchase!</strong> This page serves as your receipt. Please print it for your records. You will receive a copy of this receipt and license key by email shortly.</p><%
- break;
- case 'pending':
- %><p>Your purchase is pending approval by PayPal. Once it clears,
- usually in 2-5 business days, you will receive a copy of this receipt and
- your license key by email.</p><%
- break;
-} %>
-
-<%
- var instructions = "/ep/pne-manual";
- var download = "/ep/store/eepnet-download-nextsteps";
-%>
-
-<p>To install EtherPad Private Network Edition:</p>
-<ul>
- <li><a href="<%= download %>">Download Etherpad: Private Network Edition</a>.</li>
- <li>Read the <a href="<%= instructions %>">EtherPad: Private Network Edition installation instructions</a>.</li>
-</ul>
-
-<p><strong></strong></p>
-
-<%= displaySummary() %>
diff --git a/trunk/etherpad/src/templates/store/eepnet-checkout/summary.ejs b/trunk/etherpad/src/templates/store/eepnet-checkout/summary.ejs
deleted file mode 100644
index 753873c..0000000
--- a/trunk/etherpad/src/templates/store/eepnet-checkout/summary.ejs
+++ /dev/null
@@ -1,91 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><%
-function textRow(tcell, pcell) {
- %><tr>
- <td class="tcell"><%= tcell %></td>
- <td class="pcell"><%= pcell %></td>
- </tr>
- <%
-}
-var keyData = {
- ownerName: cart.ownerName,
- orgName: cart.orgName
-}
-if (cart.licenseKey) {
- var parts = cart.licenseKey.split(":");
- keyData.ownerName = parts[0];
- keyData.orgName = parts[1];
- keyData.key = parts[2];
-
- keyData.keyLine1 = keyData.key.substring(0, keyData.key.length/3);
- keyData.keyLine2 = keyData.key.substring(keyData.key.length/3, 2*keyData.key.length/3);
- keyData.keyLine3 = keyData.key.substring(2*keyData.key.length/3, keyData.key.length);
-}
-
-function makeRows(arr) {
- arr.forEach(function(arr) { textRow(arr[0], arr[1]); });
-}
-%>
-
-<h4>License Information <% if (editable) { %><span class="editlink">(<a href="<%= pathTo("license-info") %>">edit</a>)</span><% } %></h4>
-
-<table>
- <%
- makeRows([
- [ "Administrator name:", keyData.ownerName ],
- [ "Organization/Company:", keyData.orgName ],
- [ "Email address for delivery:", cart.email ],
- [ "Total users:", cart.userCount ]
- ]);
- if (keyData.key) {
- textRow("License key:", keyData.keyLine1+"<BR>"+keyData.keyLine2+"<BR>"+keyData.keyLine3);
- %><!-- key: <%= keyData.key %> --><%
- }
- %>
-</table>
-
-<h4>Payment Information <% if (editable) { %><span class="editlink">(<a href="<%= pathTo("billing-info") %>">edit</a>)</span><% } %></h4>
-
-<table>
- <%
- var isUs = cart.billingCountry == "US";
- switch(cart.billingPurchaseType) {
- case 'creditcard':
- makeRows([
- [ "Credit card number:", obfuscateCC(cart.billingCCNumber) ],
- [ "Expiration date:", cart.billingExpirationMonth+" / 20"+cart.billingExpirationYear ]
- ]);
- // falling through intentional.
- case 'invoice':
- makeRows([
- [ "Purchaser name:", cart.billingFirstName + " " + cart.billingLastName ],
- [ "Purchaser address: ", cart.billingAddressLine1 + "<br>" +
- (cart.billingAddressLine2 ? cart.billingAddressLine2 + "<br>" : "") +
- cart.billingCity + ", " +
- (isUs?cart.billingState:cart.billingProvince) + "<br>" +
- (isUs?cart.billingZipCode:cart.billingPostalCode) +
- (isUs?'':', '+cart.billingCountry) ],
- [ "Invoice number: ", cart.invoiceId ]
- ]);
- break;
- case 'paypal':
- textRow("Paid using:", "PayPal");
- textRow("InvoiceNumber:", cart.invoiceId);
- }
- %>
-</table>
-
-<h4>Summary of Charges</h4>
-
-<%= displayCart("shoppingconfirmation", editable) %>
diff --git a/trunk/etherpad/src/templates/store/eepnet-checkout/support-contract.ejs b/trunk/etherpad/src/templates/store/eepnet-checkout/support-contract.ejs
deleted file mode 100644
index ff33fda..0000000
--- a/trunk/etherpad/src/templates/store/eepnet-checkout/support-contract.ejs
+++ /dev/null
@@ -1,41 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><p>A support contract gives you free upgrades and help directly from the engineers who developed EtherPad. Support contracts cost US $<%= dollars(costPerUser * supportCostPct/100) %> per user per year, with a US $<%= dollars(supportMinCost) %> per year minimum. <a target="_blank" href="/ep/about/pricing-eepnet-support">Learn more about support contracts</a>.</p>
-
-<p>For the <%= cart.numUsers %>-user license you've selected, a support contract costs US $<%= discountedSupportCost() !== undefined ? dollars(discountedSupportCost()) : dollars(supportCost()) %>.
-
-<p>Do you want a support contract?</p>
-
-<table>
- <tr>
- <td>
- <input id="r1" type="radio" name="supportContract" value="true"
- <%= (cart.supportContract == "true") ? "checked" : "" %> />
- </td>
- <td>
- <label for="r1">Yes, I want to purchase a support contract.</label>
- </td>
- </tr>
-
- <tr>
- <td>
- <input id="r2" type="radio" name="supportContract" value="false"
- <%= (cart.supportContract != "true")? "checked" : "" %> />
- </td>
- <td>
- <label for="r2">
- No thanks, I just want the software license.
- </label>
- </td>
- </tr>
-</table> \ No newline at end of file
diff --git a/trunk/etherpad/src/templates/store/eepnet_download.ejs b/trunk/etherpad/src/templates/store/eepnet_download.ejs
deleted file mode 100644
index 42c89ee..0000000
--- a/trunk/etherpad/src/templates/store/eepnet_download.ejs
+++ /dev/null
@@ -1,43 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.includeCss("store/store.css") %>
-<% helpers.includeJQuery() %>
-<% helpers.includeJs("store.js") %>
-
-<div class="fpcontent storepage" id="downloadpage">
-
- <% if (message) { %>
- <div id="topmsg">
- <%= message %>
- </div>
- <% } %>
-
- <h2>Download EtherPad Private Network Edition:</h2>
-
- <br/><br/>
- <center>
- <input id="license_agree" type="checkbox" />
- <label id="license_agree_label"
- for="license_agree" style="font-size: 1.2em;">
- Agree to the <a target="_blank" href="/static/html/eepnet/eepnet-eval-license.html">License</a>
- </label>
-
- <a class="downloadbutton_disabled" href="javascript:store.mustAgree();">
- Download Now
- </a>
- <h3>Version: <%= versionString %></h3><br/>
-
- </center>
-
-
-</div>
diff --git a/trunk/etherpad/src/templates/store/eepnet_eval_nextsteps.ejs b/trunk/etherpad/src/templates/store/eepnet_eval_nextsteps.ejs
deleted file mode 100644
index 4c4cec4..0000000
--- a/trunk/etherpad/src/templates/store/eepnet_eval_nextsteps.ejs
+++ /dev/null
@@ -1,40 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><div class="fpcontent">
- <h2>Downloading...</h2>
-
- <p>Your download should begin automatically. If it does not, you
- can click this link:</p>
-
- <ul>
- <li><a href="/ep/store/eepnet-download-zip">Download Now</a>
- </li>
- </ul>
-
- <h2>Next Steps</h2>
-
- <ul>
- <li>Read the
- <a href="/ep/pne-manual/">PNE System Administrator's
- Manual</a>.</li>
-
- <li>A license key was sent to you by email, which you will need to
- run EtherPad PNE.</li>
-
- </ul>
-
-</div>
-
-<iframe style="display: none;" width="0" height="0"
- src="/ep/store/eepnet-download-zip"></iframe>
-
diff --git a/trunk/etherpad/src/templates/store/eepnet_eval_signup.ejs b/trunk/etherpad/src/templates/store/eepnet_eval_signup.ejs
deleted file mode 100644
index 5a1edf4..0000000
--- a/trunk/etherpad/src/templates/store/eepnet_eval_signup.ejs
+++ /dev/null
@@ -1,125 +0,0 @@
-<% /* Copyright 2009 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-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 "AS-IS" 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. */ %><% helpers.setHtmlTitle("Sign up for EtherPad PNE Free Trial"); %>
-<% helpers.includeJQuery() %>
-<% helpers.includeJs("etherpad.js") %>
-<% helpers.includeJs("store.js") %>
-<% helpers.includeCss("store/store.css") %>
-
-<% function renderField(maxlen, id, title) {
- var oldValue = (oldData[id] || "");
- return DIV(P(LABEL({htmlFor: id}, title),
- INPUT({maxlength: maxlen,
- type: "text",
- className: "signupData",
- name: id,
- id: id,
- value: oldValue})));
- }
-
- function renderWebLeadField(name) {
- return INPUT({type: 'hidden', name: name, id: "wl_"+name, value: ""});
- }
-%>
-
-<div class="fpcontent storepage" id="eepnet_trial_signup_page">
-
- <h2 id="toph2">Private Network Edition: <%= trialDays %>-Day Free Trial</h2>
-
- <p>Enter your information here to download a free <%= trialDays
- %>-day trial of EtherPad Private Network Edition.</p>
-
- <div style="display: none;" id="errormsg">&nbsp;</div>
-
- <div style="display: none;" id="processingmsg">
- <img src="/static/img/misc/status-ball.gif" alt="" />
- Processing, please wait...
- </div>
-
- <div id="dlsignup">
-
- <form id="signupForm" method="post" action="<%= request.path %>">
-
- <% /* note: these fields should match exactly the eepnet-pricingcontact
- form in pricing_eepnet.ejs */ %>
-
- <%= renderField(40, "firstName", "First Name:") %>
- <%= renderField(80, "lastName", "Last Name:") %>
- <%= renderField(80, "email", "Your Email (license key will be sent here):") %>
- <%= renderField(40, "orgName", "Company/Organization:") %>
-
- <p>
- <label for="industry">Industry</label>
- <select id="industry" name="industry">
- <% sfIndustryList.forEach(function(i) { %>
- <%= ((i == oldData.industry) ?
- OPTION({value: toHTML(i), selected: true}, i) :
- OPTION({value: toHTML(i)}, i)) %>
- <% }); %>
- </select>
- </p>
-
- <%= renderField(40, "jobTitle", "Your Title:") %>
- <%= renderField(40, "phone", "Phone Number:") %>
- <%= renderField(160, "estUsers", "Estimated number of users:") %>
-
- </form>
-
- <p><button id="submit" onclick="javascript: void store.eepnetTrial.submit();">Go To Download --&gt;</button></p>
-
- </div>
-
- <p>If you already have a license, you
- can <a href="/ep/store/eepnet-download">skip directly to download</a>.</p>
-
- <p>You can also <a href="/ep/store/eepnet-recover-license">recover a
- lost license key</a>.</p>
-
- <p>Questions? Email <%= helpers.oemail("sales") %>.</p>
-
-</div>
-
-<form id="wlform"
- method="post"
- target="wltarget"
- action="<%= request.scheme %>://www.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8"
->
-
- <input type="hidden" name="retURL" value="<%= request.scheme %>://<%= request.host %>/ep/store/salesforce-web2lead-ok" />
-
- <% [
- "oid",
- "first_name",
- "last_name",
- "email",
- "company",
- "title",
- "phone",
- "00N80000003FYtG",
- "00N80000003FYto",
- "00N80000003FYuI",
- "lead_source",
- "industry"
- ].forEach(function(f) { %>
-
- <%= renderWebLeadField(f) %>
-
- <% }); %>
-
-</form>
-
-<iframe style="width: 1px; height: 1px; border: 0;"
- name="wltarget"
- id="wltarget"
- src="about:blank"></iframe>
-
diff --git a/trunk/infrastructure/ace/bin/make b/trunk/infrastructure/ace/bin/make
deleted file mode 100755
index dad11ff..0000000
--- a/trunk/infrastructure/ace/bin/make
+++ /dev/null
@@ -1,337 +0,0 @@
-#!/bin/sh
-exec scala -classpath lib/yuicompressor-2.4-appjet.jar:lib/rhino-js-1.7r1.jar $0 $@
-!#
-
-import java.io._;
-
-def superpack(input: String): String = {
- // this function is self-contained; takes a string, returns an expression
- // that evaluates to that string
- // XXX (This compresses well but decompression is too slow)
-
- // constraints on special chars:
- // - this string must be able to go in a character class
- // - each char must be able to go in single quotes
- val specialChars = "-~@%$#*^_`()|abcdefghijklmnopqrstuvwxyz=!+,.;:?{}";
- val specialCharsSet:Set[Char] = Set(specialChars:_*);
- def containsSpecialChar(str: String) = str.exists(specialCharsSet.contains(_));
-
- val toks:Array[String] = (
- "@|[a-zA-Z0-9]+|[^@a-zA-Z0-9]{1,3}").r.findAllIn(input).collect.toArray;
-
- val stringCounts = {
- val m = new scala.collection.mutable.HashMap[String,Int];
- def incrementCount(s: String) = { m(s) = m.getOrElse(s, 0) + 1; }
- for(s <- toks) incrementCount(s);
- m;
- }
-
- val estimatedSavings = scala.util.Sorting.stableSort(
- for((s,n) <- stringCounts.toArray; savings = s.length*n
- if (savings > 8 || containsSpecialChar(s)))
- yield (s,n,savings),
- (x:(String,Int,Int))=> -x._3);
-
- def strLast(str: String, n: Int) = str.substring(str.length - n, str.length);
- // order of encodeNames is very important!
- val encodeNames = for(n <- 0 until (36*36); c <- specialChars) yield c.toString+strLast("0"+Integer.toString(n, 36).toUpperCase, 2);
-
- val thingsToReplace:Seq[String] = estimatedSavings.map(_._1);
- assert(encodeNames.length >= thingsToReplace.length);
-
- val replacements = Map(thingsToReplace.elements.zipWithIndex.map({
- case (str, i) => (str, encodeNames(i));
- }).collect:_*);
- def encode(tk: String) = if (replacements.contains(tk)) replacements(tk) else tk;
-
- val afterReplace = toks.map(encode(_)).mkString.replaceAll(
- "(["+specialChars+"])(?=..[^0-9A-Z])(00|0)", "$1");
-
- def makeSingleQuotedContents(str: String): String = {
- str.replace("\\", "\\\\").replace("'", "\\'").replace("<", "\\x3c").replace("\n", "\\n").
- replace("\r", "\\n").replace("\t", "\\t");
- }
-
- val expansionMap = new scala.collection.mutable.HashMap[Char,scala.collection.mutable.ArrayBuffer[String]];
- for(i <- 0 until thingsToReplace.length; sc = encodeNames(i).charAt(0);
- e = thingsToReplace(i)) {
- expansionMap.getOrElseUpdate(sc, new scala.collection.mutable.ArrayBuffer[String]) +=
- (if (e == "@") "" else e);
- }
- val expansionMapLiteral = "{"+(for((sc,strs) <- expansionMap) yield {
- "'"+sc+"':'"+makeSingleQuotedContents(strs.mkString("@"))+"'";
- }).mkString(",")+"}";
-
- val expr = ("(function(m){m="+expansionMapLiteral+
- ";for(var k in m){if(m.hasOwnProperty(k))m[k]=m[k].split('@')};return '"+
- makeSingleQuotedContents(afterReplace)+
- "'.replace(/(["+specialChars+
- "])([0-9A-Z]{0,2})/g,function(a,b,c){return m[b][parseInt(c||'0',36)]||'@'})}())");
- /*val expr = ("(function(m){m="+expansionMapLiteral+
- ";for(var k in m){if(m.hasOwnProperty(k))m[k]=m[k].split('@')};"+
- "var result=[];var i=0;var s='"+makeSingleQuotedContents(afterReplace)+
- "';var len=s.length;while (i<len) {var x=s.charAt(i); var L=m[x],a = s.charAt(i+1),b = s.charAt(i+2);if (L) { var c;if (!(a >= 'A' && a <= 'Z' || a >= '0' && a <= '9')) {c=L[0];i++} else if (!(b >= 'A' && b <= 'Z' || b >= '0' && b <= '9')) {c = L[parseInt(a,36)]; i+=2} else {c = L[parseInt(a+b,36)]; i+=3}; result.push(c||'@'); } else {result.push(x); i++} }; return result.join(''); }())");*/
-
- def evaluateString(js: String): String = {
- import org.mozilla.javascript._;
- ContextFactory.getGlobal.call(new ContextAction {
- def run(cx: Context) = {
- val scope = cx.initStandardObjects;
- cx.evaluateString(scope, js, "<cmd>", 1, null) } }).asInstanceOf[String];
- }
-
- def putFile(str: String, path: String): Unit = {
- import java.io._;
- val writer = new FileWriter(path);
- writer.write(str);
- writer.close;
- }
-
- val exprOut = evaluateString(expr);
- if (exprOut != input) {
- putFile(input, "/tmp/superpack.input");
- putFile(expr, "/tmp/superpack.expr");
- putFile(exprOut, "/tmp/superpack.output");
- error("Superpacked string does not evaluate to original string; check /tmp/superpack.*");
- }
-
- val singleLiteral = "'"+makeSingleQuotedContents(input)+"'";
- if (singleLiteral.length < expr.length) {
- singleLiteral;
- }
- else {
- expr;
- }
-}
-
-def doMake {
-
- lazy val isEtherPad = (args.length >= 2 && args(1) == "etherpad");
- lazy val isNoHelma = (args.length >= 2 && args(1) == "nohelma");
-
- def getFile(path:String): String = {
- val builder = new StringBuilder(1000);
- val reader = new BufferedReader(new FileReader(path));
- val buf = new Array[Char](1024);
- var numRead = 0;
- while({ numRead = reader.read(buf); numRead } != -1) {
- builder.append(buf, 0, numRead);
- }
- reader.close;
- return builder.toString;
- }
-
- def putFile(str: String, path: String): Unit = {
- val writer = new FileWriter(path);
- writer.write(str);
- writer.close;
- }
-
- def writeToString(func:(Writer=>Unit)): String = {
- val writer = new StringWriter;
- func(writer);
- return writer.toString;
- }
-
- def compressJS(code: String, wrap: Boolean): String = {
- import yuicompressor.org.mozilla.javascript.{ErrorReporter, EvaluatorException};
- object MyErrorReporter extends ErrorReporter {
- def warning(message:String, sourceName:String, line:Int, lineSource:String, lineOffset:Int) {
- if (message startsWith "Try to use a single 'var' statement per scope.") return;
- if (line < 0) System.err.println("\n[WARNING] " + message);
- else System.err.println("\n[WARNING] " + line + ':' + lineOffset + ':' + message);
- }
- def error(message:String, sourceName:String, line:Int, lineSource:String, lineOffset:Int) {
- if (line < 0) System.err.println("\n[ERROR] " + message);
- else System.err.println("\n[ERROR] " + line + ':' + lineOffset + ':' + message);
- }
- def runtimeError(message:String, sourceName:String, line:Int, lineSource:String, lineOffset:Int): EvaluatorException = {
- error(message, sourceName, line, lineSource, lineOffset);
- return new EvaluatorException(message);
- }
- }
-
- val munge = true;
- val verbose = false;
- val optimize = true;
- val compressor = new com.yahoo.platform.yui.compressor.JavaScriptCompressor(new StringReader(code), MyErrorReporter);
- return writeToString(compressor.compress(_, if (wrap) 100 else -1, munge, verbose, true, !optimize));
- }
-
- def compressCSS(code: String, wrap: Boolean): String = {
- val compressor = new com.yahoo.platform.yui.compressor.CssCompressor(new StringReader(code));
- return writeToString(compressor.compress(_, if (wrap) 100 else -1));
- }
-
- import java.util.regex.{Pattern, Matcher, MatchResult};
-
- def stringReplace(orig: String, regex: String, groupReferences:Boolean, func:(MatchResult=>String)): String = {
- val buf = new StringBuffer;
- val m = Pattern.compile(regex).matcher(orig);
- while (m.find) {
- var str = func(m);
- if (! groupReferences) {
- str = str.replace("\\", "\\\\").replace("$", "\\$");
- }
- m.appendReplacement(buf, str);
- }
- m.appendTail(buf);
- return buf.toString;
- }
-
- def stringToExpression(str: String): String = {
- var contents = str.replace("\\", "\\\\").replace("'", "\\'").replace("<", "\\x3c").replace("\n", "\\n").
- replace("\r", "\\n").replace("\t", "\\t");
- contents = contents.replace("\\/", "\\\\x2f"); // for Norton Internet Security
- val result = "'"+contents+"'";
- result;
- }
-
- val srcDir = "www";
- val destDir = "build";
- var code = getFile(srcDir+"/ace2_outer.js");
-
- val useCompression = true; //if (isEtherPad) false else true;
-
- code = stringReplace(code, "\\$\\$INCLUDE_([A-Z_]+)\\([\"']([^\"']+)[\"']\\)", false, (m:MatchResult) => {
- val includeType = m.group(1);
- val paths = m.group(2);
- val pathsArray = paths.replaceAll("""/\*.*?\*/""", "").split(" +").filter(_.length > 0);
- def getSubcode = pathsArray.map(p => getFile(srcDir+"/"+p)).mkString("\n");
- val doPack = (stringToExpression _);
- includeType match {
- case "JS" => {
- var subcode = getSubcode;
- subcode = subcode.replaceAll("var DEBUG=true;//\\$\\$[^\n\r]*", "var DEBUG=false;");
- if (useCompression) subcode = compressJS(subcode, true);
- "('\\x3cscript type=\"text/javascript\">//<!--\\n'+" + doPack(subcode) +
- "+'//-->\\n</script>')";
- }
- case "CSS" => {
- var subcode = getSubcode;
- if (useCompression) subcode = compressCSS(subcode, false);
- "('<style type=\"text/css\">'+" + doPack(subcode) + "+'</style>')";
- }
- case "JS_Q" => {
- var subcode = getSubcode
- subcode = subcode.replaceAll("var DEBUG=true;//\\$\\$[^\n\r]*", "var DEBUG=false;");
- if (useCompression) subcode = compressJS(subcode, true);
- "('(\\'\\\\x3cscript type=\"text/javascript\">//<!--\\\\n\\'+'+" +
- doPack(stringToExpression(subcode)) +
- "+'+\\'//-->\\\\n\\\\x3c/script>\\')')";
- }
- case "CSS_Q" => {
- var subcode = getSubcode;
- if (useCompression) subcode = compressCSS(subcode, false);
- "('(\\'<style type=\"text/css\">\\'+'+" + doPack(stringToExpression(subcode)) +
- "+'+\\'\\\\x3c/style>\\')')";
- }
- case ("JS_DEV" | "CSS_DEV") => "''";
- case ("JS_Q_DEV" | "CSS_Q_DEV") => "'\\'\\''";
- //case _ => "$$INCLUDE_"+includeType+"(\"../www/"+path+"\")";
- }
- });
-
- if (useCompression) code = compressJS(code, true);
-
- putFile(code, destDir+"/ace2bare.js");
-
- //var wrapper = getFile(srcDir+"/ace2_wrapper.js");
- //if (useCompression) wrapper = compressJS(wrapper, true);
- putFile(/*wrapper+"\n"+*/code, destDir+"/ace2.js");
-
- var index = getFile(srcDir+"/index.html");
- index = index.replaceAll("<!--\\s*DEBUG\\s*-->\\s*([\\s\\S]+?)\\s*<!--\\s*/DEBUG\\s*-->", "");
- index = index.replaceAll("<!--\\s*PROD:\\s*([\\s\\S]+?)\\s*-->", "$1");
- putFile(index, destDir+"/index.html");
-
- putFile(getFile(srcDir+"/testcode.js"), destDir+"/testcode.js");
-
- def copyFile(fromFile: String, toFile: String) {
- if (0 != Runtime.getRuntime.exec("cp "+fromFile+" "+toFile).waitFor) {
- printf("copy failed (%s -> %s).\n", fromFile, toFile);
- }
- }
-
- def replaceFirstLine(txt: String, newFirstLine: String): String = {
- var newlinePos = txt.indexOf('\n');
- newFirstLine + txt.substring(newlinePos);
- }
-
- if (isEtherPad) {
- copyFile("build/ace2.js", "../../etherpad/src/static/js/ace.js");
-
- def copyFileToEtherpad(fromName: String, toName: String) {
- var code = getFile(srcDir+"/"+fromName);
- code = replaceFirstLine(code, "// DO NOT EDIT THIS FILE, edit "+
- "infrastructure/ace/www/"+fromName);
- code = code.replaceAll("""(?<=\n)\s*//\s*%APPJET%:\s*""", "");
- putFile(code, "../../etherpad/src/etherpad/collab/ace/"+toName);
- }
- def copyFileToClientSide(fromName: String, toName: String) {
- var code = getFile(srcDir+"/"+fromName);
- code = replaceFirstLine(code, "// DO NOT EDIT THIS FILE, edit "+
- "infrastructure/ace/www/"+fromName);
- code = code.replaceAll("""(?<=\n)\s*//\s*%APPJET%:.*?\n""", "");
- code = code.replaceAll("""(?<=\n)\s*//\s*%CLIENT FILE ENDS HERE%[\s\S]*""",
- "");
- putFile(code, "../../etherpad/src/static/js/"+toName);
- }
-
- copyFileToEtherpad("easy_sync.js", "easysync1.js");
- copyFileToEtherpad("easysync2.js", "easysync2.js");
- copyFileToEtherpad("contentcollector.js", "contentcollector.js");
- copyFileToEtherpad("easysync2_tests.js", "easysync2_tests.js");
- copyFileToClientSide("colorutils.js", "colorutils.js");
- copyFileToClientSide("easysync2.js", "easysync2_client.js");
- copyFileToEtherpad("linestylefilter.js", "linestylefilter.js");
- copyFileToClientSide("linestylefilter.js", "linestylefilter_client.js");
- copyFileToEtherpad("domline.js", "domline.js");
- copyFileToClientSide("domline.js", "domline_client.js");
- copyFileToClientSide("cssmanager.js", "cssmanager_client.js");
- }
- /*else if (! isNoHelma) {
- copyFile("build/ace2.js", "../helma_apps/appjet/protectedStatic/js/ace.js");
- }*/
-}
-
-def remakeLoop {
-
- def getStamp: Long = {
- return (new java.io.File("www").listFiles.
- filter(! _.getName.endsWith("~")).
- filter(! _.getName.endsWith("#")).
- filter(! _.getName.startsWith(".")).map(_.lastModified).
- reduceLeft(Math.max(_:Long,_:Long)));
- }
-
- var madeStamp:Long = 0;
- var errorStamp:Long = 0;
- while (true) {
- Thread.sleep(500);
- val s = getStamp;
- if (s > madeStamp && s != errorStamp) {
- Thread.sleep(1000);
- if (getStamp == s) {
- madeStamp = s;
- print("Remaking... ");
- try {
- doMake;
- println("OK");
- }
- catch { case e => {
- println("ERROR");
- errorStamp = s;
- } }
- }
- }
- }
-
-}
-
-if (args.length >= 1 && args(0) == "auto") {
- remakeLoop;
-}
-else {
- doMake;
-}
diff --git a/trunk/infrastructure/ace/www/ace2_inner.js b/trunk/infrastructure/ace/www/ace2_inner.js
deleted file mode 100644
index 8bd1096..0000000
--- a/trunk/infrastructure/ace/www/ace2_inner.js
+++ /dev/null
@@ -1,4817 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-function OUTER(gscope) {
-
- var DEBUG=true;//$$ build script replaces the string "var DEBUG=true;//$$" with "var DEBUG=false;"
-
- var isSetUp = false;
-
- var THE_TAB = ' ';//4
- var MAX_LIST_LEVEL = 8;
-
- var LINE_NUMBER_PADDING_RIGHT = 4;
- var LINE_NUMBER_PADDING_LEFT = 4;
- var MIN_LINEDIV_WIDTH = 20;
- var EDIT_BODY_PADDING_TOP = 8;
- var EDIT_BODY_PADDING_LEFT = 8;
-
- var caughtErrors = [];
-
- var thisAuthor = '';
-
- var disposed = false;
-
- var editorInfo = parent.editorInfo;
-
- var iframe = window.frameElement;
- var outerWin = iframe.ace_outerWin;
- iframe.ace_outerWin = null; // prevent IE 6 memory leak
- var sideDiv = iframe.nextSibling;
- var lineMetricsDiv = sideDiv.nextSibling;
- var overlaysdiv = lineMetricsDiv.nextSibling;
- initLineNumbers();
-
- var outsideKeyDown = function(evt) {};
- var outsideKeyPress = function(evt) { return true; };
- var outsideNotifyDirty = function() {};
-
- // selFocusAtStart -- determines whether the selection extends "backwards", so that the focus
- // point (controlled with the arrow keys) is at the beginning; not supported in IE, though
- // native IE selections have that behavior (which we try not to interfere with).
- // Must be false if selection is collapsed!
- var rep = { lines: newSkipList(), selStart: null, selEnd: null, selFocusAtStart: false,
- alltext: "", alines: [],
- apool: new AttribPool() };
- // lines, alltext, alines, and DOM are set up in setup()
- if (undoModule.enabled) {
- undoModule.apool = rep.apool;
- }
-
- var root, doc; // set in setup()
-
- var isEditable = true;
- var doesWrap = true;
- var hasLineNumbers = true;
- var isStyled = true;
-
- // space around the innermost iframe element
- var iframePadLeft = MIN_LINEDIV_WIDTH + LINE_NUMBER_PADDING_RIGHT + EDIT_BODY_PADDING_LEFT;
- var iframePadTop = EDIT_BODY_PADDING_TOP;
- var iframePadBottom = 0, iframePadRight = 0;
-
- var console = (DEBUG && top.console);
- if (! console) {
- var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
- "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
- console = {};
- for (var i = 0; i < names.length; ++i)
- console[names[i]] = function() {};
- //console.error = function(str) { alert(str); };
- }
- var PROFILER = window.PROFILER;
- if (!PROFILER) {
- PROFILER = function() { return {start:noop, mark:noop, literal:noop, end:noop, cancel:noop}; };
- }
- function noop() {}
- function identity(x) { return x; }
-
- // "dmesg" is for displaying messages in the in-page output pane
- // visible when "?djs=1" is appended to the pad URL. It generally
- // remains a no-op unless djs is enabled, but we make a habit of
- // only calling it in error cases or while debugging.
- var dmesg = noop;
- window.dmesg = noop;
-
- var scheduler = parent;
-
- var textFace = 'monospace';
- var textSize = 12;
- function textLineHeight() { return Math.round(textSize * 4/3); }
-
- var dynamicCSS = null;
- function initDynamicCSS() {
- dynamicCSS = makeCSSManager("dynamicsyntax");
- }
-
- var changesetTracker = makeChangesetTracker(scheduler, rep.apool, {
- withCallbacks: function(operationName, f) {
- inCallStackIfNecessary(operationName, function() {
- fastIncorp(1);
- f({
- setDocumentAttributedText: function(atext) {
- setDocAText(atext);
- },
- applyChangesetToDocument: function(changeset, preferInsertionAfterCaret) {
- var oldEventType = currentCallStack.editEvent.eventType;
- currentCallStack.startNewEvent("nonundoable");
-
- performDocumentApplyChangeset(changeset, preferInsertionAfterCaret);
-
- currentCallStack.startNewEvent(oldEventType);
- }
- });
- });
- }
- });
-
- var authorInfos = {}; // presence of key determines if author is present in doc
-
- function setAuthorInfo(author, info) {
- if ((typeof author) != "string") {
- throw new Error("setAuthorInfo: author ("+author+") is not a string");
- }
- if (! info) {
- delete authorInfos[author];
- if (dynamicCSS) {
- dynamicCSS.removeSelectorStyle(getAuthorColorClassSelector(getAuthorClassName(author)));
- }
- }
- else {
- authorInfos[author] = info;
- if (info.bgcolor) {
- if (dynamicCSS) {
- var bgcolor = info.bgcolor;
- if ((typeof info.fade) == "number") {
- bgcolor = fadeColor(bgcolor, info.fade);
- }
-
- dynamicCSS.selectorStyle(getAuthorColorClassSelector(
- getAuthorClassName(author))).backgroundColor = bgcolor;
- }
- }
- }
- }
-
- function getAuthorClassName(author) {
- return "author-"+author.replace(/[^a-y0-9]/g, function(c) {
- if (c == ".") return "-";
- return 'z'+c.charCodeAt(0)+'z';
- });
- }
- function className2Author(className) {
- if (className.substring(0,7) == "author-") {
- return className.substring(7).replace(/[a-y0-9]+|-|z.+?z/g, function(cc) {
- if (cc == '-') return '.';
- else if (cc.charAt(0) == 'z') {
- return String.fromCharCode(Number(cc.slice(1,-1)));
- }
- else {
- return cc;
- }
- });
- }
- return null;
- }
- function getAuthorColorClassSelector(oneClassName) {
- return ".authorColors ."+oneClassName;
- }
- function setUpTrackingCSS() {
- if (dynamicCSS) {
- var backgroundHeight = lineMetricsDiv.offsetHeight;
- var lineHeight = textLineHeight();
- var extraBodding = 0;
- var extraTodding = 0;
- if (backgroundHeight < lineHeight) {
- extraBodding = Math.ceil((lineHeight - backgroundHeight)/2);
- extraTodding = lineHeight - backgroundHeight - extraBodding;
- }
- var spanStyle = dynamicCSS.selectorStyle("#innerdocbody span");
- spanStyle.paddingTop = extraTodding+"px";
- spanStyle.paddingBottom = extraBodding+"px";
- }
- }
- function boldColorFromColor(lightColorCSS) {
- var color = colorutils.css2triple(lightColorCSS);
-
- // amp up the saturation to full
- color = colorutils.saturate(color);
-
- // normalize brightness based on luminosity
- color = colorutils.scaleColor(color, 0, 0.5 / colorutils.luminosity(color));
-
- return colorutils.triple2css(color);
- }
- function fadeColor(colorCSS, fadeFrac) {
- var color = colorutils.css2triple(colorCSS);
- color = colorutils.blend(color, [1,1,1], fadeFrac);
- return colorutils.triple2css(color);
- }
-
- function doAlert(str) {
- scheduler.setTimeout(function() { alert(str); }, 0);
- }
-
- var currentCallStack = null;
- function inCallStack(type, action) {
- if (disposed) return;
-
- if (currentCallStack) {
- console.error("Can't enter callstack "+type+", already in "+
- currentCallStack.type);
- }
-
- var profiling = false;
- function profileRest() {
- profiling = true;
- console.profile();
- }
-
- function newEditEvent(eventType) {
- return {eventType:eventType, backset: null};
- }
-
- function submitOldEvent(evt) {
- if (rep.selStart && rep.selEnd) {
- var selStartChar =
- rep.lines.offsetOfIndex(rep.selStart[0]) + rep.selStart[1];
- var selEndChar =
- rep.lines.offsetOfIndex(rep.selEnd[0]) + rep.selEnd[1];
- evt.selStart = selStartChar;
- evt.selEnd = selEndChar;
- evt.selFocusAtStart = rep.selFocusAtStart;
- }
- if (undoModule.enabled) {
- var undoWorked = false;
- try {
- if (evt.eventType == "setup" || evt.eventType == "importText" ||
- evt.eventType == "setBaseText") {
- undoModule.clearHistory();
- }
- else if (evt.eventType == "nonundoable") {
- if (evt.changeset) {
- undoModule.reportExternalChange(evt.changeset);
- }
- }
- else {
- undoModule.reportEvent(evt);
- }
- undoWorked = true;
- }
- finally {
- if (! undoWorked) {
- undoModule.enabled = false; // for safety
- }
- }
- }
- }
-
- function startNewEvent(eventType, dontSubmitOld) {
- var oldEvent = currentCallStack.editEvent;
- if (! dontSubmitOld) {
- submitOldEvent(oldEvent);
- }
- currentCallStack.editEvent = newEditEvent(eventType);
- return oldEvent;
- }
-
- currentCallStack = {type: type, docTextChanged: false, selectionAffected: false,
- userChangedSelection: false,
- domClean: false, profileRest:profileRest,
- isUserChange: false, // is this a "user change" type of call-stack
- repChanged: false, editEvent: newEditEvent(type),
- startNewEvent:startNewEvent};
- var cleanExit = false;
- var result;
- try {
- result = action();
- //console.log("Just did action for: "+type);
- cleanExit = true;
- }
- catch (e) {
- caughtErrors.push({error: e, time: +new Date()});
- dmesg(e.toString());
- throw e;
- }
- finally {
- var cs = currentCallStack;
- //console.log("Finished action for: "+type);
- if (cleanExit) {
- submitOldEvent(cs.editEvent);
- if (cs.domClean && cs.type != "setup") {
- if (cs.isUserChange) {
- if (cs.repChanged) parenModule.notifyChange();
- else parenModule.notifyTick();
- }
- recolorModule.recolorLines();
- if (cs.selectionAffected) {
- updateBrowserSelectionFromRep();
- }
- if ((cs.docTextChanged || cs.userChangedSelection) && cs.type != "applyChangesToBase") {
- scrollSelectionIntoView();
- }
- if (cs.docTextChanged && cs.type.indexOf("importText") < 0) {
- outsideNotifyDirty();
- }
- }
- }
- else {
- // non-clean exit
- if (currentCallStack.type == "idleWorkTimer") {
- idleWorkTimer.atLeast(1000);
- }
- }
- currentCallStack = null;
- if (profiling) console.profileEnd();
- }
- return result;
- }
-
- function inCallStackIfNecessary(type, action) {
- if (! currentCallStack) {
- inCallStack(type, action);
- }
- else {
- action();
- }
- }
-
- function recolorLineByKey(key) {
- if (rep.lines.containsKey(key)) {
- var offset = rep.lines.offsetOfKey(key);
- var width = rep.lines.atKey(key).width;
- recolorLinesInRange(offset, offset + width);
- }
- }
-
- function getLineKeyForOffset(charOffset) {
- return rep.lines.atOffset(charOffset).key;
- }
-
- var recolorModule = (function() {
- var dirtyLineKeys = {};
-
- var module = {};
- module.setCharNeedsRecoloring = function(offset) {
- if (offset >= rep.alltext.length) {
- offset = rep.alltext.length-1;
- }
- dirtyLineKeys[getLineKeyForOffset(offset)] = true;
- }
-
- module.setCharRangeNeedsRecoloring = function(offset1, offset2) {
- if (offset1 >= rep.alltext.length) {
- offset1 = rep.alltext.length-1;
- }
- if (offset2 >= rep.alltext.length) {
- offset2 = rep.alltext.length-1;
- }
- var firstEntry = rep.lines.atOffset(offset1);
- var lastKey = rep.lines.atOffset(offset2).key;
- dirtyLineKeys[lastKey] = true;
- var entry = firstEntry;
- while (entry && entry.key != lastKey) {
- dirtyLineKeys[entry.key] = true;
- entry = rep.lines.next(entry);
- }
- }
-
- module.recolorLines = function() {
- for(var k in dirtyLineKeys) {
- recolorLineByKey(k);
- }
- dirtyLineKeys = {};
- }
-
- return module;
- })();
-
- var parenModule = (function() {
- var module = {};
- module.notifyTick = function() { handleFlashing(false); };
- module.notifyChange = function() { handleFlashing(true); };
- module.shouldNormalizeOnChar = function (c) {
- if (parenFlashRep.active) {
- // avoid highlight style from carrying on to typed text
- return true;
- }
- c = String.fromCharCode(c);
- return !! (bracketMap[c]);
- }
-
- var parenFlashRep = { active: false, whichChars: null, whichLineKeys: null, expireTime: null };
- var bracketMap = {'(': 1, ')':-1, '[':2, ']':-2, '{':3, '}':-3};
- var bracketRegex = /[{}\[\]()]/g;
- function handleFlashing(docChanged) {
- function getSearchRange(aroundLoc) {
- var rng = getVisibleCharRange();
- var d = 100; // minimum radius
- var e = 3000; // maximum radius;
- if (rng[0] > aroundLoc-d) rng[0] = aroundLoc-d;
- if (rng[0] < aroundLoc-e) rng[0] = aroundLoc-e;
- if (rng[0] < 0) rng[0] = 0;
- if (rng[1] < aroundLoc+d) rng[1] = aroundLoc+d;
- if (rng[1] > aroundLoc+e) rng[1] = aroundLoc+e;
- if (rng[1] > rep.lines.totalWidth()) rng[1] = rep.lines.totalWidth();
- return rng;
- }
- function findMatchingVisibleBracket(startLoc, forwards) {
- var rng = getSearchRange(startLoc);
- var str = rep.alltext.substring(rng[0], rng[1]);
- var bstr = str.replace(bracketRegex, '('); // handy for searching
- var loc = startLoc - rng[0];
- var bracketState = [];
- var foundParen = false;
- var goodParen = false;
- function nextLoc() {
- if (loc < 0) return;
- if (forwards) loc++; else loc--;
- if (loc < 0 || loc >= str.length) loc = -1;
- if (loc >= 0) {
- if (forwards) loc = bstr.indexOf('(', loc);
- else loc = bstr.lastIndexOf('(', loc);
- }
- }
- while ((! foundParen) && (loc >= 0)) {
- if (getCharType(loc + rng[0]) == "p") {
- var b = bracketMap[str.charAt(loc)]; // -1, 1, -2, 2, -3, 3
- var into = forwards;
- var typ = b;
- if (typ < 0) { into = ! into; typ = -typ; }
- if (into) bracketState.push(typ);
- else {
- var recent = bracketState.pop();
- if (recent != typ) {
- foundParen = true; goodParen = false;
- }
- else if (bracketState.length == 0) {
- foundParen = true; goodParen = true;
- }
- }
- }
- //console.log(bracketState.toSource());
- if ((! foundParen) && (loc >= 0)) nextLoc();
- }
- if (! foundParen) return null;
- return {chr: (loc + rng[0]), good: goodParen};
- }
-
- var r = parenFlashRep;
- var charsToHighlight = null;
- var linesToUnhighlight = null;
- if (r.active && (docChanged || (now() > r.expireTime))) {
- linesToUnhighlight = r.whichLineKeys;
- r.active = false;
- }
- if ((! r.active) && docChanged && isCaret() && caretColumn() > 0) {
- var caret = caretDocChar();
- if (caret > 0 && getCharType(caret-1) == "p") {
- var charBefore = rep.alltext.charAt(caret-1);
- if (bracketMap[charBefore]) {
- var lookForwards = (bracketMap[charBefore] > 0);
- var findResult = findMatchingVisibleBracket(caret-1, lookForwards);
- if (findResult) {
- var mateLoc = findResult.chr;
- var mateGood = findResult.good;
- r.active = true;
- charsToHighlight = {};
- charsToHighlight[caret-1] = 'flash';
- charsToHighlight[mateLoc] = (mateGood ? 'flash' : 'flashbad');
- r.whichLineKeys = [];
- r.whichLineKeys.push(getLineKeyForOffset(caret-1));
- r.whichLineKeys.push(getLineKeyForOffset(mateLoc));
- r.expireTime = now() + 4000;
- newlyActive = true;
- }
- }
- }
-
- }
- if (linesToUnhighlight) {
- recolorLineByKey(linesToUnhighlight[0]);
- recolorLineByKey(linesToUnhighlight[1]);
- }
- if (r.active && charsToHighlight) {
- function f(txt, cls, next, ofst) {
- var flashClass = charsToHighlight[ofst];
- if (cls) {
- next(txt, cls+" "+flashClass);
- }
- else next(txt, cls);
- }
- for(var c in charsToHighlight) {
- recolorLinesInRange((+c), (+c)+1, null, f);
- }
- }
- }
-
- return module;
- })();
-
- function dispose() {
- disposed = true;
- if (idleWorkTimer) idleWorkTimer.never();
- teardown();
- }
-
- function checkALines() {
- return; // disable for speed
- function error() { throw new Error("checkALines"); }
- if (rep.alines.length != rep.lines.length()) {
- error();
- }
- for(var i=0;i<rep.alines.length;i++) {
- var aline = rep.alines[i];
- var lineText = rep.lines.atIndex(i).text+"\n";
- var lineTextLength = lineText.length;
- var opIter = Changeset.opIterator(aline);
- var alineLength = 0;
- while (opIter.hasNext()) {
- var o = opIter.next();
- alineLength += o.chars;
- if (opIter.hasNext()) {
- if (o.lines != 0) error();
- }
- else {
- if (o.lines != 1) error();
- }
- }
- if (alineLength != lineTextLength) {
- error();
- }
- }
- }
-
- function setWraps(newVal) {
- doesWrap = newVal;
- var dwClass = "doesWrap";
- setClassPresence(root, "doesWrap", doesWrap);
- scheduler.setTimeout(function() {
- inCallStackIfNecessary("setWraps", function() {
- fastIncorp(7);
- recreateDOM();
- fixView();
- });
- }, 0);
- }
-
- function setStyled(newVal) {
- var oldVal = isStyled;
- isStyled = !!newVal;
-
- if (newVal != oldVal) {
- if (! newVal) {
- // clear styles
- inCallStackIfNecessary("setStyled", function() {
- fastIncorp(12);
- var clearStyles = [];
- for(var k in STYLE_ATTRIBS) {
- clearStyles.push([k,'']);
- }
- performDocumentApplyAttributesToCharRange(0, rep.alltext.length, clearStyles);
- });
- }
- }
- }
-
- function setTextFace(face) {
- textFace = face;
- root.style.fontFamily = textFace;
- lineMetricsDiv.style.fontFamily = textFace;
- scheduler.setTimeout(function() {
- setUpTrackingCSS();
- }, 0);
- }
-
- function setTextSize(size) {
- textSize = size;
- root.style.fontSize = textSize+"px";
- root.style.lineHeight = textLineHeight()+"px";
- sideDiv.style.lineHeight = textLineHeight()+"px";
- lineMetricsDiv.style.fontSize = textSize+"px";
- scheduler.setTimeout(function() {
- setUpTrackingCSS();
- }, 0);
- }
-
- function recreateDOM() {
- // precond: normalized
- recolorLinesInRange(0, rep.alltext.length);
- }
-
- function setEditable(newVal) {
- isEditable = newVal;
-
- // the following may fail, e.g. if iframe is hidden
- if (! isEditable) {
- setDesignMode(false);
- }
- else {
- setDesignMode(true);
- }
- setClassPresence(root, "static", ! isEditable);
- }
-
- function enforceEditability() {
- setEditable(isEditable);
- }
-
- function importText(text, undoable, dontProcess) {
- var lines;
- if (dontProcess) {
- if (text.charAt(text.length-1) != "\n") {
- throw new Error("new raw text must end with newline");
- }
- if (/[\r\t\xa0]/.exec(text)) {
- throw new Error("new raw text must not contain CR, tab, or nbsp");
- }
- lines = text.substring(0, text.length-1).split('\n');
- }
- else {
- lines = map(text.split('\n'), textify);
- }
- var newText = "\n";
- if (lines.length > 0) {
- newText = lines.join('\n')+'\n';
- }
-
- inCallStackIfNecessary("importText"+(undoable?"Undoable":""), function() {
- setDocText(newText);
- });
-
- if (dontProcess && rep.alltext != text) {
- throw new Error("mismatch error setting raw text in importText");
- }
- }
-
- function importAText(atext, apoolJsonObj, undoable) {
- atext = Changeset.cloneAText(atext);
- if (apoolJsonObj) {
- var wireApool = (new AttribPool()).fromJsonable(apoolJsonObj);
- atext.attribs = Changeset.moveOpsToNewPool(atext.attribs, wireApool, rep.apool);
- }
- inCallStackIfNecessary("importText"+(undoable?"Undoable":""), function() {
- setDocAText(atext);
- });
- }
-
- function setDocAText(atext) {
- fastIncorp(8);
-
- var oldLen = rep.lines.totalWidth();
- var numLines = rep.lines.length();
- var upToLastLine = rep.lines.offsetOfIndex(numLines-1);
- var lastLineLength = rep.lines.atIndex(numLines-1).text.length;
- var assem = Changeset.smartOpAssembler();
- var o = Changeset.newOp('-');
- o.chars = upToLastLine;
- o.lines = numLines-1;
- assem.append(o);
- o.chars = lastLineLength;
- o.lines = 0;
- assem.append(o);
- Changeset.appendATextToAssembler(atext, assem);
- var newLen = oldLen + assem.getLengthChange();
- var changeset = Changeset.checkRep(
- Changeset.pack(oldLen, newLen, assem.toString(),
- atext.text.slice(0, -1)));
- performDocumentApplyChangeset(changeset);
-
- performSelectionChange([0,rep.lines.atIndex(0).lineMarker],
- [0,rep.lines.atIndex(0).lineMarker]);
-
- idleWorkTimer.atMost(100);
-
- if (rep.alltext != atext.text) {
- dmesg(htmlPrettyEscape(rep.alltext));
- dmesg(htmlPrettyEscape(atext.text));
- throw new Error("mismatch error setting raw text in setDocAText");
- }
- }
-
- function setDocText(text) {
- setDocAText(Changeset.makeAText(text));
- }
-
- function getDocText() {
- var alltext = rep.alltext;
- var len = alltext.length;
- if (len > 0) len--; // final extra newline
- return alltext.substring(0, len);
- }
-
- function exportText() {
- if (currentCallStack && ! currentCallStack.domClean) {
- inCallStackIfNecessary("exportText", function() { fastIncorp(2); });
- }
- return getDocText();
- }
-
- function editorChangedSize() {
- fixView();
- }
-
- function setOnKeyPress(handler) {
- outsideKeyPress = handler;
- }
-
- function setOnKeyDown(handler) {
- outsideKeyDown = handler;
- }
-
- function setNotifyDirty(handler) {
- outsideNotifyDirty = handler;
- }
-
- function getFormattedCode() {
- if (currentCallStack && ! currentCallStack.domClean) {
- inCallStackIfNecessary("getFormattedCode", incorporateUserChanges);
- }
- var buf = [];
- if (rep.lines.length() > 0) {
- // should be the case, even for empty file
- var entry = rep.lines.atIndex(0);
- while (entry) {
- var domInfo = entry.domInfo;
- buf.push((domInfo && domInfo.getInnerHTML()) ||
- domline.processSpaces(domline.escapeHTML(entry.text),
- doesWrap) ||
- '&nbsp;' /*empty line*/);
- entry = rep.lines.next(entry);
- }
- }
- return '<div class="syntax"><div>'+buf.join('</div>\n<div>')+
- '</div></div>';
- }
-
- var CMDS = {
- bold: function() { toggleAttributeOnSelection('bold'); },
- italic: function() { toggleAttributeOnSelection('italic'); },
- underline: function() { toggleAttributeOnSelection('underline'); },
- strikethrough: function() { toggleAttributeOnSelection('strikethrough'); },
- h1: function() { toggleAttributeOnSelection('h1'); },
- h2: function() { toggleAttributeOnSelection('h2'); },
- h3: function() { toggleAttributeOnSelection('h3'); },
- h4: function() { toggleAttributeOnSelection('h4'); },
- h5: function() { toggleAttributeOnSelection('h5'); },
- h6: function() { toggleAttributeOnSelection('h6'); },
- undo: function() { doUndoRedo('undo'); },
- redo: function() { doUndoRedo('redo'); },
- clearauthorship: function(prompt) {
- if ((!(rep.selStart && rep.selEnd)) || isCaret()) {
- if (prompt) {
- prompt();
- }
- else {
- performDocumentApplyAttributesToCharRange(0, rep.alltext.length,
- [['author', '']]);
- }
- }
- else {
- setAttributeOnSelection('author', '');
- }
- },
- insertunorderedlist: doInsertUnorderedList,
- indent: function() {
- if (! doIndentOutdent(false)) {
- doInsertUnorderedList();
- }
- },
- outdent: function() { doIndentOutdent(true); }
- };
-
- function execCommand(cmd) {
- cmd = cmd.toLowerCase();
- var cmdArgs = Array.prototype.slice.call(arguments, 1);
- if (CMDS[cmd]) {
- inCallStack(cmd, function() {
- fastIncorp(9);
- CMDS[cmd].apply(CMDS, cmdArgs);
- });
- }
- }
-
- editorInfo.ace_focus = focus;
- editorInfo.ace_importText = importText;
- editorInfo.ace_importAText = importAText;
- editorInfo.ace_exportText = exportText;
- editorInfo.ace_editorChangedSize = editorChangedSize;
- editorInfo.ace_setOnKeyPress = setOnKeyPress;
- editorInfo.ace_setOnKeyDown = setOnKeyDown;
- editorInfo.ace_setNotifyDirty = setNotifyDirty;
- editorInfo.ace_dispose = dispose;
- editorInfo.ace_getFormattedCode = getFormattedCode;
- editorInfo.ace_setEditable = setEditable;
- editorInfo.ace_execCommand = execCommand;
-
- editorInfo.ace_setProperty = function(key, value) {
- var k = key.toLowerCase();
- if (k == "wraps") {
- setWraps(value);
- }
- else if (k == "showsauthorcolors") {
- setClassPresence(root, "authorColors", !!value);
- }
- else if (k == "showsuserselections") {
- setClassPresence(root, "userSelections", !!value);
- }
- else if (k == "showslinenumbers") {
- hasLineNumbers = !!value;
- setClassPresence(sideDiv, "sidedivhidden", ! hasLineNumbers);
- fixView();
- }
- else if (k == "grayedout") {
- setClassPresence(outerWin.document.body, "grayedout", !!value);
- }
- else if (k == "dmesg") {
- dmesg = value;
- window.dmesg = value;
- }
- else if (k == 'userauthor') {
- thisAuthor = String(value);
- }
- else if (k == 'styled') {
- setStyled(value);
- }
- else if (k == 'textface') {
- setTextFace(value);
- }
- else if (k == 'textsize') {
- setTextSize(value);
- }
- }
-
- editorInfo.ace_setBaseText = function(txt) {
- changesetTracker.setBaseText(txt);
- };
- editorInfo.ace_setBaseAttributedText = function(atxt, apoolJsonObj) {
- setUpTrackingCSS();
- changesetTracker.setBaseAttributedText(atxt, apoolJsonObj);
- };
- editorInfo.ace_applyChangesToBase = function(c, optAuthor, apoolJsonObj) {
- changesetTracker.applyChangesToBase(c, optAuthor, apoolJsonObj);
- };
- editorInfo.ace_prepareUserChangeset = function() {
- return changesetTracker.prepareUserChangeset();
- };
- editorInfo.ace_applyPreparedChangesetToBase = function() {
- changesetTracker.applyPreparedChangesetToBase();
- };
- editorInfo.ace_setUserChangeNotificationCallback = function(f) {
- changesetTracker.setUserChangeNotificationCallback(f);
- };
- editorInfo.ace_setAuthorInfo = function(author, info) {
- setAuthorInfo(author, info);
- };
- editorInfo.ace_setAuthorSelectionRange = function(author, start, end) {
- changesetTracker.setAuthorSelectionRange(author, start, end);
- };
-
- editorInfo.ace_getUnhandledErrors = function() {
- return caughtErrors.slice();
- };
-
- editorInfo.ace_getDebugProperty = function(prop) {
- if (prop == "debugger") {
- // obfuscate "eval" so as not to scare yuicompressor
- window['ev'+'al']("debugger");
- }
- else if (prop == "rep") {
- return rep;
- }
- else if (prop == "window") {
- return window;
- }
- else if (prop == "document") {
- return document;
- }
- return undefined;
- };
-
- function now() { return (new Date()).getTime(); }
-
- function newTimeLimit(ms) {
- //console.debug("new time limit");
- var startTime = now();
- var lastElapsed = 0;
- var exceededAlready = false;
- var printedTrace = false;
- var isTimeUp = function () {
- if (exceededAlready) {
- if ((! printedTrace)) {// && now() - startTime - ms > 300) {
- //console.trace();
- printedTrace = true;
- }
- return true;
- }
- var elapsed = now() - startTime;
- if (elapsed > ms) {
- exceededAlready = true;
- //console.debug("time limit hit, before was %d/%d", lastElapsed, ms);
- //console.trace();
- return true;
- }
- else {
- lastElapsed = elapsed;
- return false;
- }
- }
- isTimeUp.elapsed = function() { return now() - startTime; }
- return isTimeUp;
- }
-
-
- function makeIdleAction(func) {
- var scheduledTimeout = null;
- var scheduledTime = 0;
- function unschedule() {
- if (scheduledTimeout) {
- scheduler.clearTimeout(scheduledTimeout);
- scheduledTimeout = null;
- }
- }
- function reschedule(time) {
- unschedule();
- scheduledTime = time;
- var delay = time - now();
- if (delay < 0) delay = 0;
- scheduledTimeout = scheduler.setTimeout(callback, delay);
- }
- function callback() {
- scheduledTimeout = null;
- // func may reschedule the action
- func();
- }
- return {
- atMost: function (ms) {
- var latestTime = now() + ms;
- if ((! scheduledTimeout) || scheduledTime > latestTime) {
- reschedule(latestTime);
- }
- },
- // atLeast(ms) will schedule the action if not scheduled yet.
- // In other words, "infinity" is replaced by ms, even though
- // it is technically larger.
- atLeast: function (ms) {
- var earliestTime = now()+ms;
- if ((! scheduledTimeout) || scheduledTime < earliestTime) {
- reschedule(earliestTime);
- }
- },
- never: function() {
- unschedule();
- }
- }
- }
-
- function fastIncorp(n) {
- // normalize but don't do any lexing or anything
- incorporateUserChanges(newTimeLimit(0));
- }
-
- function incorpIfQuick() {
- var me = incorpIfQuick;
- var failures = (me.failures || 0);
- if (failures < 5) {
- var isTimeUp = newTimeLimit(40);
- var madeChanges = incorporateUserChanges(isTimeUp);
- if (isTimeUp()) {
- me.failures = failures+1;
- }
- return true;
- }
- else {
- var skipCount = (me.skipCount || 0);
- skipCount++;
- if (skipCount == 20) {
- skipCount = 0;
- me.failures = 0;
- }
- me.skipCount = skipCount;
- }
- return false;
- }
-
- var idleWorkTimer = makeIdleAction(function() {
-
- //if (! top.BEFORE) top.BEFORE = [];
- //top.BEFORE.push(magicdom.root.dom.innerHTML);
-
- if (! isEditable) return; // and don't reschedule
-
- if (inInternationalComposition) {
- // don't do idle input incorporation during international input composition
- idleWorkTimer.atLeast(500);
- return;
- }
-
- inCallStack("idleWorkTimer", function() {
-
- var isTimeUp = newTimeLimit(250);
-
- //console.time("idlework");
-
- var finishedImportantWork = false;
- var finishedWork = false;
-
- try {
-
- // isTimeUp() is a soft constraint for incorporateUserChanges,
- // which always renormalizes the DOM, no matter how long it takes,
- // but doesn't necessarily lex and highlight it
- incorporateUserChanges(isTimeUp);
-
- if (isTimeUp()) return;
-
- updateLineNumbers(); // update line numbers if any time left
-
- if (isTimeUp()) return;
-
- var visibleRange = getVisibleCharRange();
- var docRange = [0, rep.lines.totalWidth()];
- //console.log("%o %o", docRange, visibleRange);
-
- finishedImportantWork = true;
- finishedWork = true;
- }
- finally {
- //console.timeEnd("idlework");
- if (finishedWork) {
- idleWorkTimer.atMost(1000);
- }
- else if (finishedImportantWork) {
- // if we've finished highlighting the view area,
- // more highlighting could be counter-productive,
- // e.g. if the user just opened a triple-quote and will soon close it.
- idleWorkTimer.atMost(500);
- }
- else {
- var timeToWait = Math.round(isTimeUp.elapsed() / 2);
- if (timeToWait < 100) timeToWait = 100;
- idleWorkTimer.atMost(timeToWait);
- }
- }
- });
-
- //if (! top.AFTER) top.AFTER = [];
- //top.AFTER.push(magicdom.root.dom.innerHTML);
-
- });
-
- var _nextId = 1;
- function uniqueId(n) {
- // not actually guaranteed to be unique, e.g. if user copy-pastes
- // nodes with ids
- var nid = n.id;
- if (nid) return nid;
- return (n.id = "magicdomid"+(_nextId++));
- }
-
-
- function recolorLinesInRange(startChar, endChar, isTimeUp, optModFunc) {
- if (endChar <= startChar) return;
- if (startChar < 0 || startChar >= rep.lines.totalWidth()) return;
- var lineEntry = rep.lines.atOffset(startChar); // rounds down to line boundary
- var lineStart = rep.lines.offsetOfEntry(lineEntry);
- var lineIndex = rep.lines.indexOfEntry(lineEntry);
- var selectionNeedsResetting = false;
- var firstLine = null;
- var lastLine = null;
- isTimeUp = (isTimeUp || noop);
-
- // tokenFunc function; accesses current value of lineEntry and curDocChar,
- // also mutates curDocChar
- var curDocChar;
- var tokenFunc = function(tokenText, tokenClass) {
- lineEntry.domInfo.appendSpan(tokenText, tokenClass);
- };
- if (optModFunc) {
- var f = tokenFunc;
- tokenFunc = function(tokenText, tokenClass) {
- optModFunc(tokenText, tokenClass, f, curDocChar);
- curDocChar += tokenText.length;
- };
- }
-
- while (lineEntry && lineStart < endChar && ! isTimeUp()) {
- //var timer = newTimeLimit(200);
- var lineEnd = lineStart + lineEntry.width;
-
- curDocChar = lineStart;
- lineEntry.domInfo.clearSpans();
- getSpansForLine(lineEntry, tokenFunc, lineStart);
- lineEntry.domInfo.finishUpdate();
-
- markNodeClean(lineEntry.lineNode);
-
- if (rep.selStart && rep.selStart[0] == lineIndex ||
- rep.selEnd && rep.selEnd[0] == lineIndex) {
- selectionNeedsResetting = true;
- }
-
- //if (timer()) console.dirxml(lineEntry.lineNode.dom);
-
- if (firstLine === null) firstLine = lineIndex;
- lastLine = lineIndex;
- lineStart = lineEnd;
- lineEntry = rep.lines.next(lineEntry);
- lineIndex++;
- }
- if (selectionNeedsResetting) {
- currentCallStack.selectionAffected = true;
- }
- //console.debug("Recolored line range %d-%d", firstLine, lastLine);
- }
-
- // like getSpansForRange, but for a line, and the func takes (text,class)
- // instead of (width,class); excludes the trailing '\n' from
- // consideration by func
- function getSpansForLine(lineEntry, textAndClassFunc, lineEntryOffsetHint) {
- var lineEntryOffset = lineEntryOffsetHint;
- if ((typeof lineEntryOffset) != "number") {
- lineEntryOffset = rep.lines.offsetOfEntry(lineEntry);
- }
- var text = lineEntry.text;
- var width = lineEntry.width; // text.length+1
-
- if (text.length == 0) {
- // allow getLineStyleFilter to set line-div styles
- var func = linestylefilter.getLineStyleFilter(
- 0, '', textAndClassFunc, rep.apool);
- func('', '');
- }
- else {
- var offsetIntoLine = 0;
- var filteredFunc = textAndClassFunc;
- filteredFunc = linestylefilter.getURLFilter(text, filteredFunc);
- if (browser.msie) {
- // IE7+ will take an e-mail address like <foo@bar.com> and linkify it to foo@bar.com.
- // We then normalize it back to text with no angle brackets. It's weird. So always
- // break spans at an "at" sign.
- filteredFunc = linestylefilter.getAtSignSplitterFilter(
- text, filteredFunc);
- }
- var lineNum = rep.lines.indexOfEntry(lineEntry);
- var aline = rep.alines[lineNum];
- filteredFunc = linestylefilter.getLineStyleFilter(
- text.length, aline, filteredFunc, rep.apool);
- filteredFunc(text, '');
- }
- }
-
-
- function getCharType(charIndex) {
- return '';
- }
-
- var observedChanges;
- function clearObservedChanges() {
- observedChanges = { cleanNodesNearChanges: {} };
- }
- clearObservedChanges();
-
- function getCleanNodeByKey(key) {
- var p = PROFILER("getCleanNodeByKey", false);
- p.extra = 0;
- var n = doc.getElementById(key);
- // copying and pasting can lead to duplicate ids
- while (n && isNodeDirty(n)) {
- p.extra++;
- n.id = "";
- n = doc.getElementById(key);
- }
- p.literal(p.extra, "extra");
- p.end();
- return n;
- }
-
- function observeChangesAroundNode(node) {
- // Around this top-level DOM node, look for changes to the document
- // (from how it looks in our representation) and record them in a way
- // that can be used to "normalize" the document (apply the changes to our
- // representation, and put the DOM in a canonical form).
-
- //top.console.log("observeChangesAroundNode(%o)", node);
-
- var cleanNode;
- var hasAdjacentDirtyness;
- if (! isNodeDirty(node)) {
- cleanNode = node;
- var prevSib = cleanNode.previousSibling;
- var nextSib = cleanNode.nextSibling;
- hasAdjacentDirtyness = ((prevSib && isNodeDirty(prevSib))
- || (nextSib && isNodeDirty(nextSib)));
- }
- else {
- // node is dirty, look for clean node above
- var upNode = node.previousSibling;
- while (upNode && isNodeDirty(upNode)) {
- upNode = upNode.previousSibling;
- }
- if (upNode) {
- cleanNode = upNode;
- }
- else {
- var downNode = node.nextSibling;
- while (downNode && isNodeDirty(downNode)) {
- downNode = downNode.nextSibling;
- }
- if (downNode) {
- cleanNode = downNode;
- }
- }
- if (! cleanNode) {
- // Couldn't find any adjacent clean nodes!
- // Since top and bottom of doc is dirty, the dirty area will be detected.
- return;
- }
- hasAdjacentDirtyness = true;
- }
-
- if (hasAdjacentDirtyness) {
- // previous or next line is dirty
- observedChanges.cleanNodesNearChanges['$'+uniqueId(cleanNode)] = true;
- }
- else {
- // next and prev lines are clean (if they exist)
- var lineKey = uniqueId(cleanNode);
- var prevSib = cleanNode.previousSibling;
- var nextSib = cleanNode.nextSibling;
- var actualPrevKey = ((prevSib && uniqueId(prevSib)) || null);
- var actualNextKey = ((nextSib && uniqueId(nextSib)) || null);
- var repPrevEntry = rep.lines.prev(rep.lines.atKey(lineKey));
- var repNextEntry = rep.lines.next(rep.lines.atKey(lineKey));
- var repPrevKey = ((repPrevEntry && repPrevEntry.key) || null);
- var repNextKey = ((repNextEntry && repNextEntry.key) || null);
- if (actualPrevKey != repPrevKey || actualNextKey != repNextKey) {
- observedChanges.cleanNodesNearChanges['$'+uniqueId(cleanNode)] = true;
- }
- }
- }
-
- function observeChangesAroundSelection() {
- if (currentCallStack.observedSelection) return;
- currentCallStack.observedSelection = true;
-
- var p = PROFILER("getSelection", false);
- var selection = getSelection();
- p.end();
- if (selection) {
- function topLevel(n) {
- if ((!n) || n == root) return null;
- while (n.parentNode != root) {
- n = n.parentNode;
- }
- return n;
- }
- var node1 = topLevel(selection.startPoint.node);
- var node2 = topLevel(selection.endPoint.node);
- if (node1) observeChangesAroundNode(node1);
- if (node2 && node1 != node2) {
- observeChangesAroundNode(node2);
- }
- }
- }
-
- function observeSuspiciousNodes() {
- // inspired by Firefox bug #473255, where pasting formatted text
- // causes the cursor to jump away, making the new HTML never found.
- if (root.getElementsByTagName) {
- var nds = root.getElementsByTagName("style");
- for(var i=0;i<nds.length;i++) {
- var n = nds[i];
- while (n.parentNode && n.parentNode != root) {
- n = n.parentNode;
- }
- if (n.parentNode == root) {
- observeChangesAroundNode(n);
- }
- }
- }
- }
-
- function incorporateUserChanges(isTimeUp) {
-
- if (currentCallStack.domClean) return false;
-
- inInternationalComposition = false; // if we need the document normalized, so be it
-
- currentCallStack.isUserChange = true;
-
- isTimeUp = (isTimeUp || function() { return false; });
-
- if (DEBUG && top.DONT_INCORP || window.DEBUG_DONT_INCORP) return false;
-
- var p = PROFILER("incorp", false);
-
- //if (doc.body.innerHTML.indexOf("AppJet") >= 0)
- //dmesg(htmlPrettyEscape(doc.body.innerHTML));
- //if (top.RECORD) top.RECORD.push(doc.body.innerHTML);
-
- // returns true if dom changes were made
-
- if (! root.firstChild) {
- root.innerHTML = "<div><!-- --></div>";
- }
-
- p.mark("obs");
- observeChangesAroundSelection();
- observeSuspiciousNodes();
- p.mark("dirty");
- var dirtyRanges = getDirtyRanges();
- //console.log("dirtyRanges: "+toSource(dirtyRanges));
-
- var dirtyRangesCheckOut = true;
- var j = 0;
- var a,b;
- while (j < dirtyRanges.length) {
- a = dirtyRanges[j][0];
- b = dirtyRanges[j][1];
- if (! ((a == 0 || getCleanNodeByKey(rep.lines.atIndex(a-1).key)) &&
- (b == rep.lines.length() || getCleanNodeByKey(rep.lines.atIndex(b).key)))) {
- dirtyRangesCheckOut = false;
- break;
- }
- j++;
- }
- if (! dirtyRangesCheckOut) {
- var numBodyNodes = root.childNodes.length;
- for(var k=0;k<numBodyNodes;k++) {
- var bodyNode = root.childNodes.item(k);
- if ((bodyNode.tagName) && ((! bodyNode.id) || (! rep.lines.containsKey(bodyNode.id)))) {
- observeChangesAroundNode(bodyNode);
- }
- }
- dirtyRanges = getDirtyRanges();
- }
-
- clearObservedChanges();
-
- p.mark("getsel");
- var selection = getSelection();
-
- //console.log(magicdom.root.dom.innerHTML);
- //console.log("got selection: %o", selection);
- var selStart, selEnd; // each one, if truthy, has [line,char] needed to set selection
-
- var i = 0;
- var splicesToDo = [];
- var netNumLinesChangeSoFar = 0;
- var toDeleteAtEnd = [];
- p.mark("ranges");
- p.literal(dirtyRanges.length, "numdirt");
- var domInsertsNeeded = []; // each entry is [nodeToInsertAfter, [info1, info2, ...]]
- while (i < dirtyRanges.length) {
- var range = dirtyRanges[i];
- a = range[0];
- b = range[1];
- var firstDirtyNode = (((a == 0) && root.firstChild) ||
- getCleanNodeByKey(rep.lines.atIndex(a-1).key).nextSibling);
- firstDirtyNode = (firstDirtyNode && isNodeDirty(firstDirtyNode) && firstDirtyNode);
- var lastDirtyNode = (((b == rep.lines.length()) && root.lastChild) ||
- getCleanNodeByKey(rep.lines.atIndex(b).key).previousSibling);
- lastDirtyNode = (lastDirtyNode && isNodeDirty(lastDirtyNode) && lastDirtyNode);
- if (firstDirtyNode && lastDirtyNode) {
- var cc = makeContentCollector(isStyled, browser, rep.apool, null,
- className2Author);
- cc.notifySelection(selection);
- var dirtyNodes = [];
- for(var n = firstDirtyNode; n && ! (n.previousSibling &&
- n.previousSibling == lastDirtyNode);
- n = n.nextSibling) {
- if (browser.msie) {
- // try to undo IE's pesky and overzealous linkification
- try { n.createTextRange().execCommand("unlink", false, null); }
- catch (e) {}
- }
- cc.collectContent(n);
- dirtyNodes.push(n);
- }
- cc.notifyNextNode(lastDirtyNode.nextSibling);
- var lines = cc.getLines();
- if ((lines.length <= 1 || lines[lines.length-1] !== "")
- && lastDirtyNode.nextSibling) {
- // dirty region doesn't currently end a line, even taking the following node
- // (or lack of node) into account, so include the following clean node.
- // It could be SPAN or a DIV; basically this is any case where the contentCollector
- // decides it isn't done.
- // Note that this clean node might need to be there for the next dirty range.
- //console.log("inclusive of "+lastDirtyNode.next().dom.tagName);
- b++;
- var cleanLine = lastDirtyNode.nextSibling;
- cc.collectContent(cleanLine);
- toDeleteAtEnd.push(cleanLine);
- cc.notifyNextNode(cleanLine.nextSibling);
- }
-
- var ccData = cc.finish();
- var ss = ccData.selStart;
- var se = ccData.selEnd;
- lines = ccData.lines;
- var lineAttribs = ccData.lineAttribs;
- var linesWrapped = ccData.linesWrapped;
-
- if (linesWrapped > 0) {
- doAlert("Editor warning: "+linesWrapped+" long line"+
- (linesWrapped == 1 ? " was" : "s were")+" hard-wrapped into "+
- ccData.numLinesAfter
- +" lines.");
- }
-
- if (ss[0] >= 0) selStart = [ss[0]+a+netNumLinesChangeSoFar, ss[1]];
- if (se[0] >= 0) selEnd = [se[0]+a+netNumLinesChangeSoFar, se[1]];
-
- /*var oldLines = rep.alltext.substring(rep.lines.offsetOfIndex(a),
- rep.lines.offsetOfIndex(b));
- var newLines = lines.join('\n')+'\n';
- dmesg("OLD: "+htmlPrettyEscape(oldLines));
- dmesg("NEW: "+htmlPrettyEscape(newLines));*/
-
- var entries = [];
- var nodeToAddAfter = lastDirtyNode;
- var lineNodeInfos = new Array(lines.length);
- for(var k=0;k<lines.length;k++) {
- var lineString = lines[k];
- var newEntry = createDomLineEntry(lineString);
- entries.push(newEntry);
- lineNodeInfos[k] = newEntry.domInfo;
- }
- //var fragment = magicdom.wrapDom(document.createDocumentFragment());
- domInsertsNeeded.push([nodeToAddAfter, lineNodeInfos]);
- forEach(dirtyNodes, function (n) { toDeleteAtEnd.push(n); });
- var spliceHints = {};
- if (selStart) spliceHints.selStart = selStart;
- if (selEnd) spliceHints.selEnd = selEnd;
- splicesToDo.push([a+netNumLinesChangeSoFar, b-a, entries, lineAttribs, spliceHints]);
- netNumLinesChangeSoFar += (lines.length - (b-a));
- }
- else if (b > a) {
- splicesToDo.push([a+netNumLinesChangeSoFar, b-a, [], []]);
- }
- i++;
- }
-
- var domChanges = (splicesToDo.length > 0);
-
- // update the representation
- p.mark("splice");
- forEach(splicesToDo, function (splice) {
- doIncorpLineSplice(splice[0], splice[1], splice[2], splice[3], splice[4]);
- });
-
- //p.mark("relex");
- //rep.lexer.lexCharRange(getVisibleCharRange(), function() { return false; });
- //var isTimeUp = newTimeLimit(100);
-
- // do DOM inserts
- p.mark("insert");
- forEach(domInsertsNeeded, function (ins) {
- insertDomLines(ins[0], ins[1], isTimeUp);
- });
-
- p.mark("del");
- // delete old dom nodes
- forEach(toDeleteAtEnd, function (n) {
- //var id = n.uniqueId();
-
- // parent of n may not be "root" in IE due to non-tree-shaped DOM (wtf)
- n.parentNode.removeChild(n);
-
- //dmesg(htmlPrettyEscape(htmlForRemovedChild(n)));
- //console.log("removed: "+id);
- });
-
- p.mark("findsel");
- // if the nodes that define the selection weren't encountered during
- // content collection, figure out where those nodes are now.
- if (selection && !selStart) {
- //if (domChanges) dmesg("selection not collected");
- selStart = getLineAndCharForPoint(selection.startPoint);
- }
- if (selection && !selEnd) {
- selEnd = getLineAndCharForPoint(selection.endPoint);
- }
-
- // selection from content collection can, in various ways, extend past final
- // BR in firefox DOM, so cap the line
- var numLines = rep.lines.length();
- if (selStart && selStart[0] >= numLines) {
- selStart[0] = numLines-1;
- selStart[1] = rep.lines.atIndex(selStart[0]).text.length;
- }
- if (selEnd && selEnd[0] >= numLines) {
- selEnd[0] = numLines-1;
- selEnd[1] = rep.lines.atIndex(selEnd[0]).text.length;
- }
-
- p.mark("repsel");
- // update rep
- repSelectionChange(selStart, selEnd, selection && selection.focusAtStart);
- // update browser selection
- p.mark("browsel");
- if (selection && (domChanges || isCaret())) {
- // if no DOM changes (not this case), want to treat range selection delicately,
- // e.g. in IE not lose which end of the selection is the focus/anchor;
- // on the other hand, we may have just noticed a press of PageUp/PageDown
- currentCallStack.selectionAffected = true;
- }
-
- currentCallStack.domClean = true;
-
- p.mark("fixview");
-
- fixView();
-
- p.end("END");
-
- return domChanges;
- }
-
- function htmlForRemovedChild(n) {
- var div = doc.createElement("DIV");
- div.appendChild(n);
- return div.innerHTML;
- }
-
- var STYLE_ATTRIBS = {bold: true, italic: true, underline: true,
- strikethrough: true, h1: true, h2: true,
- h3: true, h4: true, h5: true, h6: true,
- list: true};
- var OTHER_INCORPED_ATTRIBS = {insertorder: true, author: true};
-
- function isStyleAttribute(aname) {
- return !! STYLE_ATTRIBS[aname];
- }
- function isIncorpedAttribute(aname) {
- return (!! STYLE_ATTRIBS[aname]) || (!! OTHER_INCORPED_ATTRIBS[aname]);
- }
-
- function insertDomLines(nodeToAddAfter, infoStructs, isTimeUp) {
- isTimeUp = (isTimeUp || function() { return false; });
-
- var lastEntry;
- var lineStartOffset;
- if (infoStructs.length < 1) return;
- var startEntry = rep.lines.atKey(uniqueId(infoStructs[0].node));
- var endEntry = rep.lines.atKey(uniqueId(infoStructs[infoStructs.length-1].node));
- var charStart = rep.lines.offsetOfEntry(startEntry);
- var charEnd = rep.lines.offsetOfEntry(endEntry) + endEntry.width;
-
- //rep.lexer.lexCharRange([charStart, charEnd], isTimeUp);
-
- forEach(infoStructs, function (info) {
- var p2 = PROFILER("insertLine", false);
- var node = info.node;
- var key = uniqueId(node);
- var entry;
- p2.mark("findEntry");
- if (lastEntry) {
- // optimization to avoid recalculation
- var next = rep.lines.next(lastEntry);
- if (next && next.key == key) {
- entry = next;
- lineStartOffset += lastEntry.width;
- }
- }
- if (! entry) {
- p2.literal(1, "nonopt");
- entry = rep.lines.atKey(key);
- lineStartOffset = rep.lines.offsetOfKey(key);
- }
- else p2.literal(0, "nonopt");
- lastEntry = entry;
- p2.mark("spans");
- getSpansForLine(entry, function (tokenText, tokenClass) {
- info.appendSpan(tokenText, tokenClass);
- }, lineStartOffset, isTimeUp());
- //else if (entry.text.length > 0) {
- //info.appendSpan(entry.text, 'dirty');
- //}
- p2.mark("addLine");
- info.prepareForAdd();
- entry.lineMarker = info.lineMarker;
- if (! nodeToAddAfter) {
- root.insertBefore(node, root.firstChild);
- }
- else {
- root.insertBefore(node, nodeToAddAfter.nextSibling);
- }
- nodeToAddAfter = node;
- info.notifyAdded();
- p2.mark("markClean");
- markNodeClean(node);
- p2.end();
- });
- }
-
- function isCaret() {
- return (rep.selStart && rep.selEnd && rep.selStart[0] == rep.selEnd[0] &&
- rep.selStart[1] == rep.selEnd[1]);
- }
-
- // prereq: isCaret()
- function caretLine() { return rep.selStart[0]; }
- function caretColumn() { return rep.selStart[1]; }
- function caretDocChar() {
- return rep.lines.offsetOfIndex(caretLine()) + caretColumn();
- }
-
- function handleReturnIndentation() {
- // on return, indent to level of previous line
- if (isCaret() && caretColumn() == 0 && caretLine() > 0) {
- var lineNum = caretLine();
- var thisLine = rep.lines.atIndex(lineNum);
- var prevLine = rep.lines.prev(thisLine);
- var prevLineText = prevLine.text;
- var theIndent = /^ *(?:)/.exec(prevLineText)[0];
- if (/[\[\(\{]\s*$/.exec(prevLineText)) theIndent += THE_TAB;
- var cs = Changeset.builder(rep.lines.totalWidth()).keep(
- rep.lines.offsetOfIndex(lineNum), lineNum).insert(
- theIndent, [['author',thisAuthor]], rep.apool).toString();
- performDocumentApplyChangeset(cs);
- performSelectionChange([lineNum, theIndent.length], [lineNum, theIndent.length]);
- }
- }
-
-
- function setupMozillaCaretHack(lineNum) {
- // This is really ugly, but by god, it works!
- // Fixes annoying Firefox caret artifact (observed in 2.0.0.12
- // and unfixed in Firefox 2 as of now) where mutating the DOM
- // and then moving the caret to the beginning of a line causes
- // an image of the caret to be XORed at the top of the iframe.
- // The previous solution involved remembering to set the selection
- // later, in response to the next event in the queue, which was hugely
- // annoying.
- // This solution: add a space character (0x20) to the beginning of the line.
- // After setting the selection, remove the space.
- var lineNode = rep.lines.atIndex(lineNum).lineNode;
-
- var fc = lineNode.firstChild;
- while (isBlockElement(fc) && fc.firstChild) {
- fc = fc.firstChild;
- }
- var textNode;
- if (isNodeText(fc)) {
- fc.nodeValue = " "+fc.nodeValue;
- textNode = fc;
- }
- else {
- textNode = doc.createTextNode(" ");
- fc.parentNode.insertBefore(textNode, fc);
- }
- markNodeClean(lineNode);
- return { unhack: function() {
- if (textNode.nodeValue == " ") {
- textNode.parentNode.removeChild(textNode);
- }
- else {
- textNode.nodeValue = textNode.nodeValue.substring(1);
- }
- markNodeClean(lineNode);
- } };
- }
-
-
- function getPointForLineAndChar(lineAndChar) {
- var line = lineAndChar[0];
- var charsLeft = lineAndChar[1];
- //console.log("line: %d, key: %s, node: %o", line, rep.lines.atIndex(line).key,
- //getCleanNodeByKey(rep.lines.atIndex(line).key));
- var lineEntry = rep.lines.atIndex(line);
- charsLeft -= lineEntry.lineMarker;
- if (charsLeft < 0) {
- charsLeft = 0;
- }
- var lineNode = lineEntry.lineNode;
- var n = lineNode;
- var after = false;
- if (charsLeft == 0) {
- var index = 0;
- if (browser.msie && line == (rep.lines.length()-1) && lineNode.childNodes.length == 0) {
- // best to stay at end of last empty div in IE
- index = 1;
- }
- return {node: lineNode, index:index, maxIndex:1};
- }
- while (!(n == lineNode && after)) {
- if (after) {
- if (n.nextSibling) {
- n = n.nextSibling;
- after = false;
- }
- else n = n.parentNode;
- }
- else {
- if (isNodeText(n)) {
- var len = n.nodeValue.length;
- if (charsLeft <= len) {
- return {node: n, index:charsLeft, maxIndex:len};
- }
- charsLeft -= len;
- after = true;
- }
- else {
- if (n.firstChild) n = n.firstChild;
- else after = true;
- }
- }
- }
- return {node: lineNode, index:1, maxIndex:1};
- }
-
- function nodeText(n) {
- return n.innerText || n.textContent || n.nodeValue || '';
- }
-
- function getLineAndCharForPoint(point) {
- // Turn DOM node selection into [line,char] selection.
- // This method has to work when the DOM is not pristine,
- // assuming the point is not in a dirty node.
- if (point.node == root) {
- if (point.index == 0) {
- return [0, 0];
- }
- else {
- var N = rep.lines.length();
- var ln = rep.lines.atIndex(N-1);
- return [N-1, ln.text.length];
- }
- }
- else {
- var n = point.node;
- var col = 0;
- // if this part fails, it probably means the selection node
- // was dirty, and we didn't see it when collecting dirty nodes.
- if (isNodeText(n)) {
- col = point.index;
- }
- else if (point.index > 0) {
- col = nodeText(n).length;
- }
- var parNode, prevSib;
- while ((parNode = n.parentNode) != root) {
- if ((prevSib = n.previousSibling)) {
- n = prevSib;
- col += nodeText(n).length;
- }
- else {
- n = parNode;
- }
- }
- if (n.id == "") console.debug("BAD");
- if (n.firstChild && isBlockElement(n.firstChild)) {
- col += 1; // lineMarker
- }
- var lineEntry = rep.lines.atKey(n.id);
- var lineNum = rep.lines.indexOfEntry(lineEntry);
- return [lineNum, col];
- }
- }
-
- function createDomLineEntry(lineString) {
- var info = doCreateDomLine(lineString.length > 0);
- var newNode = info.node;
- return {key: uniqueId(newNode), text: lineString, lineNode: newNode,
- domInfo: info, lineMarker: 0};
- }
-
- function canApplyChangesetToDocument(changes) {
- return Changeset.oldLen(changes) == rep.alltext.length;
- }
-
- function performDocumentApplyChangeset(changes, insertsAfterSelection) {
- doRepApplyChangeset(changes, insertsAfterSelection);
-
- var requiredSelectionSetting = null;
- if (rep.selStart && rep.selEnd) {
- var selStartChar = rep.lines.offsetOfIndex(rep.selStart[0]) + rep.selStart[1];
- var selEndChar = rep.lines.offsetOfIndex(rep.selEnd[0]) + rep.selEnd[1];
- var result = Changeset.characterRangeFollow(changes, selStartChar, selEndChar,
- insertsAfterSelection);
- requiredSelectionSetting = [result[0], result[1], rep.selFocusAtStart];
- }
-
- var linesMutatee = {
- splice: function(start, numRemoved, newLinesVA) {
- domAndRepSplice(start, numRemoved,
- map(Array.prototype.slice.call(arguments, 2),
- function(s) { return s.slice(0,-1); }),
- null);
- },
- get: function(i) { return rep.lines.atIndex(i).text+'\n'; },
- length: function() { return rep.lines.length(); },
- slice_notused: function(start, end) {
- return map(rep.lines.slice(start, end), function(e) { return e.text+'\n'; });
- }
- };
-
- Changeset.mutateTextLines(changes, linesMutatee);
-
- checkALines();
-
- if (requiredSelectionSetting) {
- performSelectionChange(lineAndColumnFromChar(requiredSelectionSetting[0]),
- lineAndColumnFromChar(requiredSelectionSetting[1]),
- requiredSelectionSetting[2]);
- }
-
- function domAndRepSplice(startLine, deleteCount, newLineStrings, isTimeUp) {
- // dgreensp 3/2009: the spliced lines may be in the middle of a dirty region,
- // so if no explicit time limit, don't spend a lot of time highlighting
- isTimeUp = (isTimeUp || newTimeLimit(50));
-
- var keysToDelete = [];
- if (deleteCount > 0) {
- var entryToDelete = rep.lines.atIndex(startLine);
- for(var i=0;i<deleteCount;i++) {
- keysToDelete.push(entryToDelete.key);
- entryToDelete = rep.lines.next(entryToDelete);
- }
- }
-
- var lineEntries = map(newLineStrings, createDomLineEntry);
-
- doRepLineSplice(startLine, deleteCount, lineEntries);
-
- var nodeToAddAfter;
- if (startLine > 0) {
- nodeToAddAfter = getCleanNodeByKey(rep.lines.atIndex(startLine-1).key);
- }
- else nodeToAddAfter = null;
-
- insertDomLines(nodeToAddAfter, map(lineEntries, function (entry) { return entry.domInfo; }),
- isTimeUp);
-
- forEach(keysToDelete, function (k) {
- var n = doc.getElementById(k);
- n.parentNode.removeChild(n);
- });
-
- if ((rep.selStart && rep.selStart[0] >= startLine && rep.selStart[0] <= startLine+deleteCount) ||
- (rep.selEnd && rep.selEnd[0] >= startLine && rep.selEnd[0] <= startLine+deleteCount)) {
- currentCallStack.selectionAffected = true;
- }
- }
- }
-
- function checkChangesetLineInformationAgainstRep(changes) {
- return true; // disable for speed
- var opIter = Changeset.opIterator(Changeset.unpack(changes).ops);
- var curOffset = 0;
- var curLine = 0;
- var curCol = 0;
- while (opIter.hasNext()) {
- var o = opIter.next();
- if (o.opcode == '-' || o.opcode == '=') {
- curOffset += o.chars;
- if (o.lines) {
- curLine += o.lines;
- curCol = 0;
- }
- else {
- curCol += o.chars;
- }
- }
- var calcLine = rep.lines.indexOfOffset(curOffset);
- var calcLineStart = rep.lines.offsetOfIndex(calcLine);
- var calcCol = curOffset - calcLineStart;
- if (calcCol != curCol || calcLine != curLine) {
- return false;
- }
- }
- return true;
- }
-
- function doRepApplyChangeset(changes, insertsAfterSelection) {
- Changeset.checkRep(changes);
-
- if (Changeset.oldLen(changes) != rep.alltext.length)
- throw new Error("doRepApplyChangeset length mismatch: "+
- Changeset.oldLen(changes)+"/"+rep.alltext.length);
-
- if (! checkChangesetLineInformationAgainstRep(changes)) {
- throw new Error("doRepApplyChangeset line break mismatch");
- }
-
- (function doRecordUndoInformation(changes) {
- var editEvent = currentCallStack.editEvent;
- if (editEvent.eventType == "nonundoable") {
- if (! editEvent.changeset) {
- editEvent.changeset = changes;
- }
- else {
- editEvent.changeset = Changeset.compose(editEvent.changeset, changes,
- rep.apool);
- }
- }
- else {
- var inverseChangeset = Changeset.inverse(changes, {get: function(i) {
- return rep.lines.atIndex(i).text+'\n';
- }, length: function() { return rep.lines.length(); }},
- rep.alines, rep.apool);
-
- if (! editEvent.backset) {
- editEvent.backset = inverseChangeset;
- }
- else {
- editEvent.backset = Changeset.compose(inverseChangeset,
- editEvent.backset, rep.apool);
- }
- }
- })(changes);
-
- //rep.alltext = Changeset.applyToText(changes, rep.alltext);
- Changeset.mutateAttributionLines(changes, rep.alines, rep.apool);
-
- if (changesetTracker.isTracking()) {
- changesetTracker.composeUserChangeset(changes);
- }
-
- }
-
- function lineAndColumnFromChar(x) {
- var lineEntry = rep.lines.atOffset(x);
- var lineStart = rep.lines.offsetOfEntry(lineEntry);
- var lineNum = rep.lines.indexOfEntry(lineEntry);
- return [lineNum, x - lineStart];
- }
-
- function performDocumentReplaceCharRange(startChar, endChar, newText) {
- if (startChar == endChar && newText.length == 0) {
- return;
- }
- // Requires that the replacement preserve the property that the
- // internal document text ends in a newline. Given this, we
- // rewrite the splice so that it doesn't touch the very last
- // char of the document.
- if (endChar == rep.alltext.length) {
- if (startChar == endChar) {
- // an insert at end
- startChar--;
- endChar--;
- newText = '\n'+newText.substring(0, newText.length-1);
- }
- else if (newText.length == 0) {
- // a delete at end
- startChar--;
- endChar--;
- }
- else {
- // a replace at end
- endChar--;
- newText = newText.substring(0, newText.length-1);
- }
- }
- performDocumentReplaceRange(lineAndColumnFromChar(startChar),
- lineAndColumnFromChar(endChar),
- newText);
- }
-
- function performDocumentReplaceRange(start, end, newText) {
- //dmesg(String([start.toSource(),end.toSource(),newText.toSource()]));
-
- // start[0]: <--- start[1] --->CCCCCCCCCCC\n
- // CCCCCCCCCCCCCCCCCCCC\n
- // CCCC\n
- // end[0]: <CCC end[1] CCC>-------\n
-
- var builder = Changeset.builder(rep.lines.totalWidth());
- buildKeepToStartOfRange(builder, start);
- buildRemoveRange(builder, start, end);
- builder.insert(newText, [['author',thisAuthor]], rep.apool);
- var cs = builder.toString();
-
- performDocumentApplyChangeset(cs);
- }
-
- function performDocumentApplyAttributesToCharRange(start, end, attribs) {
- if (end >= rep.alltext.length) {
- end = rep.alltext.length-1;
- }
- performDocumentApplyAttributesToRange(lineAndColumnFromChar(start),
- lineAndColumnFromChar(end), attribs);
- }
-
- function performDocumentApplyAttributesToRange(start, end, attribs) {
- var builder = Changeset.builder(rep.lines.totalWidth());
- buildKeepToStartOfRange(builder, start);
- buildKeepRange(builder, start, end, attribs, rep.apool);
- var cs = builder.toString();
- performDocumentApplyChangeset(cs);
- }
-
- function buildKeepToStartOfRange(builder, start) {
- var startLineOffset = rep.lines.offsetOfIndex(start[0]);
-
- builder.keep(startLineOffset, start[0]);
- builder.keep(start[1]);
- }
- function buildRemoveRange(builder, start, end) {
- var startLineOffset = rep.lines.offsetOfIndex(start[0]);
- var endLineOffset = rep.lines.offsetOfIndex(end[0]);
-
- if (end[0] > start[0]) {
- builder.remove(endLineOffset - startLineOffset - start[1], end[0] - start[0]);
- builder.remove(end[1]);
- }
- else {
- builder.remove(end[1] - start[1]);
- }
- }
- function buildKeepRange(builder, start, end, attribs, pool) {
- var startLineOffset = rep.lines.offsetOfIndex(start[0]);
- var endLineOffset = rep.lines.offsetOfIndex(end[0]);
-
- if (end[0] > start[0]) {
- builder.keep(endLineOffset - startLineOffset - start[1], end[0] - start[0], attribs, pool);
- builder.keep(end[1], 0, attribs, pool);
- }
- else {
- builder.keep(end[1] - start[1], 0, attribs, pool);
- }
- }
-
- function setAttributeOnSelection(attributeName, attributeValue) {
- if (!(rep.selStart && rep.selEnd)) return;
-
- performDocumentApplyAttributesToRange(rep.selStart, rep.selEnd,
- [[attributeName, attributeValue]]);
- }
-
- function toggleAttributeOnSelection(attributeName) {
- if (!(rep.selStart && rep.selEnd)) return;
-
- var selectionAllHasIt = true;
- var withIt = Changeset.makeAttribsString('+', [[attributeName, 'true']], rep.apool);
- var withItRegex = new RegExp(withIt.replace(/\*/g,'\\*')+"(\\*|$)");
- function hasIt(attribs) { return withItRegex.test(attribs); }
-
- var selStartLine = rep.selStart[0];
- var selEndLine = rep.selEnd[0];
- for(var n=selStartLine; n<=selEndLine; n++) {
- var opIter = Changeset.opIterator(rep.alines[n]);
- var indexIntoLine = 0;
- var selectionStartInLine = 0;
- var selectionEndInLine = rep.lines.atIndex(n).text.length; // exclude newline
- if (n == selStartLine) {
- selectionStartInLine = rep.selStart[1];
- }
- if (n == selEndLine) {
- selectionEndInLine = rep.selEnd[1];
- }
- while (opIter.hasNext()) {
- var op = opIter.next();
- var opStartInLine = indexIntoLine;
- var opEndInLine = opStartInLine + op.chars;
- if (! hasIt(op.attribs)) {
- // does op overlap selection?
- if (! (opEndInLine <= selectionStartInLine || opStartInLine >= selectionEndInLine)) {
- selectionAllHasIt = false;
- break;
- }
- }
- indexIntoLine = opEndInLine;
- }
- if (! selectionAllHasIt) {
- break;
- }
- }
-
- if (selectionAllHasIt) {
- performDocumentApplyAttributesToRange(rep.selStart, rep.selEnd,
- [[attributeName,'']]);
- }
- else {
- var settings = [[attributeName, 'true']];
-
- if (attributeName == 'h1' || attributeName == 'h2' || attributeName == 'h3' ||
- attributeName == 'h4' || attributeName == 'h5' || attributeName == 'h6') {
-
- settings = [['h1',''], ['h2',''], ['h3',''],
- ['h4',''], ['h5',''], ['h6','']];
- if (attributeName == 'h1') {
- settings[0] = [attributeName, 'true'];
- }
- else if (attributeName == 'h2') {
- settings[1] = [attributeName, 'true'];
- }
- else if (attributeName == 'h3') {
- settings[2] = [attributeName, 'true'];
- }
- else if (attributeName == 'h4') {
- settings[3] = [attributeName, 'true'];
- }
- else if (attributeName == 'h5') {
- settings[4] = [attributeName, 'true'];
- }
- else if (attributeName == 'h6') {
- settings[5] = [attributeName, 'true'];
- }
- }
-
- performDocumentApplyAttributesToRange(rep.selStart, rep.selEnd, settings);
- }
- }
-
- function performDocumentReplaceSelection(newText) {
- if (!(rep.selStart && rep.selEnd)) return;
- performDocumentReplaceRange(rep.selStart, rep.selEnd, newText);
- }
-
- // Change the abstract representation of the document to have a different set of lines.
- // Must be called after rep.alltext is set.
- function doRepLineSplice(startLine, deleteCount, newLineEntries) {
-
- forEach(newLineEntries, function (entry) { entry.width = entry.text.length+1; });
-
- var startOldChar = rep.lines.offsetOfIndex(startLine);
- var endOldChar = rep.lines.offsetOfIndex(startLine+deleteCount);
-
- var oldRegionStart = rep.lines.offsetOfIndex(startLine);
- var oldRegionEnd = rep.lines.offsetOfIndex(startLine+deleteCount);
- rep.lines.splice(startLine, deleteCount, newLineEntries);
- currentCallStack.docTextChanged = true;
- currentCallStack.repChanged = true;
- var newRegionEnd = rep.lines.offsetOfIndex(startLine + newLineEntries.length);
-
- var newText = map(newLineEntries, function (e) { return e.text+'\n'; }).join('');
-
- rep.alltext = rep.alltext.substring(0, startOldChar) + newText +
- rep.alltext.substring(endOldChar, rep.alltext.length);
-
- //var newTotalLength = rep.alltext.length;
-
- //rep.lexer.updateBuffer(rep.alltext, oldRegionStart, oldRegionEnd - oldRegionStart,
- //newRegionEnd - oldRegionStart);
- }
-
- function doIncorpLineSplice(startLine, deleteCount, newLineEntries, lineAttribs, hints) {
-
- var startOldChar = rep.lines.offsetOfIndex(startLine);
- var endOldChar = rep.lines.offsetOfIndex(startLine+deleteCount);
-
- var oldRegionStart = rep.lines.offsetOfIndex(startLine);
-
- var selStartHintChar, selEndHintChar;
- if (hints && hints.selStart) {
- selStartHintChar = rep.lines.offsetOfIndex(hints.selStart[0]) + hints.selStart[1] -
- oldRegionStart;
- }
- if (hints && hints.selEnd) {
- selEndHintChar = rep.lines.offsetOfIndex(hints.selEnd[0]) + hints.selEnd[1] -
- oldRegionStart;
- }
-
- var newText = map(newLineEntries, function (e) { return e.text+'\n'; }).join('');
- var oldText = rep.alltext.substring(startOldChar, endOldChar);
- var oldAttribs = rep.alines.slice(startLine, startLine+deleteCount).join('');
- var newAttribs = lineAttribs.join('|1+1')+'|1+1'; // not valid in a changeset
- var analysis = analyzeChange(oldText, newText, oldAttribs, newAttribs,
- selStartHintChar, selEndHintChar);
- var commonStart = analysis[0];
- var commonEnd = analysis[1];
- var shortOldText = oldText.substring(commonStart, oldText.length - commonEnd);
- var shortNewText = newText.substring(commonStart, newText.length - commonEnd);
- var spliceStart = startOldChar+commonStart;
- var spliceEnd = endOldChar-commonEnd;
- var shiftFinalNewlineToBeforeNewText = false;
-
- // adjust the splice to not involve the final newline of the document;
- // be very defensive
- if (shortOldText.charAt(shortOldText.length-1) == '\n' &&
- shortNewText.charAt(shortNewText.length-1) == '\n') {
- // replacing text that ends in newline with text that also ends in newline
- // (still, after analysis, somehow)
- shortOldText = shortOldText.slice(0,-1);
- shortNewText = shortNewText.slice(0,-1);
- spliceEnd--;
- commonEnd++;
- }
- if (shortOldText.length == 0 && spliceStart == rep.alltext.length
- && shortNewText.length > 0) {
- // inserting after final newline, bad
- spliceStart--;
- spliceEnd--;
- shortNewText = '\n'+shortNewText.slice(0,-1);
- shiftFinalNewlineToBeforeNewText = true;
- }
- if (spliceEnd == rep.alltext.length && shortOldText.length > 0 &&
- shortNewText.length == 0) {
- // deletion at end of rep.alltext
- if (rep.alltext.charAt(spliceStart-1) == '\n') {
- // (if not then what the heck? it will definitely lead
- // to a rep.alltext without a final newline)
- spliceStart--;
- spliceEnd--;
- }
- }
-
- if (! (shortOldText.length == 0 && shortNewText.length == 0)) {
- var oldDocText = rep.alltext;
- var oldLen = oldDocText.length;
-
- var spliceStartLine = rep.lines.indexOfOffset(spliceStart);
- var spliceStartLineStart = rep.lines.offsetOfIndex(spliceStartLine);
- function startBuilder() {
- var builder = Changeset.builder(oldLen);
- builder.keep(spliceStartLineStart, spliceStartLine);
- builder.keep(spliceStart - spliceStartLineStart);
- return builder;
- }
-
- function eachAttribRun(attribs, func/*(startInNewText, endInNewText, attribs)*/) {
- var attribsIter = Changeset.opIterator(attribs);
- var textIndex = 0;
- var newTextStart = commonStart;
- var newTextEnd = newText.length - commonEnd - (shiftFinalNewlineToBeforeNewText ? 1 : 0);
- while (attribsIter.hasNext()) {
- var op = attribsIter.next();
- var nextIndex = textIndex + op.chars;
- if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
- func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);
- }
- textIndex = nextIndex;
- }
- }
-
- var justApplyStyles = (shortNewText == shortOldText);
- var theChangeset;
-
- if (justApplyStyles) {
- // create changeset that clears the incorporated styles on
- // the existing text. we compose this with the
- // changeset the applies the styles found in the DOM.
- // This allows us to incorporate, e.g., Safari's native "unbold".
-
- var incorpedAttribClearer = cachedStrFunc(function (oldAtts) {
- return Changeset.mapAttribNumbers(oldAtts, function(n) {
- var k = rep.apool.getAttribKey(n);
- if (isStyleAttribute(k)) {
- return rep.apool.putAttrib([k,'']);
- }
- return false;
- });
- });
-
- var builder1 = startBuilder();
- if (shiftFinalNewlineToBeforeNewText) {
- builder1.keep(1, 1);
- }
- eachAttribRun(oldAttribs, function(start, end, attribs) {
- builder1.keepText(newText.substring(start, end), incorpedAttribClearer(attribs));
- });
- var clearer = builder1.toString();
-
- var builder2 = startBuilder();
- if (shiftFinalNewlineToBeforeNewText) {
- builder2.keep(1, 1);
- }
- eachAttribRun(newAttribs, function(start, end, attribs) {
- builder2.keepText(newText.substring(start, end), attribs);
- });
- var styler = builder2.toString();
-
- theChangeset = Changeset.compose(clearer, styler, rep.apool);
- }
- else {
- var builder = startBuilder();
-
- var spliceEndLine = rep.lines.indexOfOffset(spliceEnd);
- var spliceEndLineStart = rep.lines.offsetOfIndex(spliceEndLine);
- if (spliceEndLineStart > spliceStart) {
- builder.remove(spliceEndLineStart - spliceStart, spliceEndLine - spliceStartLine);
- builder.remove(spliceEnd - spliceEndLineStart);
- }
- else {
- builder.remove(spliceEnd - spliceStart);
- }
-
- var isNewTextMultiauthor = false;
- var authorAtt = Changeset.makeAttribsString(
- '+', (thisAuthor ? [['author', thisAuthor]] : []), rep.apool);
- var authorizer = cachedStrFunc(function(oldAtts) {
- if (isNewTextMultiauthor) {
- // prefer colors from DOM
- return Changeset.composeAttributes(authorAtt, oldAtts, true, rep.apool);
- }
- else {
- // use this author's color
- return Changeset.composeAttributes(oldAtts, authorAtt, true, rep.apool);
- }
- });
-
- var foundDomAuthor = '';
- eachAttribRun(newAttribs, function(start, end, attribs) {
- var a = Changeset.attribsAttributeValue(attribs, 'author', rep.apool);
- if (a && a != foundDomAuthor) {
- if (! foundDomAuthor) {
- foundDomAuthor = a;
- }
- else {
- isNewTextMultiauthor = true; // multiple authors in DOM!
- }
- }
- });
-
- if (shiftFinalNewlineToBeforeNewText) {
- builder.insert('\n', authorizer(''));
- }
-
- eachAttribRun(newAttribs, function(start, end, attribs) {
- builder.insert(newText.substring(start, end), authorizer(attribs));
- });
- theChangeset = builder.toString();
- }
-
- //dmesg(htmlPrettyEscape(theChangeset));
-
- doRepApplyChangeset(theChangeset);
- }
-
- // do this no matter what, because we need to get the right
- // line keys into the rep.
- doRepLineSplice(startLine, deleteCount, newLineEntries);
-
- checkALines();
- }
-
- function cachedStrFunc(func) {
- var cache = {};
- return function(s) {
- if (! cache[s]) {
- cache[s] = func(s);
- }
- return cache[s];
- };
- }
-
- function analyzeChange(oldText, newText, oldAttribs, newAttribs, optSelStartHint, optSelEndHint) {
- function incorpedAttribFilter(anum) {
- return isStyleAttribute(rep.apool.getAttribKey(anum));
- }
- function attribRuns(attribs) {
- var lengs = [];
- var atts = [];
- var iter = Changeset.opIterator(attribs);
- while (iter.hasNext()) {
- var op = iter.next();
- lengs.push(op.chars);
- atts.push(op.attribs);
- }
- return [lengs,atts];
- }
- function attribIterator(runs, backward) {
- var lengs = runs[0];
- var atts = runs[1];
- var i = (backward ? lengs.length-1 : 0);
- var j = 0;
- return function next() {
- while (j >= lengs[i]) {
- if (backward) i--; else i++;
- j = 0;
- }
- var a = atts[i];
- j++;
- return a;
- };
- }
-
- var oldLen = oldText.length;
- var newLen = newText.length;
- var minLen = Math.min(oldLen, newLen);
-
- var oldARuns = attribRuns(Changeset.filterAttribNumbers(oldAttribs, incorpedAttribFilter));
- var newARuns = attribRuns(Changeset.filterAttribNumbers(newAttribs, incorpedAttribFilter));
-
- var commonStart = 0;
- var oldStartIter = attribIterator(oldARuns, false);
- var newStartIter = attribIterator(newARuns, false);
- while (commonStart < minLen) {
- if (oldText.charAt(commonStart) == newText.charAt(commonStart) &&
- oldStartIter() == newStartIter()) {
- commonStart++;
- }
- else break;
- }
-
- var commonEnd = 0;
- var oldEndIter = attribIterator(oldARuns, true);
- var newEndIter = attribIterator(newARuns, true);
- while (commonEnd < minLen) {
- if (commonEnd == 0) {
- // assume newline in common
- oldEndIter(); newEndIter();
- commonEnd++;
- }
- else if (oldText.charAt(oldLen-1-commonEnd) == newText.charAt(newLen-1-commonEnd) &&
- oldEndIter() == newEndIter()) {
- commonEnd++;
- }
- else break;
- }
-
- var hintedCommonEnd = -1;
- if ((typeof optSelEndHint) == "number") {
- hintedCommonEnd = newLen - optSelEndHint;
- }
-
-
- if (commonStart + commonEnd > oldLen) {
- // ambiguous insertion
- var minCommonEnd = oldLen - commonStart;
- var maxCommonEnd = commonEnd;
- if (hintedCommonEnd >= minCommonEnd && hintedCommonEnd <= maxCommonEnd) {
- commonEnd = hintedCommonEnd;
- }
- else {
- commonEnd = minCommonEnd;
- }
- commonStart = oldLen - commonEnd;
- }
- if (commonStart + commonEnd > newLen) {
- // ambiguous deletion
- var minCommonEnd = newLen - commonStart;
- var maxCommonEnd = commonEnd;
- if (hintedCommonEnd >= minCommonEnd && hintedCommonEnd <= maxCommonEnd) {
- commonEnd = hintedCommonEnd;
- }
- else {
- commonEnd = minCommonEnd;
- }
- commonStart = newLen - commonEnd;
- }
-
- return [commonStart, commonEnd];
- }
-
- function equalLineAndChars(a, b) {
- if (!a) return !b;
- if (!b) return !a;
- return (a[0] == b[0] && a[1] == b[1]);
- }
-
- function performSelectionChange(selectStart, selectEnd, focusAtStart) {
- if (repSelectionChange(selectStart, selectEnd, focusAtStart)) {
- currentCallStack.selectionAffected = true;
- }
- }
-
- // Change the abstract representation of the document to have a different selection.
- // Should not rely on the line representation. Should not affect the DOM.
- function repSelectionChange(selectStart, selectEnd, focusAtStart) {
- focusAtStart = !! focusAtStart;
-
- var newSelFocusAtStart = (focusAtStart &&
- ((! selectStart) || (! selectEnd) ||
- (selectStart[0] != selectEnd[0]) ||
- (selectStart[1] != selectEnd[1])));
-
- if ((! equalLineAndChars(rep.selStart, selectStart)) ||
- (! equalLineAndChars(rep.selEnd, selectEnd)) ||
- (rep.selFocusAtStart != newSelFocusAtStart)) {
- rep.selStart = selectStart;
- rep.selEnd = selectEnd;
- rep.selFocusAtStart = newSelFocusAtStart;
- if (mozillaFakeArrows) mozillaFakeArrows.notifySelectionChanged();
- currentCallStack.repChanged = true;
-
- return true;
- //console.log("selStart: %o, selEnd: %o, focusAtStart: %s", rep.selStart, rep.selEnd,
- //String(!!rep.selFocusAtStart));
- }
- return false;
- //console.log("%o %o %s", rep.selStart, rep.selEnd, rep.selFocusAtStart);
- }
-
- /*function escapeHTML(s) {
- var re = /[&<>'"]/g; /']/; // stupid indentation thing
- if (! re.MAP) {
- // persisted across function calls!
- re.MAP = {
- '&': '&amp;',
- '<': '&lt;',
- '>': '&gt;',
- '"': '&#34;',
- "'": '&#39;'
- };
- }
- return s.replace(re, function(c) { return re.MAP[c]; });
- }*/
-
- function doCreateDomLine(nonEmpty) {
- if (browser.msie && (! nonEmpty)) {
- var result = { node: null,
- appendSpan: noop,
- prepareForAdd: noop,
- notifyAdded: noop,
- clearSpans: noop,
- finishUpdate: noop,
- lineMarker: 0 };
-
- var lineElem = doc.createElement("div");
- result.node = lineElem;
-
- result.notifyAdded = function() {
- // magic -- settng an empty div's innerHTML to the empty string
- // keeps it from collapsing. Apparently innerHTML must be set *after*
- // adding the node to the DOM.
- // Such a div is what IE 6 creates naturally when you make a blank line
- // in a document of divs. However, when copy-and-pasted the div will
- // contain a space, so we note its emptiness with a property.
- lineElem.innerHTML = "";
- // a primitive-valued property survives copy-and-paste
- setAssoc(lineElem, "shouldBeEmpty", true);
- // an object property doesn't
- setAssoc(lineElem, "unpasted", {});
- };
- var lineClass = 'ace-line';
- result.appendSpan = function(txt, cls) {
- if ((! txt) && cls) {
- // gain a whole-line style (currently to show insertion point in CSS)
- lineClass = domline.addToLineClass(lineClass, cls);
- }
- // otherwise, ignore appendSpan, this is an empty line
- };
- result.clearSpans = function() {
- lineClass = ''; // non-null to cause update
- };
- function writeClass() {
- if (lineClass !== null) lineElem.className = lineClass;
- }
- result.prepareForAdd = writeClass;
- result.finishUpdate = writeClass;
- result.getInnerHTML = function() { return ""; };
-
- return result;
- }
- else {
- return domline.createDomLine(nonEmpty, doesWrap, browser, doc);
- }
- }
-
- function textify(str) {
- return str.replace(/[\n\r ]/g, ' ').replace(/\xa0/g, ' ').replace(/\t/g, ' ');
- }
-
- var _blockElems = { "div":1, "p":1, "pre":1, "li":1, "ol":1, "ul":1 };
- function isBlockElement(n) {
- return !!_blockElems[(n.tagName || "").toLowerCase()];
- }
-
- function getDirtyRanges() {
- // based on observedChanges, return a list of ranges of original lines
- // that need to be removed or replaced with new user content to incorporate
- // the user's changes into the line representation. ranges may be zero-length,
- // indicating inserted content. for example, [0,0] means content was inserted
- // at the top of the document, while [3,4] means line 3 was deleted, modified,
- // or replaced with one or more new lines of content. ranges do not touch.
-
- var p = PROFILER("getDirtyRanges", false);
- p.forIndices = 0;
- p.consecutives = 0;
- p.corrections = 0;
-
- var cleanNodeForIndexCache = {};
- var N = rep.lines.length(); // old number of lines
- function cleanNodeForIndex(i) {
- // if line (i) in the un-updated line representation maps to a clean node
- // in the document, return that node.
- // if (i) is out of bounds, return true. else return false.
- if (cleanNodeForIndexCache[i] === undefined) {
- p.forIndices++;
- var result;
- if (i < 0 || i >= N) {
- result = true; // truthy, but no actual node
- }
- else {
- var key = rep.lines.atIndex(i).key;
- result = (getCleanNodeByKey(key) || false);
- }
- cleanNodeForIndexCache[i] = result;
- }
- return cleanNodeForIndexCache[i];
- }
- var isConsecutiveCache = {};
- function isConsecutive(i) {
- if (isConsecutiveCache[i] === undefined) {
- p.consecutives++;
- isConsecutiveCache[i] = (function() {
- // returns whether line (i) and line (i-1), assumed to be map to clean DOM nodes,
- // or document boundaries, are consecutive in the changed DOM
- var a = cleanNodeForIndex(i-1);
- var b = cleanNodeForIndex(i);
- if ((!a) || (!b)) return false; // violates precondition
- if ((a === true) && (b === true)) return ! root.firstChild;
- if ((a === true) && b.previousSibling) return false;
- if ((b === true) && a.nextSibling) return false;
- if ((a === true) || (b === true)) return true;
- return a.nextSibling == b;
- })();
- }
- return isConsecutiveCache[i];
- }
- function isClean(i) {
- // returns whether line (i) in the un-updated representation maps to a clean node,
- // or is outside the bounds of the document
- return !! cleanNodeForIndex(i);
- }
- // list of pairs, each representing a range of lines that is clean and consecutive
- // in the changed DOM. lines (-1) and (N) are always clean, but may or may not
- // be consecutive with lines in the document. pairs are in sorted order.
- var cleanRanges = [[-1,N+1]];
- function rangeForLine(i) {
- // returns index of cleanRange containing i, or -1 if none
- var answer = -1;
- forEach(cleanRanges, function (r, idx) {
- if (i >= r[1]) return false; // keep looking
- if (i < r[0]) return true; // not found, stop looking
- answer = idx;
- return true; // found, stop looking
- });
- return answer;
- }
- function removeLineFromRange(rng, line) {
- // rng is index into cleanRanges, line is line number
- // precond: line is in rng
- var a = cleanRanges[rng][0];
- var b = cleanRanges[rng][1];
- if ((a+1) == b) cleanRanges.splice(rng, 1);
- else if (line == a) cleanRanges[rng][0]++;
- else if (line == (b-1)) cleanRanges[rng][1]--;
- else cleanRanges.splice(rng, 1, [a,line], [line+1,b]);
- }
- function splitRange(rng, pt) {
- // precond: pt splits cleanRanges[rng] into two non-empty ranges
- var a = cleanRanges[rng][0];
- var b = cleanRanges[rng][1];
- cleanRanges.splice(rng, 1, [a,pt], [pt,b]);
- }
- var correctedLines = {};
- function correctlyAssignLine(line) {
- if (correctedLines[line]) return true;
- p.corrections++;
- correctedLines[line] = true;
- // "line" is an index of a line in the un-updated rep.
- // returns whether line was already correctly assigned (i.e. correctly
- // clean or dirty, according to cleanRanges, and if clean, correctly
- // attached or not attached (i.e. in the same range as) the prev and next lines).
- //console.log("correctly assigning: %d", line);
- var rng = rangeForLine(line);
- var lineClean = isClean(line);
- if (rng < 0) {
- if (lineClean) {
- console.debug("somehow lost clean line");
- }
- return true;
- }
- if (! lineClean) {
- // a clean-range includes this dirty line, fix it
- removeLineFromRange(rng, line);
- return false;
- }
- else {
- // line is clean, but could be wrongly connected to a clean line
- // above or below
- var a = cleanRanges[rng][0];
- var b = cleanRanges[rng][1];
- var didSomething = false;
- // we'll leave non-clean adjacent nodes in the clean range for the caller to
- // detect and deal with. we deal with whether the range should be split
- // just above or just below this line.
- if (a < line && isClean(line-1) && ! isConsecutive(line)) {
- splitRange(rng, line);
- didSomething = true;
- }
- if (b > (line+1) && isClean(line+1) && ! isConsecutive(line+1)) {
- splitRange(rng, line+1);
- didSomething = true;
- }
- return ! didSomething;
- }
- }
- function detectChangesAroundLine(line, reqInARow) {
- // make sure cleanRanges is correct about line number "line" and the surrounding
- // lines; only stops checking at end of document or after no changes need
- // making for several consecutive lines. note that iteration is over old lines,
- // so this operation takes time proportional to the number of old lines
- // that are changed or missing, not the number of new lines inserted.
- var correctInARow = 0;
- var currentIndex = line;
- while (correctInARow < reqInARow && currentIndex >= 0) {
- if (correctlyAssignLine(currentIndex)) {
- correctInARow++;
- }
- else correctInARow = 0;
- currentIndex--;
- }
- correctInARow = 0;
- currentIndex = line;
- while (correctInARow < reqInARow && currentIndex < N) {
- if (correctlyAssignLine(currentIndex)) {
- correctInARow++;
- }
- else correctInARow = 0;
- currentIndex++;
- }
- }
-
- if (N == 0) {
- p.cancel();
- if (! isConsecutive(0)) {
- splitRange(0, 0);
- }
- }
- else {
- p.mark("topbot");
- detectChangesAroundLine(0,1);
- detectChangesAroundLine(N-1,1);
-
- p.mark("obs");
- //console.log("observedChanges: "+toSource(observedChanges));
- for (var k in observedChanges.cleanNodesNearChanges) {
- var key = k.substring(1);
- if (rep.lines.containsKey(key)) {
- var line = rep.lines.indexOfKey(key);
- detectChangesAroundLine(line,2);
- }
- }
- p.mark("stats&calc");
- p.literal(p.forIndices, "byidx");
- p.literal(p.consecutives, "cons");
- p.literal(p.corrections, "corr");
- }
-
- var dirtyRanges = [];
- for(var r=0;r<cleanRanges.length-1;r++) {
- dirtyRanges.push([cleanRanges[r][1], cleanRanges[r+1][0]]);
- }
-
- p.end();
-
- return dirtyRanges;
- }
-
- function markNodeClean(n) {
- // clean nodes have knownHTML that matches their innerHTML
- var dirtiness = {};
- dirtiness.nodeId = uniqueId(n);
- dirtiness.knownHTML = n.innerHTML;
- if (browser.msie) {
- // adding a space to an "empty" div in IE designMode doesn't
- // change the innerHTML of the div's parent; also, other
- // browsers don't support innerText
- dirtiness.knownText = n.innerText;
- }
- setAssoc(n, "dirtiness", dirtiness);
- }
-
- function isNodeDirty(n) {
- var p = PROFILER("cleanCheck", false);
- if (n.parentNode != root) return true;
- var data = getAssoc(n, "dirtiness");
- if (!data) return true;
- if (n.id !== data.nodeId) return true;
- if (browser.msie) {
- if (n.innerText !== data.knownText) return true;
- }
- if (n.innerHTML !== data.knownHTML) return true;
- p.end();
- return false;
- }
-
- function getLineEntryTopBottom(entry, destObj) {
- var dom = entry.lineNode;
- var top = dom.offsetTop;
- var height = dom.offsetHeight;
- var obj = (destObj || {});
- obj.top = top;
- obj.bottom = (top+height);
- return obj;
- }
-
- function getViewPortTopBottom() {
- var theTop = getScrollY();
- var doc = outerWin.document;
- var height = doc.documentElement.clientHeight;
- return {top:theTop, bottom:(theTop+height)};
- }
-
- function getVisibleLineRange() {
- var viewport = getViewPortTopBottom();
- //console.log("viewport top/bottom: %o", viewport);
- var obj = {};
- var start = rep.lines.search(function (e) {
- return getLineEntryTopBottom(e, obj).bottom > viewport.top;
- });
- var end = rep.lines.search(function(e) {
- return getLineEntryTopBottom(e, obj).top >= viewport.bottom;
- });
- if (end < start) end = start; // unlikely
- //console.log(start+","+end);
- return [start,end];
- }
-
- function getVisibleCharRange() {
- var lineRange = getVisibleLineRange();
- return [rep.lines.offsetOfIndex(lineRange[0]),
- rep.lines.offsetOfIndex(lineRange[1])];
- }
-
- function handleClick(evt) {
- inCallStack("handleClick", function() {
- idleWorkTimer.atMost(200);
- });
-
- // only want to catch left-click
- if ((! evt.ctrlKey) && (evt.button != 2) && (evt.button != 3)) {
- // find A tag with HREF
- function isLink(n) { return (n.tagName||'').toLowerCase() == "a" && n.href; }
- var n = evt.target;
- while (n && n.parentNode && ! isLink(n)) { n = n.parentNode; }
- if (n && isLink(n)) {
- try {
- var newWindow = window.open(n.href, '_blank');
- newWindow.focus();
- }
- catch (e) {
- // absorb "user canceled" error in IE for certain prompts
- }
- evt.preventDefault();
- }
- }
- }
-
- function doReturnKey() {
- if (! (rep.selStart && rep.selEnd)) {
- return;
- }
- var lineNum = rep.selStart[0];
- var listType = getLineListType(lineNum);
-
- performDocumentReplaceSelection('\n');
- if (listType) {
- if (lineNum+1 < rep.lines.length()) {
- setLineListType(lineNum+1, listType);
- }
- }
- else {
- handleReturnIndentation();
- }
- }
-
- function doIndentOutdent(isOut) {
- if (! (rep.selStart && rep.selEnd)) {
- return false;
- }
-
- var firstLine, lastLine;
- firstLine = rep.selStart[0];
- lastLine = Math.max(firstLine,
- rep.selEnd[0] - ((rep.selEnd[1] == 0) ? 1 : 0));
-
- var mods = [];
- var foundLists = false;
- for(var n=firstLine;n<=lastLine;n++) {
- var listType = getLineListType(n);
- if (listType) {
- listType = /([a-z]+)([12345678])/.exec(listType);
- if (listType) {
- foundLists = true;
- var t = listType[1];
- var level = Number(listType[2]);
- var newLevel =
- Math.max(1, Math.min(MAX_LIST_LEVEL,
- level + (isOut ? -1 : 1)));
- if (level != newLevel) {
- mods.push([n, t+newLevel]);
- }
- }
- }
- }
-
- if (mods.length > 0) {
- setLineListTypes(mods);
- }
-
- return foundLists;
- }
-
- function doTabKey(shiftDown) {
- if (! doIndentOutdent(shiftDown)) {
- performDocumentReplaceSelection(THE_TAB);
- }
- }
-
- function doDeleteKey(optEvt) {
- var evt = optEvt || {};
- var handled = false;
- if (rep.selStart) {
- if (isCaret()) {
- var lineNum = caretLine();
- var col = caretColumn();
- var lineEntry = rep.lines.atIndex(lineNum);
- var lineText = lineEntry.text;
- var lineMarker = lineEntry.lineMarker;
- if (/^ +$/.exec(lineText.substring(lineMarker, col))) {
- var col2 = col - lineMarker;
- var tabSize = THE_TAB.length;
- var toDelete = ((col2 - 1) % tabSize)+1;
- performDocumentReplaceRange([lineNum,col-toDelete],
- [lineNum,col], '');
- //scrollSelectionIntoView();
- handled = true;
- }
- }
- if (! handled) {
- if (isCaret()) {
- var theLine = caretLine();
- var lineEntry = rep.lines.atIndex(theLine);
- if (caretColumn() <= lineEntry.lineMarker) {
- // delete at beginning of line
- var action = 'delete_newline';
- var prevLineListType =
- (theLine > 0 ? getLineListType(theLine-1) : '');
- var thisLineListType = getLineListType(theLine);
- var prevLineEntry = (theLine > 0 &&
- rep.lines.atIndex(theLine-1));
- var prevLineBlank = (prevLineEntry &&
- prevLineEntry.text.length ==
- prevLineEntry.lineMarker);
- if (thisLineListType) {
- // this line is a list
- /*if (prevLineListType) {
- // prev line is a list too, remove this bullet
- performDocumentReplaceRange([theLine-1, prevLineEntry.text.length],
- [theLine, lineEntry.lineMarker], '');
- }
- else*/ if (prevLineBlank && ! prevLineListType) {
- // previous line is blank, remove it
- performDocumentReplaceRange([theLine-1, prevLineEntry.text.length],
- [theLine, 0], '');
- }
- else {
- // delistify
- performDocumentReplaceRange([theLine, 0],
- [theLine, lineEntry.lineMarker], '');
- }
- }
- else if (theLine > 0) {
- // remove newline
- performDocumentReplaceRange([theLine-1, prevLineEntry.text.length],
- [theLine, 0], '');
- }
- }
- else {
- var docChar = caretDocChar();
- if (docChar > 0) {
- if (evt.metaKey || evt.ctrlKey || evt.altKey) {
- // delete as many unicode "letters or digits" in a row as possible;
- // always delete one char, delete further even if that first char
- // isn't actually a word char.
- var deleteBackTo = docChar-1;
- while (deleteBackTo > lineEntry.lineMarker &&
- isWordChar(rep.alltext.charAt(deleteBackTo-1))) {
- deleteBackTo--;
- }
- performDocumentReplaceCharRange(deleteBackTo, docChar, '');
- }
- else {
- // normal delete
- performDocumentReplaceCharRange(docChar-1, docChar, '');
- }
- }
- }
- }
- else {
- performDocumentReplaceSelection('');
- }
- }
- }
- }
-
- // set of "letter or digit" chars is based on section 20.5.16 of the original Java Language Spec
- var REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/;
- var REGEX_SPACE = /\s/;
-
- function isWordChar(c) {
- return !! REGEX_WORDCHAR.exec(c);
- }
- function isSpaceChar(c) {
- return !! REGEX_SPACE.exec(c);
- }
-
- function moveByWordInLine(lineText, initialIndex, forwardNotBack) {
- var i = initialIndex;
- function nextChar() {
- if (forwardNotBack) return lineText.charAt(i);
- else return lineText.charAt(i-1);
- }
- function advance() { if (forwardNotBack) i++; else i--; }
- function isDone() {
- if (forwardNotBack) return i >= lineText.length;
- else return i <= 0;
- }
-
- // On Mac and Linux, move right moves to end of word and move left moves to start;
- // on Windows, always move to start of word.
- // On Windows, Firefox and IE disagree on whether to stop for punctuation (FF says no).
- if (browser.windows && forwardNotBack) {
- while ((! isDone()) && isWordChar(nextChar())) { advance(); }
- while ((! isDone()) && ! isWordChar(nextChar())) { advance(); }
- }
- else {
- while ((! isDone()) && ! isWordChar(nextChar())) { advance(); }
- while ((! isDone()) && isWordChar(nextChar())) { advance(); }
- }
-
- return i;
- }
-
- function handleKeyEvent(evt) {
- if (DEBUG && top.DONT_INCORP) return;
-
- /*if (evt.which == 48) {
- //setEditable(! isEditable);
- //doAlert(getInnerWidth());
- //doAlert(doc.documentElement.innerWidth)
- alert(eval(prompt()));
- evt.preventDefault();
- return;
- }*/
- /*if (evt.which == 48) {
- alert(doc.body.innerHTML);
- }*/
- /*if (evt.which == 48 && evt.type == "keydown") {
- var lineHeights = [];
- function eachChild(node, func) {
- if (node.firstChild) {
- var n = node.firstChild;
- while (n) {
- func(n);
- n = n.nextSibling;
- }
- }
- }
- eachChild(doc.body, function (n) {
- if (n.clientHeight) {
- lineHeights.push(n.clientHeight);
- }
- });
- alert(lineHeights.join(','));
- }*/
- /*if (evt.which == 48) {
- top.DONT_INCORP = true;
- var cmdTarget = doc;
- if (browser.msie) {
- if (doc.selection) {
- cmdTarget = doc.selection.createRange();
- }
- else cmdTarget = null;
- }
- if (cmdTarget) {
- cmdTarget.execCommand("Bold", false, null);
- }
- alert(doc.body.innerHTML);
- evt.preventDefault();
- return;
- }*/
- /*if (evt.which == 48) {
- if (evt.type == "keypress") {
- top.console.log(window.getSelection().getRangeAt(0));
- evt.preventDefault();
- }
- return;
- }*/
- /*if (evt.which == 48) {
- if (evt.type == "keypress") {
- inCallStack("bold", function() {
- fastIncorp(9);
- toggleAttributeOnSelection('bold');
- });
- evt.preventDefault();
- }
- return;
- }*/
- /*if (evt.which == 48) {
- if (evt.type == "keypress") {
- inCallStack("insertunorderedlist", function() {
- fastIncorp(9);
- doInsertUnorderedList();
- });
- evt.preventDefault();
- }
- return;
- }*/
-
- if (! isEditable) return;
-
- var type = evt.type;
- var charCode = evt.charCode;
- var keyCode = evt.keyCode;
- var mods = "";
- if (evt.altKey) mods = mods+"A";
- if (evt.ctrlKey) mods = mods+"C";
- if (evt.shiftKey) mods = mods+"S";
- if (evt.metaKey) mods = mods+"M";
- var modsPrfx = "";
- if (mods) modsPrfx = mods+"-";
- var which = evt.which;
-
- //dmesg("keyevent type: "+type+", which: "+which);
-
- // Don't take action based on modifier keys going up and down.
- // Modifier keys do not generate "keypress" events.
- // 224 is the command-key under Mac Firefox.
- // 91 is the Windows key in IE; it is ASCII for open-bracket but isn't the keycode for that key
- // 20 is capslock in IE.
- var isModKey = ((!charCode) &&
- ((type == "keyup") || (type == "keydown")) &&
- (keyCode == 16 || keyCode == 17 || keyCode == 18 || keyCode == 20 || keyCode == 224
- || keyCode == 91));
- if (isModKey) return;
-
- var specialHandled = false;
- var isTypeForSpecialKey = ((browser.msie || browser.safari) ?
- (type == "keydown") : (type == "keypress"));
- var isTypeForCmdKey = ((browser.msie || browser.safari) ? (type == "keydown") : (type == "keypress"));
-
- var stopped = false;
-
- inCallStack("handleKeyEvent", function() {
-
- if (type == "keypress" ||
- (isTypeForSpecialKey && keyCode == 13/*return*/)) {
- // in IE, special keys don't send keypress, the keydown does the action
- if (! outsideKeyPress(evt)) {
- evt.preventDefault();
- stopped = true;
- }
- }
- else if (type == "keydown") {
- outsideKeyDown(evt);
- }
-
- if (! stopped) {
- if (isTypeForSpecialKey && keyCode == 8) {
- // "delete" key; in mozilla, if we're at the beginning of a line, normalize now,
- // or else deleting a blank line can take two delete presses.
- // --
- // we do deletes completely customly now:
- // - allows consistent (and better) meta-delete behavior
- // - normalizing and then allowing default behavior confused IE
- // - probably eliminates a few minor quirks
- fastIncorp(3);
- evt.preventDefault();
- doDeleteKey(evt);
- specialHandled = true;
- }
- if ((!specialHandled) && isTypeForSpecialKey && keyCode == 13) {
- // return key, handle specially;
- // note that in mozilla we need to do an incorporation for proper return behavior anyway.
- fastIncorp(4);
- evt.preventDefault();
- doReturnKey();
- //scrollSelectionIntoView();
- scheduler.setTimeout(function() {outerWin.scrollBy(-100,0);}, 0);
- specialHandled = true;
- }
- if ((!specialHandled) && isTypeForSpecialKey && keyCode == 9 &&
- ! (evt.metaKey || evt.ctrlKey)) {
- // tab
- fastIncorp(5);
- evt.preventDefault();
- doTabKey(evt.shiftKey);
- //scrollSelectionIntoView();
- specialHandled = true;
- }
- if ((!specialHandled) && isTypeForCmdKey &&
- String.fromCharCode(which).toLowerCase() == "z" &&
- (evt.metaKey || evt.ctrlKey)) {
- // cmd-Z (undo)
- fastIncorp(6);
- evt.preventDefault();
- if (evt.shiftKey) {
- doUndoRedo("redo");
- }
- else {
- doUndoRedo("undo");
- }
- specialHandled = true;
- }
- if ((!specialHandled) && isTypeForCmdKey &&
- String.fromCharCode(which).toLowerCase() == "y" &&
- (evt.metaKey || evt.ctrlKey)) {
- // cmd-Y (redo)
- fastIncorp(10);
- evt.preventDefault();
- doUndoRedo("redo");
- specialHandled = true;
- }
- if ((!specialHandled) && isTypeForCmdKey &&
- String.fromCharCode(which).toLowerCase() == "b" &&
- (evt.metaKey || evt.ctrlKey)) {
- // cmd-B (bold)
- fastIncorp(13);
- evt.preventDefault();
- toggleAttributeOnSelection('bold');
- specialHandled = true;
- }
- if ((!specialHandled) && isTypeForCmdKey &&
- String.fromCharCode(which).toLowerCase() == "i" &&
- (evt.metaKey || evt.ctrlKey)) {
- // cmd-I (italic)
- fastIncorp(14);
- evt.preventDefault();
- toggleAttributeOnSelection('italic');
- specialHandled = true;
- }
- if ((!specialHandled) && isTypeForCmdKey &&
- String.fromCharCode(which).toLowerCase() == "u" &&
- (evt.metaKey || evt.ctrlKey)) {
- // cmd-U (underline)
- fastIncorp(15);
- evt.preventDefault();
- toggleAttributeOnSelection('underline');
- specialHandled = true;
- }
- if ((!specialHandled) && isTypeForCmdKey &&
- String.fromCharCode(which).toLowerCase() == "h" &&
- (evt.ctrlKey)) {
- // cmd-H (backspace)
- fastIncorp(20);
- evt.preventDefault();
- doDeleteKey();
- specialHandled = true;
- }
- /*if ((!specialHandled) && isTypeForCmdKey &&
- String.fromCharCode(which).toLowerCase() == "u" &&
- (evt.metaKey || evt.ctrlKey)) {
- // cmd-U
- doc.body.innerHTML = '';
- evt.preventDefault();
- specialHandled = true;
- }*/
-
- if (mozillaFakeArrows && mozillaFakeArrows.handleKeyEvent(evt)) {
- evt.preventDefault();
- specialHandled = true;
- }
- }
-
- if (type == "keydown") {
- idleWorkTimer.atLeast(500);
- }
- else if (type == "keypress") {
- if ((! specialHandled) && parenModule.shouldNormalizeOnChar(charCode)) {
- idleWorkTimer.atMost(0);
- }
- else {
- idleWorkTimer.atLeast(500);
- }
- }
- else if (type == "keyup") {
- var wait = 200;
- idleWorkTimer.atLeast(wait);
- idleWorkTimer.atMost(wait);
- }
-
- // Is part of multi-keystroke international character on Firefox Mac
- var isFirefoxHalfCharacter =
- (browser.mozilla && evt.altKey && charCode == 0 && keyCode == 0);
-
- // Is part of multi-keystroke international character on Safari Mac
- var isSafariHalfCharacter =
- (browser.safari && evt.altKey && keyCode == 229);
-
- if (thisKeyDoesntTriggerNormalize || isFirefoxHalfCharacter || isSafariHalfCharacter) {
- idleWorkTimer.atLeast(3000); // give user time to type
- // if this is a keydown, e.g., the keyup shouldn't trigger a normalize
- thisKeyDoesntTriggerNormalize = true;
- }
-
- if ((! specialHandled) && (! thisKeyDoesntTriggerNormalize) &&
- (! inInternationalComposition)) {
- if (type != "keyup" || ! incorpIfQuick()) {
- observeChangesAroundSelection();
- }
- }
-
- if (type == "keyup") {
- thisKeyDoesntTriggerNormalize = false;
- }
- });
- }
-
- var thisKeyDoesntTriggerNormalize = false;
-
- function doUndoRedo(which) {
- // precond: normalized DOM
- if (undoModule.enabled) {
- var whichMethod;
- if (which == "undo") whichMethod = 'performUndo';
- if (which == "redo") whichMethod = 'performRedo';
- if (whichMethod) {
- var oldEventType = currentCallStack.editEvent.eventType;
- currentCallStack.startNewEvent(which);
- undoModule[whichMethod](function(backset, selectionInfo) {
- if (backset) {
- performDocumentApplyChangeset(backset);
- }
- if (selectionInfo) {
- performSelectionChange(lineAndColumnFromChar(selectionInfo.selStart),
- lineAndColumnFromChar(selectionInfo.selEnd),
- selectionInfo.selFocusAtStart);
- }
- var oldEvent = currentCallStack.startNewEvent(oldEventType, true);
- return oldEvent;
- });
- }
- }
- }
-
- /*function enforceNewTextTypedStyle() {
- var sel = getSelection();
- var n = (sel && sel.startPoint && sel.startPoint.node);
- if (!n) return;
- var isInOurNode = false;
- while (n) {
- if (n.tagName) {
- var tag = n.tagName.toLowerCase();
- if (tag == "b" || tag == "strong") {
- isInOurNode = true;
- break;
- }
- if (((typeof n.className) == "string") &&
- n.className.toLowerCase().indexOf("Apple-style-span") >= 0) {
- isInOurNode = true;
- break;
- }
- }
- n = n.parentNode;
- }
-
- if (! isInOurNode) {
- doc.execCommand("Bold", false, null);
- }
-
- if (! browser.msie) {
- var browserSelection = window.getSelection();
- if (browserSelection && browserSelection.type != "None" &&
- browserSelection.rangeCount !== 0) {
- var range = browserSelection.getRangeAt(0);
- var surrounder = doc.createElement("B");
- range.surroundContents(surrounder);
- range.selectNodeContents(surrounder);
- browserSelection.removeAllRanges();
- browserSelection.addRange(range);
- }
- }
- }*/
-
- function updateBrowserSelectionFromRep() {
- // requires normalized DOM!
- var selStart = rep.selStart, selEnd = rep.selEnd;
-
- if (!(selStart && selEnd)) {
- setSelection(null);
- return;
- }
-
- var mozillaCaretHack = (false && browser.mozilla && selStart && selEnd &&
- selStart[0] == selEnd[0]
- && selStart[1] == rep.lines.atIndex(selStart[0]).lineMarker
- && selEnd[1] == rep.lines.atIndex(selEnd[0]).lineMarker &&
- setupMozillaCaretHack(selStart[0]));
-
- var selection = {};
-
- var ss = [selStart[0], selStart[1]];
- if (mozillaCaretHack) ss[1] += 1;
- selection.startPoint = getPointForLineAndChar(ss);
-
- var se = [selEnd[0], selEnd[1]];
- if (mozillaCaretHack) se[1] += 1;
- selection.endPoint = getPointForLineAndChar(se);
-
- selection.focusAtStart = !!rep.selFocusAtStart;
-
- setSelection(selection);
-
- if (mozillaCaretHack) {
- mozillaCaretHack.unhack();
- }
- }
-
- function getRepHTML() {
- /*function lineWithSelection(text, lineNum) {
- var haveSelStart = (rep.selStart && rep.selStart[0] == lineNum);
- var haveSelEnd = (rep.selEnd && rep.selEnd[0] == lineNum);
- var startCol = (haveSelStart && rep.selStart[1]);
- var endCol = (haveSelEnd && rep.selEnd[1]);
- var len = text.length;
- if (haveSelStart && haveSelEnd && startCol == endCol) {
- var color = "#000";
- if (endCol == len) {
- return '<span style="border-right: 1px solid '+color+'">'+
- htmlEscape(text)+'</span>';
- }
- else {
- return htmlEscape
- }
- }
- }*/
-
- return map(rep.lines.slice(), function (entry) {
- var text = entry.text;
- var content;
- if (text.length == 0) {
- content = '<span style="color: #aaa">--</span>';
- }
- else {
- content = htmlPrettyEscape(text);
- }
- return '<div><code>'+content+'</div></code>';
- }).join('');
- }
-
- function nodeMaxIndex(nd) {
- if (isNodeText(nd)) return nd.nodeValue.length;
- else return 1;
- }
-
- function hasIESelection() {
- var browserSelection;
- try { browserSelection = doc.selection; } catch (e) {}
- if (! browserSelection) return false;
- var origSelectionRange;
- try { origSelectionRange = browserSelection.createRange(); } catch (e) {}
- if (! origSelectionRange) return false;
- var selectionParent = origSelectionRange.parentElement();
- if (selectionParent.ownerDocument != doc) return false;
- return true;
- }
-
- function getSelection() {
- // returns null, or a structure containing startPoint and endPoint,
- // each of which has node (a magicdom node), index, and maxIndex. If the node
- // is a text node, maxIndex is the length of the text; else maxIndex is 1.
- // index is between 0 and maxIndex, inclusive.
- if (browser.msie) {
- var browserSelection;
- try { browserSelection = doc.selection; } catch (e) {}
- if (! browserSelection) return null;
- var origSelectionRange;
- try { origSelectionRange = browserSelection.createRange(); } catch (e) {}
- if (! origSelectionRange) return null;
- var selectionParent = origSelectionRange.parentElement();
- if (selectionParent.ownerDocument != doc) return null;
- function newRange() {
- return doc.body.createTextRange();
- }
- function rangeForElementNode(nd) {
- var rng = newRange();
- // doesn't work on text nodes
- rng.moveToElementText(nd);
- return rng;
- }
- function pointFromCollapsedRange(rng) {
- var parNode = rng.parentElement();
- var elemBelow = -1;
- var elemAbove = parNode.childNodes.length;
- var rangeWithin = rangeForElementNode(parNode);
-
- if (rng.compareEndPoints("StartToStart", rangeWithin) == 0) {
- return {node:parNode, index:0, maxIndex:1};
- }
- else if (rng.compareEndPoints("EndToEnd", rangeWithin) == 0) {
- if (isBlockElement(parNode) && parNode.nextSibling) {
- // caret after block is not consistent across browsers
- // (same line vs next) so put caret before next node
- return {node:parNode.nextSibling, index:0, maxIndex:1};
- }
- return {node:parNode, index:1, maxIndex:1};
- }
- else if (parNode.childNodes.length == 0) {
- return {node:parNode, index:0, maxIndex:1};
- }
-
- for(var i=0;i<parNode.childNodes.length;i++) {
- var n = parNode.childNodes.item(i);
- if (! isNodeText(n)) {
- var nodeRange = rangeForElementNode(n);
- var startComp = rng.compareEndPoints("StartToStart", nodeRange);
- var endComp = rng.compareEndPoints("EndToEnd", nodeRange);
- if (startComp >= 0 && endComp <= 0) {
- var index = 0;
- if (startComp > 0) {
- index = 1;
- }
- return {node:n, index:index, maxIndex:1};
- }
- else if (endComp > 0) {
- if (i > elemBelow) {
- elemBelow = i;
- rangeWithin.setEndPoint("StartToEnd", nodeRange);
- }
- }
- else if (startComp < 0) {
- if (i < elemAbove) {
- elemAbove = i;
- rangeWithin.setEndPoint("EndToStart", nodeRange);
- }
- }
- }
- }
- if ((elemAbove - elemBelow) == 1) {
- if (elemBelow >= 0) {
- return {node:parNode.childNodes.item(elemBelow), index:1, maxIndex:1};
- }
- else {
- return {node:parNode.childNodes.item(elemAbove), index:0, maxIndex:1};
- }
- }
- var idx = 0;
- var r = rng.duplicate();
- // infinite stateful binary search! call function for values 0 to inf,
- // expecting the answer to be about 40. return index of smallest
- // true value.
- var indexIntoRange = binarySearchInfinite(40, function (i) {
- // the search algorithm whips the caret back and forth,
- // though it has to be moved relatively and may hit
- // the end of the buffer
- var delta = i-idx;
- var moved = Math.abs(r.move("character", -delta));
- // next line is work-around for fact that when moving left, the beginning
- // of a text node is considered to be after the start of the parent element:
- if (r.move("character", -1)) r.move("character", 1);
- if (delta < 0) idx -= moved;
- else idx += moved;
- return (r.compareEndPoints("StartToStart", rangeWithin) <= 0);
- });
- // iterate over consecutive text nodes, point is in one of them
- var textNode = elemBelow+1;
- var indexLeft = indexIntoRange;
- while (textNode < elemAbove) {
- var tn = parNode.childNodes.item(textNode);
- if (indexLeft <= tn.nodeValue.length) {
- return {node:tn, index:indexLeft, maxIndex:tn.nodeValue.length};
- }
- indexLeft -= tn.nodeValue.length;
- textNode++;
- }
- var tn = parNode.childNodes.item(textNode-1);
- return {node:tn, index:tn.nodeValue.length, maxIndex:tn.nodeValue.length};
- }
- var selection = {};
- if (origSelectionRange.compareEndPoints("StartToEnd", origSelectionRange) == 0) {
- // collapsed
- var pnt = pointFromCollapsedRange(origSelectionRange);
- selection.startPoint = pnt;
- selection.endPoint = {node:pnt.node, index:pnt.index, maxIndex:pnt.maxIndex};
- }
- else {
- var start = origSelectionRange.duplicate();
- start.collapse(true);
- var end = origSelectionRange.duplicate();
- end.collapse(false);
- selection.startPoint = pointFromCollapsedRange(start);
- selection.endPoint = pointFromCollapsedRange(end);
- /*if ((!selection.startPoint.node.isText) && (!selection.endPoint.node.isText)) {
- console.log(selection.startPoint.node.uniqueId()+","+
- selection.startPoint.index+" / "+
- selection.endPoint.node.uniqueId()+","+
- selection.endPoint.index);
- }*/
- }
- return selection;
- }
- else {
- // non-IE browser
- var browserSelection = window.getSelection();
- if (browserSelection && browserSelection.type != "None" &&
- browserSelection.rangeCount !== 0) {
- var range = browserSelection.getRangeAt(0);
- function isInBody(n) {
- while (n && ! (n.tagName && n.tagName.toLowerCase() == "body")) {
- n = n.parentNode;
- }
- return !!n;
- }
- function pointFromRangeBound(container, offset) {
- if (! isInBody(container)) {
- // command-click in Firefox selects whole document, HEAD and BODY!
- return {node:root, index:0, maxIndex:1};
- }
- var n = container;
- var childCount = n.childNodes.length;
- if (isNodeText(n)) {
- return {node:n, index:offset, maxIndex:n.nodeValue.length};
- }
- else if (childCount == 0) {
- return {node:n, index:0, maxIndex:1};
- }
- // treat point between two nodes as BEFORE the second (rather than after the first)
- // if possible; this way point at end of a line block-element is treated as
- // at beginning of next line
- else if (offset == childCount) {
- var nd = n.childNodes.item(childCount-1);
- var max = nodeMaxIndex(nd);
- return {node:nd, index:max, maxIndex:max};
- }
- else {
- var nd = n.childNodes.item(offset);
- var max = nodeMaxIndex(nd);
- return {node:nd, index:0, maxIndex:max};
- }
- }
- var selection = {};
- selection.startPoint = pointFromRangeBound(range.startContainer, range.startOffset);
- selection.endPoint = pointFromRangeBound(range.endContainer, range.endOffset);
- selection.focusAtStart = (((range.startContainer != range.endContainer) ||
- (range.startOffset != range.endOffset)) &&
- browserSelection.anchorNode &&
- (browserSelection.anchorNode == range.endContainer) &&
- (browserSelection.anchorOffset == range.endOffset));
- return selection;
- }
- else return null;
- }
- }
-
- function setSelection(selection) {
- function copyPoint(pt) {
- return {node:pt.node, index:pt.index, maxIndex:pt.maxIndex};
- }
- if (browser.msie) {
- // Oddly enough, accessing scrollHeight fixes return key handling on IE 8,
- // presumably by forcing some kind of internal DOM update.
- doc.body.scrollHeight;
-
- function moveToElementText(s, n) {
- while (n.firstChild && ! isNodeText(n.firstChild)) {
- n = n.firstChild;
- }
- s.moveToElementText(n);
- }
- function newRange() {
- return doc.body.createTextRange();
- }
- function setCollapsedBefore(s, n) {
- // s is an IE TextRange, n is a dom node
- if (isNodeText(n)) {
- // previous node should not also be text, but prevent inf recurs
- if (n.previousSibling && ! isNodeText(n.previousSibling)) {
- setCollapsedAfter(s, n.previousSibling);
- }
- else {
- setCollapsedBefore(s, n.parentNode);
- }
- }
- else {
- moveToElementText(s, n);
- // work around for issue that caret at beginning of line
- // somehow ends up at end of previous line
- if (s.move('character', 1)) {
- s.move('character', -1);
- }
- s.collapse(true); // to start
- }
- }
- function setCollapsedAfter(s, n) {
- // s is an IE TextRange, n is a magicdom node
- if (isNodeText(n)) {
- // can't use end of container when no nextSibling (could be on next line),
- // so use previousSibling or start of container and move forward.
- setCollapsedBefore(s, n);
- s.move("character", n.nodeValue.length);
- }
- else {
- moveToElementText(s, n);
- s.collapse(false); // to end
- }
- }
- function getPointRange(point) {
- var s = newRange();
- var n = point.node;
- if (isNodeText(n)) {
- setCollapsedBefore(s, n);
- s.move("character", point.index);
- }
- else if (point.index == 0) {
- setCollapsedBefore(s, n);
- }
- else {
- setCollapsedAfter(s, n);
- }
- return s;
- }
-
- if (selection) {
- if (! hasIESelection()) {
- return; // don't steal focus
- }
-
- var startPoint = copyPoint(selection.startPoint);
- var endPoint = copyPoint(selection.endPoint);
-
- // fix issue where selection can't be extended past end of line
- // with shift-rightarrow or shift-downarrow
- if (endPoint.index == endPoint.maxIndex && endPoint.node.nextSibling) {
- endPoint.node = endPoint.node.nextSibling;
- endPoint.index = 0;
- endPoint.maxIndex = nodeMaxIndex(endPoint.node);
- }
- var range = getPointRange(startPoint);
- range.setEndPoint("EndToEnd", getPointRange(endPoint));
-
- // setting the selection in IE causes everything to scroll
- // so that the selection is visible. if setting the selection
- // definitely accomplishes nothing, don't do it.
- function isEqualToDocumentSelection(rng) {
- var browserSelection;
- try { browserSelection = doc.selection; } catch (e) {}
- if (! browserSelection) return false;
- var rng2 = browserSelection.createRange();
- if (rng2.parentElement().ownerDocument != doc) return false;
- if (rng.compareEndPoints("StartToStart", rng2) !== 0) return false;
- if (rng.compareEndPoints("EndToEnd", rng2) !== 0) return false;
- return true;
- }
- if (! isEqualToDocumentSelection(range)) {
- //dmesg(toSource(selection));
- //dmesg(escapeHTML(doc.body.innerHTML));
- range.select();
- }
- }
- else {
- try { doc.selection.empty(); } catch (e) {}
- }
- }
- else {
- // non-IE browser
- var isCollapsed;
- function pointToRangeBound(pt) {
- var p = copyPoint(pt);
- // Make sure Firefox cursor is deep enough; fixes cursor jumping when at top level,
- // and also problem where cut/copy of a whole line selected with fake arrow-keys
- // copies the next line too.
- if (isCollapsed) {
- function diveDeep() {
- while (p.node.childNodes.length > 0) {
- //&& (p.node == root || p.node.parentNode == root)) {
- if (p.index == 0) {
- p.node = p.node.firstChild;
- p.maxIndex = nodeMaxIndex(p.node);
- }
- else if (p.index == p.maxIndex) {
- p.node = p.node.lastChild;
- p.maxIndex = nodeMaxIndex(p.node);
- p.index = p.maxIndex;
- }
- else break;
- }
- }
- // now fix problem where cursor at end of text node at end of span-like element
- // with background doesn't seem to show up...
- if (isNodeText(p.node) && p.index == p.maxIndex) {
- var n = p.node;
- while ((! n.nextSibling) && (n != root) && (n.parentNode != root)) {
- n = n.parentNode;
- }
- if (n.nextSibling &&
- (! ((typeof n.nextSibling.tagName) == "string" &&
- n.nextSibling.tagName.toLowerCase() == "br")) &&
- (n != p.node) && (n != root) && (n.parentNode != root)) {
- // found a parent, go to next node and dive in
- p.node = n.nextSibling;
- p.maxIndex = nodeMaxIndex(p.node);
- p.index = 0;
- diveDeep();
- }
- }
- // try to make sure insertion point is styled;
- // also fixes other FF problems
- if (! isNodeText(p.node)) {
- diveDeep();
- }
- }
- /*// make sure Firefox cursor is shallow enough;
- // to fix problem where "return" between two spans doesn't move the caret to
- // the next line
- // (decided against)
- while (!(p.node.isRoot || p.node.parent().isRoot || p.node.parent().parent().isRoot)) {
- if (p.index == 0 && ! p.node.prev()) {
- p.node = p.node.parent();
- p.maxIndex = 1;
- }
- else if (p.index == p.maxIndex && ! p.node.next()) {
- p.node = p.node.parent();
- p.maxIndex = 1;
- p.index = 1;
- }
- else break;
- }
- if ((! p.node.isRoot) && (!p.node.parent().isRoot) &&
- (p.index == p.maxIndex) && p.node.next()) {
- p.node = p.node.next();
- p.maxIndex = nodeMaxIndex(p.node);
- p.index = 0;
- }*/
- if (isNodeText(p.node)) {
- return { container: p.node, offset: p.index };
- }
- else {
- // p.index in {0,1}
- return { container: p.node.parentNode, offset: childIndex(p.node) + p.index };
- }
- }
- var browserSelection = window.getSelection();
- if (browserSelection) {
- browserSelection.removeAllRanges();
- if (selection) {
- isCollapsed = (selection.startPoint.node === selection.endPoint.node &&
- selection.startPoint.index === selection.endPoint.index);
- var start = pointToRangeBound(selection.startPoint);
- var end = pointToRangeBound(selection.endPoint);
-
- if ((!isCollapsed) && selection.focusAtStart && browserSelection.collapse && browserSelection.extend) {
- // can handle "backwards"-oriented selection, shift-arrow-keys move start
- // of selection
- browserSelection.collapse(end.container, end.offset);
- //console.trace();
- //console.log(htmlPrettyEscape(rep.alltext));
- //console.log("%o %o", rep.selStart, rep.selEnd);
- //console.log("%o %d", start.container, start.offset);
- browserSelection.extend(start.container, start.offset);
- }
- else {
- var range = doc.createRange();
- range.setStart(start.container, start.offset);
- range.setEnd(end.container, end.offset);
- browserSelection.removeAllRanges();
- browserSelection.addRange(range);
- }
- }
- }
- }
- }
-
- function childIndex(n) {
- var idx = 0;
- while (n.previousSibling) {
- idx++;
- n = n.previousSibling;
- }
- return idx;
- }
-
- function fixView() {
- // calling this method repeatedly should be fast
-
- if (getInnerWidth() == 0 || getInnerHeight() == 0) {
- return;
- }
-
- function setIfNecessary(obj, prop, value) {
- if (obj[prop] != value) {
- obj[prop] = value;
- }
- }
-
- var lineNumberWidth = sideDiv.firstChild.offsetWidth;
- var newSideDivWidth = lineNumberWidth + LINE_NUMBER_PADDING_LEFT;
- if (newSideDivWidth < MIN_LINEDIV_WIDTH) newSideDivWidth = MIN_LINEDIV_WIDTH;
- iframePadLeft = EDIT_BODY_PADDING_LEFT;
- if (hasLineNumbers) iframePadLeft += newSideDivWidth + LINE_NUMBER_PADDING_RIGHT;
- setIfNecessary(iframe.style, "left", iframePadLeft+"px");
- setIfNecessary(sideDiv.style, "width", newSideDivWidth+"px");
-
- for(var i=0;i<2;i++) {
- var newHeight = root.clientHeight;
- var newWidth = (browser.msie ? root.createTextRange().boundingWidth : root.clientWidth);
- var viewHeight = getInnerHeight() - iframePadBottom - iframePadTop;
- var viewWidth = getInnerWidth() - iframePadLeft - iframePadRight;
- if (newHeight < viewHeight) {
- newHeight = viewHeight;
- if (browser.msie) setIfNecessary(outerWin.document.documentElement.style, 'overflowY', 'auto');
- }
- else {
- if (browser.msie) setIfNecessary(outerWin.document.documentElement.style, 'overflowY', 'scroll');
- }
- if (doesWrap) {
- newWidth = viewWidth;
- }
- else {
- if (newWidth < viewWidth) newWidth = viewWidth;
- }
- if (newHeight > 32000) newHeight = 32000;
- if (newWidth > 32000) newWidth = 32000;
- setIfNecessary(iframe.style, "height", newHeight+"px");
- setIfNecessary(iframe.style, "width", newWidth+"px");
- setIfNecessary(sideDiv.style, "height", newHeight+"px");
- }
- if (browser.mozilla) {
- if (! doesWrap) {
- // the body:display:table-cell hack makes mozilla do scrolling
- // correctly by shrinking the <body> to fit around its content,
- // but mozilla won't act on clicks below the body. We keep the
- // style.height property set to the viewport height (editor height
- // not including scrollbar), so it will never shrink so that part of
- // the editor isn't clickable.
- var body = root;
- var styleHeight = viewHeight+"px";
- setIfNecessary(body.style, "height", styleHeight);
- }
- else {
- setIfNecessary(root.style, "height", "");
- }
- }
- // if near edge, scroll to edge
- var scrollX = getScrollX();
- var scrollY = getScrollY();
- var win = outerWin;
- var r = 20;
- /*if (scrollX <= iframePadLeft+r) win.scrollBy(-iframePadLeft-r, 0);
- else if (getPageWidth() - scrollX - getInnerWidth() <= iframePadRight+r)
- scrollBy(iframePadRight+r, 0);*/
- /*if (scrollY <= iframePadTop+r) win.scrollBy(0, -iframePadTop-r);
- else if (getPageHeight() - scrollY - getInnerHeight() <= iframePadBottom+r)
- scrollBy(0, iframePadBottom+r);*/
-
- enforceEditability();
-
- addClass(sideDiv, 'sidedivdelayed');
- }
-
- function getScrollXY() {
- var win = outerWin;
- var odoc = outerWin.document;
- if (typeof(win.pageYOffset) == "number") {
- return {x: win.pageXOffset, y: win.pageYOffset};
- }
- var docel = odoc.documentElement;
- if (docel && typeof(docel.scrollTop) == "number") {
- return {x:docel.scrollLeft, y:docel.scrollTop};
- }
- }
-
- function getScrollX() {
- return getScrollXY().x;
- }
-
- function getScrollY() {
- return getScrollXY().y;
- }
-
- function setScrollX(x) {
- outerWin.scrollTo(x, getScrollY());
- }
-
- function setScrollY(y) {
- outerWin.scrollTo(getScrollX(), y);
- }
-
- function setScrollXY(x, y) {
- outerWin.scrollTo(x, y);
- }
-
- var _teardownActions = [];
- function teardown() {
- forEach(_teardownActions, function (a) { a(); });
- }
-
- bindEventHandler(window, "load", setup);
-
- function setDesignMode(newVal) {
- try {
- function setIfNecessary(target, prop, val) {
- if (String(target[prop]).toLowerCase() != val) {
- target[prop] = val;
- return true;
- }
- return false;
- }
- if (browser.msie || browser.safari) {
- setIfNecessary(root, 'contentEditable', (newVal ? 'true' : 'false'));
- }
- else {
- var wasSet = setIfNecessary(doc, 'designMode', (newVal ? 'on' : 'off'));
- if (wasSet && newVal && browser.opera) {
- // turning on designMode clears event handlers
- bindTheEventHandlers();
- }
- }
- return true;
- }
- catch (e) {
- return false;
- }
- }
-
- var iePastedLines = null;
- function handleIEPaste(evt) {
- // Pasting in IE loses blank lines in a way that loses information;
- // "one\n\ntwo\nthree" becomes "<p>one</p><p>two</p><p>three</p>",
- // which becomes "one\ntwo\nthree". We can get the correct text
- // from the clipboard directly, but we still have to let the paste
- // happen to get the style information.
-
- var clipText = window.clipboardData && window.clipboardData.getData("Text");
- if (clipText && doc.selection) {
- // this "paste" event seems to mess with the selection whether we try to
- // stop it or not, so can't really do document-level manipulation now
- // or in an idle call-stack. instead, use IE native manipulation
- //function escapeLine(txt) {
- //return processSpaces(escapeHTML(textify(txt)));
- //}
- //var newHTML = map(clipText.replace(/\r/g,'').split('\n'), escapeLine).join('<br>');
- //doc.selection.createRange().pasteHTML(newHTML);
- //evt.preventDefault();
-
- //iePastedLines = map(clipText.replace(/\r/g,'').split('\n'), textify);
- }
- }
-
- var inInternationalComposition = false;
-
- function handleCompositionEvent(evt) {
- // international input events, fired in FF3, at least; allow e.g. Japanese input
- if (evt.type == "compositionstart") {
- inInternationalComposition = true;
- }
- else if (evt.type == "compositionend") {
- inInternationalComposition = false;
- }
- }
-
- /*function handleTextEvent(evt) {
- top.console.log("TEXT EVENT");
- inCallStackIfNecessary("handleTextEvent", function() {
- observeChangesAroundSelection();
- });
- }*/
-
- function bindTheEventHandlers() {
- bindEventHandler(window, "unload", teardown);
- bindEventHandler(document, "keydown", handleKeyEvent);
- bindEventHandler(document, "keypress", handleKeyEvent);
- bindEventHandler(document, "keyup", handleKeyEvent);
- bindEventHandler(document, "click", handleClick);
- bindEventHandler(root, "blur", handleBlur);
- if (browser.msie) {
- bindEventHandler(document, "click", handleIEOuterClick);
- }
- if (browser.msie) bindEventHandler(root, "paste", handleIEPaste);
- if ((! browser.msie) && document.documentElement) {
- bindEventHandler(document.documentElement, "compositionstart", handleCompositionEvent);
- bindEventHandler(document.documentElement, "compositionend", handleCompositionEvent);
- }
-
- /*bindEventHandler(window, "mousemove", function(e) {
- if (e.pageX < 10) {
- window.DEBUG_DONT_INCORP = (e.pageX < 2);
- }
- });*/
- }
-
- function handleIEOuterClick(evt) {
- if ((evt.target.tagName||'').toLowerCase() != "html") {
- return;
- }
- if (!(evt.pageY > root.clientHeight)) {
- return;
- }
-
- // click below the body
- inCallStack("handleOuterClick", function() {
- // put caret at bottom of doc
- fastIncorp(11);
- if (isCaret()) { // don't interfere with drag
- var lastLine = rep.lines.length()-1;
- var lastCol = rep.lines.atIndex(lastLine).text.length;
- performSelectionChange([lastLine,lastCol],[lastLine,lastCol]);
- }
- });
- }
-
- function getClassArray(elem, optFilter) {
- var bodyClasses = [];
- (elem.className || '').replace(/\S+/g, function (c) {
- if ((! optFilter) || (optFilter(c))) {
- bodyClasses.push(c);
- }
- });
- return bodyClasses;
- }
- function setClassArray(elem, array) {
- elem.className = array.join(' ');
- }
- function addClass(elem, className) {
- var seen = false;
- var cc = getClassArray(elem, function(c) { if (c == className) seen = true; return true; });
- if (! seen) {
- cc.push(className);
- setClassArray(elem, cc);
- }
- }
- function removeClass(elem, className) {
- var seen = false;
- var cc = getClassArray(elem, function(c) {
- if (c == className) { seen = true; return false; } return true; });
- if (seen) {
- setClassArray(elem, cc);
- }
- }
- function setClassPresence(elem, className, present) {
- if (present) addClass(elem, className);
- else removeClass(elem, className);
- }
-
- function setup() {
- doc = document; // defined as a var in scope outside
- inCallStack("setup", function() {
- var body = doc.getElementById("innerdocbody");
- root = body; // defined as a var in scope outside
-
- if (browser.mozilla) addClass(root, "mozilla");
- if (browser.safari) addClass(root, "safari");
- if (browser.msie) addClass(root, "msie");
- if (browser.msie) {
- // cache CSS background images
- try {
- doc.execCommand("BackgroundImageCache", false, true);
- }
- catch (e) {
- /* throws an error in some IE 6 but not others! */
- }
- }
- setClassPresence(root, "authorColors", true);
- setClassPresence(root, "doesWrap", doesWrap);
-
- initDynamicCSS();
-
- enforceEditability();
-
- // set up dom and rep
- while (root.firstChild) root.removeChild(root.firstChild);
- var oneEntry = createDomLineEntry("");
- doRepLineSplice(0, rep.lines.length(), [oneEntry]);
- insertDomLines(null, [oneEntry.domInfo], null);
- rep.alines = Changeset.splitAttributionLines(
- Changeset.makeAttribution("\n"), "\n");
-
- bindTheEventHandlers();
-
- });
-
- scheduler.setTimeout(function() {
- parent.readyFunc(); // defined in code that sets up the inner iframe
- }, 0);
-
- isSetUp = true;
- }
-
- function focus() {
- window.focus();
- }
-
- function handleBlur(evt) {
- if (browser.msie) {
- // a fix: in IE, clicking on a control like a button outside the
- // iframe can "blur" the editor, causing it to stop getting
- // events, though typing still affects it(!).
- setSelection(null);
- }
- }
-
- function bindEventHandler(target, type, func) {
- var handler;
- if ((typeof func._wrapper) != "function") {
- func._wrapper = function(event) {
- func(fixEvent(event || window.event || {}));
- }
- }
- var handler = func._wrapper;
- if (target.addEventListener)
- target.addEventListener(type, handler, false);
- else
- target.attachEvent("on" + type, handler);
- _teardownActions.push(function() {
- unbindEventHandler(target, type, func);
- });
- }
-
- function unbindEventHandler(target, type, func) {
- var handler = func._wrapper;
- if (target.removeEventListener)
- target.removeEventListener(type, handler, false);
- else
- target.detachEvent("on" + type, handler);
- }
-
- /*forEach(['rep', 'getCleanNodeByKey', 'getDirtyRanges', 'isNodeDirty',
- 'getSelection', 'setSelection', 'updateBrowserSelectionFromRep',
- 'makeRecentSet', 'resetProfiler', 'getScrollXY', 'makeIdleAction'], function (k) {
- top['_'+k] = eval(k);
- });*/
-
- function getSelectionPointX(point) {
- // doesn't work in wrap-mode
- var node = point.node;
- var index = point.index;
- function leftOf(n) { return n.offsetLeft; }
- function rightOf(n) { return n.offsetLeft + n.offsetWidth; }
- if (! isNodeText(node)) {
- if (index == 0) return leftOf(node);
- else return rightOf(node);
- }
- else {
- // we can get bounds of element nodes, so look for those.
- // allow consecutive text nodes for robustness.
- var charsToLeft = index;
- var charsToRight = node.nodeValue.length - index;
- var n;
- for(n = node.previousSibling; n && isNodeText(n); n = n.previousSibling)
- charsToLeft += n.nodeValue;
- var leftEdge = (n ? rightOf(n) : leftOf(node.parentNode));
- for(n = node.nextSibling; n && isNodeText(n); n = n.nextSibling)
- charsToRight += n.nodeValue;
- var rightEdge = (n ? leftOf(n) : rightOf(node.parentNode));
- var frac = (charsToLeft / (charsToLeft + charsToRight));
- var pixLoc = leftEdge + frac*(rightEdge - leftEdge);
- return Math.round(pixLoc);
- }
- }
-
- function getPageHeight() {
- var win = outerWin;
- var odoc = win.document;
- if (win.innerHeight && win.scrollMaxY) return win.innerHeight + win.scrollMaxY;
- else if (odoc.body.scrollHeight > odoc.body.offsetHeight) return odoc.body.scrollHeight;
- else return odoc.body.offsetHeight;
- }
-
- function getPageWidth() {
- var win = outerWin;
- var odoc = win.document;
- if (win.innerWidth && win.scrollMaxX) return win.innerWidth + win.scrollMaxX;
- else if (odoc.body.scrollWidth > odoc.body.offsetWidth) return odoc.body.scrollWidth;
- else return odoc.body.offsetWidth;
- }
-
- function getInnerHeight() {
- var win = outerWin;
- var odoc = win.document;
- var h;
- if (browser.opera) h = win.innerHeight;
- else h = odoc.documentElement.clientHeight;
- if (h) return h;
-
- // deal with case where iframe is hidden, hope that
- // style.height of iframe container is set in px
- return Number(editorInfo.frame.parentNode.style.height.replace(/[^0-9]/g,'')
- || 0);
- }
-
- function getInnerWidth() {
- var win = outerWin;
- var odoc = win.document;
- return odoc.documentElement.clientWidth;
- }
-
- function scrollNodeVerticallyIntoView(node) {
- // requires element (non-text) node;
- // if node extends above top of viewport or below bottom of viewport (or top of scrollbar),
- // scroll it the minimum distance needed to be completely in view.
- var win = outerWin;
- var odoc = outerWin.document;
- var distBelowTop = node.offsetTop + iframePadTop - win.scrollY;
- var distAboveBottom = win.scrollY + getInnerHeight() -
- (node.offsetTop +iframePadTop + node.offsetHeight);
-
- if (distBelowTop < 0) {
- win.scrollBy(0, distBelowTop);
- }
- else if (distAboveBottom < 0) {
- win.scrollBy(0, -distAboveBottom);
- }
- }
-
- function scrollXHorizontallyIntoView(pixelX) {
- var win = outerWin;
- var odoc = outerWin.document;
- pixelX += iframePadLeft;
- var distInsideLeft = pixelX - win.scrollX;
- var distInsideRight = win.scrollX + getInnerWidth() - pixelX;
- if (distInsideLeft < 0) {
- win.scrollBy(distInsideLeft, 0);
- }
- else if (distInsideRight < 0) {
- win.scrollBy(-distInsideRight+1, 0);
- }
- }
-
- function scrollSelectionIntoView() {
- if (! rep.selStart) return;
- fixView();
- var focusLine = (rep.selFocusAtStart ? rep.selStart[0] : rep.selEnd[0]);
- scrollNodeVerticallyIntoView(rep.lines.atIndex(focusLine).lineNode);
- if (! doesWrap) {
- var browserSelection = getSelection();
- if (browserSelection) {
- var focusPoint = (browserSelection.focusAtStart ? browserSelection.startPoint :
- browserSelection.endPoint);
- var selectionPointX = getSelectionPointX(focusPoint);
- scrollXHorizontallyIntoView(selectionPointX);
- fixView();
- }
- }
- }
-
- function getLineListType(lineNum) {
- // get "list" attribute of first char of line
- var aline = rep.alines[lineNum];
- if (aline) {
- var opIter = Changeset.opIterator(aline);
- if (opIter.hasNext()) {
- return Changeset.opAttributeValue(opIter.next(), 'list', rep.apool) || '';
- }
- }
- return '';
- }
-
- function setLineListType(lineNum, listType) {
- setLineListTypes([[lineNum, listType]]);
- }
-
- function setLineListTypes(lineNumTypePairsInOrder) {
- var loc = [0,0];
- var builder = Changeset.builder(rep.lines.totalWidth());
- for(var i=0;i<lineNumTypePairsInOrder.length;i++) {
- var pair = lineNumTypePairsInOrder[i];
- var lineNum = pair[0];
- var listType = pair[1];
- buildKeepRange(builder, loc, (loc = [lineNum,0]));
- if (getLineListType(lineNum)) {
- // already a line marker
- if (listType) {
- // make different list type
- buildKeepRange(builder, loc, (loc = [lineNum,1]),
- [['list',listType]], rep.apool);
- }
- else {
- // remove list marker
- buildRemoveRange(builder, loc, (loc = [lineNum,1]));
- }
- }
- else {
- // currently no line marker
- if (listType) {
- // add a line marker
- builder.insert('*', [['author', thisAuthor],
- ['insertorder', 'first'],
- ['list', listType]], rep.apool);
- }
- }
- }
-
- var cs = builder.toString();
- if (! Changeset.isIdentity(cs)) {
- performDocumentApplyChangeset(cs);
- }
- }
-
- function doInsertUnorderedList() {
- if (! (rep.selStart && rep.selEnd)) {
- return;
- }
-
- var firstLine, lastLine;
- firstLine = rep.selStart[0];
- lastLine = Math.max(firstLine,
- rep.selEnd[0] - ((rep.selEnd[1] == 0) ? 1 : 0));
-
- var allLinesAreList = true;
- for(var n=firstLine;n<=lastLine;n++) {
- if (! getLineListType(n)) {
- allLinesAreList = false;
- break;
- }
- }
-
- var mods = [];
- for(var n=firstLine;n<=lastLine;n++) {
- var t = getLineListType(n);
- mods.push([n, allLinesAreList ? '' : (t ? t : 'bullet1')]);
- }
- setLineListTypes(mods);
- }
-
- var mozillaFakeArrows = (browser.mozilla && (function() {
- // In Firefox 2, arrow keys are unstable while DOM-manipulating
- // operations are going on. Specifically, if an operation
- // (computation that ties up the event queue) is going on (in the
- // call-stack of some event, like a timeout) that at some point
- // mutates nodes involved in the selection, then the arrow
- // keypress may (randomly) move the caret to the beginning or end
- // of the document. If the operation also mutates the selection
- // range, the old selection or the new selection may be used, or
- // neither.
-
- // As long as the arrow is pressed during the busy operation, it
- // doesn't seem to matter that the keydown and keypress events
- // aren't generated until afterwards, or that the arrow movement
- // can still be stopped (meaning it hasn't been performed yet);
- // Firefox must be preserving some old information about the
- // selection or the DOM from when the key was initially pressed.
- // However, it also doesn't seem to matter when the key was
- // actually pressed relative to the time of the mutation within
- // the prolonged operation. Also, even in very controlled tests
- // (like a mutation followed by a long period of busyWaiting), the
- // problem shows up often but not every time, with no discernable
- // pattern. Who knows, it could have something to do with the
- // caret-blinking timer, or DOM changes not being applied
- // immediately.
-
- // This problem, mercifully, does not show up at all in IE or
- // Safari. My solution is to have my own, full-featured arrow-key
- // implementation for Firefox.
-
- // Note that the problem addressed here is potentially very subtle,
- // especially if the operation is quick and is timed to usually happen
- // when the user is idle.
-
- // features:
- // - 'up' and 'down' arrows preserve column when passing through shorter lines
- // - shift-arrows extend the "focus" point, which may be start or end of range
- // - the focus point is kept horizontally and vertically scrolled into view
- // - arrows without shift cause caret to move to beginning or end of selection (left,right)
- // or move focus point up or down a line (up,down)
- // - command-(left,right,up,down) on Mac acts like (line-start, line-end, doc-start, doc-end)
- // - takes wrapping into account when doesWrap is true, i.e. up-arrow and down-arrow move
- // between the virtual lines within a wrapped line; this was difficult, and unfortunately
- // requires mutating the DOM to get the necessary information
-
- var savedFocusColumn = 0; // a value of 0 has no effect
- var updatingSelectionNow = false;
-
- function getVirtualLineView(lineNum) {
- var lineNode = rep.lines.atIndex(lineNum).lineNode;
- while (lineNode.firstChild && isBlockElement(lineNode.firstChild)) {
- lineNode = lineNode.firstChild;
- }
- return makeVirtualLineView(lineNode);
- }
-
- function markerlessLineAndChar(line, chr) {
- return [line, chr - rep.lines.atIndex(line).lineMarker];
- }
- function markerfulLineAndChar(line, chr) {
- return [line, chr + rep.lines.atIndex(line).lineMarker];
- }
-
- return {
- notifySelectionChanged: function() {
- if (! updatingSelectionNow) {
- savedFocusColumn = 0;
- }
- },
- handleKeyEvent: function(evt) {
- // returns "true" if handled
- if (evt.type != "keypress") return false;
- var keyCode = evt.keyCode;
- if (keyCode < 37 || keyCode > 40) return false;
- incorporateUserChanges();
-
- if (!(rep.selStart && rep.selEnd)) return true;
-
- // {byWord,toEnd,normal}
- var moveMode = (evt.altKey ? "byWord" :
- (evt.ctrlKey ? "byWord" :
- (evt.metaKey ? "toEnd" :
- "normal")));
-
- var anchorCaret =
- markerlessLineAndChar(rep.selStart[0], rep.selStart[1]);
- var focusCaret =
- markerlessLineAndChar(rep.selEnd[0], rep.selEnd[1]);
- var wasCaret = isCaret();
- if (rep.selFocusAtStart) {
- var tmp = anchorCaret; anchorCaret = focusCaret; focusCaret = tmp;
- }
- var K_UP = 38, K_DOWN = 40, K_LEFT = 37, K_RIGHT = 39;
- var dontMove = false;
- if (wasCaret && ! evt.shiftKey) {
- // collapse, will mutate both together
- anchorCaret = focusCaret;
- }
- else if ((! wasCaret) && (! evt.shiftKey)) {
- if (keyCode == K_LEFT) {
- // place caret at beginning
- if (rep.selFocusAtStart) anchorCaret = focusCaret;
- else focusCaret = anchorCaret;
- if (moveMode == "normal") dontMove = true;
- }
- else if (keyCode == K_RIGHT) {
- // place caret at end
- if (rep.selFocusAtStart) focusCaret = anchorCaret;
- else anchorCaret = focusCaret;
- if (moveMode == "normal") dontMove = true;
- }
- else {
- // collapse, will mutate both together
- anchorCaret = focusCaret;
- }
- }
- if (! dontMove) {
- function lineLength(i) {
- var entry = rep.lines.atIndex(i);
- return entry.text.length - entry.lineMarker;
- }
- function lineText(i) {
- var entry = rep.lines.atIndex(i);
- return entry.text.substring(entry.lineMarker);
- }
-
- if (keyCode == K_UP || keyCode == K_DOWN) {
- var up = (keyCode == K_UP);
- var canChangeLines = ((up && focusCaret[0]) ||
- ((!up) && focusCaret[0] < rep.lines.length()-1));
- var virtualLineView, virtualLineSpot, canChangeVirtualLines = false;
- if (doesWrap) {
- virtualLineView = getVirtualLineView(focusCaret[0]);
- virtualLineSpot = virtualLineView.getVLineAndOffsetForChar(focusCaret[1]);
- canChangeVirtualLines = ((up && virtualLineSpot.vline > 0) ||
- ((!up) && virtualLineSpot.vline < (
- virtualLineView.getNumVirtualLines() - 1)));
- }
- var newColByVirtualLineChange;
- if (moveMode == "toEnd") {
- if (up) {
- focusCaret[0] = 0;
- focusCaret[1] = 0;
- }
- else {
- focusCaret[0] = rep.lines.length()-1;
- focusCaret[1] = lineLength(focusCaret[0]);
- }
- }
- else if (moveMode == "byWord") {
- // move by "paragraph", a feature that Firefox lacks but IE and Safari both have
- if (up) {
- if (focusCaret[1] == 0 && canChangeLines) {
- focusCaret[0]--;
- focusCaret[1] = 0;
- }
- else focusCaret[1] = 0;
- }
- else {
- var lineLen = lineLength(focusCaret[0]);
- if (browser.windows) {
- if (canChangeLines) {
- focusCaret[0]++;
- focusCaret[1] = 0;
- }
- else {
- focusCaret[1] = lineLen;
- }
- }
- else {
- if (focusCaret[1] == lineLen && canChangeLines) {
- focusCaret[0]++;
- focusCaret[1] = lineLength(focusCaret[0]);
- }
- else {
- focusCaret[1] = lineLen;
- }
- }
- }
- savedFocusColumn = 0;
- }
- else if (canChangeVirtualLines) {
- var vline = virtualLineSpot.vline;
- var offset = virtualLineSpot.offset;
- if (up) vline--;
- else vline++;
- if (savedFocusColumn > offset) offset = savedFocusColumn;
- else {
- savedFocusColumn = offset;
- }
- var newSpot = virtualLineView.getCharForVLineAndOffset(vline, offset);
- focusCaret[1] = newSpot.lineChar;
- }
- else if (canChangeLines) {
- if (up) focusCaret[0]--;
- else focusCaret[0]++;
- var offset = focusCaret[1];
- if (doesWrap) {
- offset = virtualLineSpot.offset;
- }
- if (savedFocusColumn > offset) offset = savedFocusColumn;
- else {
- savedFocusColumn = offset;
- }
- if (doesWrap) {
- var newLineView = getVirtualLineView(focusCaret[0]);
- var vline = (up ? newLineView.getNumVirtualLines()-1 : 0);
- var newSpot = newLineView.getCharForVLineAndOffset(vline, offset);
- focusCaret[1] = newSpot.lineChar;
- }
- else {
- var lineLen = lineLength(focusCaret[0]);
- if (offset > lineLen) offset = lineLen;
- focusCaret[1] = offset;
- }
- }
- else {
- if (up) focusCaret[1] = 0;
- else focusCaret[1] = lineLength(focusCaret[0]);
- savedFocusColumn = 0;
- }
- }
- else if (keyCode == K_LEFT || keyCode == K_RIGHT) {
- var left = (keyCode == K_LEFT);
- if (left) {
- if (moveMode == "toEnd") focusCaret[1] = 0;
- else if (focusCaret[1] > 0) {
- if (moveMode == "byWord") {
- focusCaret[1] = moveByWordInLine(lineText(focusCaret[0]), focusCaret[1], false);
- }
- else {
- focusCaret[1]--;
- }
- }
- else if (focusCaret[0] > 0) {
- focusCaret[0]--;
- focusCaret[1] = lineLength(focusCaret[0]);
- if (moveMode == "byWord") {
- focusCaret[1] = moveByWordInLine(lineText(focusCaret[0]), focusCaret[1], false);
- }
- }
- }
- else {
- var lineLen = lineLength(focusCaret[0]);
- if (moveMode == "toEnd") focusCaret[1] = lineLen;
- else if (focusCaret[1] < lineLen) {
- if (moveMode == "byWord") {
- focusCaret[1] = moveByWordInLine(lineText(focusCaret[0]), focusCaret[1], true);
- }
- else {
- focusCaret[1]++;
- }
- }
- else if (focusCaret[0] < rep.lines.length()-1) {
- focusCaret[0]++;
- focusCaret[1] = 0;
- if (moveMode == "byWord") {
- focusCaret[1] = moveByWordInLine(lineText(focusCaret[0]), focusCaret[1], true);
- }
- }
- }
- savedFocusColumn = 0;
- }
- }
-
- var newSelFocusAtStart = ((focusCaret[0] < anchorCaret[0]) ||
- (focusCaret[0] == anchorCaret[0] &&
- focusCaret[1] < anchorCaret[1]));
- var newSelStart = (newSelFocusAtStart ? focusCaret : anchorCaret);
- var newSelEnd = (newSelFocusAtStart ? anchorCaret : focusCaret);
- updatingSelectionNow = true;
- performSelectionChange(markerfulLineAndChar(newSelStart[0],
- newSelStart[1]),
- markerfulLineAndChar(newSelEnd[0],
- newSelEnd[1]),
- newSelFocusAtStart);
- updatingSelectionNow = false;
- currentCallStack.userChangedSelection = true;
- return true;
- }
- };
- })());
-
-
- // stolen from jquery-1.2.1
- function fixEvent(event) {
- // store a copy of the original event object
- // and clone to set read-only properties
- var originalEvent = event;
- event = extend({}, originalEvent);
-
- // add preventDefault and stopPropagation since
- // they will not work on the clone
- event.preventDefault = function() {
- // if preventDefault exists run it on the original event
- if (originalEvent.preventDefault)
- originalEvent.preventDefault();
- // otherwise set the returnValue property of the original event to false (IE)
- originalEvent.returnValue = false;
- };
- event.stopPropagation = function() {
- // if stopPropagation exists run it on the original event
- if (originalEvent.stopPropagation)
- originalEvent.stopPropagation();
- // otherwise set the cancelBubble property of the original event to true (IE)
- originalEvent.cancelBubble = true;
- };
-
- // Fix target property, if necessary
- if ( !event.target && event.srcElement )
- event.target = event.srcElement;
-
- // check if target is a textnode (safari)
- if (browser.safari && event.target.nodeType == 3)
- event.target = originalEvent.target.parentNode;
-
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && event.fromElement )
- event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && event.clientX != null ) {
- var e = document.documentElement, b = document.body;
- event.pageX = event.clientX + (e && e.scrollLeft || b.scrollLeft || 0);
- event.pageY = event.clientY + (e && e.scrollTop || b.scrollTop || 0);
- }
-
- // Add which for key events
- if ( !event.which && (event.charCode || event.keyCode) )
- event.which = event.charCode || event.keyCode;
-
- // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
- if ( !event.metaKey && event.ctrlKey )
- event.metaKey = event.ctrlKey;
-
- // Add which for click: 1 == left; 2 == middle; 3 == right
- // Note: button is not normalized, so don't use it
- if ( !event.which && event.button )
- event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
-
- return event;
- }
-
- var lineNumbersShown;
- var sideDivInner;
- function initLineNumbers() {
- lineNumbersShown = 1;
- sideDiv.innerHTML =
- '<table border="0" cellpadding="0" cellspacing="0" align="right">'+
- '<tr><td id="sidedivinner"><div>1</div></td></tr></table>';
- sideDivInner = outerWin.document.getElementById("sidedivinner");
- }
-
- function updateLineNumbers() {
- var newNumLines = rep.lines.length();
- if (newNumLines < 1) newNumLines = 1;
- if (newNumLines != lineNumbersShown) {
- var container = sideDivInner;
- var odoc = outerWin.document;
- while (lineNumbersShown < newNumLines) {
- lineNumbersShown++;
- var n = lineNumbersShown;
- var div = odoc.createElement("DIV");
- div.appendChild(odoc.createTextNode(String(n)));
- container.appendChild(div);
- }
- while (lineNumbersShown > newNumLines) {
- container.removeChild(container.lastChild);
- lineNumbersShown--;
- }
- }
-
- if (currentCallStack && currentCallStack.domClean) {
- var a = sideDivInner.firstChild;
- var b = doc.body.firstChild;
- while (a && b) {
- var h = (b.clientHeight || b.offsetHeight);
- if (b.nextSibling) {
- // when text is zoomed in mozilla, divs have fractional
- // heights (though the properties are always integers)
- // and the line-numbers don't line up unless we pay
- // attention to where the divs are actually placed...
- // (also: padding on TTs/SPANs in IE...)
- h = b.nextSibling.offsetTop - b.offsetTop;
- }
- if (h) {
- var hpx = h+"px";
- if (a.style.height != hpx)
- a.style.height = hpx;
- }
- a = a.nextSibling;
- b = b.nextSibling;
- }
-
- // fix if first line has margin (f.e. h1 in first line)
- sideDivInner.firstChild.style.marginTop =
- (doc.body.firstChild.offsetTop - sideDivInner.firstChild.offsetTop +
- parseInt(sideDivInner.firstChild.style.marginTop + "0")) + "px";
- }
- }
-
-};
-
-OUTER(this);
diff --git a/trunk/infrastructure/ace/www/ace2_outer.js b/trunk/infrastructure/ace/www/ace2_outer.js
deleted file mode 100644
index b0fc20c..0000000
--- a/trunk/infrastructure/ace/www/ace2_outer.js
+++ /dev/null
@@ -1,214 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-
-Ace2Editor.registry = { nextId: 1 };
-
-function Ace2Editor() {
- var thisFunctionsName = "Ace2Editor";
- var ace2 = Ace2Editor;
-
- var editor = {};
- var info = { editor: editor, id: (ace2.registry.nextId++) };
- var loaded = false;
-
- var actionsPendingInit = [];
- function pendingInit(func, optDoNow) {
- return function() {
- var that = this;
- var args = arguments;
- function action() {
- func.apply(that, args);
- }
- if (optDoNow) {
- optDoNow.apply(that, args);
- }
- if (loaded) {
- action();
- }
- else {
- actionsPendingInit.push(action);
- }
- };
- }
- function doActionsPendingInit() {
- for(var i=0;i<actionsPendingInit.length;i++) {
- actionsPendingInit[i]();
- }
- actionsPendingInit = [];
- }
-
- ace2.registry[info.id] = info;
-
- editor.importText = pendingInit(function(newCode, undoable) {
- info.ace_importText(newCode, undoable); });
- editor.importAText = pendingInit(function(newCode, apoolJsonObj, undoable) {
- info.ace_importAText(newCode, apoolJsonObj, undoable); });
- editor.exportText = function() {
- if (! loaded) return "(awaiting init)\n";
- return info.ace_exportText();
- };
- editor.getFrame = function() { return info.frame || null; };
- editor.focus = pendingInit(function() { info.ace_focus(); });
- editor.adjustSize = pendingInit(function() {
- var frameParent = info.frame.parentNode;
- var parentHeight = frameParent.clientHeight;
- // deal with case where iframe is hidden, no clientHeight
- info.frame.style.height = (parentHeight ? parentHeight+"px" :
- frameParent.style.height);
- info.ace_editorChangedSize();
- });
- editor.setEditable = pendingInit(function(newVal) { info.ace_setEditable(newVal); });
- editor.getFormattedCode = function() { return info.ace_getFormattedCode(); };
- editor.setOnKeyPress = pendingInit(function (handler) { info.ace_setOnKeyPress(handler); });
- editor.setOnKeyDown = pendingInit(function (handler) { info.ace_setOnKeyDown(handler); });
- editor.setNotifyDirty = pendingInit(function (handler) { info.ace_setNotifyDirty(handler); });
-
- editor.setProperty = pendingInit(function(key, value) { info.ace_setProperty(key, value); });
- editor.getDebugProperty = function(prop) { return info.ace_getDebugProperty(prop); };
-
- editor.setBaseText = pendingInit(function(txt) { info.ace_setBaseText(txt); });
- editor.setBaseAttributedText = pendingInit(function(atxt, apoolJsonObj) {
- info.ace_setBaseAttributedText(atxt, apoolJsonObj); });
- editor.applyChangesToBase = pendingInit(function (changes, optAuthor,apoolJsonObj) {
- info.ace_applyChangesToBase(changes, optAuthor, apoolJsonObj); });
- // prepareUserChangeset:
- // Returns null if no new changes or ACE not ready. Otherwise, bundles up all user changes
- // to the latest base text into a Changeset, which is returned (as a string if encodeAsString).
- // If this method returns a truthy value, then applyPreparedChangesetToBase can be called
- // at some later point to consider these changes part of the base, after which prepareUserChangeset
- // must be called again before applyPreparedChangesetToBase. Multiple consecutive calls
- // to prepareUserChangeset will return an updated changeset that takes into account the
- // latest user changes, and modify the changeset to be applied by applyPreparedChangesetToBase
- // accordingly.
- editor.prepareUserChangeset = function() {
- if (! loaded) return null;
- return info.ace_prepareUserChangeset();
- };
- editor.applyPreparedChangesetToBase = pendingInit(
- function() { info.ace_applyPreparedChangesetToBase(); });
- editor.setUserChangeNotificationCallback = pendingInit(function(callback) {
- info.ace_setUserChangeNotificationCallback(callback);
- });
- editor.setAuthorInfo = pendingInit(function(author, authorInfo) {
- info.ace_setAuthorInfo(author, authorInfo);
- });
- editor.setAuthorSelectionRange = pendingInit(function(author, start, end) {
- info.ace_setAuthorSelectionRange(author, start, end);
- });
-
- editor.getUnhandledErrors = function() {
- if (! loaded) return [];
- // returns array of {error: <browser Error object>, time: +new Date()}
- return info.ace_getUnhandledErrors();
- };
- editor.execCommand = pendingInit(function(cmd, arg1) {
- info.ace_execCommand(cmd, arg1);
- });
-
- // calls to these functions ($$INCLUDE_...) are replaced when this file is processed
- // and compressed, putting the compressed code from the named file directly into the
- // source here.
-
- var $$INCLUDE_CSS = function(fileName) {
- return '<link rel="stylesheet" type="text/css" href="'+fileName+'"/>';
- };
- var $$INCLUDE_JS = function(fileName) {
- return '\x3cscript type="text/javascript" src="'+fileName+'">\x3c/script>';
- };
- var $$INCLUDE_JS_DEV = $$INCLUDE_JS;
- var $$INCLUDE_CSS_DEV = $$INCLUDE_CSS;
-
- var $$INCLUDE_CSS_Q = function(fileName) {
- return '\'<link rel="stylesheet" type="text/css" href="'+fileName+'"/>\'';
- };
- var $$INCLUDE_JS_Q = function(fileName) {
- return '\'\\x3cscript type="text/javascript" src="'+fileName+'">\\x3c/script>\'';
- };
- var $$INCLUDE_JS_Q_DEV = $$INCLUDE_JS_Q;
- var $$INCLUDE_CSS_Q_DEV = $$INCLUDE_CSS_Q;
-
- editor.destroy = pendingInit(function() {
- info.ace_dispose();
- info.frame.parentNode.removeChild(info.frame);
- delete ace2.registry[info.id];
- info = null; // prevent IE 6 closure memory leaks
- });
-
- editor.init = function(containerId, initialCode, doneFunc) {
-
- editor.importText(initialCode);
-
- info.onEditorReady = function() {
- loaded = true;
- doActionsPendingInit();
- doneFunc();
- };
-
- (function() {
- var doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '+
- '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
-
- var iframeHTML = ["'"+doctype+"<html><head>'"];
- // these lines must conform to a specific format because they are passed by the build script:
- iframeHTML.push($$INCLUDE_CSS_Q("editor.css syntax.css inner.css"));
- //iframeHTML.push(INCLUDE_JS_Q_DEV("ace2_common_dev.js"));
- //iframeHTML.push(INCLUDE_JS_Q_DEV("profiler.js"));
- iframeHTML.push($$INCLUDE_JS_Q("ace2_common.js skiplist.js virtual_lines.js easysync2.js cssmanager.js colorutils.js undomodule.js contentcollector.js changesettracker.js linestylefilter.js domline.js"));
- iframeHTML.push($$INCLUDE_JS_Q("ace2_inner.js"));
- iframeHTML.push('\'\\n<style type="text/css" title="dynamicsyntax"></style>\\n\'');
- iframeHTML.push('\'</head><body id="innerdocbody" class="syntax" spellcheck="false">&nbsp;</body></html>\'');
-
- var outerScript = 'editorId = "'+info.id+'"; editorInfo = parent.'+
- thisFunctionsName+'.registry[editorId]; '+
- 'window.onload = function() '+
- '{ window.onload = null; setTimeout'+
- '(function() '+
- '{ var iframe = document.createElement("IFRAME"); '+
- 'iframe.scrolling = "no"; var outerdocbody = document.getElementById("outerdocbody"); '+
- 'iframe.frameBorder = 0; iframe.allowTransparency = true; '+ // for IE
- 'outerdocbody.insertBefore(iframe, outerdocbody.firstChild); '+
- 'iframe.ace_outerWin = window; '+
- 'readyFunc = function() { editorInfo.onEditorReady(); readyFunc = null; editorInfo = null; }; '+
- 'var doc = iframe.contentWindow.document; doc.open(); doc.write('+
- iframeHTML.join('+')+'); doc.close(); '+
- '}, 0); }';
-
- var outerHTML = [doctype, '<html><head>',
- $$INCLUDE_CSS("editor.css"),
- // bizarrely, in FF2, a file with no "external" dependencies won't finish loading properly
- // (throbs busy while typing)
- '<link rel="stylesheet" type="text/css" href="data:text/css,"/>',
- '\x3cscript>', outerScript, '\x3c/script>',
- '</head><body id="outerdocbody"><div id="sidediv"><!-- --></div><div id="linemetricsdiv">x</div><div id="overlaysdiv"><!-- --></div></body></html>'];
-
- var outerFrame = document.createElement("IFRAME");
- outerFrame.frameBorder = 0; // for IE
- info.frame = outerFrame;
- document.getElementById(containerId).appendChild(outerFrame);
-
- var editorDocument = outerFrame.contentWindow.document;
-
- editorDocument.open();
- editorDocument.write(outerHTML.join(''));
- editorDocument.close();
-
- editor.adjustSize();
- })();
- };
-
- return editor;
-}
diff --git a/trunk/infrastructure/ace/www/domline.js b/trunk/infrastructure/ace/www/domline.js
deleted file mode 100644
index 70f86cc..0000000
--- a/trunk/infrastructure/ace/www/domline.js
+++ /dev/null
@@ -1,210 +0,0 @@
-// THIS FILE IS ALSO AN APPJET MODULE: etherpad.collab.ace.domline
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-var domline = {};
-domline.noop = function() {};
-domline.identity = function(x) { return x; };
-
-domline.addToLineClass = function(lineClass, cls) {
- // an "empty span" at any point can be used to add classes to
- // the line, using line:className. otherwise, we ignore
- // the span.
- cls.replace(/\S+/g, function (c) {
- if (c.indexOf("line:") == 0) {
- // add class to line
- lineClass = (lineClass ? lineClass+' ' : '')+c.substring(5);
- }
- });
- return lineClass;
-}
-
-// if "document" is falsy we don't create a DOM node, just
-// an object with innerHTML and className
-domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument) {
- var result = { node: null,
- appendSpan: domline.noop,
- prepareForAdd: domline.noop,
- notifyAdded: domline.noop,
- clearSpans: domline.noop,
- finishUpdate: domline.noop,
- lineMarker: 0 };
-
- var browser = (optBrowser || {});
- var document = optDocument;
-
- if (document) {
- result.node = document.createElement("div");
- }
- else {
- result.node = {innerHTML: '', className: ''};
- }
-
- var html = [];
- var preHtml, postHtml;
- var curHTML = null;
- function processSpaces(s) {
- return domline.processSpaces(s, doesWrap);
- }
- var identity = domline.identity;
- var perTextNodeProcess = (doesWrap ? identity : processSpaces);
- var perHtmlLineProcess = (doesWrap ? processSpaces : identity);
- var lineClass = 'ace-line';
- result.appendSpan = function(txt, cls) {
- if (cls.indexOf('list') >= 0) {
- var listType = /(?:^| )list:(\S+)/.exec(cls);
- if (listType) {
- listType = listType[1];
- if (listType) {
- preHtml = '<ul class="list-'+listType+'"><li>';
- postHtml = '</li></ul>';
- }
- result.lineMarker += txt.length;
- return; // don't append any text
- }
- }
- var href = null;
- var simpleTags = null;
- if (cls.indexOf('url') >= 0) {
- cls = cls.replace(/(^| )url:(\S+)/g, function(x0, space, url) {
- href = url;
- return space+"url";
- });
- }
- if (cls.indexOf('tag') >= 0) {
- cls = cls.replace(/(^| )tag:(\S+)/g, function(x0, space, tag) {
- if (! simpleTags) simpleTags = [];
- simpleTags.push(tag.toLowerCase());
- return space+tag;
- });
- }
- if ((! txt) && cls) {
- lineClass = domline.addToLineClass(lineClass, cls);
- }
- else if (txt) {
- var extraOpenTags = "";
- var extraCloseTags = "";
- if (href) {
- extraOpenTags = extraOpenTags+'<a href="'+
- href.replace(/\"/g, '&quot;')+'">';
- extraCloseTags = '</a>'+extraCloseTags;
- }
- if (simpleTags) {
- simpleTags.sort();
- extraOpenTags = extraOpenTags+'<'+simpleTags.join('><')+'>';
- simpleTags.reverse();
- extraCloseTags = '</'+simpleTags.join('></')+'>'+extraCloseTags;
- }
- html.push('<span class="',cls||'','">',extraOpenTags,
- perTextNodeProcess(domline.escapeHTML(txt)),
- extraCloseTags,'</span>');
- }
- };
- result.clearSpans = function() {
- html = [];
- lineClass = ''; // non-null to cause update
- result.lineMarker = 0;
- };
- function writeHTML() {
- var newHTML = perHtmlLineProcess(html.join(''));
- if (! newHTML) {
- if ((! document) || (! optBrowser)) {
- newHTML += '&nbsp;';
- }
- else if (! browser.msie) {
- newHTML += '<br/>';
- }
- }
- if (nonEmpty) {
- newHTML = (preHtml||'')+newHTML+(postHtml||'');
- }
- html = preHtml = postHtml = null; // free memory
- if (newHTML !== curHTML) {
- curHTML = newHTML;
- result.node.innerHTML = curHTML;
- }
- if (lineClass !== null) result.node.className = lineClass;
- }
- result.prepareForAdd = writeHTML;
- result.finishUpdate = writeHTML;
- result.getInnerHTML = function() { return curHTML || ''; };
-
- return result;
-};
-
-domline.escapeHTML = function(s) {
- var re = /[&<>'"]/g; /']/; // stupid indentation thing
- if (! re.MAP) {
- // persisted across function calls!
- re.MAP = {
- '&': '&amp;',
- '<': '&lt;',
- '>': '&gt;',
- '"': '&#34;',
- "'": '&#39;'
- };
- }
- return s.replace(re, function(c) { return re.MAP[c]; });
-};
-
-domline.processSpaces = function(s, doesWrap) {
- if (s.indexOf("<") < 0 && ! doesWrap) {
- // short-cut
- return s.replace(/ /g, '&nbsp;');
- }
- var parts = [];
- s.replace(/<[^>]*>?| |[^ <]+/g, function(m) { parts.push(m); });
- if (doesWrap) {
- var endOfLine = true;
- var beforeSpace = false;
- // last space in a run is normal, others are nbsp,
- // end of line is nbsp
- for(var i=parts.length-1;i>=0;i--) {
- var p = parts[i];
- if (p == " ") {
- if (endOfLine || beforeSpace)
- parts[i] = '&nbsp;';
- endOfLine = false;
- beforeSpace = true;
- }
- else if (p.charAt(0) != "<") {
- endOfLine = false;
- beforeSpace = false;
- }
- }
- // beginning of line is nbsp
- for(var i=0;i<parts.length;i++) {
- var p = parts[i];
- if (p == " ") {
- parts[i] = '&nbsp;';
- break;
- }
- else if (p.charAt(0) != "<") {
- break;
- }
- }
- }
- else {
- for(var i=0;i<parts.length;i++) {
- var p = parts[i];
- if (p == " ") {
- parts[i] = '&nbsp;';
- }
- }
- }
- return parts.join('');
-};
diff --git a/trunk/infrastructure/ace/www/linestylefilter.js b/trunk/infrastructure/ace/www/linestylefilter.js
deleted file mode 100644
index ef824cc..0000000
--- a/trunk/infrastructure/ace/www/linestylefilter.js
+++ /dev/null
@@ -1,253 +0,0 @@
-// THIS FILE IS ALSO AN APPJET MODULE: etherpad.collab.ace.linestylefilter
-// %APPJET%: import("etherpad.collab.ace.easysync2.Changeset");
-
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-// requires: easysync2.Changeset
-
-var linestylefilter = {};
-
-linestylefilter.ATTRIB_CLASSES = {
- 'bold':'tag:b',
- 'italic':'tag:i',
- 'underline':'tag:u',
- 'strikethrough':'tag:s',
- 'h1':'tag:h1',
- 'h2':'tag:h2',
- 'h3':'tag:h3',
- 'h4':'tag:h4',
- 'h5':'tag:h5',
- 'h6':'tag:h6'
-};
-
-linestylefilter.getAuthorClassName = function(author) {
- return "author-"+author.replace(/[^a-y0-9]/g, function(c) {
- if (c == ".") return "-";
- return 'z'+c.charCodeAt(0)+'z';
- });
-};
-
-// lineLength is without newline; aline includes newline,
-// but may be falsy if lineLength == 0
-linestylefilter.getLineStyleFilter = function(lineLength, aline,
- textAndClassFunc, apool) {
-
- if (lineLength == 0) return textAndClassFunc;
-
- var nextAfterAuthorColors = textAndClassFunc;
-
- var authorColorFunc = (function() {
- var lineEnd = lineLength;
- var curIndex = 0;
- var extraClasses;
- var leftInAuthor;
-
- function attribsToClasses(attribs) {
- var classes = '';
- Changeset.eachAttribNumber(attribs, function(n) {
- var key = apool.getAttribKey(n);
- if (key) {
- var value = apool.getAttribValue(n);
- if (value) {
- if (key == 'author') {
- classes += ' '+linestylefilter.getAuthorClassName(value);
- }
- else if (key == 'list') {
- classes += ' list:'+value;
- }
- else if (linestylefilter.ATTRIB_CLASSES[key]) {
- classes += ' '+linestylefilter.ATTRIB_CLASSES[key];
- }
- }
- }
- });
- return classes.substring(1);
- }
-
- var attributionIter = Changeset.opIterator(aline);
- var nextOp, nextOpClasses;
- function goNextOp() {
- nextOp = attributionIter.next();
- nextOpClasses = (nextOp.opcode && attribsToClasses(nextOp.attribs));
- }
- goNextOp();
- function nextClasses() {
- if (curIndex < lineEnd) {
- extraClasses = nextOpClasses;
- leftInAuthor = nextOp.chars;
- goNextOp();
- while (nextOp.opcode && nextOpClasses == extraClasses) {
- leftInAuthor += nextOp.chars;
- goNextOp();
- }
- }
- }
- nextClasses();
-
- return function(txt, cls) {
- while (txt.length > 0) {
- if (leftInAuthor <= 0) {
- // prevent infinite loop if something funny's going on
- return nextAfterAuthorColors(txt, cls);
- }
- var spanSize = txt.length;
- if (spanSize > leftInAuthor) {
- spanSize = leftInAuthor;
- }
- var curTxt = txt.substring(0, spanSize);
- txt = txt.substring(spanSize);
- nextAfterAuthorColors(curTxt, (cls&&cls+" ")+extraClasses);
- curIndex += spanSize;
- leftInAuthor -= spanSize;
- if (leftInAuthor == 0) {
- nextClasses();
- }
- }
- };
- })();
- return authorColorFunc;
-};
-
-linestylefilter.getAtSignSplitterFilter = function(lineText,
- textAndClassFunc) {
- var at = /@/g;
- at.lastIndex = 0;
- var splitPoints = null;
- var execResult;
- while ((execResult = at.exec(lineText))) {
- if (! splitPoints) {
- splitPoints = [];
- }
- splitPoints.push(execResult.index);
- }
-
- if (! splitPoints) return textAndClassFunc;
-
- return linestylefilter.textAndClassFuncSplitter(textAndClassFunc,
- splitPoints);
-};
-
-linestylefilter.REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/;
-linestylefilter.REGEX_URLCHAR = new RegExp('('+/[-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/.source+'|'+linestylefilter.REGEX_WORDCHAR.source+')');
-linestylefilter.REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:)/.source+linestylefilter.REGEX_URLCHAR.source+'*(?![:.,;])'+linestylefilter.REGEX_URLCHAR.source, 'g');
-
-linestylefilter.getURLFilter = function(lineText, textAndClassFunc) {
- linestylefilter.REGEX_URL.lastIndex = 0;
- var urls = null;
- var splitPoints = null;
- var execResult;
- while ((execResult = linestylefilter.REGEX_URL.exec(lineText))) {
- if (! urls) {
- urls = [];
- splitPoints = [];
- }
- var startIndex = execResult.index;
- var url = execResult[0];
- urls.push([startIndex, url]);
- splitPoints.push(startIndex, startIndex + url.length);
- }
-
- if (! urls) return textAndClassFunc;
-
- function urlForIndex(idx) {
- for(var k=0; k<urls.length; k++) {
- var u = urls[k];
- if (idx >= u[0] && idx < u[0]+u[1].length) {
- return u[1];
- }
- }
- return false;
- }
-
- var handleUrlsAfterSplit = (function() {
- var curIndex = 0;
- return function(txt, cls) {
- var txtlen = txt.length;
- var newCls = cls;
- var url = urlForIndex(curIndex);
- if (url) {
- newCls += " url:"+url;
- }
- textAndClassFunc(txt, newCls);
- curIndex += txtlen;
- };
- })();
-
- return linestylefilter.textAndClassFuncSplitter(handleUrlsAfterSplit,
- splitPoints);
-};
-
-linestylefilter.textAndClassFuncSplitter = function(func, splitPointsOpt) {
- var nextPointIndex = 0;
- var idx = 0;
-
- // don't split at 0
- while (splitPointsOpt &&
- nextPointIndex < splitPointsOpt.length &&
- splitPointsOpt[nextPointIndex] == 0) {
- nextPointIndex++;
- }
-
- function spanHandler(txt, cls) {
- if ((! splitPointsOpt) || nextPointIndex >= splitPointsOpt.length) {
- func(txt, cls);
- idx += txt.length;
- }
- else {
- var splitPoints = splitPointsOpt;
- var pointLocInSpan = splitPoints[nextPointIndex] - idx;
- var txtlen = txt.length;
- if (pointLocInSpan >= txtlen) {
- func(txt, cls);
- idx += txt.length;
- if (pointLocInSpan == txtlen) {
- nextPointIndex++;
- }
- }
- else {
- if (pointLocInSpan > 0) {
- func(txt.substring(0, pointLocInSpan), cls);
- idx += pointLocInSpan;
- }
- nextPointIndex++;
- // recurse
- spanHandler(txt.substring(pointLocInSpan), cls);
- }
- }
- }
- return spanHandler;
-};
-
-// domLineObj is like that returned by domline.createDomLine
-linestylefilter.populateDomLine = function(textLine, aline, apool,
- domLineObj) {
- // remove final newline from text if any
- var text = textLine;
- if (text.slice(-1) == '\n') {
- text = text.substring(0, text.length-1);
- }
-
- function textAndClassFunc(tokenText, tokenClass) {
- domLineObj.appendSpan(tokenText, tokenClass);
- }
-
- var func = textAndClassFunc;
- func = linestylefilter.getURLFilter(text, func);
- func = linestylefilter.getLineStyleFilter(text.length, aline,
- func, apool);
- func(text, '');
-};
diff --git a/trunk/infrastructure/bin/compilecache.sh b/trunk/infrastructure/bin/compilecache.sh
deleted file mode 100644
index a2b6220..0000000
--- a/trunk/infrastructure/bin/compilecache.sh
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/bin/bash
-
-# Copyright 2009 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS-IS" 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.
-
-CP_CMD="cp -R -u"
-if [ `uname` == "Darwin" ]; then
- CP_CMD="/bin/cp -R -n"
-fi
-
-function cacheonfiles {
- NAME=$1; FILES=$2; FUNC=$3; NOCOPY=1;
- if [ -z "$4" ]; then
- NOCOPY=0
- fi
- REBUILD=0
- BPATH=buildcache/$NAME
- FILETEST=$BPATH/t
- if [ ! -f $FILETEST ]; then
- REBUILD=1
- else
- for a in $FILES; do
- if [ $FILETEST -ot $a ]; then
- echo $a has changed, rebuilding $NAME
- REBUILD=1
- fi
- done
- fi
- if [ $REBUILD -eq 1 ]; then
- if [ -d $BPATH ]; then
- rm -rf $BPATH
- fi
- mkdir -p $BPATH
- $FUNC $BPATH
- pushd $BPATH >> /dev/null
- touch t
- popd >> /dev/null
- else
- echo using cached $NAME...
- fi
- if [ $NOCOPY -ne 1 ]; then
- for a in $BPATH/*; do
- if [ -d $a ]; then
- $CP_CMD $a build/
- elif [ -f $a ]; then
- cp $a build/
- else
- echo unknown file type $a
- exit 1
- fi
- done
- fi
-}
diff --git a/trunk/infrastructure/bin/makejar.sh b/trunk/infrastructure/bin/makejar.sh
deleted file mode 100755
index c774fa6..0000000
--- a/trunk/infrastructure/bin/makejar.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2009 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS-IS" 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.
-
-if [ -z "$JAR" ]; then
- JAR=jar
-else
- echo "using JAR $JAR..."
-fi
-
-cp ${MYSQL_CONNECTOR_JAR} lib/
-
-source bin/compilecache.sh
-
-if [ "$1" == "clearcache" ]; then
- echo "CLEARING BUILD CACHE"
- rm -rf buildcache
- shift;
-fi
-
-TMPSTORE=/tmp/ajbuild-tmpstore-`date +%s`
-
-JARFILES=`echo $SCALA_HOME/lib/scala-library.jar lib/*.jar lib/manifest`
-function genjar {
- echo "unzipping JARs..."
- pushd $1 >> /dev/null
- $JAR xf $SCALA_HOME/lib/scala-library.jar
- rm -rf META-INF
- for a in ../../lib/*.jar; do
- $JAR xf $a
- rm -rf META-INF/{MANIFEST.MF,NOTICE{,.txt},LICENSE{,.txt},INDEX.LIST,SUN_MICR.{RSA,SF},maven}
- done
-
- echo "making cached JAR...."
- $JAR -cfm appjet.jar ../../lib/manifest .
- mv appjet.jar /tmp/appjet.jar
- rm -rf *
- mv /tmp/appjet.jar ./
-
- popd >> /dev/null
-}
-cacheonfiles JAR "$JARFILES" genjar 1
-
-echo "compiling..."
-bin/comp.sh $@
-
-pushd build >> /dev/null
-
-echo "copying cached JAR..."
-cp ../buildcache/JAR/appjet.jar ./
-
-echo "making JAR..."
-mv appjet.jar /tmp/appjet.jar
-$JAR -uf /tmp/appjet.jar . #META-INF com javax org net uk v scala dojox
-mv /tmp/appjet.jar ./
-
-echo "cleaning up..."
-rm -rf $TMPSTORE
-
-popd >> /dev/null
-
-echo "done."
diff --git a/trunk/infrastructure/com.etherpad.openofficeservice/importexport.scala b/trunk/infrastructure/com.etherpad.openofficeservice/importexport.scala
deleted file mode 100644
index f5150ad..0000000
--- a/trunk/infrastructure/com.etherpad.openofficeservice/importexport.scala
+++ /dev/null
@@ -1,189 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-package com.etherpad.openofficeservice;
-
-import net.appjet.common.sars.{SarsServer,SarsMessageHandler};
-
-import java.io.{DataInputStream,DataOutputStream};
-import java.io.{File,FileOutputStream,ByteArrayInputStream,ByteArrayOutputStream};
-
-class OOSException(m: String) extends RuntimeException(m);
-class UnsupportedFormatException(format: String) extends OOSException("Unsupported format: "+format);
-object TemporaryFailure extends OOSException("Temporary failure");
-
-// stub object here. Please replace if you'd like to use openoffice!
-object OpenOfficeServerUtility {
- def checkServerAvailability(host: String, port: Int): Boolean = {
- return false;
- }
- def runOpenOfficeServer(path: String, host: String, port: Int, timeout: Int, wait: Boolean) {
- // nothing
- }
-}
-
-class OpenOfficeFileConverter {
- def setOpenOfficeServerDetails(host: String, port: Int) {
- // nothing
- }
-
- def convertFile(src: File, dst: File, converter: String, extension: String): Boolean = {
- return false;
- }
-}
-
-object OpenOfficeService {
- val formats = Map(
- "pdf" -> "writer_pdf_Export",
- "doc" -> "MS Word 97",
- "html" -> "HTML (StarWriter)",
- "odt" -> "writer8",
- //"html" -> "XHTML Writer File",
- "txt" -> "Text"
- );
-
- def createTempFile(bytes: Array[byte], suffix: String) = {
- var f = File.createTempFile("ooconvert-", if (suffix == null) { null } else if (suffix == "") { "" } else { "."+suffix });
- if (bytes != null) {
- val fos = new FileOutputStream(f);
- fos.write(bytes);
- }
- f;
- }
-
- var soffice = "soffice";
- def setExecutable(exec: String) {
- soffice = exec;
- }
-
- def convertFile(from: String, to: String, bytes: Array[byte]): Array[byte] = {
- if (from == to) {
- return bytes;
- }
-
- val tempFile = createTempFile(bytes, from);
- val outFile = createTempFile(null, to);
-
- val openOfficeServerHost = "localhost";
- val openOfficeServerPort = 8100;
- if (! OpenOfficeServerUtility.checkServerAvailability(openOfficeServerHost, openOfficeServerPort)) {
- try {
- OpenOfficeServerUtility.runOpenOfficeServer(soffice, openOfficeServerHost, openOfficeServerPort, 20000, true);
- } catch {
- case e: java.io.IOException => {
- e.printStackTrace();
- throw TemporaryFailure;
- }
- }
- }
- var converter = new OpenOfficeFileConverter();
- converter.setOpenOfficeServerDetails(openOfficeServerHost, openOfficeServerPort);
- var status = false;
- try {
- status = converter.convertFile(tempFile, outFile, formats(to), to);
- } catch {
- case e => {
- e.printStackTrace();
- throw new OOSException("Unknown exception occurred: "+e.getMessage());
- }
- }
- if (status == false) {
- throw new UnsupportedFormatException(from);
- }
- net.appjet.common.util.BetterFile.getFileBytes(outFile);
- }
-
- def main(args: Array[String]) {
- if (args.length > 0) {
- soffice = args(0);
- if (soffice.length == 0) {
- exit(1);
- }
- }
-
- // Query format:
- // from: String, to: String, count: Int, bytes: Array[byte]
- // Response format:
- // status: Int, <data>
- // status 0 (success) - <data>: count: Int, bytes: Array[byte]
- // status 1 (temporary failure) - <data>: <none>
- // status 2 (permanent failure) - <data>: type: Int
- // type - 0: unknown failure.
- // - 1: unsupported format
- val handler = new SarsMessageHandler {
- override def handle(b: Array[byte]): Option[Array[byte]] = {
- val is = new DataInputStream(new ByteArrayInputStream(b));
- val from = is.readUTF;
- val to = is.readUTF;
- val len = is.readInt;
- val bytes = new Array[byte](len);
- is.readFully(bytes);
- var status = 0;
- var permfailuretype = 0;
-
- println("Converting "+from+" -> "+to+" ("+len+" bytes)");
-
- val output = try {
- convertFile(from, to, bytes);
- } catch {
- case TemporaryFailure => {
- status = 1;
- null;
- }
- case e: UnsupportedFormatException => {
- status = 2;
- permfailuretype = 1;
- null;
- }
- case e => {
- status = 2;
- permfailuretype = 0;
- e.printStackTrace();
- null;
- }
- }
-
- val retBytes = new ByteArrayOutputStream();
- val ret = new DataOutputStream(retBytes);
- if (status != 0) {
- ret.writeInt(status); // error
- status match {
- case 2 => {
- ret.writeInt(permfailuretype);
- }
- case _ => { }
- }
- } else {
- ret.writeInt(0); // success
- ret.writeInt(output.length);
- ret.write(output, 0, output.length);
- }
- Some(retBytes.toByteArray());
- }
- }
-
- val server = new SarsServer("ooffice-password", handler, None, 8101);
- server.start();
- println("Server running...");
- server.join();
- println("Server quitting...");
- }
-}
-
-
-
-
-
diff --git a/trunk/infrastructure/com.etherpad/licensing.scala b/trunk/infrastructure/com.etherpad/licensing.scala
deleted file mode 100644
index 620738f..0000000
--- a/trunk/infrastructure/com.etherpad/licensing.scala
+++ /dev/null
@@ -1,169 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-package com.etherpad;
-
-import net.appjet.oui.{Encryptomatic, config};
-import net.appjet.common.util.BetterFile;
-
-import java.io.{FileInputStream, FileOutputStream, ByteArrayInputStream, ByteArrayOutputStream, PrintWriter}
-
-import java.security._;
-import java.security.spec._;
-
-object Licensing {
- val publicKey = "s0dD94jKFjlSHIumgDQ4ldcyIyna1vMHmG5tsgkP987eBTW88XeEIUTo5JtWOjPzb252GURUrr7MReTqMz6NnsOupeJMqtXgjuVxcXbK8AnckxkxhRqMiFfBW39T9NzPgq09yBdH4tKGlPZQmgaBvjFI8cXTYa7a64LrDnrzrpDhDdJsZPZI2kE7G4vBCGijuhsZpyowK8zT5y2cKqIgIdLxUnXNFtayDi0oyuX1ywfBds2OEil9fEUQOQvkcHAt6kYfPXkE2XgQZFasAv0DPeWMUEtaHTbMaQn1U6BsfmsKjHlLhM3oWEzp0wEwUWxCC39iHYjxa5QKtxm5BNvUTTqJgkoEvk7Uu08j8jhFeCFosph6igDWPmyfAPKTnETXJobO2VON83bVHlX8UfKonnalMy0Hnw2C0I7c0UE0MtMIRtJxtwU62a311Ohp1EVrY4LwKIFfqRMVWKDP0cjXDkJyjJS58rC1DRU7SfPspgfuOy5YZo9sLKztXfzAPzNbXerQ24m2AjmYLV4JQked7MnaKQ6VfyZbFBK5th9NFcJwY1bGbIHW2EsKmiKUoNjPKRJ6VMC7odUCIXQyE9J";
-
- val pkhash = "f7a3dd5940a3f79904b81e4d32a08e2efaa0b2ab";
- val keyVersion = 2.toByte;
-
- def thanksForStealingFromPoorHackersTryingToEkeAMeagerLivingFromThisCruelWorld =
- Encryptomatic.bytesToAscii(MessageDigest.getInstance("SHA1").digest(publicKey.getBytes())) == pkhash;
- def sha1(b: Array[Byte]): String = Encryptomatic.bytesToAscii(MessageDigest.getInstance("SHA1").digest(b));
- def sha1(s: String): String = sha1(s.getBytes("UTF-8"));
-
- def toBytes(i: Int): Array[Byte] =
- Array((i >> 24).toByte,
- (i >> 16).toByte,
- (i >> 8).toByte,
- i.toByte);
- def toByte(i: Int): Array[Byte] =
- Array(i.toByte);
- def toBytes(l: Long): Array[Byte] =
- Array((l >> 56).toByte,
- (l >> 48).toByte,
- (l >> 40).toByte,
- (l >> 32).toByte,
- (l >> 24).toByte,
- (l >> 16).toByte,
- (l >> 8).toByte,
- l.toByte);
-
- def toInt(b0: Array[Byte]): Int = {
- val b = b0.map(_.toInt & 0x00FF);
- (b(0) << 24) | (b(1) << 16) | (b(2) << 8) | b(3);
- }
- def toInt(b: Byte): Int = b.toInt & 0x00FF;
-
- def toLong(b0: Array[Byte]): Long = {
- val b = b0.map(_.toLong & 0x000000FF);
- (b(0) << 56) | (b(1) << 48) | (b(2) << 40) | (b(3) << 32) | (b(4) << 24) | (b(5) << 16) | (b(6) << 8) | b(7);
- }
-
- def generateKey(personName: String, organizationName: String, expiresDate: Long, editionId: Int, userQuota: Int, majorVersion: Int, minorVersion: Int, patchVersion: Int) = {
- if (config.licenseGeneratorKey == null) {
- throw new RuntimeException("No private key available to generate license key.");
- }
- def privateKey = Encryptomatic.readPrivateKey("DSA", new FileInputStream(config.licenseGeneratorKey));
- def clean(s: String) = s.replaceAll(":", "-");
- val keyPrefix =
- List(personName, organizationName, expiresDate.toString, editionId.toString, userQuota.toString, majorVersion.toString, minorVersion.toString, patchVersion.toString).map(clean).mkString(":");
- val sig = Encryptomatic.sign(new ByteArrayInputStream(keyPrefix.getBytes("UTF-8")), privateKey)
-
- List(personName, organizationName).mkString(":") + ":" +
- Encryptomatic.bytesToAscii(
- Array.concat[Byte](Array(keyVersion), // don't want BigInt dropping bytes, that'd be sad. :(
- toBytes(expiresDate),
- toBytes(editionId),
- toBytes(userQuota),
- toByte(majorVersion),
- toByte(minorVersion),
- toByte(patchVersion),
- sig));
- }
-
- def decodeKey(key: String) = try {
- val Array(personName0, organizationName0, sigAndInfo) = key.split(":");
- val sigAndInfoBytes = Encryptomatic.asciiToBytes(sigAndInfo);
- val thisKeyVersion = toInt(sigAndInfoBytes(0));
- val expiresDate0 = toLong(sigAndInfoBytes.slice(1, 9));
- val editionId0 = toInt(sigAndInfoBytes.slice(9, 13));
- val userQuota0 = toInt(sigAndInfoBytes.slice(13, 17));
- val (majorVersion0, minorVersion0, patchVersion0) =
- if (thisKeyVersion >= 2) {
- (toInt(sigAndInfoBytes(17)), toInt(sigAndInfoBytes(18)), toInt(sigAndInfoBytes(19)));
- } else {
- (0, 0, 0);
- }
- val sig = sigAndInfoBytes.drop(if (thisKeyVersion >= 2) 20 else 17);
- val keyPrefix = {
- var a = Seq(personName0, organizationName0, expiresDate0.toString, editionId0.toString, userQuota0.toString);
- if (thisKeyVersion >= 2) {
- a = a ++ Seq(majorVersion0.toString, minorVersion0.toString, patchVersion0.toString);
- }
- a.mkString(":");
- }
- if (! Encryptomatic.verify(new ByteArrayInputStream(keyPrefix.getBytes("UTF-8")),
- Encryptomatic.readPublicKey("DSA",
- new ByteArrayInputStream(publicKey.getBytes())), sig)) {
- null;
- } else {
- new {
- def personName = personName0;
- def organizationName = organizationName0;
- def expiresDate = expiresDate0;
- def editionId = editionId0;
- def userQuota = userQuota0;
- def majorVersion = majorVersion0;
- def minorVersion = minorVersion0;
- def patchVersion = patchVersion0;
- }
- }
- } catch {
- case e => null;
- }
-
- def main(args: Array[String]) {
- args(0) match {
- case "genkeypair" => {
- println("Generating keypair...");
- Encryptomatic.writeKeyPair(Encryptomatic.generateKeyPair("DSA"), args(1), args(2));
- println("Done.");
- }
- case "genmainkey" => {
- println("Generating key for pad.spline.inf.fu-berlin.de...");
- config.values("licenseGeneratorKey") = args(1);
- val out = new PrintWriter(new FileOutputStream(args(2)));
- out.print(generateKey("etherpad", "AppJet", -1, 0, -1, 0, 0, 0))
- out.close();
- println("Done.");
- }
- case "test" => {
- println("Testing key generation.");
- config.values("licenseGeneratorKey") = args(1);
- val key = generateKey("Foo Bar", "Baz, Inc.", System.currentTimeMillis() + 86400*1000, 0, 100, 1, 2, 3);
- println("Key is: "+key);
- val obj = decodeKey(key);
- println(List(obj.personName, obj.organizationName, obj.expiresDate, obj.editionId, obj.userQuota, obj.majorVersion, obj.minorVersion, obj.patchVersion).mkString(", "));
- }
- case "parsekey" => {
- println("Testing key decode.");
- val obj = decodeKey(args(1));
- println("Key: "+List(obj.personName, obj.organizationName, obj.expiresDate, obj.editionId, obj.userQuota, obj.majorVersion, obj.minorVersion, obj.patchVersion).mkString(", "));
- }
- case "testascii" => {
- val one = 17;
- val two = -1L;
- val three = (Math.random*Math.pow(10, (Math.random*10).toInt)).toInt;
- println(List(one, two, three).mkString(", "));
- println(List(toInt(toBytes(one)), toLong(toBytes(two)), toInt(toBytes(three))).mkString(", "));
- val bytes = Encryptomatic.asciiToBytes(Encryptomatic.bytesToAscii(Array.concat[Byte](Array(1.toByte), toBytes(one), toBytes(two), toBytes(three))));
- println("I can has bytes: "+bytes.length);
- println(List(toInt(bytes.slice(1, 5)), toLong(bytes.slice(5, 13)), toInt(bytes.slice(13, 17))).mkString(", "));
- }
- }
- }
-}
diff --git a/trunk/infrastructure/framework-src/modules/ejs.js b/trunk/infrastructure/framework-src/modules/ejs.js
deleted file mode 100644
index bf14ed3..0000000
--- a/trunk/infrastructure/framework-src/modules/ejs.js
+++ /dev/null
@@ -1,471 +0,0 @@
-/*--------------------------------------------------------------------------
- * EJS - Embedded JavaScript, version 0.1.0
- * Copyright (c) 2007 Edward Benson
- * http://www.edwardbenson.com/projects/ejs
- * ------------------------------------------------------------------------
- *
- * EJS is freely distributable under the terms of an MIT-style license.
- *
- * EJS is a client-side preprocessing engine written in and for JavaScript.
- * If you have used PHP, ASP, JSP, or ERB then you get the idea: code embedded
- * in <% // Code here %> tags will be executed, and code embedded in <%= .. %>
- * tags will be evaluated and appended to the output.
- *
- * This is essentially a direct JavaScript port of Masatoshi Seki's erb.rb
- * from the Ruby Core, though it contains a subset of ERB's functionality.
- *
- * Requirements:
- * prototype.js
- *
- * Usage:
- * // source should be either a string or a DOM node whose innerHTML
- * // contains EJB source.
- * var source = "<% var ejb="EJB"; %><h1>Hello, <%= ejb %>!</h1>";
- * var compiler = new EjsCompiler(source);
- * compiler.compile();
- * var output = eval(compiler.out);
- * alert(output); // -> "<h1>Hello, EJB!</h1>"
- *
- * For a demo: see demo.html
- * For the license: see license.txt
- *
- *--------------------------------------------------------------------------*/
-
-import("jsutils.*");
-import("funhtml");
-
-jimport("java.lang.System.out.println");
-jimport("net.appjet.ajstdlib.execution.executeCodeInNewScope");
-
-/* Make a split function like Ruby's: "abc".split(/b/) -> ['a', 'b', 'c'] */
-function rsplit(x, regex) {
- var item = x;
- var result = regex.exec(item);
- var retArr = new Array();
- while (result != null)
- {
- var first_idx = result.index;
- var last_idx = regex.lastIndex;
- if ((first_idx) != 0)
- {
- var first_bit = item.substring(0,first_idx);
- retArr.push(item.substring(0,first_idx));
- item = item.slice(first_idx);
- }
- retArr.push(result[0]);
- item = item.slice(result[0].length);
- result = regex.exec(item);
- }
- if (! item == '')
- {
- retArr.push(item);
- }
- return retArr;
-};
-
-/* Chop is nice to have too */
-function chop(x) {
- return x.substr(0, x.length - 1);
-}
-
-/* Adaptation from the Scanner of erb.rb */
-var EjsScanner = function(source, left, right) {
- this.left_delimiter = left +'%'; //<%
- this.right_delimiter = '%'+right; //>
- this.double_left = left+'%%';
- this.double_right = '%%'+right;
- this.left_equal = left+'%=';
- this.left_comment = left+'%#';
- if(left=='[') {
- this.SplitRegexp = /(\[%%)|(%%\])|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/;
- }
- else {
- this.SplitRegexp = new RegExp('('+this.double_left+')|(%%'+this.double_right+')|('+this.left_equal+')|('+this.left_comment+')|('+this.left_delimiter+')|('+this.right_delimiter+'\n)|('+this.right_delimiter+')|(\n)')
- }
-
- this.source = source;
- this.stag = null;
- this.lines = 0;
-};
-EjsView = function(data) {
- this.data = data;
-};
-EjsView.prototype.partial = function(options, data){
- if(!data) data = this.data;
- return new EJS(options).render(data);
-};
-
-EjsScanner.to_text = function(input){
- if(input == null || input === undefined)
- return '';
- if(input instanceof Date)
- return input.toDateString();
- if(input.toString)
- return input.toString();
- return '';
-}
-
-EjsScanner.prototype = {
-
- /* For each line, scan! */
- scan: function(block) {
- scanline = this.scanline;
- regex = this.SplitRegexp;
- if (! this.source == '')
- {
- var source_split = rsplit(this.source, /\n/);
- for(var i=0; i<source_split.length; i++) {
- var item = source_split[i];
- this.scanline(item, regex, block);
- }
- }
- },
-
- /* For each token, block! */
- scanline: function(line, regex, block) {
- this.lines++;
- var line_split = rsplit(line, regex);
- for(var i=0; i<line_split.length; i++) {
- var token = line_split[i];
- if (token != null) {
- try{
- block(token, this);
- }catch(e){
- throw {type: 'EjsScanner', line: this.lines};
- }
- }
- }
- }
-};
-
-/* Adaptation from the Buffer of erb.rb */
-var EjsBuffer = function(pre_cmd, post_cmd) {
- this.line = new Array();
- this.script = "";
- this.pre_cmd = pre_cmd;
- this.post_cmd = post_cmd;
-
- for (var i=0; i<this.pre_cmd.length; i++)
- {
- this.push(pre_cmd[i]);
- }
-}
-EjsBuffer.prototype = {
-
- push: function(cmd) {
- this.line.push(cmd);
- },
-
- cr: function() {
- this.script = this.script + this.line.join('; ');
- this.line = new Array();
- this.script = this.script + "\n";
- },
-
- close: function() {
- if (this.line.length > 0)
- {
- for (var i=0; i<this.post_cmd.length; i++)
- {
- this.push(pre_cmd[i]);
- }
- this.script = this.script + this.line.join('; ');
- line = null;
- }
- }
-
-};
-
-/* Adaptation from the Compiler of erb.rb */
-EjsCompiler = function(source, left) {
- this.pre_cmd = ['var ___ejsO = "";'];
- this.post_cmd = new Array();
- this.source = ' ';
- if (source != null)
- {
- if (typeof source == 'string')
- {
- source = source.replace(/\r\n/g, "\n");
- source = source.replace(/\r/g, "\n");
- this.source = source;
- }
- else if (source.innerHTML)
- {
- this.source = source.innerHTML;
- }
- if (typeof this.source != 'string')
- {
- this.source = "";
- }
- }
- left = left || '<'
- var right = '>'
- switch(left) {
- case '[':
- right = ']'
- break;
- case '<':
- break;
- default:
- throw left+' is not a supported deliminator'
- break;
- }
- this.scanner = new EjsScanner(this.source, left, right);
- this.out = '';
-}
-EjsCompiler.prototype = {
- compile: function(options) {
- options = options || {};
- this.out = '';
- var put_cmd = "___ejsO += ";
- var insert_cmd = put_cmd;
- var buff = new EjsBuffer(this.pre_cmd, this.post_cmd);
- var content = '';
- var clean = function(content)
- {
- content = content.replace(/\\/g, '\\\\');
- content = content.replace(/\n/g, '\\n');
- content = content.replace(/\"/g, '\\"');
- return content;
- };
- this.scanner.scan(function(token, scanner) {
- if (scanner.stag == null)
- {
- //alert(token+'|'+(token == "\n"))
- switch(token) {
- case '\n':
- content = content + "\n";
- buff.push(put_cmd + '"' + clean(content) + '";');
- buff.cr();
- content = '';
- break;
- case scanner.left_delimiter:
- case scanner.left_equal:
- case scanner.left_comment:
- scanner.stag = token;
- if (content.length > 0)
- {
- // Chould be content.dump in Ruby
-
- buff.push(put_cmd + '"' + clean(content) + '"');
- }
- content = '';
- break;
- case scanner.double_left:
- content = content + scanner.left_delimiter;
- break;
- default:
- content = content + token;
- break;
- }
- }
- else {
- switch(token) {
- case scanner.right_delimiter:
- switch(scanner.stag) {
- case scanner.left_delimiter:
- if (content[content.length - 1] == '\n')
- {
- content = chop(content);
- buff.push(content);
- buff.cr();
- }
- else {
- buff.push(content);
- }
- break;
- case scanner.left_equal:
- buff.push(insert_cmd + "(EjsScanner.to_text(" + content + "))");
- break;
- }
- scanner.stag = null;
- content = '';
- break;
- case scanner.double_right:
- content = content + scanner.right_delimiter;
- break;
- default:
- content = content + token;
- break;
- }
- }
- });
- if (content.length > 0)
- {
- // Chould be content.dump in Ruby
- buff.push(put_cmd + '"' + clean(content) + '"');
- }
- buff.close();
- this.out = buff.script + ";";
- var to_be_evaled = [
- 'var process = function(_CONTEXT,_VIEW) {',
- ' with(_VIEW) {',
- ' with (_CONTEXT) {',
- this.out,
- ' return ___ejsO;',
- ' }',
- ' }',
- '};'
- ].join('');
- // make funhtml.* available in parent scope.
- var parentScope = {};
- parentScope.EjsScanner = EjsScanner;
- keys(funhtml).forEach(function(k) {
- parentScope[k] = funhtml[k];
- });
- var ret = executeCodeInNewScope(
- parentScope,
- to_be_evaled,
- (options.name || "template"),
- 1
- );
- this.process = ret.process;
- }
-}
-
-
-//type, cache, folder
-EJS = function( options ){
- this.set_options(options);
-
- if(options.url){
- var template = EJS.get(options.url, this.cache);
- if (template) return template;
- if (template == EJS.INVALID_PATH) return null;
- this.text = EJS.request(options.url);
- if(this.text == null){
- //EJS.update(options.url, this.INVALID_PATH);
- throw 'There is no template at '+options.url;
- }
- this.name = options.url;
- }else if(options.element)
- {
- if(typeof options.element == 'string'){
- var name = options.element;
- options.element = document.getElementById( options.element );
- if(options.element == null) throw name+'does not exist!';
- }
- if(options.element.value){
- this.text = options.element.value;
- }else{
- this.text = options.element.innerHTML;
- }
- this.name = options.element.id;
- this.type = '[';
- }
- var template = new EjsCompiler(this.text, this.type);
-
- template.compile(options);
-
-
- EJS.update(this.name, this);
- this.template = template;
-};
-EJS.config = function(options){
- EJS.cache = options.cache != null ? options.cache : EJS.cache;
- EJS.type = options.type != null ? options.type : EJS.type;
- var templates_directory = {}; //nice and private container
-
- EJS.get = function(path, cache){
- if(cache == false) return null;
- if(templates_directory[path]) return templates_directory[path];
- return null;
- };
-
- EJS.update = function(path, template) {
- if(path == null) return;
- templates_directory[path] = template;
- };
-
- EJS.INVALID_PATH = -1;
-
-
-};
-EJS.config( {cache: true, type: '<' } );
-
-EJS.prototype = {
- render : function(object){
- var v = new EjsView(object);
- return this.template.process.call(v, object, v);
- },
- out : function(){
- return this.template.out;
- },
- set_options : function(options){
- this.type = options.type != null ? options.type : EJS.type;
- this.cache = options.cache != null ? options.cache : EJS.cache;
- this.text = options.text != null ? options.text : null;
- this.name = options.name != null ? options.name : null;
- },
- // called without options, returns a function that takes the object
- // called with options being a string, uses that as a url
- // called with options as an object
- update : function(element, options){
- if(typeof element == 'string'){
- element = document.getElementById(element);
- }
- if(options == null){
- _template = this;
- return function(object){
- EJS.prototype.update.call(_template, element, object);
- };
- }
- if(typeof options == 'string'){
- params = {};
- params.url = options;
- _template = this;
- params.onComplete = function(request){
- var object = eval( request.responseText );
- EJS.prototype.update.call(_template, element, object);
- };
- EJS.ajax_request(params);
- }else
- {
- element.innerHTML = this.render(options);
- }
- }
-};
-
- EJS.newRequest = function(){
- var factories = [function() { return new ActiveXObject("Msxml2.XMLHTTP"); },function() { return new XMLHttpRequest(); },function() { return new ActiveXObject("Microsoft.XMLHTTP"); }];
- for(var i = 0; i < factories.length; i++) {
- try {
- var request = factories[i]();
- if (request != null) return request;
- }
- catch(e) { continue;}
- }
- };
-
- EJS.request = function(path){
- var request = new EJS.newRequest();
- request.open("GET", path, false);
-
- try{request.send(null);}
- catch(e){return null;}
-
- if ( request.status == 404 || request.status == 2 ||(request.status == 0 && request.responseText == '') ) return null;
-
- return request.responseText
- };
- EJS.ajax_request = function(params){
- params.method = ( params.method ? params.method : 'GET');
-
- var request = new EJS.newRequest();
- request.onreadystatechange = function(){
- if(request.readyState == 4){
- if(request.status == 200){
- params.onComplete(request);
- }else
- {
- params.onComplete(request);
- }
- }
- };
- request.open(params.method, params.url);
- request.send(null);
- };
-
-//}
-
-
diff --git a/trunk/infrastructure/framework-src/modules/execution.js b/trunk/infrastructure/framework-src/modules/execution.js
deleted file mode 100644
index 1cec418..0000000
--- a/trunk/infrastructure/framework-src/modules/execution.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("jsutils.{scalaF0,scalaF1}");
-
-/**
- * Asynchronously call a function as soon as the current request completes.
- **/
-function async(f) {
- Packages.net.appjet.ajstdlib.execution.runAsync(appjet.context, f);
-}
-
-function initTaskThreadPool(name, poolSize) {
- Packages.net.appjet.ajstdlib.execution.createNamedTaskThreadPool(name, poolSize);
-}
-
-function scheduleTask(poolName, taskName, delayMillis, args) {
- return Packages.net.appjet.ajstdlib.execution.scheduleTaskInPool(poolName, taskName, delayMillis, args);
-}
-
-function shutdownAndWaitOnTaskThreadPool(poolName, timeoutMillis) {
- return Packages.net.appjet.ajstdlib.execution.shutdownAndWaitOnTaskThreadPool(poolName, timeoutMillis);
-}
-
-function fancyAssEval(initCode, mainCode) {
- function init(runner) {
- Packages.net.appjet.bodylock.BodyLock.evaluateString(
- runner.globalScope(),
- initCode,
- "eval'd code imports",
- 1);
- }
- var runner = Packages.net.appjet.oui.ScopeReuseManager.getEmpty(scalaF1(init));
- var ec = new Packages.net.appjet.oui.ExecutionContext(
- new Packages.net.appjet.oui.RequestWrapper(request.underlying),
- null, runner);
- return Packages.net.appjet.oui.ExecutionContextUtils.withContext(ec,
- scalaF0(function() {
- return Packages.net.appjet.bodylock.BodyLock.evaluateString(
- runner.globalScope(),
- mainCode,
- "eval'd code main",
- 1);
- }));
-} \ No newline at end of file
diff --git a/trunk/infrastructure/framework-src/modules/faststatic.js b/trunk/infrastructure/framework-src/modules/faststatic.js
deleted file mode 100644
index 5cca676..0000000
--- a/trunk/infrastructure/framework-src/modules/faststatic.js
+++ /dev/null
@@ -1,318 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-/**
- * @fileOverview serving static files, including js and css, and cacheing
- * and minifying.
- *
- * Terminology Note:
- * "path" is confusing because paths can be part of URLs and part
- * of filesystem paths, and static files have both types of paths
- * associated with them. Therefore, in this module:
- *
- * LOCALDIR or LOCALFILE refers to directories or files on the filesystem.
- *
- * HREF is used to describe things that go in a URL.
- */
-
-import("fileutils.{readFile,readFileBytes}");
-import("yuicompressor");
-import("stringutils");
-import("varz");
-import("ejs.EJS");
-
-jimport("java.lang.System.out.println");
-
-//----------------------------------------------------------------
-// Content Type Guessing
-//----------------------------------------------------------------
-
-var _contentTypes = {
- 'gif': 'image/gif',
- 'png': 'image/png',
- 'jpg': 'image/jpeg',
- 'jpeg': 'image/jpeg',
- 'css': 'text/css',
- 'js': 'application/x-javascript',
- 'txt': 'text/plain',
- 'html': 'text/html; charset=utf-8',
- 'ico': 'image/x-icon',
- 'swf': 'application/x-shockwave-flash',
- 'zip': 'application/zip',
- 'xml': 'application/xml'
-};
-
-var _gzipableTypes = {
- 'text/css': true,
- 'application/x-javascript': true,
- 'text/html; charset=utf-8': true
-};
-
-function _guessContentType(path) {
- var ext = path.split('.').pop().toLowerCase();
- return _contentTypes[ext] || 'text/plain';
-}
-
-//----------------------------------------------------------------
-
-function _getCache(name) {
- var m = 'faststatic';
- if (!appjet.cache[m]) {
- appjet.cache[m] = {};
- }
- var c = appjet.cache[m];
- if (!c[name]) {
- c[name] = {};
- }
- return c[name];
-}
-
-var _mtimeCheckInterval = 5000; // 5 seconds
-
-function _getMTime(f) {
- var mcache = _getCache('mtimes');
- var now = +(new Date);
- if (appjet.config.devMode ||
- !(mcache[f] && (now - mcache[f].lastCheck < _mtimeCheckInterval))) {
- var jfile = new net.appjet.oui.JarVirtualFile(f);
- if (jfile.exists() && !jfile.isDirectory()) {
- mcache[f] = {
- lastCheck: now,
- mtime: jfile.lastModified()
- };
- } else {
- mcache[f] = null;
- }
- }
- if (mcache[f]) {
- return +mcache[f].mtime;
- } else {
- return null;
- }
-}
-
-function _wrapFile(localFile) {
- return {
- getPath: function() { return localFile; },
- getMTime: function() { return _getMTime(localFile); },
- getContents: function() { return _readFileAndProcess(localFile, 'string'); }
- };
-}
-
-function _readFileAndProcess(fileName, type) {
- if (fileName.slice(-8) == "_ejs.css") {
- // run CSS through EJS
- var template = readFile(fileName);
- var ejs = new EJS({text:template, name:fileName});
- var resultString = ejs.render({});
- if (type == 'bytes') {
- return new java.lang.String(resultString).getBytes("UTF-8");
- }
- else {
- return resultString;
- }
- }
- else if (type == 'string') {
- return readFile(fileName);
- }
- else if (type == 'bytes') {
- return readFileBytes(fileName);
- }
-}
-
-function _cachedFileBytes(f) {
- var mtime = _getMTime(f);
- if (!mtime) { return null; }
- var fcache = _getCache('file-bytes-cache');
- if (!(fcache[f] && (fcache[f].mtime == mtime))) {
- varz.incrementInt("faststatic-file-bytes-cache-miss");
- var bytes = _readFileAndProcess(f, 'bytes');
- if (bytes) {
- fcache[f] = {mtime: mtime, bytes: bytes};
- };
- }
- if (fcache[f] && fcache[f].bytes) {
- return fcache[f].bytes;
- } else {
- return null;
- }
-}
-
-function _shouldGzip(contentType) {
- var userAgent = request.headers["User-Agent"];
- if (! userAgent) return false;
- if (! (/Firefox/.test(userAgent) || /webkit/i.test(userAgent))) return false;
- if (! _gzipableTypes[contentType]) return false;
-
- return request.acceptsGzip;
-}
-
-function _getCachedGzip(original, key) {
- var c = _getCache("gzipped");
- if (! c[key] || ! java.util.Arrays.equals(c[key].original, original)) {
- c[key] = {original: original,
- gzip: stringutils.gzip(original)};
- }
- return c[key].gzip;
-}
-
-function _setGzipHeader() {
- response.setHeader("Content-Encoding", "gzip");
-}
-
-//----------------------------------------------------------------
-
-/**
- * Function for serving a single static file.
- */
-function singleFileServer(localPath, opts) {
- var contentType = _guessContentType(localPath);
-
- return function() {
- (opts.cache ? response.alwaysCache() : response.neverCache());
- response.setContentType(contentType);
- var bytes = _cachedFileBytes(localPath);
- if (bytes) {
- if (_shouldGzip(contentType)) {
- bytes = _getCachedGzip(bytes, "file:"+localPath);
- _setGzipHeader();
- }
- response.writeBytes(bytes);
- return true;
- } else {
- return false;
- }
- };
-}
-
-/**
- * valid opts:
- * alwaysCache: default false
- */
-function directoryServer(localDir, opts) {
- if (stringutils.endsWith(localDir, "/")) {
- localDir = localDir.substr(0, localDir.length-1);
- }
- return function(relpath) {
- if (stringutils.startsWith(relpath, "/")) {
- relpath = relpath.substr(1);
- }
- if (relpath.indexOf('..') != -1) {
- response.forbid();
- }
- (opts.cache ? response.alwaysCache() : response.neverCache());
- var contentType = _guessContentType(relpath);
- response.setContentType(contentType);
- var fullPath = localDir + "/" + relpath;
- var bytes = _cachedFileBytes(fullPath);
-
- if (bytes) {
- if (_shouldGzip(contentType)) {
- bytes = _getCachedGzip(bytes, "file:"+fullPath);
- _setGzipHeader();
- }
- response.writeBytes(bytes);
- return true;
- } else {
- return false;
- }
- };
-}
-
-/**
- * Serves cat files, which are concatenated versions of many files.
- */
-function compressedFileServer(opts) {
- var cfcache = _getCache('compressed-files');
- return function() {
- var key = request.path.split('/').slice(-1)[0];
- var contentType = _guessContentType(request.path);
- response.setContentType(contentType);
- response.alwaysCache();
- var data = cfcache[key];
- if (data) {
- if (_shouldGzip(contentType)) {
- data = _getCachedGzip((new java.lang.String(data)).getBytes(response.getCharacterEncoding()), "comp:"+key);
- _setGzipHeader();
- response.writeBytes(data);
- } else {
- response.write(data);
- }
- return true;
- } else {
- return false;
- }
- };
-}
-
-function getCompressedFilesKey(type, baseLocalDir, localFileList) {
- if (stringutils.endsWith(baseLocalDir, '/')) {
- baseLocalDir = baseLocalDir.substr(0, baseLocalDir.length-1);
- }
-
- var fileList = [];
- // convert passed-in file list into list of our file objects
- localFileList.forEach(function(f) {
- if (typeof(f) == 'string') {
- fileList.push(_wrapFile(baseLocalDir+'/'+f));
- } else {
- fileList.push(f);
- }
- });
-
- // have we seen this exact fileset before?
- var fsId = fileList.map(function(f) { return f.getPath(); }).join('|');
- var fsMTime = Math.max.apply(this,
- fileList.map(function(f) { return f.getMTime(); }));
-
- var kdcache = _getCache('fileset-keydata-cache');
- if (!(kdcache[fsId] && (kdcache[fsId].mtime == fsMTime))) {
- //println("cache miss for fileset: "+fsId);
- //println("compressing fileset...");
- kdcache[fsId] = {
- mtime: fsMTime,
- keyString: _compressFilesAndMakeKey(type, fileList)
- };
- }
- return kdcache[fsId].keyString;
-}
-
-function _compressFilesAndMakeKey(type, fileList) {
- function _compress(s) {
- if (type == 'css') {
- varz.incrementInt("faststatic-yuicompressor-compressCSS");
- return yuicompressor.compressCSS(s);
- } else if (type == 'js') {
- varz.incrementInt("faststatic-yuicompressor-compressJS");
- return yuicompressor.compressJS(s);
- } else {
- throw Error('Dont know how to compress this filetype: '+type);
- }
- }
-
- var fullstr = "";
- fileList.forEach(function(f) {
- fullstr += _compress(f.getContents());
- });
-
- fullstr = _compress(fullstr);
-
- var key = stringutils.md5(fullstr) + '.' + type;
- var cfcache = _getCache('compressed-files');
- cfcache[key] = fullstr;
- return key;
-}
-
diff --git a/trunk/infrastructure/framework-src/modules/sqlbase/sqlobj.js b/trunk/infrastructure/framework-src/modules/sqlbase/sqlobj.js
deleted file mode 100644
index 4bc1263..0000000
--- a/trunk/infrastructure/framework-src/modules/sqlbase/sqlobj.js
+++ /dev/null
@@ -1,505 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-import("cache_utils.syncedWithCache");
-import("sqlbase.sqlcommon.*");
-import("jsutils.*");
-
-jimport("java.lang.System.out.println");
-jimport("java.sql.Statement");
-
-function _withCache(name, fn) {
- return syncedWithCache('sqlobj.'+name, fn);
-}
-
-function getIdColspec() {
- return ('INT NOT NULL '+autoIncrementClause()+' PRIMARY KEY');
-}
-
-function getLongtextColspec(extra) {
- var spec = getSqlBase().longTextType();
- if (extra) {
- spec = (spec + " " + extra);
- }
- return spec;
-}
-
-function getBoolColspec(extra) {
- var spec;
- if (isMysql()) {
- spec = 'TINYINT(1)';
- } else {
- spec = 'SMALLINT';
- }
- if (extra) {
- spec = (spec + " " + extra);
- }
- return spec;
-}
-
-function getDateColspec(extra) {
- var spec;
- if (isMysql()) {
- spec = 'DATETIME';
- } else {
- spec = 'TIMESTAMP';
- }
- if (extra) {
- spec = (spec + " " + extra);
- }
- return spec;
-}
-
-function _bq(x) { return btquote(x); }
-
-/*
- * for debugging queries
- */
-function _qdebug(q) {
- if (appjet.config.debugSQL) {
- println(q);
- }
-}
-
-/** executeFn is either "execute" or "executeUpdate" "executeQuery" */
-function _execute(stmnt, executeFn) {
- if (!executeFn) {
- executeFn = 'execute';
- }
- return withConnection(function(conn) {
- var pstmnt = conn.prepareStatement(stmnt);
- return closing(pstmnt, function() {
- _qdebug(stmnt);
- return pstmnt[executeFn]();
- });
- });
-}
-
-function _executeUpdate(stmnt) {
- return _execute(stmnt, 'executeUpdate');
-}
-
-function _executeQuery(stmnt) {
- return _execute(stmnt, 'executeQuery');
-}
-
-/*
- * Not all SQL/JS types supported.
- */
-function _getJsValFromResultSet(rs, type, colName) {
- var r;
- if (type == java.sql.Types.VARCHAR ||
- type == java.sql.Types.LONGVARCHAR ||
- type == java.sql.Types.CHAR) {
- r = String(rs.getString(colName));
- } else if (type == java.sql.Types.TIMESTAMP) {
- var t = rs.getTimestamp(colName);
- if (t) {
- r = new Date(t.getTime());
- } else {
- r = null;
- }
- } else if (type == java.sql.Types.INTEGER ||
- type == java.sql.Types.SMALLINT ||
- type == java.sql.Types.TINYINT) {
- r = rs.getInt(colName);
- } else if (type == java.sql.Types.BIT) {
- r = rs.getBoolean(colName);
- } else {
- throw Error("Cannot fetch sql type ID "+type+" (columnName = "+colName+")");
- }
-
- if (rs.wasNull()) {
- r = null;
- }
- return r;
-}
-
-function _lookupColumnType(tableName, columnName) {
- return withConnection(function(conn) {
- var metadata = conn.getMetaData();
- var rs = metadata.getColumns(null, null, tableName, columnName);
- if (!rs) {
- throw Error("Table '"+tableName+"' does not appear to have colum '"+columnName+"'.");
- }
- var rsmd = rs.getMetaData();
- var colCount = rsmd.getColumnCount();
-// rs.first();
- rs.next();
- var type = rs.getInt("DATA_TYPE");
- return type;
- });
-}
-
-/* cached, on misses calls _lookuParameterType */
-function _getParameterType(tableName, columnName) {
- var key = [tableName, columnName].join(".");
- return _withCache('column-types', function(cache) {
- if (!cache[key]) {
- cache[key] = _lookupColumnType(tableName, columnName);
- }
- return cache[key];
- });
-}
-
-/*
- * Not all SQL/JS types supported.
- */
-function _setPreparedValues(tableName, pstmnt, keyList, obj, indexOffset) {
- if (!indexOffset) { indexOffset = 0; }
-
- for (var i = 1; i <= keyList.length; i++) {
- var k = keyList[i-1];
- var v = obj[k];
- var j = i + indexOffset;
-
- if (v === undefined) {
- throw Error("value is undefined for key "+k);
- }
-
- if (v === null) {
- var type = _getParameterType(tableName, k);
- pstmnt.setNull(j, type);
- } else if (typeof(v) == 'string') {
- pstmnt.setString(j, v);
- } else if (typeof(v) == 'number') {
- pstmnt.setInt(j, v);
- } else if (typeof(v) == 'boolean') {
- pstmnt.setBoolean(j, v);
- } else if (v.valueOf && v.getDate && v.getHours) {
- pstmnt.setTimestamp(j, new java.sql.Timestamp(+v));
- } else {
- throw Error("Cannot insert this type of javascript object: "+typeof(v)+" (key="+k+", value = "+v+")");
- }
- }
-}
-
-function _resultRowToJsObj(resultSet) {
- var resultObj = {};
-
- var metaData = resultSet.getMetaData();
- var colCount = metaData.getColumnCount();
- for (var i = 1; i <= colCount; i++) {
- var colName = metaData.getColumnName(i);
- var type = metaData.getColumnType(i);
- resultObj[colName] = _getJsValFromResultSet(resultSet, type, colName);
- }
-
- return resultObj;
-}
-
-/*
- * Inserts the object into the given table, and returns auto-incremented ID if any.
- */
-function insert(tableName, obj) {
- var keyList = keys(obj);
-
- var stmnt = "INSERT INTO "+_bq(tableName)+" (";
- stmnt += keyList.map(function(k) { return _bq(k); }).join(', ');
- stmnt += ") VALUES (";
- stmnt += keyList.map(function(k) { return '?'; }).join(', ');
- stmnt += ")";
-
- return withConnection(function(conn) {
- var pstmnt = conn.prepareStatement(stmnt, Statement.RETURN_GENERATED_KEYS);
- return closing(pstmnt, function() {
- _setPreparedValues(tableName, pstmnt, keyList, obj, 0);
- _qdebug(stmnt);
- pstmnt.executeUpdate();
- var rs = pstmnt.getGeneratedKeys();
- if (rs != null) {
- return closing(rs, function() {
- if (rs.next()) {
- return rs.getInt(1);
- }
- });
- }
- });
- });
-};
-
-/*
- * Selects a single object given the constraintMap. If there are more
- * than 1 objects that match, it will return a single one of them
- * (unspecified which one). If no objects match, returns null.
- *
- * constraints is a javascript object of column names to values.
- * Currently only supports string equality of constraints.
- */
-function selectSingle(tableName, constraints) {
- var keyList = keys(constraints);
-
- var stmnt = "SELECT * FROM "+_bq(tableName)+" WHERE (";
- stmnt += keyList.map(function(k) { return '('+_bq(k)+' = '+'?)'; }).join(' AND ');
- stmnt += ')';
- if (isMysql()) {
- stmnt += ' LIMIT 1';
- }
-
- return withConnection(function(conn) {
- var pstmnt = conn.prepareStatement(stmnt);
- return closing(pstmnt, function() {
- _setPreparedValues(tableName, pstmnt, keyList, constraints, 0);
- _qdebug(stmnt);
- var resultSet = pstmnt.executeQuery();
- return closing(resultSet, function() {
- if (!resultSet.next()) {
- return null;
- }
- return _resultRowToJsObj(resultSet);
- });
- });
- });
-}
-
-function _makeConstraintString(key, value) {
- if (typeof(value) != 'object' || ! (value instanceof Array)) {
- return '('+_bq(key)+' = ?)';
- } else {
- var comparator = value[0];
- return '('+_bq(key)+' '+comparator+' ?)';
- }
-}
-
-function _preparedValuesConstraints(constraints) {
- var c = {};
- eachProperty(constraints, function(k, v) {
- c[k] = (typeof(v) != 'object' || ! (v instanceof Array) ? v : v[1]);
- });
- return c;
-}
-
-function selectMulti(tableName, constraints, options) {
- if (!options) {
- options = {};
- }
-
- var constraintKeys = keys(constraints);
-
- var stmnt = "SELECT * FROM "+_bq(tableName)+" ";
-
- if (constraintKeys.length > 0) {
- stmnt += "WHERE (";
- stmnt += constraintKeys.map(function(key) {
- return _makeConstraintString(key, constraints[key]);
- }).join(' AND ');
- stmnt += ')';
- }
-
- if (options.orderBy) {
- var orderEntries = [];
- options.orderBy.split(",").forEach(function(orderBy) {
- var asc = "ASC";
- if (orderBy.charAt(0) == '-') {
- orderBy = orderBy.substr(1);
- asc = "DESC";
- }
- orderEntries.push(_bq(orderBy)+" "+asc);
- });
- stmnt += " ORDER BY "+orderEntries.join(", ");
- }
-
- if (options.limit) {
- stmnt += " LIMIT "+options.limit;
- }
-
- return withConnection(function(conn) {
- var pstmnt = conn.prepareStatement(stmnt);
- return closing(pstmnt, function() {
- _setPreparedValues(
- tableName, pstmnt, constraintKeys,
- _preparedValuesConstraints(constraints), 0);
-
- _qdebug(stmnt);
- var resultSet = pstmnt.executeQuery();
- var resultArray = [];
-
- return closing(resultSet, function() {
- while (resultSet.next()) {
- resultArray.push(_resultRowToJsObj(resultSet));
- }
-
- return resultArray;
- });
- });
- });
-}
-
-/* returns number of rows updated */
-function update(tableName, constraints, obj) {
- var objKeys = keys(obj);
- var constraintKeys = keys(constraints);
-
- var stmnt = "UPDATE "+_bq(tableName)+" SET ";
- stmnt += objKeys.map(function(k) { return ''+_bq(k)+' = ?'; }).join(', ');
- stmnt += " WHERE (";
- stmnt += constraintKeys.map(function(k) { return '('+_bq(k)+' = ?)'; }).join(' AND ');
- stmnt += ')';
-
- return withConnection(function(conn) {
- var pstmnt = conn.prepareStatement(stmnt);
- return closing(pstmnt, function() {
- _setPreparedValues(tableName, pstmnt, objKeys, obj, 0);
- _setPreparedValues(tableName, pstmnt, constraintKeys, constraints, objKeys.length);
- _qdebug(stmnt);
- return pstmnt.executeUpdate();
- });
- });
-}
-
-function updateSingle(tableName, constraints, obj) {
- var count = update(tableName, constraints, obj);
- if (count != 1) {
- throw Error("save count != 1. instead, count = "+count);
- }
-}
-
-function deleteRows(tableName, constraints) {
- var constraintKeys = keys(constraints);
- var stmnt = "DELETE FROM "+_bq(tableName)+" WHERE (";
- stmnt += constraintKeys.map(function(k) { return '('+_bq(k)+' = ?)'; }).join(' AND ');
- stmnt += ')';
- withConnection(function(conn) {
- var pstmnt = conn.prepareStatement(stmnt);
- closing(pstmnt, function() {
- _setPreparedValues(tableName, pstmnt, constraintKeys, constraints);
- _qdebug(stmnt);
- pstmnt.executeUpdate();
- });
- })
-}
-
-//----------------------------------------------------------------
-// table management
-//----------------------------------------------------------------
-
-/*
- * Create a SQL table, specifying column names and types with a
- * javascript object.
- */
-function createTable(tableName, colspec, indices) {
- if (doesTableExist(tableName)) {
- return;
- }
-
- var stmnt = "CREATE TABLE "+_bq(tableName)+ " (";
- stmnt += keys(colspec).map(function(k) { return (_bq(k) + ' ' + colspec[k]); }).join(', ');
- if (indices) {
- stmnt += ', ' + keys(indices).map(function(k) { return 'INDEX (' + _bq(k) + ')'; }).join(', ');
- }
- stmnt += ')'+createTableOptions();
- _execute(stmnt);
-}
-
-function dropTable(tableName) {
- _execute("DROP TABLE "+_bq(tableName));
-}
-
-function dropAndCreateTable(tableName, colspec, indices) {
- if (doesTableExist(tableName)) {
- dropTable(tableName);
- }
-
- return createTable(tableName, colspec, indices);
-}
-
-function renameTable(oldName, newName) {
- _executeUpdate("RENAME TABLE "+_bq(oldName)+" TO "+_bq(newName));
-}
-
-function modifyColumn(tableName, columnName, newSpec) {
- _executeUpdate("ALTER TABLE "+_bq(tableName)+" MODIFY "+_bq(columnName)+" "+newSpec);
-}
-
-function alterColumn(tableName, columnName, alteration) {
- var q = "ALTER TABLE "+_bq(tableName)+" ALTER COLUMN "+_bq(columnName)+" "+alteration;
- _executeUpdate(q);
-}
-
-function changeColumn(tableName, columnName, newSpec) {
- var q = ("ALTER TABLE "+_bq(tableName)+" CHANGE COLUMN "+_bq(columnName)
- +" "+newSpec);
- _executeUpdate(q);
-}
-
-function addColumns(tableName, colspec) {
- inTransaction(function(conn) {
- eachProperty(colspec, function(name, definition) {
- var stmnt = "ALTER TABLE "+_bq(tableName)+" ADD COLUMN "+_bq(name)+" "+definition;
- _executeUpdate(stmnt);
- });
- });
-}
-
-function dropColumn(tableName, columnName) {
- var stmnt = "ALTER TABLE "+_bq(tableName)+" DROP COLUMN "+_bq(columnName);
- _executeUpdate(stmnt);
-}
-
-function listTables() {
- return withConnection(function(conn) {
- var metadata = conn.getMetaData();
- var resultSet = metadata.getTables(null, null, null, null);
- var resultArray = [];
-
- return closing(resultSet, function() {
- while (resultSet.next()) {
- resultArray.push(resultSet.getString("TABLE_NAME"));
- }
- return resultArray;
- });
- });
-}
-
-function setTableEngine(tableName, engineName) {
- var stmnt = "ALTER TABLE "+_bq(tableName)+" ENGINE="+_bq(engineName);
- _executeUpdate(stmnt);
-}
-
-function getTableEngine(tableName) {
- if (!isMysql()) {
- throw Error("getTableEngine() only supported by MySQL database type.");
- }
-
- var tableEngines = {};
-
- withConnection(function(conn) {
- var stmnt = "show table status";
- var pstmnt = conn.prepareStatement(stmnt);
- closing(pstmnt, function() {
- _qdebug(stmnt);
- var resultSet = pstmnt.executeQuery();
- closing(resultSet, function() {
- while (resultSet.next()) {
- var n = resultSet.getString("Name");
- var eng = resultSet.getString("Engine");
- tableEngines[n] = eng;
- }
- });
- });
- });
-
- return tableEngines[tableName];
-}
-
-function createIndex(tableName, columns) {
- var indexName = "idx_"+(columns.join("_"));
- var stmnt = "CREATE INDEX "+_bq(indexName)+" on "+_bq(tableName)+" (";
- stmnt += columns.map(_bq).join(", ");
- stmnt += ")";
- _executeUpdate(stmnt);
-}
-
diff --git a/trunk/infrastructure/net.appjet.oui/config.scala b/trunk/infrastructure/net.appjet.oui/config.scala
deleted file mode 100644
index 46e73cf..0000000
--- a/trunk/infrastructure/net.appjet.oui/config.scala
+++ /dev/null
@@ -1,240 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-package net.appjet.oui;
-
-import scala.collection.mutable.HashMap;
-import java.util.regex.Pattern;
-import java.net.URL;
-import org.mortbay.jetty.servlet.Context;
-import org.mozilla.javascript.{Scriptable, ScriptableObject, Context => JSContext};
-
-import net.appjet.common.util.BetterFile;
-
-
-object config {
- val values = new HashMap[String, String];
- def stringOrElse(name: String, default: String): String = {
- val v = values.getOrElse(name, default);
- if (v != null) {
- val m = propertiesPattern.matcher(v);
- val sb = new StringBuffer();
- while (m.find()) {
- m.appendReplacement(sb, getClass.getDeclaredMethod(m.group(1), Array[Class[_]](): _*).invoke(this, Array[Class[_]](): _*).asInstanceOf[String]);
- }
- m.appendTail(sb);
- sb.toString();
- } else {
- null;
- }
- }
- def boolOrElse(name: String, default: Boolean) = values.get(name).map(_.equals("true")).getOrElse(default);
- def intOrElse(name: String, default: Int) = values.get(name).map(Integer.parseInt(_)).getOrElse(default);
- def longOrElse(name: String, default: Long) = values.get(name).map(java.lang.Long.parseLong(_)).getOrElse(default);
-
- @ConfigParam("Read configuration options from this file before processing any command-line flags.")
- { val argName = "file" }
- def configFile = stringOrElse("configFile", null);
-
- // configuation parameters
- var specialDebug = false;
-
- @ConfigParam("Enable additional logging output.")
- def verbose = boolOrElse("verbose", false);
-
- @ConfigParam("Activate \"developer\" mode.")
- def devMode = boolOrElse("devMode", false);
-
- @ConfigParam("Activate \"profiling\" mode.")
- def profile = boolOrElse("profile", false);
-
- @ConfigParam("Directory to use for storing appjet support files, logs, etc. This directory will be created if it does not exist and must be writeable by the user who runs appjet.jar. Defaults to current working directory.")
- { val argName = "directory" }
- def appjetHome = stringOrElse("appjetHome", "appjet");
-
- @ConfigParam("Directory to use for storing built-in database (Apache Derby) files. Will be created if it doesn't exist. Defaults to [appjetHome]/db")
- def derbyHome = stringOrElse("derbyHome", "[appjetHome]/derbydb");
-
- @ConfigParam("Directory to use for storing appserver logs. Defaults to [appjetHome]/log/appserver")
- { val argName = "directory" }
- def logDir = stringOrElse("logDir", "[appjetHome]/log/appserver");
-
- @ConfigParam("Optional alternative directory to load built-in libraries from. Used by AppJet platform hackers to develop and debug built-in libraries. Default: use built-in libraries.")
- { val argName = "directory" }
- def ajstdlibHome = stringOrElse("ajstdlibHome", null);
-
- @ConfigParam("Optional directory to specify as the \"app home\".")
- { val argName = "directory" }
- def appHome = stringOrElse("appHome", "");
-
-
- @ConfigParam("Search path for modules imported via \"import\". Defaults to current working directory.")
- { val argName = "dir1:dir2:..." }
- def modulePath = stringOrElse("modulePath", null);
- def moduleRoots =
- Array.concat(Array("."), if (modulePath != null) modulePath.split(":") else Array[String](), Array(ajstdlibHome));
-
- @ConfigParam("Where to read the static files from on the local filesystem. Don't specify this to read static files from the classpath/JAR.")
- { val argName = "directory" }
- def useVirtualFileRoot = stringOrElse("useVirtualFileRoot", null);
-
- @ConfigParam("Directory to use for storing the temporary sessions file on shutdown. Will be created if it does not exist.")
- { val argName = "directory" }
- def sessionStoreDir = stringOrElse("sessionStoreDir", "[appjetHome]/sessions");
-
- // performance tuning
- @ConfigParam("Create this many runners before opening up the server.")
- { val argName = "count" }
- def preloadRunners = intOrElse("preloadRunners", 0);
-
- @ConfigParam("Have this many JDBC connections available in the pool.")
- { val argName = "count" }
- def jdbcPoolSize = intOrElse("jdbcPoolSize", 10);
- @ConfigParam("Max count of worker threads.")
- { val argName = "num" }
- def maxThreads = intOrElse("maxThreads", 250);
-
- // specifying ports and such
- def extractHostAndPort(s: String): (String, Int) =
- if (s.indexOf(":") >= 0)
- (s.split(":")(0), Integer.parseInt(s.split(":")(1)))
- else
- ("", Integer.parseInt(s))
-
- @ConfigParam("[host:]port on which to serve the app. Default: 8080.")
- { val argName = "[host:]port" }
- def listen = stringOrElse("listen", "8080");
- @GeneratedConfigParam
- def listenHost = extractHostAndPort(listen)._1;
- @GeneratedConfigParam
- def listenPort = extractHostAndPort(listen)._2;
-
- @ConfigParam("[host:]port on which to serve the app using SSL. Default: none.")
- { val argName = "[host:]port" }
- def listenSecure = stringOrElse("listenSecure", "0");
- @GeneratedConfigParam
- def listenSecureHost = extractHostAndPort(listenSecure)._1;
- @GeneratedConfigParam
- def listenSecurePort = extractHostAndPort(listenSecure)._2;
-
- @ConfigParam("[host:]port:port on which to listen for monitoring. Default: none.")
- { val argName = "[host:]primaryPort:secondaryPort" }
- def listenMonitoring = stringOrElse("listenMonitoring", "0:0");
- def extractHostAndPortPort(s: String): (String, Int, Int) = {
- val spl = s.split(":", 3);
- if (spl.length > 2)
- (spl(0), Integer.parseInt(spl(1)), Integer.parseInt(spl(2)))
- else
- ("", Integer.parseInt(spl(0)), Integer.parseInt(spl(1)));
- }
- @GeneratedConfigParam
- def listenMonitoringHost = extractHostAndPortPort(listenMonitoring)._1;
- @GeneratedConfigParam
- def listenMonitoringPrimaryPort = extractHostAndPortPort(listenMonitoring)._2;
- @GeneratedConfigParam
- def listenMonitoringSecondaryPort = extractHostAndPortPort(listenMonitoring)._3;
-
- @ConfigParam("[host:]port on which to listen for RPCs (via SARS). Default: none.")
- { val argName = "[host:]port" }
- def listenSars = stringOrElse("listenSars", "0");
- @GeneratedConfigParam
- def listenSarsHost = extractHostAndPort(listenSars)._1;
- @GeneratedConfigParam
- def listenSarsPort = extractHostAndPort(listenSars)._2;
-
- // Licensing
- @ConfigParam("Private key for generating license keys.")
- { val argName = "pathToKey" }
- def licenseGeneratorKey = stringOrElse("licenseGeneratorKey", null);
-
- // SARS
- @ConfigParam("SARS auth key. Default: \"appjet\".")
- { val argName = "authkey" }
- def sarsAuthKey = stringOrElse("sarsAuthKey", "appjet");
-
- // SSL
- @ConfigParam("[SSL] Keystore location. Default: appjetHome/sslkeystore.")
- { val argName = "keystore" }
- def sslKeyStore = stringOrElse("sslKeyStore", appjetHome+"/sslkeystore");
- def sslKeyStore_isSet = values.contains("sslKeyStore");
- @ConfigParam("[SSL] Key password. Default: same as store password.")
- { val argName = "password" }
- def sslKeyPassword = stringOrElse("sslKeyPassword", "[sslStorePassword]");
- @ConfigParam("[SSL] Store password. Default: 'appjet'.")
- { val argName = "password" }
- def sslStorePassword = stringOrElse("sslStorePassword", "appjet");
-
- // email
- @ConfigParam("host:port of mail server to use for sending email. Default: localhost:25.")
- { val argName = "host:port" }
- def smtpServer = stringOrElse("smtpServer", "localhost:25");
- def smtpServerHost = extractHostAndPort(smtpServer)._1;
- def smtpServerPort = extractHostAndPort(smtpServer)._2;
- @ConfigParam("username for authentication to mail server. Default: no authentication.")
- { val argName = "username" }
- def smtpUser = stringOrElse("smtpUser", "");
- @ConfigParam("password for authentication to mail server. Default: no authentication.")
- { val argName = "password" }
- def smtpPass = stringOrElse("smtpPass", "");
-
- // comet
- @ConfigParam("prefix for all comet requests. Required to use Comet system.")
- { val argName = "path" }
- def transportPrefix = stringOrElse("transportPrefix", null);
- @ConfigParam("Use a subdomain for all comet requests.")
- def transportUseWildcardSubdomains = boolOrElse("transportUseWildcardSubdomains", false);
- @ConfigParam("Don't use short polling, ever.")
- def disableShortPolling = boolOrElse("disableShortPolling", false);
-
- // helpers
- val allProperties =
- for (m <- getClass.getDeclaredMethods() if (m.getAnnotation(classOf[ConfigParam]) != null || m.getAnnotation(classOf[GeneratedConfigParam]) != null))
- yield m;
- val configParamNames =
- for (m <- allProperties if m.getAnnotation(classOf[ConfigParam]) != null) yield m.getName
- lazy val allPropertiesMap =
- Map((for (m <- allProperties) yield ((m.getName, () => m.invoke(this)))): _*);
- val propertiesPattern = Pattern.compile("\\[("+allProperties.map(x => "(?:"+x.getName()+")").mkString("|")+")\\]");
-
- override def toString() =
- (allProperties.map(m => m.getName()+" -> "+m.invoke(this)) ++
- values.keys.toList.filter(! allPropertiesMap.contains(_)).map(k => k+" -> "+values(k))).mkString("[Config ", ", ", "]");
- def print {
- for (m <- allProperties) {
- println(m.getName() + " -> " + m.invoke(this));
- }
- for ((k, v) <- values if (! allPropertiesMap.contains(k))) {
- println(k + " -> " + v);
- }
- }
- def configObject(globalScope: Scriptable) =
- new ScriptableAdapter {
- val keys = (Set.empty[Object] ++ allProperties.map(m => m.getName) ++ values.keySet).toList.toArray;
- override def get(n: String, start: Scriptable) =
- allPropertiesMap.getOrElse(n, () => values.getOrElse(n, JSContext.getUndefinedValue()))();
- override def put(n: String, start: Scriptable, value: Object) =
- values(n) = value.toString();
- override def getIds() = keys;
- override def getPrototype() = ScriptableObject.getObjectPrototype(globalScope);
- override def has(n: String, start: Scriptable) =
- allPropertiesMap.contains(n) || values.contains(n);
- override def getDefaultValue(hint: Class[_]) = config.toString();
- }
-}
-
-object global {
- var context: Context = null;
-}
diff --git a/trunk/infrastructure/net.appjet.oui/execution.scala b/trunk/infrastructure/net.appjet.oui/execution.scala
deleted file mode 100644
index 63749b1..0000000
--- a/trunk/infrastructure/net.appjet.oui/execution.scala
+++ /dev/null
@@ -1,654 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-package net.appjet.oui;
-
-import java.net.URLDecoder;
-import java.util.Enumeration;
-import java.util.concurrent.atomic.AtomicLong;
-
-import javax.servlet.http.{HttpServletRequest, HttpServletResponse, HttpServlet};
-
-import scala.collection.mutable.{ListBuffer, LinkedHashSet, HashMap, ArrayBuffer};
-import scala.collection.immutable.Map;
-import scala.collection.jcl.Conversions;
-
-import org.mozilla.javascript.{Scriptable, Context, Function, ScriptableObject, JavaScriptException};
-import org.mortbay.jetty.RetryRequest;
-
-import net.appjet.bodylock.{BodyLock, Executable, JSRuntimeException, JSCompileException};
-import net.appjet.common.util.{HttpServletRequestFactory, BetterFile};
-
-import Util.enumerationToRichEnumeration;
-
-class RequestWrapper(val req: HttpServletRequest) {
- req.setCharacterEncoding("UTF-8");
-// private lazy val parameterNames =
-// (for (i <- Conversions.convertSet(req.getParameterMap.keySet().asInstanceOf[java.util.Set[String]])) yield i).toList.toArray
-// private def parameterValues(k: String) = req.getParameterValues(k);
- def headerCapitalize(s: String) =
- s.split("-").map(
- s =>
- if (s == null || s.length < 1) s
- else s.substring(0, 1).toUpperCase()+s.substring(1).toLowerCase()
- ).mkString("-");
- def isFake = false;
- lazy val path = req.getRequestURI();
- lazy val host = {
- val hostFromHeader = req.getHeader("Host");
- if ((hostFromHeader ne null) && hostFromHeader.indexOf(':') >= 0) {
- // fix the port, which may be wrong in Host header (e.g. IE 6)
- hostFromHeader.substring(0, hostFromHeader.indexOf(':')) + ":" +
- req.getLocalPort;
- }
- else {
- hostFromHeader;
- }
- }
- lazy val query = req.getQueryString();
- lazy val method = req.getMethod();
- lazy val scheme = req.getScheme();
- lazy val clientAddr = req.getRemoteAddr();
-
- def decodeWwwFormUrlencoded(content: => String): Map[String, Array[String]] = {
- val map = new HashMap[String, ArrayBuffer[String]];
- if (content != null) {
- for (pair <- content.split("&").map(_.split("=", 2))) {
- val key = URLDecoder.decode(pair(0), "UTF-8");
- val list = map.getOrElseUpdate(key, new ArrayBuffer[String]);
- if (pair.length > 1) {
- list += URLDecoder.decode(pair(1), "UTF-8");
- }
- }
- }
- Map((for ((k, v) <- map) yield (k, v.toArray)).toSeq: _*);
- }
-
- def postParams = decodeWwwFormUrlencoded(content.asInstanceOf[String]);
- def getParams = decodeWwwFormUrlencoded(query);
-
- lazy val params_i = {
- if (contentType != null && contentType.startsWith("application/x-www-form-urlencoded")) {
- if (req.getAttribute("ajcache_parameters") == null) {
- req.setAttribute("ajcache_parameters",
- Map((for (k <- (postParams.keys ++ getParams.keys).toList)
- yield (k, postParams.getOrElse(k, Array[String]()) ++
- getParams.getOrElse(k, Array[String]()))).toSeq: _*));
- }
- req.getAttribute("ajcache_parameters").asInstanceOf[Map[String, Array[String]]];
- } else {
- Conversions.convertMap(req.getParameterMap().asInstanceOf[java.util.Map[String, Array[String]]]);
- }
- }
-
- def params(globalScope: Scriptable) = new ScriptableFromMapOfStringArrays(
- globalScope,
- params_i.keys.toList,
- params_i.get(_),
- false);
- def headers(globalScope: Scriptable) = new ScriptableFromMapOfStringArrays(
- globalScope,
- req.getHeaderNames().asInstanceOf[Enumeration[String]]
- .map(headerCapitalize).toList,
- h => h match {
- case "Host" => Some(Array(host));
- case hh => Some(Util.enumerationToArray(req.getHeaders(headerCapitalize(hh)).asInstanceOf[Enumeration[String]])) },
- true);
- lazy val protocol = req.getProtocol();
- lazy val contentType = req.getHeader("Content-Type");
- lazy val postParamsInBody = contentType != null && contentType.startsWith("application/x-www-form-urlencoded");
- lazy val content =
- if ((contentType != null && contentType.startsWith("text/")) || postParamsInBody) {
- val reader = req.getReader();
- if (reader != null)
- BetterFile.getReaderString(req.getReader());
- else
- null;
- } else {
- val stream = req.getInputStream();
- if (stream != null)
- BetterFile.getStreamBytes(req.getInputStream());
- else
- null;
- }
- def files(globalScope: Scriptable): Object = {
-// if (! req.isInstanceOf[com.oreilly.servlet.MultipartWrapper]) {
- new ScriptableAdapter();
-// } else {
-// val r = req.asInstanceOf[com.oreilly.servlet.MultipartWrapper];
-// val fileScriptables = new HashMap[String, Scriptable]();
-// val fileBytes = new HashMap[String, Array[byte]]();
-// new ScriptableFromMapOfScriptableArrays(globalScope,
-// r.getFileNames().asInstanceOf[Enumeration[String]].toList,
-// name => {
-// if (r.getFile(name) == null)
-// None
-// else
-// Some(Array(fileScriptables.getOrElseUpdate(name,
-// new ScriptableFromMapOfArrays[Object](globalScope,
-// Set("contentType", "filesystemName", "bytes").toSeq,
-// _ match {
-// case "contentType" => Some(Array(r.getContentType(name)));
-// case "filesystemName" =>
-// Some(Array(r.getFilesystemName(name)));
-// case "bytes" =>
-// Some(Array(Context.javaToJS(fileBytes.getOrElseUpdate(name,
-// BetterFile.getFileBytes(r.getFile(name))), globalScope)));
-// case _ => None;
-// },
-// true))))
-// },
-// true);
-// }
- }
-}
-
-class ResponseWrapper(val res: HttpServletResponse) {
- private lazy val outputStrings = new ListBuffer[String];
- private lazy val outputBytes = new ListBuffer[Array[byte]];
- private var statusCode = 200;
- private var contentType = "text/html";
- private var redirect: String = null;
- private lazy val headers = new LinkedHashSet[(String, String, HttpServletResponse => Unit)] {
- def removeAll(k: String) {
- this.foreach(x => if (x._1 == k) remove(x));
- }
- }
-
- private[oui] def overwriteOutputWithError(code: Int, errorStr: String) {
- statusCode = code;
- outputStrings.clear();
- outputStrings += errorStr;
- outputBytes.clear();
- headers.clear();
- Util.noCacheHeaders.foreach(x => headers += (x._1, x._2, res => res.setHeader(x._1, x._2)));
- redirect = null;
- contentType = "text/html; charset=utf-8";
- }
-
- def reset() {
- outputStrings.clear();
- outputBytes.clear();
- redirect = null;
- headers.clear();
- Util.noCacheHeaders.foreach(x => headers += (x._1, x._2, res => res.setHeader(x._1, x._2)));
- statusCode = 200;
- contentType = "text/html; charset=utf-8";
- }
- def error(code: Int, errorStr: String) {
- overwriteOutputWithError(code, errorStr);
- stop();
- }
- def stop() {
- throw AppGeneratedStopException;
- }
-
- def write(s: String) {
- outputStrings += s;
- }
- def getOutput() = outputStrings.mkString("");
- def writeBytes(bytes: String) {
- val a = new Array[byte](bytes.length());
- bytes.getBytes(0, bytes.length(), a, 0);
- outputBytes += a;
- }
- def writeBytes(bytes: Array[Byte]) {
- outputBytes += bytes;
- }
- def getOutputBytes() = outputBytes.flatMap(x => x).toArray
- def setContentType(s: String) {
- contentType = s;
- }
- def getCharacterEncoding() = {
- res.setContentType(contentType);
- res.getCharacterEncoding();
- }
- def setStatusCode(sc: Int) {
- statusCode = sc;
- }
- def getStatusCode() = statusCode;
- def redirect(loc: String) {
- statusCode = 302;
- redirect = loc;
- stop();
- }
- def setHeader(name: String, value: String) {
- headers += ((name, value, res => res.setHeader(name, value)));
- }
- def addHeader(name: String, value: String) {
- headers += ((name, value, res => res.addHeader(name, value)));
- }
- def getHeader(name: String) = {
- headers.filter(_._1 == name).map(_._2).toSeq.toArray;
- }
- def removeHeader(name: String) {
- headers.removeAll(name);
- }
-
- var gzipOutput = false;
- def setGzip(gzip: Boolean) {
- gzipOutput = gzip;
- }
-
- def print() {
- if (redirect != null && statusCode == 302) {
- headers.foreach(_._3(res));
- res.sendRedirect(redirect);
- } else {
- res.setStatus(statusCode);
- res.setContentType(contentType);
- headers.foreach(_._3(res));
- if (gzipOutput) res.setHeader("Content-Encoding", "gzip");
- if (outputStrings.length > 0) {
- var bytes: Seq[Array[Byte]] = outputStrings.map(_.getBytes(res.getCharacterEncoding()));
- if (gzipOutput) bytes = List(Util.gzip(Array.concat(bytes:_*)));
- res.setContentLength((bytes :\ 0) {_.length + _});
- bytes.foreach(res.getOutputStream.write(_));
- } else if (outputBytes.length > 0) {
- var bytes: Seq[Array[Byte]] = outputBytes;
- if (gzipOutput) bytes = List(Util.gzip(Array.concat(bytes:_*)));
- res.setContentLength((bytes :\ 0) {_.length + _});
- bytes.foreach(res.getOutputStream.write(_));
- }
- }
- }
-}
-
-class ScriptableAdapter extends Scriptable {
- private def unsupported() = throw UnsupportedOperationException;
- def delete(index: Int) { unsupported(); }
- def delete(name: String) { unsupported(); }
- def get(index: Int, start: Scriptable): Object = Context.getUndefinedValue();
- def get(name: String, start: Scriptable): Object = Context.getUndefinedValue();
- def getClassName() = getClass.getName();
- def getDefaultValue(hint: Class[_]) = "[ScriptableAdapter]";
- def getIds(): Array[Object] = Array[Object]();
- def getParentScope: Scriptable = null;
- def getPrototype: Scriptable = null;
- def has(index: Int, start: Scriptable): Boolean = false;
- def has(name: String, start: Scriptable): Boolean = false;
- def hasInstance(instance: Scriptable): Boolean = false;
- def put(index: Int, start: Scriptable, value: Object) { unsupported(); }
- def put(name: String, start: Scriptable, value: Object) { unsupported(); }
- def setParentScope(parent: Scriptable) { unsupported(); }
- def setPrototype(prototype: Scriptable) { unsupported(); }
-}
-
-class ScriptableFromMapOfStringArrays(globalScope: Scriptable,
- keys: Seq[String], values: String => Option[Array[String]],
- zeroMeansNone: Boolean) extends ScriptableFromMapOfArrays[String](
- globalScope, keys, values, zeroMeansNone);
-
-class ScriptableFromMapOfScriptableArrays(globalScope: Scriptable,
- keys: Seq[String], values: String => Option[Array[Scriptable]],
- zeroMeansNone: Boolean) extends ScriptableFromMapOfArrays[Scriptable](
- globalScope, keys, values, zeroMeansNone);
-
-
-class ScriptableFromMapOfArrays[V <: Object](globalScope: Scriptable,
- keys: Seq[String], values: String => Option[Array[V]],
- zeroMeansNone: Boolean) extends ScriptableAdapter {
- override def get(n: String, start: Scriptable): Object = {
- val v = values(n);
- if (v.isEmpty || (zeroMeansNone && v.get.length == 0)) {
- Context.getUndefinedValue();
- } else if (v.get.length == 1) {
- v.get.apply(0);
- } else {
- Context.getCurrentContext().newArray(globalScope, v.get.map(x => x.asInstanceOf[Object]));
- }
- }
- override def getIds(): Array[Object] = keys.toArray[Object];
- override def getPrototype = ScriptableObject.getObjectPrototype(globalScope);
- override def has(n: String, start: Scriptable): Boolean = ! (values(n).isEmpty || (zeroMeansNone && values(n).get.length == 0));
-}
-
-object AppGeneratedStopException extends JSRuntimeException("User-generated stop.", null);
-class NoHandlerException(msg: String) extends JSRuntimeException(msg, null);
-object UnsupportedOperationException extends JSRuntimeException("Unsupported operation.", null);
-
-object ExecutionContextUtils {
- val uniqueIds = new AtomicLong(0);
-
- val ecVar = new NoninheritedDynamicVariable[ExecutionContext](null);
- def withContext[E](ec: ExecutionContext)(block: => E): E = {
- ecVar.withValue(ec)(block);
- }
-
- def currentContext = ecVar.value;
-}
-
-case class ExecutionContext(
- val request: RequestWrapper,
- val response: ResponseWrapper,
- var runner: ScopeReuseManager.Runner) {
- val asyncs = new ListBuffer[Function];
- lazy val attributes = new HashMap[String, Any];
- var completed = false;
- lazy val executionId = ""+ExecutionContextUtils.uniqueIds.incrementAndGet();
- var result: AnyRef = null;
-}
-
-object CometSupport {
- trait CometHandler {
- def handleCometRequest(req: HttpServletRequest, res: HttpServletResponse);
- }
- var cometHandler: CometHandler = null;
-}
-
-class OuiServlet extends HttpServlet {
- override def doGet(req: HttpServletRequest, res: HttpServletResponse) {
- execute(req, res);
- }
-
- override def doPost(req: HttpServletRequest, res: HttpServletResponse) {
- execute(req, res);
- }
-
- override def doHead(req: HttpServletRequest, res: HttpServletResponse) {
- execute(req, res);
- }
-
- override def doPut(req: HttpServletRequest, res: HttpServletResponse) {
- execute(req, res);
- }
-
- override def doDelete(req: HttpServletRequest, res: HttpServletResponse) {
- execute(req, res);
- }
-
- override def doTrace(req: HttpServletRequest, res: HttpServletResponse) {
- execute(req, res);
- }
-
- override def doOptions(req: HttpServletRequest, res: HttpServletResponse) {
- execute(req, res);
- }
-
- def execute(req: HttpServletRequest, res: HttpServletResponse) {
- if (req.getProtocol() == "HTTP/1.1" && req.getHeader("Host") == null) {
- res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid HTTP/1.1 request: No \"Host\" header found.");
- } else if (config.transportPrefix != null && req.getRequestURI().startsWith(config.transportPrefix)) {
- val runner = ScopeReuseManager.getRunner;
- val ec = new ExecutionContext(new RequestWrapper(req), new ResponseWrapper(res), runner);
- req.setAttribute("executionContext", ec);
- req.setAttribute("isServerPushConnection", true);
- try {
- CometSupport.cometHandler.handleCometRequest(req, res);
- } catch {
- case e: RetryRequest => {
- ec.runner = null;
- ScopeReuseManager.freeRunner(runner);
- throw e;
- }
- case _ => {};
- }
- try {
- ec.response.print();
- execution.onprint(ec, BodyLock.subScope(runner.mainScope));
- } finally {
- ec.runner = null;
- ScopeReuseManager.freeRunner(runner);
- }
- } else {
- execution.execute(req, res);
- }
- }
-}
-
-object execution {
- // maybe find a better place for this?
- { // initialize ajstdlib
- val c = Class.forName("net.appjet.ajstdlib.ajstdlib$");
- val m = c.getDeclaredMethod("init");
- val o = c.getDeclaredField("MODULE$");
- m.invoke(o.get(null));
- }
-
- val requestLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onrequest.js"));
- val errorLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onerror.js"));
- val printLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onprint.js"));
- val syntaxErrorLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "syntaxerror.js"));
- val onSyntaxErrorLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onsyntaxerror.js"));
- val sarsLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onsars.js"));
- val scheduledTaskLib = new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onscheduledtask.js"));
- def requestExecutable = requestLib.executable;
- def errorExecutable = errorLib.executable;
- def printExecutable = printLib.executable;
- def syntaxErrorExecutable = syntaxErrorLib.executable;
- def onSyntaxErrorExecutable = onSyntaxErrorLib.executable;
- def sarsExecutable = sarsLib.executable;
- def scheduledTaskExecutable = scheduledTaskLib.executable;
-
- def postSuccessfulRun(ec: ExecutionContext) {
- try {
- for (f <- ec.asyncs) {
- BodyLock.runInContext({ cx =>
- f.call(cx, f.getParentScope(), ec.runner.mainScope, Array[Object]());
- });
- }
- } catch {
- case e => exceptionlog(e);
- }
- }
-
- def onprint(ec: ExecutionContext, scope: Scriptable) {
- try {
-// ec.runner.globalScope.put("_appjetcontext_", ec.runner.globalScope, ec);
- printExecutable.execute(scope);
- } catch {
- case e => { exceptionlog(e); } // shrug. this was best-effort anyway.
- }
- }
-
- def execute(req: HttpServletRequest, res: HttpServletResponse) {
- val runner = try {
- ScopeReuseManager.getRunner;
- } catch {
- case e: JSCompileException => {
- val r = ScopeReuseManager.getEmpty { r =>
- syntaxErrorExecutable.execute(r.globalScope)
- }
- val ec = ExecutionContext(new RequestWrapper(req), new ResponseWrapper(res), r);
-// r.globalScope.put("_appjetcontext_", r.globalScope, ec);
- ExecutionContextUtils.withContext(ec) {
- ec.attributes("error") = e;
- ec.result = onSyntaxErrorExecutable.execute(r.globalScope);
- ec.response.print();
- }
- return;
- }
- }
- val ec = ExecutionContext(new RequestWrapper(req), new ResponseWrapper(res), runner);
- val startTime = executionlatencies.time;
- execute(ec,
- (sc: Int, msg: String) => {
- ec.response.overwriteOutputWithError(sc, msg);
- },
- () => { executionlatencies.log(Map(
- "time" -> (executionlatencies.time - startTime)));
- ec.response.print() },
- () => { ScopeReuseManager.freeRunner(runner) },
- None);
- }
-
- def errorToHTML(e: Throwable) = {
- val trace = new java.io.StringWriter();
- e.printStackTrace(new java.io.PrintWriter(trace));
- trace.toString().split("\n").mkString("<br>\n");
- }
- def execute(ec: ExecutionContext,
- errorHandler: (Int, String) => Unit,
- doneWritingHandler: () => Unit,
- completedHandler: () => Unit,
- customExecutable: Option[Executable]) =
- ExecutionContextUtils.withContext(ec) {
-// ec.runner.globalScope.put("_appjetcontext_", ec.runner.globalScope, ec);
- val runScope = BodyLock.subScope(ec.runner.mainScope);
- try {
- ec.result = customExecutable.getOrElse(requestExecutable).execute(runScope);
- ec.completed = true;
- } catch {
- case AppGeneratedStopException => { ec.completed = true; }
- case e: NoHandlerException => errorHandler(500, "No request handler is defined.");
- case e: RetryRequest => { completedHandler(); throw e; }
- case e => {
- ec.attributes("error") = e;
- try {
- ec.result = errorExecutable.execute(runScope);
- } catch {
- case AppGeneratedStopException => { }
- case nhe: NoHandlerException => {
- exceptionlog(e);
- e.printStackTrace();
- errorHandler(500, "An error occurred and no error handler is defined.");
- }
- case e2 => {
- exceptionlog(e); exceptionlog(e2);
- val etext = e2 match {
- case jse: JavaScriptException => { (jse.getValue() match {
- case ne: org.mozilla.javascript.IdScriptableObject => ne.get("message", ne)
- case e => e.getClass.getName
- }) + "<br>\n" + errorToHTML(jse); }
- case _ => errorToHTML(e2);
- }
- errorHandler(
- 500,
- "You like apples? An error occurred in the error handler while handling an error. How do you like <i>them</i> apples?<br>\n"+
- etext+"<br>\nCaused by:<br>\n"+errorToHTML(e));
- }
- }
- }
- }
- onprint(ec, runScope);
- doneWritingHandler();
- if (ec.completed && ! ec.asyncs.isEmpty) {
- main.server.getThreadPool().dispatch(new Runnable {
- def run() {
- postSuccessfulRun(ec);
- completedHandler();
- }
- });
- } else {
- completedHandler();
- }
- }
-
- def runOutOfBandSimply(executable: Executable,
- props: Option[Map[String, Any]]) = {
- // there must be a context already.
- val currentContext = ExecutionContextUtils.currentContext;
- val request =
- if (currentContext != null) {
- currentContext.request;
- } else {
- val fakeHeaders = scala.collection.jcl.Conversions.convertMap(
- new java.util.HashMap[String, String]);
- fakeHeaders("Host") = "unknown.local";
- new RequestWrapper(HttpServletRequestFactory.createRequest(
- "/", fakeHeaders.underlying, "GET", null)) {
- override val isFake = true;
- }
- }
- val response =
- if (currentContext != null && currentContext.response != null) {
- currentContext.response;
- } else {
- new ResponseWrapper(null);
- }
- val runner =
- if (currentContext != null) {
- (false, currentContext.runner);
- } else {
- (true, ScopeReuseManager.getRunner);
- }
- val ec = new ExecutionContext(request, response, runner._2)
- if (props.isDefined) {
- for ((k, v) <- props.get) {
- ec.attributes(k) = v;
- }
- }
- try {
- ExecutionContextUtils.withContext(ec) {
- executable.execute(BodyLock.subScope(ec.runner.mainScope));
- }
- } finally {
- if (runner._1) {
- ScopeReuseManager.freeRunner(runner._2);
- }
- }
- }
-
- def runOutOfBand(executable: Executable, name: String,
- props: Option[Map[String, Any]],
- onFailure: Any => Unit) = {
- var ec: ExecutionContext = null;
- try {
- val runner = ScopeReuseManager.getRunner;
- val currentContext = ExecutionContextUtils.currentContext;
- val request =
- if (currentContext != null) {
- currentContext.request;
- } else {
- val fakeHeaders = scala.collection.jcl.Conversions.convertMap(
- new java.util.HashMap[String, String]);
- fakeHeaders("Host") = "unknown.local";
- new RequestWrapper(HttpServletRequestFactory.createRequest(
- "/", fakeHeaders.underlying, "GET", null)) {
- override val isFake = true;
- }
- }
- val response =
- if (currentContext != null && currentContext.response != null) {
- new ResponseWrapper(currentContext.response.res);
- } else {
- new ResponseWrapper(null);
- }
- ec = new ExecutionContext(request, response, runner);
- if (props.isDefined)
- for ((k, v) <- props.get) {
- ec.attributes(k) = v;
- }
- execution.execute(ec,
- (sc: Int, msg: String) => { println(name+" execution failed with error: "+sc+"\n"+msg); onFailure((sc, msg)); },
- () => { },
- () => { ScopeReuseManager.freeRunner(runner) },
- Some(executable));
- if (ec.response != null && ec.response.getStatusCode() != 200) {
- println(name+" execution failed with non-200 response: "+ec.response.getStatusCode());
- onFailure((ec.response.getStatusCode, ec.response.getOutput()));
- }
- ec;
- } catch {
- case e: JSCompileException => {
- val r = ScopeReuseManager.getEmpty { r =>
- execution.syntaxErrorExecutable.execute(r.globalScope);
- }
- val ec = ExecutionContext(null, null, r);
-// r.globalScope.put("_appjetcontext_", r.globalScope, ec);
- ExecutionContextUtils.withContext(ec) {
- ec.attributes("error") = e;
- ec.result = execution.onSyntaxErrorExecutable.execute(r.globalScope);
- onFailure(e);
- }
- ec;
- }
- case e => {
- println(name+" execution failed with error."); onFailure(e); ec;
- }
- }
- }
-}
diff --git a/trunk/infrastructure/net.appjet.oui/main.scala b/trunk/infrastructure/net.appjet.oui/main.scala
deleted file mode 100644
index 42cd268..0000000
--- a/trunk/infrastructure/net.appjet.oui/main.scala
+++ /dev/null
@@ -1,386 +0,0 @@
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 "AS-IS" 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.
- */
-
-package net.appjet.oui;
-
-import net.appjet.bodylock.{BodyLock, Executable};
-
-import java.io.File;
-import java.util.{Properties, Date};
-import java.lang.annotation.Annotation;
-import java.text.SimpleDateFormat;
-
-import scala.collection.mutable.{HashMap, SynchronizedMap, HashSet};
-import scala.collection.jcl.{IterableWrapper, Conversions};
-
-import org.mortbay.thread.QueuedThreadPool;
-import org.mortbay.jetty.servlet.{Context, HashSessionIdManager, FilterHolder, ServletHolder};
-import org.mortbay.jetty.handler.{HandlerCollection, RequestLogHandler, HandlerList};
-import org.mortbay.jetty.{Server, NCSARequestLog, Request, Response};
-import org.mortbay.servlet.GzipFilter;
-
-// removed due to license restrictions
-// import com.oreilly.servlet.MultipartFilter;
-
-import net.appjet.common.util.{BetterFile, HttpServletRequestFactory};
-import net.appjet.common.cli._;
-import net.appjet.bodylock.JSCompileException;
-
-import Util.enumerationToRichEnumeration;
-
-object main {
- val startTime = new java.util.Date();
-
- def quit(status: Int) {
- java.lang.Runtime.getRuntime().halt(status);
- }
-
- def setupFilesystem() {
- val logdir = new File(config.logDir+"/backend/access");
- if (! logdir.isDirectory())
- if (! logdir.mkdirs())
- quit(1);
- }
-
- val options =
- for (m <- config.allProperties if (m.getAnnotation(classOf[ConfigParam]) != null)) yield {
- val cp = m.getAnnotation(classOf[ConfigParam])
- new CliOption(m.getName(), cp.value(), if (cp.argName().length > 0) Some(cp.argName()) else None);
- }
-
- def printUsage() {
- println("\n--------------------------------------------------------------------------------");
- println("usage:");
- println((new CliParser(options)).usage);
- println("--------------------------------------------------------------------------------\n");
- }
-
- def extractOptions(args: Array[String]) {
- val parser = new CliParser(options);
- val opts =
- try {
- parser.parseOptions(args)._1;
- } catch {
- case e: ParseException => {
- println("error: "+e.getMessage());
- printUsage();
- System.exit(1);
- null;
- }
- }
- if (opts.contains("configFile")) {
- val p = new Properties();
- p.load(new java.io.FileInputStream(opts("configFile")));
- extractOptions(p);
- }
- for ((k, v) <- opts) {
- config.values(k) = v;
- }
- }
-
- def extractOptions(props: Properties) {
- for (k <- for (o <- props.propertyNames()) yield o.asInstanceOf[String]) {
- config.values(k) = props.getProperty(k);
- }
- }
-
- val startupExecutable = (new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onstartup.js"))).executable;
- def runOnStartup() {
- execution.runOutOfBand(startupExecutable, "Startup", None, { error =>
- error match {
- case e: JSCompileException => { }
- case e: Throwable => { e.printStackTrace(); }
- case (sc: Int, msg: String) => { println(msg); }
- case x => println(x);
- }
- System.exit(1);
- });
- }
-
- lazy val shutdownExecutable = (new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onshutdown.js"))).executable;
- def runOnShutdown() {
- execution.runOutOfBand(shutdownExecutable, "Shutdown", None, { error =>
- error match {
- case e: JSCompileException => { }
- case e: Throwable => { }
- case (sc: Int, msg: String) => { println(msg); }
- case x => println(x);
- }
- });
- }
-
- def runOnSars(q: String) = {
- val ec = execution.runOutOfBand(execution.sarsExecutable, "SARS", Some(Map("sarsRequest" -> q)), { error =>
- error match {
- case e: JSCompileException => { throw e; }
- case e: Throwable => { exceptionlog(e); throw e; }
- case (sc: Int, msg: String) => { println(msg); throw new RuntimeException(""+sc+": "+msg) }
- case x => { println(x); throw new RuntimeException(x.toString()) }
- }
- });
- ec.attributes.get("sarsResponse").map(_.toString());
- }
-
- def stfu() {
- System.setProperty("org.mortbay.log.class", "net.appjet.oui.STFULogger");
- System.setProperty("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
- System.setProperty("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "OFF");
- }
- var server: Server = null;
- var sarsServer: net.appjet.common.sars.SarsServer = null;
-
- var loggers = new HashSet[GenericLogger];
- def main(args: Array[String]) {
- val etherpadProperties = getClass.getResource("/etherpad.properties");
- if (etherpadProperties != null) {
- val p = new Properties();
- p.load(etherpadProperties.openStream);
- extractOptions(p);
- }
- extractOptions(args);
-
- if (! config.verbose)
- stfu();
- setupFilesystem();
- if (config.devMode)
- config.print;
- if (config.profile)
- profiler.start();
- if (config.listenMonitoring != "0:0")
- monitoring.startMonitoringServer();
-
- // this needs a better place.
- if (config.devMode)
- BodyLock.map = Some(new HashMap[String, String] with SynchronizedMap[String, String]);
-
- server = new Server();
- if (config.maxThreads > 0)
- server.setThreadPool(new QueuedThreadPool(config.maxThreads));
- else
- server.setThreadPool(new QueuedThreadPool());
- // set up socket connectors
- val nioconnector = new CometSelectChannelConnector;
- var sslconnector: CometSslSelectChannelConnector = null;
- nioconnector.setPort(config.listenPort);
- if (config.listenHost.length > 0)
- nioconnector.setHost(config.listenHost);
- if (config.listenSecurePort == 0) {
- server.setConnectors(Array(nioconnector));
- } else {
- sslconnector = new CometSslSelectChannelConnector;
- sslconnector.setPort(config.listenSecurePort);
- if (config.listenSecureHost.length > 0)
- sslconnector.setHost(config.listenSecureHost);
- if (! config.sslKeyStore_isSet) {
- val url = getClass.getResource("/mirror/snakeoil-ssl-cert");
- if (url != null)
- sslconnector.setKeystore(url.toString());
- else
- sslconnector.setKeystore(config.sslKeyStore);
- } else {
- sslconnector.setKeystore(config.sslKeyStore);
- }
- sslconnector.setPassword(config.sslStorePassword);
- sslconnector.setKeyPassword(config.sslKeyPassword);
- sslconnector.setTrustPassword(config.sslStorePassword);
- sslconnector.setExcludeCipherSuites(Array[String](
- "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
- "SSL_DHE_RSA_WITH_DES_CBC_SHA",
- "SSL_DHE_DSS_WITH_DES_CBC_SHA",
- "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
- "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
- "SSL_RSA_WITH_DES_CBC_SHA",
- "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
- "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
- "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
- "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
- "SSL_RSA_WITH_NULL_MD5",
- "SSL_RSA_WITH_NULL_SHA",
- "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
- "SSL_DH_anon_WITH_DES_CBC_SHA",
- "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
- "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"));
- server.setConnectors(Array(nioconnector, sslconnector));
- }
-
- // set up Context and Servlet
- val handler = new Context(server, "/", Context.NO_SESSIONS | Context.NO_SECURITY);
- handler.addServlet(new ServletHolder(new OuiServlet), "/");
-
-// val filterHolder = new FilterHolder(new MultipartFilter());
-// filterHolder.setInitParameter("uploadDir", System.getProperty("java.io.tmpdir"));
-// handler.addFilter(filterHolder, "/*", 1);
-
- global.context = handler;
-
- // set up apache-style logging
- val requestLogHandler = new RequestLogHandler();
- val requestLog = new NCSARequestLog(config.logDir+"/backend/access/access-yyyy_mm_dd.request.log") {
- override def log(req: Request, res: Response) {
- try {
- if (config.devMode || config.specialDebug)
- super.log(req, res);
- else if (res.getStatus() != 200 || config.transportPrefix == null || ! req.getRequestURI().startsWith(config.transportPrefix))
- super.log(req, res);
- val d = new Date();
- appstats.stati.foreach(_(if (res.getStatus() < 0) 404 else res.getStatus()).hit(d));
- } catch {
- case e => { exceptionlog("Error writing to log?"); exceptionlog(e); }
- }
- }
- };
- requestLog.setRetainDays(365);
- requestLog.setAppend(true);
- requestLog.setExtended(true);
- requestLog.setLogServer(true);
- requestLog.setLogLatency(true);
- requestLog.setLogTimeZone("PST");
- requestLogHandler.setRequestLog(requestLog);
-
- // set handlers with server
- val businessHandlers = new HandlerList();
- businessHandlers.setHandlers(Array(handler));
- val allHandlers = new HandlerCollection();
- allHandlers.setHandlers(Array(businessHandlers, requestLogHandler));
- server.setHandler(allHandlers);
-
- // fix slow startup bug
- server.setSessionIdManager(new HashSessionIdManager(new java.util.Random()));
-
- // run the onStartup script.
- runOnStartup();
-
- // preload some runners, if necessary.
- if (config.preloadRunners > 0) {
- val b = new java.util.concurrent.CountDownLatch(config.preloadRunners);
- for (i <- 0 until config.preloadRunners)
- (new Thread {
- ScopeReuseManager.freeRunner(ScopeReuseManager.newRunner);
- b.countDown();
- }).start();
- while (b.getCount() > 0) {
- b.await();
- }
- println("Preloaded "+config.preloadRunners+" runners.");
- }
-
- // start SARS server.
- if (config.listenSarsPort > 0) {
- try {
- import net.appjet.common.sars._;
- sarsServer = new SarsServer(config.sarsAuthKey,
- new SarsMessageHandler { override def handle(q: String) = runOnSars(q) },
- if (config.listenSarsHost.length > 0) Some(config.listenSarsHost) else None,
- config.listenSarsPort);
- sarsServer.daemon = true;
- sarsServer.start();
- } catch {
- case e: java.net.SocketException => {
- println("SARS: A socket exception occurred: "+e.getMessage()+" on SARS server at "+config.listenSarsHost+":"+config.listenSarsPort);
- java.lang.Runtime.getRuntime().halt(1);
- }
- }
- }
-
- // start server
- java.lang.Runtime.getRuntime().addShutdownHook(new Thread() {
- override def run() {
- val df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
- def printts(str: String) {
- println("["+df.format(new Date())+"]: "+str);
- }
- printts("Shutting down...");
- handler.setShutdown(true);
- Thread.sleep(if (config.devMode) 500 else 3000);
- printts("...done, running onshutdown.");
- runOnShutdown();
- printts("...done, stopping server.");
- server.stop();
- server.join();
- printts("...done, flushing logs.");
- for (l <- loggers) { l.flush(); l.close(); }
- printts("...done.");
- }
- });
-
- def socketError(c: org.mortbay.jetty.Connector, e: java.net.SocketException) {
- var msg = e.getMessage();
- println("SOCKET ERROR: "+msg+" - "+(c match {
- case null => "(unknown socket)";
- case x => {
- (x.getHost() match {
- case null => "localhost";
- case y => y;
- })+":"+x.getPort();
- }
- }));
- if (msg.contains("Address already in use")) {
- println("Did you make sure that ports "+config.listenPort+" and "+config.listenSecurePort+" are not in use?");
- }
- if (msg.contains("Permission denied")) {
- println("Perhaps you need to run as the root user or as an Administrator?");
- }
- }
-
- var c: org.mortbay.jetty.Connector = null;
-
- try {
- c = nioconnector;
- c.open();
- if (sslconnector != null) {
- c = sslconnector;
- c.open();
- }
- c = null;
- allHandlers.start();
- server.start();
- } catch {
- case e: java.net.SocketException => {
- socketError(c, e);
- java.lang.Runtime.getRuntime().halt(1);
- }
- case e: org.mortbay.util.MultiException => {
- println("SERVER ERROR: Couldn't start server; multiple errors.");
- for (i <- new IterableWrapper[Throwable] { override val underlying = e.getThrowables.asInstanceOf[java.util.List[Throwable]] }) {
- i match {
- case se: java.net.SocketException => {
- socketError(c, se);
- }
- case e =>
- println("SERVER ERROR: Couldn't start server: "+i.getMessage());
- }
- }
- java.lang.Runtime.getRuntime().halt(1);
- }
- case e => {
- println("SERVER ERROR: Couldn't start server: "+e.getMessage());
- java.lang.Runtime.getRuntime().halt(1);
- }
- }
-
- println("HTTP server listening on http://"+
- (if (config.listenHost.length > 0) config.listenHost else "localhost")+
- ":"+config.listenPort+"/");
- if (config.listenSecurePort > 0)
- println("HTTPS server listening on https://"+
- (if (config.listenSecureHost.length > 0) config.listenSecureHost else "localhost")+
- ":"+config.listenSecurePort+"/");
- if (config.listenSarsPort > 0)
- println("SARS server listening on "+
- (if (config.listenSarsHost.length > 0) config.listenSarsHost else "localhost")+
- ":"+config.listenSarsPort);
- }
-}
diff --git a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java.orig b/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java.orig
deleted file mode 100644
index cdb00b7..0000000
--- a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Decompiler.java.orig
+++ /dev/null
@@ -1,910 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1997-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Mike Ang
- * Igor Bukanov
- * Bob Jervis
- * Mike McCabe
- *
- * Alternatively, the contents of this file may be used under the terms of
- * the GNU General Public License Version 2 or later (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of those above. If
- * you wish to allow use of your version of this file only under the terms of
- * the GPL and not to allow others to use your version of this file under the
- * MPL, indicate your decision by deleting the provisions above and replacing
- * them with the notice and other provisions required by the GPL. If you do
- * not delete the provisions above, a recipient may use your version of this
- * file under either the MPL or the GPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-/**
- * The following class save decompilation information about the source.
- * Source information is returned from the parser as a String
- * associated with function nodes and with the toplevel script. When
- * saved in the constant pool of a class, this string will be UTF-8
- * encoded, and token values will occupy a single byte.
-
- * Source is saved (mostly) as token numbers. The tokens saved pretty
- * much correspond to the token stream of a 'canonical' representation
- * of the input program, as directed by the parser. (There were a few
- * cases where tokens could have been left out where decompiler could
- * easily reconstruct them, but I left them in for clarity). (I also
- * looked adding source collection to TokenStream instead, where I
- * could have limited the changes to a few lines in getToken... but
- * this wouldn't have saved any space in the resulting source
- * representation, and would have meant that I'd have to duplicate
- * parser logic in the decompiler to disambiguate situations where
- * newlines are important.) The function decompile expands the
- * tokens back into their string representations, using simple
- * lookahead to correct spacing and indentation.
- *
- * Assignments are saved as two-token pairs (Token.ASSIGN, op). Number tokens
- * are stored inline, as a NUMBER token, a character representing the type, and
- * either 1 or 4 characters representing the bit-encoding of the number. String
- * types NAME, STRING and OBJECT are currently stored as a token type,
- * followed by a character giving the length of the string (assumed to
- * be less than 2^16), followed by the characters of the string
- * inlined into the source string. Changing this to some reference to
- * to the string in the compiled class' constant pool would probably
- * save a lot of space... but would require some method of deriving
- * the final constant pool entry from information available at parse
- * time.
- */
-public class Decompiler
-{
- /**
- * Flag to indicate that the decompilation should omit the
- * function header and trailing brace.
- */
- public static final int ONLY_BODY_FLAG = 1 << 0;
-
- /**
- * Flag to indicate that the decompilation generates toSource result.
- */
- public static final int TO_SOURCE_FLAG = 1 << 1;
-
- /**
- * Decompilation property to specify initial ident value.
- */
- public static final int INITIAL_INDENT_PROP = 1;
-
- /**
- * Decompilation property to specify default identation offset.
- */
- public static final int INDENT_GAP_PROP = 2;
-
- /**
- * Decompilation property to specify identation offset for case labels.
- */
- public static final int CASE_GAP_PROP = 3;
-
- // Marker to denote the last RC of function so it can be distinguished from
- // the last RC of object literals in case of function expressions
- private static final int FUNCTION_END = Token.LAST_TOKEN + 1;
-
- String getEncodedSource()
- {
- return sourceToString(0);
- }
-
- int getCurrentOffset()
- {
- return sourceTop;
- }
-
- int markFunctionStart(int functionType)
- {
- int savedOffset = getCurrentOffset();
- addToken(Token.FUNCTION);
- append((char)functionType);
- return savedOffset;
- }
-
- int markFunctionEnd(int functionStart)
- {
- int offset = getCurrentOffset();
- append((char)FUNCTION_END);
- return offset;
- }
-
- void addToken(int token)
- {
- if (!(0 <= token && token <= Token.LAST_TOKEN))
- throw new IllegalArgumentException();
-
- append((char)token);
- }
-
- void addEOL(int token)
- {
- if (!(0 <= token && token <= Token.LAST_TOKEN))
- throw new IllegalArgumentException();
-
- append((char)token);
- append((char)Token.EOL);
- }
-
- void addName(String str)
- {
- addToken(Token.NAME);
- appendString(str);
- }
-
- void addString(String str)
- {
- addToken(Token.STRING);
- appendString(str);
- }
-
- void addRegexp(String regexp, String flags)
- {
- addToken(Token.REGEXP);
- appendString('/' + regexp + '/' + flags);
- }
-
- void addNumber(double n)
- {
- addToken(Token.NUMBER);
-
- /* encode the number in the source stream.
- * Save as NUMBER type (char | char char char char)
- * where type is
- * 'D' - double, 'S' - short, 'J' - long.
-
- * We need to retain float vs. integer type info to keep the
- * behavior of liveconnect type-guessing the same after
- * decompilation. (Liveconnect tries to present 1.0 to Java
- * as a float/double)
- * OPT: This is no longer true. We could compress the format.
-
- * This may not be the most space-efficient encoding;
- * the chars created below may take up to 3 bytes in
- * constant pool UTF-8 encoding, so a Double could take
- * up to 12 bytes.
- */
-
- long lbits = (long)n;
- if (lbits != n) {
- // if it's floating point, save as a Double bit pattern.
- // (12/15/97 our scanner only returns Double for f.p.)
- lbits = Double.doubleToLongBits(n);
- append('D');
- append((char)(lbits >> 48));
- append((char)(lbits >> 32));
- append((char)(lbits >> 16));
- append((char)lbits);
- }
- else {
- // we can ignore negative values, bc they're already prefixed
- // by NEG
- if (lbits < 0) Kit.codeBug();
-
- // will it fit in a char?
- // this gives a short encoding for integer values up to 2^16.
- if (lbits <= Character.MAX_VALUE) {
- append('S');
- append((char)lbits);
- }
- else { // Integral, but won't fit in a char. Store as a long.
- append('J');
- append((char)(lbits >> 48));
- append((char)(lbits >> 32));
- append((char)(lbits >> 16));
- append((char)lbits);
- }
- }
- }
-
- private void appendString(String str)
- {
- int L = str.length();
- int lengthEncodingSize = 1;
- if (L >= 0x8000) {
- lengthEncodingSize = 2;
- }
- int nextTop = sourceTop + lengthEncodingSize + L;
- if (nextTop > sourceBuffer.length) {
- increaseSourceCapacity(nextTop);
- }
- if (L >= 0x8000) {
- // Use 2 chars to encode strings exceeding 32K, were the highest
- // bit in the first char indicates presence of the next byte
- sourceBuffer[sourceTop] = (char)(0x8000 | (L >>> 16));
- ++sourceTop;
- }
- sourceBuffer[sourceTop] = (char)L;
- ++sourceTop;
- str.getChars(0, L, sourceBuffer, sourceTop);
- sourceTop = nextTop;
- }
-
- private void append(char c)
- {
- if (sourceTop == sourceBuffer.length) {
- increaseSourceCapacity(sourceTop + 1);
- }
- sourceBuffer[sourceTop] = c;
- ++sourceTop;
- }
-
- private void increaseSourceCapacity(int minimalCapacity)
- {
- // Call this only when capacity increase is must
- if (minimalCapacity <= sourceBuffer.length) Kit.codeBug();
- int newCapacity = sourceBuffer.length * 2;
- if (newCapacity < minimalCapacity) {
- newCapacity = minimalCapacity;
- }
- char[] tmp = new char[newCapacity];
- System.arraycopy(sourceBuffer, 0, tmp, 0, sourceTop);
- sourceBuffer = tmp;
- }
-
- private String sourceToString(int offset)
- {
- if (offset < 0 || sourceTop < offset) Kit.codeBug();
- return new String(sourceBuffer, offset, sourceTop - offset);
- }
-
- /**
- * Decompile the source information associated with this js
- * function/script back into a string. For the most part, this
- * just means translating tokens back to their string
- * representations; there's a little bit of lookahead logic to
- * decide the proper spacing/indentation. Most of the work in
- * mapping the original source to the prettyprinted decompiled
- * version is done by the parser.
- *
- * @param source encoded source tree presentation
- *
- * @param flags flags to select output format
- *
- * @param properties indentation properties
- *
- */
- public static String decompile(String source, int flags,
- UintMap properties)
- {
- int length = source.length();
- if (length == 0) { return ""; }
-
- int indent = properties.getInt(INITIAL_INDENT_PROP, 0);
- if (indent < 0) throw new IllegalArgumentException();
- int indentGap = properties.getInt(INDENT_GAP_PROP, 4);
- if (indentGap < 0) throw new IllegalArgumentException();
- int caseGap = properties.getInt(CASE_GAP_PROP, 2);
- if (caseGap < 0) throw new IllegalArgumentException();
-
- StringBuffer result = new StringBuffer();
- boolean justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
- boolean toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG));
-
- // Spew tokens in source, for debugging.
- // as TYPE number char
- if (printSource) {
- System.err.println("length:" + length);
- for (int i = 0; i < length; ++i) {
- // Note that tokenToName will fail unless Context.printTrees
- // is true.
- String tokenname = null;
- if (Token.printNames) {
- tokenname = Token.name(source.charAt(i));
- }
- if (tokenname == null) {
- tokenname = "---";
- }
- String pad = tokenname.length() > 7
- ? "\t"
- : "\t\t";
- System.err.println
- (tokenname
- + pad + (int)source.charAt(i)
- + "\t'" + ScriptRuntime.escapeString
- (source.substring(i, i+1))
- + "'");
- }
- System.err.println();
- }
-
- int braceNesting = 0;
- boolean afterFirstEOL = false;
- int i = 0;
- int topFunctionType;
- if (source.charAt(i) == Token.SCRIPT) {
- ++i;
- topFunctionType = -1;
- } else {
- topFunctionType = source.charAt(i + 1);
- }
-
- if (!toSource) {
- // add an initial newline to exactly match js.
- result.append('\n');
- for (int j = 0; j < indent; j++)
- result.append(' ');
- } else {
- if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
- result.append('(');
- }
- }
-
- while (i < length) {
- switch(source.charAt(i)) {
- case Token.GET:
- case Token.SET:
- result.append(source.charAt(i) == Token.GET ? "get " : "set ");
- ++i;
- i = printSourceString(source, i + 1, false, result);
- // Now increment one more to get past the FUNCTION token
- ++i;
- break;
-
- case Token.NAME:
- case Token.REGEXP: // re-wrapped in '/'s in parser...
- i = printSourceString(source, i + 1, false, result);
- continue;
-
- case Token.STRING:
- i = printSourceString(source, i + 1, true, result);
- continue;
-
- case Token.NUMBER:
- i = printSourceNumber(source, i + 1, result);
- continue;
-
- case Token.TRUE:
- result.append("true");
- break;
-
- case Token.FALSE:
- result.append("false");
- break;
-
- case Token.NULL:
- result.append("null");
- break;
-
- case Token.THIS:
- result.append("this");
- break;
-
- case Token.FUNCTION:
- ++i; // skip function type
- result.append("function ");
- break;
-
- case FUNCTION_END:
- // Do nothing
- break;
-
- case Token.COMMA:
- result.append(", ");
- break;
-
- case Token.LC:
- ++braceNesting;
- if (Token.EOL == getNext(source, length, i))
- indent += indentGap;
- result.append('{');
- break;
-
- case Token.RC: {
- --braceNesting;
- /* don't print the closing RC if it closes the
- * toplevel function and we're called from
- * decompileFunctionBody.
- */
- if (justFunctionBody && braceNesting == 0)
- break;
-
- result.append('}');
- switch (getNext(source, length, i)) {
- case Token.EOL:
- case FUNCTION_END:
- indent -= indentGap;
- break;
- case Token.WHILE:
- case Token.ELSE:
- indent -= indentGap;
- result.append(' ');
- break;
- }
- break;
- }
- case Token.LP:
- result.append('(');
- break;
-
- case Token.RP:
- result.append(')');
- if (Token.LC == getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.LB:
- result.append('[');
- break;
-
- case Token.RB:
- result.append(']');
- break;
-
- case Token.EOL: {
- if (toSource) break;
- boolean newLine = true;
- if (!afterFirstEOL) {
- afterFirstEOL = true;
- if (justFunctionBody) {
- /* throw away just added 'function name(...) {'
- * and restore the original indent
- */
- result.setLength(0);
- indent -= indentGap;
- newLine = false;
- }
- }
- if (newLine) {
- result.append('\n');
- }
-
- /* add indent if any tokens remain,
- * less setback if next token is
- * a label, case or default.
- */
- if (i + 1 < length) {
- int less = 0;
- int nextToken = source.charAt(i + 1);
- if (nextToken == Token.CASE
- || nextToken == Token.DEFAULT)
- {
- less = indentGap - caseGap;
- } else if (nextToken == Token.RC) {
- less = indentGap;
- }
-
- /* elaborate check against label... skip past a
- * following inlined NAME and look for a COLON.
- */
- else if (nextToken == Token.NAME) {
- int afterName = getSourceStringEnd(source, i + 2);
- if (source.charAt(afterName) == Token.COLON)
- less = indentGap;
- }
-
- for (; less < indent; less++)
- result.append(' ');
- }
- break;
- }
- case Token.DOT:
- result.append('.');
- break;
-
- case Token.NEW:
- result.append("new ");
- break;
-
- case Token.DELPROP:
- result.append("delete ");
- break;
-
- case Token.IF:
- result.append("if ");
- break;
-
- case Token.ELSE:
- result.append("else ");
- break;
-
- case Token.FOR:
- result.append("for ");
- break;
-
- case Token.IN:
- result.append(" in ");
- break;
-
- case Token.WITH:
- result.append("with ");
- break;
-
- case Token.WHILE:
- result.append("while ");
- break;
-
- case Token.DO:
- result.append("do ");
- break;
-
- case Token.TRY:
- result.append("try ");
- break;
-
- case Token.CATCH:
- result.append("catch ");
- break;
-
- case Token.FINALLY:
- result.append("finally ");
- break;
-
- case Token.THROW:
- result.append("throw ");
- break;
-
- case Token.SWITCH:
- result.append("switch ");
- break;
-
- case Token.BREAK:
- result.append("break");
- if (Token.NAME == getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.CONTINUE:
- result.append("continue");
- if (Token.NAME == getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.CASE:
- result.append("case ");
- break;
-
- case Token.DEFAULT:
- result.append("default");
- break;
-
- case Token.RETURN:
- result.append("return");
- if (Token.SEMI != getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.VAR:
- result.append("var ");
- break;
-
- case Token.SEMI:
- result.append(';');
- if (Token.EOL != getNext(source, length, i)) {
- // separators in FOR
- result.append(' ');
- }
- break;
-
- case Token.ASSIGN:
- result.append(" = ");
- break;
-
- case Token.ASSIGN_ADD:
- result.append(" += ");
- break;
-
- case Token.ASSIGN_SUB:
- result.append(" -= ");
- break;
-
- case Token.ASSIGN_MUL:
- result.append(" *= ");
- break;
-
- case Token.ASSIGN_DIV:
- result.append(" /= ");
- break;
-
- case Token.ASSIGN_MOD:
- result.append(" %= ");
- break;
-
- case Token.ASSIGN_BITOR:
- result.append(" |= ");
- break;
-
- case Token.ASSIGN_BITXOR:
- result.append(" ^= ");
- break;
-
- case Token.ASSIGN_BITAND:
- result.append(" &= ");
- break;
-
- case Token.ASSIGN_LSH:
- result.append(" <<= ");
- break;
-
- case Token.ASSIGN_RSH:
- result.append(" >>= ");
- break;
-
- case Token.ASSIGN_URSH:
- result.append(" >>>= ");
- break;
-
- case Token.HOOK:
- result.append(" ? ");
- break;
-
- case Token.OBJECTLIT:
- // pun OBJECTLIT to mean colon in objlit property
- // initialization.
- // This needs to be distinct from COLON in the general case
- // to distinguish from the colon in a ternary... which needs
- // different spacing.
- result.append(':');
- break;
-
- case Token.COLON:
- if (Token.EOL == getNext(source, length, i))
- // it's the end of a label
- result.append(':');
- else
- // it's the middle part of a ternary
- result.append(" : ");
- break;
-
- case Token.OR:
- result.append(" || ");
- break;
-
- case Token.AND:
- result.append(" && ");
- break;
-
- case Token.BITOR:
- result.append(" | ");
- break;
-
- case Token.BITXOR:
- result.append(" ^ ");
- break;
-
- case Token.BITAND:
- result.append(" & ");
- break;
-
- case Token.SHEQ:
- result.append(" === ");
- break;
-
- case Token.SHNE:
- result.append(" !== ");
- break;
-
- case Token.EQ:
- result.append(" == ");
- break;
-
- case Token.NE:
- result.append(" != ");
- break;
-
- case Token.LE:
- result.append(" <= ");
- break;
-
- case Token.LT:
- result.append(" < ");
- break;
-
- case Token.GE:
- result.append(" >= ");
- break;
-
- case Token.GT:
- result.append(" > ");
- break;
-
- case Token.INSTANCEOF:
- result.append(" instanceof ");
- break;
-
- case Token.LSH:
- result.append(" << ");
- break;
-
- case Token.RSH:
- result.append(" >> ");
- break;
-
- case Token.URSH:
- result.append(" >>> ");
- break;
-
- case Token.TYPEOF:
- result.append("typeof ");
- break;
-
- case Token.VOID:
- result.append("void ");
- break;
-
- case Token.CONST:
- result.append("const ");
- break;
-
- case Token.NOT:
- result.append('!');
- break;
-
- case Token.BITNOT:
- result.append('~');
- break;
-
- case Token.POS:
- result.append('+');
- break;
-
- case Token.NEG:
- result.append('-');
- break;
-
- case Token.INC:
- result.append("++");
- break;
-
- case Token.DEC:
- result.append("--");
- break;
-
- case Token.ADD:
- result.append(" + ");
- break;
-
- case Token.SUB:
- result.append(" - ");
- break;
-
- case Token.MUL:
- result.append(" * ");
- break;
-
- case Token.DIV:
- result.append(" / ");
- break;
-
- case Token.MOD:
- result.append(" % ");
- break;
-
- case Token.COLONCOLON:
- result.append("::");
- break;
-
- case Token.DOTDOT:
- result.append("..");
- break;
-
- case Token.DOTQUERY:
- result.append(".(");
- break;
-
- case Token.XMLATTR:
- result.append('@');
- break;
-
- default:
- // If we don't know how to decompile it, raise an exception.
- throw new RuntimeException("Token: " +
- Token.name(source.charAt(i)));
- }
- ++i;
- }
-
- if (!toSource) {
- // add that trailing newline if it's an outermost function.
- if (!justFunctionBody)
- result.append('\n');
- } else {
- if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
- result.append(')');
- }
- }
-
- return result.toString();
- }
-
- private static int getNext(String source, int length, int i)
- {
- return (i + 1 < length) ? source.charAt(i + 1) : Token.EOF;
- }
-
- private static int getSourceStringEnd(String source, int offset)
- {
- return printSourceString(source, offset, false, null);
- }
-
- private static int printSourceString(String source, int offset,
- boolean asQuotedString,
- StringBuffer sb)
- {
- int length = source.charAt(offset);
- ++offset;
- if ((0x8000 & length) != 0) {
- length = ((0x7FFF & length) << 16) | source.charAt(offset);
- ++offset;
- }
- if (sb != null) {
- String str = source.substring(offset, offset + length);
- if (!asQuotedString) {
- sb.append(str);
- } else {
- sb.append('"');
- sb.append(ScriptRuntime.escapeString(str));
- sb.append('"');
- }
- }
- return offset + length;
- }
-
- private static int printSourceNumber(String source, int offset,
- StringBuffer sb)
- {
- double number = 0.0;
- char type = source.charAt(offset);
- ++offset;
- if (type == 'S') {
- if (sb != null) {
- int ival = source.charAt(offset);
- number = ival;
- }
- ++offset;
- } else if (type == 'J' || type == 'D') {
- if (sb != null) {
- long lbits;
- lbits = (long)source.charAt(offset) << 48;
- lbits |= (long)source.charAt(offset + 1) << 32;
- lbits |= (long)source.charAt(offset + 2) << 16;
- lbits |= source.charAt(offset + 3);
- if (type == 'J') {
- number = lbits;
- } else {
- number = Double.longBitsToDouble(lbits);
- }
- }
- offset += 4;
- } else {
- // Bad source
- throw new RuntimeException();
- }
- if (sb != null) {
- sb.append(ScriptRuntime.numberToString(number, 10));
- }
- return offset;
- }
-
- private char[] sourceBuffer = new char[128];
-
-// Per script/function source buffer top: parent source does not include a
-// nested functions source and uses function index as a reference instead.
- private int sourceTop;
-
-// whether to do a debug print of the source information, when decompiling.
- private static final boolean printSource = false;
-
-}
diff --git a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig b/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig
deleted file mode 100644
index 628bb42..0000000
--- a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig
+++ /dev/null
@@ -1,2159 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1997-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Mike Ang
- * Igor Bukanov
- * Yuh-Ruey Chen
- * Ethan Hugg
- * Bob Jervis
- * Terry Lucas
- * Mike McCabe
- * Milen Nankov
- *
- * Alternatively, the contents of this file may be used under the terms of
- * the GNU General Public License Version 2 or later (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of those above. If
- * you wish to allow use of your version of this file only under the terms of
- * the GPL and not to allow others to use your version of this file under the
- * MPL, indicate your decision by deleting the provisions above and replacing
- * them with the notice and other provisions required by the GPL. If you do
- * not delete the provisions above, a recipient may use your version of this
- * file under either the MPL or the GPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-import java.io.Reader;
-import java.io.IOException;
-import java.util.Hashtable;
-
-/**
- * This class implements the JavaScript parser.
- *
- * It is based on the C source files jsparse.c and jsparse.h
- * in the jsref package.
- *
- * @see TokenStream
- *
- * @author Mike McCabe
- * @author Brendan Eich
- */
-
-public class Parser
-{
- // TokenInformation flags : currentFlaggedToken stores them together
- // with token type
- final static int
- CLEAR_TI_MASK = 0xFFFF, // mask to clear token information bits
- TI_AFTER_EOL = 1 << 16, // first token of the source line
- TI_CHECK_LABEL = 1 << 17; // indicates to check for label
-
- CompilerEnvirons compilerEnv;
- private ErrorReporter errorReporter;
- private String sourceURI;
- boolean calledByCompileFunction;
-
- private TokenStream ts;
- private int currentFlaggedToken;
- private int syntaxErrorCount;
-
- private IRFactory nf;
-
- private int nestingOfFunction;
-
- private Decompiler decompiler;
- private String encodedSource;
-
-// The following are per function variables and should be saved/restored
-// during function parsing.
-// XXX Move to separated class?
- ScriptOrFnNode currentScriptOrFn;
- private int nestingOfWith;
- private Hashtable labelSet; // map of label names into nodes
- private ObjArray loopSet;
- private ObjArray loopAndSwitchSet;
- private boolean hasReturnValue;
- private int functionEndFlags;
-// end of per function variables
-
- // Exception to unwind
- private static class ParserException extends RuntimeException
- {
- static final long serialVersionUID = 5882582646773765630L;
- }
-
- public Parser(CompilerEnvirons compilerEnv, ErrorReporter errorReporter)
- {
- this.compilerEnv = compilerEnv;
- this.errorReporter = errorReporter;
- }
-
- protected Decompiler createDecompiler(CompilerEnvirons compilerEnv)
- {
- return new Decompiler();
- }
-
- void addStrictWarning(String messageId, String messageArg)
- {
- if (compilerEnv.isStrictMode())
- addWarning(messageId, messageArg);
- }
-
- void addWarning(String messageId, String messageArg)
- {
- String message = ScriptRuntime.getMessage1(messageId, messageArg);
- if (compilerEnv.reportWarningAsError()) {
- ++syntaxErrorCount;
- errorReporter.error(message, sourceURI, ts.getLineno(),
- ts.getLine(), ts.getOffset());
- } else
- errorReporter.warning(message, sourceURI, ts.getLineno(),
- ts.getLine(), ts.getOffset());
- }
-
- void addError(String messageId)
- {
- ++syntaxErrorCount;
- String message = ScriptRuntime.getMessage0(messageId);
- errorReporter.error(message, sourceURI, ts.getLineno(),
- ts.getLine(), ts.getOffset());
- }
-
- void addError(String messageId, String messageArg)
- {
- ++syntaxErrorCount;
- String message = ScriptRuntime.getMessage1(messageId, messageArg);
- errorReporter.error(message, sourceURI, ts.getLineno(),
- ts.getLine(), ts.getOffset());
- }
-
- RuntimeException reportError(String messageId)
- {
- addError(messageId);
-
- // Throw a ParserException exception to unwind the recursive descent
- // parse.
- throw new ParserException();
- }
-
- private int peekToken()
- throws IOException
- {
- int tt = currentFlaggedToken;
- if (tt == Token.EOF) {
- tt = ts.getToken();
- if (tt == Token.EOL) {
- do {
- tt = ts.getToken();
- } while (tt == Token.EOL);
- tt |= TI_AFTER_EOL;
- }
- currentFlaggedToken = tt;
- }
- return tt & CLEAR_TI_MASK;
- }
-
- private int peekFlaggedToken()
- throws IOException
- {
- peekToken();
- return currentFlaggedToken;
- }
-
- private void consumeToken()
- {
- currentFlaggedToken = Token.EOF;
- }
-
- private int nextToken()
- throws IOException
- {
- int tt = peekToken();
- consumeToken();
- return tt;
- }
-
- private int nextFlaggedToken()
- throws IOException
- {
- peekToken();
- int ttFlagged = currentFlaggedToken;
- consumeToken();
- return ttFlagged;
- }
-
- private boolean matchToken(int toMatch)
- throws IOException
- {
- int tt = peekToken();
- if (tt != toMatch) {
- return false;
- }
- consumeToken();
- return true;
- }
-
- private int peekTokenOrEOL()
- throws IOException
- {
- int tt = peekToken();
- // Check for last peeked token flags
- if ((currentFlaggedToken & TI_AFTER_EOL) != 0) {
- tt = Token.EOL;
- }
- return tt;
- }
-
- private void setCheckForLabel()
- {
- if ((currentFlaggedToken & CLEAR_TI_MASK) != Token.NAME)
- throw Kit.codeBug();
- currentFlaggedToken |= TI_CHECK_LABEL;
- }
-
- private void mustMatchToken(int toMatch, String messageId)
- throws IOException, ParserException
- {
- if (!matchToken(toMatch)) {
- reportError(messageId);
- }
- }
-
- private void mustHaveXML()
- {
- if (!compilerEnv.isXmlAvailable()) {
- reportError("msg.XML.not.available");
- }
- }
-
- public String getEncodedSource()
- {
- return encodedSource;
- }
-
- public boolean eof()
- {
- return ts.eof();
- }
-
- boolean insideFunction()
- {
- return nestingOfFunction != 0;
- }
-
- private Node enterLoop(Node loopLabel)
- {
- Node loop = nf.createLoopNode(loopLabel, ts.getLineno());
- if (loopSet == null) {
- loopSet = new ObjArray();
- if (loopAndSwitchSet == null) {
- loopAndSwitchSet = new ObjArray();
- }
- }
- loopSet.push(loop);
- loopAndSwitchSet.push(loop);
- return loop;
- }
-
- private void exitLoop()
- {
- loopSet.pop();
- loopAndSwitchSet.pop();
- }
-
- private Node enterSwitch(Node switchSelector, int lineno)
- {
- Node switchNode = nf.createSwitch(switchSelector, lineno);
- if (loopAndSwitchSet == null) {
- loopAndSwitchSet = new ObjArray();
- }
- loopAndSwitchSet.push(switchNode);
- return switchNode;
- }
-
- private void exitSwitch()
- {
- loopAndSwitchSet.pop();
- }
-
- /*
- * Build a parse tree from the given sourceString.
- *
- * @return an Object representing the parsed
- * program. If the parse fails, null will be returned. (The
- * parse failure will result in a call to the ErrorReporter from
- * CompilerEnvirons.)
- */
- public ScriptOrFnNode parse(String sourceString,
- String sourceURI, int lineno)
- {
- this.sourceURI = sourceURI;
- this.ts = new TokenStream(this, null, sourceString, lineno);
- try {
- return parse();
- } catch (IOException ex) {
- // Should never happen
- throw new IllegalStateException();
- }
- }
-
- /*
- * Build a parse tree from the given sourceString.
- *
- * @return an Object representing the parsed
- * program. If the parse fails, null will be returned. (The
- * parse failure will result in a call to the ErrorReporter from
- * CompilerEnvirons.)
- */
- public ScriptOrFnNode parse(Reader sourceReader,
- String sourceURI, int lineno)
- throws IOException
- {
- this.sourceURI = sourceURI;
- this.ts = new TokenStream(this, sourceReader, null, lineno);
- return parse();
- }
-
- private ScriptOrFnNode parse()
- throws IOException
- {
- this.decompiler = createDecompiler(compilerEnv);
- this.nf = new IRFactory(this);
- currentScriptOrFn = nf.createScript();
- int sourceStartOffset = decompiler.getCurrentOffset();
- this.encodedSource = null;
- decompiler.addToken(Token.SCRIPT);
-
- this.currentFlaggedToken = Token.EOF;
- this.syntaxErrorCount = 0;
-
- int baseLineno = ts.getLineno(); // line number where source starts
-
- /* so we have something to add nodes to until
- * we've collected all the source */
- Node pn = nf.createLeaf(Token.BLOCK);
-
- try {
- for (;;) {
- int tt = peekToken();
-
- if (tt <= Token.EOF) {
- break;
- }
-
- Node n;
- if (tt == Token.FUNCTION) {
- consumeToken();
- try {
- n = function(calledByCompileFunction
- ? FunctionNode.FUNCTION_EXPRESSION
- : FunctionNode.FUNCTION_STATEMENT);
- } catch (ParserException e) {
- break;
- }
- } else {
- n = statement();
- }
- nf.addChildToBack(pn, n);
- }
- } catch (StackOverflowError ex) {
- String msg = ScriptRuntime.getMessage0(
- "msg.too.deep.parser.recursion");
- throw Context.reportRuntimeError(msg, sourceURI,
- ts.getLineno(), null, 0);
- }
-
- if (this.syntaxErrorCount != 0) {
- String msg = String.valueOf(this.syntaxErrorCount);
- msg = ScriptRuntime.getMessage1("msg.got.syntax.errors", msg);
- throw errorReporter.runtimeError(msg, sourceURI, baseLineno,
- null, 0);
- }
-
- currentScriptOrFn.setSourceName(sourceURI);
- currentScriptOrFn.setBaseLineno(baseLineno);
- currentScriptOrFn.setEndLineno(ts.getLineno());
-
- int sourceEndOffset = decompiler.getCurrentOffset();
- currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset,
- sourceEndOffset);
-
- nf.initScript(currentScriptOrFn, pn);
-
- if (compilerEnv.isGeneratingSource()) {
- encodedSource = decompiler.getEncodedSource();
- }
- this.decompiler = null; // It helps GC
-
- return currentScriptOrFn;
- }
-
- /*
- * The C version of this function takes an argument list,
- * which doesn't seem to be needed for tree generation...
- * it'd only be useful for checking argument hiding, which
- * I'm not doing anyway...
- */
- private Node parseFunctionBody()
- throws IOException
- {
- ++nestingOfFunction;
- Node pn = nf.createBlock(ts.getLineno());
- try {
- bodyLoop: for (;;) {
- Node n;
- int tt = peekToken();
- switch (tt) {
- case Token.ERROR:
- case Token.EOF:
- case Token.RC:
- break bodyLoop;
-
- case Token.FUNCTION:
- consumeToken();
- n = function(FunctionNode.FUNCTION_STATEMENT);
- break;
- default:
- n = statement();
- break;
- }
- nf.addChildToBack(pn, n);
- }
- } catch (ParserException e) {
- // Ignore it
- } finally {
- --nestingOfFunction;
- }
-
- return pn;
- }
-
- private Node function(int functionType)
- throws IOException, ParserException
- {
- int syntheticType = functionType;
- int baseLineno = ts.getLineno(); // line number where source starts
-
- int functionSourceStart = decompiler.markFunctionStart(functionType);
- String name;
- Node memberExprNode = null;
- if (matchToken(Token.NAME)) {
- name = ts.getString();
- decompiler.addName(name);
- if (!matchToken(Token.LP)) {
- if (compilerEnv.isAllowMemberExprAsFunctionName()) {
- // Extension to ECMA: if 'function <name>' does not follow
- // by '(', assume <name> starts memberExpr
- Node memberExprHead = nf.createName(name);
- name = "";
- memberExprNode = memberExprTail(false, memberExprHead);
- }
- mustMatchToken(Token.LP, "msg.no.paren.parms");
- }
- } else if (matchToken(Token.LP)) {
- // Anonymous function
- name = "";
- } else {
- name = "";
- if (compilerEnv.isAllowMemberExprAsFunctionName()) {
- // Note that memberExpr can not start with '(' like
- // in function (1+2).toString(), because 'function (' already
- // processed as anonymous function
- memberExprNode = memberExpr(false);
- }
- mustMatchToken(Token.LP, "msg.no.paren.parms");
- }
-
- if (memberExprNode != null) {
- syntheticType = FunctionNode.FUNCTION_EXPRESSION;
- }
-
- boolean nested = insideFunction();
-
- FunctionNode fnNode = nf.createFunction(name);
- if (nested || nestingOfWith > 0) {
- // 1. Nested functions are not affected by the dynamic scope flag
- // as dynamic scope is already a parent of their scope.
- // 2. Functions defined under the with statement also immune to
- // this setup, in which case dynamic scope is ignored in favor
- // of with object.
- fnNode.itsIgnoreDynamicScope = true;
- }
-
- int functionIndex = currentScriptOrFn.addFunction(fnNode);
-
- int functionSourceEnd;
-
- ScriptOrFnNode savedScriptOrFn = currentScriptOrFn;
- currentScriptOrFn = fnNode;
- int savedNestingOfWith = nestingOfWith;
- nestingOfWith = 0;
- Hashtable savedLabelSet = labelSet;
- labelSet = null;
- ObjArray savedLoopSet = loopSet;
- loopSet = null;
- ObjArray savedLoopAndSwitchSet = loopAndSwitchSet;
- loopAndSwitchSet = null;
- boolean savedHasReturnValue = hasReturnValue;
- int savedFunctionEndFlags = functionEndFlags;
-
- Node body;
- try {
- decompiler.addToken(Token.LP);
- if (!matchToken(Token.RP)) {
- boolean first = true;
- do {
- if (!first)
- decompiler.addToken(Token.COMMA);
- first = false;
- mustMatchToken(Token.NAME, "msg.no.parm");
- String s = ts.getString();
- if (fnNode.hasParamOrVar(s)) {
- addWarning("msg.dup.parms", s);
- }
- fnNode.addParam(s);
- decompiler.addName(s);
- } while (matchToken(Token.COMMA));
-
- mustMatchToken(Token.RP, "msg.no.paren.after.parms");
- }
- decompiler.addToken(Token.RP);
-
- mustMatchToken(Token.LC, "msg.no.brace.body");
- decompiler.addEOL(Token.LC);
- body = parseFunctionBody();
- mustMatchToken(Token.RC, "msg.no.brace.after.body");
-
- if (compilerEnv.isStrictMode() && !body.hasConsistentReturnUsage())
- {
- String msg = name.length() > 0 ? "msg.no.return.value"
- : "msg.anon.no.return.value";
- addStrictWarning(msg, name);
- }
-
- decompiler.addToken(Token.RC);
- functionSourceEnd = decompiler.markFunctionEnd(functionSourceStart);
- if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
- // Add EOL only if function is not part of expression
- // since it gets SEMI + EOL from Statement in that case
- decompiler.addToken(Token.EOL);
- }
- }
- finally {
- hasReturnValue = savedHasReturnValue;
- functionEndFlags = savedFunctionEndFlags;
- loopAndSwitchSet = savedLoopAndSwitchSet;
- loopSet = savedLoopSet;
- labelSet = savedLabelSet;
- nestingOfWith = savedNestingOfWith;
- currentScriptOrFn = savedScriptOrFn;
- }
-
- fnNode.setEncodedSourceBounds(functionSourceStart, functionSourceEnd);
- fnNode.setSourceName(sourceURI);
- fnNode.setBaseLineno(baseLineno);
- fnNode.setEndLineno(ts.getLineno());
-
- if (name != null) {
- int index = currentScriptOrFn.getParamOrVarIndex(name);
- if (index >= 0 && index < currentScriptOrFn.getParamCount())
- addStrictWarning("msg.var.hides.arg", name);
- }
-
- Node pn = nf.initFunction(fnNode, functionIndex, body, syntheticType);
- if (memberExprNode != null) {
- pn = nf.createAssignment(Token.ASSIGN, memberExprNode, pn);
- if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
- // XXX check JScript behavior: should it be createExprStatement?
- pn = nf.createExprStatementNoReturn(pn, baseLineno);
- }
- }
- return pn;
- }
-
- private Node statements()
- throws IOException
- {
- Node pn = nf.createBlock(ts.getLineno());
-
- int tt;
- while((tt = peekToken()) > Token.EOF && tt != Token.RC) {
- nf.addChildToBack(pn, statement());
- }
-
- return pn;
- }
-
- private Node condition()
- throws IOException, ParserException
- {
- mustMatchToken(Token.LP, "msg.no.paren.cond");
- decompiler.addToken(Token.LP);
- Node pn = expr(false);
- mustMatchToken(Token.RP, "msg.no.paren.after.cond");
- decompiler.addToken(Token.RP);
-
- // Report strict warning on code like "if (a = 7) ...". Suppress the
- // warning if the condition is parenthesized, like "if ((a = 7)) ...".
- if (pn.getProp(Node.PARENTHESIZED_PROP) == null &&
- (pn.getType() == Token.SETNAME || pn.getType() == Token.SETPROP ||
- pn.getType() == Token.SETELEM))
- {
- addStrictWarning("msg.equal.as.assign", "");
- }
- return pn;
- }
-
- // match a NAME; return null if no match.
- private Node matchJumpLabelName()
- throws IOException, ParserException
- {
- Node label = null;
-
- int tt = peekTokenOrEOL();
- if (tt == Token.NAME) {
- consumeToken();
- String name = ts.getString();
- decompiler.addName(name);
- if (labelSet != null) {
- label = (Node)labelSet.get(name);
- }
- if (label == null) {
- reportError("msg.undef.label");
- }
- }
-
- return label;
- }
-
- private Node statement()
- throws IOException
- {
- try {
- Node pn = statementHelper(null);
- if (pn != null) {
- if (compilerEnv.isStrictMode() && !pn.hasSideEffects())
- addStrictWarning("msg.no.side.effects", "");
- return pn;
- }
- } catch (ParserException e) { }
-
- // skip to end of statement
- int lineno = ts.getLineno();
- guessingStatementEnd: for (;;) {
- int tt = peekTokenOrEOL();
- consumeToken();
- switch (tt) {
- case Token.ERROR:
- case Token.EOF:
- case Token.EOL:
- case Token.SEMI:
- break guessingStatementEnd;
- }
- }
- return nf.createExprStatement(nf.createName("error"), lineno);
- }
-
- /**
- * Whether the "catch (e: e instanceof Exception) { ... }" syntax
- * is implemented.
- */
-
- private Node statementHelper(Node statementLabel)
- throws IOException, ParserException
- {
- Node pn = null;
-
- int tt;
-
- tt = peekToken();
-
- switch(tt) {
- case Token.IF: {
- consumeToken();
-
- decompiler.addToken(Token.IF);
- int lineno = ts.getLineno();
- Node cond = condition();
- decompiler.addEOL(Token.LC);
- Node ifTrue = statement();
- Node ifFalse = null;
- if (matchToken(Token.ELSE)) {
- decompiler.addToken(Token.RC);
- decompiler.addToken(Token.ELSE);
- decompiler.addEOL(Token.LC);
- ifFalse = statement();
- }
- decompiler.addEOL(Token.RC);
- pn = nf.createIf(cond, ifTrue, ifFalse, lineno);
- return pn;
- }
-
- case Token.SWITCH: {
- consumeToken();
-
- decompiler.addToken(Token.SWITCH);
- int lineno = ts.getLineno();
- mustMatchToken(Token.LP, "msg.no.paren.switch");
- decompiler.addToken(Token.LP);
- pn = enterSwitch(expr(false), lineno);
- try {
- mustMatchToken(Token.RP, "msg.no.paren.after.switch");
- decompiler.addToken(Token.RP);
- mustMatchToken(Token.LC, "msg.no.brace.switch");
- decompiler.addEOL(Token.LC);
-
- boolean hasDefault = false;
- switchLoop: for (;;) {
- tt = nextToken();
- Node caseExpression;
- switch (tt) {
- case Token.RC:
- break switchLoop;
-
- case Token.CASE:
- decompiler.addToken(Token.CASE);
- caseExpression = expr(false);
- mustMatchToken(Token.COLON, "msg.no.colon.case");
- decompiler.addEOL(Token.COLON);
- break;
-
- case Token.DEFAULT:
- if (hasDefault) {
- reportError("msg.double.switch.default");
- }
- decompiler.addToken(Token.DEFAULT);
- hasDefault = true;
- caseExpression = null;
- mustMatchToken(Token.COLON, "msg.no.colon.case");
- decompiler.addEOL(Token.COLON);
- break;
-
- default:
- reportError("msg.bad.switch");
- break switchLoop;
- }
-
- Node block = nf.createLeaf(Token.BLOCK);
- while ((tt = peekToken()) != Token.RC
- && tt != Token.CASE
- && tt != Token.DEFAULT
- && tt != Token.EOF)
- {
- nf.addChildToBack(block, statement());
- }
-
- // caseExpression == null => add default lable
- nf.addSwitchCase(pn, caseExpression, block);
- }
- decompiler.addEOL(Token.RC);
- nf.closeSwitch(pn);
- } finally {
- exitSwitch();
- }
- return pn;
- }
-
- case Token.WHILE: {
- consumeToken();
- decompiler.addToken(Token.WHILE);
-
- Node loop = enterLoop(statementLabel);
- try {
- Node cond = condition();
- decompiler.addEOL(Token.LC);
- Node body = statement();
- decompiler.addEOL(Token.RC);
- pn = nf.createWhile(loop, cond, body);
- } finally {
- exitLoop();
- }
- return pn;
- }
-
- case Token.DO: {
- consumeToken();
- decompiler.addToken(Token.DO);
- decompiler.addEOL(Token.LC);
-
- Node loop = enterLoop(statementLabel);
- try {
- Node body = statement();
- decompiler.addToken(Token.RC);
- mustMatchToken(Token.WHILE, "msg.no.while.do");
- decompiler.addToken(Token.WHILE);
- Node cond = condition();
- pn = nf.createDoWhile(loop, body, cond);
- } finally {
- exitLoop();
- }
- // Always auto-insert semicon to follow SpiderMonkey:
- // It is required by EMAScript but is ignored by the rest of
- // world, see bug 238945
- matchToken(Token.SEMI);
- decompiler.addEOL(Token.SEMI);
- return pn;
- }
-
- case Token.FOR: {
- consumeToken();
- boolean isForEach = false;
- decompiler.addToken(Token.FOR);
-
- Node loop = enterLoop(statementLabel);
- try {
-
- Node init; // Node init is also foo in 'foo in Object'
- Node cond; // Node cond is also object in 'foo in Object'
- Node incr = null; // to kill warning
- Node body;
-
- // See if this is a for each () instead of just a for ()
- if (matchToken(Token.NAME)) {
- decompiler.addName(ts.getString());
- if (ts.getString().equals("each")) {
- isForEach = true;
- } else {
- reportError("msg.no.paren.for");
- }
- }
-
- mustMatchToken(Token.LP, "msg.no.paren.for");
- decompiler.addToken(Token.LP);
- tt = peekToken();
- if (tt == Token.SEMI) {
- init = nf.createLeaf(Token.EMPTY);
- } else {
- if (tt == Token.VAR) {
- // set init to a var list or initial
- consumeToken(); // consume the 'var' token
- init = variables(Token.FOR);
- }
- else {
- init = expr(true);
- }
- }
-
- if (matchToken(Token.IN)) {
- decompiler.addToken(Token.IN);
- // 'cond' is the object over which we're iterating
- cond = expr(false);
- } else { // ordinary for loop
- mustMatchToken(Token.SEMI, "msg.no.semi.for");
- decompiler.addToken(Token.SEMI);
- if (peekToken() == Token.SEMI) {
- // no loop condition
- cond = nf.createLeaf(Token.EMPTY);
- } else {
- cond = expr(false);
- }
-
- mustMatchToken(Token.SEMI, "msg.no.semi.for.cond");
- decompiler.addToken(Token.SEMI);
- if (peekToken() == Token.RP) {
- incr = nf.createLeaf(Token.EMPTY);
- } else {
- incr = expr(false);
- }
- }
-
- mustMatchToken(Token.RP, "msg.no.paren.for.ctrl");
- decompiler.addToken(Token.RP);
- decompiler.addEOL(Token.LC);
- body = statement();
- decompiler.addEOL(Token.RC);
-
- if (incr == null) {
- // cond could be null if 'in obj' got eaten
- // by the init node.
- pn = nf.createForIn(loop, init, cond, body, isForEach);
- } else {
- pn = nf.createFor(loop, init, cond, incr, body);
- }
- } finally {
- exitLoop();
- }
- return pn;
- }
-
- case Token.TRY: {
- consumeToken();
- int lineno = ts.getLineno();
-
- Node tryblock;
- Node catchblocks = null;
- Node finallyblock = null;
-
- decompiler.addToken(Token.TRY);
- decompiler.addEOL(Token.LC);
- tryblock = statement();
- decompiler.addEOL(Token.RC);
-
- catchblocks = nf.createLeaf(Token.BLOCK);
-
- boolean sawDefaultCatch = false;
- int peek = peekToken();
- if (peek == Token.CATCH) {
- while (matchToken(Token.CATCH)) {
- if (sawDefaultCatch) {
- reportError("msg.catch.unreachable");
- }
- decompiler.addToken(Token.CATCH);
- mustMatchToken(Token.LP, "msg.no.paren.catch");
- decompiler.addToken(Token.LP);
-
- mustMatchToken(Token.NAME, "msg.bad.catchcond");
- String varName = ts.getString();
- decompiler.addName(varName);
-
- Node catchCond = null;
- if (matchToken(Token.IF)) {
- decompiler.addToken(Token.IF);
- catchCond = expr(false);
- } else {
- sawDefaultCatch = true;
- }
-
- mustMatchToken(Token.RP, "msg.bad.catchcond");
- decompiler.addToken(Token.RP);
- mustMatchToken(Token.LC, "msg.no.brace.catchblock");
- decompiler.addEOL(Token.LC);
-
- nf.addChildToBack(catchblocks,
- nf.createCatch(varName, catchCond,
- statements(),
- ts.getLineno()));
-
- mustMatchToken(Token.RC, "msg.no.brace.after.body");
- decompiler.addEOL(Token.RC);
- }
- } else if (peek != Token.FINALLY) {
- mustMatchToken(Token.FINALLY, "msg.try.no.catchfinally");
- }
-
- if (matchToken(Token.FINALLY)) {
- decompiler.addToken(Token.FINALLY);
- decompiler.addEOL(Token.LC);
- finallyblock = statement();
- decompiler.addEOL(Token.RC);
- }
-
- pn = nf.createTryCatchFinally(tryblock, catchblocks,
- finallyblock, lineno);
-
- return pn;
- }
-
- case Token.THROW: {
- consumeToken();
- if (peekTokenOrEOL() == Token.EOL) {
- // ECMAScript does not allow new lines before throw expression,
- // see bug 256617
- reportError("msg.bad.throw.eol");
- }
-
- int lineno = ts.getLineno();
- decompiler.addToken(Token.THROW);
- pn = nf.createThrow(expr(false), lineno);
- break;
- }
-
- case Token.BREAK: {
- consumeToken();
- int lineno = ts.getLineno();
-
- decompiler.addToken(Token.BREAK);
-
- // matchJumpLabelName only matches if there is one
- Node breakStatement = matchJumpLabelName();
- if (breakStatement == null) {
- if (loopAndSwitchSet == null || loopAndSwitchSet.size() == 0) {
- reportError("msg.bad.break");
- return null;
- }
- breakStatement = (Node)loopAndSwitchSet.peek();
- }
- pn = nf.createBreak(breakStatement, lineno);
- break;
- }
-
- case Token.CONTINUE: {
- consumeToken();
- int lineno = ts.getLineno();
-
- decompiler.addToken(Token.CONTINUE);
-
- Node loop;
- // matchJumpLabelName only matches if there is one
- Node label = matchJumpLabelName();
- if (label == null) {
- if (loopSet == null || loopSet.size() == 0) {
- reportError("msg.continue.outside");
- return null;
- }
- loop = (Node)loopSet.peek();
- } else {
- loop = nf.getLabelLoop(label);
- if (loop == null) {
- reportError("msg.continue.nonloop");
- return null;
- }
- }
- pn = nf.createContinue(loop, lineno);
- break;
- }
-
- case Token.WITH: {
- consumeToken();
-
- decompiler.addToken(Token.WITH);
- int lineno = ts.getLineno();
- mustMatchToken(Token.LP, "msg.no.paren.with");
- decompiler.addToken(Token.LP);
- Node obj = expr(false);
- mustMatchToken(Token.RP, "msg.no.paren.after.with");
- decompiler.addToken(Token.RP);
- decompiler.addEOL(Token.LC);
-
- ++nestingOfWith;
- Node body;
- try {
- body = statement();
- } finally {
- --nestingOfWith;
- }
-
- decompiler.addEOL(Token.RC);
-
- pn = nf.createWith(obj, body, lineno);
- return pn;
- }
-
- case Token.CONST:
- case Token.VAR: {
- consumeToken();
- pn = variables(tt);
- break;
- }
-
- case Token.RETURN: {
- if (!insideFunction()) {
- reportError("msg.bad.return");
- }
- consumeToken();
- decompiler.addToken(Token.RETURN);
- int lineno = ts.getLineno();
-
- Node retExpr;
- /* This is ugly, but we don't want to require a semicolon. */
- tt = peekTokenOrEOL();
- switch (tt) {
- case Token.SEMI:
- case Token.RC:
- case Token.EOF:
- case Token.EOL:
- case Token.ERROR:
- retExpr = null;
- break;
- default:
- retExpr = expr(false);
- hasReturnValue = true;
- }
- pn = nf.createReturn(retExpr, lineno);
-
- // see if we need a strict mode warning
- if (retExpr == null) {
- if (functionEndFlags == Node.END_RETURNS_VALUE)
- addStrictWarning("msg.return.inconsistent", "");
-
- functionEndFlags |= Node.END_RETURNS;
- } else {
- if (functionEndFlags == Node.END_RETURNS)
- addStrictWarning("msg.return.inconsistent", "");
-
- functionEndFlags |= Node.END_RETURNS_VALUE;
- }
-
- break;
- }
-
- case Token.LC:
- consumeToken();
- if (statementLabel != null) {
- decompiler.addToken(Token.LC);
- }
- pn = statements();
- mustMatchToken(Token.RC, "msg.no.brace.block");
- if (statementLabel != null) {
- decompiler.addEOL(Token.RC);
- }
- return pn;
-
- case Token.ERROR:
- // Fall thru, to have a node for error recovery to work on
- case Token.SEMI:
- consumeToken();
- pn = nf.createLeaf(Token.EMPTY);
- return pn;
-
- case Token.FUNCTION: {
- consumeToken();
- pn = function(FunctionNode.FUNCTION_EXPRESSION_STATEMENT);
- return pn;
- }
-
- case Token.DEFAULT :
- consumeToken();
- mustHaveXML();
-
- decompiler.addToken(Token.DEFAULT);
- int nsLine = ts.getLineno();
-
- if (!(matchToken(Token.NAME)
- && ts.getString().equals("xml")))
- {
- reportError("msg.bad.namespace");
- }
- decompiler.addName(" xml");
-
- if (!(matchToken(Token.NAME)
- && ts.getString().equals("namespace")))
- {
- reportError("msg.bad.namespace");
- }
- decompiler.addName(" namespace");
-
- if (!matchToken(Token.ASSIGN)) {
- reportError("msg.bad.namespace");
- }
- decompiler.addToken(Token.ASSIGN);
-
- Node expr = expr(false);
- pn = nf.createDefaultNamespace(expr, nsLine);
- break;
-
- case Token.NAME: {
- int lineno = ts.getLineno();
- String name = ts.getString();
- setCheckForLabel();
- pn = expr(false);
- if (pn.getType() != Token.LABEL) {
- pn = nf.createExprStatement(pn, lineno);
- } else {
- // Parsed the label: push back token should be
- // colon that primaryExpr left untouched.
- if (peekToken() != Token.COLON) Kit.codeBug();
- consumeToken();
- // depend on decompiling lookahead to guess that that
- // last name was a label.
- decompiler.addName(name);
- decompiler.addEOL(Token.COLON);
-
- if (labelSet == null) {
- labelSet = new Hashtable();
- } else if (labelSet.containsKey(name)) {
- reportError("msg.dup.label");
- }
-
- boolean firstLabel;
- if (statementLabel == null) {
- firstLabel = true;
- statementLabel = pn;
- } else {
- // Discard multiple label nodes and use only
- // the first: it allows to simplify IRFactory
- firstLabel = false;
- }
- labelSet.put(name, statementLabel);
- try {
- pn = statementHelper(statementLabel);
- } finally {
- labelSet.remove(name);
- }
- if (firstLabel) {
- pn = nf.createLabeledStatement(statementLabel, pn);
- }
- return pn;
- }
- break;
- }
-
- default: {
- int lineno = ts.getLineno();
- pn = expr(false);
- pn = nf.createExprStatement(pn, lineno);
- break;
- }
- }
-
- int ttFlagged = peekFlaggedToken();
- switch (ttFlagged & CLEAR_TI_MASK) {
- case Token.SEMI:
- // Consume ';' as a part of expression
- consumeToken();
- break;
- case Token.ERROR:
- case Token.EOF:
- case Token.RC:
- // Autoinsert ;
- break;
- default:
- if ((ttFlagged & TI_AFTER_EOL) == 0) {
- // Report error if no EOL or autoinsert ; otherwise
- reportError("msg.no.semi.stmt");
- }
- break;
- }
- decompiler.addEOL(Token.SEMI);
-
- return pn;
- }
-
- /**
- * Parse a 'var' or 'const' statement, or a 'var' init list in a for
- * statement.
- * @param context A token value: either VAR, CONST or FOR depending on
- * context.
- * @return The parsed statement
- * @throws IOException
- * @throws ParserException
- */
- private Node variables(int context)
- throws IOException, ParserException
- {
- Node pn;
- boolean first = true;
-
- if (context == Token.CONST){
- pn = nf.createVariables(Token.CONST, ts.getLineno());
- decompiler.addToken(Token.CONST);
- } else {
- pn = nf.createVariables(Token.VAR, ts.getLineno());
- decompiler.addToken(Token.VAR);
- }
-
- for (;;) {
- Node name;
- Node init;
- mustMatchToken(Token.NAME, "msg.bad.var");
- String s = ts.getString();
-
- if (!first)
- decompiler.addToken(Token.COMMA);
- first = false;
-
- decompiler.addName(s);
-
- if (context == Token.CONST) {
- if (!currentScriptOrFn.addConst(s)) {
- // We know it's already defined, since addConst passes if
- // it's not defined at all. The addVar call just confirms
- // what it is.
- if (currentScriptOrFn.addVar(s) != ScriptOrFnNode.DUPLICATE_CONST)
- addError("msg.var.redecl", s);
- else
- addError("msg.const.redecl", s);
- }
- } else {
- int dupState = currentScriptOrFn.addVar(s);
- if (dupState == ScriptOrFnNode.DUPLICATE_CONST)
- addError("msg.const.redecl", s);
- else if (dupState == ScriptOrFnNode.DUPLICATE_PARAMETER)
- addStrictWarning("msg.var.hides.arg", s);
- else if (dupState == ScriptOrFnNode.DUPLICATE_VAR)
- addStrictWarning("msg.var.redecl", s);
- }
- name = nf.createName(s);
-
- // omitted check for argument hiding
-
- if (matchToken(Token.ASSIGN)) {
- decompiler.addToken(Token.ASSIGN);
-
- init = assignExpr(context == Token.FOR);
- nf.addChildToBack(name, init);
- }
- nf.addChildToBack(pn, name);
- if (!matchToken(Token.COMMA))
- break;
- }
- return pn;
- }
-
- private Node expr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = assignExpr(inForInit);
- while (matchToken(Token.COMMA)) {
- decompiler.addToken(Token.COMMA);
- if (compilerEnv.isStrictMode() && !pn.hasSideEffects())
- addStrictWarning("msg.no.side.effects", "");
- pn = nf.createBinary(Token.COMMA, pn, assignExpr(inForInit));
- }
- return pn;
- }
-
- private Node assignExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = condExpr(inForInit);
-
- int tt = peekToken();
- if (Token.FIRST_ASSIGN <= tt && tt <= Token.LAST_ASSIGN) {
- consumeToken();
- decompiler.addToken(tt);
- pn = nf.createAssignment(tt, pn, assignExpr(inForInit));
- }
-
- return pn;
- }
-
- private Node condExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = orExpr(inForInit);
-
- if (matchToken(Token.HOOK)) {
- decompiler.addToken(Token.HOOK);
- Node ifTrue = assignExpr(false);
- mustMatchToken(Token.COLON, "msg.no.colon.cond");
- decompiler.addToken(Token.COLON);
- Node ifFalse = assignExpr(inForInit);
- return nf.createCondExpr(pn, ifTrue, ifFalse);
- }
-
- return pn;
- }
-
- private Node orExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = andExpr(inForInit);
- if (matchToken(Token.OR)) {
- decompiler.addToken(Token.OR);
- pn = nf.createBinary(Token.OR, pn, orExpr(inForInit));
- }
-
- return pn;
- }
-
- private Node andExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = bitOrExpr(inForInit);
- if (matchToken(Token.AND)) {
- decompiler.addToken(Token.AND);
- pn = nf.createBinary(Token.AND, pn, andExpr(inForInit));
- }
-
- return pn;
- }
-
- private Node bitOrExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = bitXorExpr(inForInit);
- while (matchToken(Token.BITOR)) {
- decompiler.addToken(Token.BITOR);
- pn = nf.createBinary(Token.BITOR, pn, bitXorExpr(inForInit));
- }
- return pn;
- }
-
- private Node bitXorExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = bitAndExpr(inForInit);
- while (matchToken(Token.BITXOR)) {
- decompiler.addToken(Token.BITXOR);
- pn = nf.createBinary(Token.BITXOR, pn, bitAndExpr(inForInit));
- }
- return pn;
- }
-
- private Node bitAndExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = eqExpr(inForInit);
- while (matchToken(Token.BITAND)) {
- decompiler.addToken(Token.BITAND);
- pn = nf.createBinary(Token.BITAND, pn, eqExpr(inForInit));
- }
- return pn;
- }
-
- private Node eqExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = relExpr(inForInit);
- for (;;) {
- int tt = peekToken();
- switch (tt) {
- case Token.EQ:
- case Token.NE:
- case Token.SHEQ:
- case Token.SHNE:
- consumeToken();
- int decompilerToken = tt;
- int parseToken = tt;
- if (compilerEnv.getLanguageVersion() == Context.VERSION_1_2) {
- // JavaScript 1.2 uses shallow equality for == and != .
- // In addition, convert === and !== for decompiler into
- // == and != since the decompiler is supposed to show
- // canonical source and in 1.2 ===, !== are allowed
- // only as an alias to ==, !=.
- switch (tt) {
- case Token.EQ:
- parseToken = Token.SHEQ;
- break;
- case Token.NE:
- parseToken = Token.SHNE;
- break;
- case Token.SHEQ:
- decompilerToken = Token.EQ;
- break;
- case Token.SHNE:
- decompilerToken = Token.NE;
- break;
- }
- }
- decompiler.addToken(decompilerToken);
- pn = nf.createBinary(parseToken, pn, relExpr(inForInit));
- continue;
- }
- break;
- }
- return pn;
- }
-
- private Node relExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = shiftExpr();
- for (;;) {
- int tt = peekToken();
- switch (tt) {
- case Token.IN:
- if (inForInit)
- break;
- // fall through
- case Token.INSTANCEOF:
- case Token.LE:
- case Token.LT:
- case Token.GE:
- case Token.GT:
- consumeToken();
- decompiler.addToken(tt);
- pn = nf.createBinary(tt, pn, shiftExpr());
- continue;
- }
- break;
- }
- return pn;
- }
-
- private Node shiftExpr()
- throws IOException, ParserException
- {
- Node pn = addExpr();
- for (;;) {
- int tt = peekToken();
- switch (tt) {
- case Token.LSH:
- case Token.URSH:
- case Token.RSH:
- consumeToken();
- decompiler.addToken(tt);
- pn = nf.createBinary(tt, pn, addExpr());
- continue;
- }
- break;
- }
- return pn;
- }
-
- private Node addExpr()
- throws IOException, ParserException
- {
- Node pn = mulExpr();
- for (;;) {
- int tt = peekToken();
- if (tt == Token.ADD || tt == Token.SUB) {
- consumeToken();
- decompiler.addToken(tt);
- // flushNewLines
- pn = nf.createBinary(tt, pn, mulExpr());
- continue;
- }
- break;
- }
-
- return pn;
- }
-
- private Node mulExpr()
- throws IOException, ParserException
- {
- Node pn = unaryExpr();
- for (;;) {
- int tt = peekToken();
- switch (tt) {
- case Token.MUL:
- case Token.DIV:
- case Token.MOD:
- consumeToken();
- decompiler.addToken(tt);
- pn = nf.createBinary(tt, pn, unaryExpr());
- continue;
- }
- break;
- }
-
- return pn;
- }
-
- private Node unaryExpr()
- throws IOException, ParserException
- {
- int tt;
-
- tt = peekToken();
-
- switch(tt) {
- case Token.VOID:
- case Token.NOT:
- case Token.BITNOT:
- case Token.TYPEOF:
- consumeToken();
- decompiler.addToken(tt);
- return nf.createUnary(tt, unaryExpr());
-
- case Token.ADD:
- consumeToken();
- // Convert to special POS token in decompiler and parse tree
- decompiler.addToken(Token.POS);
- return nf.createUnary(Token.POS, unaryExpr());
-
- case Token.SUB:
- consumeToken();
- // Convert to special NEG token in decompiler and parse tree
- decompiler.addToken(Token.NEG);
- return nf.createUnary(Token.NEG, unaryExpr());
-
- case Token.INC:
- case Token.DEC:
- consumeToken();
- decompiler.addToken(tt);
- return nf.createIncDec(tt, false, memberExpr(true));
-
- case Token.DELPROP:
- consumeToken();
- decompiler.addToken(Token.DELPROP);
- return nf.createUnary(Token.DELPROP, unaryExpr());
-
- case Token.ERROR:
- consumeToken();
- break;
-
- // XML stream encountered in expression.
- case Token.LT:
- if (compilerEnv.isXmlAvailable()) {
- consumeToken();
- Node pn = xmlInitializer();
- return memberExprTail(true, pn);
- }
- // Fall thru to the default handling of RELOP
-
- default:
- Node pn = memberExpr(true);
-
- // Don't look across a newline boundary for a postfix incop.
- tt = peekTokenOrEOL();
- if (tt == Token.INC || tt == Token.DEC) {
- consumeToken();
- decompiler.addToken(tt);
- return nf.createIncDec(tt, true, pn);
- }
- return pn;
- }
- return nf.createName("err"); // Only reached on error. Try to continue.
-
- }
-
- private Node xmlInitializer() throws IOException
- {
- int tt = ts.getFirstXMLToken();
- if (tt != Token.XML && tt != Token.XMLEND) {
- reportError("msg.syntax");
- return null;
- }
-
- /* Make a NEW node to append to. */
- Node pnXML = nf.createLeaf(Token.NEW);
-
- String xml = ts.getString();
- boolean fAnonymous = xml.trim().startsWith("<>");
-
- Node pn = nf.createName(fAnonymous ? "XMLList" : "XML");
- nf.addChildToBack(pnXML, pn);
-
- pn = null;
- Node expr;
- for (;;tt = ts.getNextXMLToken()) {
- switch (tt) {
- case Token.XML:
- xml = ts.getString();
- decompiler.addName(xml);
- mustMatchToken(Token.LC, "msg.syntax");
- decompiler.addToken(Token.LC);
- expr = (peekToken() == Token.RC)
- ? nf.createString("")
- : expr(false);
- mustMatchToken(Token.RC, "msg.syntax");
- decompiler.addToken(Token.RC);
- if (pn == null) {
- pn = nf.createString(xml);
- } else {
- pn = nf.createBinary(Token.ADD, pn, nf.createString(xml));
- }
- if (ts.isXMLAttribute()) {
- /* Need to put the result in double quotes */
- expr = nf.createUnary(Token.ESCXMLATTR, expr);
- Node prepend = nf.createBinary(Token.ADD,
- nf.createString("\""),
- expr);
- expr = nf.createBinary(Token.ADD,
- prepend,
- nf.createString("\""));
- } else {
- expr = nf.createUnary(Token.ESCXMLTEXT, expr);
- }
- pn = nf.createBinary(Token.ADD, pn, expr);
- break;
- case Token.XMLEND:
- xml = ts.getString();
- decompiler.addName(xml);
- if (pn == null) {
- pn = nf.createString(xml);
- } else {
- pn = nf.createBinary(Token.ADD, pn, nf.createString(xml));
- }
-
- nf.addChildToBack(pnXML, pn);
- return pnXML;
- default:
- reportError("msg.syntax");
- return null;
- }
- }
- }
-
- private void argumentList(Node listNode)
- throws IOException, ParserException
- {
- boolean matched;
- matched = matchToken(Token.RP);
- if (!matched) {
- boolean first = true;
- do {
- if (!first)
- decompiler.addToken(Token.COMMA);
- first = false;
- nf.addChildToBack(listNode, assignExpr(false));
- } while (matchToken(Token.COMMA));
-
- mustMatchToken(Token.RP, "msg.no.paren.arg");
- }
- decompiler.addToken(Token.RP);
- }
-
- private Node memberExpr(boolean allowCallSyntax)
- throws IOException, ParserException
- {
- int tt;
-
- Node pn;
-
- /* Check for new expressions. */
- tt = peekToken();
- if (tt == Token.NEW) {
- /* Eat the NEW token. */
- consumeToken();
- decompiler.addToken(Token.NEW);
-
- /* Make a NEW node to append to. */
- pn = nf.createCallOrNew(Token.NEW, memberExpr(false));
-
- if (matchToken(Token.LP)) {
- decompiler.addToken(Token.LP);
- /* Add the arguments to pn, if any are supplied. */
- argumentList(pn);
- }
-
- /* XXX there's a check in the C source against
- * "too many constructor arguments" - how many
- * do we claim to support?
- */
-
- /* Experimental syntax: allow an object literal to follow a new expression,
- * which will mean a kind of anonymous class built with the JavaAdapter.
- * the object literal will be passed as an additional argument to the constructor.
- */
- tt = peekToken();
- if (tt == Token.LC) {
- nf.addChildToBack(pn, primaryExpr());
- }
- } else {
- pn = primaryExpr();
- }
-
- return memberExprTail(allowCallSyntax, pn);
- }
-
- private Node memberExprTail(boolean allowCallSyntax, Node pn)
- throws IOException, ParserException
- {
- tailLoop:
- for (;;) {
- int tt = peekToken();
- switch (tt) {
-
- case Token.DOT:
- case Token.DOTDOT:
- {
- int memberTypeFlags;
- String s;
-
- consumeToken();
- decompiler.addToken(tt);
- memberTypeFlags = 0;
- if (tt == Token.DOTDOT) {
- mustHaveXML();
- memberTypeFlags = Node.DESCENDANTS_FLAG;
- }
- if (!compilerEnv.isXmlAvailable()) {
- mustMatchToken(Token.NAME, "msg.no.name.after.dot");
- s = ts.getString();
- decompiler.addName(s);
- pn = nf.createPropertyGet(pn, null, s, memberTypeFlags);
- break;
- }
-
- tt = nextToken();
- switch (tt) {
- // handles: name, ns::name, ns::*, ns::[expr]
- case Token.NAME:
- s = ts.getString();
- decompiler.addName(s);
- pn = propertyName(pn, s, memberTypeFlags);
- break;
-
- // handles: *, *::name, *::*, *::[expr]
- case Token.MUL:
- decompiler.addName("*");
- pn = propertyName(pn, "*", memberTypeFlags);
- break;
-
- // handles: '@attr', '@ns::attr', '@ns::*', '@ns::*',
- // '@::attr', '@::*', '@*', '@*::attr', '@*::*'
- case Token.XMLATTR:
- decompiler.addToken(Token.XMLATTR);
- pn = attributeAccess(pn, memberTypeFlags);
- break;
-
- default:
- reportError("msg.no.name.after.dot");
- }
- }
- break;
-
- case Token.DOTQUERY:
- consumeToken();
- mustHaveXML();
- decompiler.addToken(Token.DOTQUERY);
- pn = nf.createDotQuery(pn, expr(false), ts.getLineno());
- mustMatchToken(Token.RP, "msg.no.paren");
- decompiler.addToken(Token.RP);
- break;
-
- case Token.LB:
- consumeToken();
- decompiler.addToken(Token.LB);
- pn = nf.createElementGet(pn, null, expr(false), 0);
- mustMatchToken(Token.RB, "msg.no.bracket.index");
- decompiler.addToken(Token.RB);
- break;
-
- case Token.LP:
- if (!allowCallSyntax) {
- break tailLoop;
- }
- consumeToken();
- decompiler.addToken(Token.LP);
- pn = nf.createCallOrNew(Token.CALL, pn);
- /* Add the arguments to pn, if any are supplied. */
- argumentList(pn);
- break;
-
- default:
- break tailLoop;
- }
- }
- return pn;
- }
-
- /*
- * Xml attribute expression:
- * '@attr', '@ns::attr', '@ns::*', '@ns::*', '@*', '@*::attr', '@*::*'
- */
- private Node attributeAccess(Node pn, int memberTypeFlags)
- throws IOException
- {
- memberTypeFlags |= Node.ATTRIBUTE_FLAG;
- int tt = nextToken();
-
- switch (tt) {
- // handles: @name, @ns::name, @ns::*, @ns::[expr]
- case Token.NAME:
- {
- String s = ts.getString();
- decompiler.addName(s);
- pn = propertyName(pn, s, memberTypeFlags);
- }
- break;
-
- // handles: @*, @*::name, @*::*, @*::[expr]
- case Token.MUL:
- decompiler.addName("*");
- pn = propertyName(pn, "*", memberTypeFlags);
- break;
-
- // handles @[expr]
- case Token.LB:
- decompiler.addToken(Token.LB);
- pn = nf.createElementGet(pn, null, expr(false), memberTypeFlags);
- mustMatchToken(Token.RB, "msg.no.bracket.index");
- decompiler.addToken(Token.RB);
- break;
-
- default:
- reportError("msg.no.name.after.xmlAttr");
- pn = nf.createPropertyGet(pn, null, "?", memberTypeFlags);
- break;
- }
-
- return pn;
- }
-
- /**
- * Check if :: follows name in which case it becomes qualified name
- */
- private Node propertyName(Node pn, String name, int memberTypeFlags)
- throws IOException, ParserException
- {
- String namespace = null;
- if (matchToken(Token.COLONCOLON)) {
- decompiler.addToken(Token.COLONCOLON);
- namespace = name;
-
- int tt = nextToken();
- switch (tt) {
- // handles name::name
- case Token.NAME:
- name = ts.getString();
- decompiler.addName(name);
- break;
-
- // handles name::*
- case Token.MUL:
- decompiler.addName("*");
- name = "*";
- break;
-
- // handles name::[expr]
- case Token.LB:
- decompiler.addToken(Token.LB);
- pn = nf.createElementGet(pn, namespace, expr(false),
- memberTypeFlags);
- mustMatchToken(Token.RB, "msg.no.bracket.index");
- decompiler.addToken(Token.RB);
- return pn;
-
- default:
- reportError("msg.no.name.after.coloncolon");
- name = "?";
- }
- }
-
- pn = nf.createPropertyGet(pn, namespace, name, memberTypeFlags);
- return pn;
- }
-
- private Node primaryExpr()
- throws IOException, ParserException
- {
- Node pn;
-
- int ttFlagged = nextFlaggedToken();
- int tt = ttFlagged & CLEAR_TI_MASK;
-
- switch(tt) {
-
- case Token.FUNCTION:
- return function(FunctionNode.FUNCTION_EXPRESSION);
-
- case Token.LB: {
- ObjArray elems = new ObjArray();
- int skipCount = 0;
- decompiler.addToken(Token.LB);
- boolean after_lb_or_comma = true;
- for (;;) {
- tt = peekToken();
-
- if (tt == Token.COMMA) {
- consumeToken();
- decompiler.addToken(Token.COMMA);
- if (!after_lb_or_comma) {
- after_lb_or_comma = true;
- } else {
- elems.add(null);
- ++skipCount;
- }
- } else if (tt == Token.RB) {
- consumeToken();
- decompiler.addToken(Token.RB);
- break;
- } else {
- if (!after_lb_or_comma) {
- reportError("msg.no.bracket.arg");
- }
- elems.add(assignExpr(false));
- after_lb_or_comma = false;
- }
- }
- return nf.createArrayLiteral(elems, skipCount);
- }
-
- case Token.LC: {
- ObjArray elems = new ObjArray();
- decompiler.addToken(Token.LC);
- if (!matchToken(Token.RC)) {
-
- boolean first = true;
- commaloop:
- do {
- Object property;
-
- if (!first)
- decompiler.addToken(Token.COMMA);
- else
- first = false;
-
- tt = peekToken();
- switch(tt) {
- case Token.NAME:
- case Token.STRING:
- consumeToken();
- // map NAMEs to STRINGs in object literal context
- // but tell the decompiler the proper type
- String s = ts.getString();
- if (tt == Token.NAME) {
- if (s.equals("get") &&
- peekToken() == Token.NAME) {
- decompiler.addToken(Token.GET);
- consumeToken();
- s = ts.getString();
- decompiler.addName(s);
- property = ScriptRuntime.getIndexObject(s);
- if (!getterSetterProperty(elems, property,
- true))
- break commaloop;
- break;
- } else if (s.equals("set") &&
- peekToken() == Token.NAME) {
- decompiler.addToken(Token.SET);
- consumeToken();
- s = ts.getString();
- decompiler.addName(s);
- property = ScriptRuntime.getIndexObject(s);
- if (!getterSetterProperty(elems, property,
- false))
- break commaloop;
- break;
- }
- decompiler.addName(s);
- } else {
- decompiler.addString(s);
- }
- property = ScriptRuntime.getIndexObject(s);
- plainProperty(elems, property);
- break;
-
- case Token.NUMBER:
- consumeToken();
- double n = ts.getNumber();
- decompiler.addNumber(n);
- property = ScriptRuntime.getIndexObject(n);
- plainProperty(elems, property);
- break;
-
- case Token.RC:
- // trailing comma is OK.
- break commaloop;
- default:
- reportError("msg.bad.prop");
- break commaloop;
- }
- } while (matchToken(Token.COMMA));
-
- mustMatchToken(Token.RC, "msg.no.brace.prop");
- }
- decompiler.addToken(Token.RC);
- return nf.createObjectLiteral(elems);
- }
-
- case Token.LP:
-
- /* Brendan's IR-jsparse.c makes a new node tagged with
- * TOK_LP here... I'm not sure I understand why. Isn't
- * the grouping already implicit in the structure of the
- * parse tree? also TOK_LP is already overloaded (I
- * think) in the C IR as 'function call.' */
- decompiler.addToken(Token.LP);
- pn = expr(false);
- pn.putProp(Node.PARENTHESIZED_PROP, Boolean.TRUE);
- decompiler.addToken(Token.RP);
- mustMatchToken(Token.RP, "msg.no.paren");
- return pn;
-
- case Token.XMLATTR:
- mustHaveXML();
- decompiler.addToken(Token.XMLATTR);
- pn = attributeAccess(null, 0);
- return pn;
-
- case Token.NAME: {
- String name = ts.getString();
- if ((ttFlagged & TI_CHECK_LABEL) != 0) {
- if (peekToken() == Token.COLON) {
- // Do not consume colon, it is used as unwind indicator
- // to return to statementHelper.
- // XXX Better way?
- return nf.createLabel(ts.getLineno());
- }
- }
-
- decompiler.addName(name);
- if (compilerEnv.isXmlAvailable()) {
- pn = propertyName(null, name, 0);
- } else {
- pn = nf.createName(name);
- }
- return pn;
- }
-
- case Token.NUMBER: {
- double n = ts.getNumber();
- decompiler.addNumber(n);
- return nf.createNumber(n);
- }
-
- case Token.STRING: {
- String s = ts.getString();
- decompiler.addString(s);
- return nf.createString(s);
- }
-
- case Token.DIV:
- case Token.ASSIGN_DIV: {
- // Got / or /= which should be treated as regexp in fact
- ts.readRegExp(tt);
- String flags = ts.regExpFlags;
- ts.regExpFlags = null;
- String re = ts.getString();
- decompiler.addRegexp(re, flags);
- int index = currentScriptOrFn.addRegexp(re, flags);
- return nf.createRegExp(index);
- }
-
- case Token.NULL:
- case Token.THIS:
- case Token.FALSE:
- case Token.TRUE:
- decompiler.addToken(tt);
- return nf.createLeaf(tt);
-
- case Token.RESERVED:
- reportError("msg.reserved.id");
- break;
-
- case Token.ERROR:
- /* the scanner or one of its subroutines reported the error. */
- break;
-
- case Token.EOF:
- reportError("msg.unexpected.eof");
- break;
-
- default:
- reportError("msg.syntax");
- break;
- }
- return null; // should never reach here
- }
-
- private void plainProperty(ObjArray elems, Object property)
- throws IOException {
- mustMatchToken(Token.COLON, "msg.no.colon.prop");
-
- // OBJLIT is used as ':' in object literal for
- // decompilation to solve spacing ambiguity.
- decompiler.addToken(Token.OBJECTLIT);
- elems.add(property);
- elems.add(assignExpr(false));
- }
-
- private boolean getterSetterProperty(ObjArray elems, Object property,
- boolean isGetter) throws IOException {
- Node f = function(FunctionNode.FUNCTION_EXPRESSION);
- if (f.getType() != Token.FUNCTION) {
- reportError("msg.bad.prop");
- return false;
- }
- int fnIndex = f.getExistingIntProp(Node.FUNCTION_PROP);
- FunctionNode fn = currentScriptOrFn.getFunctionNode(fnIndex);
- if (fn.getFunctionName().length() != 0) {
- reportError("msg.bad.prop");
- return false;
- }
- elems.add(property);
- if (isGetter) {
- elems.add(nf.createUnary(Token.GET, f));
- } else {
- elems.add(nf.createUnary(Token.SET, f));
- }
- return true;
- }
-}
diff --git a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java.orig b/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java.orig
deleted file mode 100644
index 7f7cdc2..0000000
--- a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Token.java.orig
+++ /dev/null
@@ -1,417 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1997-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Roger Lawrence
- * Mike McCabe
- * Igor Bukanov
- * Bob Jervis
- * Milen Nankov
- *
- * Alternatively, the contents of this file may be used under the terms of
- * the GNU General Public License Version 2 or later (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of those above. If
- * you wish to allow use of your version of this file only under the terms of
- * the GPL and not to allow others to use your version of this file under the
- * MPL, indicate your decision by deleting the provisions above and replacing
- * them with the notice and other provisions required by the GPL. If you do
- * not delete the provisions above, a recipient may use your version of this
- * file under either the MPL or the GPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-/**
- * This class implements the JavaScript scanner.
- *
- * It is based on the C source files jsscan.c and jsscan.h
- * in the jsref package.
- *
- * @see org.mozilla.javascript.Parser
- *
- * @author Mike McCabe
- * @author Brendan Eich
- */
-
-public class Token
-{
-
- // debug flags
- public static final boolean printTrees = false;
- static final boolean printICode = false;
- static final boolean printNames = printTrees || printICode;
-
- /**
- * Token types. These values correspond to JSTokenType values in
- * jsscan.c.
- */
-
- public final static int
- // start enum
- ERROR = -1, // well-known as the only code < EOF
- EOF = 0, // end of file token - (not EOF_CHAR)
- EOL = 1, // end of line
-
- // Interpreter reuses the following as bytecodes
- FIRST_BYTECODE_TOKEN = 2,
-
- ENTERWITH = 2,
- LEAVEWITH = 3,
- RETURN = 4,
- GOTO = 5,
- IFEQ = 6,
- IFNE = 7,
- SETNAME = 8,
- BITOR = 9,
- BITXOR = 10,
- BITAND = 11,
- EQ = 12,
- NE = 13,
- LT = 14,
- LE = 15,
- GT = 16,
- GE = 17,
- LSH = 18,
- RSH = 19,
- URSH = 20,
- ADD = 21,
- SUB = 22,
- MUL = 23,
- DIV = 24,
- MOD = 25,
- NOT = 26,
- BITNOT = 27,
- POS = 28,
- NEG = 29,
- NEW = 30,
- DELPROP = 31,
- TYPEOF = 32,
- GETPROP = 33,
- SETPROP = 34,
- GETELEM = 35,
- SETELEM = 36,
- CALL = 37,
- NAME = 38,
- NUMBER = 39,
- STRING = 40,
- NULL = 41,
- THIS = 42,
- FALSE = 43,
- TRUE = 44,
- SHEQ = 45, // shallow equality (===)
- SHNE = 46, // shallow inequality (!==)
- REGEXP = 47,
- BINDNAME = 48,
- THROW = 49,
- RETHROW = 50, // rethrow caught execetion: catch (e if ) use it
- IN = 51,
- INSTANCEOF = 52,
- LOCAL_LOAD = 53,
- GETVAR = 54,
- SETVAR = 55,
- CATCH_SCOPE = 56,
- ENUM_INIT_KEYS = 57,
- ENUM_INIT_VALUES = 58,
- ENUM_NEXT = 59,
- ENUM_ID = 60,
- THISFN = 61,
- RETURN_RESULT = 62, // to return prevoisly stored return result
- ARRAYLIT = 63, // array literal
- OBJECTLIT = 64, // object literal
- GET_REF = 65, // *reference
- SET_REF = 66, // *reference = something
- DEL_REF = 67, // delete reference
- REF_CALL = 68, // f(args) = something or f(args)++
- REF_SPECIAL = 69, // reference for special properties like __proto
-
- // For XML support:
- DEFAULTNAMESPACE = 70, // default xml namespace =
- ESCXMLATTR = 71,
- ESCXMLTEXT = 72,
- REF_MEMBER = 73, // Reference for x.@y, x..y etc.
- REF_NS_MEMBER = 74, // Reference for x.ns::y, x..ns::y etc.
- REF_NAME = 75, // Reference for @y, @[y] etc.
- REF_NS_NAME = 76; // Reference for ns::y, @ns::y@[y] etc.
-
- // End of interpreter bytecodes
- public final static int
- LAST_BYTECODE_TOKEN = REF_NS_NAME,
-
- TRY = 77,
- SEMI = 78, // semicolon
- LB = 79, // left and right brackets
- RB = 80,
- LC = 81, // left and right curlies (braces)
- RC = 82,
- LP = 83, // left and right parentheses
- RP = 84,
- COMMA = 85, // comma operator
-
- ASSIGN = 86, // simple assignment (=)
- ASSIGN_BITOR = 87, // |=
- ASSIGN_BITXOR = 88, // ^=
- ASSIGN_BITAND = 89, // |=
- ASSIGN_LSH = 90, // <<=
- ASSIGN_RSH = 91, // >>=
- ASSIGN_URSH = 92, // >>>=
- ASSIGN_ADD = 93, // +=
- ASSIGN_SUB = 94, // -=
- ASSIGN_MUL = 95, // *=
- ASSIGN_DIV = 96, // /=
- ASSIGN_MOD = 97; // %=
-
- public final static int
- FIRST_ASSIGN = ASSIGN,
- LAST_ASSIGN = ASSIGN_MOD,
-
- HOOK = 98, // conditional (?:)
- COLON = 99,
- OR = 100, // logical or (||)
- AND = 101, // logical and (&&)
- INC = 102, // increment/decrement (++ --)
- DEC = 103,
- DOT = 104, // member operator (.)
- FUNCTION = 105, // function keyword
- EXPORT = 106, // export keyword
- IMPORT = 107, // import keyword
- IF = 108, // if keyword
- ELSE = 109, // else keyword
- SWITCH = 110, // switch keyword
- CASE = 111, // case keyword
- DEFAULT = 112, // default keyword
- WHILE = 113, // while keyword
- DO = 114, // do keyword
- FOR = 115, // for keyword
- BREAK = 116, // break keyword
- CONTINUE = 117, // continue keyword
- VAR = 118, // var keyword
- WITH = 119, // with keyword
- CATCH = 120, // catch keyword
- FINALLY = 121, // finally keyword
- VOID = 122, // void keyword
- RESERVED = 123, // reserved keywords
-
- EMPTY = 124,
-
- /* types used for the parse tree - these never get returned
- * by the scanner.
- */
-
- BLOCK = 125, // statement block
- LABEL = 126, // label
- TARGET = 127,
- LOOP = 128,
- EXPR_VOID = 129, // expression statement in functions
- EXPR_RESULT = 130, // expression statement in scripts
- JSR = 131,
- SCRIPT = 132, // top-level node for entire script
- TYPEOFNAME = 133, // for typeof(simple-name)
- USE_STACK = 134,
- SETPROP_OP = 135, // x.y op= something
- SETELEM_OP = 136, // x[y] op= something
- LOCAL_BLOCK = 137,
- SET_REF_OP = 138, // *reference op= something
-
- // For XML support:
- DOTDOT = 139, // member operator (..)
- COLONCOLON = 140, // namespace::name
- XML = 141, // XML type
- DOTQUERY = 142, // .() -- e.g., x.emps.emp.(name == "terry")
- XMLATTR = 143, // @
- XMLEND = 144,
-
- // Optimizer-only-tokens
- TO_OBJECT = 145,
- TO_DOUBLE = 146,
-
- GET = 147, // JS 1.5 get pseudo keyword
- SET = 148, // JS 1.5 set pseudo keyword
- CONST = 149,
- SETCONST = 150,
- SETCONSTVAR = 151,
- LAST_TOKEN = 152;
-
- public static String name(int token)
- {
- if (!printNames) {
- return String.valueOf(token);
- }
- switch (token) {
- case ERROR: return "ERROR";
- case EOF: return "EOF";
- case EOL: return "EOL";
- case ENTERWITH: return "ENTERWITH";
- case LEAVEWITH: return "LEAVEWITH";
- case RETURN: return "RETURN";
- case GOTO: return "GOTO";
- case IFEQ: return "IFEQ";
- case IFNE: return "IFNE";
- case SETNAME: return "SETNAME";
- case BITOR: return "BITOR";
- case BITXOR: return "BITXOR";
- case BITAND: return "BITAND";
- case EQ: return "EQ";
- case NE: return "NE";
- case LT: return "LT";
- case LE: return "LE";
- case GT: return "GT";
- case GE: return "GE";
- case LSH: return "LSH";
- case RSH: return "RSH";
- case URSH: return "URSH";
- case ADD: return "ADD";
- case SUB: return "SUB";
- case MUL: return "MUL";
- case DIV: return "DIV";
- case MOD: return "MOD";
- case NOT: return "NOT";
- case BITNOT: return "BITNOT";
- case POS: return "POS";
- case NEG: return "NEG";
- case NEW: return "NEW";
- case DELPROP: return "DELPROP";
- case TYPEOF: return "TYPEOF";
- case GETPROP: return "GETPROP";
- case SETPROP: return "SETPROP";
- case GETELEM: return "GETELEM";
- case SETELEM: return "SETELEM";
- case CALL: return "CALL";
- case NAME: return "NAME";
- case NUMBER: return "NUMBER";
- case STRING: return "STRING";
- case NULL: return "NULL";
- case THIS: return "THIS";
- case FALSE: return "FALSE";
- case TRUE: return "TRUE";
- case SHEQ: return "SHEQ";
- case SHNE: return "SHNE";
- case REGEXP: return "OBJECT";
- case BINDNAME: return "BINDNAME";
- case THROW: return "THROW";
- case RETHROW: return "RETHROW";
- case IN: return "IN";
- case INSTANCEOF: return "INSTANCEOF";
- case LOCAL_LOAD: return "LOCAL_LOAD";
- case GETVAR: return "GETVAR";
- case SETVAR: return "SETVAR";
- case CATCH_SCOPE: return "CATCH_SCOPE";
- case ENUM_INIT_KEYS: return "ENUM_INIT_KEYS";
- case ENUM_INIT_VALUES: return "ENUM_INIT_VALUES";
- case ENUM_NEXT: return "ENUM_NEXT";
- case ENUM_ID: return "ENUM_ID";
- case THISFN: return "THISFN";
- case RETURN_RESULT: return "RETURN_RESULT";
- case ARRAYLIT: return "ARRAYLIT";
- case OBJECTLIT: return "OBJECTLIT";
- case GET_REF: return "GET_REF";
- case SET_REF: return "SET_REF";
- case DEL_REF: return "DEL_REF";
- case REF_CALL: return "REF_CALL";
- case REF_SPECIAL: return "REF_SPECIAL";
- case DEFAULTNAMESPACE:return "DEFAULTNAMESPACE";
- case ESCXMLTEXT: return "ESCXMLTEXT";
- case ESCXMLATTR: return "ESCXMLATTR";
- case REF_MEMBER: return "REF_MEMBER";
- case REF_NS_MEMBER: return "REF_NS_MEMBER";
- case REF_NAME: return "REF_NAME";
- case REF_NS_NAME: return "REF_NS_NAME";
- case TRY: return "TRY";
- case SEMI: return "SEMI";
- case LB: return "LB";
- case RB: return "RB";
- case LC: return "LC";
- case RC: return "RC";
- case LP: return "LP";
- case RP: return "RP";
- case COMMA: return "COMMA";
- case ASSIGN: return "ASSIGN";
- case ASSIGN_BITOR: return "ASSIGN_BITOR";
- case ASSIGN_BITXOR: return "ASSIGN_BITXOR";
- case ASSIGN_BITAND: return "ASSIGN_BITAND";
- case ASSIGN_LSH: return "ASSIGN_LSH";
- case ASSIGN_RSH: return "ASSIGN_RSH";
- case ASSIGN_URSH: return "ASSIGN_URSH";
- case ASSIGN_ADD: return "ASSIGN_ADD";
- case ASSIGN_SUB: return "ASSIGN_SUB";
- case ASSIGN_MUL: return "ASSIGN_MUL";
- case ASSIGN_DIV: return "ASSIGN_DIV";
- case ASSIGN_MOD: return "ASSIGN_MOD";
- case HOOK: return "HOOK";
- case COLON: return "COLON";
- case OR: return "OR";
- case AND: return "AND";
- case INC: return "INC";
- case DEC: return "DEC";
- case DOT: return "DOT";
- case FUNCTION: return "FUNCTION";
- case EXPORT: return "EXPORT";
- case IMPORT: return "IMPORT";
- case IF: return "IF";
- case ELSE: return "ELSE";
- case SWITCH: return "SWITCH";
- case CASE: return "CASE";
- case DEFAULT: return "DEFAULT";
- case WHILE: return "WHILE";
- case DO: return "DO";
- case FOR: return "FOR";
- case BREAK: return "BREAK";
- case CONTINUE: return "CONTINUE";
- case VAR: return "VAR";
- case WITH: return "WITH";
- case CATCH: return "CATCH";
- case FINALLY: return "FINALLY";
- case RESERVED: return "RESERVED";
- case EMPTY: return "EMPTY";
- case BLOCK: return "BLOCK";
- case LABEL: return "LABEL";
- case TARGET: return "TARGET";
- case LOOP: return "LOOP";
- case EXPR_VOID: return "EXPR_VOID";
- case EXPR_RESULT: return "EXPR_RESULT";
- case JSR: return "JSR";
- case SCRIPT: return "SCRIPT";
- case TYPEOFNAME: return "TYPEOFNAME";
- case USE_STACK: return "USE_STACK";
- case SETPROP_OP: return "SETPROP_OP";
- case SETELEM_OP: return "SETELEM_OP";
- case LOCAL_BLOCK: return "LOCAL_BLOCK";
- case SET_REF_OP: return "SET_REF_OP";
- case DOTDOT: return "DOTDOT";
- case COLONCOLON: return "COLONCOLON";
- case XML: return "XML";
- case DOTQUERY: return "DOTQUERY";
- case XMLATTR: return "XMLATTR";
- case XMLEND: return "XMLEND";
- case TO_OBJECT: return "TO_OBJECT";
- case TO_DOUBLE: return "TO_DOUBLE";
- case GET: return "GET";
- case SET: return "SET";
- case CONST: return "CONST";
- case SETCONST: return "SETCONST";
- }
-
- // Token without name
- throw new IllegalStateException(String.valueOf(token));
- }
-}
diff --git a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java.orig b/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java.orig
deleted file mode 100644
index c276894..0000000
--- a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/TokenStream.java.orig
+++ /dev/null
@@ -1,1398 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1997-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Roger Lawrence
- * Mike McCabe
- * Igor Bukanov
- * Ethan Hugg
- * Bob Jervis
- * Terry Lucas
- * Milen Nankov
- *
- * Alternatively, the contents of this file may be used under the terms of
- * the GNU General Public License Version 2 or later (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of those above. If
- * you wish to allow use of your version of this file only under the terms of
- * the GPL and not to allow others to use your version of this file under the
- * MPL, indicate your decision by deleting the provisions above and replacing
- * them with the notice and other provisions required by the GPL. If you do
- * not delete the provisions above, a recipient may use your version of this
- * file under either the MPL or the GPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-import java.io.*;
-
-/**
- * This class implements the JavaScript scanner.
- *
- * It is based on the C source files jsscan.c and jsscan.h
- * in the jsref package.
- *
- * @see org.mozilla.javascript.Parser
- *
- * @author Mike McCabe
- * @author Brendan Eich
- */
-
-class TokenStream
-{
- /*
- * For chars - because we need something out-of-range
- * to check. (And checking EOF by exception is annoying.)
- * Note distinction from EOF token type!
- */
- private final static int
- EOF_CHAR = -1;
-
- TokenStream(Parser parser, Reader sourceReader, String sourceString,
- int lineno)
- {
- this.parser = parser;
- this.lineno = lineno;
- if (sourceReader != null) {
- if (sourceString != null) Kit.codeBug();
- this.sourceReader = sourceReader;
- this.sourceBuffer = new char[512];
- this.sourceEnd = 0;
- } else {
- if (sourceString == null) Kit.codeBug();
- this.sourceString = sourceString;
- this.sourceEnd = sourceString.length();
- }
- this.sourceCursor = 0;
- }
-
- /* This function uses the cached op, string and number fields in
- * TokenStream; if getToken has been called since the passed token
- * was scanned, the op or string printed may be incorrect.
- */
- String tokenToString(int token)
- {
- if (Token.printTrees) {
- String name = Token.name(token);
-
- switch (token) {
- case Token.STRING:
- case Token.REGEXP:
- case Token.NAME:
- return name + " `" + this.string + "'";
-
- case Token.NUMBER:
- return "NUMBER " + this.number;
- }
-
- return name;
- }
- return "";
- }
-
- static boolean isKeyword(String s)
- {
- return Token.EOF != stringToKeyword(s);
- }
-
- private static int stringToKeyword(String name)
- {
-// #string_id_map#
-// The following assumes that Token.EOF == 0
- final int
- Id_break = Token.BREAK,
- Id_case = Token.CASE,
- Id_continue = Token.CONTINUE,
- Id_default = Token.DEFAULT,
- Id_delete = Token.DELPROP,
- Id_do = Token.DO,
- Id_else = Token.ELSE,
- Id_export = Token.EXPORT,
- Id_false = Token.FALSE,
- Id_for = Token.FOR,
- Id_function = Token.FUNCTION,
- Id_if = Token.IF,
- Id_in = Token.IN,
- Id_new = Token.NEW,
- Id_null = Token.NULL,
- Id_return = Token.RETURN,
- Id_switch = Token.SWITCH,
- Id_this = Token.THIS,
- Id_true = Token.TRUE,
- Id_typeof = Token.TYPEOF,
- Id_var = Token.VAR,
- Id_void = Token.VOID,
- Id_while = Token.WHILE,
- Id_with = Token.WITH,
-
- // the following are #ifdef RESERVE_JAVA_KEYWORDS in jsscan.c
- Id_abstract = Token.RESERVED,
- Id_boolean = Token.RESERVED,
- Id_byte = Token.RESERVED,
- Id_catch = Token.CATCH,
- Id_char = Token.RESERVED,
- Id_class = Token.RESERVED,
- Id_const = Token.CONST,
- Id_debugger = Token.RESERVED,
- Id_double = Token.RESERVED,
- Id_enum = Token.RESERVED,
- Id_extends = Token.RESERVED,
- Id_final = Token.RESERVED,
- Id_finally = Token.FINALLY,
- Id_float = Token.RESERVED,
- Id_goto = Token.RESERVED,
- Id_implements = Token.RESERVED,
- Id_import = Token.IMPORT,
- Id_instanceof = Token.INSTANCEOF,
- Id_int = Token.RESERVED,
- Id_interface = Token.RESERVED,
- Id_long = Token.RESERVED,
- Id_native = Token.RESERVED,
- Id_package = Token.RESERVED,
- Id_private = Token.RESERVED,
- Id_protected = Token.RESERVED,
- Id_public = Token.RESERVED,
- Id_short = Token.RESERVED,
- Id_static = Token.RESERVED,
- Id_super = Token.RESERVED,
- Id_synchronized = Token.RESERVED,
- Id_throw = Token.THROW,
- Id_throws = Token.RESERVED,
- Id_transient = Token.RESERVED,
- Id_try = Token.TRY,
- Id_volatile = Token.RESERVED;
-
- int id;
- String s = name;
-// #generated# Last update: 2001-06-01 17:45:01 CEST
- L0: { id = 0; String X = null; int c;
- L: switch (s.length()) {
- case 2: c=s.charAt(1);
- if (c=='f') { if (s.charAt(0)=='i') {id=Id_if; break L0;} }
- else if (c=='n') { if (s.charAt(0)=='i') {id=Id_in; break L0;} }
- else if (c=='o') { if (s.charAt(0)=='d') {id=Id_do; break L0;} }
- break L;
- case 3: switch (s.charAt(0)) {
- case 'f': if (s.charAt(2)=='r' && s.charAt(1)=='o') {id=Id_for; break L0;} break L;
- case 'i': if (s.charAt(2)=='t' && s.charAt(1)=='n') {id=Id_int; break L0;} break L;
- case 'n': if (s.charAt(2)=='w' && s.charAt(1)=='e') {id=Id_new; break L0;} break L;
- case 't': if (s.charAt(2)=='y' && s.charAt(1)=='r') {id=Id_try; break L0;} break L;
- case 'v': if (s.charAt(2)=='r' && s.charAt(1)=='a') {id=Id_var; break L0;} break L;
- } break L;
- case 4: switch (s.charAt(0)) {
- case 'b': X="byte";id=Id_byte; break L;
- case 'c': c=s.charAt(3);
- if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='a') {id=Id_case; break L0;} }
- else if (c=='r') { if (s.charAt(2)=='a' && s.charAt(1)=='h') {id=Id_char; break L0;} }
- break L;
- case 'e': c=s.charAt(3);
- if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='l') {id=Id_else; break L0;} }
- else if (c=='m') { if (s.charAt(2)=='u' && s.charAt(1)=='n') {id=Id_enum; break L0;} }
- break L;
- case 'g': X="goto";id=Id_goto; break L;
- case 'l': X="long";id=Id_long; break L;
- case 'n': X="null";id=Id_null; break L;
- case 't': c=s.charAt(3);
- if (c=='e') { if (s.charAt(2)=='u' && s.charAt(1)=='r') {id=Id_true; break L0;} }
- else if (c=='s') { if (s.charAt(2)=='i' && s.charAt(1)=='h') {id=Id_this; break L0;} }
- break L;
- case 'v': X="void";id=Id_void; break L;
- case 'w': X="with";id=Id_with; break L;
- } break L;
- case 5: switch (s.charAt(2)) {
- case 'a': X="class";id=Id_class; break L;
- case 'e': X="break";id=Id_break; break L;
- case 'i': X="while";id=Id_while; break L;
- case 'l': X="false";id=Id_false; break L;
- case 'n': c=s.charAt(0);
- if (c=='c') { X="const";id=Id_const; }
- else if (c=='f') { X="final";id=Id_final; }
- break L;
- case 'o': c=s.charAt(0);
- if (c=='f') { X="float";id=Id_float; }
- else if (c=='s') { X="short";id=Id_short; }
- break L;
- case 'p': X="super";id=Id_super; break L;
- case 'r': X="throw";id=Id_throw; break L;
- case 't': X="catch";id=Id_catch; break L;
- } break L;
- case 6: switch (s.charAt(1)) {
- case 'a': X="native";id=Id_native; break L;
- case 'e': c=s.charAt(0);
- if (c=='d') { X="delete";id=Id_delete; }
- else if (c=='r') { X="return";id=Id_return; }
- break L;
- case 'h': X="throws";id=Id_throws; break L;
- case 'm': X="import";id=Id_import; break L;
- case 'o': X="double";id=Id_double; break L;
- case 't': X="static";id=Id_static; break L;
- case 'u': X="public";id=Id_public; break L;
- case 'w': X="switch";id=Id_switch; break L;
- case 'x': X="export";id=Id_export; break L;
- case 'y': X="typeof";id=Id_typeof; break L;
- } break L;
- case 7: switch (s.charAt(1)) {
- case 'a': X="package";id=Id_package; break L;
- case 'e': X="default";id=Id_default; break L;
- case 'i': X="finally";id=Id_finally; break L;
- case 'o': X="boolean";id=Id_boolean; break L;
- case 'r': X="private";id=Id_private; break L;
- case 'x': X="extends";id=Id_extends; break L;
- } break L;
- case 8: switch (s.charAt(0)) {
- case 'a': X="abstract";id=Id_abstract; break L;
- case 'c': X="continue";id=Id_continue; break L;
- case 'd': X="debugger";id=Id_debugger; break L;
- case 'f': X="function";id=Id_function; break L;
- case 'v': X="volatile";id=Id_volatile; break L;
- } break L;
- case 9: c=s.charAt(0);
- if (c=='i') { X="interface";id=Id_interface; }
- else if (c=='p') { X="protected";id=Id_protected; }
- else if (c=='t') { X="transient";id=Id_transient; }
- break L;
- case 10: c=s.charAt(1);
- if (c=='m') { X="implements";id=Id_implements; }
- else if (c=='n') { X="instanceof";id=Id_instanceof; }
- break L;
- case 12: X="synchronized";id=Id_synchronized; break L;
- }
- if (X!=null && X!=s && !X.equals(s)) id = 0;
- }
-// #/generated#
-// #/string_id_map#
- if (id == 0) { return Token.EOF; }
- return id & 0xff;
- }
-
- final int getLineno() { return lineno; }
-
- final String getString() { return string; }
-
- final double getNumber() { return number; }
-
- final boolean eof() { return hitEOF; }
-
- final int getToken() throws IOException
- {
- int c;
-
- retry:
- for (;;) {
- // Eat whitespace, possibly sensitive to newlines.
- for (;;) {
- c = getChar();
- if (c == EOF_CHAR) {
- return Token.EOF;
- } else if (c == '\n') {
- dirtyLine = false;
- return Token.EOL;
- } else if (!isJSSpace(c)) {
- if (c != '-') {
- dirtyLine = true;
- }
- break;
- }
- }
-
- if (c == '@') return Token.XMLATTR;
-
- // identifier/keyword/instanceof?
- // watch out for starting with a <backslash>
- boolean identifierStart;
- boolean isUnicodeEscapeStart = false;
- if (c == '\\') {
- c = getChar();
- if (c == 'u') {
- identifierStart = true;
- isUnicodeEscapeStart = true;
- stringBufferTop = 0;
- } else {
- identifierStart = false;
- ungetChar(c);
- c = '\\';
- }
- } else {
- identifierStart = Character.isJavaIdentifierStart((char)c);
- if (identifierStart) {
- stringBufferTop = 0;
- addToString(c);
- }
- }
-
- if (identifierStart) {
- boolean containsEscape = isUnicodeEscapeStart;
- for (;;) {
- if (isUnicodeEscapeStart) {
- // strictly speaking we should probably push-back
- // all the bad characters if the <backslash>uXXXX
- // sequence is malformed. But since there isn't a
- // correct context(is there?) for a bad Unicode
- // escape sequence in an identifier, we can report
- // an error here.
- int escapeVal = 0;
- for (int i = 0; i != 4; ++i) {
- c = getChar();
- escapeVal = Kit.xDigitToInt(c, escapeVal);
- // Next check takes care about c < 0 and bad escape
- if (escapeVal < 0) { break; }
- }
- if (escapeVal < 0) {
- parser.addError("msg.invalid.escape");
- return Token.ERROR;
- }
- addToString(escapeVal);
- isUnicodeEscapeStart = false;
- } else {
- c = getChar();
- if (c == '\\') {
- c = getChar();
- if (c == 'u') {
- isUnicodeEscapeStart = true;
- containsEscape = true;
- } else {
- parser.addError("msg.illegal.character");
- return Token.ERROR;
- }
- } else {
- if (c == EOF_CHAR
- || !Character.isJavaIdentifierPart((char)c))
- {
- break;
- }
- addToString(c);
- }
- }
- }
- ungetChar(c);
-
- String str = getStringFromBuffer();
- if (!containsEscape) {
- // OPT we shouldn't have to make a string (object!) to
- // check if it's a keyword.
-
- // Return the corresponding token if it's a keyword
- int result = stringToKeyword(str);
- if (result != Token.EOF) {
- if (result != Token.RESERVED) {
- return result;
- } else if (!parser.compilerEnv.
- isReservedKeywordAsIdentifier())
- {
- return result;
- } else {
- // If implementation permits to use future reserved
- // keywords in violation with the EcmaScript,
- // treat it as name but issue warning
- parser.addWarning("msg.reserved.keyword", str);
- }
- }
- }
- this.string = (String)allStrings.intern(str);
- return Token.NAME;
- }
-
- // is it a number?
- if (isDigit(c) || (c == '.' && isDigit(peekChar()))) {
-
- stringBufferTop = 0;
- int base = 10;
-
- if (c == '0') {
- c = getChar();
- if (c == 'x' || c == 'X') {
- base = 16;
- c = getChar();
- } else if (isDigit(c)) {
- base = 8;
- } else {
- addToString('0');
- }
- }
-
- if (base == 16) {
- while (0 <= Kit.xDigitToInt(c, 0)) {
- addToString(c);
- c = getChar();
- }
- } else {
- while ('0' <= c && c <= '9') {
- /*
- * We permit 08 and 09 as decimal numbers, which
- * makes our behavior a superset of the ECMA
- * numeric grammar. We might not always be so
- * permissive, so we warn about it.
- */
- if (base == 8 && c >= '8') {
- parser.addWarning("msg.bad.octal.literal",
- c == '8' ? "8" : "9");
- base = 10;
- }
- addToString(c);
- c = getChar();
- }
- }
-
- boolean isInteger = true;
-
- if (base == 10 && (c == '.' || c == 'e' || c == 'E')) {
- isInteger = false;
- if (c == '.') {
- do {
- addToString(c);
- c = getChar();
- } while (isDigit(c));
- }
- if (c == 'e' || c == 'E') {
- addToString(c);
- c = getChar();
- if (c == '+' || c == '-') {
- addToString(c);
- c = getChar();
- }
- if (!isDigit(c)) {
- parser.addError("msg.missing.exponent");
- return Token.ERROR;
- }
- do {
- addToString(c);
- c = getChar();
- } while (isDigit(c));
- }
- }
- ungetChar(c);
- String numString = getStringFromBuffer();
-
- double dval;
- if (base == 10 && !isInteger) {
- try {
- // Use Java conversion to number from string...
- dval = Double.valueOf(numString).doubleValue();
- }
- catch (NumberFormatException ex) {
- parser.addError("msg.caught.nfe");
- return Token.ERROR;
- }
- } else {
- dval = ScriptRuntime.stringToNumber(numString, 0, base);
- }
-
- this.number = dval;
- return Token.NUMBER;
- }
-
- // is it a string?
- if (c == '"' || c == '\'') {
- // We attempt to accumulate a string the fast way, by
- // building it directly out of the reader. But if there
- // are any escaped characters in the string, we revert to
- // building it out of a StringBuffer.
-
- int quoteChar = c;
- stringBufferTop = 0;
-
- c = getChar();
- strLoop: while (c != quoteChar) {
- if (c == '\n' || c == EOF_CHAR) {
- ungetChar(c);
- parser.addError("msg.unterminated.string.lit");
- return Token.ERROR;
- }
-
- if (c == '\\') {
- // We've hit an escaped character
- int escapeVal;
-
- c = getChar();
- switch (c) {
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
-
- // \v a late addition to the ECMA spec,
- // it is not in Java, so use 0xb
- case 'v': c = 0xb; break;
-
- case 'u':
- // Get 4 hex digits; if the u escape is not
- // followed by 4 hex digits, use 'u' + the
- // literal character sequence that follows.
- int escapeStart = stringBufferTop;
- addToString('u');
- escapeVal = 0;
- for (int i = 0; i != 4; ++i) {
- c = getChar();
- escapeVal = Kit.xDigitToInt(c, escapeVal);
- if (escapeVal < 0) {
- continue strLoop;
- }
- addToString(c);
- }
- // prepare for replace of stored 'u' sequence
- // by escape value
- stringBufferTop = escapeStart;
- c = escapeVal;
- break;
- case 'x':
- // Get 2 hex digits, defaulting to 'x'+literal
- // sequence, as above.
- c = getChar();
- escapeVal = Kit.xDigitToInt(c, 0);
- if (escapeVal < 0) {
- addToString('x');
- continue strLoop;
- } else {
- int c1 = c;
- c = getChar();
- escapeVal = Kit.xDigitToInt(c, escapeVal);
- if (escapeVal < 0) {
- addToString('x');
- addToString(c1);
- continue strLoop;
- } else {
- // got 2 hex digits
- c = escapeVal;
- }
- }
- break;
-
- case '\n':
- // Remove line terminator after escape to follow
- // SpiderMonkey and C/C++
- c = getChar();
- continue strLoop;
-
- default:
- if ('0' <= c && c < '8') {
- int val = c - '0';
- c = getChar();
- if ('0' <= c && c < '8') {
- val = 8 * val + c - '0';
- c = getChar();
- if ('0' <= c && c < '8' && val <= 037) {
- // c is 3rd char of octal sequence only
- // if the resulting val <= 0377
- val = 8 * val + c - '0';
- c = getChar();
- }
- }
- ungetChar(c);
- c = val;
- }
- }
- }
- addToString(c);
- c = getChar();
- }
-
- String str = getStringFromBuffer();
- this.string = (String)allStrings.intern(str);
- return Token.STRING;
- }
-
- switch (c) {
- case ';': return Token.SEMI;
- case '[': return Token.LB;
- case ']': return Token.RB;
- case '{': return Token.LC;
- case '}': return Token.RC;
- case '(': return Token.LP;
- case ')': return Token.RP;
- case ',': return Token.COMMA;
- case '?': return Token.HOOK;
- case ':':
- if (matchChar(':')) {
- return Token.COLONCOLON;
- } else {
- return Token.COLON;
- }
- case '.':
- if (matchChar('.')) {
- return Token.DOTDOT;
- } else if (matchChar('(')) {
- return Token.DOTQUERY;
- } else {
- return Token.DOT;
- }
-
- case '|':
- if (matchChar('|')) {
- return Token.OR;
- } else if (matchChar('=')) {
- return Token.ASSIGN_BITOR;
- } else {
- return Token.BITOR;
- }
-
- case '^':
- if (matchChar('=')) {
- return Token.ASSIGN_BITXOR;
- } else {
- return Token.BITXOR;
- }
-
- case '&':
- if (matchChar('&')) {
- return Token.AND;
- } else if (matchChar('=')) {
- return Token.ASSIGN_BITAND;
- } else {
- return Token.BITAND;
- }
-
- case '=':
- if (matchChar('=')) {
- if (matchChar('='))
- return Token.SHEQ;
- else
- return Token.EQ;
- } else {
- return Token.ASSIGN;
- }
-
- case '!':
- if (matchChar('=')) {
- if (matchChar('='))
- return Token.SHNE;
- else
- return Token.NE;
- } else {
- return Token.NOT;
- }
-
- case '<':
- /* NB:treat HTML begin-comment as comment-till-eol */
- if (matchChar('!')) {
- if (matchChar('-')) {
- if (matchChar('-')) {
- skipLine();
- continue retry;
- }
- ungetChar('-');
- }
- ungetChar('!');
- }
- if (matchChar('<')) {
- if (matchChar('=')) {
- return Token.ASSIGN_LSH;
- } else {
- return Token.LSH;
- }
- } else {
- if (matchChar('=')) {
- return Token.LE;
- } else {
- return Token.LT;
- }
- }
-
- case '>':
- if (matchChar('>')) {
- if (matchChar('>')) {
- if (matchChar('=')) {
- return Token.ASSIGN_URSH;
- } else {
- return Token.URSH;
- }
- } else {
- if (matchChar('=')) {
- return Token.ASSIGN_RSH;
- } else {
- return Token.RSH;
- }
- }
- } else {
- if (matchChar('=')) {
- return Token.GE;
- } else {
- return Token.GT;
- }
- }
-
- case '*':
- if (matchChar('=')) {
- return Token.ASSIGN_MUL;
- } else {
- return Token.MUL;
- }
-
- case '/':
- // is it a // comment?
- if (matchChar('/')) {
- skipLine();
- continue retry;
- }
- if (matchChar('*')) {
- boolean lookForSlash = false;
- for (;;) {
- c = getChar();
- if (c == EOF_CHAR) {
- parser.addError("msg.unterminated.comment");
- return Token.ERROR;
- } else if (c == '*') {
- lookForSlash = true;
- } else if (c == '/') {
- if (lookForSlash) {
- continue retry;
- }
- } else {
- lookForSlash = false;
- }
- }
- }
-
- if (matchChar('=')) {
- return Token.ASSIGN_DIV;
- } else {
- return Token.DIV;
- }
-
- case '%':
- if (matchChar('=')) {
- return Token.ASSIGN_MOD;
- } else {
- return Token.MOD;
- }
-
- case '~':
- return Token.BITNOT;
-
- case '+':
- if (matchChar('=')) {
- return Token.ASSIGN_ADD;
- } else if (matchChar('+')) {
- return Token.INC;
- } else {
- return Token.ADD;
- }
-
- case '-':
- if (matchChar('=')) {
- c = Token.ASSIGN_SUB;
- } else if (matchChar('-')) {
- if (!dirtyLine) {
- // treat HTML end-comment after possible whitespace
- // after line start as comment-utill-eol
- if (matchChar('>')) {
- skipLine();
- continue retry;
- }
- }
- c = Token.DEC;
- } else {
- c = Token.SUB;
- }
- dirtyLine = true;
- return c;
-
- default:
- parser.addError("msg.illegal.character");
- return Token.ERROR;
- }
- }
- }
-
- private static boolean isAlpha(int c)
- {
- // Use 'Z' < 'a'
- if (c <= 'Z') {
- return 'A' <= c;
- } else {
- return 'a' <= c && c <= 'z';
- }
- }
-
- static boolean isDigit(int c)
- {
- return '0' <= c && c <= '9';
- }
-
- /* As defined in ECMA. jsscan.c uses C isspace() (which allows
- * \v, I think.) note that code in getChar() implicitly accepts
- * '\r' == \u000D as well.
- */
- static boolean isJSSpace(int c)
- {
- if (c <= 127) {
- return c == 0x20 || c == 0x9 || c == 0xC || c == 0xB;
- } else {
- return c == 0xA0
- || Character.getType((char)c) == Character.SPACE_SEPARATOR;
- }
- }
-
- private static boolean isJSFormatChar(int c)
- {
- return c > 127 && Character.getType((char)c) == Character.FORMAT;
- }
-
- /**
- * Parser calls the method when it gets / or /= in literal context.
- */
- void readRegExp(int startToken)
- throws IOException
- {
- stringBufferTop = 0;
- if (startToken == Token.ASSIGN_DIV) {
- // Miss-scanned /=
- addToString('=');
- } else {
- if (startToken != Token.DIV) Kit.codeBug();
- }
-
- int c;
- while ((c = getChar()) != '/') {
- if (c == '\n' || c == EOF_CHAR) {
- ungetChar(c);
- throw parser.reportError("msg.unterminated.re.lit");
- }
- if (c == '\\') {
- addToString(c);
- c = getChar();
- }
-
- addToString(c);
- }
- int reEnd = stringBufferTop;
-
- while (true) {
- if (matchChar('g'))
- addToString('g');
- else if (matchChar('i'))
- addToString('i');
- else if (matchChar('m'))
- addToString('m');
- else
- break;
- }
-
- if (isAlpha(peekChar())) {
- throw parser.reportError("msg.invalid.re.flag");
- }
-
- this.string = new String(stringBuffer, 0, reEnd);
- this.regExpFlags = new String(stringBuffer, reEnd,
- stringBufferTop - reEnd);
- }
-
- boolean isXMLAttribute()
- {
- return xmlIsAttribute;
- }
-
- int getFirstXMLToken() throws IOException
- {
- xmlOpenTagsCount = 0;
- xmlIsAttribute = false;
- xmlIsTagContent = false;
- ungetChar('<');
- return getNextXMLToken();
- }
-
- int getNextXMLToken() throws IOException
- {
- stringBufferTop = 0; // remember the XML
-
- for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
- if (xmlIsTagContent) {
- switch (c) {
- case '>':
- addToString(c);
- xmlIsTagContent = false;
- xmlIsAttribute = false;
- break;
- case '/':
- addToString(c);
- if (peekChar() == '>') {
- c = getChar();
- addToString(c);
- xmlIsTagContent = false;
- xmlOpenTagsCount--;
- }
- break;
- case '{':
- ungetChar(c);
- this.string = getStringFromBuffer();
- return Token.XML;
- case '\'':
- case '"':
- addToString(c);
- if (!readQuotedString(c)) return Token.ERROR;
- break;
- case '=':
- addToString(c);
- xmlIsAttribute = true;
- break;
- case ' ':
- case '\t':
- case '\r':
- case '\n':
- addToString(c);
- break;
- default:
- addToString(c);
- xmlIsAttribute = false;
- break;
- }
-
- if (!xmlIsTagContent && xmlOpenTagsCount == 0) {
- this.string = getStringFromBuffer();
- return Token.XMLEND;
- }
- } else {
- switch (c) {
- case '<':
- addToString(c);
- c = peekChar();
- switch (c) {
- case '!':
- c = getChar(); // Skip !
- addToString(c);
- c = peekChar();
- switch (c) {
- case '-':
- c = getChar(); // Skip -
- addToString(c);
- c = getChar();
- if (c == '-') {
- addToString(c);
- if(!readXmlComment()) return Token.ERROR;
- } else {
- // throw away the string in progress
- stringBufferTop = 0;
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return Token.ERROR;
- }
- break;
- case '[':
- c = getChar(); // Skip [
- addToString(c);
- if (getChar() == 'C' &&
- getChar() == 'D' &&
- getChar() == 'A' &&
- getChar() == 'T' &&
- getChar() == 'A' &&
- getChar() == '[')
- {
- addToString('C');
- addToString('D');
- addToString('A');
- addToString('T');
- addToString('A');
- addToString('[');
- if (!readCDATA()) return Token.ERROR;
-
- } else {
- // throw away the string in progress
- stringBufferTop = 0;
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return Token.ERROR;
- }
- break;
- default:
- if(!readEntity()) return Token.ERROR;
- break;
- }
- break;
- case '?':
- c = getChar(); // Skip ?
- addToString(c);
- if (!readPI()) return Token.ERROR;
- break;
- case '/':
- // End tag
- c = getChar(); // Skip /
- addToString(c);
- if (xmlOpenTagsCount == 0) {
- // throw away the string in progress
- stringBufferTop = 0;
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return Token.ERROR;
- }
- xmlIsTagContent = true;
- xmlOpenTagsCount--;
- break;
- default:
- // Start tag
- xmlIsTagContent = true;
- xmlOpenTagsCount++;
- break;
- }
- break;
- case '{':
- ungetChar(c);
- this.string = getStringFromBuffer();
- return Token.XML;
- default:
- addToString(c);
- break;
- }
- }
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return Token.ERROR;
- }
-
- /**
- *
- */
- private boolean readQuotedString(int quote) throws IOException
- {
- for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
- addToString(c);
- if (c == quote) return true;
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- /**
- *
- */
- private boolean readXmlComment() throws IOException
- {
- for (int c = getChar(); c != EOF_CHAR;) {
- addToString(c);
- if (c == '-' && peekChar() == '-') {
- c = getChar();
- addToString(c);
- if (peekChar() == '>') {
- c = getChar(); // Skip >
- addToString(c);
- return true;
- } else {
- continue;
- }
- }
- c = getChar();
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- /**
- *
- */
- private boolean readCDATA() throws IOException
- {
- for (int c = getChar(); c != EOF_CHAR;) {
- addToString(c);
- if (c == ']' && peekChar() == ']') {
- c = getChar();
- addToString(c);
- if (peekChar() == '>') {
- c = getChar(); // Skip >
- addToString(c);
- return true;
- } else {
- continue;
- }
- }
- c = getChar();
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- /**
- *
- */
- private boolean readEntity() throws IOException
- {
- int declTags = 1;
- for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
- addToString(c);
- switch (c) {
- case '<':
- declTags++;
- break;
- case '>':
- declTags--;
- if (declTags == 0) return true;
- break;
- }
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- /**
- *
- */
- private boolean readPI() throws IOException
- {
- for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
- addToString(c);
- if (c == '?' && peekChar() == '>') {
- c = getChar(); // Skip >
- addToString(c);
- return true;
- }
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- private String getStringFromBuffer()
- {
- return new String(stringBuffer, 0, stringBufferTop);
- }
-
- private void addToString(int c)
- {
- int N = stringBufferTop;
- if (N == stringBuffer.length) {
- char[] tmp = new char[stringBuffer.length * 2];
- System.arraycopy(stringBuffer, 0, tmp, 0, N);
- stringBuffer = tmp;
- }
- stringBuffer[N] = (char)c;
- stringBufferTop = N + 1;
- }
-
- private void ungetChar(int c)
- {
- // can not unread past across line boundary
- if (ungetCursor != 0 && ungetBuffer[ungetCursor - 1] == '\n')
- Kit.codeBug();
- ungetBuffer[ungetCursor++] = c;
- }
-
- private boolean matchChar(int test) throws IOException
- {
- int c = getChar();
- if (c == test) {
- return true;
- } else {
- ungetChar(c);
- return false;
- }
- }
-
- private int peekChar() throws IOException
- {
- int c = getChar();
- ungetChar(c);
- return c;
- }
-
- private int getChar() throws IOException
- {
- if (ungetCursor != 0) {
- return ungetBuffer[--ungetCursor];
- }
-
- for(;;) {
- int c;
- if (sourceString != null) {
- if (sourceCursor == sourceEnd) {
- hitEOF = true;
- return EOF_CHAR;
- }
- c = sourceString.charAt(sourceCursor++);
- } else {
- if (sourceCursor == sourceEnd) {
- if (!fillSourceBuffer()) {
- hitEOF = true;
- return EOF_CHAR;
- }
- }
- c = sourceBuffer[sourceCursor++];
- }
-
- if (lineEndChar >= 0) {
- if (lineEndChar == '\r' && c == '\n') {
- lineEndChar = '\n';
- continue;
- }
- lineEndChar = -1;
- lineStart = sourceCursor - 1;
- lineno++;
- }
-
- if (c <= 127) {
- if (c == '\n' || c == '\r') {
- lineEndChar = c;
- c = '\n';
- }
- } else {
- if (isJSFormatChar(c)) {
- continue;
- }
- if (ScriptRuntime.isJSLineTerminator(c)) {
- lineEndChar = c;
- c = '\n';
- }
- }
- return c;
- }
- }
-
- private void skipLine() throws IOException
- {
- // skip to end of line
- int c;
- while ((c = getChar()) != EOF_CHAR && c != '\n') { }
- ungetChar(c);
- }
-
- final int getOffset()
- {
- int n = sourceCursor - lineStart;
- if (lineEndChar >= 0) { --n; }
- return n;
- }
-
- final String getLine()
- {
- if (sourceString != null) {
- // String case
- int lineEnd = sourceCursor;
- if (lineEndChar >= 0) {
- --lineEnd;
- } else {
- for (; lineEnd != sourceEnd; ++lineEnd) {
- int c = sourceString.charAt(lineEnd);
- if (ScriptRuntime.isJSLineTerminator(c)) {
- break;
- }
- }
- }
- return sourceString.substring(lineStart, lineEnd);
- } else {
- // Reader case
- int lineLength = sourceCursor - lineStart;
- if (lineEndChar >= 0) {
- --lineLength;
- } else {
- // Read until the end of line
- for (;; ++lineLength) {
- int i = lineStart + lineLength;
- if (i == sourceEnd) {
- try {
- if (!fillSourceBuffer()) { break; }
- } catch (IOException ioe) {
- // ignore it, we're already displaying an error...
- break;
- }
- // i recalculuation as fillSourceBuffer can move saved
- // line buffer and change lineStart
- i = lineStart + lineLength;
- }
- int c = sourceBuffer[i];
- if (ScriptRuntime.isJSLineTerminator(c)) {
- break;
- }
- }
- }
- return new String(sourceBuffer, lineStart, lineLength);
- }
- }
-
- private boolean fillSourceBuffer() throws IOException
- {
- if (sourceString != null) Kit.codeBug();
- if (sourceEnd == sourceBuffer.length) {
- if (lineStart != 0) {
- System.arraycopy(sourceBuffer, lineStart, sourceBuffer, 0,
- sourceEnd - lineStart);
- sourceEnd -= lineStart;
- sourceCursor -= lineStart;
- lineStart = 0;
- } else {
- char[] tmp = new char[sourceBuffer.length * 2];
- System.arraycopy(sourceBuffer, 0, tmp, 0, sourceEnd);
- sourceBuffer = tmp;
- }
- }
- int n = sourceReader.read(sourceBuffer, sourceEnd,
- sourceBuffer.length - sourceEnd);
- if (n < 0) {
- return false;
- }
- sourceEnd += n;
- return true;
- }
-
- // stuff other than whitespace since start of line
- private boolean dirtyLine;
-
- String regExpFlags;
-
- // Set this to an inital non-null value so that the Parser has
- // something to retrieve even if an error has occured and no
- // string is found. Fosters one class of error, but saves lots of
- // code.
- private String string = "";
- private double number;
-
- private char[] stringBuffer = new char[128];
- private int stringBufferTop;
- private ObjToIntMap allStrings = new ObjToIntMap(50);
-
- // Room to backtrace from to < on failed match of the last - in <!--
- private final int[] ungetBuffer = new int[3];
- private int ungetCursor;
-
- private boolean hitEOF = false;
-
- private int lineStart = 0;
- private int lineno;
- private int lineEndChar = -1;
-
- private String sourceString;
- private Reader sourceReader;
- private char[] sourceBuffer;
- private int sourceEnd;
- private int sourceCursor;
-
- // for xml tokenizer
- private boolean xmlIsAttribute;
- private boolean xmlIsTagContent;
- private int xmlOpenTagsCount;
-
- private Parser parser;
-}