Giter Site home page Giter Site logo

mit-lcp / physionet-build Goto Github PK

View Code? Open in Web Editor NEW
54.0 17.0 20.0 86.13 MB

The new PhysioNet platform.

Home Page: https://physionet.org/

License: BSD 3-Clause "New" or "Revised" License

Python 12.09% CSS 0.51% HTML 6.98% JavaScript 63.02% Makefile 0.84% Prolog 0.14% Smarty 0.22% C 5.72% Shell 0.47% Roff 3.37% TeX 3.22% Perl 0.33% PostScript 1.59% sed 0.05% Dockerfile 0.01% SCSS 1.45%
physionet

physionet-build's Introduction

PhysioNet Build

The new PhysioNet platform built using Django. The new site is currently hosted at https://physionet.org/

Running Local Instance Using Django Server

  • Install sqlite3: sudo apt-get install sqlite3.
  • Create python environment with >=python 3.8.
  • Activate virtual python environment.
  • Install python packages in requirements.txt.
  • Copy .env.example file to .env.
  • Within the physionet-django directory:
    • Run: python manage.py resetdb to reset the database.
    • Run: python manage.py loaddemo to load the demo fixtures set up example files.
    • Run: python manage.py runserver to run the server.

The local development server will be available at http://localhost:8000.

Running Local Instance Using Docker

  • Install docker: https://docs.docker.com/engine/install/.
  • Copy the example config: cp .env.example .env.
  • Build the physionet image: docker-compose build.
  • Run docker-compose up to run the postgres database, development and test containers.
  • In a separate shell:
    • Run: docker-compose exec dev /bin/bash to enter the development container shell.
    • Within the physionet-django directory:
      • Run: python manage.py resetdb to reset the database.
      • Run: python manage.py loaddemo to load the demo fixtures set up example files.
    • Run: docker-compose exec test /bin/bash to enter the test container shell.
    • Within the physionet-django directory:
      • Run: python manage.py resetdb to reset the database.
      • Run: python manage.py loaddemo to load the demo fixtures set up example files.
      • Run: python manage.py test to run the tests.

The local development server will be available at http://localhost:8000.

All the management commands should be executed inside the desired container (with docker-compose exec dev /bin/bash/ or docker-compose exec test /bin/bash).

The code should dynamically reload in development, however, if there are any issues you can stop the docker-compose up command and run docker-compose up --build which will rebuild the physionet image.

Docker-compose uses volumes to persist the database contents and data directories (media and static files). To clean up the created containers, networks and volumes stop docker-compose up and run docker-compose down -v. Do not run docker-compose down -v if you want to retain current database contents.

Background tasks

Background tasks are managed by Django Q2, "a native Django task queue, scheduler and worker application using Python multiprocessing".

If you would like to run background tasks on your development server, you will need to start the task manager with python manage.py qcluster

Using a debugger with Docker

To access a debug prompt raised using breakpoint():

  • Run docker container ls to get a list of active containers
  • Find the "CONTAINER_ID" for the dev_1 container
  • In a new shell, attach to the container with docker attach CONTAINER_ID

The debugger should now be available in the new shell.

  • To detach from the container, press "Control+p, "Control+q" in a sequence. Note: "Control+c" will stop the container dev_1.

Contribution Guidelines

  • Familiarise yourself with the PEP8 style guidelines.
  • Create a branch originating from the dev branch, titled after the new feature/change to be implemented.
  • Write tests for your code where possible (see "Testing" section below). Confirm that all tests pass before making a pull request.
  • If you create or alter any models or fields, you'll need to generate one or more accompanying migration scripts. Commit these scripts alongside your other changes.
  • Make a pull request to the dev branch with a clear title and description of the changes. Tips for a good pull request: http://blog.ploeh.dk/2015/01/15/10-tips-for-better-pull-requests/

Testing

If using docker, all of the commands should run inside the test container (docker-compose exec test /bin/bash). You may need to pip install coverage beforehand if not using docker.

  • Unit tests for each app are kept in their test*.py files.
  • To run the unit tests, change to the physionet-django directory and run python manage.py test.
  • To check test coverage, change to the physionet-django directory and run coverage run --source='.' manage.py test. Next run coverage html to generate an html output of the coverage results.
  • To check code style, change to the physionet-django directory and run flake8 [PATH_TO_FILE(s)]. As part of the physionet-build-test workflow, flake8 will be run only against modified code relative to dev or the base PR branch. Note: flake8 is only installed in the workflow. To install it for local testing, see here.
  • To run the browser tests in the test_browser.py files, selenium and the firefox driver are required. If you want to see the test run in your browser, remove the options.set_headless(True) lines in the setUpClass of the browser testing modules.

Database Content During Development

During development, the following workflow is applied for convenience:

  • The database engine is sqlite3 if not using docker. The db.sqlite3 file will not be tracked by git, and hence will not be uploaded and shared between developers
  • Demo model instances will be specified in json files in the fixtures subdirectory of each app. Example file: <BASE_DIR>/<appname>/fixtures/demo-<appname>.json

To conveniently obtain a clean database with the latest applied migrations, run:python manage.py resetdb. This does not populate the database with any data.

When using docker, the migrated and empty database will be the default state and only python manage.py loaddemo has to be called in both dev and test containers.

Creating a branch with migrations

If you need to add, remove, or modify any models or fields, your branch will also need to include the necessary migration script(s). In most cases, Django can generate these scripts for you automatically, but you should still review them to be sure that they are doing what you intend.

After making a change (such as adding a field or changing options), run ./manage.py makemigrations to generate a corresponding migration script. Then run ./manage.py migrate to run that script on your local sqlite database.

If you make changes and later decide to undo them without committing, the easiest way is to simply run rm */migrations/*.py && git checkout */migrations to revert to your current HEAD. Then run ./manage.py makemigrations again if necessary, followed by ./manage.py resetdb && ./manage.py loaddemo.

If other migrations are committed to dev in the meantime, you will need to resolve the resulting conflicts before your feature branch can be merged back into dev. There are two ways to do this:

Merging migrations

If the two sets of changes are independent, they can be combined by merging dev into the feature branch and adding a "merge migration":

  • git checkout my-new-feature && git pull && rm */migrations/*.py && git checkout */migrations
  • git merge --no-ff --no-commit origin/dev
  • ./manage.py makemigrations --merge The latter command will ask you to confirm that the changes do not conflict (it will not detect conflicts automatically.) Read the list of changes carefully before answering. If successful, you can then run:
  • ./manage.py migrate && ./manage.py test
  • git add */migrations/ && git commit As with any pull request, have someone else review your changes before merging the result back into dev.

Rebasing migrations

If the migration behavior interacts with other changes that have been applied to dev in the meantime, the migration scripts will need to be rewritten.

  • Either rebase the feature branch onto origin/dev, or merge origin/dev into the feature branch.
  • Roll back migrations by running rm */migrations/*.py; git checkout origin/dev */migrations
  • Generate new migrations by running ./manage.py makemigrations
  • ./manage.py migrate && ./manage.py test
  • git add */migrations/ && git commit

Theming instructions

The theme of the deployed website can be configured by changing the following environment variables:

  • DARK
  • PRIMARY
  • SECONDARY
  • SUCCESS
  • INFO
  • WARNING
  • DANGER
  • LIGHT

The management command "compilestatic" generates a theme.scss file and compiles the following CSS files.

  • static/custom/css/home.css
  • static/bootstrap/css/bootstrap.css

Note: The css files above are not tracked by git and are generated only when you run compilestatic command.

Setting Up Cronjobs

If you want to setup cronjobs, you can do that by adding a new file or update the existing cronjobs file based on your requirements.

Here are the loations where you might want to add your cronjobs.

  1. deploy/common/etc/cron.d/

  2. deploy/staging/etc/cron.d/ (For cronjobs that should run on staging environment)

  3. deploy/production/etc/cron.d/ (For cronjobs that should run on production environment)

Here is an example of existing cronjob from deploy/production/etc/cron.d/physionet:

31 23 * * *  www-data  env DJANGO_SETTINGS_MODULE=physionet.settings.production /physionet/python-env/physionet/bin/python3 /physionet/physionet-build/physionet-django/manage.py clearsessions

Package management

pyproject.toml is the primary record of dependencies. This file is typically used by pip for package management. Dependencies are also tracked in pyproject.toml and requirements.txt.

The process for updating packages is:

  1. Add the dependency to pyproject.toml
  2. Generate a new poetry.lock file with: poetry lock --no-update
  3. Generate a new requirements.txt with: poetry export -f requirements.txt --output requirements.txt --with dev

physionet-build's People

Contributors

adrianryt avatar alistairewj avatar amitupreti avatar bemoody avatar briangow avatar chrystinne avatar cx1111 avatar danamouk avatar dependabot[bot] avatar elfeto avatar fiedosiukr avatar grzegorz-wcislo avatar harryface avatar hsaeedx avatar kepaik avatar kpiercehst avatar kshalot avatar lamawmouk avatar lbulgarelli avatar li-lcp avatar lucas-mc avatar marcinjosinski avatar mira-mm avatar mscanlan-git avatar rafalkosla101 avatar rutvikrj26 avatar shulim avatar sichengh avatar tompollard avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

physionet-build's Issues

Project random url generator

When you create the projects, the url should be a hash or a UID, not the ID of the project, the ID of the project is a auto increment number, which will tell how many projects there are.

Email features/enhancements/gotchas

Potential things to consider down the line

  • Gmail extra dots make emails unique.
  • Show unverified emails
  • Put the form functions in a more compact interface. ie. in that top card panel, implement multiple functionalities:
    • make public
    • make primary
    • delete

Versions and DOIs

Put DOI field in PublishedProject so that there's one for each version, and remove it from BaseProject.

resetdbs.py: OperationalError: Problem installing fixtures: no such column: REFERRED.id

Running the following command:

 python manage.py shell < resetdbs.py

raises an error:

In [14]: Operations to perform:
  Apply all migrations: admin, auth, contenttypes, project, sessions, user
Running migrations:
  Applying user.0001_initial... OK
  Applying contenttypes.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0001_initial... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying project.0001_initial... OK
  Applying sessions.0001_initial... OK
  Applying user.0002_auto_20170921_2056... OK
  Applying user.0003_auto_20170929_1459... OK

In [15]: 
In [15]: 
In [16]: 
In [17]: 
In [18]: 
In [19]: 
In [19]: 
In [20]:     ...:     ...:     ...:     ...: Installed 3 object(s) from 1 fixture(s)
---------------------------------------------------------------------------
OperationalError                          Traceback (most recent call last)
<ipython-input-20-4b0c042487be> in <module>()
      2     app_fixtures_dir = os.path.join(settings.BASE_DIR, app, 'fixtures')
      3     if os.path.isdir(app_fixtures_dir) and os.path.isfile(os.path.join(app_fixtures_dir, app+'.json')):
----> 4         execute_from_command_line(['manage.py', 'loaddata', app])
      5 

/usr/local/lib/python2.7/site-packages/django/core/management/__init__.pyc in execute_from_command_line(argv)
    365     """
    366     utility = ManagementUtility(argv)
--> 367     utility.execute()

/usr/local/lib/python2.7/site-packages/django/core/management/__init__.pyc in execute(self)
    357             sys.stdout.write(self.main_help_text() + '\n')
    358         else:
--> 359             self.fetch_command(subcommand).run_from_argv(self.argv)
    360 
    361 

/usr/local/lib/python2.7/site-packages/django/core/management/base.pyc in run_from_argv(self, argv)
    292         handle_default_options(options)
    293         try:
--> 294             self.execute(*args, **cmd_options)
    295         except Exception as e:
    296             if options.traceback or not isinstance(e, CommandError):

/usr/local/lib/python2.7/site-packages/django/core/management/base.pyc in execute(self, *args, **options)
    343             if self.requires_migrations_checks:
    344                 self.check_migrations()
--> 345             output = self.handle(*args, **options)
    346             if output:
    347                 if self.output_transaction:

/usr/local/lib/python2.7/site-packages/django/core/management/commands/loaddata.pyc in handle(self, *fixture_labels, **options)
     62 
     63         with transaction.atomic(using=self.using):
---> 64             self.loaddata(fixture_labels)
     65 
     66         # Close the DB connection -- unless we're still in a transaction. This

/usr/local/lib/python2.7/site-packages/django/core/management/commands/loaddata.pyc in loaddata(self, fixture_labels)
    108         table_names = [model._meta.db_table for model in self.models]
    109         try:
--> 110             connection.check_constraints(table_names=table_names)
    111         except Exception as e:
    112             e.args = ("Problem installing fixtures: %s" % e,)

/usr/local/lib/python2.7/site-packages/django/db/backends/sqlite3/base.pyc in check_constraints(self, table_names)
    293                         primary_key_column_name, column_name, table_name,
    294                         referenced_table_name, column_name, referenced_column_name,
--> 295                         column_name, referenced_column_name,
    296                     )
    297                 )

/usr/local/lib/python2.7/site-packages/django/db/backends/utils.pyc in execute(self, sql, params)
     77         start = time()
     78         try:
---> 79             return super(CursorDebugWrapper, self).execute(sql, params)
     80         finally:
     81             stop = time()

/usr/local/lib/python2.7/site-packages/django/db/backends/utils.pyc in execute(self, sql, params)
     62                 return self.cursor.execute(sql)
     63             else:
---> 64                 return self.cursor.execute(sql, params)
     65 
     66     def executemany(self, sql, param_list):

/usr/local/lib/python2.7/site-packages/django/db/utils.pyc in __exit__(self, exc_type, exc_value, traceback)
     92                 if dj_exc_type not in (DataError, IntegrityError):
     93                     self.wrapper.errors_occurred = True
---> 94                 six.reraise(dj_exc_type, dj_exc_value, traceback)
     95 
     96     def __call__(self, func):

/usr/local/lib/python2.7/site-packages/django/db/backends/utils.pyc in execute(self, sql, params)
     60         with self.db.wrap_database_errors:
     61             if params is None:
---> 62                 return self.cursor.execute(sql)
     63             else:
     64                 return self.cursor.execute(sql, params)

/usr/local/lib/python2.7/site-packages/django/db/backends/sqlite3/base.pyc in execute(self, query, params)
    333     def execute(self, query, params=None):
    334         if params is None:
--> 335             return Database.Cursor.execute(self, query)
    336         query = self.convert_query(query)
    337         return Database.Cursor.execute(self, query, params)

OperationalError: Problem installing fixtures: no such column: REFERRED.id

"Remove email" notification displays wrong email address

Steps to reproduce:

  1. From a fresh database build, login at http://127.0.0.1:8000/login/ as [email protected]
  2. Navigate to the Email form at: http://127.0.0.1:8000/settings/emails/
  3. Add [email protected] to the "Remove email" form, select [email protected], and click "Remove email"
  4. The form behaves as expected ([email protected] is removed) but the notification message says "Your email: [email protected] has been removed from your account."

Create readme

Add readme for project. Outline steps for running locally.

Deciding/tracking views/forms for authentication

This is going to be a big issue for deciding and justifying whether to use the default Django option, or whether we should create our own custom definitions, for each authentication functionality.

The views and forms are all up for discussion, but we definitely want to define our own templates for every case. There is zero point in trying to use/adapt/extend/etc the ugly default templates when it is much less hassle to make our own.

To decide on specific views/forms, we have to decide what pages we want. Also, don't think about the django admin functionalities at this point. The pages we will want there will be different, and more straightforward to add in. I believe the following urls and views are appropriate (some inspiration from github settings). Note how I believe that it's cleaner/more visually usable not to provide a single page to edit one's authentication info along with their profile info. This is in contrast to what we may want in the admin page where we can edit all parts of a user/profile at once:

urlpatterns = [
    url(r'^login/$', views.login), # Email and password. Upon success, redirect to userhome.
    url(r'^logout/$', views.logout), # Redirect to home page of site
    url(r'^register/$', views.register), # Email, password, confirm password
    url(r'resetpassword/$', views.reset_password),
    url(r'^home/$', views.user_home), # Personalized home dashboard
    url(r'^users/(?P<email>[\w\-\.]+@[\w\-\.]+)/$', views.profile), # Public profile. No editing done here.
    url(r'settings/profile/$', views.change_profile), # edit profile info such as name, location, etc.
    url(r'settings/password/$', views.change_password),
    url(r'settings/emails/$', views.change_emails), # Each user can have multiple verified emails, one of which is primary
]

Tick each following item for which we should use the default django provision:

  • login view - Works as intended. Just have to change settings.LOGIN_REDIRECT_URL. Note, we use the class based view LoginView.as_view() because the view function is deprecated.
  • login form - NO. The default form used for the login view is AuthenticationForm which does work. But I want to add some html classes to its fields to make them look better, and add a 'remember me' field. I don't think there is any harm in subclassing this form, keeping all the main functionalities and just overriding the form fields with the exact same code, plus the html attributes we want. In the form's docstring, it even does suggest subclassing it for certain cases.
  • logout view - YES. Works as intended. Note, we use the class based view LogoutView.as_view() because the view function is deprecated.
  • register view -NO. There is no django default for this.
  • register form - NO. There is a usercreationform but we'd end up overriding 95% of it anyway.
  • password reset view - YES. Works as intended.
  • password reset form - YES. Works as intended.
  • profile edit view - NO. There is no django default for this.
  • profile edit form - NO. There is no django default for this.
  • password edit view - YES. Works as intended. I commented earlier about a weird popup box. That was from firefox password manager. Annoyingly though, it forces a success redirect url. If I set it to the same page, I can't show a 'success' alert since I can't control the view.
  • password edit form - YES. Works as intended.
  • emails edit view - NO. There is no django default for this.
  • emails edit form - NO. There is no django default for this.

Possible reasons for needing custom definitions:

  • The default view contains unwanted logic such as unwanted redirects.
  • The default views are trying to access certain model fields which we have overwritten, and cannot be stopped from doing so.

For everyone's information, here is the django auth urls file so you can see what views they do have:

urlpatterns = [
    url(r'^login/$', views.LoginView.as_view(), name='login'),
    url(r'^logout/$', views.LogoutView.as_view(), name='logout'),

    url(r'^password_change/$', views.PasswordChangeView.as_view(), name='password_change'),
    url(r'^password_change/done/$', views.PasswordChangeDoneView.as_view(), name='password_change_done'),

    url(r'^password_reset/$', views.PasswordResetView.as_view(), name='password_reset'),
    url(r'^password_reset/done/$', views.PasswordResetDoneView.as_view(), name='password_reset_done'),
    url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
    url(r'^reset/done/$', views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]

Reference: https://docs.djangoproject.com/en/1.11/topics/auth/default/

Periodic Jobs

Issue to list/keep track of periodic jobs the system will have to run.

Every N days:

  • delete all unverified non-primary emails.
  • delete outstanding invitations past expiration date.

User Notifications

I believe user notifications are a necessary feature to implement. Some uses of a notifications box are for:

  • Project review status update
  • Being invited to be a project collaborator
  • Having storage requests approved/denied

If we're all happy with this idea, I will start a new branch to implement notifications.

Work flow

Do a complete work flow of how the new PhysioNet website will work.

Add model for published project

Published projects should be a snapshot in time (not possible to change them) but there should be a core project that allows additional versions etc to be submitted.

Add/update models for project (core) and publishedproject.

Password validation

We need to define and organize custom password validators. Django by default uses:

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': { 'min_length': 8, }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

which Felipe pointed out is weaker than ideal.

I don't know much about password validators but we should define them in a custom file, I think user/validators.py, which we will add to the AUTH_PASSWORD_VALIDATORS variable in settings.py. We should not define validation rules in the clean functions.

Docs:

Data search tool - beyond individual records

Would like to gather ideas for searching data in physionet beyond searching for individual records (only waveforms in MIT or EDF format) that satisfy certain criteria. Right now we have the pbs which searches records and annotations (tied to records by name) using information parsed from the header files.

Features which would be nice to have:

  • Non-waveform record search. We will be receiving images and other file types in the future.
  • Benjamin pointed out that in many cases, there are multiple different records from the same patient. For instance in the mimic waveform database, a patient's waveform and numerics (that occur at the same time) have slightly different names, hence are not seen as related in the search. Can we implement a search that ties together patient information from multiple records/files (aside from using annotation names)?

Perhaps having a standardized csv flat file in database index pages which map files to subjects would be a method. We could generate the search database from those. If so, we would have to figure out the exact structure of that csv.

Please contribute ideas.

upload file size limit

Are we going to have a file size limit? how we can deal with files bigger than 100MB or bigger than the limit?

changelog

If we keep the changelog, then we have to make it a changelog not a free text input with no snapshot of the time of change.

Reference field

Complete the reference class. there should be added fields to point to the paper citation and/or other.

Add fresh install of Django to repo

We've agreed to rebuild using the Django framework, so a vanilla install of the latest version of Django needs to be added to the repo as a starting point .

Create logo

Create a logo for the site for display in the site header, marketing materials, etc (being handled by Ken P).

Add username

Require users to create a unique username during registration. This username will be used in the public profile URL (see: #57).

Admin panel use

What will be in the project admin panel? just the storage requests? if so, then change the name to storage requests.

Which project views should admins have access to?

In the project branch, collaborators of projects can edit descriptions, upload files, make storage requests, etc. Currently for projects, I have made views for:

  1. project overview
  2. project metadata (edit metadata)
  3. project files (upload/delete... content)
  4. project collaborators (view/add/remove collaborators).

I'm about to code up functionality for admins to approve/deny storage requests, which get listed in their project_home view. Aside from the approve/deny button on this page, admins would usually want to check out what the project is about. But does it make sense to give them universal access? ie. to the project_files page where they can upload/create folder/delete items etc.

So overall, which views should the admins have access to, for projects they don't own, if any?

Idea for publishing and updating databases

Bear in mind, we don't need to talk about names here.

We should distinguish:

  1. A published projects section of the site (physiobank).
  • Content here can be both open, and protected.
  • The point is, people should be looking at physiobank to find all data.
  • Content from here should not be directly editable.
  1. A projects in works section of the site (physioworks, as in, 'in the works').
  • Content originates from here. After a curation step, it may get accepted and transformed into a physiobank project, where it becomes released.
  • This section of the site can also be used to edit/update physiobank content, acting as a staging area. Eg. Someone releases 1000 xray images in the xraydb on physiobank. As physiobank content, no-one can directly edit it. But this guy wants to add on 500 more images, so he creates a physionetworks project based on the published state of the physiobank one (automated function obviously). The initial files will be symbolic links (or something similar) so that there is no duplication of files for storage. Then they can add, delete, rename, etc... files without any restriction because the changes only appear in the works project, not the bank one. Finally when they are ready, they can request us to approve the changes and we can push it to physiobank.

The idea is that we separate the published databases section of the site, from the works in progress section of the site. Works should be dedicated to initially setting up databases to publish, and where the editing/updating effort goes into. Using bank and works to separate public and protected projects is counterintuitive and confusing.

Right now, we put potentially sensitive projects, or databases that the owners do not want to make completely open, on physionetworks, because physiobank content is forced to be completely open. A project like MIMIC-III should not be put into a 'works in progress' section solely because we want to protect who has access to it. All sensitive databases with potential PHI under the current scheme would be perpetually placed in a 'in the works' section of the site, even if the project will never be changed. Under the new layout, it would go under physiobank as a protected database.

If you want data, go to bank. If you want to work on a project, go to works.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.