Commit eb3c1ab9 by Christine Lytwynec

removing rake and outdated references to it

parent 44c41020
source 'https://rubygems.org'
gem 'rake', '~> 10.0.3'
gem 'sass', '3.3.5'
gem 'bourbon', '~> 4.0.2'
gem 'neat', '~> 1.6.0'
......
......@@ -13,7 +13,6 @@ GEM
neat (1.6.0)
bourbon (>= 3.1)
sass (>= 3.3)
rake (10.0.4)
rb-fsevent (0.9.3)
rb-inotify (0.9.2)
ffi (>= 0.5.0)
......@@ -30,7 +29,6 @@ DEPENDENCIES
dalli (~> 2.6.4)
launchy (~> 2.1.2)
neat (~> 1.6.0)
rake (~> 10.0.3)
rb-fsevent (~> 0.9.3)
rb-inotify (~> 0.9)
sass (= 3.3.5)
......
......@@ -64,7 +64,7 @@ CONTENTSTORE = {
}
}
# Set this up so that rake lms[acceptance] and running the
# Set this up so that 'paver cms --settings=acceptance' and running the
# harvest command both use the same (test) database
# which they can flush without messing up your dev db
DATABASES = {
......
......@@ -3,7 +3,7 @@ unittests for xmodule
Run like this:
rake test_common/lib/xmodule
paver test_lib -l common/lib/xmodule
"""
......
......@@ -147,7 +147,7 @@ Caveats and Warnings
Next, run the commands::
rake i18n:generate
paver i18n_generate
python i18n/verify.py
This will generate reports of broken translations in your language. This will not, however,
......
......@@ -15,7 +15,7 @@ we can ensure that pull requests have a very high percentage of test coverage
To check the coverage of your pull request, just go to the top level of the
edx-platform codebase and run::
$ rake coverage
$ paver coverage
This will print a coverage report for your branch. We aim for
a coverage report score of 95% or higher. We also encourage you to write
......
......@@ -20,8 +20,8 @@ edx-platform codebase and run::
$ paver run_quality
Note: The rake commands ``rake quality``, ``rake pep8``, and ``rake pylint`` are now deprecated
to ``paver run_quality``, ``paver run_pep8``, and ``paver run_pylint`` respectively.
You can also use the `paver run_pep8`` and ``paver run_pylint`` commands to run just pep8 or
pylint.
This will print a report of the quality violations that your branch has made.
......
......@@ -36,8 +36,8 @@ Connect to the Devstack Virtual Machine
sudo su edxapp
This command loads the edxapp environment from the file
``/edx/app/edxapp/edxapp_env``. This puts ``venv python``, ``rbenv ruby`` and
``rake`` are in your search path.
``/edx/app/edxapp/edxapp_env``. This puts ``venv python`` and ``rbenv ruby``
in your search path.
This command also sets the current working directory to the edx-platform
repository (``/edx/app/edxapp/edx-platform``).
......
......@@ -4,9 +4,8 @@
### Ruby
To install all of the libraries needed for our rake commands, run `bundle install`.
To install all of the required ruby libraries, run `bundle install`.
This will read the `Gemfile` and install all of the gems specified there.
Note: Rake has been deprecated to the Python Paver. This is only needed until rake is fully deprecated
### Python
......
......@@ -223,7 +223,7 @@ To run JavaScript tests in your default browser:
paver test_js_dev -s common
These rake commands call through to a custom test runner. For more info, see [js-test-tool](https://github.com/edx/js-test-tool).
These paver commands call through to a custom test runner. For more info, see [js-test-tool](https://github.com/edx/js-test-tool).
### Running Bok Choy Acceptance Tests
......@@ -287,7 +287,7 @@ installed to run the tests in Chrome. The tests are confirmed to run
with Chrome (not Chromium) version 34.0.1847.116 with ChromeDriver version 2.6.232917.
To run all the acceptance tests:
rake test:acceptance
paver test_acceptance
To run only for lms or cms:
......@@ -309,7 +309,7 @@ To start the debugger on failure, add the `--pdb` option to extra_args:
To run tests faster by not collecting static files, you can use
`paver test_acceptance -s lms --fasttest` and `paver test_acceptance -s cms --fasttest`.
Acceptance tests will run on a randomized port and can be run in the background of rake cms and lms or unit tests.
Acceptance tests will run on a randomized port and can be run in the background of paver cms and lms or unit tests.
To specify the port, change the LETTUCE_SERVER_PORT constant in cms/envs/acceptance.py and lms/envs/acceptance.py
as well as the port listed in cms/djangoapps/contentstore/feature/upload.py
......
......@@ -57,7 +57,7 @@ CONTENTSTORE = {
}
}
# Set this up so that rake lms[acceptance] and running the
# Set this up so that 'paver lms --settings=acceptance' and running the
# harvest command both use the same (test) database
# which they can flush without messing up your dev db
DATABASES = {
......
begin
require 'json'
require 'rake/clean'
require './rakelib/helpers.rb'
rescue LoadError => error
puts "Import failed (#{error})"
puts "Please run `bundle install` to bootstrap ruby dependencies"
exit 1
end
# Build Constants
REPO_ROOT = File.dirname(__FILE__)
ENV_ROOT = File.dirname(REPO_ROOT)
REPORT_DIR = File.join(REPO_ROOT, "reports")
# Environment constants
SERVICE_VARIANT = ENV['SERVICE_VARIANT']
CONFIG_PREFIX = SERVICE_VARIANT ? SERVICE_VARIANT + "." : ""
ENV_FILE = File.join(ENV_ROOT, CONFIG_PREFIX + "env.json")
ENV_TOKENS = File.exists?(ENV_FILE) ? JSON.parse(File.read(ENV_FILE)) : {}
task :default => [:test, :pep8, :pylint]
# acceptance test tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by, *args)
task deprecated, [:harvest_args] do |t,args|
# Need to install paver dependencies for the commands to work!
sh("pip install -r requirements/edx/paver.txt")
args.with_defaults(:harvest_args => nil)
new_cmd = deprecated_by
if !args.harvest_args.nil?
new_cmd = "#{new_cmd} --extra_args='#{args.harvest_args}'"
end
puts("Task #{deprecated} has been deprecated. Use #{new_cmd} instead.".red)
sh(new_cmd)
end
end
deprecated("test:acceptance", "paver test_acceptance")
deprecated("test:acceptance:cms", "paver test_acceptance -s cms")
deprecated("test:acceptance:cms:fast", "paver test_acceptance -s cms --fasttest")
deprecated("test:acceptance:lms", "paver test_acceptance -s lms")
deprecated("test:acceptance:lms:fast", "paver test_acceptance -s lms --fasttest")
# assets tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by, *args)
task deprecated, [:system, :env] do |t,args|
# Need to install paver dependencies for the commands to work!
sh("pip install -r requirements/edx/paver.txt")
args.with_defaults(:system => "lms", :env => "dev")
if deprecated_by.nil?
puts("Task #{deprecated} has been deprecated.".red)
else
if deprecated.include? "gather_assets"
new_cmd = deprecated_by
else
new_cmd = deprecated_by + " #{args.system} --settings=#{args.env}"
end
puts("Task #{deprecated} has been deprecated. Use #{new_cmd} instead.".red)
sh(new_cmd)
end
end
end
deprecated("assets:coffee", "paver update_assets --skip-collect")
deprecated("assets:coffee:clobber", nil)
deprecated("assets:coffee:debug", "paver update_assets --debug")
deprecated("assets:coffee:watch", "paver update_assets")
deprecated("assets:sass", "paver update_assets")
deprecated("assets:sass:debug", "paver update_assets --debug")
deprecated("assets:sass:watch", "paver update_assets")
deprecated("assets:xmodule", "paver update_assets")
deprecated("assets:xmodule:debug", "paver update_assets --debug")
deprecated("assets:xmodule:watch", "paver update_assets")
deprecated("assets:debug", "paver update_assets --debug")
deprecated("assets:watch", "paver update_assets")
deprecated("assets", "paver update_assets")
[:lms, :cms].each do |system|
deprecated("#{system}:gather_assets", "paver update_assets #{system}")
environments(system).each do |env|
deprecated("#{system}:gather_assets:#{env}", "paver update_assets #{system} --settings=#{env}")
end
end
# test tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by, *args)
task deprecated, [:test_spec] do |t,args|
args.with_defaults(:test_spec => nil)
new_cmd = "#{deprecated_by}"
if !args.test_spec.nil?
new_cmd = "#{new_cmd} -t #{args.test_spec}"
end
puts("Task #{deprecated} has been deprecated. Using #{new_cmd} instead.".red)
sh(new_cmd)
end
end
deprecated('test:bok_choy', 'paver test_bokchoy')
deprecated('test:bok_choy:coverage', 'paver bokchoy_coverage')
deprecated('test:bok_choy:fast', 'paver test_bokchoy --fasttest')
deprecated('test:bok_choy:setup', 'paver test_bokchoy')
require 'colorize'
def deprecated(deprecated, deprecated_by, *args)
task deprecated do
if args.length > 0 then
args_str = args.join(',')
new_cmd = "#{deprecated_by}[#{args_str}]"
else
new_cmd = deprecated_by
end
puts("Task #{deprecated} has been deprecated. Use #{new_cmd} instead. Waiting 5 seconds...".red)
sleep(5)
Rake::Task[deprecated_by].invoke(*args)
end
end
[:lms, :cms].each do |system|
deprecated("browse_jasmine_#{system}", "test:js:dev", system)
deprecated("phantomjs_jasmine_#{system}", "test:js:run", system)
deprecated("jasmine:#{system}", "test:js:run", system)
deprecated("jasmine:#{system}:browser", "test:js:dev", system)
deprecated("jasmine:#{system}:browser:watch", "test:js:dev", system)
deprecated("jasmine:#{system}:phantomjs", "test:js:run", system)
deprecated("#{system}:check_settings:jasmine", "")
deprecated("#{system}:gather_assets:jasmine", "")
deprecated("test_acceptance_#{system}", "test:acceptance:#{system}")
deprecated("fasttest_acceptance_#{system}", "test:acceptance:#{system}:fast")
end
Dir["common/lib/*"].select{|lib| File.directory?(lib)}.each do |lib|
if lib == 'common/lib/xmodule' then
deprecated("browse_jasmine_#{lib}", "test:js:dev", "xmodule")
deprecated("phantomjs_jasmine_#{lib}", "test:js:run", "xmodule")
else
deprecated("browse_jasmine_#{lib}", "test:js:dev")
deprecated("phantomjs_jasmine_#{lib}", "test:js:run")
end
end
deprecated("browse_jasmine_discussion", "test:js:dev", "common")
deprecated("phantomjs_jasmine_discussion", "test:js:run", "common")
deprecated("jasmine:common/lib/xmodule", "test:js:run", "xmodule")
deprecated("jasmine:common/lib/xmodule:browser", "test:js:dev", "xmodule")
deprecated("jasmine:common/lib/xmodule:phantomjs", "test:js:run", "xmodule")
deprecated("jasmine:common/static/coffee", "test:js:run", "common")
deprecated("jasmine:common/static/coffee:browser", "test:js:dev", "common")
deprecated("jasmine:common/static/coffee:phantomjs", "test:js:run", "common")
deprecated("jasmine", "test:js")
deprecated("jasmine:phantomjs", "test:js:run")
deprecated("jasmine:browser", "test:js:dev")
deprecated("test_acceptance", "test:acceptance")
# devstack tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by, *args)
task deprecated, [:system] do |t,args|
# Need to install paver dependencies for the commands to work!
sh("pip install -r requirements/edx/paver.txt")
args.with_defaults(:system => 'lms')
deprecated_by = "#{deprecated_by} #{args.system}"
puts("Task #{deprecated} has been deprecated. Use #{deprecated_by} instead. Waiting 5 seconds...".red)
sleep(5)
sh(deprecated_by)
exit
end
end
deprecated("devstack:start", "paver devstack --fast")
deprecated("devstack:assets", "paver update_assets --settings=devstack")
deprecated("devstack:install", "paver install_prereqs")
deprecated("devstack", "paver devstack")
# django assets tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by)
task deprecated, [:arg1, :arg2, :arg3, :arg4] do |t,args|
# Need to install paver dependencies for the commands to work!
sh("pip install -r requirements/edx/paver.txt")
if deprecated == "cms" or deprecated == "lms"
args.with_defaults(:arg1 => "dev", :arg2 => "")
port = args.arg2 == "" ? "" : "--port=#{args.arg2}"
new_cmd = deprecated_by + " --settings=#{args.arg1} #{port}"
else
new_cmd = deprecated_by
end
puts("Task #{deprecated} has been deprecated. Use #{new_cmd} instead. Waiting 5 seconds...".red)
sleep(5)
sh(new_cmd)
exit
end
end
deprecated('lms','paver lms')
deprecated('fastlms', 'paver lms --fast')
deprecated('cms','paver studio')
deprecated('fastcms', 'paver studio --fast')
deprecated('cms:clone', 'python manage.py cms -h')
deprecated('cms:delete_course', 'python manage.py cms -h')
deprecated('cms:export', 'python manage.py cms -h')
deprecated('cms:import', 'python manage.py cms -h')
deprecated('cms:xlint', 'python manage.py cms -h')
deprecated('set_staff', 'python manage.py cms -h')
deprecated("django-admin", "python manage.py -h")
deprecated("resetdb", "paver update_db")
[:lms, :cms].each do |system|
deprecated("#{system}:resetdb", "paver update_db")
deprecated("#{system}_worker", "paver celery")
environments(system).each do |env|
deprecated("#{system}:resetdb:#{env}", "paver update_db")
deprecated("#{system}:#{env}", "paver #{system} --settings=#{env}")
deprecated("#{system}:check_settings:#{env}", "paver check_settings #{system} #{env}")
end
end
# doc tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by)
task deprecated, [:type, :quiet] do |t,args|
# Need to install paver dependencies for the commands to work!
sh("pip install -r requirements/edx/paver.txt")
args.with_defaults(:quiet => "quiet")
new_cmd = [deprecated_by]
if args.quiet == 'verbose' and deprecated == 'builddocs'
new_cmd << '--verbose'
end
if not args.type.nil?
new_cmd << "--type=#{args.type}"
end
new_cmd = new_cmd.join(" ")
puts("Task #{deprecated} has been deprecated. Use \"#{new_cmd}\" instead. Waiting 5 seconds...".red)
sleep(5)
sh(new_cmd)
end
end
deprecated('builddocs','paver build_docs')
deprecated('showdocs','paver build_docs')
deprecated('doc','paver build_docs')
require 'digest/md5'
require 'sys/proctable'
require 'colorize'
require 'timeout'
require 'net/http'
def django_admin(system, env, command, *args)
return "./manage.py #{system} --settings #{env} #{command} --traceback #{args.join(' ')}"
end
def report_dir_path(dir)
return File.join(REPORT_DIR, dir.to_s)
end
def compute_fingerprint(files, dirs)
digest = Digest::MD5.new()
# Digest the contents of all the files.
Dir[*files].select{|file| File.file?(file)}.each do |file|
digest.file(file)
end
# Digest the names of the files in all the dirs.
dirs.each do |dir|
file_names = Dir.entries(dir).sort.join(" ")
digest.update(file_names)
end
digest.hexdigest
end
# Hash the contents of all the files, and the names of files in the dirs.
# Run the block if they've changed.
def when_changed(unchanged_message, files, dirs=[])
Rake::Task[PREREQS_MD5_DIR].invoke
cache_file = File.join(PREREQS_MD5_DIR, files[0].gsub(/\W+/, '-').sub(/-+$/, '')) + '.md5'
if !File.exists?(cache_file) or compute_fingerprint(files, dirs) != File.read(cache_file)
yield
File.write(cache_file, compute_fingerprint(files, dirs))
elsif !unchanged_message.empty?
puts unchanged_message
end
end
# Runs Process.spawn, and kills the process at the end of the rake process
# Expects the same arguments as Process.spawn
def background_process(command, logfile=nil)
spawn_opts = {:pgroup => true}
if !logfile.nil?
puts "Running '#{command.join(' ')}', redirecting output to #{logfile}"
spawn_opts[[:err, :out]] = [logfile, 'a']
end
pid = Process.spawn({}, *command, spawn_opts)
command = [*command]
at_exit do
pgid = Process.getpgid(pid)
begin
Timeout.timeout(5) do
Process.kill(:SIGINT, -pgid)
Process.wait(-pgid)
end
rescue Timeout::Error
begin
Timeout.timeout(5) do
Process.kill(:SIGTERM, -pgid)
Process.wait(-pgid)
end
rescue Timeout::Error
Process.kill(:SIGKILL, -pgid)
Process.wait(-pgid)
end
end
end
end
# Runs a command as a background process, as long as no other processes
# tagged with the same tag are running
def singleton_process(command, logfile=nil)
command = [*command]
if Sys::ProcTable.ps.select {|proc| proc.cmdline.include?(command.join(' '))}.empty?
background_process(command, logfile)
else
puts "Process '#{command.join(' ')} already running, skipping".blue
end
end
# Wait for a server to respond with status 200 at "/"
def wait_for_server(server, port)
attempts = 0
begin
http = Net::HTTP.start(server, port, {open_timeout: 10, read_timeout: 10})
response = http.head("/")
response.code == "200"
true
rescue
sleep(1)
attempts += 1
if attempts < 20
retry
else
false
end
end
end
def environments(system)
Dir["#{system}/envs/**/*.py"].select{|file| ! (/__init__.py$/ =~ file)}.map do |env_file|
env_file.gsub("#{system}/envs/", '').gsub(/\.py/, '').gsub('/', '.')
end
end
$failed_tests = []
# Run sh on args. If TESTS_FAIL_FAST is set, then stop on the first shell failure.
# Otherwise, a final task will be added that will fail if any tests have failed
def test_sh(name, *args)
puts("\n=======================================".green)
puts("Running #{name} tests".green)
puts("=======================================".green)
sh(*args) do |ok, res|
if ok
return
end
if ENV['TESTS_FAIL_FAST']
fail("Test failed!")
else
$failed_tests << name
end
end
puts("\n=======================================\n".green)
end
# Add a task after all other tasks that fails if any tests have failed
if !ENV['TESTS_FAIL_FAST']
task :fail_tests do
if $failed_tests.length > 0
puts("=======================================".red)
puts("Tests failed in these test suites:".red)
$failed_tests.each do |test|
puts("* #{test}".red)
end
exit 1
end
end
Rake.application.top_level_tasks << :fail_tests
end
# Internationalization tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by, *args)
task deprecated do
# Need to install paver dependencies for the commands to work!
sh("pip install -r requirements/edx/paver.txt")
new_cmd = deprecated_by
puts("Task #{deprecated} has been deprecated. Using #{deprecated_by} instead.".red)
sh(new_cmd)
exit
end
end
deprecated("i18n:extract", "paver i18n_extract")
deprecated("i18n:generate", "paver i18n_generate")
deprecated("i18n:generate_strict", "paver i18n_generate_strict")
deprecated("i18n:dummy", "paver i18n_dummy")
deprecated("i18n:validate:gettext", "paver i18n_validate_gettext")
deprecated("i18n:validate:transifex_config", "paver i18n_validate_transifex_config")
deprecated("i18n:transifex:push", "paver i18n_transifex_push")
deprecated("i18n:transifex:pull", "paver i18n_transifex_pull")
deprecated("i18n:robot:push", "paver i18n_robot_push")
deprecated("i18n:robot:pull", "paver i18n_robot_pull")
# js_test tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by, *args)
task deprecated, [:env] do |t,args|
args.with_defaults(:env => nil)
new_cmd = "#{deprecated_by}"
if !args.env.nil?
new_cmd = "#{new_cmd} --suite=#{args.env}"
end
puts("Task #{deprecated} has been deprecated. Using #{new_cmd} instead.".red)
sh(new_cmd)
end
end
# deprecates all js_test.rake tasks
deprecated('test:js', 'paver test_js')
deprecated('test:js:coverage', 'paver test_js -c')
deprecated('test:js:dev', 'paver test_js_dev')
deprecated('test:js:run', 'paver test_js_run')
# prereqs tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by)
task deprecated do
# Need to install paver dependencies for the commands to work!
sh("pip install -r requirements/edx/paver.txt")
puts("Task #{deprecated} has been deprecated. Use #{deprecated_by} instead.".red)
sh(deprecated_by)
end
end
deprecated('install_prereqs','paver install_prereqs')
deprecated('install_node_prereqs','paver install_node_prereqs')
deprecated('install_ruby_prereqs','paver install_ruby_prereqs')
deprecated('install_python_prereqs','paver install_python_prereqs')
# quality tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by)
task deprecated do
# Need to install paver dependencies for the commands to work!
sh("pip install -r requirements/edx/paver.txt")
if deprecated.include? "extract" and ARGV.last.downcase == 'extract'
new_cmd = deprecated_by + " --extract"
else
new_cmd = deprecated_by
end
puts("Task #{deprecated} has been deprecated. Use #{deprecated_by} instead.".red)
sh(new_cmd)
exit
end
end
deprecated("pep8:cms", "paver run_pep8 --system=cms")
deprecated("pep8:lms", "paver run_pep8 --system=lms")
deprecated("pep8:common", "paver run_pep8 --system=common")
deprecated("pep8", "paver run_pep8")
deprecated("pylint:cms", "paver run_pylint --system=cms")
deprecated("pylint:lms", "paver run_pylint --system=lms")
deprecated("pylint:common", "paver run_pylint --system=common")
deprecated("pylint", "paver run_pylint")
deprecated("pylint:cms:errors", "paver run_pylint --system=cms --errors")
deprecated("pylint:lms:errors", "paver run_pylint --system=lms --errors")
deprecated("pylint:common:errors", "paver run_pylint --system=common --errors")
deprecated("pylint:errors", "paver run_pylint --errors")
deprecated("quality", "paver run_quality")
# test tasks deprecated to paver
require 'colorize'
def deprecated(deprecated, deprecated_by, use_id, *args)
task deprecated, [:test_id] do |t,args|
args.with_defaults(:test_id => nil)
new_cmd = "#{deprecated_by}"
if !args.test_id.nil? && use_id
new_cmd = "#{new_cmd} --test_id=#{args.test_id}"
end
puts("Task #{deprecated} has been deprecated. Using #{new_cmd} instead.".red)
sh(new_cmd)
end
end
# deprecates all test.rake tasks
deprecated("test", "paver test", false)
deprecated('test:python', 'paver test_python', false)
deprecated("test_cms", "paver test_system -s cms", true)
deprecated("test_lms", "paver test_system -s lms", true)
deprecated("fasttest_cms", "paver test_system -s cms --fasttest", true)
deprecated("fasttest_lms", "paver test_system -s lms --fasttest", true)
Dir["common/lib/*"].select{|lib| File.directory?(lib)}.each do |lib|
deprecated("test_#{lib}", "paver test_lib --lib=#{lib}", true)
deprecated("fasttest_#{lib}", "paver test_lib --lib=#{lib}", true)
end
deprecated("coverage", "paver coverage", false)
deprecated("clean_reports_dir", "paver clean_reports_dir", false)
deprecated("clean_test_files", "paver clean_test_files", false)
deprecated("test:clean_mongo", "paver clean_mongo", false)
# acceptance tests deprecated to paver
require 'colorize'
task :'ws:migrate' do
puts "Task ws:migrate has been deprecated".red
end
......@@ -74,4 +74,4 @@ fi
# Activate the Python virtualenv
source $HOME/edx-venv/bin/activate
rake test:acceptance:${TEST_SUITE}["-v 3 ${FEATURE_PATH}"]
paver test_acceptance -s ${TEST_SUITE} --extra_args="-v 3 ${FEATURE_PATH}"
......@@ -37,7 +37,7 @@ class DjangoEventHandler(FileSystemEventHandler):
break
if __name__ == "__main__":
event_handler = DjangoEventHandler(Popen(['rake', 'lms']))
event_handler = DjangoEventHandler(Popen(['paver', 'lms']))
observer = Observer()
for dir in WATCH_DIRS:
observer.schedule(event_handler, dir, recursive=True)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment