From 0e96d8b2c293dd2c5f45414125acca5cffd76fd9 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 29 Jun 2018 17:26:36 +0200 Subject: [PATCH 001/115] working on model --- pkdb_app/behaviours.py | 21 ++++++++++ pkdb_app/choices.py | 18 ++++----- pkdb_app/studies/models.py | 27 ++++++++++++- pkdb_app/subjects/models.py | 81 +++++++++++++++++++++++++++---------- 4 files changed, 115 insertions(+), 32 deletions(-) diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index 54e8f03b..c6dab6a0 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -1,15 +1,33 @@ +""" +Reusable behavior for models. +""" + from django.db import models from pkdb_app.studies.utils import CHAR_MAX_LENGTH class Sidable(models.Model): + """ Model has an sid. """ sid = models.CharField(max_length=CHAR_MAX_LENGTH, unique=True) class Meta: abstract = True +# FIXME: This has to be more complicated. +- multiple users can comment and every comment should be tracked to user with provenance information like + timestamp (last modified) + + Comment(model): + text + user + timestamp + +- Annotation (annotatable), at some point, but not now + + class Commentable(models.Model): + """ Model has a comment field. """ comment = models.TextField(blank=True, null=True) class Meta: @@ -17,6 +35,9 @@ class Meta: class Describable(models.Model): + """ + + """ description = models.TextField(blank=True, null=True) class Meta: diff --git a/pkdb_app/choices.py b/pkdb_app/choices.py index 154e744c..132ff70d 100644 --- a/pkdb_app/choices.py +++ b/pkdb_app/choices.py @@ -1,20 +1,20 @@ INTERVENTION_CHOICES = ( - (1, "Else"), - (2, "Dynamic Single"), - (3, "Dynamic Multiple"), + (1, "Other"), + (2, "Dynamic Individual"), + (3, "Dynamic Group"), (4, "Static Single"), (5, "Static Multiple"), ) -SPECIE_CHOICES = ( - (1, "Else"), +SPECIES_CHOICES = ( + (1, "Other"), (2, "Homo Sapiens"), ) CHARATERISTIC_CHOICES = ( - (1,"Else"), - (2,"Antropometrie"), - (3,"Life Style"), - (4,"Genetics") + (1, "Other"), + (2, "Antropometrie"), + (3, "Life Style"), + (4, "Genetics") ) \ No newline at end of file diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index a33e1fb8..c8e2e942 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -15,18 +15,41 @@ def __str__(self): return '%s %s' % (self.first_name, self.last_name) +# All models should be commentable + + class Study(Commentable, Describable, models.Model): """ Single clinical study. Mainly reported as a single publication. + """ + # sid should be the AuthorYear if possible + # comments + description (if no description is provided, this is filled with the abstract) + files (PNG, CSV) (all files with exception of pdf) + reference + + interventions + subjects + .... +class Reference(): + """ + This is the main class describing the publication or reference which describes the study. + In most cases this is a published paper, but could be a thesis or unpublished. + """ + + pmid = models.CharField(max_length=CHAR_MAX_LENGTH) (optional) + doi (optional) title = models.TextField() - pmid = models.CharField(max_length=CHAR_MAX_LENGTH) abstract = models.TextField(blank=True, null=True) - file = models.FileField(upload_to="study", null=True, blank=True) + journal + year + pdf = models.FileField(upload_to="study", null=True, blank=True) authors = models.ManyToManyField(Author, blank=True, related_name='authors') + keywords class Intervention(Sidable, Commentable, Describable, models.Model): diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 8ed0df79..77df6504 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -1,64 +1,103 @@ +""" +Describes subjects which participated in a study. +This can be individuals or groups. +""" from django.db import models -#studies import from ..studies.models import Intervention from ..behaviours import Sidable, Describable -from ..choices import SPECIE_CHOICES ,CHARATERISTIC_CHOICES +from ..choices import SPECIES_CHOICES ,CHARATERISTIC_CHOICES -class SubjectTag(Sidable,Describable,models.Model): +class SubjectTag(Sidable, Describable, models.Model): pass -class Characteristic(Sidable,models.Model): +class Characteristic(Sidable, models.Model): + """ Property which the individual or group has, examples are age, weight. + These can be either + - categorial + - continuous + + """ + count (optional: either subset, or all) # can be done via through type = models.IntegerField(choices=CHARATERISTIC_CHOICES) class Meta: abstract = True -class CharacteristicBinary(Characteristic): - value = models.BinaryField() +class CharacteristicCategorial(Characteristic): + """ + - sex (M/F) + - healthy (healthy/non-healthy) + - ethnicity (Asian, Afroamerican, African, Caucasian) + """ + category (sex, healthy) + value = models.ChoiceField() + + + +class Value(): + category/keyword/type (age, bodyweight, height, ...) + n (=1) # ? + mean + unit + +class GroupValue(): + """ + can be single or group value + """ + n + mean + median + sd (standard deviation) + se (standard error) + min + max + cv + unit -class CharacteristicContinous(Characteristic): + + +class CharacteristicContinuous(Characteristic): + """ + - + """ value = models.FloatField() + class CharacteristicRange(Characteristic): start = models.FloatField() end = models.FloatField() -class Subject(Sidable,models.Model): - specie = models.IntegerField(choices=SPECIE_CHOICES) + + +class Individual(Sidable, models.Model): + specie = models.IntegerField(choices=SPECIES_CHOICES) tags = models.ManyToManyField(SubjectTag) characteristics_binary = models.ManyToManyField(CharacteristicBinary) - characteristics_continous = models.ManyToManyField(CharacteristicContinous) - characteristics_range = models.ManyToManyField(CharacteristicRange) + characteristics_continous = models.ManyToManyField(CharacteristicContinouos) + # characteristics_range = models.ManyToManyField(CharacteristicRange) -class Group(Sidable,models.Model): +class Group(Sidable, models.Model): number = models.IntegerField() class Meta: abstract = True + class SubjectGroup(Group): Intervention = models.ForeignKey(Intervention,on_delete=True) subjects = models.ManyToManyField(Subject, through="RelativeAmount") class RelativeAmount(models.Model): - subjects = models.ForeignKey(Subject,on_delete=models.CASCADE) + subjects = models.ForeignKey(Subject, on_delete=models.CASCADE) subjects_group = models.ForeignKey(SubjectGroup,on_delete=models.CASCADE) relative_amount = models.FloatField() - - - - - - - - From 1abdc7d1ba49717004a355d179c8bde25723e176 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 29 Jun 2018 17:28:47 +0200 Subject: [PATCH 002/115] latest comments --- pkdb_app/subjects/models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 77df6504..211e7d2d 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -75,7 +75,6 @@ class CharacteristicRange(Characteristic): - class Individual(Sidable, models.Model): specie = models.IntegerField(choices=SPECIES_CHOICES) tags = models.ManyToManyField(SubjectTag) @@ -96,7 +95,7 @@ class SubjectGroup(Group): Intervention = models.ForeignKey(Intervention,on_delete=True) subjects = models.ManyToManyField(Subject, through="RelativeAmount") - +# dont do this class RelativeAmount(models.Model): subjects = models.ForeignKey(Subject, on_delete=models.CASCADE) subjects_group = models.ForeignKey(SubjectGroup,on_delete=models.CASCADE) From b7fd7d561abb7b2b9fbca8295ec1eb855b7aabd7 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 29 Jun 2018 18:02:18 +0200 Subject: [PATCH 003/115] tmp file removed From e9dfe445692b54a5f5f22688e7b0ff7fbd25f7ad Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 2 Jul 2018 16:47:59 +0200 Subject: [PATCH 004/115] work in progress: models subjects --- pkdb_app/behaviours.py | 5 +- pkdb_app/categoricals.py | 124 ++++++++++++++++++++++++++++++++ pkdb_app/choices.py | 20 ------ pkdb_app/studies/models.py | 58 +++++++++------ pkdb_app/subjects/models.py | 104 +++++++++++++++++++++++---- pkdb_app/users/models.py | 1 + pkdb_app/{studies => }/utils.py | 0 7 files changed, 254 insertions(+), 58 deletions(-) create mode 100644 pkdb_app/categoricals.py delete mode 100644 pkdb_app/choices.py rename pkdb_app/{studies => }/utils.py (100%) diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index c6dab6a0..d9787743 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -3,7 +3,7 @@ """ from django.db import models -from pkdb_app.studies.utils import CHAR_MAX_LENGTH +from pkdb_app.utils import CHAR_MAX_LENGTH class Sidable(models.Model): @@ -15,6 +15,7 @@ class Meta: # FIXME: This has to be more complicated. +''' - multiple users can comment and every comment should be tracked to user with provenance information like timestamp (last modified) @@ -24,6 +25,8 @@ class Meta: timestamp - Annotation (annotatable), at some point, but not now +''' + class Commentable(models.Model): diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py new file mode 100644 index 00000000..d47874bc --- /dev/null +++ b/pkdb_app/categoricals.py @@ -0,0 +1,124 @@ +""" +Model choices and more specifically possible categories of subject characteristics. +""" +from enum import Enum, IntEnum +from itertools import chain +##################### +#Abstract Catergories + +class ChoiceEnum(Enum): + + @classmethod + def choices(cls): + return tuple((x.name, x.value) for x in cls) + +BOOLEAN_CHOICES = ( + (0,"Yes"), + (1,"No") +) + +NULL_BOOLEAN_CHOICE = BOOLEAN_CHOICES + (2,"NULL") + + +##################### +#Study Choices +KEY_WORD_CHOICES = () +##################### +#Characteristics + +class BodyParams(ChoiceEnum): + Height = "height" + BODYWEIGHT = "bodyweight" + +class Sex(ChoiceEnum): + MALE = 'male' + FEMALE = 'female' + +class Species(ChoiceEnum): + HOMOSAPIEN = "Home Sapiens" + +class Ethnicitiy(ChoiceEnum): + ASIAN = "asian" + CAUCASIAN = "caucasian" + AFRICAN = "african" + AFROAMERICAN = "afroamerican" + +class Health(ChoiceEnum): + HEALTHY = "healthy" + NONHEALTHY = "non-healthy" + +class Smoking(ChoiceEnum): + SMOKING = "smoking" + NONSMOKING = "non-smoking" + +characteristics_dict = {"sex":Sex, + "ethnicity":Ethnicitiy, + "health":Health, + "smoking":Smoking, + "body_params": BodyParams, + "species":Species} + + +characteristics_types = {} +for k,v in characteristics_dict.items(): + for vv in v: + characteristics_types[vv.value] = k + +All_Characteristics = ChoiceEnum("All Characteristics", [(i.name, i.value) for i in chain(*characteristics_dict.values)]) + + + + + + +INTERVENTION_CHOICES = ( + (1, "Other"), + (2, "Dynamic Individual"), + (3, "Dynamic Group"), + (4, "Static Single"), + (5, "Static Multiple"), + ) +# +# SPECIES_CHOICES = ( +# (1, "Other"), +# (2, "Homo Sapiens"), +# ) +# +# CHARATERISTIC_CHOICES = ( +# (1, "Other"), +# (2, "Antropometrie"), +# (3, "Life Style"), +# (4, "Genetics") +# ) +# ##################### +# # Subject categories +# CHARATERISTIC_CATEGORIES = ( +# #(1, "Other"), +# (2,"Health"), +# (3,"Sex"), +# (4,"Smoking"), +# (5,"Ethnicity"), +# ) +# +# SEX_CATEGORIES = ( +# (1,"Male"), +# (2,"Female"), +# ) +# +# ETHNICITY_CATEGORIES = ( +# (1,"Asian"), +# (2,"Afroamerican"), +# (3,"American"), +# (4,"Caucasian"), +# ) +# +# HEALTH_CATEGORIES = BOOLEAN_CHOICES +# SMOKING_CATEGORIES = BOOLEAN_CHOICES +# +# +# SUBJECT_CATEGORIES = {"health":HEALTH_CATEGORIES, +# "smoking":SMOKING_CATEGORIES, +# "sex": SEX_CATEGORIES, +# "ethnicity": ETHNICITY_CATEGORIES, +# } + diff --git a/pkdb_app/choices.py b/pkdb_app/choices.py deleted file mode 100644 index 132ff70d..00000000 --- a/pkdb_app/choices.py +++ /dev/null @@ -1,20 +0,0 @@ - -INTERVENTION_CHOICES = ( - (1, "Other"), - (2, "Dynamic Individual"), - (3, "Dynamic Group"), - (4, "Static Single"), - (5, "Static Multiple"), - ) - -SPECIES_CHOICES = ( - (1, "Other"), - (2, "Homo Sapiens"), - ) - -CHARATERISTIC_CHOICES = ( - (1, "Other"), - (2, "Antropometrie"), - (3, "Life Style"), - (4, "Genetics") -) \ No newline at end of file diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index c8e2e942..d93d58fe 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -2,9 +2,9 @@ Django model for Study. """ from django.db import models -from .utils import CHAR_MAX_LENGTH +from pkdb_app.utils import CHAR_MAX_LENGTH from pkdb_app.behaviours import Sidable, Describable, Commentable -from pkdb_app.choices import INTERVENTION_CHOICES +from pkdb_app.categoricals import INTERVENTION_CHOICES class Author(models.Model): @@ -14,11 +14,35 @@ class Author(models.Model): def __str__(self): return '%s %s' % (self.first_name, self.last_name) +class Files(models.Model): + name = models.CharField(max_length=CHAR_MAX_LENGTH) + file = models.FileField(null=True, blank=True) + +class KeyWord(models.Model): + """ + This class describes the keyowrds / tags of a publication or any other reference. + """ + #name = models.IntegerField(choices=KEY_WORD_CHOICES) + name = models.CharField(max_length=CHAR_MAX_LENGTH) # All models should be commentable +class Reference(models.Model): + """ + This is the main class describing the publication or reference which describes the study. + In most cases this is a published paper, but could be a thesis or unpublished. + """ -class Study(Commentable, Describable, models.Model): + pmid = models.CharField(max_length=CHAR_MAX_LENGTH) #optional + doi = models.CharField(max_length=CHAR_MAX_LENGTH) #optional + title = models.TextField() + abstract = models.TextField(blank=True, null=True) + journal = models.CharField(max_length=CHAR_MAX_LENGTH) + year = models.DateField() + pdf = models.FileField(upload_to="study", null=True, blank=True) + authors = models.ManyToManyField(Author, blank=True, related_name='authors') + +class Study(Sidable, Commentable, Describable, models.Model): """ Single clinical study. Mainly reported as a single publication. @@ -26,30 +50,18 @@ class Study(Commentable, Describable, models.Model): """ # sid should be the AuthorYear if possible # comments - description (if no description is provided, this is filled with the abstract) - files (PNG, CSV) (all files with exception of pdf) - reference + #description (if no description is provided, this is filled with the abstract) + #files (PNG, CSV) (all files with exception of pdf) + files = models.ManyToManyField(Files, related_name="files") + reference = models.ForeignKey(Reference, null=True, blank=True, on_delete=True) + keywords = models.ManyToManyField(KeyWord, blank=True, related_name='keywords') + + #interventions + #subjects - interventions - subjects - .... -class Reference(): - """ - This is the main class describing the publication or reference which describes the study. - In most cases this is a published paper, but could be a thesis or unpublished. - """ - pmid = models.CharField(max_length=CHAR_MAX_LENGTH) (optional) - doi (optional) - title = models.TextField() - abstract = models.TextField(blank=True, null=True) - journal - year - pdf = models.FileField(upload_to="study", null=True, blank=True) - authors = models.ManyToManyField(Author, blank=True, related_name='authors') - keywords class Intervention(Sidable, Commentable, Describable, models.Model): diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 211e7d2d..98158975 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -4,10 +4,60 @@ """ from django.db import models -from ..studies.models import Intervention +from ..studies.models import Intervention,Study from ..behaviours import Sidable, Describable -from ..choices import SPECIES_CHOICES ,CHARATERISTIC_CHOICES - +from ..categoricals import ChoiceEnum, All_Characteristics, characteristics_types +from ..utils import CHAR_MAX_LENGTH +############################################################# + +#New Approach +#General Categorical +# class CharacteristicType(models.Model): +# name = models.CharField(max_length=CHAR_MAX_LENGTH) +# pass +# +# class Characteristic(models.Model): +# name = models.CharField(max_length=CHAR_MAX_LENGTH) +# type = models.ForeignKey(CharacteristicType, on_delete=False) +# #unit = models.CharField(max_length=CHAR_MAX_LENGTH) +# +# +# +# class Category(models.Model): +# name = models.CharField(max_length=CHAR_MAX_LENGTH) +# characteristic = models.ForeignKey(Characteristic, on_delete=False) +# +############################################################## + + +class Group(Sidable,models.Model): + study = models.ForeignKey(Study, on_delete=True) + + +class GroupCharacteristic(Sidable,models.Model): + name = models.CharField(choices=All_Characteristics.choices(), max_length=CHAR_MAX_LENGTH) + ####################### + #statistical properties + value = models.FloatField(null=True,blank=True) + mean = models.FloatField(null=True,blank=True) + min = models.FloatField(null=True,blank=True) + max = models.FloatField(null=True,blank=True) + std = models.FloatField(null=True,blank=True) + count = models.IntegerField() + ######################## + unit = models.CharField(choices=All_Units.choices(),max_length=CHAR_MAX_LENGTH) + group = models.ForeignKey(Group,on_delete=True) + + + def type(self): + return characteristics_types[self.name] + + +########################################################################################## + +class CharacteristicValue(models.Model): + count = models.IntegerField(null=True) + mean = models.FloatField(null=True) class SubjectTag(Sidable, Describable, models.Model): pass @@ -20,8 +70,14 @@ class Characteristic(Sidable, models.Model): - continuous """ - count (optional: either subset, or all) # can be done via through - type = models.IntegerField(choices=CHARATERISTIC_CHOICES) + class Type(ChoiceEnum): + OTHER = 'other' + ANTROPOMETRIE = 'antropometrie' + LIFE_STYLE = 'life style' + GENETICS = 'genetics' + + count = models.IntegerField() #count (optional: either subset, or all) # can be done via through + type = models.CharField(choices=Type.choices()) class Meta: abstract = True @@ -33,13 +89,38 @@ class CharacteristicCategorial(Characteristic): - healthy (healthy/non-healthy) - ethnicity (Asian, Afroamerican, African, Caucasian) """ - category (sex, healthy) - value = models.ChoiceField() + class Category(ChoiceEnum): + + Health = "health" + Sex = "sex" + Smoking = "smoking" + Ethnicity = "ethnicity" + + #category = models.CharField(choices=Category.choices()) + name = models.CharField(choices=Category.choices()) + value = models.CharField(choices=All_Characteristics.choices()) +############################################################### + +class CharacteristicContinuous(Characteristic): + """ + - + """ + class Category(ChoiceEnum): + Age = "age" + BodyWeight = "bodyweight" + Height = "height" -class Value(): - category/keyword/type (age, bodyweight, height, ...) + + name = models.CharField(choices=Category.choices()) + #value = models.FloatField() + + +class Value(models.Model): + + #category/keyword/type (age, bodyweight, height, ...) + models.ForeignKey(CharacteristicContinuous, on_delete=True) n (=1) # ? mean unit @@ -61,11 +142,6 @@ class GroupValue(): -class CharacteristicContinuous(Characteristic): - """ - - - """ - value = models.FloatField() diff --git a/pkdb_app/users/models.py b/pkdb_app/users/models.py index 00ec7ee8..3281fd00 100644 --- a/pkdb_app/users/models.py +++ b/pkdb_app/users/models.py @@ -11,6 +11,7 @@ @python_2_unicode_compatible class User(AbstractUser): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + models.BO def __str__(self): return self.username diff --git a/pkdb_app/studies/utils.py b/pkdb_app/utils.py similarity index 100% rename from pkdb_app/studies/utils.py rename to pkdb_app/utils.py From f198d69d5240c36c761cb31fe24b4ef2089720a9 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 2 Jul 2018 18:43:08 +0200 Subject: [PATCH 005/115] updated models --- .gitignore | 4 + pkdb_app/categoricals.py | 148 +++++++++----------------- pkdb_app/studies/models.py | 12 ++- pkdb_app/subjects/models.py | 204 +++++++++++------------------------- 4 files changed, 123 insertions(+), 245 deletions(-) diff --git a/.gitignore b/.gitignore index 0f49fc6d..c33d94f3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,10 @@ __pycache__/ # C extensions *.so +# open/libre office +.ods# + + # Distribution / packaging .Python build/ diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index d47874bc..b34a08ee 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -1,124 +1,74 @@ """ -Model choices and more specifically possible categories of subject characteristics. -""" -from enum import Enum, IntEnum -from itertools import chain -##################### -#Abstract Catergories - -class ChoiceEnum(Enum): - - @classmethod - def choices(cls): - return tuple((x.name, x.value) for x in cls) - -BOOLEAN_CHOICES = ( - (0,"Yes"), - (1,"No") -) +To be easily extendable we do not hardcode information about characteristics in classes, +but define in some custom data structure which is referenced. -NULL_BOOLEAN_CHOICE = BOOLEAN_CHOICES + (2,"NULL") +Model choices and more specifically possible categories of subject characteristics. -##################### -#Study Choices -KEY_WORD_CHOICES = () -##################### -#Characteristics - -class BodyParams(ChoiceEnum): - Height = "height" - BODYWEIGHT = "bodyweight" +In the future the relationship between the characteristics could be implemented via +an ontology which represents the relationship between the differnent values. +""" -class Sex(ChoiceEnum): - MALE = 'male' - FEMALE = 'female' +# TODO: How to handle the genetic information? Genetic variants? -class Species(ChoiceEnum): - HOMOSAPIEN = "Home Sapiens" +from collections import namedtuple +CharacteristicType = namedtuple("CharacteristicType", ["value", "class", "dtype", "choices"]) +UnitType = namedtuple("UnitType", ["name"]) -class Ethnicitiy(ChoiceEnum): - ASIAN = "asian" - CAUCASIAN = "caucasian" - AFRICAN = "african" - AFROAMERICAN = "afroamerican" +# TODO: lookup units package and proper units handling (units conversion, default units, ...) +UNIT_DATA = [ + UnitType('-'), + UnitType('cm'), UnitType('m'), + UnitType('kg'), + UnitType('y'), + UnitType('kg/m^2'), +] +UNITS_CHOICES = [(utype.name, utype.name) for utype in UNIT_DATA] -class Health(ChoiceEnum): - HEALTHY = "healthy" - NONHEALTHY = "non-healthy" -class Smoking(ChoiceEnum): - SMOKING = "smoking" - NONSMOKING = "non-smoking" -characteristics_dict = {"sex":Sex, - "ethnicity":Ethnicitiy, - "health":Health, - "smoking":Smoking, - "body_params": BodyParams, - "species":Species} +# class, value, dtype (numeric, boolean, categorial), choices +# dates? +# How to store NA? Is this necessary? +# numeric: NA, None +# boolean: NA, None +# categorial: NA, None +CHARACTERISTIC_DATA = [ + CharacteristicType('height', 'BodyParameter', 'numeric', None), + CharacteristicType('body weight', 'BodyParameter', 'numeric', None), + CharacteristicType('age', 'BodyParameter', 'numeric', None), + CharacteristicType('sex', 'BodyParameter', 'categorial', ["M", "F"]), + CharacteristicType('bmi', 'BodyParameter', 'numeric', None), + CharacteristicType('waist circumference', 'BodyParameter', 'numeric', None), -characteristics_types = {} -for k,v in characteristics_dict.items(): - for vv in v: - characteristics_types[vv.value] = k + CharacteristicType('ethnicity', 'Ethnicity', 'categorial', ["african", "afroamerican", "asian", "caucasian"]), -All_Characteristics = ChoiceEnum("All Characteristics", [(i.name, i.value) for i in chain(*characteristics_dict.values)]) + # exists as yes/no or as amount + CharacteristicType('healthy', "Health status", "boolean", None), + CharacteristicType('disease', "Disease", "categorial", ["cirrhosis"]), + CharacteristicType('smoking', 'Lifestyle', 'boolean', ["Y", "N"]), + CharacteristicType('smoking_amount', 'Lifestyle', 'numeric', None), + CharacteristicType('alcohol', 'Lifestyle', 'boolean', ["Y", "N"]), + CharacteristicType('alcohol_amount', 'Lifestyle', 'numeric', None), + CharacteristicType('oral contraceptives', 'Contraceptives', 'boolean', ["Y", "N"]), + CharacteristicType('medication', 'Medication', 'categorial', ["ibuprofen", "paracetamol", "aspirin"]), # ? dosing + CharacteristicType('species', 'Species', 'categorial', ["Homo sapiens"]), +] +CHARACTERISTIC_DICT = {item.value: item for item in CHARACTERISTIC_DATA} +CHARACTERISTIC_CHOICES = [(ctype.value, ctype.value) for ctype in CHARACTERISTIC_DATA] -INTERVENTION_CHOICES = ( +''' +DATA_CHOICES = ( (1, "Other"), (2, "Dynamic Individual"), (3, "Dynamic Group"), (4, "Static Single"), (5, "Static Multiple"), ) -# -# SPECIES_CHOICES = ( -# (1, "Other"), -# (2, "Homo Sapiens"), -# ) -# -# CHARATERISTIC_CHOICES = ( -# (1, "Other"), -# (2, "Antropometrie"), -# (3, "Life Style"), -# (4, "Genetics") -# ) -# ##################### -# # Subject categories -# CHARATERISTIC_CATEGORIES = ( -# #(1, "Other"), -# (2,"Health"), -# (3,"Sex"), -# (4,"Smoking"), -# (5,"Ethnicity"), -# ) -# -# SEX_CATEGORIES = ( -# (1,"Male"), -# (2,"Female"), -# ) -# -# ETHNICITY_CATEGORIES = ( -# (1,"Asian"), -# (2,"Afroamerican"), -# (3,"American"), -# (4,"Caucasian"), -# ) -# -# HEALTH_CATEGORIES = BOOLEAN_CHOICES -# SMOKING_CATEGORIES = BOOLEAN_CHOICES -# -# -# SUBJECT_CATEGORIES = {"health":HEALTH_CATEGORIES, -# "smoking":SMOKING_CATEGORIES, -# "sex": SEX_CATEGORIES, -# "ethnicity": ETHNICITY_CATEGORIES, -# } - +''' diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index d93d58fe..5775289e 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -61,10 +61,14 @@ class Study(Sidable, Commentable, Describable, models.Model): +# ------------------------------------------------- +# Intervention +# ------------------------------------------------- +# Here only the different (two or more) groups which were compared in the study have to be defined. +# In a single study/paper multiple groups are compared (these can be defined as groups). - -class Intervention(Sidable, Commentable, Describable, models.Model): - type = models.IntegerField(choices=INTERVENTION_CHOICES) - study = models.ForeignKey(Study, null=True, blank=True, on_delete=True) +# class Intervention(Sidable, Commentable, Describable, models.Model): +# type = models.IntegerField(choices=INTERVENTION_CHOICES) +# study = models.ForeignKey(Study, null=True, blank=True, on_delete=True) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 98158975..47964ee1 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -1,178 +1,98 @@ """ -Describes subjects which participated in a study. -This can be individuals or groups. +Describe group of subjects or individual (i.e. define the characteristics of the +group or individual). + +How is different from things which will be measured? +From the data structure this has to be handled very similar. + + """ from django.db import models -from ..studies.models import Intervention,Study +from ..studies.models import Study from ..behaviours import Sidable, Describable -from ..categoricals import ChoiceEnum, All_Characteristics, characteristics_types +from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, UNITS_CHOICES from ..utils import CHAR_MAX_LENGTH -############################################################# - -#New Approach -#General Categorical -# class CharacteristicType(models.Model): -# name = models.CharField(max_length=CHAR_MAX_LENGTH) -# pass -# -# class Characteristic(models.Model): -# name = models.CharField(max_length=CHAR_MAX_LENGTH) -# type = models.ForeignKey(CharacteristicType, on_delete=False) -# #unit = models.CharField(max_length=CHAR_MAX_LENGTH) -# -# -# -# class Category(models.Model): -# name = models.CharField(max_length=CHAR_MAX_LENGTH) -# characteristic = models.ForeignKey(Characteristic, on_delete=False) -# -############################################################## - - -class Group(Sidable,models.Model): - study = models.ForeignKey(Study, on_delete=True) - - -class GroupCharacteristic(Sidable,models.Model): - name = models.CharField(choices=All_Characteristics.choices(), max_length=CHAR_MAX_LENGTH) - ####################### - #statistical properties - value = models.FloatField(null=True,blank=True) - mean = models.FloatField(null=True,blank=True) - min = models.FloatField(null=True,blank=True) - max = models.FloatField(null=True,blank=True) - std = models.FloatField(null=True,blank=True) - count = models.IntegerField() - ######################## - unit = models.CharField(choices=All_Units.choices(),max_length=CHAR_MAX_LENGTH) - group = models.ForeignKey(Group,on_delete=True) - - - def type(self): - return characteristics_types[self.name] - -########################################################################################## -class CharacteristicValue(models.Model): - count = models.IntegerField(null=True) - mean = models.FloatField(null=True) +class Timecourse(models.Model): + """ Storing of time course data. -class SubjectTag(Sidable, Describable, models.Model): - pass + Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). + """ + data = models.BinaryField() class Characteristic(Sidable, models.Model): - """ Property which the individual or group has, examples are age, weight. - These can be either - - categorial - - continuous - + """ Characteristic. + Characteristics are used to store the information about subjects. """ - class Type(ChoiceEnum): - OTHER = 'other' - ANTROPOMETRIE = 'antropometrie' - LIFE_STYLE = 'life style' - GENETICS = 'genetics' + name = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) - count = models.IntegerField() #count (optional: either subset, or all) # can be done via through - type = models.CharField(choices=Type.choices()) + @property + def characteristic_data(self): + """ Returns the full information about the characteristic. - class Meta: - abstract = True + :return: + """ + return CHARACTERISTIC_DICT[self.name] + @property + def choices(self): + return self.characteristic_data.choices -class CharacteristicCategorial(Characteristic): - """ - - sex (M/F) - - healthy (healthy/non-healthy) - - ethnicity (Asian, Afroamerican, African, Caucasian) - """ - class Category(ChoiceEnum): - - Health = "health" - Sex = "sex" - Smoking = "smoking" - Ethnicity = "ethnicity" + class Meta: + abstract = True - #category = models.CharField(choices=Category.choices()) - name = models.CharField(choices=Category.choices()) - value = models.CharField(choices=All_Characteristics.choices()) -############################################################### -class CharacteristicContinuous(Characteristic): +class CharacteristicValue(Characteristic): """ - - + This is the concrete selection/information of the characteristics. + This stores the raw information. Derived values can be calculated. """ + choice = models.CharField() # check in validation that allowed choice - class Category(ChoiceEnum): - Age = "age" - BodyWeight = "bodyweight" - Height = "height" + count = models.IntegerField() # how many participants in characteristics + value = models.FloatField(null=True, blank=True) + mean = models.FloatField(null=True, blank=True) + median = models.FloatField(null=True, blank=True) + min = models.FloatField(null=True, blank=True) + max = models.FloatField(null=True, blank=True) + sd = models.FloatField(null=True, blank=True) + se = models.FloatField(null=True, blank=True) + cv = models.FloatField(null=True, blank=True) + unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH) - name = models.CharField(choices=Category.choices()) - #value = models.FloatField() + timecourse = models.ForeignKey(Timecourse) + def validate(self): + """ Check that choices are valid. I.e. that choice is allowed choice from choices for + characteristics. -class Value(models.Model): + Add checks for individuals and groups. For instance if count==1 than value must be filled, + but not entries in mean, median, ... - #category/keyword/type (age, bodyweight, height, ...) - models.ForeignKey(CharacteristicContinuous, on_delete=True) - n (=1) # ? - mean - unit + :return: + """ + raise NotImplemented -class GroupValue(): +class ProcessedCharacteristicValue(CharacteristicValue): + """ Processed and normalized data (calculated on change from + corresponding raw CharacteristicValue. """ - can be single or group value - """ - n - mean - median - sd (standard deviation) - se (standard error) - min - max - cv - unit - - - - - - -class CharacteristicRange(Characteristic): - start = models.FloatField() - end = models.FloatField() - - - -class Individual(Sidable, models.Model): - specie = models.IntegerField(choices=SPECIES_CHOICES) - tags = models.ManyToManyField(SubjectTag) - characteristics_binary = models.ManyToManyField(CharacteristicBinary) - characteristics_continous = models.ManyToManyField(CharacteristicContinouos) - # characteristics_range = models.ManyToManyField(CharacteristicRange) + raw = models.OneToOneField(CharacteristicValue) class Group(Sidable, models.Model): - number = models.IntegerField() - - class Meta: - abstract = True - + """ Individual or group of people. + Groups are defined via their characteristics. + """ + study = models.ForeignKey(Study, on_delete=True) + count = models.IntegerField() + characteristics = models.ManyToManyField(Characteristic, on_delete=True) -class SubjectGroup(Group): - Intervention = models.ForeignKey(Intervention,on_delete=True) - subjects = models.ManyToManyField(Subject, through="RelativeAmount") - -# dont do this -class RelativeAmount(models.Model): - subjects = models.ForeignKey(Subject, on_delete=models.CASCADE) - subjects_group = models.ForeignKey(SubjectGroup,on_delete=models.CASCADE) - relative_amount = models.FloatField() +# TODO: How to handle Pharmacokinetics data? From c84bf038420491e10002534e23875abf49a95866 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 2 Jul 2018 19:00:08 +0200 Subject: [PATCH 006/115] latest changes in data model --- pkdb_app/categoricals.py | 43 +++++++++++++++++++++++++++++++++---- pkdb_app/subjects/models.py | 1 + 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index b34a08ee..1f0c4fc2 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -35,28 +35,44 @@ # categorial: NA, None CHARACTERISTIC_DATA = [ + # Antropmetrical information + CharacteristicType('species', 'Species', 'categorial', ["Homo sapiens"]), CharacteristicType('height', 'BodyParameter', 'numeric', None), CharacteristicType('body weight', 'BodyParameter', 'numeric', None), CharacteristicType('age', 'BodyParameter', 'numeric', None), CharacteristicType('sex', 'BodyParameter', 'categorial', ["M", "F"]), CharacteristicType('bmi', 'BodyParameter', 'numeric', None), CharacteristicType('waist circumference', 'BodyParameter', 'numeric', None), - CharacteristicType('ethnicity', 'Ethnicity', 'categorial', ["african", "afroamerican", "asian", "caucasian"]), - # exists as yes/no or as amount + # Disease (status) CharacteristicType('healthy', "Health status", "boolean", None), CharacteristicType('disease', "Disease", "categorial", ["cirrhosis"]), + + # Lifestyle CharacteristicType('smoking', 'Lifestyle', 'boolean', ["Y", "N"]), CharacteristicType('smoking_amount', 'Lifestyle', 'numeric', None), CharacteristicType('alcohol', 'Lifestyle', 'boolean', ["Y", "N"]), CharacteristicType('alcohol_amount', 'Lifestyle', 'numeric', None), + CharacteristicType('caffeine', 'Lifestyle', 'boolean', ["Y", "N"]), + CharacteristicType('caffeine_amount', 'Lifestyle', 'numeric', None), - CharacteristicType('oral contraceptives', 'Contraceptives', 'boolean', ["Y", "N"]), + # Study protocol + CharacteristicType('overnight fast', 'Study protocol', 'boolean', ["Y", "N"]), + CharacteristicType('alcohol abstinence', 'Study protocol', 'boolean', ["Y", "N"]), + # Medication + CharacteristicType('oral contraceptives', 'Contraceptives', 'boolean', ["Y", "N"]), CharacteristicType('medication', 'Medication', 'categorial', ["ibuprofen", "paracetamol", "aspirin"]), # ? dosing - CharacteristicType('species', 'Species', 'categorial', ["Homo sapiens"]), + + # Genetics ??? + # Requires storage of the variants and effects of clearance + +] + +PK_DATA = [ + ] CHARACTERISTIC_DICT = {item.value: item for item in CHARACTERISTIC_DATA} @@ -72,3 +88,22 @@ (5, "Static Multiple"), ) ''' + +class Dosing: + substance + route + form + dose + dose_unit + dose_bodyweight + times + +class Pharmacokinetics (CharacteristicValue): + group (intervention) + dosing + substance + source + entry + + + diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 47964ee1..a158da85 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -92,6 +92,7 @@ class Group(Sidable, models.Model): Groups are defined via their characteristics. """ study = models.ForeignKey(Study, on_delete=True) + name = models.TextField() count = models.IntegerField() characteristics = models.ManyToManyField(Characteristic, on_delete=True) From e2767397249d0d249a6e221d56cc005e31959315 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 2 Jul 2018 19:27:29 +0200 Subject: [PATCH 007/115] temp files removed From cf3ec63c16fd64c1d98fc2ce364686942de9e405 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 3 Jul 2018 16:15:52 +0200 Subject: [PATCH 008/115] working on data model --- pkdb_app/categoricals.py | 35 ++++++++++++++++++++++++--------- pkdb_app/studies/models.py | 1 - pkdb_app/studies/serializers.py | 29 +++++++++++++++------------ pkdb_app/studies/views.py | 25 +++++++++++------------ pkdb_app/subjects/models.py | 3 +-- pkdb_app/urls.py | 31 ++++++++++++++--------------- 6 files changed, 70 insertions(+), 54 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 1f0c4fc2..53a9f571 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -26,7 +26,6 @@ UNITS_CHOICES = [(utype.name, utype.name) for utype in UNIT_DATA] - # class, value, dtype (numeric, boolean, categorial), choices # dates? # How to store NA? Is this necessary? @@ -34,7 +33,17 @@ # boolean: NA, None # categorial: NA, None -CHARACTERISTIC_DATA = [ +COMMON_DATA = [ + # Medication + CharacteristicType('oral contraceptives', 'Contraceptives', 'boolean', ["Y", "N"]), + CharacteristicType('medication', 'Medication', 'categorial', ["ibuprofen", "paracetamol", "aspirin"]), # ? dosing + + # Lifestyle + CharacteristicType('caffeine', 'Lifestyle', 'boolean', ["Y", "N"]), + CharacteristicType('caffeine_amount', 'Lifestyle', 'numeric', None), +] + +CHARACTERISTIC_DATA = COMMON_DATA+ [ # Antropmetrical information CharacteristicType('species', 'Species', 'categorial', ["Homo sapiens"]), CharacteristicType('height', 'BodyParameter', 'numeric', None), @@ -55,28 +64,33 @@ CharacteristicType('smoking_amount', 'Lifestyle', 'numeric', None), CharacteristicType('alcohol', 'Lifestyle', 'boolean', ["Y", "N"]), CharacteristicType('alcohol_amount', 'Lifestyle', 'numeric', None), - CharacteristicType('caffeine', 'Lifestyle', 'boolean', ["Y", "N"]), - CharacteristicType('caffeine_amount', 'Lifestyle', 'numeric', None), + # Study protocol CharacteristicType('overnight fast', 'Study protocol', 'boolean', ["Y", "N"]), CharacteristicType('alcohol abstinence', 'Study protocol', 'boolean', ["Y", "N"]), # Medication - CharacteristicType('oral contraceptives', 'Contraceptives', 'boolean', ["Y", "N"]), - CharacteristicType('medication', 'Medication', 'categorial', ["ibuprofen", "paracetamol", "aspirin"]), # ? dosing # Genetics ??? # Requires storage of the variants and effects of clearance - ] PK_DATA = [ +] +# class, value, dtype (numeric, boolean, categorial), choices +INTERVENTION_DATA = COMMON_DATA + [ ] -CHARACTERISTIC_DICT = {item.value: item for item in CHARACTERISTIC_DATA} -CHARACTERISTIC_CHOICES = [(ctype.value, ctype.value) for ctype in CHARACTERISTIC_DATA] +def dict_and_choices(data): + data_dict = {item.value: item for item in data} + data_choices = [(ctype.value, ctype.value) for ctype in data] + return data_dict, data_choices + + +CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES = dict_and_choices(CHARACTERISTIC_DATA) +INTERVENTION_DICT, INTERVENTION_CHOICES = dict_and_choices(INTERVENTION_DATA) ''' @@ -89,6 +103,7 @@ ) ''' +''' class Dosing: substance route @@ -104,6 +119,8 @@ class Pharmacokinetics (CharacteristicValue): substance source entry +''' + diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 5775289e..f80f7e90 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -4,7 +4,6 @@ from django.db import models from pkdb_app.utils import CHAR_MAX_LENGTH from pkdb_app.behaviours import Sidable, Describable, Commentable -from pkdb_app.categoricals import INTERVENTION_CHOICES class Author(models.Model): diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 9d8b58cd..206c62c2 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -1,15 +1,15 @@ from rest_framework import serializers -from .models import Intervention, Author, Study +from .models import Reference, Author, Study BASE_FIELDS = ('comment', 'description',) -class InterventionSerializer(serializers.ModelSerializer): +#class InterventionSerializer(serializers.ModelSerializer): - class Meta: - model = Intervention - fields = BASE_FIELDS + ('type', 'study',) +# class Meta: +# model = Intervention +# fields = BASE_FIELDS + ('type', 'study',) class AuthorSerializer(serializers.ModelSerializer): @@ -25,20 +25,23 @@ def create(self, validated_data): return author -class StudySerializer(serializers.ModelSerializer): +class ReferenceSerializer(serializers.ModelSerializer): authors = AuthorSerializer(many=True,read_only=False)#, queryset=Study.objects.all(), source='studies') - class Meta: - model = Study - fields = BASE_FIELDS + ('title', 'pmid', 'authors', 'abstract','file') + model = Reference + fields = BASE_FIELDS + ('pmid', 'doi', 'title', 'abstract', 'journal','year', 'authors','pdf') def create(self, validated_data): authors_data = validated_data.pop('authors') - study, _ = Study.objects.update_or_create(pmid=validated_data["pmid"],defaults = validated_data) + reference, _ = Reference.objects.update_or_create(pmid=validated_data["pmid"],defaults = validated_data) for author_data in authors_data: author, created = Author.objects.update_or_create(**author_data) - study.authors.add(author) - study.save() + reference.authors.add(author) + reference.save() + + studies_data = validated_data.pop('study') + for study in studies_data: + reference.study_set.update_or_create(sid=study["sid"], defaults=study) - return study \ No newline at end of file + return reference diff --git a/pkdb_app/studies/views.py b/pkdb_app/studies/views.py index af0c9626..66de5423 100644 --- a/pkdb_app/studies/views.py +++ b/pkdb_app/studies/views.py @@ -1,11 +1,10 @@ -from .models import Author,Study,Intervention -from .serializers import AuthorSerializer,InterventionSerializer,StudySerializer +from .models import Author,Study, Reference +from .serializers import AuthorSerializer, ReferenceSerializer from rest_framework import viewsets import django_filters.rest_framework from rest_framework import filters -# Create your views here. class AuthorsViewSet(viewsets.ModelViewSet): queryset = Author.objects.all() @@ -15,20 +14,20 @@ class AuthorsViewSet(viewsets.ModelViewSet): search_fields = filter_fields -class StudiesViewSet(viewsets.ModelViewSet): +class ReferencesViewSet(viewsets.ModelViewSet): - queryset = Study.objects.all() - serializer_class = StudySerializer + queryset = Reference.objects.all() + serializer_class = ReferenceSerializer filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) - filter_fields = ( 'comment','description','title','pmid') + filter_fields = ( 'comment','description','pmid', 'doi', 'title', 'abstract', 'journal','year', 'authors') search_fields = filter_fields -class InterventionsViewSet(viewsets.ModelViewSet): +#class InterventionsViewSet(viewsets.ModelViewSet): - queryset = Intervention.objects.all() - serializer_class = InterventionSerializer - filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) - filter_fields = ('comment','description','type') - search_fields = filter_fields +# queryset = Intervention.objects.all() +# serializer_class = InterventionSerializer +# filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) +# filter_fields = ('comment','description','type') + # search_fields = filter_fields diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index a158da85..457deb44 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -4,9 +4,8 @@ How is different from things which will be measured? From the data structure this has to be handled very similar. - - """ + from django.db import models from ..studies.models import Study diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index 1064f130..c9e5c3fb 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -1,7 +1,3 @@ -""" -URLs -""" - from django.conf import settings from django.urls import path, include from django.conf.urls import url @@ -11,30 +7,33 @@ from rest_framework_swagger.views import get_swagger_view from .users.views import UserViewSet, UserCreateViewSet -from .studies.views import AuthorsViewSet,InterventionsViewSet,StudiesViewSet +from .studies.views import AuthorsViewSet,ReferencesViewSet + +# views in User router = DefaultRouter() +router.register(r'users', UserViewSet) +router.register(r'users', UserCreateViewSet) # views in studies -router.register('authors', AuthorsViewSet, base_name="authors") -router.register('studies', StudiesViewSet, base_name="study") -router.register('intervention', InterventionsViewSet, base_name="intervention") +router.register('authors',AuthorsViewSet,base_name="authors") +router.register('references', ReferencesViewSet, base_name="references") +#router.register('intervention',InterventionsViewSet,base_name="intervention") + +schema_view = get_swagger_view(title='PkBD API') + -# views in users -router.register(r'users', UserViewSet) -router.register(r'users', UserCreateViewSet, 'user') -# REST API -schema_view = get_swagger_view(title='PKDB API') urlpatterns = [ path('admin/', admin.site.urls), url(r'^$', schema_view), path('api/v1/', include(router.urls)), - # path('api-token-auth/', views.obtain_auth_token), + #path('api-token-auth/', views.obtain_auth_token), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), # the 'api-root' from django rest-frameworks default router # http://www.django-rest-framework.org/api-guide/routers/#defaultrouter - # re_path(r'^$', RedirectView.as_view(url=reverse_lazy('api-root'), permanent=False)), -] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + #re_path(r'^$', RedirectView.as_view(url=reverse_lazy('api-root'), permanent=False)), + + ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) From a4367590b5c05e76a417e50ed8de9c5e33324016 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 5 Jul 2018 20:26:52 +0200 Subject: [PATCH 009/115] working on models and import of caffee data --- .gitignore | 5 +- Dockerfile | 2 + docker-compose.yml | 12 +- docs/api/api.ipynb | 268 +++++++++++++----- docs/api/biopython.ipynb | 121 +++++++- pkdb_app/behaviours.py | 2 +- pkdb_app/categoricals.py | 6 +- pkdb_app/config/common.py | 3 +- pkdb_app/data_management/create_master.py | 51 +++- .../data_management/create_master_json.py | 17 +- pkdb_app/data_management/create_subjects.py | 75 +++++ pkdb_app/data_management/fill_database.py | 16 +- pkdb_app/studies/migrations/0001_initial.py | 51 ---- .../migrations/0002_publication_authors.py | 18 -- .../migrations/0003_auto_20180619_0834.py | 68 ----- .../migrations/0004_auto_20180629_1437.py | 32 --- pkdb_app/studies/migrations/__init__.py | 0 pkdb_app/studies/models.py | 25 +- pkdb_app/studies/serializers.py | 17 +- pkdb_app/studies/views.py | 5 +- pkdb_app/subjects/migrations/0001_initial.py | 113 -------- pkdb_app/subjects/migrations/__init__.py | 0 pkdb_app/subjects/models.py | 20 +- pkdb_app/subjects/serializers.py | 12 + pkdb_app/users/migrations/0001_initial.py | 47 --- .../migrations/0002_auto_20171227_2246.py | 18 -- pkdb_app/users/migrations/__init__.py | 0 pkdb_app/users/models.py | 2 +- wait_for_postgres.py | 2 +- 29 files changed, 506 insertions(+), 502 deletions(-) create mode 100644 pkdb_app/data_management/create_subjects.py delete mode 100644 pkdb_app/studies/migrations/0001_initial.py delete mode 100644 pkdb_app/studies/migrations/0002_publication_authors.py delete mode 100644 pkdb_app/studies/migrations/0003_auto_20180619_0834.py delete mode 100644 pkdb_app/studies/migrations/0004_auto_20180629_1437.py delete mode 100644 pkdb_app/studies/migrations/__init__.py delete mode 100644 pkdb_app/subjects/migrations/0001_initial.py delete mode 100644 pkdb_app/subjects/migrations/__init__.py create mode 100644 pkdb_app/subjects/serializers.py delete mode 100644 pkdb_app/users/migrations/0001_initial.py delete mode 100644 pkdb_app/users/migrations/0002_auto_20171227_2246.py delete mode 100644 pkdb_app/users/migrations/__init__.py diff --git a/.gitignore b/.gitignore index c33d94f3..4abf4dce 100644 --- a/.gitignore +++ b/.gitignore @@ -110,6 +110,9 @@ venv.bak/ # django staticfiles /static -/migrations +*/migrations/ # mypy .mypy_cache/ +pkdb_app/studies/migrations +pkdb_app/users/migrations +pkdb_app/subjects/migrations \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 0559e1f2..402e26b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,8 @@ ENV PYTHONUNBUFFERED 1 # Allows docker to cache installed dependencies between builds COPY ./requirements.txt requirements.txt RUN pip install -r requirements.txt +#ENV DJANGO_SETTINGS_MODULE pkdb_app.config.local + # Adds our application code to the image COPY . code diff --git a/docker-compose.yml b/docker-compose.yml index 3597592d..578ab504 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,12 +3,20 @@ version: '2' services: postgres: image: postgres:9.6 - #ports: - # - "5432:5432" + ports: + - "5432:5432" + environment: + + POSTGRES_USER : postgres + POSTGRES_PASSWORD: pass + POSTGRES_DB: postgres + + web: restart: always environment: - DJANGO_SECRET_KEY=local + image: web build: ./ command: > diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index cd2d3dfa..c7e53e9b 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -14,7 +14,9 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "URL_PKDB = \"http://0.0.0.0:8000/\"" @@ -50,7 +52,9 @@ { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "#r = requests.post(\"http://0.0.0.0:8000/api-auth/login/?next=/api/v1/\", data={'username': 'janek', 'password': 'test'})\n", @@ -67,7 +71,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 16, "metadata": { "collapsed": true }, @@ -81,14 +85,14 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "PKDB API\n", + "PkBD API\n", "http://0.0.0.0:8000/\n" ] } @@ -102,14 +106,14 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", " authors: {\n", " list([page], [first_name], [last_name], [search])\n", " create([first_name], [last_name])\n", @@ -118,21 +122,13 @@ " partial_update(id, [first_name], [last_name], [first_name], [last_name], [search])\n", " delete(id, [first_name], [last_name], [search])\n", " }\n", - " intervention: {\n", - " list([page], [comment], [description], [type], [search])\n", - " create(type, [comment], [description], [study])\n", - " read(id, [comment], [description], [type], [search])\n", - " update(id, type, [comment], [description], [study], [comment], [description], [type], [search])\n", - " partial_update(id, [comment], [description], [type], [study], [comment], [description], [type], [search])\n", - " delete(id, [comment], [description], [type], [search])\n", - " }\n", - " studies: {\n", - " list([page], [comment], [description], [title], [pmid], [search])\n", - " create(title, pmid, authors, [comment], [description], [abstract], [file])\n", - " read(id, [comment], [description], [title], [pmid], [search])\n", - " update(id, title, pmid, authors, [comment], [description], [abstract], [file], [comment], [description], [title], [pmid], [search])\n", - " partial_update(id, [comment], [description], [title], [pmid], [authors], [abstract], [file], [comment], [description], [title], [pmid], [search])\n", - " delete(id, [comment], [description], [title], [pmid], [search])\n", + " references: {\n", + " list([page], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " create(sid, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf])\n", + " read(id, [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " update(id, sid, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " partial_update(id, [sid], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " delete(id, [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", " }\n" ] } @@ -152,7 +148,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -188,7 +184,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -206,7 +202,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -236,7 +232,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -244,7 +240,7 @@ "output_type": "stream", "text": [ "{\n", - " \"count\": 3,\n", + " \"count\": 1,\n", " \"next\": null,\n", " \"previous\": null,\n", " \"results\": [\n", @@ -252,16 +248,6 @@ " \"id\": 1,\n", " \"first_name\": \"Lucek\",\n", " \"last_name\": \"Grzegorzewski\"\n", - " },\n", - " {\n", - " \"id\": 16,\n", - " \"first_name\": \"Marika T\",\n", - " \"last_name\": \"Granfors\"\n", - " },\n", - " {\n", - " \"id\": 42,\n", - " \"first_name\": \"L\",\n", - " \"last_name\": \"Granit\"\n", " }\n", " ]\n", "}\n" @@ -276,65 +262,193 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "ename": "ParameterError", + "evalue": "{'groups': 'Unknown parameter.'}", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mParameterError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0;34m\"doi\"\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 29\u001b[0m }\n\u001b[0;32m---> 30\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"references\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_lookup_link\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 165\u001b[0;31m \u001b[0m_validate_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0moverrides\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36m_validate_parameters\u001b[0;34m(link, parameters)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 80\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mParameterError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 81\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mParameterError\u001b[0m: {'groups': 'Unknown parameter.'}" + ] + } + ], + "source": [ + "# Create study\n", + "study_dict = {\n", + " \"pmid\": 16198659,\n", + " \"sid\": \"Granfors2005\",\n", + " \"date\": \"2005-11-02\",\n", + " \"journal\": \"Clinical pharmacology and therapeutics\",\n", + " \"title\": \"Oral contraceptives containing ethinyl estradiol and gestodene markedly increase plasma concentrations and effects of tizanidine by inhibiting cytochrome P450 1A2.\",\n", + " \"abstract\": \"OCs containing ethinyl estradiol and gestodene increase, to a clinically significant extent, the plasma concentrations and effects of tizanidine, probably mainly by inhibiting its CYP1A2-mediated presystemic metabolism. Care should be exercised when tizanidine is prescribed to OC users.\",\n", + " \"groups\":,\n", + " \"authors\": [\n", + " {\n", + " \"first_name\": \"Marika T\",\n", + " \"last_name\": \"Granfors\"\n", + " },\n", + " {\n", + " \"first_name\": \"Janne T\",\n", + " \"last_name\": \"Backman\"\n", + " },\n", + " {\n", + " \"first_name\": \"Jouko\",\n", + " \"last_name\": \"Laitila\"\n", + " },\n", + " {\n", + " \"first_name\": \"Pertti J\",\n", + " \"last_name\": \"Neuvonen\"\n", + " }\n", + " ],\n", + " \"doi\": \"\"\n", + "}\n", + "client.action(document,[\"references\", \"create\"], params=study_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": null, "metadata": { "collapsed": true }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "path =\"/home/janekg89/Develop/Pycharm_Projects/pkdb/pkdb_app/data/caffeine/Subjects.tsv\"" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def subjects_load(json_reference):\n", + " data_pd = pd.read_csv(path,delimiter='\\t')\n", + " this_data = data_pd[data_pd[\"study\"] == json_reference[\"json\"][\"sid\"]]\n", + " json = {**json_reference[\"json\"]}\n", + " json[\"groups\"] = []\n", + " print(len(this_data))\n", + " for name, row in this_data.iterrows():\n", + " yield {\"json\": json, \"group\": row.to_dict()}# \"reference_path\": json_reference[\"reference_path\"]}" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [], + "source": [ + "data = {\"json\" : study_dict }\n", + "this = subjects_load(data)" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n" + ] + }, { "data": { "text/plain": [ - "OrderedDict([('comment', None),\n", - " ('description', None),\n", - " ('title',\n", - " '4-quinolones inhibit joiijojiojioijojioji of caffeine.'),\n", - " ('pmid', '19125908'),\n", - " ('authors',\n", - " [OrderedDict([('id', 2),\n", - " ('first_name', 'C-Y'),\n", - " ('last_name', 'Fun')]),\n", - " OrderedDict([('id', 3),\n", - " ('first_name', 'Y-L'),\n", - " ('last_name', 'Law')]),\n", - " OrderedDict([('id', 4),\n", - " ('first_name', 'W-M'),\n", - " ('last_name', 'Lim')]),\n", - " OrderedDict([('id', 5),\n", - " ('first_name', 'W'),\n", - " ('last_name', 'Fan')]),\n", - " OrderedDict([('id', 6),\n", - " ('first_name', 'C-L'),\n", - " ('last_name', 'Lim')])]),\n", - " ('abstract', None),\n", - " ('file', None)])" + "{'json': {'pmid': 16198659,\n", + " 'sid': 'Granfors2005',\n", + " 'date': '2005-11-02',\n", + " 'journal': 'Clinical pharmacology and therapeutics',\n", + " 'title': 'Oral contraceptives containing ethinyl estradiol and gestodene markedly increase plasma concentrations and effects of tizanidine by inhibiting cytochrome P450 1A2.',\n", + " 'abstract': 'OCs containing ethinyl estradiol and gestodene increase, to a clinically significant extent, the plasma concentrations and effects of tizanidine, probably mainly by inhibiting its CYP1A2-mediated presystemic metabolism. Care should be exercised when tizanidine is prescribed to OC users.',\n", + " 'groups': [],\n", + " 'authors': [{'first_name': 'Marika T', 'last_name': 'Granfors'},\n", + " {'first_name': 'Janne T', 'last_name': 'Backman'},\n", + " {'first_name': 'Jouko', 'last_name': 'Laitila'},\n", + " {'first_name': 'Pertti J', 'last_name': 'Neuvonen'}],\n", + " 'doi': ''},\n", + " 'group': {'study': 'Granfors2005',\n", + " 'subjects': 'S1',\n", + " 'keywords': 'control',\n", + " 'species': 'homo sapiens',\n", + " 'strain': '-',\n", + " 'ethnicity': nan,\n", + " 'count': 15,\n", + " 'gender': 'female',\n", + " 'healthy': 'yes',\n", + " 'condition': 'healthy',\n", + " 'alcohol': nan,\n", + " 'caffeine ': nan,\n", + " 'smoking': 'no',\n", + " 'smoking_amount': nan,\n", + " 'oc': 'no',\n", + " 'age': 22.0,\n", + " 'age_sd': 2.0,\n", + " 'age_sem': nan,\n", + " 'age_min': 19.0,\n", + " 'age_max': 26.0,\n", + " 'age_unit': 'yr',\n", + " 'bw': 62.0,\n", + " 'bw_sd': 10.0,\n", + " 'bw_sem': nan,\n", + " 'bw_min': 52.0,\n", + " 'bw_max': 74.0,\n", + " 'bw_unit': 'kg',\n", + " 'height': nan,\n", + " 'height_sd': nan,\n", + " 'height_se': nan,\n", + " 'height_min': nan,\n", + " 'height_max': nan,\n", + " 'height_unit': nan,\n", + " 'subjects_details': 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.'}}" ] }, - "execution_count": 12, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# Create study\n", - "study_dict = {\n", - " 'title': \"4-quinolones inhibit joiijojiojioijojioji of caffeine.\", \n", - " 'pmid': '19125908', \n", - " 'authors':[ \n", - " {'first_name': 'C-Y', 'last_name': 'Fun'}, \n", - " {'first_name': 'Y-L', 'last_name': 'Law'}, \n", - " {'first_name': 'W-M', 'last_name': 'Lim'},\n", - " {'first_name': 'W', 'last_name': 'Fan'}, \n", - " {'first_name': 'C-L', 'last_name': 'Lim'}\n", - " \n", - " ]\n", - "}\n", - "client.action(document,[\"studies\", \"create\"], params=study_dict)" + "next(this)" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [] } diff --git a/docs/api/biopython.ipynb b/docs/api/biopython.ipynb index d0fe637c..4d5c59a4 100644 --- a/docs/api/biopython.ipynb +++ b/docs/api/biopython.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 5, + "execution_count": 1, "metadata": { "collapsed": true }, @@ -15,7 +15,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 2, "metadata": { "collapsed": true }, @@ -32,7 +32,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 47, "metadata": { "collapsed": true }, @@ -43,7 +43,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 4, "metadata": { "collapsed": true }, @@ -54,7 +54,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -78,7 +78,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -94,6 +94,115 @@ " print(t.text)" ] }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1988\n", + "1\n", + "1\n", + "1988\n", + "1\n", + "1\n", + "1988\n", + "1\n", + "1\n" + ] + } + ], + "source": [ + " for date in x.iter(\"PubMedPubDate\"):\n", + "\n", + " print(date.find('Year').text)\n", + " print(date.find('Month').text)\n", + " print(date.find('Day').text)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "import requests" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "d1 = 14699080" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "response = requests.get(f'https://www.ncbi.nlm.nih.gov/pmc/utils/idconv/v1.0/?tool=my_tool&email=my_email@example.com&ids={d}')" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "pmcids = ET.fromstring(response.content)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n", + "{'requested-id': '2853056', 'pmid': '2853056', 'live': 'false', 'status': 'error'}\n" + ] + } + ], + "source": [ + "for records in pmcids.iter(\"record\"):\n", + " #if 'doi' in records.attrib:\n", + " print(records.get('doi'))\n", + " \n", + " print(records.attrib)\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'attribs'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mrecord\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mattribs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'attribs'" + ] + } + ], + "source": [] + }, { "cell_type": "code", "execution_count": null, diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index d9787743..96ff4d11 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -8,7 +8,7 @@ class Sidable(models.Model): """ Model has an sid. """ - sid = models.CharField(max_length=CHAR_MAX_LENGTH, unique=True) + sid = models.CharField(max_length=CHAR_MAX_LENGTH) class Meta: abstract = True diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 53a9f571..6be2a566 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -12,7 +12,7 @@ # TODO: How to handle the genetic information? Genetic variants? from collections import namedtuple -CharacteristicType = namedtuple("CharacteristicType", ["value", "class", "dtype", "choices"]) +CharacteristicType = namedtuple("CharacteristicType", ["value", "category", "dtype", "choices"]) UnitType = namedtuple("UnitType", ["name"]) # TODO: lookup units package and proper units handling (units conversion, default units, ...) @@ -68,7 +68,7 @@ # Study protocol CharacteristicType('overnight fast', 'Study protocol', 'boolean', ["Y", "N"]), - CharacteristicType('alcohol abstinence', 'Study protocol', 'boolean', ["Y", "N"]), + CharacteristicType('alcohol_abstinence', 'Study protocol', 'boolean', ["Y", "N"]), # Medication @@ -88,7 +88,7 @@ def dict_and_choices(data): data_choices = [(ctype.value, ctype.value) for ctype in data] return data_dict, data_choices - +CHARACTERISTIC_CATEGORIES = set([item.value for item in CHARACTERISTIC_DATA]) CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES = dict_and_choices(CHARACTERISTIC_DATA) INTERVENTION_DICT, INTERVENTION_CHOICES = dict_and_choices(INTERVENTION_DATA) diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index c99990d4..7a4a2c79 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -29,6 +29,7 @@ class Common(Configuration): 'pkdb_app.users', 'pkdb_app.studies', 'pkdb_app.subjects', + ) # https://docs.djangoproject.com/en/2.0/topics/http/middleware/ @@ -57,7 +58,7 @@ class Common(Configuration): # Postgres DATABASES = { 'default': dj_database_url.config( - default='postgres://postgres:@postgres:5432/postgres', + default='postgres://postgres:pass@postgres:5432/postgres', conn_max_age=int(os.getenv('POSTGRES_CONN_MAX_AGE', 600)) ) } diff --git a/pkdb_app/data_management/create_master.py b/pkdb_app/data_management/create_master.py index 37cd9c13..6a286a92 100644 --- a/pkdb_app/data_management/create_master.py +++ b/pkdb_app/data_management/create_master.py @@ -8,23 +8,24 @@ import xml.etree.ElementTree as ET from Bio import Entrez import json +import requests -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../')) +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..//')) Master = os.path.join(BASEPATH, "Master") if BASEPATH not in sys.path: sys.path.append(BASEPATH) DATABASEPATH = os.path.join(BASEPATH, "data") -STUDIESPATH = os.path.join(DATABASEPATH, "caffeine", "Studies.tsv") +REFERENCESPATH = os.path.join(DATABASEPATH, "caffeine", "Studies.tsv") SUBJECTSPATH = os.path.join(DATABASEPATH, "caffeine", "Subjects.tsv") PHARMACOKINETICSPATH = os.path.join(DATABASEPATH, "caffeine", "Pharmacokinetics.tsv") INTERVENTIONSPATH = os.path.join(DATABASEPATH, "caffeine", "Interventions.tsv") DOSINGPATH = os.path.join(DATABASEPATH, "caffeine", "Dosing.tsv") MASTERPATH = os.path.join(DATABASEPATH, "Master") -STUDIESMASTERPATH = os.path.join(MASTERPATH, "Studies") +REFERENCESMASTERPATH = os.path.join(MASTERPATH, "Studies") -def extract_studies(path): +def extract_references(path): reader = csv.DictReader(open(path), delimiter='\t') for line in reader: yield dict(line) @@ -35,14 +36,14 @@ def pmid_to_int(d): yield d -def add_study_sid(d): +def add_reference_sid(d): sid = str(d["study"]) yield {**d , 'sid': sid} -def add_study_path(d): - study_path = os.path.join(STUDIESMASTERPATH, d['sid']) - yield {**d, "study_path":study_path} +def add_reference_path(d): + reference_path = os.path.join(REFERENCESMASTERPATH, d['sid']) + return {**d, "reference_path":reference_path} def load_from_biopython(d): @@ -59,13 +60,24 @@ def xml_to_data(d): def create_json(d): json_dict = {} + json_dict["pmid"] = d["pmid"] + json_dict["sid"] = d["sid"] + for date in d["data"].iter("DateCompleted"): + year = date.find('Year').text + month = date.find('Month').text + day = date.find('Day').text + json_dict["date"] = f"{year}-{str(month).zfill(2)}-{str(day).zfill(2)}" + continue + for journal in d["data"].iter("Title"): + json_dict["journal"] = journal.text + continue for title in d["data"].iter("ArticleTitle"): json_dict["title"] = title.text continue for abstract in d["data"].iter("AbstractText"): json_dict["abstract"] = abstract.text continue - json_dict["pmid"] = d["pmid"] + authors = [] for author in d["data"].iter("Author"): author_dict = {} @@ -73,11 +85,21 @@ def create_json(d): author_dict["last_name"] = author.find("LastName").text authors.append(author_dict) json_dict["authors"] = authors - return {'json': json_dict, 'study_path' : d["study_path"]} + return {'json': json_dict, 'reference_path' : d["reference_path"]} + + +def add_doi(d): + json_dict = d["json"] + response = requests.get(f'https://www.ncbi.nlm.nih.gov/pmc/utils/idconv/v1.0/?tool=my_tool&email=my_email@example.com&ids={json_dict["pmid"]}') + pmcids = ET.fromstring(response.content) + for records in pmcids.iter("record"): + json_dict["doi"] = records.get('doi', "") + + return {"json":json_dict, "reference_path": d["reference_path"]} def save_json(d): - json_file = os.path.join(d["study_path"],"data.json") + json_file = os.path.join(d["reference_path"],"data.json") with open(json_file, 'w') as fp: json.dump(d['json'],fp, indent=4) @@ -90,13 +112,14 @@ def get_graph(**options): """ graph = bonobo.Graph() graph.add_chain( - extract_studies(STUDIESPATH), + extract_references(REFERENCESPATH), pmid_to_int, - add_study_sid, - add_study_path, + add_reference_sid, + add_reference_path, load_from_biopython, xml_to_data, create_json, + add_doi, save_json, ) return graph diff --git a/pkdb_app/data_management/create_master_json.py b/pkdb_app/data_management/create_master_json.py index facf087e..882c57d1 100644 --- a/pkdb_app/data_management/create_master_json.py +++ b/pkdb_app/data_management/create_master_json.py @@ -12,7 +12,7 @@ import xml.etree.ElementTree as ET import pandas as pd -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../')) +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..//')) Master = os.path.join(BASEPATH,"Master") if BASEPATH not in sys.path: sys.path.append(BASEPATH) @@ -20,11 +20,11 @@ DATABASEPATH = os.path.join(BASEPATH, "data") path_studies = os.path.join(DATABASEPATH, "caffeine", "Studies.tsv") path_subjects = os.path.join(DATABASEPATH, "caffeine", "Subjects.tsv") -path_pharmacokinetics = os.path.join(DATABASEPATH,"caffeine", "Pharmacokinetics.tsv") -path_interventions = os.path.join(DATABASEPATH,"caffeine", "Interventions.tsv") -path_dosing = os.path.join(DATABASEPATH,"caffeine", "Dosing.tsv") -path_master = os.path.join(DATABASEPATH,"Master") -path_master_studies = os.path.join(path_master,"Studies") +path_pharmacokinetics = os.path.join(DATABASEPATH, "caffeine", "Pharmacokinetics.tsv") +path_interventions = os.path.join(DATABASEPATH, "caffeine", "Interventions.tsv") +path_dosing = os.path.join(DATABASEPATH, "caffeine", "Dosing.tsv") +path_master = os.path.join(DATABASEPATH, "Master") +path_master_studies = os.path.join(path_master, "Studies") def ensure_dir(file_path): @@ -45,6 +45,7 @@ def create_data(data_pd, file_name): ensure_dir(data_path) d.to_csv(data_path, sep="\t") + def split_into_study_folder(path,file_name): data_pd = pd.read_csv(path,delimiter='\t') create_data(data_pd, file_name) @@ -52,16 +53,16 @@ def split_into_study_folder(path,file_name): yield row - - def pmid_to_int(d): d['pmid'] = int(d['pmid']) yield d + def add_study_sid(d): sid = str(d["study"]) yield {**d ,'sid':sid} + def create_study_folder(d): study_path = os.path.join(path_master_studies,d['sid']) ensure_dir(study_path) diff --git a/pkdb_app/data_management/create_subjects.py b/pkdb_app/data_management/create_subjects.py new file mode 100644 index 00000000..b549003d --- /dev/null +++ b/pkdb_app/data_management/create_subjects.py @@ -0,0 +1,75 @@ +""" +Creates json files in master folder +""" +from fill_database import get_reference_json_path,open_json +from create_master import SUBJECTSPATH, save_json, add_reference_path +from categoricals import CHARACTERISTIC_CATEGORIES +import bonobo +import pandas as pd + + + + +def subjects_load(json_reference): + data_pd = pd.read_csv(SUBJECTSPATH,delimiter='\t') + this_data = data_pd[data_pd["reference"] == json_reference["json"]["sid"]] + json = {**json_reference["json"]} + json["groups"] = [] + for name, row in this_data.iterrows(): + yield {"json": json, "group": row.to_dict()} + + + + +def add_subject_to_json(data): + group = {} + group["count"] = data["group"]["count"] + group["sid"] = f'{data["json"]["sid"]}-{data["group"]["groups"]}' + group["description"] = data["group"]["description"] + group["characteristics_values"] = add_characteristic_values(data["group"]) + + json = {**data["json"]} + json["groups"].append(group) + return {"json":json, "reference_path":add_reference_path(json)["reference_path"]} + + +def add_characteristic_values(group): + characteristics_values = [] + for value in CHARACTERISTIC_CATEGORIES: + value_dict = {} + value_dict["value"] = value + value_dict["choice"] = group.get(value) + characteristics_values.append(value_dict) + #process_characteristic_values(category_dict) + return characteristics_values + + +def process_characteristic_values(data): + if "/" in data["choice"]: + data["choice"].split("/") + + + +def get_graph(**options): + graph = bonobo.Graph() + # add studies + graph.add_chain( + get_reference_json_path, + open_json, + subjects_load, + add_subject_to_json, + save_json, + ) + return graph + + + + +def get_services(**options): + return {} + + +if __name__ == '__main__': + parser = bonobo.get_argument_parser() + with bonobo.parse_args(parser) as options: + bonobo.run(get_graph(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 2e8da657..46fbdf3e 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -2,14 +2,14 @@ import bonobo import coreapi import json -from create_master import STUDIESMASTERPATH +from create_master import REFERENCESMASTERPATH client = coreapi.Client() document = client.get("http://0.0.0.0:8000/") -def get_study_json_path(): - for root, dirs, files in os.walk(STUDIESMASTERPATH, topdown=False): +def get_reference_json_path(): + for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "data.json" in files: yield os.path.join(root, 'data.json') @@ -17,20 +17,20 @@ def get_study_json_path(): def open_json(d): with open(d) as f: json_dict = json.loads(f.read()) - return json_dict + return {"json":json_dict, "reference_path":d} -def upload_study(json_study): - client.action(document, ["studies", "create"], params=json_study) +def upload_reference(json_reference): + client.action(document, ["references", "create"], params=json_reference["json"]) def get_graph(**options): graph = bonobo.Graph() # add studies graph.add_chain( - get_study_json_path, + get_reference_json_path, open_json, - upload_study, + upload_reference, ) return graph diff --git a/pkdb_app/studies/migrations/0001_initial.py b/pkdb_app/studies/migrations/0001_initial.py deleted file mode 100644 index 06df8ecd..00000000 --- a/pkdb_app/studies/migrations/0001_initial.py +++ /dev/null @@ -1,51 +0,0 @@ -# Generated by Django 2.0.6 on 2018-06-18 16:21 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='Author', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('first_name', models.CharField(blank=True, max_length=30)), - ('last_name', models.CharField(blank=True, max_length=150)), - ], - ), - migrations.CreateModel( - name='Publication', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sid', models.CharField(max_length=30, unique=True)), - ('comment', models.TextField(blank=True, null=True)), - ('description', models.TextField(blank=True, null=True)), - ('title', models.CharField(max_length=30)), - ('pmid', models.CharField(max_length=30)), - ('file', models.FileField(blank=True, null=True, upload_to='publications')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='Study', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sid', models.CharField(max_length=30, unique=True)), - ('comment', models.TextField(blank=True, null=True)), - ('description', models.TextField(blank=True, null=True)), - ('type', models.IntegerField(choices=[(1, 'Dynamic Single'), (2, 'Dynamic Multiple'), (3, 'Static Single'), (4, 'Static Multiple'), (5, 'Else')])), - ('publication', models.ForeignKey(blank=True, null=True, on_delete=True, to='studies.Publication')), - ], - options={ - 'abstract': False, - }, - ), - ] diff --git a/pkdb_app/studies/migrations/0002_publication_authors.py b/pkdb_app/studies/migrations/0002_publication_authors.py deleted file mode 100644 index 30f92f40..00000000 --- a/pkdb_app/studies/migrations/0002_publication_authors.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.0.6 on 2018-06-18 16:23 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('studies', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='publication', - name='authors', - field=models.ManyToManyField(blank=True, to='studies.Author'), - ), - ] diff --git a/pkdb_app/studies/migrations/0003_auto_20180619_0834.py b/pkdb_app/studies/migrations/0003_auto_20180619_0834.py deleted file mode 100644 index 8f19f939..00000000 --- a/pkdb_app/studies/migrations/0003_auto_20180619_0834.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 2.0.6 on 2018-06-19 08:34 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('studies', '0002_publication_authors'), - ] - - operations = [ - migrations.CreateModel( - name='Intervention', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sid', models.CharField(max_length=30, unique=True)), - ('comment', models.TextField(blank=True, null=True)), - ('description', models.TextField(blank=True, null=True)), - ('type', models.IntegerField(choices=[(1, 'Else'), (2, 'Dynamic Single'), (3, 'Dynamic Multiple'), (4, 'Static Single'), (5, 'Static Multiple')])), - ], - options={ - 'abstract': False, - }, - ), - migrations.RemoveField( - model_name='publication', - name='authors', - ), - migrations.RemoveField( - model_name='study', - name='publication', - ), - migrations.RemoveField( - model_name='study', - name='type', - ), - migrations.AddField( - model_name='study', - name='authors', - field=models.ManyToManyField(blank=True, to='studies.Author'), - ), - migrations.AddField( - model_name='study', - name='file', - field=models.FileField(blank=True, null=True, upload_to='study'), - ), - migrations.AddField( - model_name='study', - name='pmid', - field=models.CharField(default=0, max_length=30), - preserve_default=False, - ), - migrations.AddField( - model_name='study', - name='title', - field=models.CharField(default=0, max_length=30), - preserve_default=False, - ), - migrations.DeleteModel( - name='Publication', - ), - migrations.AddField( - model_name='intervention', - name='study', - field=models.ForeignKey(blank=True, null=True, on_delete=True, to='studies.Study'), - ), - ] diff --git a/pkdb_app/studies/migrations/0004_auto_20180629_1437.py b/pkdb_app/studies/migrations/0004_auto_20180629_1437.py deleted file mode 100644 index 49e8c080..00000000 --- a/pkdb_app/studies/migrations/0004_auto_20180629_1437.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 2.0.6 on 2018-06-29 14:37 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('studies', '0003_auto_20180619_0834'), - ] - - operations = [ - migrations.RemoveField( - model_name='study', - name='sid', - ), - migrations.AddField( - model_name='study', - name='abstract', - field=models.TextField(blank=True, null=True), - ), - migrations.AlterField( - model_name='study', - name='authors', - field=models.ManyToManyField(blank=True, related_name='authors', to='studies.Author'), - ), - migrations.AlterField( - model_name='study', - name='title', - field=models.TextField(), - ), - ] diff --git a/pkdb_app/studies/migrations/__init__.py b/pkdb_app/studies/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index f80f7e90..3eab1237 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -26,34 +26,33 @@ class KeyWord(models.Model): # All models should be commentable -class Reference(models.Model): +class Reference(Sidable,models.Model): """ This is the main class describing the publication or reference which describes the study. In most cases this is a published paper, but could be a thesis or unpublished. """ - - pmid = models.CharField(max_length=CHAR_MAX_LENGTH) #optional - doi = models.CharField(max_length=CHAR_MAX_LENGTH) #optional + pmid = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) #optional + doi = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) #optional title = models.TextField() abstract = models.TextField(blank=True, null=True) - journal = models.CharField(max_length=CHAR_MAX_LENGTH) - year = models.DateField() + journal = models.TextField(blank=True, null=True) + date = models.DateField() pdf = models.FileField(upload_to="study", null=True, blank=True) authors = models.ManyToManyField(Author, blank=True, related_name='authors') -class Study(Sidable, Commentable, Describable, models.Model): - """ Single clinical study. +#class Study(Sidable, Commentable, Describable, models.Model): + # """ Single clinical study. - Mainly reported as a single publication. + # Mainly reported as a single publication. - """ + # """ # sid should be the AuthorYear if possible # comments #description (if no description is provided, this is filled with the abstract) #files (PNG, CSV) (all files with exception of pdf) - files = models.ManyToManyField(Files, related_name="files") - reference = models.ForeignKey(Reference, null=True, blank=True, on_delete=True) - keywords = models.ManyToManyField(KeyWord, blank=True, related_name='keywords') + #files = models.ManyToManyField(Files, related_name="files") + #reference = models.ForeignKey(Reference, null=True, blank=True, on_delete=True) + #keywords = models.ManyToManyField(KeyWord, blank=True, related_name='keywords') #interventions #subjects diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 206c62c2..11eef754 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -1,8 +1,8 @@ from rest_framework import serializers -from .models import Reference, Author, Study +from .models import Reference, Author +from ..subjects.serializers import GroupSerializer - -BASE_FIELDS = ('comment', 'description',) +BASE_FIELDS = () #class InterventionSerializer(serializers.ModelSerializer): @@ -27,21 +27,24 @@ def create(self, validated_data): class ReferenceSerializer(serializers.ModelSerializer): authors = AuthorSerializer(many=True,read_only=False)#, queryset=Study.objects.all(), source='studies') + groups = GroupSerializer(many=True,read_only=False)#, queryset=Study.objects.all(), source='studies') class Meta: model = Reference - fields = BASE_FIELDS + ('pmid', 'doi', 'title', 'abstract', 'journal','year', 'authors','pdf') + fields = BASE_FIELDS + ('sid','groups', 'pmid', 'doi', 'title', 'abstract', 'journal','date', 'authors','pdf') def create(self, validated_data): authors_data = validated_data.pop('authors') + groups_data = validated_data.pop('groups') + reference, _ = Reference.objects.update_or_create(pmid=validated_data["pmid"],defaults = validated_data) for author_data in authors_data: author, created = Author.objects.update_or_create(**author_data) reference.authors.add(author) reference.save() - studies_data = validated_data.pop('study') - for study in studies_data: - reference.study_set.update_or_create(sid=study["sid"], defaults=study) + for group in groups_data: + reference.group_set.update_or_create(sid=group["sid"], defaults=group) return reference + diff --git a/pkdb_app/studies/views.py b/pkdb_app/studies/views.py index 66de5423..8372360e 100644 --- a/pkdb_app/studies/views.py +++ b/pkdb_app/studies/views.py @@ -1,4 +1,4 @@ -from .models import Author,Study, Reference +from .models import Author, Reference from .serializers import AuthorSerializer, ReferenceSerializer from rest_framework import viewsets import django_filters.rest_framework @@ -19,10 +19,11 @@ class ReferencesViewSet(viewsets.ModelViewSet): queryset = Reference.objects.all() serializer_class = ReferenceSerializer filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) - filter_fields = ( 'comment','description','pmid', 'doi', 'title', 'abstract', 'journal','year', 'authors') + filter_fields = ( 'pmid', 'doi','title', 'abstract', 'journal','date', 'authors') search_fields = filter_fields + #class InterventionsViewSet(viewsets.ModelViewSet): # queryset = Intervention.objects.all() diff --git a/pkdb_app/subjects/migrations/0001_initial.py b/pkdb_app/subjects/migrations/0001_initial.py deleted file mode 100644 index 16be2815..00000000 --- a/pkdb_app/subjects/migrations/0001_initial.py +++ /dev/null @@ -1,113 +0,0 @@ -# Generated by Django 2.0.6 on 2018-06-19 08:57 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('studies', '0003_auto_20180619_0834'), - ] - - operations = [ - migrations.CreateModel( - name='CharacteristicBinary', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sid', models.CharField(max_length=30, unique=True)), - ('type', models.IntegerField(choices=[(1, 'Else'), (2, 'Antropometrie'), (3, 'Life Style'), (4, 'Genetics')])), - ('value', models.BinaryField()), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='CharacteristicContinous', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sid', models.CharField(max_length=30, unique=True)), - ('type', models.IntegerField(choices=[(1, 'Else'), (2, 'Antropometrie'), (3, 'Life Style'), (4, 'Genetics')])), - ('value', models.FloatField()), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='CharacteristicRange', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sid', models.CharField(max_length=30, unique=True)), - ('type', models.IntegerField(choices=[(1, 'Else'), (2, 'Antropometrie'), (3, 'Life Style'), (4, 'Genetics')])), - ('start', models.FloatField()), - ('end', models.FloatField()), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='RelativeAmount', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('relative_amount', models.FloatField()), - ], - ), - migrations.CreateModel( - name='Subject', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sid', models.CharField(max_length=30, unique=True)), - ('specie', models.IntegerField(choices=[(1, 'Else'), (2, 'Homo Sapiens')])), - ('characteristics_binary', models.ManyToManyField(to='subjects.CharacteristicBinary')), - ('characteristics_continous', models.ManyToManyField(to='subjects.CharacteristicContinous')), - ('characteristics_range', models.ManyToManyField(to='subjects.CharacteristicRange')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='SubjectGroup', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sid', models.CharField(max_length=30, unique=True)), - ('number', models.IntegerField()), - ('Intervention', models.ForeignKey(on_delete=True, to='studies.Intervention')), - ('subjects', models.ManyToManyField(through='subjects.RelativeAmount', to='subjects.Subject')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='SubjectTag', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sid', models.CharField(max_length=30, unique=True)), - ('description', models.TextField(blank=True, null=True)), - ], - options={ - 'abstract': False, - }, - ), - migrations.AddField( - model_name='subject', - name='tags', - field=models.ManyToManyField(to='subjects.SubjectTag'), - ), - migrations.AddField( - model_name='relativeamount', - name='subjects', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.Subject'), - ), - migrations.AddField( - model_name='relativeamount', - name='subjects_group', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.SubjectGroup'), - ), - ] diff --git a/pkdb_app/subjects/migrations/__init__.py b/pkdb_app/subjects/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 457deb44..26ed1ce7 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -8,7 +8,7 @@ from django.db import models -from ..studies.models import Study +from ..studies.models import Reference from ..behaviours import Sidable, Describable from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, UNITS_CHOICES from ..utils import CHAR_MAX_LENGTH @@ -26,7 +26,7 @@ class Characteristic(Sidable, models.Model): """ Characteristic. Characteristics are used to store the information about subjects. """ - name = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) + value = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) @property def characteristic_data(self): @@ -34,7 +34,7 @@ def characteristic_data(self): :return: """ - return CHARACTERISTIC_DICT[self.name] + return CHARACTERISTIC_DICT[self.value] @property def choices(self): @@ -49,7 +49,7 @@ class CharacteristicValue(Characteristic): This is the concrete selection/information of the characteristics. This stores the raw information. Derived values can be calculated. """ - choice = models.CharField() # check in validation that allowed choice + choice = models.CharField(max_length=CHAR_MAX_LENGTH) # check in validation that allowed choice count = models.IntegerField() # how many participants in characteristics value = models.FloatField(null=True, blank=True) @@ -64,7 +64,7 @@ class CharacteristicValue(Characteristic): unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH) - timecourse = models.ForeignKey(Timecourse) + #timecourse = models.ForeignKey(Timecourse) def validate(self): """ Check that choices are valid. I.e. that choice is allowed choice from choices for @@ -82,17 +82,17 @@ class ProcessedCharacteristicValue(CharacteristicValue): """ Processed and normalized data (calculated on change from corresponding raw CharacteristicValue. """ - raw = models.OneToOneField(CharacteristicValue) + raw = models.OneToOneField(CharacteristicValue,parent_link=True, on_delete=True) -class Group(Sidable, models.Model): +class Group(Sidable,Describable, models.Model): """ Individual or group of people. Groups are defined via their characteristics. """ - study = models.ForeignKey(Study, on_delete=True) - name = models.TextField() + reference = models.ForeignKey(Reference, on_delete=True) + # = models.TextField(null=True) count = models.IntegerField() - characteristics = models.ManyToManyField(Characteristic, on_delete=True) + characteristic_value = models.ManyToManyField(CharacteristicValue) # TODO: How to handle Pharmacokinetics data? diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py new file mode 100644 index 00000000..4a12a948 --- /dev/null +++ b/pkdb_app/subjects/serializers.py @@ -0,0 +1,12 @@ +from rest_framework import serializers +from .models import Group + +BASE_FIELDS = () + + + +class GroupSerializer(serializers.ModelSerializer): + + class Meta: + model = Group + fields = BASE_FIELDS + ('sid','description','count') \ No newline at end of file diff --git a/pkdb_app/users/migrations/0001_initial.py b/pkdb_app/users/migrations/0001_initial.py deleted file mode 100644 index 30879fb3..00000000 --- a/pkdb_app/users/migrations/0001_initial.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.8 on 2017-12-21 03:04 -from __future__ import unicode_literals - -import django.contrib.auth.models -import django.contrib.auth.validators -from django.db import migrations, models -import django.utils.timezone -import uuid - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('auth', '0008_alter_user_username_max_length'), - ] - - operations = [ - migrations.CreateModel( - name='User', - fields=[ - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=30, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), - ], - options={ - 'verbose_name': 'user', - 'verbose_name_plural': 'users', - 'abstract': False, - }, - managers=[ - ('objects', django.contrib.auth.models.UserManager()), - ], - ), - ] diff --git a/pkdb_app/users/migrations/0002_auto_20171227_2246.py b/pkdb_app/users/migrations/0002_auto_20171227_2246.py deleted file mode 100644 index f192825f..00000000 --- a/pkdb_app/users/migrations/0002_auto_20171227_2246.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.0 on 2017-12-27 22:46 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='last_name', - field=models.CharField(blank=True, max_length=150, verbose_name='last name'), - ), - ] diff --git a/pkdb_app/users/migrations/__init__.py b/pkdb_app/users/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkdb_app/users/models.py b/pkdb_app/users/models.py index 3281fd00..77d6759b 100644 --- a/pkdb_app/users/models.py +++ b/pkdb_app/users/models.py @@ -11,7 +11,7 @@ @python_2_unicode_compatible class User(AbstractUser): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - models.BO + def __str__(self): return self.username diff --git a/wait_for_postgres.py b/wait_for_postgres.py index 4ab45e2a..2e2b31ee 100644 --- a/wait_for_postgres.py +++ b/wait_for_postgres.py @@ -8,7 +8,7 @@ config = { "dbname": os.getenv("POSTGRES_DB", "postgres"), "user": os.getenv("POSTGRES_USER", "postgres"), - "password": os.getenv("POSTGRES_PASSWORD", ""), + "password": os.getenv("POSTGRES_PASSWORD", "pass"), "host": os.getenv("DATABASE_URL", "postgres") } From 00b0e8776c50753feb8d194cbecb6a452e091aba Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 6 Jul 2018 22:29:29 +0200 Subject: [PATCH 010/115] groups and references can be uploaded. now interventaions and data! --- docs/api/api.ipynb | 401 ++++++++++++++++---- pkdb_app/categoricals.py | 12 +- pkdb_app/data_management/create_master.py | 1 + pkdb_app/data_management/create_subjects.py | 87 ++++- pkdb_app/studies/models.py | 2 +- pkdb_app/studies/serializers.py | 11 +- pkdb_app/subjects/managers.py | 15 + pkdb_app/subjects/models.py | 48 +-- pkdb_app/subjects/serializers.py | 11 +- pkdb_app/subjects/views.py | 34 ++ pkdb_app/urls.py | 5 +- 11 files changed, 516 insertions(+), 111 deletions(-) create mode 100644 pkdb_app/subjects/managers.py create mode 100644 pkdb_app/subjects/views.py diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index c7e53e9b..0c2c99be 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -71,7 +71,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 42, "metadata": { "collapsed": true }, @@ -85,7 +85,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 43, "metadata": {}, "outputs": [ { @@ -106,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 44, "metadata": {}, "outputs": [ { @@ -122,12 +122,28 @@ " partial_update(id, [first_name], [last_name], [first_name], [last_name], [search])\n", " delete(id, [first_name], [last_name], [search])\n", " }\n", + " characteristic_values: {\n", + " list([page], [choice], [count], [category], [search])\n", + " create(category, count, unit, [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv])\n", + " read(id, [choice], [count], [category], [search])\n", + " update(id, category, count, unit, [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [choice], [count], [category], [search])\n", + " partial_update(id, [category], [choice], [count], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [choice], [count], [category], [search])\n", + " delete(id, [choice], [count], [category], [search])\n", + " }\n", + " groups: {\n", + " list([page], [description], [sid], [search])\n", + " create(sid, count, [description])\n", + " read(id, [description], [sid], [search])\n", + " update(id, sid, count, [description], [description], [sid], [search])\n", + " partial_update(id, [sid], [description], [count], [description], [sid], [search])\n", + " delete(id, [description], [sid], [search])\n", + " }\n", " references: {\n", " list([page], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " create(sid, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf])\n", + " create(sid, groups, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf])\n", " read(id, [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " update(id, sid, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " partial_update(id, [sid], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " update(id, sid, groups, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " partial_update(id, [sid], [groups], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", " delete(id, [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", " }\n" ] @@ -148,7 +164,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -156,16 +172,10 @@ "output_type": "stream", "text": [ "{\n", - " \"count\": 1,\n", + " \"count\": 0,\n", " \"next\": null,\n", " \"previous\": null,\n", - " \"results\": [\n", - " {\n", - " \"id\": 1,\n", - " \"first_name\": \"Lucek\",\n", - " \"last_name\": \"Grzegorzewski\"\n", - " }\n", - " ]\n", + " \"results\": []\n", "}\n" ] } @@ -184,7 +194,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -202,7 +212,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -232,7 +242,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 77, "metadata": {}, "outputs": [ { @@ -240,16 +250,10 @@ "output_type": "stream", "text": [ "{\n", - " \"count\": 1,\n", + " \"count\": 0,\n", " \"next\": null,\n", " \"previous\": null,\n", - " \"results\": [\n", - " {\n", - " \"id\": 1,\n", - " \"first_name\": \"Lucek\",\n", - " \"last_name\": \"Grzegorzewski\"\n", - " }\n", - " ]\n", + " \"results\": []\n", "}\n" ] } @@ -257,70 +261,317 @@ "source": [ "# Search for author\n", "data = client.action(document, [\"authors\", \"list\"], params={\"search\": \"Gr\"} )\n", - "print(json.dumps(data, indent=2))" + "print(json.dumps(data, indent=2))\n", + "import numpy as np" ] }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 80, "metadata": {}, "outputs": [ { - "ename": "ParameterError", - "evalue": "{'groups': 'Unknown parameter.'}", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mParameterError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0;34m\"doi\"\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 29\u001b[0m }\n\u001b[0;32m---> 30\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"references\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_lookup_link\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 165\u001b[0;31m \u001b[0m_validate_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0moverrides\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36m_validate_parameters\u001b[0;34m(link, parameters)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 80\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mParameterError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 81\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mParameterError\u001b[0m: {'groups': 'Unknown parameter.'}" - ] + "data": { + "text/plain": [ + "OrderedDict([('sid', 'Haller2002'),\n", + " ('groups',\n", + " [OrderedDict([('reference', 1),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 43),\n", + " ('category', 'caffeine_amount'),\n", + " ('choice', None),\n", + " ('count', 8),\n", + " ('value', None),\n", + " ('mean', 6.0),\n", + " ('median', 4.0),\n", + " ('min', 8.0),\n", + " ('max', None),\n", + " ('sd', 8.0),\n", + " ('se', 4.0),\n", + " ('cv', 7.0),\n", + " ('unit', 'yr'),\n", + " ('group', 1)])]),\n", + " ('sid', 'Haller2002-S1'),\n", + " ('description',\n", + " 'tory teses rate or blood pressure.'),\n", + " ('count', 8)])]),\n", + " ('pmid', '12087345'),\n", + " ('doi', ''),\n", + " ('title',\n", + " 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.'),\n", + " ('abstract', 'Botanical stimgle dose.'),\n", + " ('journal', 'Clinical pharmacology and therapeutics'),\n", + " ('date', '2002-07-16'),\n", + " ('authors',\n", + " [OrderedDict([('id', 1),\n", + " ('first_name', 'Christine A'),\n", + " ('last_name', 'Haller')]),\n", + " OrderedDict([('id', 2),\n", + " ('first_name', 'Peyton'),\n", + " ('last_name', 'Jacob')]),\n", + " OrderedDict([('id', 3),\n", + " ('first_name', 'Neal L'),\n", + " ('last_name', 'Benowitz')])]),\n", + " ('pdf', None)])" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ "# Create study\n", - "study_dict = {\n", - " \"pmid\": 16198659,\n", - " \"sid\": \"Granfors2005\",\n", - " \"date\": \"2005-11-02\",\n", + "reference_dict = {\n", + " \"pmid\": 12087345,\n", + " \"sid\": \"Haller2002\",\n", + " \"date\": \"2002-07-16\",\n", " \"journal\": \"Clinical pharmacology and therapeutics\",\n", - " \"title\": \"Oral contraceptives containing ethinyl estradiol and gestodene markedly increase plasma concentrations and effects of tizanidine by inhibiting cytochrome P450 1A2.\",\n", - " \"abstract\": \"OCs containing ethinyl estradiol and gestodene increase, to a clinically significant extent, the plasma concentrations and effects of tizanidine, probably mainly by inhibiting its CYP1A2-mediated presystemic metabolism. Care should be exercised when tizanidine is prescribed to OC users.\",\n", - " \"groups\":,\n", + " \"title\": \"Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.\",\n", + " \"abstract\": \"Botanical stimgle dose.\",\n", " \"authors\": [\n", " {\n", - " \"first_name\": \"Marika T\",\n", - " \"last_name\": \"Granfors\"\n", - " },\n", - " {\n", - " \"first_name\": \"Janne T\",\n", - " \"last_name\": \"Backman\"\n", + " \"first_name\": \"Christine A\",\n", + " \"last_name\": \"Haller\"\n", " },\n", " {\n", - " \"first_name\": \"Jouko\",\n", - " \"last_name\": \"Laitila\"\n", + " \"first_name\": \"Peyton\",\n", + " \"last_name\": \"Jacob\"\n", " },\n", " {\n", - " \"first_name\": \"Pertti J\",\n", - " \"last_name\": \"Neuvonen\"\n", + " \"first_name\": \"Neal L\",\n", + " \"last_name\": \"Benowitz\"\n", " }\n", " ],\n", - " \"doi\": \"\"\n", + " \"doi\": \"\",\n", + " \"groups\":[\n", + " {\n", + " \"count\": 8,\n", + " \"sid\": \"Haller2002-S1\",\n", + " \"description\": \" tory teses rate or blood pressure.\",\n", + " \"characteristic_values\": [\n", + " {\n", + " \"category\": \"caffeine_amount\",\n", + " \"count\": 8,\n", + " \"mean\": 6,\n", + " \"median\": 4,\n", + " \"min\": 8,\n", + " \"max\": None,\n", + " \"sd\": 8,\n", + " \"se\": 4,\n", + " \"cv\": 7,\n", + " \"unit\": \"yr\"\n", + " },\n", + " ]\n", + " }\n", + " ]\n", "}\n", - "client.action(document,[\"references\", \"create\"], params=study_dict)" + "\n", + "client.action(document,[\"references\", \"create\"], params=reference_dict)" ] }, { "cell_type": "code", - "execution_count": 32, - "metadata": { - "collapsed": true - }, + "execution_count": 116, + "metadata": {}, "outputs": [], "source": [ - "import pandas as pd" + "import json\n", + "with open('/home/janekg89/Develop/Pycharm_Projects/pkdb/pkdb_app/data/Master/Studies/Kaplan1997/data.json') as f:\n", + " data = json.load(f)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [ + { + "ename": "ParameterError", + "evalue": "{'groups': 'This parameter is required.'}", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mParameterError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"references\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_lookup_link\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 165\u001b[0;31m \u001b[0m_validate_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0moverrides\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36m_validate_parameters\u001b[0;34m(link, parameters)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 80\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mParameterError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 81\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mParameterError\u001b[0m: {'groups': 'This parameter is required.'}" + ] + } + ], + "source": [ + "client.action(document,[\"references\", \"create\"], params=data)" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "ename": "ErrorMessage", + "evalue": "\n group: [\n \"This field is required.\"\n ]", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;34m\"unit\"\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m }\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"characteristic_values\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcharaVal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mErrorMessage\u001b[0m: \n group: [\n \"This field is required.\"\n ]" + ] + } + ], + "source": [ + "charaVal = {\n", + " \"category\": \"caffeine_amount\",\n", + " \"count\": 8,\n", + " \"mean\": None,\n", + " \"median\": None,\n", + " \"min\": None,\n", + " \"max\": None,\n", + " \"sd\": None,\n", + " \"se\": None,\n", + " \"cv\": None,\n", + " \"unit\": None\n", + " }\n", + "client.action(document,[\"characteristic_values\", \"create\"], params=charaVal)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'pmid': 12087345,\n", + " 'sid': 'Haller2002',\n", + " 'date': '2002-07-16',\n", + " 'journal': 'Clinical pharmacology and therapeutics',\n", + " 'title': 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.',\n", + " 'abstract': 'Botanical stimulants have disposition characteristics similar to their pharmaceutical counterparts, and they can produce significant cardiovascular responses after a single dose.',\n", + " 'authors': [{'first_name': 'Christine A', 'last_name': 'Haller'},\n", + " {'first_name': 'Peyton', 'last_name': 'Jacob'},\n", + " {'first_name': 'Neal L', 'last_name': 'Benowitz'}],\n", + " 'doi': '',\n", + " 'groups': [{'count': 8,\n", + " 'sid': 'Haller2002-S1',\n", + " 'description': 'Eight healthy volunteers (5 women and 3 men) from 25 to 38 years old participated in the study. Eligibility for the study was determined on the basis of medical history, brief physical examination, and screening laboratory tests that included complete blood count, serum chemistry values to assess liver and renal function, urine toxicology testing for drugs of abuse, and a urine pregnancy test for women. Exclusion criteria included any person with obesity (body mass index 30), or a history of heart, thyroid, liver, kidney, or psychiatric disease, diabetes, central nervous system disorders, prostate hypertrophy, narrow angle glaucoma, or pregnancy or lactation. Any person with recent use (previous 1 month) of any product that contained ephedrine alkaloids or with a history of illicit substance use within the previous year was excluded. Smokers and heavy users of caffeine (4 cups of coffee per day) were excluded. Participants were not taking any medications that would cause changes in heart rate or blood pressure.',\n", + " 'characteristic_values': [{'count': 8,\n", + " 'category': 'medication',\n", + " 'choice': ''},\n", + " {'count': 8, 'category': 'overnight_fast', 'choice': ''},\n", + " {'count': 8, 'category': 'healthy', 'choice': 'Y'},\n", + " {'count': 8, 'category': 'species', 'choice': 'homo sapiens'},\n", + " {'count': 8, 'category': 'ethnicity', 'choice': 'NANS'},\n", + " {'category': 'height',\n", + " 'count': 8,\n", + " 'mean': '',\n", + " 'median': '',\n", + " 'min': '',\n", + " 'max': '',\n", + " 'sd': '',\n", + " 'se': '',\n", + " 'cv': '',\n", + " 'unit': ''},\n", + " {'category': 'waist_circumference',\n", + " 'count': 8,\n", + " 'mean': '',\n", + " 'median': '',\n", + " 'min': '',\n", + " 'max': '',\n", + " 'sd': '',\n", + " 'se': '',\n", + " 'cv': '',\n", + " 'unit': ''},\n", + " {'category': 'age',\n", + " 'count': 8,\n", + " 'mean': 'NANS',\n", + " 'median': '',\n", + " 'min': '25',\n", + " 'max': '38',\n", + " 'sd': 'NANS',\n", + " 'se': 'NANS',\n", + " 'cv': '',\n", + " 'unit': 'yr'},\n", + " {'category': 'bmi',\n", + " 'count': 8,\n", + " 'mean': '',\n", + " 'median': '',\n", + " 'min': '',\n", + " 'max': '',\n", + " 'sd': '',\n", + " 'se': '',\n", + " 'cv': '',\n", + " 'unit': ''},\n", + " {'count': 8, 'category': 'smoking', 'choice': 'N'},\n", + " {'category': 'alcohol_amount',\n", + " 'count': 8,\n", + " 'mean': '',\n", + " 'median': '',\n", + " 'min': '',\n", + " 'max': '',\n", + " 'sd': '',\n", + " 'se': '',\n", + " 'cv': '',\n", + " 'unit': ''},\n", + " {'count': 8, 'category': 'caffeine', 'choice': ''},\n", + " {'count': 8, 'category': 'alcohol_abstinence', 'choice': ''},\n", + " {'category': 'body_weight',\n", + " 'count': 8,\n", + " 'mean': '68.49',\n", + " 'median': '',\n", + " 'min': '',\n", + " 'max': '88.9',\n", + " 'sd': '',\n", + " 'se': 'NANS',\n", + " 'cv': '',\n", + " 'unit': 'kg'},\n", + " {'category': 'smoking_amount',\n", + " 'count': 8,\n", + " 'mean': '',\n", + " 'median': '',\n", + " 'min': '',\n", + " 'max': '',\n", + " 'sd': '',\n", + " 'se': '',\n", + " 'cv': '',\n", + " 'unit': ''},\n", + " {'count': '2', 'category': 'oral_contraceptives', 'choice': 'Y'},\n", + " {'count': '5', 'category': 'oral_contraceptives', 'choice': 'N'},\n", + " {'count': 8, 'category': 'disease', 'choice': ''},\n", + " {'count': 8, 'category': 'alcohol', 'choice': ''},\n", + " {'count': '3', 'category': 'sex', 'choice': 'M'},\n", + " {'count': '5', 'category': 'sex', 'choice': 'F'},\n", + " {'category': 'caffeine_amount',\n", + " 'count': 8,\n", + " 'mean': '',\n", + " 'median': '',\n", + " 'min': '',\n", + " 'max': '',\n", + " 'sd': '',\n", + " 'se': '',\n", + " 'cv': '',\n", + " 'unit': ''}]}]}" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reference_dict" ] }, { @@ -364,7 +615,9 @@ { "cell_type": "code", "execution_count": 54, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "data = {\"json\" : study_dict }\n", @@ -443,6 +696,26 @@ "next(this)" ] }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"33.7\".replace('.','',1).isdigit()" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 6be2a566..9826440a 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -20,8 +20,9 @@ UnitType('-'), UnitType('cm'), UnitType('m'), UnitType('kg'), - UnitType('y'), + UnitType('yr'), UnitType('kg/m^2'), + UnitType('1/day'), ] UNITS_CHOICES = [(utype.name, utype.name) for utype in UNIT_DATA] @@ -35,7 +36,7 @@ COMMON_DATA = [ # Medication - CharacteristicType('oral contraceptives', 'Contraceptives', 'boolean', ["Y", "N"]), + CharacteristicType('oral_contraceptives', 'Contraceptives', 'boolean', ["Y", "N"]), CharacteristicType('medication', 'Medication', 'categorial', ["ibuprofen", "paracetamol", "aspirin"]), # ? dosing # Lifestyle @@ -47,11 +48,11 @@ # Antropmetrical information CharacteristicType('species', 'Species', 'categorial', ["Homo sapiens"]), CharacteristicType('height', 'BodyParameter', 'numeric', None), - CharacteristicType('body weight', 'BodyParameter', 'numeric', None), + CharacteristicType('body_weight', 'BodyParameter', 'numeric', None), CharacteristicType('age', 'BodyParameter', 'numeric', None), CharacteristicType('sex', 'BodyParameter', 'categorial', ["M", "F"]), CharacteristicType('bmi', 'BodyParameter', 'numeric', None), - CharacteristicType('waist circumference', 'BodyParameter', 'numeric', None), + CharacteristicType('waist_circumference', 'BodyParameter', 'numeric', None), CharacteristicType('ethnicity', 'Ethnicity', 'categorial', ["african", "afroamerican", "asian", "caucasian"]), # Disease (status) @@ -67,7 +68,7 @@ # Study protocol - CharacteristicType('overnight fast', 'Study protocol', 'boolean', ["Y", "N"]), + CharacteristicType('overnight_fast', 'Study protocol', 'boolean', ["Y", "N"]), CharacteristicType('alcohol_abstinence', 'Study protocol', 'boolean', ["Y", "N"]), # Medication @@ -88,6 +89,7 @@ def dict_and_choices(data): data_choices = [(ctype.value, ctype.value) for ctype in data] return data_dict, data_choices +CHARACTERISTIC_DTYPE = {item.value : item.dtype for item in CHARACTERISTIC_DATA} CHARACTERISTIC_CATEGORIES = set([item.value for item in CHARACTERISTIC_DATA]) CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES = dict_and_choices(CHARACTERISTIC_DATA) INTERVENTION_DICT, INTERVENTION_CHOICES = dict_and_choices(INTERVENTION_DATA) diff --git a/pkdb_app/data_management/create_master.py b/pkdb_app/data_management/create_master.py index 6a286a92..641132bc 100644 --- a/pkdb_app/data_management/create_master.py +++ b/pkdb_app/data_management/create_master.py @@ -60,6 +60,7 @@ def xml_to_data(d): def create_json(d): json_dict = {} + json_dict["groups"] = [] json_dict["pmid"] = d["pmid"] json_dict["sid"] = d["sid"] for date in d["data"].iter("DateCompleted"): diff --git a/pkdb_app/data_management/create_subjects.py b/pkdb_app/data_management/create_subjects.py index b549003d..30ab2c57 100644 --- a/pkdb_app/data_management/create_subjects.py +++ b/pkdb_app/data_management/create_subjects.py @@ -3,11 +3,11 @@ """ from fill_database import get_reference_json_path,open_json from create_master import SUBJECTSPATH, save_json, add_reference_path -from categoricals import CHARACTERISTIC_CATEGORIES +from categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE import bonobo import pandas as pd - - +import numpy as np +import math def subjects_load(json_reference): @@ -26,7 +26,7 @@ def add_subject_to_json(data): group["count"] = data["group"]["count"] group["sid"] = f'{data["json"]["sid"]}-{data["group"]["groups"]}' group["description"] = data["group"]["description"] - group["characteristics_values"] = add_characteristic_values(data["group"]) + group["characteristic_values"] = add_characteristic_values(data["group"]) json = {**data["json"]} json["groups"].append(group) @@ -35,18 +35,79 @@ def add_subject_to_json(data): def add_characteristic_values(group): characteristics_values = [] - for value in CHARACTERISTIC_CATEGORIES: - value_dict = {} - value_dict["value"] = value - value_dict["choice"] = group.get(value) - characteristics_values.append(value_dict) - #process_characteristic_values(category_dict) + for category in CHARACTERISTIC_CATEGORIES: + for characteristics_value in process_characteristic_values(group,category): + characteristics_values.append(characteristics_value) return characteristics_values +def remove_nans(group): + for key, value in group.items(): + if value is np.NaN: + group[key] = None + if str(value) == "nan": + group[key] = None + if str(value) == "": + group[key] = None + if str(value) == "NANS": + group[key] = None + if str(value) == "None": + group[key] = None + + + + + +def process_characteristic_values(group,category): + remove_nans(group) + this_value = str(group.get(category,"")) + + if "|" in this_value: + characteristic_values = [] + counts_and_choices = this_value.split("|") + for count_and_choice in counts_and_choices: + count , choice = count_and_choice.split() + this_group = {**group} + this_group["count"] = count + this_group[category] = choice + characteristic_values += process_characteristic_values(this_group,category) + return characteristic_values + + elif this_value.strip().replace('.','',1).isdigit() or CHARACTERISTIC_DTYPE[category] == "numeric": + numeric_data = {} + numeric_data["category"] = category + #numeric_data["choice"] = None + numeric_data["count"] = group["count"] + if numeric_data["count"] > 1: + + numeric_data["mean"] = group.get(category, None) + numeric_data["median"] = group.get(f"{category}_median",None) + numeric_data["min"] = group.get(f"{category}_min",None) + numeric_data["max"] = group.get(f"{category}_max",None) + numeric_data["sd"] = group.get(f"{category}_sd",None) + numeric_data["se"] = group.get(f"{category}_se",None) + numeric_data["cv"] = group.get(f"{category}_cv",None) + numeric_data["unit"] = group.get(f"{category}_unit",None) + else: + numeric_data["float"] = group.get(category, None) + + return [numeric_data] + + + + else: + categorical_data = {} + categorical_data["count"] = group.get("count",None) + categorical_data["category"] = category + categorical_data["choice"] = group.get(category,None) + return [categorical_data] + + + + + + + -def process_characteristic_values(data): - if "/" in data["choice"]: - data["choice"].split("/") diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 3eab1237..3091133c 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -32,7 +32,7 @@ class Reference(Sidable,models.Model): In most cases this is a published paper, but could be a thesis or unpublished. """ pmid = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) #optional - doi = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) #optional + doi = models.CharField(max_length=150, null=True, blank=True) #optional title = models.TextField() abstract = models.TextField(blank=True, null=True) journal = models.TextField(blank=True, null=True) diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 11eef754..7e46afdc 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -1,5 +1,6 @@ from rest_framework import serializers from .models import Reference, Author +from ..subjects.models import Group from ..subjects.serializers import GroupSerializer BASE_FIELDS = () @@ -33,18 +34,22 @@ class Meta: model = Reference fields = BASE_FIELDS + ('sid','groups', 'pmid', 'doi', 'title', 'abstract', 'journal','date', 'authors','pdf') + def validate(self, data): + return data + def create(self, validated_data): - authors_data = validated_data.pop('authors') - groups_data = validated_data.pop('groups') + authors_data = validated_data.pop('authors',[]) + groups_data = validated_data.pop('groups',[]) reference, _ = Reference.objects.update_or_create(pmid=validated_data["pmid"],defaults = validated_data) + for author_data in authors_data: author, created = Author.objects.update_or_create(**author_data) reference.authors.add(author) reference.save() for group in groups_data: - reference.group_set.update_or_create(sid=group["sid"], defaults=group) + Group.objects.update_or_create(sid=group["sid"], reference=reference, defaults=group) return reference diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py new file mode 100644 index 00000000..6304b14a --- /dev/null +++ b/pkdb_app/subjects/managers.py @@ -0,0 +1,15 @@ +""" +the managers can be used to overwrite class methods of the models module. +""" +from django.db import models + +class GroupManager(models.Manager): + def update_or_create(self, *args, **kwargs): + characteristic_values = kwargs["defaults"].pop("characteristic_values",[]) + group, created = super(GroupManager, self).update_or_create(*args, **kwargs) + group.characteristic_values.all().delete() + for characteristic_value in characteristic_values: + group.characteristic_values.create(**characteristic_value) + + group.save() + diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 26ed1ce7..5038c10d 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -12,6 +12,7 @@ from ..behaviours import Sidable, Describable from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, UNITS_CHOICES from ..utils import CHAR_MAX_LENGTH +from .managers import GroupManager class Timecourse(models.Model): @@ -22,11 +23,11 @@ class Timecourse(models.Model): data = models.BinaryField() -class Characteristic(Sidable, models.Model): +class Characteristic(models.Model): """ Characteristic. Characteristics are used to store the information about subjects. """ - value = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) + category = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) @property def characteristic_data(self): @@ -34,7 +35,7 @@ def characteristic_data(self): :return: """ - return CHARACTERISTIC_DICT[self.value] + return CHARACTERISTIC_DICT[self.category] @property def choices(self): @@ -44,12 +45,23 @@ class Meta: abstract = True +class Group(Sidable,Describable, models.Model): + """ Individual or group of people. + + Groups are defined via their characteristics. + """ + reference = models.ForeignKey(Reference, on_delete=True, related_name='groups', null=True, blank=True) + # = models.TextField(null=True) + count = models.IntegerField() + + objects = GroupManager() + class CharacteristicValue(Characteristic): """ This is the concrete selection/information of the characteristics. This stores the raw information. Derived values can be calculated. """ - choice = models.CharField(max_length=CHAR_MAX_LENGTH) # check in validation that allowed choice + choice = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) # check in validation that allowed choice count = models.IntegerField() # how many participants in characteristics value = models.FloatField(null=True, blank=True) @@ -62,20 +74,20 @@ class CharacteristicValue(Characteristic): se = models.FloatField(null=True, blank=True) cv = models.FloatField(null=True, blank=True) - unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH) + unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH,null=True, blank=True) + group = models.ForeignKey(Group, related_name="characteristic_values", null=True, on_delete=True) - #timecourse = models.ForeignKey(Timecourse) - def validate(self): - """ Check that choices are valid. I.e. that choice is allowed choice from choices for - characteristics. + #def validate(self): + # """ Check that choices are valid. I.e. that choice is allowed choice from choices for + # characteristics. - Add checks for individuals and groups. For instance if count==1 than value must be filled, - but not entries in mean, median, ... + # Add checks for individuals and groups. For instance if count==1 than value must be filled, + # but not entries in mean, median, ... - :return: - """ - raise NotImplemented + # :return: + # """ + # raise NotImplemented class ProcessedCharacteristicValue(CharacteristicValue): @@ -85,14 +97,6 @@ class ProcessedCharacteristicValue(CharacteristicValue): raw = models.OneToOneField(CharacteristicValue,parent_link=True, on_delete=True) -class Group(Sidable,Describable, models.Model): - """ Individual or group of people. - Groups are defined via their characteristics. - """ - reference = models.ForeignKey(Reference, on_delete=True) - # = models.TextField(null=True) - count = models.IntegerField() - characteristic_value = models.ManyToManyField(CharacteristicValue) # TODO: How to handle Pharmacokinetics data? diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 4a12a948..ee578ce6 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,12 +1,19 @@ from rest_framework import serializers -from .models import Group +from .models import Group, CharacteristicValue BASE_FIELDS = () +class CharacteristicValueSerializer(serializers.ModelSerializer): + + class Meta: + model = CharacteristicValue + fields = "__all__" + class GroupSerializer(serializers.ModelSerializer): + characteristic_values = CharacteristicValueSerializer(many=True,read_only=False) class Meta: model = Group - fields = BASE_FIELDS + ('sid','description','count') \ No newline at end of file + fields = BASE_FIELDS + ('reference','characteristic_values','sid','description','count',) diff --git a/pkdb_app/subjects/views.py b/pkdb_app/subjects/views.py new file mode 100644 index 00000000..15e03f95 --- /dev/null +++ b/pkdb_app/subjects/views.py @@ -0,0 +1,34 @@ +from .models import Group, CharacteristicValue +from .serializers import GroupSerializer, CharacteristicValueSerializer +from rest_framework import viewsets +import django_filters.rest_framework +from rest_framework import filters + + +class GroupsViewSet(viewsets.ModelViewSet): + + queryset = Group.objects.all() + serializer_class = GroupSerializer + filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) + filter_fields = ('description', 'sid') + search_fields = filter_fields + + +class CharacteristicValuesViewSet(viewsets.ModelViewSet): + + queryset = CharacteristicValue.objects.all() + serializer_class = CharacteristicValueSerializer + filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) + filter_fields = ( 'choice', 'count','category') + search_fields = filter_fields + + + +#class InterventionsViewSet(viewsets.ModelViewSet): + +# queryset = Intervention.objects.all() +# serializer_class = InterventionSerializer +# filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) +# filter_fields = ('comment','description','type') + # search_fields = filter_fields + diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index c9e5c3fb..2248ac94 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -8,7 +8,7 @@ from .users.views import UserViewSet, UserCreateViewSet from .studies.views import AuthorsViewSet,ReferencesViewSet - +from .subjects.views import GroupsViewSet,CharacteristicValuesViewSet # views in User router = DefaultRouter() @@ -18,6 +18,9 @@ # views in studies router.register('authors',AuthorsViewSet,base_name="authors") router.register('references', ReferencesViewSet, base_name="references") +router.register('groups', GroupsViewSet, base_name="groups") +router.register('characteristic_values', CharacteristicValuesViewSet, base_name="characteristic_values") + #router.register('intervention',InterventionsViewSet,base_name="intervention") schema_view = get_swagger_view(title='PkBD API') From 04988e64d9490c389c8df40cead727a3152011bd Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 9 Jul 2018 10:28:59 +0200 Subject: [PATCH 011/115] small fix on input, subjects From 4fcf1a575dbecbd6df49320569dc1b14335f0539 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 9 Jul 2018 12:37:43 +0200 Subject: [PATCH 012/115] caffene subjets able to upload. Models build for intervention and Output --- .gitignore | 3 +- pkdb_app/behaviours.py | 23 +++++++++ pkdb_app/categoricals.py | 1 + pkdb_app/config/common.py | 1 + pkdb_app/data_management/create_subjects.py | 11 +++- pkdb_app/interventions/__init__.py | 0 pkdb_app/interventions/admin.py | 3 ++ pkdb_app/interventions/apps.py | 5 ++ pkdb_app/interventions/models.py | 56 +++++++++++++++++++++ pkdb_app/interventions/tests.py | 3 ++ pkdb_app/interventions/views.py | 3 ++ pkdb_app/studies/models.py | 12 +---- pkdb_app/subjects/models.py | 26 +++------- 13 files changed, 114 insertions(+), 33 deletions(-) create mode 100644 pkdb_app/interventions/__init__.py create mode 100644 pkdb_app/interventions/admin.py create mode 100644 pkdb_app/interventions/apps.py create mode 100644 pkdb_app/interventions/models.py create mode 100644 pkdb_app/interventions/tests.py create mode 100644 pkdb_app/interventions/views.py diff --git a/.gitignore b/.gitignore index 4abf4dce..94b3bca1 100644 --- a/.gitignore +++ b/.gitignore @@ -115,4 +115,5 @@ venv.bak/ .mypy_cache/ pkdb_app/studies/migrations pkdb_app/users/migrations -pkdb_app/subjects/migrations \ No newline at end of file +pkdb_app/subjects/migrations +pkdb_app/interventions/migrations \ No newline at end of file diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index 96ff4d11..5941d9e8 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -4,6 +4,7 @@ from django.db import models from pkdb_app.utils import CHAR_MAX_LENGTH +from .categoricals import UNITS_CHOICES class Sidable(models.Model): @@ -49,5 +50,27 @@ class Meta: class Hashable(models.Model): hash = models.CharField(max_length=CHAR_MAX_LENGTH,blank=True, null=True) + class Meta: + abstract = True + + +class Values(models.Model): + + choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, + blank=True) # check in validation that allowed choice + + count = models.IntegerField() # how many participants in characteristics + value = models.FloatField(null=True, blank=True) + + mean = models.FloatField(null=True, blank=True) + median = models.FloatField(null=True, blank=True) + min = models.FloatField(null=True, blank=True) + max = models.FloatField(null=True, blank=True) + sd = models.FloatField(null=True, blank=True) + se = models.FloatField(null=True, blank=True) + cv = models.FloatField(null=True, blank=True) + + unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH, null=True, blank=True) + class Meta: abstract = True \ No newline at end of file diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 9826440a..6d9eb01d 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -37,6 +37,7 @@ COMMON_DATA = [ # Medication CharacteristicType('oral_contraceptives', 'Contraceptives', 'boolean', ["Y", "N"]), + CharacteristicType('oral_contraceptives_amount', 'Contraceptives', 'numeric', None), CharacteristicType('medication', 'Medication', 'categorial', ["ibuprofen", "paracetamol", "aspirin"]), # ? dosing # Lifestyle diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index 7a4a2c79..d78e19db 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -29,6 +29,7 @@ class Common(Configuration): 'pkdb_app.users', 'pkdb_app.studies', 'pkdb_app.subjects', + 'pkdb_app.interventions', ) diff --git a/pkdb_app/data_management/create_subjects.py b/pkdb_app/data_management/create_subjects.py index 30ab2c57..9f955ba7 100644 --- a/pkdb_app/data_management/create_subjects.py +++ b/pkdb_app/data_management/create_subjects.py @@ -37,7 +37,12 @@ def add_characteristic_values(group): characteristics_values = [] for category in CHARACTERISTIC_CATEGORIES: for characteristics_value in process_characteristic_values(group,category): - characteristics_values.append(characteristics_value) + temp_characteristics_value = {**characteristics_value} + for key in ["category","count"]: + temp_characteristics_value.pop(key) + if not all(value is None for value in temp_characteristics_value.values()): + characteristics_values.append(characteristics_value) + return characteristics_values def remove_nans(group): @@ -48,10 +53,12 @@ def remove_nans(group): group[key] = None if str(value) == "": group[key] = None - if str(value) == "NANS": + if str(value) == "NA": group[key] = None if str(value) == "None": group[key] = None + if str(value) == "-": + group[key] = None diff --git a/pkdb_app/interventions/__init__.py b/pkdb_app/interventions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pkdb_app/interventions/admin.py b/pkdb_app/interventions/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/pkdb_app/interventions/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/pkdb_app/interventions/apps.py b/pkdb_app/interventions/apps.py new file mode 100644 index 00000000..fef6ac94 --- /dev/null +++ b/pkdb_app/interventions/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class InterventionsConfig(AppConfig): + name = 'interventions' diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py new file mode 100644 index 00000000..e659dac0 --- /dev/null +++ b/pkdb_app/interventions/models.py @@ -0,0 +1,56 @@ + +''' +Describe Interventions and Output (i.e. define the characteristics of the +group or individual). +''' + +from django.db import models +from ..behaviours import Sidable, Describable, Values +from ..categoricals import INTERVENTION_CHOICES, UNITS_CHOICES +from ..subjects.models import Group +from ..utils import CHAR_MAX_LENGTH +# ------------------------------------------------- +# Intervention +# ------------------------------------------------- + + + +# Create your models here. +class Output(Sidable,Describable,models.Model): + file = models.FileField(upload_to="output", null=True, blank=True) + groups = models.ManyToManyField(Group,through="InterventionValue") + + +class Intervention(Sidable,Describable, models.Model): + category = models.IntegerField(choices=INTERVENTION_CHOICES) + group = models.ForeignKey(Group, related_name='intervention', on_delete=True) + output = models.ForeignKey(Output, related_name='intervention',on_delete=True) + + @property + def Intervention_data(self): + """ Returns the full information about the characteristic. + + :return: + """ + return INTERVENTION_CHOICES[self.category] + + @property + def choices(self): + return self.Intervention_data.choices + + class Meta: + abstract = True + + +class InterventionValue(Values ,Intervention): + pass + #def validate(self): + # """ Check that choices are valid. I.e. that choice is allowed choice from choices for + # Interventions. + + # Add checks for individuals and groups. For instance if count==1 than value must be filled, + # but not entries in mean, median, ... + + # :return: + # """ + # raise NotImplemented \ No newline at end of file diff --git a/pkdb_app/interventions/tests.py b/pkdb_app/interventions/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/pkdb_app/interventions/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/pkdb_app/interventions/views.py b/pkdb_app/interventions/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/pkdb_app/interventions/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 3091133c..3b2796bc 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -13,10 +13,12 @@ class Author(models.Model): def __str__(self): return '%s %s' % (self.first_name, self.last_name) + class Files(models.Model): name = models.CharField(max_length=CHAR_MAX_LENGTH) file = models.FileField(null=True, blank=True) + class KeyWord(models.Model): """ This class describes the keyowrds / tags of a publication or any other reference. @@ -59,14 +61,4 @@ class Reference(Sidable,models.Model): -# ------------------------------------------------- -# Intervention -# ------------------------------------------------- -# Here only the different (two or more) groups which were compared in the study have to be defined. -# In a single study/paper multiple groups are compared (these can be defined as groups). - - -# class Intervention(Sidable, Commentable, Describable, models.Model): -# type = models.IntegerField(choices=INTERVENTION_CHOICES) -# study = models.ForeignKey(Study, null=True, blank=True, on_delete=True) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 5038c10d..f094d624 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -9,8 +9,8 @@ from django.db import models from ..studies.models import Reference -from ..behaviours import Sidable, Describable -from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, UNITS_CHOICES +from ..behaviours import Sidable, Describable, Values +from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES from ..utils import CHAR_MAX_LENGTH from .managers import GroupManager @@ -53,28 +53,14 @@ class Group(Sidable,Describable, models.Model): reference = models.ForeignKey(Reference, on_delete=True, related_name='groups', null=True, blank=True) # = models.TextField(null=True) count = models.IntegerField() - objects = GroupManager() -class CharacteristicValue(Characteristic): + +class CharacteristicValue(Values,Characteristic): """ This is the concrete selection/information of the characteristics. This stores the raw information. Derived values can be calculated. """ - choice = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) # check in validation that allowed choice - - count = models.IntegerField() # how many participants in characteristics - value = models.FloatField(null=True, blank=True) - - mean = models.FloatField(null=True, blank=True) - median = models.FloatField(null=True, blank=True) - min = models.FloatField(null=True, blank=True) - max = models.FloatField(null=True, blank=True) - sd = models.FloatField(null=True, blank=True) - se = models.FloatField(null=True, blank=True) - cv = models.FloatField(null=True, blank=True) - - unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH,null=True, blank=True) group = models.ForeignKey(Group, related_name="characteristic_values", null=True, on_delete=True) @@ -90,11 +76,11 @@ class CharacteristicValue(Characteristic): # raise NotImplemented -class ProcessedCharacteristicValue(CharacteristicValue): +class ProcessedCharacteristicValue(Values,Characteristic,models.Model): """ Processed and normalized data (calculated on change from corresponding raw CharacteristicValue. """ - raw = models.OneToOneField(CharacteristicValue,parent_link=True, on_delete=True) + raw = models.ForeignKey(CharacteristicValue, null=True, on_delete=True) From fe8a5054860e576cef002022b318b97cc95d8f1f Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 9 Jul 2018 14:22:59 +0200 Subject: [PATCH 013/115] changes to get container to run --- README.md | 11 +++++++++++ pkdb_app/config/common.py | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b727035..8d6e3471 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,17 @@ Create a superuser to login to the admin: docker-compose run --rm web ./manage.py createsuperuser ``` +# Update after code change +``` +docker-compose down +docker-compose up --build +``` +reset migrations +``` +sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete +``` + + # Local Development Start the dev server for local development: diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index d78e19db..d0da02c1 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -7,6 +7,7 @@ import dj_database_url from configurations import Configuration BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +POSTGRES_PORT = 5432 class Common(Configuration): @@ -59,7 +60,7 @@ class Common(Configuration): # Postgres DATABASES = { 'default': dj_database_url.config( - default='postgres://postgres:pass@postgres:5432/postgres', + default=f'postgres://postgres:pass@postgres:{POSTGRES_PORT}/postgres', conn_max_age=int(os.getenv('POSTGRES_CONN_MAX_AGE', 600)) ) } From 59b75361b4e9ccdadefb1ebc21be62352f9f4245 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 9 Jul 2018 15:26:05 +0200 Subject: [PATCH 014/115] init files added to fix docker issue --- .gitignore | 9 +++++---- pkdb_app/interventions/migrations/__init__.py | 0 pkdb_app/studies/migrations/__init__.py | 0 pkdb_app/subjects/migrations/__init__.py | 0 pkdb_app/users/migrations/__init__.py | 0 5 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 pkdb_app/interventions/migrations/__init__.py create mode 100644 pkdb_app/studies/migrations/__init__.py create mode 100644 pkdb_app/subjects/migrations/__init__.py create mode 100644 pkdb_app/users/migrations/__init__.py diff --git a/.gitignore b/.gitignore index 94b3bca1..eb5c4b52 100644 --- a/.gitignore +++ b/.gitignore @@ -110,10 +110,11 @@ venv.bak/ # django staticfiles /static + */migrations/ # mypy .mypy_cache/ -pkdb_app/studies/migrations -pkdb_app/users/migrations -pkdb_app/subjects/migrations -pkdb_app/interventions/migrations \ No newline at end of file +pkdb_app/studies/migrations/00*.py +pkdb_app/users/migrations/00*.py +pkdb_app/subjects/migrations/00*.py +pkdb_app/interventions/migrations/00*.py diff --git a/pkdb_app/interventions/migrations/__init__.py b/pkdb_app/interventions/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pkdb_app/studies/migrations/__init__.py b/pkdb_app/studies/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pkdb_app/subjects/migrations/__init__.py b/pkdb_app/subjects/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pkdb_app/users/migrations/__init__.py b/pkdb_app/users/migrations/__init__.py new file mode 100644 index 00000000..e69de29b From c551fe5ea5e97dcc4c4309768e5dadea9d805e4f Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 9 Jul 2018 16:53:23 +0200 Subject: [PATCH 015/115] new ideas for model --- README.md | 14 ++++++++ docker-compose.yml | 2 +- pkdb_app/behaviours.py | 18 ++++++---- pkdb_app/categoricals.py | 59 +++++++++++++++++++------------- pkdb_app/interventions/models.py | 41 ++++++++++++++++------ pkdb_app/studies/models.py | 11 ++++-- pkdb_app/subjects/managers.py | 3 +- pkdb_app/subjects/models.py | 59 ++++++++++++++++++++++---------- 8 files changed, 143 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 8d6e3471..752cdf1f 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,20 @@ reset migrations sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete ``` +# Fill database +``` +workon pkdb +(pkdb) pip install -r requirements.txt --upgrade +(pkdb) python ./pkdb_app/data_management/fill_database.py + +docker-compose run --rm web ./data_management/fill_database.py +``` + +# Connect database pycharm +``` +DataSource -> postgres +``` +Use port defined in `docker-compose.yml` (5433), database name and password in `docker-compose.yml` # Local Development Start the dev server for local development: diff --git a/docker-compose.yml b/docker-compose.yml index 578ab504..2f6a29e6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: postgres: image: postgres:9.6 ports: - - "5432:5432" + - "5433:5432" environment: POSTGRES_USER : postgres diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index 5941d9e8..28ae4d0d 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -29,7 +29,6 @@ class Meta: ''' - class Commentable(models.Model): """ Model has a comment field. """ comment = models.TextField(blank=True, null=True) @@ -39,22 +38,26 @@ class Meta: class Describable(models.Model): - """ - - """ + """ Add description field. """ description = models.TextField(blank=True, null=True) class Meta: abstract = True + class Hashable(models.Model): + """ Add hash key field. """ hash = models.CharField(max_length=CHAR_MAX_LENGTH,blank=True, null=True) class Meta: abstract = True -class Values(models.Model): +class Valueable(models.Model): + """ Add fields to store values. + + In addition all the statistical values are stored. + """ choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) # check in validation that allowed choice @@ -73,4 +76,7 @@ class Values(models.Model): unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH, null=True, blank=True) class Meta: - abstract = True \ No newline at end of file + abstract = True + + # FIXME: all validation rules & methods should be on Valuable + # for instance, if choice set, other fields must be empty, ... \ No newline at end of file diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 6d9eb01d..02f95aa5 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -34,43 +34,51 @@ # boolean: NA, None # categorial: NA, None +BOOLEAN_TYPE = 'boolean' +NUMERIC_TYPE = 'numeric' +CATEGORIAL_TYPE = 'categorial' +YES = "Y" +NO = 'N' +BOOLEAN_CHOICES = [YES, NO] + + COMMON_DATA = [ # Medication - CharacteristicType('oral_contraceptives', 'Contraceptives', 'boolean', ["Y", "N"]), - CharacteristicType('oral_contraceptives_amount', 'Contraceptives', 'numeric', None), - CharacteristicType('medication', 'Medication', 'categorial', ["ibuprofen", "paracetamol", "aspirin"]), # ? dosing + CharacteristicType('oral_contraceptives', 'Contraceptives', BOOLEAN_TYPE, BOOLEAN_CHOICES), + CharacteristicType('oral_contraceptives_amount', 'Contraceptives', NUMERIC_TYPE, None), + CharacteristicType('medication', 'Medication', CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"]), # ? dosing # Lifestyle - CharacteristicType('caffeine', 'Lifestyle', 'boolean', ["Y", "N"]), - CharacteristicType('caffeine_amount', 'Lifestyle', 'numeric', None), + CharacteristicType('caffeine', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES), + CharacteristicType('caffeine_amount', 'Lifestyle', NUMERIC_TYPE, None), ] CHARACTERISTIC_DATA = COMMON_DATA+ [ # Antropmetrical information - CharacteristicType('species', 'Species', 'categorial', ["Homo sapiens"]), - CharacteristicType('height', 'BodyParameter', 'numeric', None), - CharacteristicType('body_weight', 'BodyParameter', 'numeric', None), - CharacteristicType('age', 'BodyParameter', 'numeric', None), - CharacteristicType('sex', 'BodyParameter', 'categorial', ["M", "F"]), - CharacteristicType('bmi', 'BodyParameter', 'numeric', None), - CharacteristicType('waist_circumference', 'BodyParameter', 'numeric', None), - CharacteristicType('ethnicity', 'Ethnicity', 'categorial', ["african", "afroamerican", "asian", "caucasian"]), + CharacteristicType('species', 'Species', CATEGORIAL_TYPE, ["Homo sapiens"]), + CharacteristicType('height', 'BodyParameter', NUMERIC_TYPE, None), + CharacteristicType('body_weight', 'BodyParameter', NUMERIC_TYPE, None), + CharacteristicType('age', 'BodyParameter', NUMERIC_TYPE, None), + CharacteristicType('sex', 'BodyParameter', CATEGORIAL_TYPE, ["M", "F"]), + CharacteristicType('bmi', 'BodyParameter', NUMERIC_TYPE, None), + CharacteristicType('waist_circumference', 'BodyParameter', NUMERIC_TYPE, None), + CharacteristicType('ethnicity', 'Ethnicity', CATEGORIAL_TYPE, ["african", "afroamerican", "asian", "caucasian"]), # Disease (status) - CharacteristicType('healthy', "Health status", "boolean", None), - CharacteristicType('disease', "Disease", "categorial", ["cirrhosis"]), + CharacteristicType('healthy', "Health status", BOOLEAN_TYPE, BOOLEAN_CHOICES), + CharacteristicType('disease', "Disease", CATEGORIAL_TYPE, ["cirrhosis"]), # Lifestyle - CharacteristicType('smoking', 'Lifestyle', 'boolean', ["Y", "N"]), - CharacteristicType('smoking_amount', 'Lifestyle', 'numeric', None), - CharacteristicType('alcohol', 'Lifestyle', 'boolean', ["Y", "N"]), - CharacteristicType('alcohol_amount', 'Lifestyle', 'numeric', None), + CharacteristicType('smoking', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES), + CharacteristicType('smoking_amount', 'Lifestyle', NUMERIC_TYPE, None), + CharacteristicType('alcohol', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES), + CharacteristicType('alcohol_amount', 'Lifestyle', NUMERIC_TYPE, None), # Study protocol - CharacteristicType('overnight_fast', 'Study protocol', 'boolean', ["Y", "N"]), - CharacteristicType('alcohol_abstinence', 'Study protocol', 'boolean', ["Y", "N"]), + CharacteristicType('overnight_fast', 'Study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES), + CharacteristicType('alcohol_abstinence', 'Study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES), # Medication @@ -82,7 +90,12 @@ ] # class, value, dtype (numeric, boolean, categorial), choices -INTERVENTION_DATA = COMMON_DATA + [ +PROTOCOL_DATA = [ + + CharacteristicType('dosing', 'Dosing', NUMERIC_TYPE, None), + + + ] def dict_and_choices(data): @@ -93,7 +106,7 @@ def dict_and_choices(data): CHARACTERISTIC_DTYPE = {item.value : item.dtype for item in CHARACTERISTIC_DATA} CHARACTERISTIC_CATEGORIES = set([item.value for item in CHARACTERISTIC_DATA]) CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES = dict_and_choices(CHARACTERISTIC_DATA) -INTERVENTION_DICT, INTERVENTION_CHOICES = dict_and_choices(INTERVENTION_DATA) +PROTOCOL_DICT, PROTOCOL_CHOICES = dict_and_choices(PROTOCOL_DATA) ''' diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index e659dac0..d9da7a91 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -1,30 +1,48 @@ -''' +""" Describe Interventions and Output (i.e. define the characteristics of the group or individual). -''' +""" from django.db import models -from ..behaviours import Sidable, Describable, Values -from ..categoricals import INTERVENTION_CHOICES, UNITS_CHOICES +from ..behaviours import Sidable, Describable, Valueable +from ..categoricals import PROTOCOL_CHOICES, UNITS_CHOICES from ..subjects.models import Group from ..utils import CHAR_MAX_LENGTH # ------------------------------------------------- # Intervention # ------------------------------------------------- +# Important to store raw DataSets & Corresponding Figures/Tables +# + +# How can data sets look +# - CharacteristicValues (value +- SE in n subjects) -> e.g. pharmacokinetics data +# - mean timecourse +- SE/SD +# - individual time courses + +# Simple pharmacokinetics # Create your models here. -class Output(Sidable,Describable,models.Model): +class Output(Sidable, Describable, models.Model): + """ Storage of data sets. """ file = models.FileField(upload_to="output", null=True, blank=True) - groups = models.ManyToManyField(Group,through="InterventionValue") + groups = models.ManyToManyField(Group, through="InterventionValue") + + +# How to represent the dosing? +# Add separate class? extension of model? +class Protocol(Sidable, Describable, models.Model): + """ What is done to the group. """ -class Intervention(Sidable,Describable, models.Model): - category = models.IntegerField(choices=INTERVENTION_CHOICES) + + # FIXME: Important to find the subset of dosing protocols + + category = models.IntegerField(choices=PROTOCOL_CHOICES) group = models.ForeignKey(Group, related_name='intervention', on_delete=True) - output = models.ForeignKey(Output, related_name='intervention',on_delete=True) + output = models.ForeignKey(Output, related_name='intervention', on_delete=True) @property def Intervention_data(self): @@ -32,7 +50,7 @@ def Intervention_data(self): :return: """ - return INTERVENTION_CHOICES[self.category] + return PROTOCOL_CHOICES[self.category] @property def choices(self): @@ -42,8 +60,9 @@ class Meta: abstract = True -class InterventionValue(Values ,Intervention): +class ProtocolValue(Valueable, Protocol): pass + #def validate(self): # """ Check that choices are valid. I.e. that choice is allowed choice from choices for # Interventions. diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 3b2796bc..4bc5e07f 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -26,9 +26,8 @@ class KeyWord(models.Model): #name = models.IntegerField(choices=KEY_WORD_CHOICES) name = models.CharField(max_length=CHAR_MAX_LENGTH) -# All models should be commentable -class Reference(Sidable,models.Model): +class Reference(Sidable, models.Model): """ This is the main class describing the publication or reference which describes the study. In most cases this is a published paper, but could be a thesis or unpublished. @@ -42,7 +41,13 @@ class Reference(Sidable,models.Model): pdf = models.FileField(upload_to="study", null=True, blank=True) authors = models.ManyToManyField(Author, blank=True, related_name='authors') -#class Study(Sidable, Commentable, Describable, models.Model): + +class Study(Sidable, Commentable, Describable, models.Model): + reference = models.ForeignKey(Reference, on_delete=True, related_name='studies', null=True, blank=True) + + + + # """ Single clinical study. # Mainly reported as a single publication. diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 6304b14a..6e579444 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -3,9 +3,10 @@ """ from django.db import models + class GroupManager(models.Manager): def update_or_create(self, *args, **kwargs): - characteristic_values = kwargs["defaults"].pop("characteristic_values",[]) + characteristic_values = kwargs["defaults"].pop("characteristic_values", []) group, created = super(GroupManager, self).update_or_create(*args, **kwargs) group.characteristic_values.all().delete() for characteristic_value in characteristic_values: diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index f094d624..65a9436e 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -8,19 +8,40 @@ from django.db import models -from ..studies.models import Reference -from ..behaviours import Sidable, Describable, Values +from ..studies.models import Study, Reference +from ..behaviours import Sidable, Describable, Valueable from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES from ..utils import CHAR_MAX_LENGTH from .managers import GroupManager -class Timecourse(models.Model): - """ Storing of time course data. +# TODO: Add ExclusionCriteria as extra class on group | or via field ? +# Not clear what is best: The important thing is that stated exclusion criteria +# must be encodable and be found as such (often via cutoffs) +# - how to represent cutoff & negation - Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). +# - Exclusion/Inclusion +# - Group +# - Intervention + +# - DataSets/Output + + + +# Idea: GroupSet + +class Group(Sidable, Describable, models.Model): + """ Individual or group of people. + + Groups are defined via their characteristics. """ - data = models.BinaryField() + study = models.ForeignKey(Study, on_delete=True, related_name='groups', null=True, blank=True) + count = models.IntegerField() # number of people/animals/objects in group + objects = GroupManager() + + @property + def reference(self): + return self.study.reference class Characteristic(models.Model): @@ -45,18 +66,7 @@ class Meta: abstract = True -class Group(Sidable,Describable, models.Model): - """ Individual or group of people. - - Groups are defined via their characteristics. - """ - reference = models.ForeignKey(Reference, on_delete=True, related_name='groups', null=True, blank=True) - # = models.TextField(null=True) - count = models.IntegerField() - objects = GroupManager() - - -class CharacteristicValue(Values,Characteristic): +class CharacteristicValue(Valueable, Characteristic): """ This is the concrete selection/information of the characteristics. This stores the raw information. Derived values can be calculated. @@ -76,13 +86,24 @@ class CharacteristicValue(Values,Characteristic): # raise NotImplemented -class ProcessedCharacteristicValue(Values,Characteristic,models.Model): +class ProcessedCharacteristicValue(Valueable, Characteristic, models.Model): """ Processed and normalized data (calculated on change from corresponding raw CharacteristicValue. """ raw = models.ForeignKey(CharacteristicValue, null=True, on_delete=True) + # method field? for different processing? + # TODO: add methods for doing the processing & automatic update if corresponding + # Value is changed. + # -> move to a ProcessedValuable +class Timecourse(models.Model): + """ Storing of time course data. + + Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). + """ + data = models.BinaryField() + # TODO: How to handle Pharmacokinetics data? From 87c17e30e48a10a3445f559aff5d676acd65d771 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 9 Jul 2018 18:21:45 +0200 Subject: [PATCH 016/115] ideas for pharmacokinetics data model --- docs/api/api.ipynb | 10 ++-- pkdb_app/interventions/models.py | 92 ++++++++++++++++++++++++++++---- pkdb_app/studies/serializers.py | 15 +++--- pkdb_app/subjects/models.py | 11 ---- 4 files changed, 95 insertions(+), 33 deletions(-) diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index 0c2c99be..36031760 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -367,7 +367,7 @@ " ]\n", "}\n", "\n", - "client.action(document,[\"references\", \"create\"], params=reference_dict)" + "client.action(document, [\"references\", \"create\"], params=reference_dict)" ] }, { @@ -396,7 +396,6 @@ { "ename": "ParameterError", "evalue": "{'groups': 'This parameter is required.'}", - "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mParameterError\u001b[0m Traceback (most recent call last)", @@ -404,7 +403,8 @@ "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_lookup_link\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 165\u001b[0;31m \u001b[0m_validate_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0moverrides\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36m_validate_parameters\u001b[0;34m(link, parameters)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 80\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mParameterError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 81\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mParameterError\u001b[0m: {'groups': 'This parameter is required.'}" - ] + ], + "output_type": "error" } ], "source": [ @@ -419,7 +419,6 @@ { "ename": "ErrorMessage", "evalue": "\n group: [\n \"This field is required.\"\n ]", - "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", @@ -427,7 +426,8 @@ "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mErrorMessage\u001b[0m: \n group: [\n \"This field is required.\"\n ]" - ] + ], + "output_type": "error" } ], "source": [ diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index d9da7a91..85ebffd2 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -24,25 +24,35 @@ # Simple pharmacokinetics -# Create your models here. -class Output(Sidable, Describable, models.Model): - """ Storage of data sets. """ - file = models.FileField(upload_to="output", null=True, blank=True) - groups = models.ManyToManyField(Group, through="InterventionValue") - # How to represent the dosing? # Add separate class? extension of model? -class Protocol(Sidable, Describable, models.Model): - """ What is done to the group. """ +class Protocol: + """ Selection of things which were done to the group. + + """ + group = models.ForeignKey(Group, related_name='intervention', on_delete=True) + # set of protocols + # name (control, fluvoxamine, control-fluvo, fluvo-control) + + +class ProtocolStep(Sidable, Describable, models.Model): + """ What is done to the group, single step. + + - dosing of certain substance, e.g. caffeine oral + + - smoking cessation + - sports, ... + - + """ + # TODO: MedicationStep & LifestyleStep # FIXME: Important to find the subset of dosing protocols category = models.IntegerField(choices=PROTOCOL_CHOICES) - group = models.ForeignKey(Group, related_name='intervention', on_delete=True) - output = models.ForeignKey(Output, related_name='intervention', on_delete=True) + @property def Intervention_data(self): @@ -60,6 +70,24 @@ class Meta: abstract = True + +class MedicationStep(Valuable, ProtocolStep): # choices, dose, unit (per_bodyweitght is not important) + + substance: # what was given [' + route: # where ['oral', 'iv'] + application: # how timing ['single dose', 'multiple doses', 'continuous injection'] + application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) + form: # how medication [capusle, tablete] + form_details: # h details + + +class Substance(Ontologable): + """ + """ + name # example caffeine + # ontologies: has set of defined values: is, CHEBI:27732 + + class ProtocolValue(Valueable, Protocol): pass @@ -72,4 +100,46 @@ class ProtocolValue(Valueable, Protocol): # :return: # """ - # raise NotImplemented \ No newline at end of file + # raise NotImplemented + +class DatasetFile(): + """ Table or figure from where the data comes from. + + """ + file = models.FileField(upload_to="output", null=True, blank=True) # table or figure + + +# Create your models here. +class Output(Sidable, Describable, models.Model): + """ Storage of data sets. """ + protocol = models.ForeignKey(Protocol) + file = models.ForeignKey(DatasetFile) + + +class Timecourse(Output): + """ Storing of time course data. + + Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). + """ + data = models.BinaryField() + + + +class Pharmacokinetics(Output, Valueable): + """ Measured value (calculated value via ProcessedPharmacokinetics) + + category: [clearance, vd, thalf, cmax, ...] + """ + substance = models.ForeignKey(Substance) + tissue # where was it measured + + +class ProcessedPharmacokinetics(): + """ Calculated from pharmacokinetics or timecourse data. + + """ + rawid = models.ForeignKey(Pharmacokinetics) + type # ['normalized', 'timecourse-derived'] + + + diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 7e46afdc..a247913c 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -27,21 +27,24 @@ def create(self, validated_data): class ReferenceSerializer(serializers.ModelSerializer): - authors = AuthorSerializer(many=True,read_only=False)#, queryset=Study.objects.all(), source='studies') - groups = GroupSerializer(many=True,read_only=False)#, queryset=Study.objects.all(), source='studies') + authors = AuthorSerializer(many=True, read_only=False)#, queryset=Study.objects.all(), source='studies') + groups = GroupSerializer(many=True, read_only=False)#, queryset=Study.objects.all(), source='studies') class Meta: model = Reference - fields = BASE_FIELDS + ('sid','groups', 'pmid', 'doi', 'title', 'abstract', 'journal','date', 'authors','pdf') + fields = BASE_FIELDS + ('sid', 'groups', 'pmid', 'doi', 'title', 'abstract', 'journal', 'date', 'authors', 'pdf') def validate(self, data): + # TODO: add validation code + + return data def create(self, validated_data): - authors_data = validated_data.pop('authors',[]) - groups_data = validated_data.pop('groups',[]) + authors_data = validated_data.pop('authors', []) + groups_data = validated_data.pop('groups', []) - reference, _ = Reference.objects.update_or_create(pmid=validated_data["pmid"],defaults = validated_data) + reference, _ = Reference.objects.update_or_create(pmid=validated_data["pmid"], defaults=validated_data) for author_data in authors_data: author, created = Author.objects.update_or_create(**author_data) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 65a9436e..e4e3f315 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -96,14 +96,3 @@ class ProcessedCharacteristicValue(Valueable, Characteristic, models.Model): # TODO: add methods for doing the processing & automatic update if corresponding # Value is changed. # -> move to a ProcessedValuable - - -class Timecourse(models.Model): - """ Storing of time course data. - - Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). - """ - data = models.BinaryField() - - -# TODO: How to handle Pharmacokinetics data? From 0f2231232fc911af2439bb2b73840b2fedb77f3f Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 16 Jul 2018 00:24:55 +0200 Subject: [PATCH 017/115] before vaccation --- docs/api/api.ipynb | 313 ++++++++++++++++++++++--------- pkdb_app/behaviours.py | 2 +- pkdb_app/interventions/models.py | 8 +- pkdb_app/studies/models.py | 29 +-- pkdb_app/studies/serializers.py | 49 +++-- pkdb_app/studies/views.py | 11 +- pkdb_app/urls.py | 4 +- 7 files changed, 274 insertions(+), 142 deletions(-) diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index 36031760..7964cdb9 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -71,7 +71,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 5, "metadata": { "collapsed": true }, @@ -85,7 +85,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 66, "metadata": {}, "outputs": [ { @@ -106,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 67, "metadata": {}, "outputs": [ { @@ -124,27 +124,35 @@ " }\n", " characteristic_values: {\n", " list([page], [choice], [count], [category], [search])\n", - " create(category, count, unit, [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv])\n", + " create(count, category, [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [group])\n", " read(id, [choice], [count], [category], [search])\n", - " update(id, category, count, unit, [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [choice], [count], [category], [search])\n", - " partial_update(id, [category], [choice], [count], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [choice], [count], [category], [search])\n", + " update(id, count, category, [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [group], [choice], [count], [category], [search])\n", + " partial_update(id, [choice], [count], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [category], [group], [choice], [count], [category], [search])\n", " delete(id, [choice], [count], [category], [search])\n", " }\n", " groups: {\n", " list([page], [description], [sid], [search])\n", - " create(sid, count, [description])\n", + " create(characteristic_values, sid, count, [description])\n", " read(id, [description], [sid], [search])\n", - " update(id, sid, count, [description], [description], [sid], [search])\n", - " partial_update(id, [sid], [description], [count], [description], [sid], [search])\n", + " update(id, characteristic_values, sid, count, [description], [description], [sid], [search])\n", + " partial_update(id, [characteristic_values], [sid], [description], [count], [description], [sid], [search])\n", " delete(id, [description], [sid], [search])\n", " }\n", " references: {\n", " list([page], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " create(sid, groups, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf])\n", + " create(title, date, authors, [pmid], [sid], [doi], [abstract], [journal], [pdf])\n", " read(id, [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " update(id, sid, groups, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " partial_update(id, [sid], [groups], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " update(id, title, date, authors, [pmid], [sid], [doi], [abstract], [journal], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " partial_update(id, [pmid], [sid], [doi], [title], [abstract], [journal], [date], [authors], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", " delete(id, [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " }\n", + " studies: {\n", + " list([page], [sid], [search])\n", + " create(sid, groups, reference, [comment], [description])\n", + " read(id, [sid], [search])\n", + " update(id, sid, groups, reference, [comment], [description], [sid], [search])\n", + " partial_update(id, [sid], [comment], [description], [groups], [reference], [sid], [search])\n", + " delete(id, [sid], [search])\n", " }\n" ] } @@ -194,7 +202,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 32, "metadata": {}, "outputs": [ { @@ -242,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -250,10 +258,16 @@ "output_type": "stream", "text": [ "{\n", - " \"count\": 0,\n", + " \"count\": 1,\n", " \"next\": null,\n", " \"previous\": null,\n", - " \"results\": []\n", + " \"results\": [\n", + " {\n", + " \"id\": 1,\n", + " \"first_name\": \"Lucek\",\n", + " \"last_name\": \"Grzegorzewski\"\n", + " }\n", + " ]\n", "}\n" ] } @@ -267,71 +281,35 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 51, "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "OrderedDict([('sid', 'Haller2002'),\n", - " ('groups',\n", - " [OrderedDict([('reference', 1),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 43),\n", - " ('category', 'caffeine_amount'),\n", - " ('choice', None),\n", - " ('count', 8),\n", - " ('value', None),\n", - " ('mean', 6.0),\n", - " ('median', 4.0),\n", - " ('min', 8.0),\n", - " ('max', None),\n", - " ('sd', 8.0),\n", - " ('se', 4.0),\n", - " ('cv', 7.0),\n", - " ('unit', 'yr'),\n", - " ('group', 1)])]),\n", - " ('sid', 'Haller2002-S1'),\n", - " ('description',\n", - " 'tory teses rate or blood pressure.'),\n", - " ('count', 8)])]),\n", - " ('pmid', '12087345'),\n", - " ('doi', ''),\n", - " ('title',\n", - " 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.'),\n", - " ('abstract', 'Botanical stimgle dose.'),\n", - " ('journal', 'Clinical pharmacology and therapeutics'),\n", - " ('date', '2002-07-16'),\n", - " ('authors',\n", - " [OrderedDict([('id', 1),\n", - " ('first_name', 'Christine A'),\n", - " ('last_name', 'Haller')]),\n", - " OrderedDict([('id', 2),\n", - " ('first_name', 'Peyton'),\n", - " ('last_name', 'Jacob')]),\n", - " OrderedDict([('id', 3),\n", - " ('first_name', 'Neal L'),\n", - " ('last_name', 'Benowitz')])]),\n", - " ('pdf', None)])" - ] - }, - "execution_count": 80, - "metadata": {}, - "output_type": "execute_result" + "ename": "ErrorMessage", + "evalue": "\n authors: [\n {\n first_name: [\n \"Ensure this field has no more than 30 characters.\"\n ]\n },\n {},\n {}\n ]", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 27\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 29\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"references\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mreference_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mErrorMessage\u001b[0m: \n authors: [\n {\n first_name: [\n \"Ensure this field has no more than 30 characters.\"\n ]\n },\n {},\n {}\n ]" + ] } ], "source": [ "# Create study\n", "reference_dict = {\n", " \"pmid\": 12087345,\n", - " \"sid\": \"Haller2002\",\n", + " #\"sid\": \"Haller2002\",\n", " \"date\": \"2002-07-16\",\n", " \"journal\": \"Clinical pharmacology and therapeutics\",\n", " \"title\": \"Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.\",\n", " \"abstract\": \"Botanical stimgle dose.\",\n", " \"authors\": [\n", " {\n", - " \"first_name\": \"Christine A\",\n", + " \"first_name\": \"Christine A Bansakodsfjkopasdfkpodfkanodi asdin\",\n", " \"last_name\": \"Haller\"\n", " },\n", " {\n", @@ -344,36 +322,149 @@ " }\n", " ],\n", " \"doi\": \"\",\n", - " \"groups\":[\n", + " \n", + " }\n", + " \n", + "\n", + "\n", + "client.action(document, [\"references\", \"create\"], params=reference_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [], + "source": [ + "# Create study\n", + "study_dict = {\n", + " \"sid\":\"test\",\n", + " \"reference\":12087345,\n", + " \"groups\": [\n", " {\n", - " \"count\": 8,\n", - " \"sid\": \"Haller2002-S1\",\n", - " \"description\": \" tory teses rate or blood pressure.\",\n", + " \"count\": 14,\n", + " \"sid\": \"Seng2009-S_NCNS\",\n", + " \"description\": \"59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean \\u00b1 SD) 21 \\u00b1 2 years, body weight 62 \\u00b1 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 \\u00b1 4 years, body weight 69 \\u00b1 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 \\u00b1 4 cigarettes daily, age 23 \\u00b1 5 years, body weight 71 \\u00b1 19 kg).\",\n", " \"characteristic_values\": [\n", " {\n", - " \"category\": \"caffeine_amount\",\n", - " \"count\": 8,\n", - " \"mean\": 6,\n", - " \"median\": 4,\n", - " \"min\": 8,\n", - " \"max\": None,\n", - " \"sd\": 8,\n", - " \"se\": 4,\n", - " \"cv\": 7,\n", - " \"unit\": \"yr\"\n", + " \"count\": 14,\n", + " \"category\": \"sex\",\n", + " \"choice\": \"M\"\n", + " },\n", + " {\n", + " \"count\": 14,\n", + " \"category\": \"species\",\n", + " \"choice\": \"homo sapiens\"\n", + " },\n", + " {\n", + " \"category\": \"body_weight\",\n", + " \"count\": 14,\n", + " \"mean\": 62.0,\n", + " \"sd\": 9.0,\n", + " \"unit\": \"kg\"\n", " },\n", + " {\n", + " \"count\": 14,\n", + " \"category\": \"ethnicity\",\n", + " \"choice\": \"Asian\"\n", + " },\n", + " \n", " ]\n", - " }\n", - " ]\n", - "}\n", + " },\n", + " {\n", + " \"count\": 15,\n", + " \"sid\": \"Seng2009-S_CNS\",\n", + " \"description\": \"59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean \\u00b1 SD) 21 \\u00b1 2 years, body weight 62 \\u00b1 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 \\u00b1 4 years, body weight 69 \\u00b1 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 \\u00b1 4 cigarettes daily, age 23 \\u00b1 5 years, body weight 71 \\u00b1 19 kg).\",\n", + " \"characteristic_values\": [\n", + " {\n", + " \"count\": 15,\n", + " \"category\": \"sex\",\n", + " \"choice\": \"M\"\n", + " },\n", + " {\n", + " \"count\": 15,\n", + " \"category\": \"species\",\n", + " \"choice\": \"homo sapiens\"\n", + " },\n", + " {\n", + " \"category\": \"body_weight\",\n", + " \"count\": 15,\n", + " \"mean\": 69.0,\n", + " \"sd\": 12.0,\n", "\n", - "client.action(document, [\"references\", \"create\"], params=reference_dict)" + " \"unit\": \"kg\"\n", + " },\n", + " ]\n", + " },\n", + " {\n", + " \"count\": 30,\n", + " \"sid\": \"Seng2009-S_CS\",\n", + " \"description\": \"59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean \\u00b1 SD) 21 \\u00b1 2 years, body weight 62 \\u00b1 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 \\u00b1 4 years, body weight 69 \\u00b1 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 \\u00b1 4 cigarettes daily, age 23 \\u00b1 5 years, body weight 71 \\u00b1 19 kg).\",\n", + " \"characteristic_values\": [\n", + " {\n", + " \"count\": 30,\n", + " \"category\": \"sex\",\n", + " \"choice\": \"M\"\n", + " },\n", + " {\n", + " \"count\": 30,\n", + " \"category\": \"species\",\n", + " \"choice\": \"homo sapiens\"\n", + " },\n", + " {\n", + " \"category\": \"body_weight\",\n", + " \"count\": 30,\n", + " \"mean\": 71.0,\n", + " \"unit\": \"kg\"\n", + " },\n", + " {\n", + " \"count\": 30,\n", + " \"category\": \"ethnicity\",\n", + " \"choice\": \"Asian\"\n", + " },\n", + " {\n", + " \"count\": 30,\n", + " \"category\": \"alcohol_abstinence\",\n", + " \"choice\": \"N\"\n", + " },\n", + "\n", + " ]\n", + " }\n", + " ],\n", + " \n", + " }\n", + " \n" ] }, { "cell_type": "code", - "execution_count": 116, + "execution_count": 80, "metadata": {}, + "outputs": [ + { + "ename": "ErrorMessage", + "evalue": "\n sid: [\n \"study with this sid already exists.\"\n ]", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"studies\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mErrorMessage\u001b[0m: \n sid: [\n \"study with this sid already exists.\"\n ]" + ] + } + ], + "source": [ + "client.action(document, [\"studies\", \"create\"], params=study_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "import json\n", @@ -383,10 +474,48 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "data": { + "text/plain": [ + "OrderedDict([('count', 2),\n", + " ('next', None),\n", + " ('previous', None),\n", + " ('results',\n", + " [OrderedDict([('pmid', '12087345'),\n", + " ('sid', 'Haller2002'),\n", + " ('doi', ''),\n", + " ('title',\n", + " 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.'),\n", + " ('abstract', 'Botanical stimgle dose.'),\n", + " ('journal',\n", + " 'Clinical pharmacology and therapeutics'),\n", + " ('date', '2002-07-16'),\n", + " ('authors', []),\n", + " ('pdf', None)]),\n", + " OrderedDict([('pmid', '12087345'),\n", + " ('sid', '12087345'),\n", + " ('doi', ''),\n", + " ('title',\n", + " 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.'),\n", + " ('abstract', 'Botanical stimgle dose.'),\n", + " ('journal',\n", + " 'Clinical pharmacology and therapeutics'),\n", + " ('date', '2002-07-16'),\n", + " ('authors', []),\n", + " ('pdf', None)])])])" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "client.action(document, [\"references\", \"list\"])" + ] }, { "cell_type": "code", @@ -396,6 +525,7 @@ { "ename": "ParameterError", "evalue": "{'groups': 'This parameter is required.'}", + "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mParameterError\u001b[0m Traceback (most recent call last)", @@ -403,8 +533,7 @@ "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_lookup_link\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 165\u001b[0;31m \u001b[0m_validate_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0moverrides\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36m_validate_parameters\u001b[0;34m(link, parameters)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 80\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mParameterError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 81\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mParameterError\u001b[0m: {'groups': 'This parameter is required.'}" - ], - "output_type": "error" + ] } ], "source": [ @@ -419,6 +548,7 @@ { "ename": "ErrorMessage", "evalue": "\n group: [\n \"This field is required.\"\n ]", + "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", @@ -426,8 +556,7 @@ "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mErrorMessage\u001b[0m: \n group: [\n \"This field is required.\"\n ]" - ], - "output_type": "error" + ] } ], "source": [ diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index 28ae4d0d..2bb0f17c 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -9,7 +9,7 @@ class Sidable(models.Model): """ Model has an sid. """ - sid = models.CharField(max_length=CHAR_MAX_LENGTH) + sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key = True) class Meta: abstract = True diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 85ebffd2..4d178b27 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -9,6 +9,7 @@ from ..categoricals import PROTOCOL_CHOICES, UNITS_CHOICES from ..subjects.models import Group from ..utils import CHAR_MAX_LENGTH + # ------------------------------------------------- # Intervention # ------------------------------------------------- @@ -69,9 +70,9 @@ def choices(self): class Meta: abstract = True +''' - -class MedicationStep(Valuable, ProtocolStep): # choices, dose, unit (per_bodyweitght is not important) +class MedicationStep(Valueable, ProtocolStep): # choices, dose, unit (per_bodyweitght is not important) substance: # what was given [' route: # where ['oral', 'iv'] @@ -141,5 +142,8 @@ class ProcessedPharmacokinetics(): rawid = models.ForeignKey(Pharmacokinetics) type # ['normalized', 'timecourse-derived'] +''' + + diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 4bc5e07f..2a4ae5eb 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -11,7 +11,7 @@ class Author(models.Model): last_name = models.CharField(max_length=150, blank=True) def __str__(self): - return '%s %s' % (self.first_name, self.last_name) + return '%s %s' % (self.id, self.first_name, self.last_name) class Files(models.Model): @@ -27,42 +27,33 @@ class KeyWord(models.Model): name = models.CharField(max_length=CHAR_MAX_LENGTH) -class Reference(Sidable, models.Model): +class Reference( models.Model): """ This is the main class describing the publication or reference which describes the study. In most cases this is a published paper, but could be a thesis or unpublished. """ + pmid = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) #optional + sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key = True, default=pmid) doi = models.CharField(max_length=150, null=True, blank=True) #optional title = models.TextField() abstract = models.TextField(blank=True, null=True) journal = models.TextField(blank=True, null=True) date = models.DateField() pdf = models.FileField(upload_to="study", null=True, blank=True) - authors = models.ManyToManyField(Author, blank=True, related_name='authors') - - -class Study(Sidable, Commentable, Describable, models.Model): - reference = models.ForeignKey(Reference, on_delete=True, related_name='studies', null=True, blank=True) + authors = models.ManyToManyField(Author, blank=True, related_name='references') - # """ Single clinical study. +class Study(Sidable, Commentable, Describable, models.Model): + """ Single clinical study. - # Mainly reported as a single publication. + Mainly reported as a single publication. - # """ - # sid should be the AuthorYear if possible - # comments - #description (if no description is provided, this is filled with the abstract) - #files (PNG, CSV) (all files with exception of pdf) - #files = models.ManyToManyField(Files, related_name="files") - #reference = models.ForeignKey(Reference, null=True, blank=True, on_delete=True) - #keywords = models.ManyToManyField(KeyWord, blank=True, related_name='keywords') + """ + reference = models.ForeignKey(Reference, on_delete=True, related_name='studies', null=True, blank=True) - #interventions - #subjects diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index a247913c..011b9969 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -1,22 +1,14 @@ from rest_framework import serializers -from .models import Reference, Author -from ..subjects.models import Group +from .models import Reference, Author, Study + from ..subjects.serializers import GroupSerializer +from ..subjects.models import Group BASE_FIELDS = () -#class InterventionSerializer(serializers.ModelSerializer): - - -# class Meta: -# model = Intervention -# fields = BASE_FIELDS + ('type', 'study',) - - class AuthorSerializer(serializers.ModelSerializer): id = serializers.ReadOnlyField() - class Meta: model = Author fields = ('id', 'first_name', 'last_name') @@ -28,31 +20,38 @@ def create(self, validated_data): class ReferenceSerializer(serializers.ModelSerializer): authors = AuthorSerializer(many=True, read_only=False)#, queryset=Study.objects.all(), source='studies') - groups = GroupSerializer(many=True, read_only=False)#, queryset=Study.objects.all(), source='studies') class Meta: model = Reference - fields = BASE_FIELDS + ('sid', 'groups', 'pmid', 'doi', 'title', 'abstract', 'journal', 'date', 'authors', 'pdf') - - def validate(self, data): - # TODO: add validation code - + fields = BASE_FIELDS + ('pmid','sid', 'doi', 'title','abstract','journal', 'date', 'authors', 'pdf') - return data def create(self, validated_data): authors_data = validated_data.pop('authors', []) - groups_data = validated_data.pop('groups', []) - - reference, _ = Reference.objects.update_or_create(pmid=validated_data["pmid"], defaults=validated_data) + reference, _ = Reference.objects.update_or_create(sid=validated_data["pmid"], defaults=validated_data) for author_data in authors_data: - author, created = Author.objects.update_or_create(**author_data) + author, _ = Author.objects.update_or_create(**author_data) reference.authors.add(author) reference.save() + return reference - for group in groups_data: - Group.objects.update_or_create(sid=group["sid"], reference=reference, defaults=group) - return reference + +class StudySerializer(serializers.ModelSerializer): + reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all()) + groups = GroupSerializer(many=True, read_only=False) + + + class Meta: + model = Study + fields = BASE_FIELDS + ('sid','comment','description', 'groups', 'reference') + + def create(self, validated_data): + + groups_data = validated_data.pop('groups', []) + study, _ = Study.objects.update_or_create(sid=validated_data["sid"], defaults=validated_data) + + for group in groups_data: + Group.objects.update_or_create(sid=group["sid"], study=study, defaults=group) diff --git a/pkdb_app/studies/views.py b/pkdb_app/studies/views.py index 8372360e..fef86431 100644 --- a/pkdb_app/studies/views.py +++ b/pkdb_app/studies/views.py @@ -1,5 +1,5 @@ -from .models import Author, Reference -from .serializers import AuthorSerializer, ReferenceSerializer +from .models import Author, Reference, Study +from .serializers import AuthorSerializer, ReferenceSerializer, StudySerializer from rest_framework import viewsets import django_filters.rest_framework from rest_framework import filters @@ -23,6 +23,13 @@ class ReferencesViewSet(viewsets.ModelViewSet): search_fields = filter_fields +class StudyViewSet(viewsets.ModelViewSet): + queryset = Study.objects.all() + serializer_class = StudySerializer + filter_backends = (django_filters.rest_framework.DjangoFilterBackend, filters.SearchFilter,) + filter_fields = ('sid',) + search_fields = filter_fields + #class InterventionsViewSet(viewsets.ModelViewSet): diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index 2248ac94..03b612f4 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -7,7 +7,7 @@ from rest_framework_swagger.views import get_swagger_view from .users.views import UserViewSet, UserCreateViewSet -from .studies.views import AuthorsViewSet,ReferencesViewSet +from .studies.views import AuthorsViewSet,ReferencesViewSet, StudyViewSet from .subjects.views import GroupsViewSet,CharacteristicValuesViewSet # views in User @@ -18,6 +18,8 @@ # views in studies router.register('authors',AuthorsViewSet,base_name="authors") router.register('references', ReferencesViewSet, base_name="references") +router.register('studies',StudyViewSet, base_name="studies") + router.register('groups', GroupsViewSet, base_name="groups") router.register('characteristic_values', CharacteristicValuesViewSet, base_name="characteristic_values") From cacd6d6ba768fc3da27683971f7b54356fcf28d7 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Jul 2018 18:47:05 +0200 Subject: [PATCH 018/115] working on model --- docs/api/api.ipynb | 357 ++++++++++++++++++------------- pkdb_app/serializers.py | 34 +++ pkdb_app/studies/models.py | 11 +- pkdb_app/studies/serializers.py | 54 ++++- pkdb_app/studies/views.py | 6 +- pkdb_app/subjects/managers.py | 1 + pkdb_app/subjects/models.py | 5 +- pkdb_app/subjects/serializers.py | 21 +- pkdb_app/subjects/views.py | 2 +- 9 files changed, 321 insertions(+), 170 deletions(-) create mode 100644 pkdb_app/serializers.py diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index 7964cdb9..685e4df1 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -13,7 +13,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 500, "metadata": { "collapsed": true }, @@ -24,7 +24,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 501, "metadata": { "collapsed": true }, @@ -40,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 502, "metadata": { "collapsed": true }, @@ -51,7 +51,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 503, "metadata": { "collapsed": true }, @@ -71,7 +71,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 504, "metadata": { "collapsed": true }, @@ -85,7 +85,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 505, "metadata": {}, "outputs": [ { @@ -106,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 506, "metadata": {}, "outputs": [ { @@ -131,28 +131,28 @@ " delete(id, [choice], [count], [category], [search])\n", " }\n", " groups: {\n", - " list([page], [description], [sid], [search])\n", - " create(characteristic_values, sid, count, [description])\n", - " read(id, [description], [sid], [search])\n", - " update(id, characteristic_values, sid, count, [description], [description], [sid], [search])\n", - " partial_update(id, [characteristic_values], [sid], [description], [count], [description], [sid], [search])\n", - " delete(id, [description], [sid], [search])\n", + " list([page], [description], [search])\n", + " create(characteristic_values, name, count, [description])\n", + " read(id, [description], [search])\n", + " update(id, characteristic_values, name, count, [description], [description], [search])\n", + " partial_update(id, [characteristic_values], [name], [description], [count], [description], [search])\n", + " delete(id, [description], [search])\n", " }\n", " references: {\n", - " list([page], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " create(title, date, authors, [pmid], [sid], [doi], [abstract], [journal], [pdf])\n", - " read(id, [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " update(id, title, date, authors, [pmid], [sid], [doi], [abstract], [journal], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " partial_update(id, [pmid], [sid], [doi], [title], [abstract], [journal], [date], [authors], [pdf], [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", - " delete(id, [pmid], [doi], [title], [abstract], [journal], [date], [authors], [search])\n", + " list([page], [sid], [search])\n", + " create(name, title, date, authors, [pmid], [sid], [doi], [abstract], [journal], [pdf])\n", + " read(sid, [sid], [search])\n", + " update(sid, name, title, date, authors, [pmid], [sid], [doi], [abstract], [journal], [pdf], [sid], [search])\n", + " partial_update(sid, [pmid], [sid], [name], [doi], [title], [abstract], [journal], [date], [authors], [pdf], [sid], [search])\n", + " delete(sid, [sid], [search])\n", " }\n", " studies: {\n", " list([page], [sid], [search])\n", - " create(sid, groups, reference, [comment], [description])\n", - " read(id, [sid], [search])\n", - " update(id, sid, groups, reference, [comment], [description], [sid], [search])\n", - " partial_update(id, [sid], [comment], [description], [groups], [reference], [sid], [search])\n", - " delete(id, [sid], [search])\n", + " create(sid, name, groups, reference, [comment], [description])\n", + " read(sid, [sid], [search])\n", + " update(sid, sid, name, groups, reference, [comment], [description], [sid], [search])\n", + " partial_update(sid, [sid], [comment], [name], [description], [groups], [reference], [sid], [search])\n", + " delete(sid, [sid], [search])\n", " }\n" ] } @@ -172,7 +172,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 507, "metadata": {}, "outputs": [ { @@ -202,7 +202,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 508, "metadata": {}, "outputs": [ { @@ -220,7 +220,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 509, "metadata": {}, "outputs": [ { @@ -250,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 510, "metadata": {}, "outputs": [ { @@ -281,35 +281,52 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 511, "metadata": {}, "outputs": [ { - "ename": "ErrorMessage", - "evalue": "\n authors: [\n {\n first_name: [\n \"Ensure this field has no more than 30 characters.\"\n ]\n },\n {},\n {}\n ]", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 27\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 29\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"references\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mreference_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mErrorMessage\u001b[0m: \n authors: [\n {\n first_name: [\n \"Ensure this field has no more than 30 characters.\"\n ]\n },\n {},\n {}\n ]" - ] + "data": { + "text/plain": [ + "OrderedDict([('pmid', '12087394589'),\n", + " ('sid', '012087345981'),\n", + " ('name', 'Haller2002'),\n", + " ('doi', ''),\n", + " ('title',\n", + " 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.'),\n", + " ('abstract', 'Botanical stimgle dose.'),\n", + " ('journal', 'Clinical pharmacology and therapeutics'),\n", + " ('date', '2002-07-18'),\n", + " ('authors',\n", + " [OrderedDict([('id', 2),\n", + " ('first_name', 'Christine asdin'),\n", + " ('last_name', 'Haller')]),\n", + " OrderedDict([('id', 3),\n", + " ('first_name', 'Peyton'),\n", + " ('last_name', 'Jacob')]),\n", + " OrderedDict([('id', 4),\n", + " ('first_name', 'Neal L'),\n", + " ('last_name', 'Benowitz')])]),\n", + " ('pdf', None)])" + ] + }, + "execution_count": 511, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ "# Create study\n", "reference_dict = {\n", - " \"pmid\": 12087345,\n", - " #\"sid\": \"Haller2002\",\n", - " \"date\": \"2002-07-16\",\n", + " \"pmid\": 12087394589,\n", + " \"sid\": \"012087345981\",\n", + " \"name\":\"Haller2002\",\n", + " \"date\": \"2002-07-18\",\n", " \"journal\": \"Clinical pharmacology and therapeutics\",\n", " \"title\": \"Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.\",\n", " \"abstract\": \"Botanical stimgle dose.\",\n", " \"authors\": [\n", " {\n", - " \"first_name\": \"Christine A Bansakodsfjkopasdfkpodfkanodi asdin\",\n", + " \"first_name\": \"Christine asdin\",\n", " \"last_name\": \"Haller\"\n", " },\n", " {\n", @@ -332,18 +349,42 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 512, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "OrderedDict([('count', 0),\n", + " ('next', None),\n", + " ('previous', None),\n", + " ('results', [])])" + ] + }, + "execution_count": 512, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "client.action(document, [\"studies\", \"list\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 513, "metadata": {}, "outputs": [], "source": [ "# Create study\n", "study_dict = {\n", - " \"sid\":\"test\",\n", - " \"reference\":12087345,\n", + " \"sid\":\"19023902\",\n", + " \"name\":'test',\n", + " \"reference\":\"012087345981\",\n", " \"groups\": [\n", " {\n", " \"count\": 14,\n", - " \"sid\": \"Seng2009-S_NCNS\",\n", + " \"name\": \"Seng2009-S_NCNS\",\n", " \"description\": \"59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean \\u00b1 SD) 21 \\u00b1 2 years, body weight 62 \\u00b1 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 \\u00b1 4 years, body weight 69 \\u00b1 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 \\u00b1 4 cigarettes daily, age 23 \\u00b1 5 years, body weight 71 \\u00b1 19 kg).\",\n", " \"characteristic_values\": [\n", " {\n", @@ -371,65 +412,7 @@ " \n", " ]\n", " },\n", - " {\n", - " \"count\": 15,\n", - " \"sid\": \"Seng2009-S_CNS\",\n", - " \"description\": \"59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean \\u00b1 SD) 21 \\u00b1 2 years, body weight 62 \\u00b1 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 \\u00b1 4 years, body weight 69 \\u00b1 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 \\u00b1 4 cigarettes daily, age 23 \\u00b1 5 years, body weight 71 \\u00b1 19 kg).\",\n", - " \"characteristic_values\": [\n", - " {\n", - " \"count\": 15,\n", - " \"category\": \"sex\",\n", - " \"choice\": \"M\"\n", - " },\n", - " {\n", - " \"count\": 15,\n", - " \"category\": \"species\",\n", - " \"choice\": \"homo sapiens\"\n", - " },\n", - " {\n", - " \"category\": \"body_weight\",\n", - " \"count\": 15,\n", - " \"mean\": 69.0,\n", - " \"sd\": 12.0,\n", - "\n", - " \"unit\": \"kg\"\n", - " },\n", - " ]\n", - " },\n", - " {\n", - " \"count\": 30,\n", - " \"sid\": \"Seng2009-S_CS\",\n", - " \"description\": \"59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean \\u00b1 SD) 21 \\u00b1 2 years, body weight 62 \\u00b1 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 \\u00b1 4 years, body weight 69 \\u00b1 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 \\u00b1 4 cigarettes daily, age 23 \\u00b1 5 years, body weight 71 \\u00b1 19 kg).\",\n", - " \"characteristic_values\": [\n", - " {\n", - " \"count\": 30,\n", - " \"category\": \"sex\",\n", - " \"choice\": \"M\"\n", - " },\n", - " {\n", - " \"count\": 30,\n", - " \"category\": \"species\",\n", - " \"choice\": \"homo sapiens\"\n", - " },\n", - " {\n", - " \"category\": \"body_weight\",\n", - " \"count\": 30,\n", - " \"mean\": 71.0,\n", - " \"unit\": \"kg\"\n", - " },\n", - " {\n", - " \"count\": 30,\n", - " \"category\": \"ethnicity\",\n", - " \"choice\": \"Asian\"\n", - " },\n", - " {\n", - " \"count\": 30,\n", - " \"category\": \"alcohol_abstinence\",\n", - " \"choice\": \"N\"\n", - " },\n", - "\n", - " ]\n", - " }\n", + " \n", " ],\n", " \n", " }\n", @@ -438,20 +421,20 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 514, "metadata": {}, "outputs": [ { "ename": "ErrorMessage", - "evalue": "\n sid: [\n \"study with this sid already exists.\"\n ]", + "evalue": "\n message: \"\n \n \n \n \n TypeError\n at /api/v1/studies/\n \n \n \n \n \n \n
\n

TypeError\n at /api/v1/studies/

\n
Object of type 'Reference' is not JSON serializable
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Request Method:POST
Request URL:http://0.0.0.0:8000/api/v1/studies/
Django Version:2.0.6
Exception Type:TypeError
Exception Value:
Object of type 'Reference' is not JSON serializable
Exception Location:/usr/local/lib/python3.6/json/encoder.py in default, line 180
Python Executable:/usr/local/bin/python
Python Version:3.6.6
Python Path:
['/code',\n               '/usr/local/lib/python36.zip',\n               '/usr/local/lib/python3.6',\n               '/usr/local/lib/python3.6/lib-dynload',\n               '/usr/local/lib/python3.6/site-packages']
Server time:Mon, 23 Jul 2018 16:28:03 +0000
\n
\n \n \n \n \n
\n

Traceback \n Switch to copy-and-paste view\n

\n
\n
    \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py in inner\n \n \n
    \n \n
      \n \n
    1.     This decorator is automatically applied to all middleware to ensure that
    2. \n \n
    3.     no middleware leaks an exception and that the next middleware in the stack
    4. \n \n
    5.     can rely on getting a response instead of an exception.
    6. \n \n
    7.     """
    8. \n \n
    9.     @wraps(get_response)
    10. \n \n
    11.     def inner(request):
    12. \n \n
    13.         try:
    14. \n \n
    \n \n
      \n
    1.             response = get_response(request)
      ...
    2. \n
    \n \n
      \n \n
    1.         except Exception as exc:
    2. \n \n
    3.             response = response_for_exception(request, exc)
    4. \n \n
    5.         return response
    6. \n \n
    7.     return inner
    8. \n \n
    9. \n \n
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    exc
    TypeError("Object of type 'Reference' is not JSON serializable",)
    get_response
    <bound method BaseHandler._get_response of <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response\n \n \n
    \n \n
      \n \n
    1.                         "HttpResponse object. It returned None instead."
    2. \n \n
    3.                         % (middleware_method.__self__.__class__.__name__)
    4. \n \n
    5.                     )
    6. \n \n
    7. \n \n
    8.             try:
    9. \n \n
    10.                 response = response.render()
    11. \n \n
    12.             except Exception as e:
    13. \n \n
    \n \n
      \n
    1.                 response = self.process_exception_by_middleware(e, request)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2.         return response
    3. \n \n
    4. \n \n
    5.     def process_exception_by_middleware(self, exception, request):
    6. \n \n
    7.         """
    8. \n \n
    9.         Pass the exception to the exception middleware. If no middleware
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    callback
    <function StudyViewSet at 0x7f0587099378>
    callback_args
    ()
    callback_kwargs
    {}
    middleware_method
    <bound method CsrfViewMiddleware.process_view of <django.middleware.csrf.CsrfViewMiddleware object at 0x7f0586bb1588>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    resolver
    <URLResolver 'pkdb_app.urls' (None:None) '^/'>
    resolver_match
    ResolverMatch(func=pkdb_app.studies.views.StudyViewSet, args=(), kwargs={}, url_name=studies-list, app_names=[], namespaces=[])
    response
    <Response status_code=201, "application/json">
    self
    <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>
    wrapped_callback
    <function StudyViewSet at 0x7f0587099378>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response\n \n \n
    \n \n
      \n \n
    1.                     raise ValueError(
    2. \n \n
    3.                         "%s.process_template_response didn't return an "
    4. \n \n
    5.                         "HttpResponse object. It returned None instead."
    6. \n \n
    7.                         % (middleware_method.__self__.__class__.__name__)
    8. \n \n
    9.                     )
    10. \n \n
    11. \n \n
    12.             try:
    13. \n \n
    \n \n
      \n
    1.                 response = response.render()
      ...
    2. \n
    \n \n
      \n \n
    1.             except Exception as e:
    2. \n \n
    3.                 response = self.process_exception_by_middleware(e, request)
    4. \n \n
    5. \n \n
    6.         return response
    7. \n \n
    8. \n \n
    9.     def process_exception_by_middleware(self, exception, request):
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    callback
    <function StudyViewSet at 0x7f0587099378>
    callback_args
    ()
    callback_kwargs
    {}
    middleware_method
    <bound method CsrfViewMiddleware.process_view of <django.middleware.csrf.CsrfViewMiddleware object at 0x7f0586bb1588>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    resolver
    <URLResolver 'pkdb_app.urls' (None:None) '^/'>
    resolver_match
    ResolverMatch(func=pkdb_app.studies.views.StudyViewSet, args=(), kwargs={}, url_name=studies-list, app_names=[], namespaces=[])
    response
    <Response status_code=201, "application/json">
    self
    <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>
    wrapped_callback
    <function StudyViewSet at 0x7f0587099378>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/template/response.py in render\n \n \n
    \n \n
      \n \n
    1. \n \n
    2.         If the content has already been rendered, this is a no-op.
    3. \n \n
    4. \n \n
    5.         Return the baked response instance.
    6. \n \n
    7.         """
    8. \n \n
    9.         retval = self
    10. \n \n
    11.         if not self._is_rendered:
    12. \n \n
    \n \n
      \n
    1.             self.content = self.rendered_content
      ...
    2. \n
    \n \n
      \n \n
    1.             for post_callback in self._post_render_callbacks:
    2. \n \n
    3.                 newretval = post_callback(retval)
    4. \n \n
    5.                 if newretval is not None:
    6. \n \n
    7.                     retval = newretval
    8. \n \n
    9.         return retval
    10. \n \n
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    retval
    <Response status_code=201, "application/json">
    self
    <Response status_code=201, "application/json">
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/response.py in rendered_content\n \n \n
    \n \n
      \n \n
    1. \n \n
    2.         if content_type is None and charset is not None:
    3. \n \n
    4.             content_type = "{0}; charset={1}".format(media_type, charset)
    5. \n \n
    6.         elif content_type is None:
    7. \n \n
    8.             content_type = media_type
    9. \n \n
    10.         self['Content-Type'] = content_type
    11. \n \n
    12. \n \n
    \n \n
      \n
    1.         ret = renderer.render(self.data, accepted_media_type, context)
      ...
    2. \n
    \n \n
      \n \n
    1.         if isinstance(ret, six.text_type):
    2. \n \n
    3.             assert charset, (
    4. \n \n
    5.                 'renderer returned unicode, and did not specify '
    6. \n \n
    7.                 'a charset value.'
    8. \n \n
    9.             )
    10. \n \n
    11.             return bytes(ret.encode(charset))
    12. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    accepted_media_type
    'application/json'
    charset
    None
    content_type
    'application/json'
    context
    {'args': (),\n               'kwargs': {},\n               'request': <rest_framework.request.Request object at 0x7f0586b87780>,\n               'response': <Response status_code=201, "application/json">,\n               'view': <pkdb_app.studies.views.StudyViewSet object at 0x7f0586b87be0>}
    media_type
    'application/json'
    renderer
    <rest_framework.renderers.JSONRenderer object at 0x7f05870005c0>
    self
    <Response status_code=201, "application/json">
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/renderers.py in render\n \n \n
    \n \n
      \n \n
    1.             separators = SHORT_SEPARATORS if self.compact else LONG_SEPARATORS
    2. \n \n
    3.         else:
    4. \n \n
    5.             separators = INDENT_SEPARATORS
    6. \n \n
    7. \n \n
    8.         ret = json.dumps(
    9. \n \n
    10.             data, cls=self.encoder_class,
    11. \n \n
    12.             indent=indent, ensure_ascii=self.ensure_ascii,
    13. \n \n
    \n \n
      \n
    1.             allow_nan=not self.strict, separators=separators
      ...
    2. \n
    \n \n
      \n \n
    1.         )
    2. \n \n
    3. \n \n
    4.         # On python 2.x json.dumps() returns bytestrings if ensure_ascii=True,
    5. \n \n
    6.         # but if ensure_ascii=False, the return type is underspecified,
    7. \n \n
    8.         # and may (or may not) be unicode.
    9. \n \n
    10.         # On python 3.x json.dumps() returns unicode strings.
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    accepted_media_type
    'application/json'
    data
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    indent
    None
    renderer_context
    {'args': (),\n               'kwargs': {},\n               'request': <rest_framework.request.Request object at 0x7f0586b87780>,\n               'response': <Response status_code=201, "application/json">,\n               'view': <pkdb_app.studies.views.StudyViewSet object at 0x7f0586b87be0>}
    self
    <rest_framework.renderers.JSONRenderer object at 0x7f05870005c0>
    separators
    (',', ':')
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/utils/json.py in dumps\n \n \n
    \n \n
      \n \n
    1.     kwargs.setdefault('allow_nan', False)
    2. \n \n
    3.     return json.dump(*args, **kwargs)
    4. \n \n
    5. \n \n
    6. \n \n
    7. @functools.wraps(json.dumps)
    8. \n \n
    9. def dumps(*args, **kwargs):
    10. \n \n
    11.     kwargs.setdefault('allow_nan', False)
    12. \n \n
    \n \n
      \n
    1.     return json.dumps(*args, **kwargs)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. \n \n
    3. @functools.wraps(json.load)
    4. \n \n
    5. def load(*args, **kwargs):
    6. \n \n
    7.     kwargs.setdefault('parse_constant', strict_constant)
    8. \n \n
    9.     return json.load(*args, **kwargs)
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    args
    ({'comment': None,\n                'description': None,\n                'groups': [OrderedDict([('reference',\n                                         <Reference: Reference object (012087345981)>),\n                                        ('characteristic_values',\n                                         [OrderedDict([('id', 4),\n                                                       ('choice', 'Asian'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'ethnicity'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 3),\n                                                       ('choice', None),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', 62.0),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', 9.0),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', 'kg'),\n                                                       ('category', 'body_weight'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 2),\n                                                       ('choice', 'homo sapiens'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'species'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 1),\n                                                       ('choice', 'M'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'sex'),\n                                                       ('group', 1)])]),\n                                        ('name', 'Seng2009-S_NCNS'),\n                                        ('description',\n                                         '59 healthy adult Asian volunteers were included. '\n                                         'In what follows, a non-caffeine consumer (NCCS) '\n                                         'refers to an individual who consumed beverages\\\n              '\n                                         '(coffee or tea) containing <=200 mg of caffeine '\n                                         'per day, and a regular caffeine consumer to one '\n                                         'who consumed more >200 mg. A cup (150 mL) of '\n                                         'coffee or tea is equivalent to approximately a '\n                                         'caffeine dose... <trimmed 5004 bytes string>
    kwargs
    {'allow_nan': False,\n               'cls': <class 'rest_framework.utils.encoders.JSONEncoder'>,\n               'ensure_ascii': False,\n               'indent': None,\n               'separators': (',', ':')}
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/__init__.py in dumps\n \n \n
    \n \n
      \n \n
    1.         return _default_encoder.encode(obj)
    2. \n \n
    3.     if cls is None:
    4. \n \n
    5.         cls = JSONEncoder
    6. \n \n
    7.     return cls(
    8. \n \n
    9.         skipkeys=skipkeys, ensure_ascii=ensure_ascii,
    10. \n \n
    11.         check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    12. \n \n
    13.         separators=separators, default=default, sort_keys=sort_keys,
    14. \n \n
    \n \n
      \n
    1.         **kw).encode(obj)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. \n \n
    3. _default_decoder = JSONDecoder(object_hook=None, object_pairs_hook=None)
    4. \n \n
    5. \n \n
    6. \n \n
    7. def detect_encoding(b):
    8. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    allow_nan
    False
    check_circular
    True
    cls
    <class 'rest_framework.utils.encoders.JSONEncoder'>
    default
    None
    ensure_ascii
    False
    indent
    None
    kw
    {}
    obj
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    separators
    (',', ':')
    skipkeys
    False
    sort_keys
    False
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in encode\n \n \n
    \n \n
      \n \n
    1.             if self.ensure_ascii:
    2. \n \n
    3.                 return encode_basestring_ascii(o)
    4. \n \n
    5.             else:
    6. \n \n
    7.                 return encode_basestring(o)
    8. \n \n
    9.         # This doesn't pass the iterator directly to ''.join() because the
    10. \n \n
    11.         # exceptions aren't as detailed.  The list call should be roughly
    12. \n \n
    13.         # equivalent to the PySequence_Fast that ''.join() would do.
    14. \n \n
    \n \n
      \n
    1.         chunks = self.iterencode(o, _one_shot=True)
      ...
    2. \n
    \n \n
      \n \n
    1.         if not isinstance(chunks, (list, tuple)):
    2. \n \n
    3.             chunks = list(chunks)
    4. \n \n
    5.         return ''.join(chunks)
    6. \n \n
    7. \n \n
    8.     def iterencode(self, o, _one_shot=False):
    9. \n \n
    10.         """Encode the given object and yield each string
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    o
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in iterencode\n \n \n
    \n \n
      \n \n
    1.                 self.key_separator, self.item_separator, self.sort_keys,
    2. \n \n
    3.                 self.skipkeys, self.allow_nan)
    4. \n \n
    5.         else:
    6. \n \n
    7.             _iterencode = _make_iterencode(
    8. \n \n
    9.                 markers, self.default, _encoder, self.indent, floatstr,
    10. \n \n
    11.                 self.key_separator, self.item_separator, self.sort_keys,
    12. \n \n
    13.                 self.skipkeys, _one_shot)
    14. \n \n
    \n \n
      \n
    1.         return _iterencode(o, 0)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
    3. \n \n
    4.         _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
    5. \n \n
    6.         ## HACK: hand-optimized bytecode; turn globals into locals
    7. \n \n
    8.         ValueError=ValueError,
    9. \n \n
    10.         dict=dict,
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    _encoder
    <built-in function encode_basestring>
    _iterencode
    <_json.Encoder object at 0x7f0586377de0>
    _one_shot
    True
    floatstr
    <function JSONEncoder.iterencode.<locals>.floatstr at 0x7f0586ac9488>
    markers
    {139661702408232: <Reference: Reference object (012087345981)>,\n               139661711021056: OrderedDict([('reference',\n                                              <Reference: Reference object (012087345981)>),\n                                             ('characteristic_values',\n                                              [OrderedDict([('id', 4),\n                                                            ('choice', 'Asian'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'ethnicity'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 3),\n                                                            ('choice', None),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', 62.0),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', 9.0),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', 'kg'),\n                                                            ('category', 'body_weight'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 2),\n                                                            ('choice', 'homo sapiens'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'species'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 1),\n                                                            ('choice', 'M'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'sex'),\n                                                            ('group', 1)])]),\n                                             ('name', 'Seng2009-S_NCNS'),\n                                             ('description',\n                                              '59 healthy adult Asian volunteers were '\n                                              'included. In what follows, a non-caffeine '\n                                              'consumer (NCCS) refers to an individual who '\n                                         ... <trimmed 18057 bytes string>
    o
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/utils/encoders.py in default\n \n \n
    \n \n
      \n \n
    1.         elif hasattr(obj, '__getitem__'):
    2. \n \n
    3.             try:
    4. \n \n
    5.                 return dict(obj)
    6. \n \n
    7.             except Exception:
    8. \n \n
    9.                 pass
    10. \n \n
    11.         elif hasattr(obj, '__iter__'):
    12. \n \n
    13.             return tuple(item for item in obj)
    14. \n \n
    \n \n
      \n
    1.         return super(JSONEncoder, self).default(obj)
      ...
    2. \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    __class__
    <class 'rest_framework.utils.encoders.JSONEncoder'>
    obj
    <Reference: Reference object (012087345981)>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in default\n \n \n
    \n \n
      \n \n
    1.                 else:
    2. \n \n
    3.                     return list(iterable)
    4. \n \n
    5.                 # Let the base class default method raise the TypeError
    6. \n \n
    7.                 return JSONEncoder.default(self, o)
    8. \n \n
    9. \n \n
    10.         """
    11. \n \n
    12.         raise TypeError("Object of type '%s' is not JSON serializable" %
    13. \n \n
    \n \n
      \n
    1.                         o.__class__.__name__)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2.     def encode(self, o):
    3. \n \n
    4.         """Return a JSON string representation of a Python data structure.
    5. \n \n
    6. \n \n
    7.         >>> from json.encoder import JSONEncoder
    8. \n \n
    9.         >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    o
    <Reference: Reference object (012087345981)>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n
\n
\n
\n \n
\n \n \n \n \n \n

\n \n
\n
\n
\n \n \n \n
\n

Request information

\n \n \n \n

USER

\n

AnonymousUser

\n \n \n

GET

\n \n

No GET data

\n \n \n

POST

\n \n

No POST data

\n \n

FILES

\n \n

No FILES data

\n \n \n \n

COOKIES

\n \n

No cookie data

\n \n \n

META

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
VariableValue
CONTENT_LENGTH
'1292'
CONTENT_TYPE
'application/json'
DJANGO_CONFIGURATION
'Local'
DJANGO_SECRET_KEY
'local'
DJANGO_SETTINGS_MODULE
'pkdb_app.config'
GATEWAY_INTERFACE
'CGI/1.1'
GPG_KEY
'0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D'
HOME
'/root'
HOSTNAME
'83fb6011203b'
HTTP_ACCEPT
'application/coreapi+json, application/vnd.coreapi+json, */*'
HTTP_ACCEPT_ENCODING
'gzip, deflate'
HTTP_CONNECTION
'keep-alive'
HTTP_HOST
'0.0.0.0:8000'
HTTP_USER_AGENT
'coreapi'
LANG
'C.UTF-8'
PATH
'/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PATH_INFO
'/api/v1/studies/'
PWD
'/code'
PYTHONUNBUFFERED
'1'
PYTHON_PIP_VERSION
'10.0.1'
PYTHON_VERSION
'3.6.6'
QUERY_STRING
''
REMOTE_ADDR
'172.22.0.1'
REMOTE_HOST
''
REQUEST_METHOD
'POST'
RUN_MAIN
'true'
SCRIPT_NAME
''
SERVER_NAME
'83fb6011203b'
SERVER_PORT
'8000'
SERVER_PROTOCOL
'HTTP/1.1'
SERVER_SOFTWARE
'WSGIServer/0.2'
SHLVL
'1'
TZ
'UTC'
_
'./manage.py'
wsgi.errors
<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
wsgi.file_wrapper
''
wsgi.input
<_io.BufferedReader name=5>
wsgi.multiprocess
False
wsgi.multithread
True
wsgi.run_once
False
wsgi.url_scheme
'http'
wsgi.version
(1, 0)
\n \n \n

Settings

\n

Using settings module pkdb_app.config

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
SettingValue
ABSOLUTE_URL_OVERRIDES
{}
ADMINS
(('Author', 'janekg89@hotmail.de'),)
ALLOWED_HOSTS
['*']
APPEND_SLASH
False
AUTHENTICATION_BACKENDS
['django.contrib.auth.backends.ModelBackend']
AUTH_PASSWORD_VALIDATORS
'********************'
AUTH_USER_MODEL
'users.User'
CACHES
{'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
CACHE_MIDDLEWARE_ALIAS
'default'
CACHE_MIDDLEWARE_KEY_PREFIX
'********************'
CACHE_MIDDLEWARE_SECONDS
600
CONFIGURATION
'pkdb_app.config.Local'
CSRF_COOKIE_AGE
31449600
CSRF_COOKIE_DOMAIN
None
CSRF_COOKIE_HTTPONLY
False
CSRF_COOKIE_NAME
'csrftoken'
CSRF_COOKIE_PATH
'/'
CSRF_COOKIE_SECURE
False
CSRF_FAILURE_VIEW
'django.views.csrf.csrf_failure'
CSRF_HEADER_NAME
'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS
[]
CSRF_USE_SESSIONS
False
DATABASES
{'default': {'ATOMIC_REQUESTS': False,\n                           'AUTOCOMMIT': True,\n                           'CONN_MAX_AGE': 600,\n                           'ENGINE': 'django.db.backends.postgresql_psycopg2',\n                           'HOST': 'postgres',\n                           'NAME': 'postgres',\n                           'OPTIONS': {},\n                           'PASSWORD': '********************',\n                           'PORT': 5432,\n                           'TEST': {'CHARSET': None,\n                                    'COLLATION': None,\n                                    'MIRROR': None,\n                                    'NAME': None},\n                           'TIME_ZONE': None,\n                           'USER': 'postgres'}}
DATABASE_ROUTERS
[]
DATA_UPLOAD_MAX_MEMORY_SIZE
2621440
DATA_UPLOAD_MAX_NUMBER_FIELDS
1000
DATETIME_FORMAT
'N j, Y, P'
DATETIME_INPUT_FORMATS
['%Y-%m-%d %H:%M:%S',\n               '%Y-%m-%d %H:%M:%S.%f',\n               '%Y-%m-%d %H:%M',\n               '%Y-%m-%d',\n               '%m/%d/%Y %H:%M:%S',\n               '%m/%d/%Y %H:%M:%S.%f',\n               '%m/%d/%Y %H:%M',\n               '%m/%d/%Y',\n               '%m/%d/%y %H:%M:%S',\n               '%m/%d/%y %H:%M:%S.%f',\n               '%m/%d/%y %H:%M',\n               '%m/%d/%y']
DATE_FORMAT
'N j, Y'
DATE_INPUT_FORMATS
['%Y-%m-%d',\n               '%m/%d/%Y',\n               '%m/%d/%y',\n               '%b %d %Y',\n               '%b %d, %Y',\n               '%d %b %Y',\n               '%d %b, %Y',\n               '%B %d %Y',\n               '%B %d, %Y',\n               '%d %B %Y',\n               '%d %B, %Y']
DEBUG
True
DEBUG_PROPAGATE_EXCEPTIONS
False
DECIMAL_SEPARATOR
'.'
DEFAULT_CHARSET
'utf-8'
DEFAULT_CONTENT_TYPE
'text/html'
DEFAULT_EXCEPTION_REPORTER_FILTER
'django.views.debug.SafeExceptionReporterFilter'
DEFAULT_FILE_STORAGE
'django.core.files.storage.FileSystemStorage'
DEFAULT_FROM_EMAIL
'webmaster@localhost'
DEFAULT_INDEX_TABLESPACE
''
DEFAULT_TABLESPACE
''
DISALLOWED_USER_AGENTS
[]
DOTENV_LOADED
None
EMAIL_BACKEND
'django.core.mail.backends.console.EmailBackend'
EMAIL_HOST
'localhost'
EMAIL_HOST_PASSWORD
'********************'
EMAIL_HOST_USER
''
EMAIL_PORT
1025
EMAIL_SSL_CERTFILE
None
EMAIL_SSL_KEYFILE
'********************'
EMAIL_SUBJECT_PREFIX
'[Django] '
EMAIL_TIMEOUT
None
EMAIL_USE_LOCALTIME
False
EMAIL_USE_SSL
False
EMAIL_USE_TLS
False
FILE_CHARSET
'utf-8'
FILE_UPLOAD_DIRECTORY_PERMISSIONS
None
FILE_UPLOAD_HANDLERS
['django.core.files.uploadhandler.MemoryFileUploadHandler',\n               'django.core.files.uploadhandler.TemporaryFileUploadHandler']
FILE_UPLOAD_MAX_MEMORY_SIZE
2621440
FILE_UPLOAD_PERMISSIONS
None
FILE_UPLOAD_TEMP_DIR
None
FIRST_DAY_OF_WEEK
0
FIXTURE_DIRS
[]
FORCE_SCRIPT_NAME
None
FORMAT_MODULE_PATH
None
FORM_RENDERER
'django.forms.renderers.DjangoTemplates'
IGNORABLE_404_URLS
[]
INSTALLED_APPS
('django.contrib.admin',\n               'django.contrib.auth',\n               'django.contrib.contenttypes',\n               'django.contrib.sessions',\n               'django.contrib.messages',\n               'django.contrib.staticfiles',\n               'rest_framework',\n               'rest_framework.authtoken',\n               'django_filters',\n               'rest_framework_swagger',\n               'pkdb_app.users',\n               'pkdb_app.studies',\n               'pkdb_app.subjects',\n               'pkdb_app.interventions',\n               'django_nose')
INTERNAL_IPS
[]
LANGUAGES
[('af', 'Afrikaans'),\n               ('ar', 'Arabic'),\n               ('ast', 'Asturian'),\n               ('az', 'Azerbaijani'),\n               ('bg', 'Bulgarian'),\n               ('be', 'Belarusian'),\n               ('bn', 'Bengali'),\n               ('br', 'Breton'),\n               ('bs', 'Bosnian'),\n               ('ca', 'Catalan'),\n               ('cs', 'Czech'),\n               ('cy', 'Welsh'),\n               ('da', 'Danish'),\n               ('de', 'German'),\n               ('dsb', 'Lower Sorbian'),\n               ('el', 'Greek'),\n               ('en', 'English'),\n               ('en-au', 'Australian English'),\n               ('en-gb', 'British English'),\n               ('eo', 'Esperanto'),\n               ('es', 'Spanish'),\n               ('es-ar', 'Argentinian Spanish'),\n               ('es-co', 'Colombian Spanish'),\n               ('es-mx', 'Mexican Spanish'),\n               ('es-ni', 'Nicaraguan Spanish'),\n               ('es-ve', 'Venezuelan Spanish'),\n               ('et', 'Estonian'),\n               ('eu', 'Basque'),\n               ('fa', 'Persian'),\n               ('fi', 'Finnish'),\n               ('fr', 'French'),\n               ('fy', 'Frisian'),\n               ('ga', 'Irish'),\n               ('gd', 'Scottish Gaelic'),\n               ('gl', 'Galician'),\n               ('he', 'Hebrew'),\n               ('hi', 'Hindi'),\n               ('hr', 'Croatian'),\n               ('hsb', 'Upper Sorbian'),\n               ('hu', 'Hungarian'),\n               ('ia', 'Interlingua'),\n               ('id', 'Indonesian'),\n               ('io', 'Ido'),\n               ('is', 'Icelandic'),\n               ('it', 'Italian'),\n               ('ja', 'Japanese'),\n               ('ka', 'Georgian'),\n               ('kab', 'Kabyle'),\n               ('kk', 'Kazakh'),\n               ('km', 'Khmer'),\n               ('kn', 'Kannada'),\n               ('ko', 'Korean'),\n               ('lb', 'Luxembourgish'),\n               ('lt', 'Lithuanian'),\n               ('lv', 'Latvian'),\n               ('mk', 'Macedonian'),\n               ('ml', 'Malayalam'),\n               ('mn', 'Mongolian'),\n               ('mr', 'Marathi'),\n               ('my', 'Burmese'),\n               ('nb', 'Norwegian Bokm\\u00e5l'),\n               ('ne', 'Nepali'),\n               ('nl', 'Dutch'),\n               ('nn', 'Norwegian Nynorsk'),\n               ('os', 'Ossetic'),\n               ('pa', 'Punjabi'),\n               ('pl', 'Polish'),\n               ('pt', 'Portuguese'),\n               ('pt-br', 'Brazilian Portuguese'),\n               ('ro', 'Romanian'),\n               ('ru', 'Russian'),\n               ('sk', 'Slovak'),\n               ('sl', 'Slovenian'),\n               ('sq', 'Albanian'),\n               ('sr', 'Serbian'),\n               ('sr-latn', 'Serbian Latin'),\n               ('sv', 'Swedish'),\n               ('sw', 'Swahili'),\n               ('ta', 'Tamil'),\n               ('te', 'Telugu'),\n               ('th', 'Thai'),\n               ('tr', 'Turkish'),\n               ('tt', 'Tatar'),\n               ('udm', 'Udmurt'),\n               ('uk', 'Ukrainian'),\n               ('ur', 'Urdu'),\n               ('vi', 'Vietnamese'),\n               ('zh-hans', 'Simplified Chinese'),\n               ('zh-hant', 'Traditional Chinese')]
LANGUAGES_BIDI
['he', 'ar', 'fa', 'ur']
LANGUAGE_CODE
'en-us'
LANGUAGE_COOKIE_AGE
None
LANGUAGE_COOKIE_DOMAIN
None
LANGUAGE_COOKIE_NAME
'django_language'
LANGUAGE_COOKIE_PATH
'/'
LOCALE_PATHS
[]
LOGGING
{'disable_existing_loggers': False,\n               'filters': {'require_debug_true': {'()': 'django.utils.log.RequireDebugTrue'}},\n               'formatters': {'django.server': {'()': 'django.utils.log.ServerFormatter',\n                                                'format': '[%(server_time)s] %(message)s'},\n                              'simple': {'format': '%(levelname)s %(message)s'},\n                              'verbose': {'format': '%(levelname)s %(asctime)s %(module)s '\n                                                    '%(process)d %(thread)d %(message)s'}},\n               'handlers': {'console': {'class': 'logging.StreamHandler',\n                                        'formatter': 'simple',\n                                        'level': 'DEBUG'},\n                            'django.server': {'class': 'logging.StreamHandler',\n                                              'formatter': 'django.server',\n                                              'level': 'INFO'},\n                            'mail_admins': {'class': 'django.utils.log.AdminEmailHandler',\n                                            'level': 'ERROR'}},\n               'loggers': {'django': {'handlers': ['console'], 'propagate': True},\n                           'django.db.backends': {'handlers': ['console'], 'level': 'INFO'},\n                           'django.request': {'handlers': ['mail_admins', 'console'],\n                                              'level': 'ERROR',\n                                              'propagate': False},\n                           'django.server': {'handlers': ['django.server'],\n                                             'level': 'INFO',\n                                             'propagate': False}},\n               'version': 1}
LOGGING_CONFIG
'logging.config.dictConfig'
LOGIN_REDIRECT_URL
'/'
LOGIN_URL
'rest_framework:login'
LOGOUT_REDIRECT_URL
None
LOGOUT_URL
'rest_framework:logout'
MANAGERS
[]
MEDIA_ROOT
'/code/media'
MEDIA_URL
'/media/'
MESSAGE_STORAGE
'django.contrib.messages.storage.fallback.FallbackStorage'
MIDDLEWARE
('django.middleware.security.SecurityMiddleware',\n               'django.contrib.sessions.middleware.SessionMiddleware',\n               'django.middleware.common.CommonMiddleware',\n               'django.middleware.csrf.CsrfViewMiddleware',\n               'django.contrib.auth.middleware.AuthenticationMiddleware',\n               'django.contrib.messages.middleware.MessageMiddleware',\n               'django.middleware.clickjacking.XFrameOptionsMiddleware')
MIGRATION_MODULES
{}
MONTH_DAY_FORMAT
'F j'
NOSE_ARGS
['/code/pkdb_app',\n               '-s',\n               '--nologcapture',\n               '--with-coverage',\n               '--with-progressive',\n               '--cover-package=pkdb']
NUMBER_GROUPING
0
PASSWORD_HASHERS
'********************'
PASSWORD_RESET_TIMEOUT_DAYS
'********************'
PREPEND_WWW
False
REST_FRAMEWORK
{'DATETIME_FORMAT': '%Y-%m-%dT%H:%M:%S%z',\n               'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.SessionAuthentication',),\n               'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),\n               'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',\n               'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'],\n               'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer',\n                                            'rest_framework.renderers.BrowsableAPIRenderer'),\n               'PAGE_SIZE': 10}
ROOT_URLCONF
'pkdb_app.urls'
SECRET_KEY
'********************'
SECURE_BROWSER_XSS_FILTER
False
SECURE_CONTENT_TYPE_NOSNIFF
False
SECURE_HSTS_INCLUDE_SUBDOMAINS
False
SECURE_HSTS_PRELOAD
False
SECURE_HSTS_SECONDS
0
SECURE_PROXY_SSL_HEADER
None
SECURE_REDIRECT_EXEMPT
[]
SECURE_SSL_HOST
None
SECURE_SSL_REDIRECT
False
SERVER_EMAIL
'root@localhost'
SESSION_CACHE_ALIAS
'default'
SESSION_COOKIE_AGE
1209600
SESSION_COOKIE_DOMAIN
None
SESSION_COOKIE_HTTPONLY
True
SESSION_COOKIE_NAME
'sessionid'
SESSION_COOKIE_PATH
'/'
SESSION_COOKIE_SECURE
False
SESSION_ENGINE
'django.contrib.sessions.backends.db'
SESSION_EXPIRE_AT_BROWSER_CLOSE
False
SESSION_FILE_PATH
None
SESSION_SAVE_EVERY_REQUEST
False
SESSION_SERIALIZER
'django.contrib.sessions.serializers.JSONSerializer'
SETTINGS_MODULE
'pkdb_app.config'
SHORT_DATETIME_FORMAT
'm/d/Y P'
SHORT_DATE_FORMAT
'm/d/Y'
SIGNING_BACKEND
'django.core.signing.TimestampSigner'
SILENCED_SYSTEM_CHECKS
[]
STATICFILES_DIRS
[]
STATICFILES_FINDERS
('django.contrib.staticfiles.finders.FileSystemFinder',\n               'django.contrib.staticfiles.finders.AppDirectoriesFinder')
STATICFILES_STORAGE
'django.contrib.staticfiles.storage.StaticFilesStorage'
STATIC_ROOT
'/code/static'
STATIC_URL
'/static/'
SWAGGER_SETTINGS
{'APIS_SORTER': '********************',\n               'DOC_EXPANSION': 'list',\n               'LOGIN_URL': 'rest_framework:login',\n               'LOGOUT_URL': 'rest_framework:logout',\n               'SECURITY_DEFINITIONS': {'basic': {'type': 'basic'}},\n               'USE_SESSION_AUTH': True}
TEMPLATES
[{'APP_DIRS': True,\n                'BACKEND': 'django.template.backends.django.DjangoTemplates',\n                'DIRS': [],\n                'OPTIONS': {'context_processors': ['django.template.context_processors.debug',\n                                                   'django.template.context_processors.request',\n                                                   'django.contrib.auth.context_processors.auth',\n                                                   'django.contrib.messages.context_processors.messages']}}]
TEST_NON_SERIALIZED_APPS
[]
TEST_RUNNER
'django_nose.NoseTestSuiteRunner'
THOUSAND_SEPARATOR
','
TIME_FORMAT
'P'
TIME_INPUT_FORMATS
['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
TIME_ZONE
'UTC'
USE_ETAGS
False
USE_I18N
False
USE_L10N
True
USE_THOUSAND_SEPARATOR
False
USE_TZ
True
USE_X_FORWARDED_HOST
False
USE_X_FORWARDED_PORT
False
WSGI_APPLICATION
'pkdb_app.wsgi.application'
X_FRAME_OPTIONS
'SAMEORIGIN'
YEAR_MONTH_FORMAT
'F Y'
\n \n
\n \n
\n

\n You're seeing this error because you have DEBUG = True in your\n Django settings file. Change that to False, and Django will\n display a standard page generated by the handler for this status code.\n

\n
\n \n \n \n \"", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"studies\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"studies\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mErrorMessage\u001b[0m: \n sid: [\n \"study with this sid already exists.\"\n ]" + "\u001b[0;31mErrorMessage\u001b[0m: \n message: \"\n \n \n \n \n TypeError\n at /api/v1/studies/\n \n \n \n \n \n \n
\n

TypeError\n at /api/v1/studies/

\n
Object of type 'Reference' is not JSON serializable
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Request Method:POST
Request URL:http://0.0.0.0:8000/api/v1/studies/
Django Version:2.0.6
Exception Type:TypeError
Exception Value:
Object of type 'Reference' is not JSON serializable
Exception Location:/usr/local/lib/python3.6/json/encoder.py in default, line 180
Python Executable:/usr/local/bin/python
Python Version:3.6.6
Python Path:
['/code',\n               '/usr/local/lib/python36.zip',\n               '/usr/local/lib/python3.6',\n               '/usr/local/lib/python3.6/lib-dynload',\n               '/usr/local/lib/python3.6/site-packages']
Server time:Mon, 23 Jul 2018 16:28:03 +0000
\n
\n \n \n \n \n
\n

Traceback \n Switch to copy-and-paste view\n

\n
\n
    \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py in inner\n \n \n
    \n \n
      \n \n
    1.     This decorator is automatically applied to all middleware to ensure that
    2. \n \n
    3.     no middleware leaks an exception and that the next middleware in the stack
    4. \n \n
    5.     can rely on getting a response instead of an exception.
    6. \n \n
    7.     """
    8. \n \n
    9.     @wraps(get_response)
    10. \n \n
    11.     def inner(request):
    12. \n \n
    13.         try:
    14. \n \n
    \n \n
      \n
    1.             response = get_response(request)
      ...
    2. \n
    \n \n
      \n \n
    1.         except Exception as exc:
    2. \n \n
    3.             response = response_for_exception(request, exc)
    4. \n \n
    5.         return response
    6. \n \n
    7.     return inner
    8. \n \n
    9. \n \n
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    exc
    TypeError("Object of type 'Reference' is not JSON serializable",)
    get_response
    <bound method BaseHandler._get_response of <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response\n \n \n
    \n \n
      \n \n
    1.                         "HttpResponse object. It returned None instead."
    2. \n \n
    3.                         % (middleware_method.__self__.__class__.__name__)
    4. \n \n
    5.                     )
    6. \n \n
    7. \n \n
    8.             try:
    9. \n \n
    10.                 response = response.render()
    11. \n \n
    12.             except Exception as e:
    13. \n \n
    \n \n
      \n
    1.                 response = self.process_exception_by_middleware(e, request)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2.         return response
    3. \n \n
    4. \n \n
    5.     def process_exception_by_middleware(self, exception, request):
    6. \n \n
    7.         """
    8. \n \n
    9.         Pass the exception to the exception middleware. If no middleware
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    callback
    <function StudyViewSet at 0x7f0587099378>
    callback_args
    ()
    callback_kwargs
    {}
    middleware_method
    <bound method CsrfViewMiddleware.process_view of <django.middleware.csrf.CsrfViewMiddleware object at 0x7f0586bb1588>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    resolver
    <URLResolver 'pkdb_app.urls' (None:None) '^/'>
    resolver_match
    ResolverMatch(func=pkdb_app.studies.views.StudyViewSet, args=(), kwargs={}, url_name=studies-list, app_names=[], namespaces=[])
    response
    <Response status_code=201, "application/json">
    self
    <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>
    wrapped_callback
    <function StudyViewSet at 0x7f0587099378>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response\n \n \n
    \n \n
      \n \n
    1.                     raise ValueError(
    2. \n \n
    3.                         "%s.process_template_response didn't return an "
    4. \n \n
    5.                         "HttpResponse object. It returned None instead."
    6. \n \n
    7.                         % (middleware_method.__self__.__class__.__name__)
    8. \n \n
    9.                     )
    10. \n \n
    11. \n \n
    12.             try:
    13. \n \n
    \n \n
      \n
    1.                 response = response.render()
      ...
    2. \n
    \n \n
      \n \n
    1.             except Exception as e:
    2. \n \n
    3.                 response = self.process_exception_by_middleware(e, request)
    4. \n \n
    5. \n \n
    6.         return response
    7. \n \n
    8. \n \n
    9.     def process_exception_by_middleware(self, exception, request):
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    callback
    <function StudyViewSet at 0x7f0587099378>
    callback_args
    ()
    callback_kwargs
    {}
    middleware_method
    <bound method CsrfViewMiddleware.process_view of <django.middleware.csrf.CsrfViewMiddleware object at 0x7f0586bb1588>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    resolver
    <URLResolver 'pkdb_app.urls' (None:None) '^/'>
    resolver_match
    ResolverMatch(func=pkdb_app.studies.views.StudyViewSet, args=(), kwargs={}, url_name=studies-list, app_names=[], namespaces=[])
    response
    <Response status_code=201, "application/json">
    self
    <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>
    wrapped_callback
    <function StudyViewSet at 0x7f0587099378>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/template/response.py in render\n \n \n
    \n \n
      \n \n
    1. \n \n
    2.         If the content has already been rendered, this is a no-op.
    3. \n \n
    4. \n \n
    5.         Return the baked response instance.
    6. \n \n
    7.         """
    8. \n \n
    9.         retval = self
    10. \n \n
    11.         if not self._is_rendered:
    12. \n \n
    \n \n
      \n
    1.             self.content = self.rendered_content
      ...
    2. \n
    \n \n
      \n \n
    1.             for post_callback in self._post_render_callbacks:
    2. \n \n
    3.                 newretval = post_callback(retval)
    4. \n \n
    5.                 if newretval is not None:
    6. \n \n
    7.                     retval = newretval
    8. \n \n
    9.         return retval
    10. \n \n
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    retval
    <Response status_code=201, "application/json">
    self
    <Response status_code=201, "application/json">
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/response.py in rendered_content\n \n \n
    \n \n
      \n \n
    1. \n \n
    2.         if content_type is None and charset is not None:
    3. \n \n
    4.             content_type = "{0}; charset={1}".format(media_type, charset)
    5. \n \n
    6.         elif content_type is None:
    7. \n \n
    8.             content_type = media_type
    9. \n \n
    10.         self['Content-Type'] = content_type
    11. \n \n
    12. \n \n
    \n \n
      \n
    1.         ret = renderer.render(self.data, accepted_media_type, context)
      ...
    2. \n
    \n \n
      \n \n
    1.         if isinstance(ret, six.text_type):
    2. \n \n
    3.             assert charset, (
    4. \n \n
    5.                 'renderer returned unicode, and did not specify '
    6. \n \n
    7.                 'a charset value.'
    8. \n \n
    9.             )
    10. \n \n
    11.             return bytes(ret.encode(charset))
    12. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    accepted_media_type
    'application/json'
    charset
    None
    content_type
    'application/json'
    context
    {'args': (),\n               'kwargs': {},\n               'request': <rest_framework.request.Request object at 0x7f0586b87780>,\n               'response': <Response status_code=201, "application/json">,\n               'view': <pkdb_app.studies.views.StudyViewSet object at 0x7f0586b87be0>}
    media_type
    'application/json'
    renderer
    <rest_framework.renderers.JSONRenderer object at 0x7f05870005c0>
    self
    <Response status_code=201, "application/json">
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/renderers.py in render\n \n \n
    \n \n
      \n \n
    1.             separators = SHORT_SEPARATORS if self.compact else LONG_SEPARATORS
    2. \n \n
    3.         else:
    4. \n \n
    5.             separators = INDENT_SEPARATORS
    6. \n \n
    7. \n \n
    8.         ret = json.dumps(
    9. \n \n
    10.             data, cls=self.encoder_class,
    11. \n \n
    12.             indent=indent, ensure_ascii=self.ensure_ascii,
    13. \n \n
    \n \n
      \n
    1.             allow_nan=not self.strict, separators=separators
      ...
    2. \n
    \n \n
      \n \n
    1.         )
    2. \n \n
    3. \n \n
    4.         # On python 2.x json.dumps() returns bytestrings if ensure_ascii=True,
    5. \n \n
    6.         # but if ensure_ascii=False, the return type is underspecified,
    7. \n \n
    8.         # and may (or may not) be unicode.
    9. \n \n
    10.         # On python 3.x json.dumps() returns unicode strings.
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    accepted_media_type
    'application/json'
    data
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    indent
    None
    renderer_context
    {'args': (),\n               'kwargs': {},\n               'request': <rest_framework.request.Request object at 0x7f0586b87780>,\n               'response': <Response status_code=201, "application/json">,\n               'view': <pkdb_app.studies.views.StudyViewSet object at 0x7f0586b87be0>}
    self
    <rest_framework.renderers.JSONRenderer object at 0x7f05870005c0>
    separators
    (',', ':')
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/utils/json.py in dumps\n \n \n
    \n \n
      \n \n
    1.     kwargs.setdefault('allow_nan', False)
    2. \n \n
    3.     return json.dump(*args, **kwargs)
    4. \n \n
    5. \n \n
    6. \n \n
    7. @functools.wraps(json.dumps)
    8. \n \n
    9. def dumps(*args, **kwargs):
    10. \n \n
    11.     kwargs.setdefault('allow_nan', False)
    12. \n \n
    \n \n
      \n
    1.     return json.dumps(*args, **kwargs)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. \n \n
    3. @functools.wraps(json.load)
    4. \n \n
    5. def load(*args, **kwargs):
    6. \n \n
    7.     kwargs.setdefault('parse_constant', strict_constant)
    8. \n \n
    9.     return json.load(*args, **kwargs)
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    args
    ({'comment': None,\n                'description': None,\n                'groups': [OrderedDict([('reference',\n                                         <Reference: Reference object (012087345981)>),\n                                        ('characteristic_values',\n                                         [OrderedDict([('id', 4),\n                                                       ('choice', 'Asian'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'ethnicity'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 3),\n                                                       ('choice', None),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', 62.0),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', 9.0),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', 'kg'),\n                                                       ('category', 'body_weight'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 2),\n                                                       ('choice', 'homo sapiens'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'species'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 1),\n                                                       ('choice', 'M'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'sex'),\n                                                       ('group', 1)])]),\n                                        ('name', 'Seng2009-S_NCNS'),\n                                        ('description',\n                                         '59 healthy adult Asian volunteers were included. '\n                                         'In what follows, a non-caffeine consumer (NCCS) '\n                                         'refers to an individual who consumed beverages\\\n              '\n                                         '(coffee or tea) containing <=200 mg of caffeine '\n                                         'per day, and a regular caffeine consumer to one '\n                                         'who consumed more >200 mg. A cup (150 mL) of '\n                                         'coffee or tea is equivalent to approximately a '\n                                         'caffeine dose... <trimmed 5004 bytes string>
    kwargs
    {'allow_nan': False,\n               'cls': <class 'rest_framework.utils.encoders.JSONEncoder'>,\n               'ensure_ascii': False,\n               'indent': None,\n               'separators': (',', ':')}
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/__init__.py in dumps\n \n \n
    \n \n
      \n \n
    1.         return _default_encoder.encode(obj)
    2. \n \n
    3.     if cls is None:
    4. \n \n
    5.         cls = JSONEncoder
    6. \n \n
    7.     return cls(
    8. \n \n
    9.         skipkeys=skipkeys, ensure_ascii=ensure_ascii,
    10. \n \n
    11.         check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    12. \n \n
    13.         separators=separators, default=default, sort_keys=sort_keys,
    14. \n \n
    \n \n
      \n
    1.         **kw).encode(obj)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. \n \n
    3. _default_decoder = JSONDecoder(object_hook=None, object_pairs_hook=None)
    4. \n \n
    5. \n \n
    6. \n \n
    7. def detect_encoding(b):
    8. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    allow_nan
    False
    check_circular
    True
    cls
    <class 'rest_framework.utils.encoders.JSONEncoder'>
    default
    None
    ensure_ascii
    False
    indent
    None
    kw
    {}
    obj
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    separators
    (',', ':')
    skipkeys
    False
    sort_keys
    False
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in encode\n \n \n
    \n \n
      \n \n
    1.             if self.ensure_ascii:
    2. \n \n
    3.                 return encode_basestring_ascii(o)
    4. \n \n
    5.             else:
    6. \n \n
    7.                 return encode_basestring(o)
    8. \n \n
    9.         # This doesn't pass the iterator directly to ''.join() because the
    10. \n \n
    11.         # exceptions aren't as detailed.  The list call should be roughly
    12. \n \n
    13.         # equivalent to the PySequence_Fast that ''.join() would do.
    14. \n \n
    \n \n
      \n
    1.         chunks = self.iterencode(o, _one_shot=True)
      ...
    2. \n
    \n \n
      \n \n
    1.         if not isinstance(chunks, (list, tuple)):
    2. \n \n
    3.             chunks = list(chunks)
    4. \n \n
    5.         return ''.join(chunks)
    6. \n \n
    7. \n \n
    8.     def iterencode(self, o, _one_shot=False):
    9. \n \n
    10.         """Encode the given object and yield each string
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    o
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in iterencode\n \n \n
    \n \n
      \n \n
    1.                 self.key_separator, self.item_separator, self.sort_keys,
    2. \n \n
    3.                 self.skipkeys, self.allow_nan)
    4. \n \n
    5.         else:
    6. \n \n
    7.             _iterencode = _make_iterencode(
    8. \n \n
    9.                 markers, self.default, _encoder, self.indent, floatstr,
    10. \n \n
    11.                 self.key_separator, self.item_separator, self.sort_keys,
    12. \n \n
    13.                 self.skipkeys, _one_shot)
    14. \n \n
    \n \n
      \n
    1.         return _iterencode(o, 0)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
    3. \n \n
    4.         _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
    5. \n \n
    6.         ## HACK: hand-optimized bytecode; turn globals into locals
    7. \n \n
    8.         ValueError=ValueError,
    9. \n \n
    10.         dict=dict,
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    _encoder
    <built-in function encode_basestring>
    _iterencode
    <_json.Encoder object at 0x7f0586377de0>
    _one_shot
    True
    floatstr
    <function JSONEncoder.iterencode.<locals>.floatstr at 0x7f0586ac9488>
    markers
    {139661702408232: <Reference: Reference object (012087345981)>,\n               139661711021056: OrderedDict([('reference',\n                                              <Reference: Reference object (012087345981)>),\n                                             ('characteristic_values',\n                                              [OrderedDict([('id', 4),\n                                                            ('choice', 'Asian'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'ethnicity'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 3),\n                                                            ('choice', None),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', 62.0),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', 9.0),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', 'kg'),\n                                                            ('category', 'body_weight'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 2),\n                                                            ('choice', 'homo sapiens'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'species'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 1),\n                                                            ('choice', 'M'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'sex'),\n                                                            ('group', 1)])]),\n                                             ('name', 'Seng2009-S_NCNS'),\n                                             ('description',\n                                              '59 healthy adult Asian volunteers were '\n                                              'included. In what follows, a non-caffeine '\n                                              'consumer (NCCS) refers to an individual who '\n                                         ... <trimmed 18057 bytes string>
    o
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/utils/encoders.py in default\n \n \n
    \n \n
      \n \n
    1.         elif hasattr(obj, '__getitem__'):
    2. \n \n
    3.             try:
    4. \n \n
    5.                 return dict(obj)
    6. \n \n
    7.             except Exception:
    8. \n \n
    9.                 pass
    10. \n \n
    11.         elif hasattr(obj, '__iter__'):
    12. \n \n
    13.             return tuple(item for item in obj)
    14. \n \n
    \n \n
      \n
    1.         return super(JSONEncoder, self).default(obj)
      ...
    2. \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    __class__
    <class 'rest_framework.utils.encoders.JSONEncoder'>
    obj
    <Reference: Reference object (012087345981)>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in default\n \n \n
    \n \n
      \n \n
    1.                 else:
    2. \n \n
    3.                     return list(iterable)
    4. \n \n
    5.                 # Let the base class default method raise the TypeError
    6. \n \n
    7.                 return JSONEncoder.default(self, o)
    8. \n \n
    9. \n \n
    10.         """
    11. \n \n
    12.         raise TypeError("Object of type '%s' is not JSON serializable" %
    13. \n \n
    \n \n
      \n
    1.                         o.__class__.__name__)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2.     def encode(self, o):
    3. \n \n
    4.         """Return a JSON string representation of a Python data structure.
    5. \n \n
    6. \n \n
    7.         >>> from json.encoder import JSONEncoder
    8. \n \n
    9.         >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    o
    <Reference: Reference object (012087345981)>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n
\n
\n
\n \n
\n \n \n \n \n \n

\n \n
\n
\n
\n \n \n \n
\n

Request information

\n \n \n \n

USER

\n

AnonymousUser

\n \n \n

GET

\n \n

No GET data

\n \n \n

POST

\n \n

No POST data

\n \n

FILES

\n \n

No FILES data

\n \n \n \n

COOKIES

\n \n

No cookie data

\n \n \n

META

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
VariableValue
CONTENT_LENGTH
'1292'
CONTENT_TYPE
'application/json'
DJANGO_CONFIGURATION
'Local'
DJANGO_SECRET_KEY
'local'
DJANGO_SETTINGS_MODULE
'pkdb_app.config'
GATEWAY_INTERFACE
'CGI/1.1'
GPG_KEY
'0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D'
HOME
'/root'
HOSTNAME
'83fb6011203b'
HTTP_ACCEPT
'application/coreapi+json, application/vnd.coreapi+json, */*'
HTTP_ACCEPT_ENCODING
'gzip, deflate'
HTTP_CONNECTION
'keep-alive'
HTTP_HOST
'0.0.0.0:8000'
HTTP_USER_AGENT
'coreapi'
LANG
'C.UTF-8'
PATH
'/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PATH_INFO
'/api/v1/studies/'
PWD
'/code'
PYTHONUNBUFFERED
'1'
PYTHON_PIP_VERSION
'10.0.1'
PYTHON_VERSION
'3.6.6'
QUERY_STRING
''
REMOTE_ADDR
'172.22.0.1'
REMOTE_HOST
''
REQUEST_METHOD
'POST'
RUN_MAIN
'true'
SCRIPT_NAME
''
SERVER_NAME
'83fb6011203b'
SERVER_PORT
'8000'
SERVER_PROTOCOL
'HTTP/1.1'
SERVER_SOFTWARE
'WSGIServer/0.2'
SHLVL
'1'
TZ
'UTC'
_
'./manage.py'
wsgi.errors
<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
wsgi.file_wrapper
''
wsgi.input
<_io.BufferedReader name=5>
wsgi.multiprocess
False
wsgi.multithread
True
wsgi.run_once
False
wsgi.url_scheme
'http'
wsgi.version
(1, 0)
\n \n \n

Settings

\n

Using settings module pkdb_app.config

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
SettingValue
ABSOLUTE_URL_OVERRIDES
{}
ADMINS
(('Author', 'janekg89@hotmail.de'),)
ALLOWED_HOSTS
['*']
APPEND_SLASH
False
AUTHENTICATION_BACKENDS
['django.contrib.auth.backends.ModelBackend']
AUTH_PASSWORD_VALIDATORS
'********************'
AUTH_USER_MODEL
'users.User'
CACHES
{'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
CACHE_MIDDLEWARE_ALIAS
'default'
CACHE_MIDDLEWARE_KEY_PREFIX
'********************'
CACHE_MIDDLEWARE_SECONDS
600
CONFIGURATION
'pkdb_app.config.Local'
CSRF_COOKIE_AGE
31449600
CSRF_COOKIE_DOMAIN
None
CSRF_COOKIE_HTTPONLY
False
CSRF_COOKIE_NAME
'csrftoken'
CSRF_COOKIE_PATH
'/'
CSRF_COOKIE_SECURE
False
CSRF_FAILURE_VIEW
'django.views.csrf.csrf_failure'
CSRF_HEADER_NAME
'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS
[]
CSRF_USE_SESSIONS
False
DATABASES
{'default': {'ATOMIC_REQUESTS': False,\n                           'AUTOCOMMIT': True,\n                           'CONN_MAX_AGE': 600,\n                           'ENGINE': 'django.db.backends.postgresql_psycopg2',\n                           'HOST': 'postgres',\n                           'NAME': 'postgres',\n                           'OPTIONS': {},\n                           'PASSWORD': '********************',\n                           'PORT': 5432,\n                           'TEST': {'CHARSET': None,\n                                    'COLLATION': None,\n                                    'MIRROR': None,\n                                    'NAME': None},\n                           'TIME_ZONE': None,\n                           'USER': 'postgres'}}
DATABASE_ROUTERS
[]
DATA_UPLOAD_MAX_MEMORY_SIZE
2621440
DATA_UPLOAD_MAX_NUMBER_FIELDS
1000
DATETIME_FORMAT
'N j, Y, P'
DATETIME_INPUT_FORMATS
['%Y-%m-%d %H:%M:%S',\n               '%Y-%m-%d %H:%M:%S.%f',\n               '%Y-%m-%d %H:%M',\n               '%Y-%m-%d',\n               '%m/%d/%Y %H:%M:%S',\n               '%m/%d/%Y %H:%M:%S.%f',\n               '%m/%d/%Y %H:%M',\n               '%m/%d/%Y',\n               '%m/%d/%y %H:%M:%S',\n               '%m/%d/%y %H:%M:%S.%f',\n               '%m/%d/%y %H:%M',\n               '%m/%d/%y']
DATE_FORMAT
'N j, Y'
DATE_INPUT_FORMATS
['%Y-%m-%d',\n               '%m/%d/%Y',\n               '%m/%d/%y',\n               '%b %d %Y',\n               '%b %d, %Y',\n               '%d %b %Y',\n               '%d %b, %Y',\n               '%B %d %Y',\n               '%B %d, %Y',\n               '%d %B %Y',\n               '%d %B, %Y']
DEBUG
True
DEBUG_PROPAGATE_EXCEPTIONS
False
DECIMAL_SEPARATOR
'.'
DEFAULT_CHARSET
'utf-8'
DEFAULT_CONTENT_TYPE
'text/html'
DEFAULT_EXCEPTION_REPORTER_FILTER
'django.views.debug.SafeExceptionReporterFilter'
DEFAULT_FILE_STORAGE
'django.core.files.storage.FileSystemStorage'
DEFAULT_FROM_EMAIL
'webmaster@localhost'
DEFAULT_INDEX_TABLESPACE
''
DEFAULT_TABLESPACE
''
DISALLOWED_USER_AGENTS
[]
DOTENV_LOADED
None
EMAIL_BACKEND
'django.core.mail.backends.console.EmailBackend'
EMAIL_HOST
'localhost'
EMAIL_HOST_PASSWORD
'********************'
EMAIL_HOST_USER
''
EMAIL_PORT
1025
EMAIL_SSL_CERTFILE
None
EMAIL_SSL_KEYFILE
'********************'
EMAIL_SUBJECT_PREFIX
'[Django] '
EMAIL_TIMEOUT
None
EMAIL_USE_LOCALTIME
False
EMAIL_USE_SSL
False
EMAIL_USE_TLS
False
FILE_CHARSET
'utf-8'
FILE_UPLOAD_DIRECTORY_PERMISSIONS
None
FILE_UPLOAD_HANDLERS
['django.core.files.uploadhandler.MemoryFileUploadHandler',\n               'django.core.files.uploadhandler.TemporaryFileUploadHandler']
FILE_UPLOAD_MAX_MEMORY_SIZE
2621440
FILE_UPLOAD_PERMISSIONS
None
FILE_UPLOAD_TEMP_DIR
None
FIRST_DAY_OF_WEEK
0
FIXTURE_DIRS
[]
FORCE_SCRIPT_NAME
None
FORMAT_MODULE_PATH
None
FORM_RENDERER
'django.forms.renderers.DjangoTemplates'
IGNORABLE_404_URLS
[]
INSTALLED_APPS
('django.contrib.admin',\n               'django.contrib.auth',\n               'django.contrib.contenttypes',\n               'django.contrib.sessions',\n               'django.contrib.messages',\n               'django.contrib.staticfiles',\n               'rest_framework',\n               'rest_framework.authtoken',\n               'django_filters',\n               'rest_framework_swagger',\n               'pkdb_app.users',\n               'pkdb_app.studies',\n               'pkdb_app.subjects',\n               'pkdb_app.interventions',\n               'django_nose')
INTERNAL_IPS
[]
LANGUAGES
[('af', 'Afrikaans'),\n               ('ar', 'Arabic'),\n               ('ast', 'Asturian'),\n               ('az', 'Azerbaijani'),\n               ('bg', 'Bulgarian'),\n               ('be', 'Belarusian'),\n               ('bn', 'Bengali'),\n               ('br', 'Breton'),\n               ('bs', 'Bosnian'),\n               ('ca', 'Catalan'),\n               ('cs', 'Czech'),\n               ('cy', 'Welsh'),\n               ('da', 'Danish'),\n               ('de', 'German'),\n               ('dsb', 'Lower Sorbian'),\n               ('el', 'Greek'),\n               ('en', 'English'),\n               ('en-au', 'Australian English'),\n               ('en-gb', 'British English'),\n               ('eo', 'Esperanto'),\n               ('es', 'Spanish'),\n               ('es-ar', 'Argentinian Spanish'),\n               ('es-co', 'Colombian Spanish'),\n               ('es-mx', 'Mexican Spanish'),\n               ('es-ni', 'Nicaraguan Spanish'),\n               ('es-ve', 'Venezuelan Spanish'),\n               ('et', 'Estonian'),\n               ('eu', 'Basque'),\n               ('fa', 'Persian'),\n               ('fi', 'Finnish'),\n               ('fr', 'French'),\n               ('fy', 'Frisian'),\n               ('ga', 'Irish'),\n               ('gd', 'Scottish Gaelic'),\n               ('gl', 'Galician'),\n               ('he', 'Hebrew'),\n               ('hi', 'Hindi'),\n               ('hr', 'Croatian'),\n               ('hsb', 'Upper Sorbian'),\n               ('hu', 'Hungarian'),\n               ('ia', 'Interlingua'),\n               ('id', 'Indonesian'),\n               ('io', 'Ido'),\n               ('is', 'Icelandic'),\n               ('it', 'Italian'),\n               ('ja', 'Japanese'),\n               ('ka', 'Georgian'),\n               ('kab', 'Kabyle'),\n               ('kk', 'Kazakh'),\n               ('km', 'Khmer'),\n               ('kn', 'Kannada'),\n               ('ko', 'Korean'),\n               ('lb', 'Luxembourgish'),\n               ('lt', 'Lithuanian'),\n               ('lv', 'Latvian'),\n               ('mk', 'Macedonian'),\n               ('ml', 'Malayalam'),\n               ('mn', 'Mongolian'),\n               ('mr', 'Marathi'),\n               ('my', 'Burmese'),\n               ('nb', 'Norwegian Bokm\\u00e5l'),\n               ('ne', 'Nepali'),\n               ('nl', 'Dutch'),\n               ('nn', 'Norwegian Nynorsk'),\n               ('os', 'Ossetic'),\n               ('pa', 'Punjabi'),\n               ('pl', 'Polish'),\n               ('pt', 'Portuguese'),\n               ('pt-br', 'Brazilian Portuguese'),\n               ('ro', 'Romanian'),\n               ('ru', 'Russian'),\n               ('sk', 'Slovak'),\n               ('sl', 'Slovenian'),\n               ('sq', 'Albanian'),\n               ('sr', 'Serbian'),\n               ('sr-latn', 'Serbian Latin'),\n               ('sv', 'Swedish'),\n               ('sw', 'Swahili'),\n               ('ta', 'Tamil'),\n               ('te', 'Telugu'),\n               ('th', 'Thai'),\n               ('tr', 'Turkish'),\n               ('tt', 'Tatar'),\n               ('udm', 'Udmurt'),\n               ('uk', 'Ukrainian'),\n               ('ur', 'Urdu'),\n               ('vi', 'Vietnamese'),\n               ('zh-hans', 'Simplified Chinese'),\n               ('zh-hant', 'Traditional Chinese')]
LANGUAGES_BIDI
['he', 'ar', 'fa', 'ur']
LANGUAGE_CODE
'en-us'
LANGUAGE_COOKIE_AGE
None
LANGUAGE_COOKIE_DOMAIN
None
LANGUAGE_COOKIE_NAME
'django_language'
LANGUAGE_COOKIE_PATH
'/'
LOCALE_PATHS
[]
LOGGING
{'disable_existing_loggers': False,\n               'filters': {'require_debug_true': {'()': 'django.utils.log.RequireDebugTrue'}},\n               'formatters': {'django.server': {'()': 'django.utils.log.ServerFormatter',\n                                                'format': '[%(server_time)s] %(message)s'},\n                              'simple': {'format': '%(levelname)s %(message)s'},\n                              'verbose': {'format': '%(levelname)s %(asctime)s %(module)s '\n                                                    '%(process)d %(thread)d %(message)s'}},\n               'handlers': {'console': {'class': 'logging.StreamHandler',\n                                        'formatter': 'simple',\n                                        'level': 'DEBUG'},\n                            'django.server': {'class': 'logging.StreamHandler',\n                                              'formatter': 'django.server',\n                                              'level': 'INFO'},\n                            'mail_admins': {'class': 'django.utils.log.AdminEmailHandler',\n                                            'level': 'ERROR'}},\n               'loggers': {'django': {'handlers': ['console'], 'propagate': True},\n                           'django.db.backends': {'handlers': ['console'], 'level': 'INFO'},\n                           'django.request': {'handlers': ['mail_admins', 'console'],\n                                              'level': 'ERROR',\n                                              'propagate': False},\n                           'django.server': {'handlers': ['django.server'],\n                                             'level': 'INFO',\n                                             'propagate': False}},\n               'version': 1}
LOGGING_CONFIG
'logging.config.dictConfig'
LOGIN_REDIRECT_URL
'/'
LOGIN_URL
'rest_framework:login'
LOGOUT_REDIRECT_URL
None
LOGOUT_URL
'rest_framework:logout'
MANAGERS
[]
MEDIA_ROOT
'/code/media'
MEDIA_URL
'/media/'
MESSAGE_STORAGE
'django.contrib.messages.storage.fallback.FallbackStorage'
MIDDLEWARE
('django.middleware.security.SecurityMiddleware',\n               'django.contrib.sessions.middleware.SessionMiddleware',\n               'django.middleware.common.CommonMiddleware',\n               'django.middleware.csrf.CsrfViewMiddleware',\n               'django.contrib.auth.middleware.AuthenticationMiddleware',\n               'django.contrib.messages.middleware.MessageMiddleware',\n               'django.middleware.clickjacking.XFrameOptionsMiddleware')
MIGRATION_MODULES
{}
MONTH_DAY_FORMAT
'F j'
NOSE_ARGS
['/code/pkdb_app',\n               '-s',\n               '--nologcapture',\n               '--with-coverage',\n               '--with-progressive',\n               '--cover-package=pkdb']
NUMBER_GROUPING
0
PASSWORD_HASHERS
'********************'
PASSWORD_RESET_TIMEOUT_DAYS
'********************'
PREPEND_WWW
False
REST_FRAMEWORK
{'DATETIME_FORMAT': '%Y-%m-%dT%H:%M:%S%z',\n               'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.SessionAuthentication',),\n               'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),\n               'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',\n               'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'],\n               'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer',\n                                            'rest_framework.renderers.BrowsableAPIRenderer'),\n               'PAGE_SIZE': 10}
ROOT_URLCONF
'pkdb_app.urls'
SECRET_KEY
'********************'
SECURE_BROWSER_XSS_FILTER
False
SECURE_CONTENT_TYPE_NOSNIFF
False
SECURE_HSTS_INCLUDE_SUBDOMAINS
False
SECURE_HSTS_PRELOAD
False
SECURE_HSTS_SECONDS
0
SECURE_PROXY_SSL_HEADER
None
SECURE_REDIRECT_EXEMPT
[]
SECURE_SSL_HOST
None
SECURE_SSL_REDIRECT
False
SERVER_EMAIL
'root@localhost'
SESSION_CACHE_ALIAS
'default'
SESSION_COOKIE_AGE
1209600
SESSION_COOKIE_DOMAIN
None
SESSION_COOKIE_HTTPONLY
True
SESSION_COOKIE_NAME
'sessionid'
SESSION_COOKIE_PATH
'/'
SESSION_COOKIE_SECURE
False
SESSION_ENGINE
'django.contrib.sessions.backends.db'
SESSION_EXPIRE_AT_BROWSER_CLOSE
False
SESSION_FILE_PATH
None
SESSION_SAVE_EVERY_REQUEST
False
SESSION_SERIALIZER
'django.contrib.sessions.serializers.JSONSerializer'
SETTINGS_MODULE
'pkdb_app.config'
SHORT_DATETIME_FORMAT
'm/d/Y P'
SHORT_DATE_FORMAT
'm/d/Y'
SIGNING_BACKEND
'django.core.signing.TimestampSigner'
SILENCED_SYSTEM_CHECKS
[]
STATICFILES_DIRS
[]
STATICFILES_FINDERS
('django.contrib.staticfiles.finders.FileSystemFinder',\n               'django.contrib.staticfiles.finders.AppDirectoriesFinder')
STATICFILES_STORAGE
'django.contrib.staticfiles.storage.StaticFilesStorage'
STATIC_ROOT
'/code/static'
STATIC_URL
'/static/'
SWAGGER_SETTINGS
{'APIS_SORTER': '********************',\n               'DOC_EXPANSION': 'list',\n               'LOGIN_URL': 'rest_framework:login',\n               'LOGOUT_URL': 'rest_framework:logout',\n               'SECURITY_DEFINITIONS': {'basic': {'type': 'basic'}},\n               'USE_SESSION_AUTH': True}
TEMPLATES
[{'APP_DIRS': True,\n                'BACKEND': 'django.template.backends.django.DjangoTemplates',\n                'DIRS': [],\n                'OPTIONS': {'context_processors': ['django.template.context_processors.debug',\n                                                   'django.template.context_processors.request',\n                                                   'django.contrib.auth.context_processors.auth',\n                                                   'django.contrib.messages.context_processors.messages']}}]
TEST_NON_SERIALIZED_APPS
[]
TEST_RUNNER
'django_nose.NoseTestSuiteRunner'
THOUSAND_SEPARATOR
','
TIME_FORMAT
'P'
TIME_INPUT_FORMATS
['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
TIME_ZONE
'UTC'
USE_ETAGS
False
USE_I18N
False
USE_L10N
True
USE_THOUSAND_SEPARATOR
False
USE_TZ
True
USE_X_FORWARDED_HOST
False
USE_X_FORWARDED_PORT
False
WSGI_APPLICATION
'pkdb_app.wsgi.application'
X_FRAME_OPTIONS
'SAMEORIGIN'
YEAR_MONTH_FORMAT
'F Y'
\n \n
\n \n
\n

\n You're seeing this error because you have DEBUG = True in your\n Django settings file. Change that to False, and Django will\n display a standard page generated by the handler for this status code.\n

\n
\n \n \n \n \"" ] } ], @@ -461,7 +444,117 @@ }, { "cell_type": "code", - "execution_count": 116, + "execution_count": 495, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "OrderedDict([('characteristic_values',\n", + " [OrderedDict([('id', 24),\n", + " ('choice', 'Asian'),\n", + " ('count', 14),\n", + " ('value', None),\n", + " ('mean', None),\n", + " ('median', None),\n", + " ('min', None),\n", + " ('max', None),\n", + " ('sd', None),\n", + " ('se', None),\n", + " ('cv', None),\n", + " ('unit', None),\n", + " ('category', 'ethnicity'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 23),\n", + " ('choice', None),\n", + " ('count', 14),\n", + " ('value', None),\n", + " ('mean', 62.0),\n", + " ('median', None),\n", + " ('min', None),\n", + " ('max', None),\n", + " ('sd', 9.0),\n", + " ('se', None),\n", + " ('cv', None),\n", + " ('unit', 'kg'),\n", + " ('category', 'body_weight'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 22),\n", + " ('choice', 'homo sapiens'),\n", + " ('count', 14),\n", + " ('value', None),\n", + " ('mean', None),\n", + " ('median', None),\n", + " ('min', None),\n", + " ('max', None),\n", + " ('sd', None),\n", + " ('se', None),\n", + " ('cv', None),\n", + " ('unit', None),\n", + " ('category', 'species'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 21),\n", + " ('choice', 'M'),\n", + " ('count', 14),\n", + " ('value', None),\n", + " ('mean', None),\n", + " ('median', None),\n", + " ('min', None),\n", + " ('max', None),\n", + " ('sd', None),\n", + " ('se', None),\n", + " ('cv', None),\n", + " ('unit', None),\n", + " ('category', 'sex'),\n", + " ('group', 3)])]),\n", + " ('name', 'Seng2009-S_NCNSlalsöd'),\n", + " ('description',\n", + " '59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean ± SD) 21 ± 2 years, body weight 62 ± 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 ± 4 years, body weight 69 ± 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 ± 4 cigarettes daily, age 23 ± 5 years, body weight 71 ± 19 kg).'),\n", + " ('count', 14)])" + ] + }, + "execution_count": 495, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "group_dict = {\n", + " \"count\": 14,\n", + " \"name\": \"Seng2009-S_NCNSlalsöd\",\n", + " \"description\": \"59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean \\u00b1 SD) 21 \\u00b1 2 years, body weight 62 \\u00b1 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 \\u00b1 4 years, body weight 69 \\u00b1 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 \\u00b1 4 cigarettes daily, age 23 \\u00b1 5 years, body weight 71 \\u00b1 19 kg).\",\n", + " \"characteristic_values\": [\n", + " {\n", + " \"count\": 14,\n", + " \"category\": \"sex\",\n", + " \"choice\": \"M\"\n", + " },\n", + " {\n", + " \"count\": 14,\n", + " \"category\": \"species\",\n", + " \"choice\": \"homo sapiens\"\n", + " },\n", + " {\n", + " \"category\": \"body_weight\",\n", + " \"count\": 14,\n", + " \"mean\": 62.0,\n", + " \"sd\": 9.0,\n", + " \"unit\": \"kg\"\n", + " },\n", + " {\n", + " \"count\": 14,\n", + " \"category\": \"ethnicity\",\n", + " \"choice\": \"Asian\"\n", + " },\n", + " \n", + " ]\n", + " }\n", + "client.action(document, [\"groups\", \"create\"], params=group_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 359, "metadata": { "collapsed": true }, @@ -474,45 +567,9 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "OrderedDict([('count', 2),\n", - " ('next', None),\n", - " ('previous', None),\n", - " ('results',\n", - " [OrderedDict([('pmid', '12087345'),\n", - " ('sid', 'Haller2002'),\n", - " ('doi', ''),\n", - " ('title',\n", - " 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.'),\n", - " ('abstract', 'Botanical stimgle dose.'),\n", - " ('journal',\n", - " 'Clinical pharmacology and therapeutics'),\n", - " ('date', '2002-07-16'),\n", - " ('authors', []),\n", - " ('pdf', None)]),\n", - " OrderedDict([('pmid', '12087345'),\n", - " ('sid', '12087345'),\n", - " ('doi', ''),\n", - " ('title',\n", - " 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.'),\n", - " ('abstract', 'Botanical stimgle dose.'),\n", - " ('journal',\n", - " 'Clinical pharmacology and therapeutics'),\n", - " ('date', '2002-07-16'),\n", - " ('authors', []),\n", - " ('pdf', None)])])])" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "client.action(document, [\"references\", \"list\"])" ] diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py new file mode 100644 index 00000000..90fb00b0 --- /dev/null +++ b/pkdb_app/serializers.py @@ -0,0 +1,34 @@ +from rest_framework import serializers +from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned +from collections import OrderedDict + + +class BaseSerializer(serializers.ModelSerializer): + """ + This Serializer is overwriting a the is_valid method. If sid allready exisits. It adds a instance to the class. + This triggers the update method instead of the create method of the serializer. + """ + + def is_valid(self, raise_exception=False): + if "sid" in self.initial_data.keys(): + sid = self.initial_data.get("sid") + try: + # Try to get the object in question + obj = self.Meta.model.objects.get(sid = sid) + except (ObjectDoesNotExist, MultipleObjectsReturned): + # Except not finding the object or the data being ambiguous + # for defining it. Then validate the data as usual + return super().is_valid(raise_exception) + else: + # If the object is found add it to the serializer. Then + # validate the data as usual + self.instance = obj + return super().is_valid(raise_exception) + else: + # If the Serializer was instantiated with just an object, and no + # data={something} proceed as usual + return super().is_valid(raise_exception) + + def to_representation(self, instance): + result = super().to_representation(instance) + return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) \ No newline at end of file diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 2a4ae5eb..c6e377d2 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -27,14 +27,15 @@ class KeyWord(models.Model): name = models.CharField(max_length=CHAR_MAX_LENGTH) -class Reference( models.Model): +class Reference(models.Model): """ This is the main class describing the publication or reference which describes the study. In most cases this is a published paper, but could be a thesis or unpublished. """ pmid = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) #optional - sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key = True, default=pmid) + sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key=True, default=pmid) + name = models.CharField(max_length=CHAR_MAX_LENGTH) doi = models.CharField(max_length=150, null=True, blank=True) #optional title = models.TextField() abstract = models.TextField(blank=True, null=True) @@ -46,13 +47,17 @@ class Reference( models.Model): + + class Study(Sidable, Commentable, Describable, models.Model): """ Single clinical study. Mainly reported as a single publication. """ - reference = models.ForeignKey(Reference, on_delete=True, related_name='studies', null=True, blank=True) + reference = models.ForeignKey(Reference, on_delete=True, to_field="sid",db_column="reference_sid", related_name='studies', null=True, blank=True) + name = models.CharField(max_length=CHAR_MAX_LENGTH) + #todo:study design, observational sudy ... diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 011b9969..72562c14 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -1,11 +1,17 @@ from rest_framework import serializers + +from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned + from .models import Reference, Author, Study from ..subjects.serializers import GroupSerializer from ..subjects.models import Group +from ..serializers import BaseSerializer +from django.shortcuts import get_object_or_404 BASE_FIELDS = () + class AuthorSerializer(serializers.ModelSerializer): id = serializers.ReadOnlyField() @@ -18,40 +24,68 @@ def create(self, validated_data): return author -class ReferenceSerializer(serializers.ModelSerializer): +class ReferenceSerializer(BaseSerializer): authors = AuthorSerializer(many=True, read_only=False)#, queryset=Study.objects.all(), source='studies') class Meta: model = Reference - fields = BASE_FIELDS + ('pmid','sid', 'doi', 'title','abstract','journal', 'date', 'authors', 'pdf') - + fields = BASE_FIELDS + ('pmid', 'sid', 'name', 'doi', 'title','abstract','journal', 'date', 'authors', 'pdf') def create(self, validated_data): - authors_data = validated_data.pop('authors', []) - reference, _ = Reference.objects.update_or_create(sid=validated_data["pmid"], defaults=validated_data) + + authors_data = validated_data.pop('authors',[]) + reference = Reference.objects.create(**validated_data) for author_data in authors_data: author, _ = Author.objects.update_or_create(**author_data) reference.authors.add(author) reference.save() + return reference + def update(self, instance, validated_data): + authors_data = validated_data.pop('authors',[]) + + for name, value in validated_data.items(): + setattr(instance, name, value) + + for author_data in authors_data: + author, _ = Author.objects.update_or_create(**author_data) + instance.authors.add(author) + instance.save() + return instance -class StudySerializer(serializers.ModelSerializer): + +class StudySerializer(BaseSerializer): + #reference = ReferenceSerializer(read_only=False) reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all()) groups = GroupSerializer(many=True, read_only=False) - class Meta: model = Study - fields = BASE_FIELDS + ('sid','comment','description', 'groups', 'reference') + fields = BASE_FIELDS + ('sid','comment','name','description', 'groups', 'reference') def create(self, validated_data): groups_data = validated_data.pop('groups', []) - study, _ = Study.objects.update_or_create(sid=validated_data["sid"], defaults=validated_data) + reference = validated_data.pop('reference') + + study, _ = Study.objects.update_or_create(sid=validated_data["sid"], reference=reference, defaults=validated_data,) for group in groups_data: - Group.objects.update_or_create(sid=group["sid"], study=study, defaults=group) + Group.objects.update_or_create(name=group["name"], study=study, defaults=group) + + study.save() + return study + + def update(self, instance, validated_data): + groups_data = validated_data.pop('groups', []) + for name, value in validated_data.items(): + setattr(instance, name, value) + + for group in groups_data: + Group.objects.update_or_create(name=group["name"], study=instance, defaults=group) + + return instance diff --git a/pkdb_app/studies/views.py b/pkdb_app/studies/views.py index fef86431..b7e08c6b 100644 --- a/pkdb_app/studies/views.py +++ b/pkdb_app/studies/views.py @@ -19,7 +19,9 @@ class ReferencesViewSet(viewsets.ModelViewSet): queryset = Reference.objects.all() serializer_class = ReferenceSerializer filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) - filter_fields = ( 'pmid', 'doi','title', 'abstract', 'journal','date', 'authors') + filter_fields = ('sid',) + + #filter_fields = ( 'pmid', 'doi','title', 'abstract', 'journal','date', 'authors') search_fields = filter_fields @@ -31,6 +33,8 @@ class StudyViewSet(viewsets.ModelViewSet): search_fields = filter_fields + + #class InterventionsViewSet(viewsets.ModelViewSet): # queryset = Intervention.objects.all() diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 6e579444..8ecd34a1 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -14,3 +14,4 @@ def update_or_create(self, *args, **kwargs): group.save() + return group, created diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index e4e3f315..89eea4d7 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -30,12 +30,13 @@ # Idea: GroupSet -class Group(Sidable, Describable, models.Model): +class Group(Describable, models.Model): """ Individual or group of people. Groups are defined via their characteristics. """ - study = models.ForeignKey(Study, on_delete=True, related_name='groups', null=True, blank=True) + name = models.CharField(max_length=CHAR_MAX_LENGTH) + study = models.ForeignKey(Study, on_delete=True, related_name='groups',to_field="sid", db_column="study_sid",null=True, blank=True) count = models.IntegerField() # number of people/animals/objects in group objects = GroupManager() diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index ee578ce6..e12a5166 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,7 +1,9 @@ from rest_framework import serializers from .models import Group, CharacteristicValue - +from ..studies.models import Reference +from ..serializers import BaseSerializer BASE_FIELDS = () +from collections import OrderedDict class CharacteristicValueSerializer(serializers.ModelSerializer): @@ -10,10 +12,23 @@ class Meta: model = CharacteristicValue fields = "__all__" + def to_representation(self, instance): + result = super().to_representation(instance) + return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + class GroupSerializer(serializers.ModelSerializer): - characteristic_values = CharacteristicValueSerializer(many=True,read_only=False) + characteristic_values = CharacteristicValueSerializer(many=True, read_only=False) class Meta: model = Group - fields = BASE_FIELDS + ('reference','characteristic_values','sid','description','count',) + fields = BASE_FIELDS + ( 'characteristic_values', 'name', 'description', 'count',) + + def create(self, validated_data): + group , _ = Group.objects.update_or_create(name=validated_data["name"], defaults=validated_data) + return group + + def to_representation(self, instance): + result = super().to_representation(instance) + return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + diff --git a/pkdb_app/subjects/views.py b/pkdb_app/subjects/views.py index 15e03f95..2f111176 100644 --- a/pkdb_app/subjects/views.py +++ b/pkdb_app/subjects/views.py @@ -10,7 +10,7 @@ class GroupsViewSet(viewsets.ModelViewSet): queryset = Group.objects.all() serializer_class = GroupSerializer filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) - filter_fields = ('description', 'sid') + filter_fields = ('description',) search_fields = filter_fields From 771e4b0b850846a18b464863fa4dadcd3a86b78b Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Jul 2018 14:11:07 +0200 Subject: [PATCH 019/115] new working data model for studies and refrences no pharmacokinetical data. --- docs/api/api.ipynb | 225 +++++++++++++++++- .../{create_master.py => create_reference.py} | 54 ++++- .../{create_subjects.py => create_study.py} | 70 +++--- pkdb_app/data_management/fill_database.py | 36 ++- pkdb_app/subjects/managers.py | 1 + pkdb_app/subjects/serializers.py | 8 + 6 files changed, 337 insertions(+), 57 deletions(-) rename pkdb_app/data_management/{create_master.py => create_reference.py} (75%) rename pkdb_app/data_management/{create_subjects.py => create_study.py} (68%) diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index 685e4df1..25d09d80 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -372,7 +372,7 @@ }, { "cell_type": "code", - "execution_count": 513, + "execution_count": 517, "metadata": {}, "outputs": [], "source": [ @@ -421,21 +421,220 @@ }, { "cell_type": "code", - "execution_count": 514, + "execution_count": 533, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "study_dict = {\n", + " \"sid\": 16198659,\n", + " \"name\": \"Granfors2005\",\n", + " \"reference\": 16198659,\n", + " \"groups\": [\n", + " {\n", + " \"count\": 15,\n", + " \"name\": \"Granfors2005-S1\",\n", + " \"description\": \"This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.\",\n", + " \"characteristic_values\": [\n", + " {\n", + " \"category\": \"sex\",\n", + " \"choice\": \"F\"\n", + " },\n", + " {\n", + " \"category\": \"oral_contraceptives\",\n", + " \"choice\": \"N\"\n", + " },\n", + " {\n", + " \"category\": \"species\",\n", + " \"choice\": \"homo sapiens\"\n", + " },\n", + " {\n", + " \"category\": \"body_weight\",\n", + " \"mean\": 62.0,\n", + " \"min\": 52.0,\n", + " \"max\": 74.0,\n", + " \"sd\": 10.0,\n", + " \"unit\": \"kg\"\n", + " },\n", + " {\n", + " \"category\": \"smoking\",\n", + " \"choice\": \"N\"\n", + " },\n", + " {\n", + " \"category\": \"healthy\",\n", + " \"choice\": \"Y\"\n", + " },\n", + " {\n", + " \"category\": \"age\",\n", + " \"mean\": 22.0,\n", + " \"min\": 19.0,\n", + " \"max\": 26.0,\n", + " \"sd\": 2.0,\n", + " \"unit\": \"yr\"\n", + " }\n", + " ]\n", + " },\n", + " {\n", + " \"count\": 15,\n", + " \"name\": \"Granfors2005-S2\",\n", + " \"description\": \"This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.\",\n", + " \"characteristic_values\": [\n", + " {\n", + " \"category\": \"sex\",\n", + " \"choice\": \"F\"\n", + " },\n", + " {\n", + " \"category\": \"oral_contraceptives\",\n", + " \"choice\": \"Y\"\n", + " },\n", + " {\n", + " \"category\": \"species\",\n", + " \"choice\": \"homo sapiens\"\n", + " },\n", + " {\n", + " \"category\": \"body_weight\",\n", + " \"mean\": 57.0,\n", + " \"min\": 48.0,\n", + " \"max\": 63.0,\n", + " \"sd\": 6.0,\n", + " \"unit\": \"kg\"\n", + " },\n", + " {\n", + " \"category\": \"smoking\",\n", + " \"choice\": \"N\"\n", + " },\n", + " {\n", + " \"category\": \"healthy\",\n", + " \"choice\": \"Y\"\n", + " },\n", + " {\n", + " \"category\": \"age\",\n", + " \"mean\": 22.0,\n", + " \"min\": 18.0,\n", + " \"max\": 25.0,\n", + " \"sd\": 2.0,\n", + " \"unit\": \"yr\"\n", + " }\n", + " ]\n", + " }\n", + " ]\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 534, "metadata": {}, "outputs": [ { - "ename": "ErrorMessage", - "evalue": "\n message: \"\n \n \n \n \n TypeError\n at /api/v1/studies/\n \n \n \n \n \n \n
\n

TypeError\n at /api/v1/studies/

\n
Object of type 'Reference' is not JSON serializable
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Request Method:POST
Request URL:http://0.0.0.0:8000/api/v1/studies/
Django Version:2.0.6
Exception Type:TypeError
Exception Value:
Object of type 'Reference' is not JSON serializable
Exception Location:/usr/local/lib/python3.6/json/encoder.py in default, line 180
Python Executable:/usr/local/bin/python
Python Version:3.6.6
Python Path:
['/code',\n               '/usr/local/lib/python36.zip',\n               '/usr/local/lib/python3.6',\n               '/usr/local/lib/python3.6/lib-dynload',\n               '/usr/local/lib/python3.6/site-packages']
Server time:Mon, 23 Jul 2018 16:28:03 +0000
\n
\n \n \n \n \n
\n

Traceback \n Switch to copy-and-paste view\n

\n
\n
    \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py in inner\n \n \n
    \n \n
      \n \n
    1.     This decorator is automatically applied to all middleware to ensure that
    2. \n \n
    3.     no middleware leaks an exception and that the next middleware in the stack
    4. \n \n
    5.     can rely on getting a response instead of an exception.
    6. \n \n
    7.     """
    8. \n \n
    9.     @wraps(get_response)
    10. \n \n
    11.     def inner(request):
    12. \n \n
    13.         try:
    14. \n \n
    \n \n
      \n
    1.             response = get_response(request)
      ...
    2. \n
    \n \n
      \n \n
    1.         except Exception as exc:
    2. \n \n
    3.             response = response_for_exception(request, exc)
    4. \n \n
    5.         return response
    6. \n \n
    7.     return inner
    8. \n \n
    9. \n \n
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    exc
    TypeError("Object of type 'Reference' is not JSON serializable",)
    get_response
    <bound method BaseHandler._get_response of <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response\n \n \n
    \n \n
      \n \n
    1.                         "HttpResponse object. It returned None instead."
    2. \n \n
    3.                         % (middleware_method.__self__.__class__.__name__)
    4. \n \n
    5.                     )
    6. \n \n
    7. \n \n
    8.             try:
    9. \n \n
    10.                 response = response.render()
    11. \n \n
    12.             except Exception as e:
    13. \n \n
    \n \n
      \n
    1.                 response = self.process_exception_by_middleware(e, request)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2.         return response
    3. \n \n
    4. \n \n
    5.     def process_exception_by_middleware(self, exception, request):
    6. \n \n
    7.         """
    8. \n \n
    9.         Pass the exception to the exception middleware. If no middleware
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    callback
    <function StudyViewSet at 0x7f0587099378>
    callback_args
    ()
    callback_kwargs
    {}
    middleware_method
    <bound method CsrfViewMiddleware.process_view of <django.middleware.csrf.CsrfViewMiddleware object at 0x7f0586bb1588>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    resolver
    <URLResolver 'pkdb_app.urls' (None:None) '^/'>
    resolver_match
    ResolverMatch(func=pkdb_app.studies.views.StudyViewSet, args=(), kwargs={}, url_name=studies-list, app_names=[], namespaces=[])
    response
    <Response status_code=201, "application/json">
    self
    <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>
    wrapped_callback
    <function StudyViewSet at 0x7f0587099378>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response\n \n \n
    \n \n
      \n \n
    1.                     raise ValueError(
    2. \n \n
    3.                         "%s.process_template_response didn't return an "
    4. \n \n
    5.                         "HttpResponse object. It returned None instead."
    6. \n \n
    7.                         % (middleware_method.__self__.__class__.__name__)
    8. \n \n
    9.                     )
    10. \n \n
    11. \n \n
    12.             try:
    13. \n \n
    \n \n
      \n
    1.                 response = response.render()
      ...
    2. \n
    \n \n
      \n \n
    1.             except Exception as e:
    2. \n \n
    3.                 response = self.process_exception_by_middleware(e, request)
    4. \n \n
    5. \n \n
    6.         return response
    7. \n \n
    8. \n \n
    9.     def process_exception_by_middleware(self, exception, request):
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    callback
    <function StudyViewSet at 0x7f0587099378>
    callback_args
    ()
    callback_kwargs
    {}
    middleware_method
    <bound method CsrfViewMiddleware.process_view of <django.middleware.csrf.CsrfViewMiddleware object at 0x7f0586bb1588>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    resolver
    <URLResolver 'pkdb_app.urls' (None:None) '^/'>
    resolver_match
    ResolverMatch(func=pkdb_app.studies.views.StudyViewSet, args=(), kwargs={}, url_name=studies-list, app_names=[], namespaces=[])
    response
    <Response status_code=201, "application/json">
    self
    <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>
    wrapped_callback
    <function StudyViewSet at 0x7f0587099378>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/template/response.py in render\n \n \n
    \n \n
      \n \n
    1. \n \n
    2.         If the content has already been rendered, this is a no-op.
    3. \n \n
    4. \n \n
    5.         Return the baked response instance.
    6. \n \n
    7.         """
    8. \n \n
    9.         retval = self
    10. \n \n
    11.         if not self._is_rendered:
    12. \n \n
    \n \n
      \n
    1.             self.content = self.rendered_content
      ...
    2. \n
    \n \n
      \n \n
    1.             for post_callback in self._post_render_callbacks:
    2. \n \n
    3.                 newretval = post_callback(retval)
    4. \n \n
    5.                 if newretval is not None:
    6. \n \n
    7.                     retval = newretval
    8. \n \n
    9.         return retval
    10. \n \n
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    retval
    <Response status_code=201, "application/json">
    self
    <Response status_code=201, "application/json">
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/response.py in rendered_content\n \n \n
    \n \n
      \n \n
    1. \n \n
    2.         if content_type is None and charset is not None:
    3. \n \n
    4.             content_type = "{0}; charset={1}".format(media_type, charset)
    5. \n \n
    6.         elif content_type is None:
    7. \n \n
    8.             content_type = media_type
    9. \n \n
    10.         self['Content-Type'] = content_type
    11. \n \n
    12. \n \n
    \n \n
      \n
    1.         ret = renderer.render(self.data, accepted_media_type, context)
      ...
    2. \n
    \n \n
      \n \n
    1.         if isinstance(ret, six.text_type):
    2. \n \n
    3.             assert charset, (
    4. \n \n
    5.                 'renderer returned unicode, and did not specify '
    6. \n \n
    7.                 'a charset value.'
    8. \n \n
    9.             )
    10. \n \n
    11.             return bytes(ret.encode(charset))
    12. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    accepted_media_type
    'application/json'
    charset
    None
    content_type
    'application/json'
    context
    {'args': (),\n               'kwargs': {},\n               'request': <rest_framework.request.Request object at 0x7f0586b87780>,\n               'response': <Response status_code=201, "application/json">,\n               'view': <pkdb_app.studies.views.StudyViewSet object at 0x7f0586b87be0>}
    media_type
    'application/json'
    renderer
    <rest_framework.renderers.JSONRenderer object at 0x7f05870005c0>
    self
    <Response status_code=201, "application/json">
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/renderers.py in render\n \n \n
    \n \n
      \n \n
    1.             separators = SHORT_SEPARATORS if self.compact else LONG_SEPARATORS
    2. \n \n
    3.         else:
    4. \n \n
    5.             separators = INDENT_SEPARATORS
    6. \n \n
    7. \n \n
    8.         ret = json.dumps(
    9. \n \n
    10.             data, cls=self.encoder_class,
    11. \n \n
    12.             indent=indent, ensure_ascii=self.ensure_ascii,
    13. \n \n
    \n \n
      \n
    1.             allow_nan=not self.strict, separators=separators
      ...
    2. \n
    \n \n
      \n \n
    1.         )
    2. \n \n
    3. \n \n
    4.         # On python 2.x json.dumps() returns bytestrings if ensure_ascii=True,
    5. \n \n
    6.         # but if ensure_ascii=False, the return type is underspecified,
    7. \n \n
    8.         # and may (or may not) be unicode.
    9. \n \n
    10.         # On python 3.x json.dumps() returns unicode strings.
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    accepted_media_type
    'application/json'
    data
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    indent
    None
    renderer_context
    {'args': (),\n               'kwargs': {},\n               'request': <rest_framework.request.Request object at 0x7f0586b87780>,\n               'response': <Response status_code=201, "application/json">,\n               'view': <pkdb_app.studies.views.StudyViewSet object at 0x7f0586b87be0>}
    self
    <rest_framework.renderers.JSONRenderer object at 0x7f05870005c0>
    separators
    (',', ':')
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/utils/json.py in dumps\n \n \n
    \n \n
      \n \n
    1.     kwargs.setdefault('allow_nan', False)
    2. \n \n
    3.     return json.dump(*args, **kwargs)
    4. \n \n
    5. \n \n
    6. \n \n
    7. @functools.wraps(json.dumps)
    8. \n \n
    9. def dumps(*args, **kwargs):
    10. \n \n
    11.     kwargs.setdefault('allow_nan', False)
    12. \n \n
    \n \n
      \n
    1.     return json.dumps(*args, **kwargs)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. \n \n
    3. @functools.wraps(json.load)
    4. \n \n
    5. def load(*args, **kwargs):
    6. \n \n
    7.     kwargs.setdefault('parse_constant', strict_constant)
    8. \n \n
    9.     return json.load(*args, **kwargs)
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    args
    ({'comment': None,\n                'description': None,\n                'groups': [OrderedDict([('reference',\n                                         <Reference: Reference object (012087345981)>),\n                                        ('characteristic_values',\n                                         [OrderedDict([('id', 4),\n                                                       ('choice', 'Asian'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'ethnicity'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 3),\n                                                       ('choice', None),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', 62.0),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', 9.0),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', 'kg'),\n                                                       ('category', 'body_weight'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 2),\n                                                       ('choice', 'homo sapiens'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'species'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 1),\n                                                       ('choice', 'M'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'sex'),\n                                                       ('group', 1)])]),\n                                        ('name', 'Seng2009-S_NCNS'),\n                                        ('description',\n                                         '59 healthy adult Asian volunteers were included. '\n                                         'In what follows, a non-caffeine consumer (NCCS) '\n                                         'refers to an individual who consumed beverages\\\n              '\n                                         '(coffee or tea) containing <=200 mg of caffeine '\n                                         'per day, and a regular caffeine consumer to one '\n                                         'who consumed more >200 mg. A cup (150 mL) of '\n                                         'coffee or tea is equivalent to approximately a '\n                                         'caffeine dose... <trimmed 5004 bytes string>
    kwargs
    {'allow_nan': False,\n               'cls': <class 'rest_framework.utils.encoders.JSONEncoder'>,\n               'ensure_ascii': False,\n               'indent': None,\n               'separators': (',', ':')}
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/__init__.py in dumps\n \n \n
    \n \n
      \n \n
    1.         return _default_encoder.encode(obj)
    2. \n \n
    3.     if cls is None:
    4. \n \n
    5.         cls = JSONEncoder
    6. \n \n
    7.     return cls(
    8. \n \n
    9.         skipkeys=skipkeys, ensure_ascii=ensure_ascii,
    10. \n \n
    11.         check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    12. \n \n
    13.         separators=separators, default=default, sort_keys=sort_keys,
    14. \n \n
    \n \n
      \n
    1.         **kw).encode(obj)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. \n \n
    3. _default_decoder = JSONDecoder(object_hook=None, object_pairs_hook=None)
    4. \n \n
    5. \n \n
    6. \n \n
    7. def detect_encoding(b):
    8. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    allow_nan
    False
    check_circular
    True
    cls
    <class 'rest_framework.utils.encoders.JSONEncoder'>
    default
    None
    ensure_ascii
    False
    indent
    None
    kw
    {}
    obj
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    separators
    (',', ':')
    skipkeys
    False
    sort_keys
    False
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in encode\n \n \n
    \n \n
      \n \n
    1.             if self.ensure_ascii:
    2. \n \n
    3.                 return encode_basestring_ascii(o)
    4. \n \n
    5.             else:
    6. \n \n
    7.                 return encode_basestring(o)
    8. \n \n
    9.         # This doesn't pass the iterator directly to ''.join() because the
    10. \n \n
    11.         # exceptions aren't as detailed.  The list call should be roughly
    12. \n \n
    13.         # equivalent to the PySequence_Fast that ''.join() would do.
    14. \n \n
    \n \n
      \n
    1.         chunks = self.iterencode(o, _one_shot=True)
      ...
    2. \n
    \n \n
      \n \n
    1.         if not isinstance(chunks, (list, tuple)):
    2. \n \n
    3.             chunks = list(chunks)
    4. \n \n
    5.         return ''.join(chunks)
    6. \n \n
    7. \n \n
    8.     def iterencode(self, o, _one_shot=False):
    9. \n \n
    10.         """Encode the given object and yield each string
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    o
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in iterencode\n \n \n
    \n \n
      \n \n
    1.                 self.key_separator, self.item_separator, self.sort_keys,
    2. \n \n
    3.                 self.skipkeys, self.allow_nan)
    4. \n \n
    5.         else:
    6. \n \n
    7.             _iterencode = _make_iterencode(
    8. \n \n
    9.                 markers, self.default, _encoder, self.indent, floatstr,
    10. \n \n
    11.                 self.key_separator, self.item_separator, self.sort_keys,
    12. \n \n
    13.                 self.skipkeys, _one_shot)
    14. \n \n
    \n \n
      \n
    1.         return _iterencode(o, 0)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
    3. \n \n
    4.         _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
    5. \n \n
    6.         ## HACK: hand-optimized bytecode; turn globals into locals
    7. \n \n
    8.         ValueError=ValueError,
    9. \n \n
    10.         dict=dict,
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    _encoder
    <built-in function encode_basestring>
    _iterencode
    <_json.Encoder object at 0x7f0586377de0>
    _one_shot
    True
    floatstr
    <function JSONEncoder.iterencode.<locals>.floatstr at 0x7f0586ac9488>
    markers
    {139661702408232: <Reference: Reference object (012087345981)>,\n               139661711021056: OrderedDict([('reference',\n                                              <Reference: Reference object (012087345981)>),\n                                             ('characteristic_values',\n                                              [OrderedDict([('id', 4),\n                                                            ('choice', 'Asian'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'ethnicity'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 3),\n                                                            ('choice', None),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', 62.0),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', 9.0),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', 'kg'),\n                                                            ('category', 'body_weight'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 2),\n                                                            ('choice', 'homo sapiens'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'species'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 1),\n                                                            ('choice', 'M'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'sex'),\n                                                            ('group', 1)])]),\n                                             ('name', 'Seng2009-S_NCNS'),\n                                             ('description',\n                                              '59 healthy adult Asian volunteers were '\n                                              'included. In what follows, a non-caffeine '\n                                              'consumer (NCCS) refers to an individual who '\n                                         ... <trimmed 18057 bytes string>
    o
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/utils/encoders.py in default\n \n \n
    \n \n
      \n \n
    1.         elif hasattr(obj, '__getitem__'):
    2. \n \n
    3.             try:
    4. \n \n
    5.                 return dict(obj)
    6. \n \n
    7.             except Exception:
    8. \n \n
    9.                 pass
    10. \n \n
    11.         elif hasattr(obj, '__iter__'):
    12. \n \n
    13.             return tuple(item for item in obj)
    14. \n \n
    \n \n
      \n
    1.         return super(JSONEncoder, self).default(obj)
      ...
    2. \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    __class__
    <class 'rest_framework.utils.encoders.JSONEncoder'>
    obj
    <Reference: Reference object (012087345981)>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in default\n \n \n
    \n \n
      \n \n
    1.                 else:
    2. \n \n
    3.                     return list(iterable)
    4. \n \n
    5.                 # Let the base class default method raise the TypeError
    6. \n \n
    7.                 return JSONEncoder.default(self, o)
    8. \n \n
    9. \n \n
    10.         """
    11. \n \n
    12.         raise TypeError("Object of type '%s' is not JSON serializable" %
    13. \n \n
    \n \n
      \n
    1.                         o.__class__.__name__)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2.     def encode(self, o):
    3. \n \n
    4.         """Return a JSON string representation of a Python data structure.
    5. \n \n
    6. \n \n
    7.         >>> from json.encoder import JSONEncoder
    8. \n \n
    9.         >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    o
    <Reference: Reference object (012087345981)>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n
\n
\n
\n \n
\n \n \n \n \n \n

\n \n
\n
\n
\n \n \n \n
\n

Request information

\n \n \n \n

USER

\n

AnonymousUser

\n \n \n

GET

\n \n

No GET data

\n \n \n

POST

\n \n

No POST data

\n \n

FILES

\n \n

No FILES data

\n \n \n \n

COOKIES

\n \n

No cookie data

\n \n \n

META

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
VariableValue
CONTENT_LENGTH
'1292'
CONTENT_TYPE
'application/json'
DJANGO_CONFIGURATION
'Local'
DJANGO_SECRET_KEY
'local'
DJANGO_SETTINGS_MODULE
'pkdb_app.config'
GATEWAY_INTERFACE
'CGI/1.1'
GPG_KEY
'0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D'
HOME
'/root'
HOSTNAME
'83fb6011203b'
HTTP_ACCEPT
'application/coreapi+json, application/vnd.coreapi+json, */*'
HTTP_ACCEPT_ENCODING
'gzip, deflate'
HTTP_CONNECTION
'keep-alive'
HTTP_HOST
'0.0.0.0:8000'
HTTP_USER_AGENT
'coreapi'
LANG
'C.UTF-8'
PATH
'/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PATH_INFO
'/api/v1/studies/'
PWD
'/code'
PYTHONUNBUFFERED
'1'
PYTHON_PIP_VERSION
'10.0.1'
PYTHON_VERSION
'3.6.6'
QUERY_STRING
''
REMOTE_ADDR
'172.22.0.1'
REMOTE_HOST
''
REQUEST_METHOD
'POST'
RUN_MAIN
'true'
SCRIPT_NAME
''
SERVER_NAME
'83fb6011203b'
SERVER_PORT
'8000'
SERVER_PROTOCOL
'HTTP/1.1'
SERVER_SOFTWARE
'WSGIServer/0.2'
SHLVL
'1'
TZ
'UTC'
_
'./manage.py'
wsgi.errors
<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
wsgi.file_wrapper
''
wsgi.input
<_io.BufferedReader name=5>
wsgi.multiprocess
False
wsgi.multithread
True
wsgi.run_once
False
wsgi.url_scheme
'http'
wsgi.version
(1, 0)
\n \n \n

Settings

\n

Using settings module pkdb_app.config

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
SettingValue
ABSOLUTE_URL_OVERRIDES
{}
ADMINS
(('Author', 'janekg89@hotmail.de'),)
ALLOWED_HOSTS
['*']
APPEND_SLASH
False
AUTHENTICATION_BACKENDS
['django.contrib.auth.backends.ModelBackend']
AUTH_PASSWORD_VALIDATORS
'********************'
AUTH_USER_MODEL
'users.User'
CACHES
{'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
CACHE_MIDDLEWARE_ALIAS
'default'
CACHE_MIDDLEWARE_KEY_PREFIX
'********************'
CACHE_MIDDLEWARE_SECONDS
600
CONFIGURATION
'pkdb_app.config.Local'
CSRF_COOKIE_AGE
31449600
CSRF_COOKIE_DOMAIN
None
CSRF_COOKIE_HTTPONLY
False
CSRF_COOKIE_NAME
'csrftoken'
CSRF_COOKIE_PATH
'/'
CSRF_COOKIE_SECURE
False
CSRF_FAILURE_VIEW
'django.views.csrf.csrf_failure'
CSRF_HEADER_NAME
'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS
[]
CSRF_USE_SESSIONS
False
DATABASES
{'default': {'ATOMIC_REQUESTS': False,\n                           'AUTOCOMMIT': True,\n                           'CONN_MAX_AGE': 600,\n                           'ENGINE': 'django.db.backends.postgresql_psycopg2',\n                           'HOST': 'postgres',\n                           'NAME': 'postgres',\n                           'OPTIONS': {},\n                           'PASSWORD': '********************',\n                           'PORT': 5432,\n                           'TEST': {'CHARSET': None,\n                                    'COLLATION': None,\n                                    'MIRROR': None,\n                                    'NAME': None},\n                           'TIME_ZONE': None,\n                           'USER': 'postgres'}}
DATABASE_ROUTERS
[]
DATA_UPLOAD_MAX_MEMORY_SIZE
2621440
DATA_UPLOAD_MAX_NUMBER_FIELDS
1000
DATETIME_FORMAT
'N j, Y, P'
DATETIME_INPUT_FORMATS
['%Y-%m-%d %H:%M:%S',\n               '%Y-%m-%d %H:%M:%S.%f',\n               '%Y-%m-%d %H:%M',\n               '%Y-%m-%d',\n               '%m/%d/%Y %H:%M:%S',\n               '%m/%d/%Y %H:%M:%S.%f',\n               '%m/%d/%Y %H:%M',\n               '%m/%d/%Y',\n               '%m/%d/%y %H:%M:%S',\n               '%m/%d/%y %H:%M:%S.%f',\n               '%m/%d/%y %H:%M',\n               '%m/%d/%y']
DATE_FORMAT
'N j, Y'
DATE_INPUT_FORMATS
['%Y-%m-%d',\n               '%m/%d/%Y',\n               '%m/%d/%y',\n               '%b %d %Y',\n               '%b %d, %Y',\n               '%d %b %Y',\n               '%d %b, %Y',\n               '%B %d %Y',\n               '%B %d, %Y',\n               '%d %B %Y',\n               '%d %B, %Y']
DEBUG
True
DEBUG_PROPAGATE_EXCEPTIONS
False
DECIMAL_SEPARATOR
'.'
DEFAULT_CHARSET
'utf-8'
DEFAULT_CONTENT_TYPE
'text/html'
DEFAULT_EXCEPTION_REPORTER_FILTER
'django.views.debug.SafeExceptionReporterFilter'
DEFAULT_FILE_STORAGE
'django.core.files.storage.FileSystemStorage'
DEFAULT_FROM_EMAIL
'webmaster@localhost'
DEFAULT_INDEX_TABLESPACE
''
DEFAULT_TABLESPACE
''
DISALLOWED_USER_AGENTS
[]
DOTENV_LOADED
None
EMAIL_BACKEND
'django.core.mail.backends.console.EmailBackend'
EMAIL_HOST
'localhost'
EMAIL_HOST_PASSWORD
'********************'
EMAIL_HOST_USER
''
EMAIL_PORT
1025
EMAIL_SSL_CERTFILE
None
EMAIL_SSL_KEYFILE
'********************'
EMAIL_SUBJECT_PREFIX
'[Django] '
EMAIL_TIMEOUT
None
EMAIL_USE_LOCALTIME
False
EMAIL_USE_SSL
False
EMAIL_USE_TLS
False
FILE_CHARSET
'utf-8'
FILE_UPLOAD_DIRECTORY_PERMISSIONS
None
FILE_UPLOAD_HANDLERS
['django.core.files.uploadhandler.MemoryFileUploadHandler',\n               'django.core.files.uploadhandler.TemporaryFileUploadHandler']
FILE_UPLOAD_MAX_MEMORY_SIZE
2621440
FILE_UPLOAD_PERMISSIONS
None
FILE_UPLOAD_TEMP_DIR
None
FIRST_DAY_OF_WEEK
0
FIXTURE_DIRS
[]
FORCE_SCRIPT_NAME
None
FORMAT_MODULE_PATH
None
FORM_RENDERER
'django.forms.renderers.DjangoTemplates'
IGNORABLE_404_URLS
[]
INSTALLED_APPS
('django.contrib.admin',\n               'django.contrib.auth',\n               'django.contrib.contenttypes',\n               'django.contrib.sessions',\n               'django.contrib.messages',\n               'django.contrib.staticfiles',\n               'rest_framework',\n               'rest_framework.authtoken',\n               'django_filters',\n               'rest_framework_swagger',\n               'pkdb_app.users',\n               'pkdb_app.studies',\n               'pkdb_app.subjects',\n               'pkdb_app.interventions',\n               'django_nose')
INTERNAL_IPS
[]
LANGUAGES
[('af', 'Afrikaans'),\n               ('ar', 'Arabic'),\n               ('ast', 'Asturian'),\n               ('az', 'Azerbaijani'),\n               ('bg', 'Bulgarian'),\n               ('be', 'Belarusian'),\n               ('bn', 'Bengali'),\n               ('br', 'Breton'),\n               ('bs', 'Bosnian'),\n               ('ca', 'Catalan'),\n               ('cs', 'Czech'),\n               ('cy', 'Welsh'),\n               ('da', 'Danish'),\n               ('de', 'German'),\n               ('dsb', 'Lower Sorbian'),\n               ('el', 'Greek'),\n               ('en', 'English'),\n               ('en-au', 'Australian English'),\n               ('en-gb', 'British English'),\n               ('eo', 'Esperanto'),\n               ('es', 'Spanish'),\n               ('es-ar', 'Argentinian Spanish'),\n               ('es-co', 'Colombian Spanish'),\n               ('es-mx', 'Mexican Spanish'),\n               ('es-ni', 'Nicaraguan Spanish'),\n               ('es-ve', 'Venezuelan Spanish'),\n               ('et', 'Estonian'),\n               ('eu', 'Basque'),\n               ('fa', 'Persian'),\n               ('fi', 'Finnish'),\n               ('fr', 'French'),\n               ('fy', 'Frisian'),\n               ('ga', 'Irish'),\n               ('gd', 'Scottish Gaelic'),\n               ('gl', 'Galician'),\n               ('he', 'Hebrew'),\n               ('hi', 'Hindi'),\n               ('hr', 'Croatian'),\n               ('hsb', 'Upper Sorbian'),\n               ('hu', 'Hungarian'),\n               ('ia', 'Interlingua'),\n               ('id', 'Indonesian'),\n               ('io', 'Ido'),\n               ('is', 'Icelandic'),\n               ('it', 'Italian'),\n               ('ja', 'Japanese'),\n               ('ka', 'Georgian'),\n               ('kab', 'Kabyle'),\n               ('kk', 'Kazakh'),\n               ('km', 'Khmer'),\n               ('kn', 'Kannada'),\n               ('ko', 'Korean'),\n               ('lb', 'Luxembourgish'),\n               ('lt', 'Lithuanian'),\n               ('lv', 'Latvian'),\n               ('mk', 'Macedonian'),\n               ('ml', 'Malayalam'),\n               ('mn', 'Mongolian'),\n               ('mr', 'Marathi'),\n               ('my', 'Burmese'),\n               ('nb', 'Norwegian Bokm\\u00e5l'),\n               ('ne', 'Nepali'),\n               ('nl', 'Dutch'),\n               ('nn', 'Norwegian Nynorsk'),\n               ('os', 'Ossetic'),\n               ('pa', 'Punjabi'),\n               ('pl', 'Polish'),\n               ('pt', 'Portuguese'),\n               ('pt-br', 'Brazilian Portuguese'),\n               ('ro', 'Romanian'),\n               ('ru', 'Russian'),\n               ('sk', 'Slovak'),\n               ('sl', 'Slovenian'),\n               ('sq', 'Albanian'),\n               ('sr', 'Serbian'),\n               ('sr-latn', 'Serbian Latin'),\n               ('sv', 'Swedish'),\n               ('sw', 'Swahili'),\n               ('ta', 'Tamil'),\n               ('te', 'Telugu'),\n               ('th', 'Thai'),\n               ('tr', 'Turkish'),\n               ('tt', 'Tatar'),\n               ('udm', 'Udmurt'),\n               ('uk', 'Ukrainian'),\n               ('ur', 'Urdu'),\n               ('vi', 'Vietnamese'),\n               ('zh-hans', 'Simplified Chinese'),\n               ('zh-hant', 'Traditional Chinese')]
LANGUAGES_BIDI
['he', 'ar', 'fa', 'ur']
LANGUAGE_CODE
'en-us'
LANGUAGE_COOKIE_AGE
None
LANGUAGE_COOKIE_DOMAIN
None
LANGUAGE_COOKIE_NAME
'django_language'
LANGUAGE_COOKIE_PATH
'/'
LOCALE_PATHS
[]
LOGGING
{'disable_existing_loggers': False,\n               'filters': {'require_debug_true': {'()': 'django.utils.log.RequireDebugTrue'}},\n               'formatters': {'django.server': {'()': 'django.utils.log.ServerFormatter',\n                                                'format': '[%(server_time)s] %(message)s'},\n                              'simple': {'format': '%(levelname)s %(message)s'},\n                              'verbose': {'format': '%(levelname)s %(asctime)s %(module)s '\n                                                    '%(process)d %(thread)d %(message)s'}},\n               'handlers': {'console': {'class': 'logging.StreamHandler',\n                                        'formatter': 'simple',\n                                        'level': 'DEBUG'},\n                            'django.server': {'class': 'logging.StreamHandler',\n                                              'formatter': 'django.server',\n                                              'level': 'INFO'},\n                            'mail_admins': {'class': 'django.utils.log.AdminEmailHandler',\n                                            'level': 'ERROR'}},\n               'loggers': {'django': {'handlers': ['console'], 'propagate': True},\n                           'django.db.backends': {'handlers': ['console'], 'level': 'INFO'},\n                           'django.request': {'handlers': ['mail_admins', 'console'],\n                                              'level': 'ERROR',\n                                              'propagate': False},\n                           'django.server': {'handlers': ['django.server'],\n                                             'level': 'INFO',\n                                             'propagate': False}},\n               'version': 1}
LOGGING_CONFIG
'logging.config.dictConfig'
LOGIN_REDIRECT_URL
'/'
LOGIN_URL
'rest_framework:login'
LOGOUT_REDIRECT_URL
None
LOGOUT_URL
'rest_framework:logout'
MANAGERS
[]
MEDIA_ROOT
'/code/media'
MEDIA_URL
'/media/'
MESSAGE_STORAGE
'django.contrib.messages.storage.fallback.FallbackStorage'
MIDDLEWARE
('django.middleware.security.SecurityMiddleware',\n               'django.contrib.sessions.middleware.SessionMiddleware',\n               'django.middleware.common.CommonMiddleware',\n               'django.middleware.csrf.CsrfViewMiddleware',\n               'django.contrib.auth.middleware.AuthenticationMiddleware',\n               'django.contrib.messages.middleware.MessageMiddleware',\n               'django.middleware.clickjacking.XFrameOptionsMiddleware')
MIGRATION_MODULES
{}
MONTH_DAY_FORMAT
'F j'
NOSE_ARGS
['/code/pkdb_app',\n               '-s',\n               '--nologcapture',\n               '--with-coverage',\n               '--with-progressive',\n               '--cover-package=pkdb']
NUMBER_GROUPING
0
PASSWORD_HASHERS
'********************'
PASSWORD_RESET_TIMEOUT_DAYS
'********************'
PREPEND_WWW
False
REST_FRAMEWORK
{'DATETIME_FORMAT': '%Y-%m-%dT%H:%M:%S%z',\n               'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.SessionAuthentication',),\n               'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),\n               'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',\n               'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'],\n               'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer',\n                                            'rest_framework.renderers.BrowsableAPIRenderer'),\n               'PAGE_SIZE': 10}
ROOT_URLCONF
'pkdb_app.urls'
SECRET_KEY
'********************'
SECURE_BROWSER_XSS_FILTER
False
SECURE_CONTENT_TYPE_NOSNIFF
False
SECURE_HSTS_INCLUDE_SUBDOMAINS
False
SECURE_HSTS_PRELOAD
False
SECURE_HSTS_SECONDS
0
SECURE_PROXY_SSL_HEADER
None
SECURE_REDIRECT_EXEMPT
[]
SECURE_SSL_HOST
None
SECURE_SSL_REDIRECT
False
SERVER_EMAIL
'root@localhost'
SESSION_CACHE_ALIAS
'default'
SESSION_COOKIE_AGE
1209600
SESSION_COOKIE_DOMAIN
None
SESSION_COOKIE_HTTPONLY
True
SESSION_COOKIE_NAME
'sessionid'
SESSION_COOKIE_PATH
'/'
SESSION_COOKIE_SECURE
False
SESSION_ENGINE
'django.contrib.sessions.backends.db'
SESSION_EXPIRE_AT_BROWSER_CLOSE
False
SESSION_FILE_PATH
None
SESSION_SAVE_EVERY_REQUEST
False
SESSION_SERIALIZER
'django.contrib.sessions.serializers.JSONSerializer'
SETTINGS_MODULE
'pkdb_app.config'
SHORT_DATETIME_FORMAT
'm/d/Y P'
SHORT_DATE_FORMAT
'm/d/Y'
SIGNING_BACKEND
'django.core.signing.TimestampSigner'
SILENCED_SYSTEM_CHECKS
[]
STATICFILES_DIRS
[]
STATICFILES_FINDERS
('django.contrib.staticfiles.finders.FileSystemFinder',\n               'django.contrib.staticfiles.finders.AppDirectoriesFinder')
STATICFILES_STORAGE
'django.contrib.staticfiles.storage.StaticFilesStorage'
STATIC_ROOT
'/code/static'
STATIC_URL
'/static/'
SWAGGER_SETTINGS
{'APIS_SORTER': '********************',\n               'DOC_EXPANSION': 'list',\n               'LOGIN_URL': 'rest_framework:login',\n               'LOGOUT_URL': 'rest_framework:logout',\n               'SECURITY_DEFINITIONS': {'basic': {'type': 'basic'}},\n               'USE_SESSION_AUTH': True}
TEMPLATES
[{'APP_DIRS': True,\n                'BACKEND': 'django.template.backends.django.DjangoTemplates',\n                'DIRS': [],\n                'OPTIONS': {'context_processors': ['django.template.context_processors.debug',\n                                                   'django.template.context_processors.request',\n                                                   'django.contrib.auth.context_processors.auth',\n                                                   'django.contrib.messages.context_processors.messages']}}]
TEST_NON_SERIALIZED_APPS
[]
TEST_RUNNER
'django_nose.NoseTestSuiteRunner'
THOUSAND_SEPARATOR
','
TIME_FORMAT
'P'
TIME_INPUT_FORMATS
['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
TIME_ZONE
'UTC'
USE_ETAGS
False
USE_I18N
False
USE_L10N
True
USE_THOUSAND_SEPARATOR
False
USE_TZ
True
USE_X_FORWARDED_HOST
False
USE_X_FORWARDED_PORT
False
WSGI_APPLICATION
'pkdb_app.wsgi.application'
X_FRAME_OPTIONS
'SAMEORIGIN'
YEAR_MONTH_FORMAT
'F Y'
\n \n
\n \n
\n

\n You're seeing this error because you have DEBUG = True in your\n Django settings file. Change that to False, and Django will\n display a standard page generated by the handler for this status code.\n

\n
\n \n \n \n \"", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"studies\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mErrorMessage\u001b[0m: \n message: \"\n \n \n \n \n TypeError\n at /api/v1/studies/\n \n \n \n \n \n \n
\n

TypeError\n at /api/v1/studies/

\n
Object of type 'Reference' is not JSON serializable
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Request Method:POST
Request URL:http://0.0.0.0:8000/api/v1/studies/
Django Version:2.0.6
Exception Type:TypeError
Exception Value:
Object of type 'Reference' is not JSON serializable
Exception Location:/usr/local/lib/python3.6/json/encoder.py in default, line 180
Python Executable:/usr/local/bin/python
Python Version:3.6.6
Python Path:
['/code',\n               '/usr/local/lib/python36.zip',\n               '/usr/local/lib/python3.6',\n               '/usr/local/lib/python3.6/lib-dynload',\n               '/usr/local/lib/python3.6/site-packages']
Server time:Mon, 23 Jul 2018 16:28:03 +0000
\n
\n \n \n \n \n
\n

Traceback \n Switch to copy-and-paste view\n

\n
\n
    \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py in inner\n \n \n
    \n \n
      \n \n
    1.     This decorator is automatically applied to all middleware to ensure that
    2. \n \n
    3.     no middleware leaks an exception and that the next middleware in the stack
    4. \n \n
    5.     can rely on getting a response instead of an exception.
    6. \n \n
    7.     """
    8. \n \n
    9.     @wraps(get_response)
    10. \n \n
    11.     def inner(request):
    12. \n \n
    13.         try:
    14. \n \n
    \n \n
      \n
    1.             response = get_response(request)
      ...
    2. \n
    \n \n
      \n \n
    1.         except Exception as exc:
    2. \n \n
    3.             response = response_for_exception(request, exc)
    4. \n \n
    5.         return response
    6. \n \n
    7.     return inner
    8. \n \n
    9. \n \n
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    exc
    TypeError("Object of type 'Reference' is not JSON serializable",)
    get_response
    <bound method BaseHandler._get_response of <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response\n \n \n
    \n \n
      \n \n
    1.                         "HttpResponse object. It returned None instead."
    2. \n \n
    3.                         % (middleware_method.__self__.__class__.__name__)
    4. \n \n
    5.                     )
    6. \n \n
    7. \n \n
    8.             try:
    9. \n \n
    10.                 response = response.render()
    11. \n \n
    12.             except Exception as e:
    13. \n \n
    \n \n
      \n
    1.                 response = self.process_exception_by_middleware(e, request)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2.         return response
    3. \n \n
    4. \n \n
    5.     def process_exception_by_middleware(self, exception, request):
    6. \n \n
    7.         """
    8. \n \n
    9.         Pass the exception to the exception middleware. If no middleware
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    callback
    <function StudyViewSet at 0x7f0587099378>
    callback_args
    ()
    callback_kwargs
    {}
    middleware_method
    <bound method CsrfViewMiddleware.process_view of <django.middleware.csrf.CsrfViewMiddleware object at 0x7f0586bb1588>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    resolver
    <URLResolver 'pkdb_app.urls' (None:None) '^/'>
    resolver_match
    ResolverMatch(func=pkdb_app.studies.views.StudyViewSet, args=(), kwargs={}, url_name=studies-list, app_names=[], namespaces=[])
    response
    <Response status_code=201, "application/json">
    self
    <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>
    wrapped_callback
    <function StudyViewSet at 0x7f0587099378>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response\n \n \n
    \n \n
      \n \n
    1.                     raise ValueError(
    2. \n \n
    3.                         "%s.process_template_response didn't return an "
    4. \n \n
    5.                         "HttpResponse object. It returned None instead."
    6. \n \n
    7.                         % (middleware_method.__self__.__class__.__name__)
    8. \n \n
    9.                     )
    10. \n \n
    11. \n \n
    12.             try:
    13. \n \n
    \n \n
      \n
    1.                 response = response.render()
      ...
    2. \n
    \n \n
      \n \n
    1.             except Exception as e:
    2. \n \n
    3.                 response = self.process_exception_by_middleware(e, request)
    4. \n \n
    5. \n \n
    6.         return response
    7. \n \n
    8. \n \n
    9.     def process_exception_by_middleware(self, exception, request):
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    callback
    <function StudyViewSet at 0x7f0587099378>
    callback_args
    ()
    callback_kwargs
    {}
    middleware_method
    <bound method CsrfViewMiddleware.process_view of <django.middleware.csrf.CsrfViewMiddleware object at 0x7f0586bb1588>>
    request
    <WSGIRequest: POST '/api/v1/studies/'>
    resolver
    <URLResolver 'pkdb_app.urls' (None:None) '^/'>
    resolver_match
    ResolverMatch(func=pkdb_app.studies.views.StudyViewSet, args=(), kwargs={}, url_name=studies-list, app_names=[], namespaces=[])
    response
    <Response status_code=201, "application/json">
    self
    <django.core.handlers.wsgi.WSGIHandler object at 0x7f058701a828>
    wrapped_callback
    <function StudyViewSet at 0x7f0587099378>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/django/template/response.py in render\n \n \n
    \n \n
      \n \n
    1. \n \n
    2.         If the content has already been rendered, this is a no-op.
    3. \n \n
    4. \n \n
    5.         Return the baked response instance.
    6. \n \n
    7.         """
    8. \n \n
    9.         retval = self
    10. \n \n
    11.         if not self._is_rendered:
    12. \n \n
    \n \n
      \n
    1.             self.content = self.rendered_content
      ...
    2. \n
    \n \n
      \n \n
    1.             for post_callback in self._post_render_callbacks:
    2. \n \n
    3.                 newretval = post_callback(retval)
    4. \n \n
    5.                 if newretval is not None:
    6. \n \n
    7.                     retval = newretval
    8. \n \n
    9.         return retval
    10. \n \n
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    retval
    <Response status_code=201, "application/json">
    self
    <Response status_code=201, "application/json">
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/response.py in rendered_content\n \n \n
    \n \n
      \n \n
    1. \n \n
    2.         if content_type is None and charset is not None:
    3. \n \n
    4.             content_type = "{0}; charset={1}".format(media_type, charset)
    5. \n \n
    6.         elif content_type is None:
    7. \n \n
    8.             content_type = media_type
    9. \n \n
    10.         self['Content-Type'] = content_type
    11. \n \n
    12. \n \n
    \n \n
      \n
    1.         ret = renderer.render(self.data, accepted_media_type, context)
      ...
    2. \n
    \n \n
      \n \n
    1.         if isinstance(ret, six.text_type):
    2. \n \n
    3.             assert charset, (
    4. \n \n
    5.                 'renderer returned unicode, and did not specify '
    6. \n \n
    7.                 'a charset value.'
    8. \n \n
    9.             )
    10. \n \n
    11.             return bytes(ret.encode(charset))
    12. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    accepted_media_type
    'application/json'
    charset
    None
    content_type
    'application/json'
    context
    {'args': (),\n               'kwargs': {},\n               'request': <rest_framework.request.Request object at 0x7f0586b87780>,\n               'response': <Response status_code=201, "application/json">,\n               'view': <pkdb_app.studies.views.StudyViewSet object at 0x7f0586b87be0>}
    media_type
    'application/json'
    renderer
    <rest_framework.renderers.JSONRenderer object at 0x7f05870005c0>
    self
    <Response status_code=201, "application/json">
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/renderers.py in render\n \n \n
    \n \n
      \n \n
    1.             separators = SHORT_SEPARATORS if self.compact else LONG_SEPARATORS
    2. \n \n
    3.         else:
    4. \n \n
    5.             separators = INDENT_SEPARATORS
    6. \n \n
    7. \n \n
    8.         ret = json.dumps(
    9. \n \n
    10.             data, cls=self.encoder_class,
    11. \n \n
    12.             indent=indent, ensure_ascii=self.ensure_ascii,
    13. \n \n
    \n \n
      \n
    1.             allow_nan=not self.strict, separators=separators
      ...
    2. \n
    \n \n
      \n \n
    1.         )
    2. \n \n
    3. \n \n
    4.         # On python 2.x json.dumps() returns bytestrings if ensure_ascii=True,
    5. \n \n
    6.         # but if ensure_ascii=False, the return type is underspecified,
    7. \n \n
    8.         # and may (or may not) be unicode.
    9. \n \n
    10.         # On python 3.x json.dumps() returns unicode strings.
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    accepted_media_type
    'application/json'
    data
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    indent
    None
    renderer_context
    {'args': (),\n               'kwargs': {},\n               'request': <rest_framework.request.Request object at 0x7f0586b87780>,\n               'response': <Response status_code=201, "application/json">,\n               'view': <pkdb_app.studies.views.StudyViewSet object at 0x7f0586b87be0>}
    self
    <rest_framework.renderers.JSONRenderer object at 0x7f05870005c0>
    separators
    (',', ':')
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/utils/json.py in dumps\n \n \n
    \n \n
      \n \n
    1.     kwargs.setdefault('allow_nan', False)
    2. \n \n
    3.     return json.dump(*args, **kwargs)
    4. \n \n
    5. \n \n
    6. \n \n
    7. @functools.wraps(json.dumps)
    8. \n \n
    9. def dumps(*args, **kwargs):
    10. \n \n
    11.     kwargs.setdefault('allow_nan', False)
    12. \n \n
    \n \n
      \n
    1.     return json.dumps(*args, **kwargs)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. \n \n
    3. @functools.wraps(json.load)
    4. \n \n
    5. def load(*args, **kwargs):
    6. \n \n
    7.     kwargs.setdefault('parse_constant', strict_constant)
    8. \n \n
    9.     return json.load(*args, **kwargs)
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    args
    ({'comment': None,\n                'description': None,\n                'groups': [OrderedDict([('reference',\n                                         <Reference: Reference object (012087345981)>),\n                                        ('characteristic_values',\n                                         [OrderedDict([('id', 4),\n                                                       ('choice', 'Asian'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'ethnicity'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 3),\n                                                       ('choice', None),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', 62.0),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', 9.0),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', 'kg'),\n                                                       ('category', 'body_weight'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 2),\n                                                       ('choice', 'homo sapiens'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'species'),\n                                                       ('group', 1)]),\n                                          OrderedDict([('id', 1),\n                                                       ('choice', 'M'),\n                                                       ('count', 14),\n                                                       ('value', None),\n                                                       ('mean', None),\n                                                       ('median', None),\n                                                       ('min', None),\n                                                       ('max', None),\n                                                       ('sd', None),\n                                                       ('se', None),\n                                                       ('cv', None),\n                                                       ('unit', None),\n                                                       ('category', 'sex'),\n                                                       ('group', 1)])]),\n                                        ('name', 'Seng2009-S_NCNS'),\n                                        ('description',\n                                         '59 healthy adult Asian volunteers were included. '\n                                         'In what follows, a non-caffeine consumer (NCCS) '\n                                         'refers to an individual who consumed beverages\\\n              '\n                                         '(coffee or tea) containing <=200 mg of caffeine '\n                                         'per day, and a regular caffeine consumer to one '\n                                         'who consumed more >200 mg. A cup (150 mL) of '\n                                         'coffee or tea is equivalent to approximately a '\n                                         'caffeine dose... <trimmed 5004 bytes string>
    kwargs
    {'allow_nan': False,\n               'cls': <class 'rest_framework.utils.encoders.JSONEncoder'>,\n               'ensure_ascii': False,\n               'indent': None,\n               'separators': (',', ':')}
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/__init__.py in dumps\n \n \n
    \n \n
      \n \n
    1.         return _default_encoder.encode(obj)
    2. \n \n
    3.     if cls is None:
    4. \n \n
    5.         cls = JSONEncoder
    6. \n \n
    7.     return cls(
    8. \n \n
    9.         skipkeys=skipkeys, ensure_ascii=ensure_ascii,
    10. \n \n
    11.         check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    12. \n \n
    13.         separators=separators, default=default, sort_keys=sort_keys,
    14. \n \n
    \n \n
      \n
    1.         **kw).encode(obj)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. \n \n
    3. _default_decoder = JSONDecoder(object_hook=None, object_pairs_hook=None)
    4. \n \n
    5. \n \n
    6. \n \n
    7. def detect_encoding(b):
    8. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    allow_nan
    False
    check_circular
    True
    cls
    <class 'rest_framework.utils.encoders.JSONEncoder'>
    default
    None
    ensure_ascii
    False
    indent
    None
    kw
    {}
    obj
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    separators
    (',', ':')
    skipkeys
    False
    sort_keys
    False
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in encode\n \n \n
    \n \n
      \n \n
    1.             if self.ensure_ascii:
    2. \n \n
    3.                 return encode_basestring_ascii(o)
    4. \n \n
    5.             else:
    6. \n \n
    7.                 return encode_basestring(o)
    8. \n \n
    9.         # This doesn't pass the iterator directly to ''.join() because the
    10. \n \n
    11.         # exceptions aren't as detailed.  The list call should be roughly
    12. \n \n
    13.         # equivalent to the PySequence_Fast that ''.join() would do.
    14. \n \n
    \n \n
      \n
    1.         chunks = self.iterencode(o, _one_shot=True)
      ...
    2. \n
    \n \n
      \n \n
    1.         if not isinstance(chunks, (list, tuple)):
    2. \n \n
    3.             chunks = list(chunks)
    4. \n \n
    5.         return ''.join(chunks)
    6. \n \n
    7. \n \n
    8.     def iterencode(self, o, _one_shot=False):
    9. \n \n
    10.         """Encode the given object and yield each string
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    o
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in iterencode\n \n \n
    \n \n
      \n \n
    1.                 self.key_separator, self.item_separator, self.sort_keys,
    2. \n \n
    3.                 self.skipkeys, self.allow_nan)
    4. \n \n
    5.         else:
    6. \n \n
    7.             _iterencode = _make_iterencode(
    8. \n \n
    9.                 markers, self.default, _encoder, self.indent, floatstr,
    10. \n \n
    11.                 self.key_separator, self.item_separator, self.sort_keys,
    12. \n \n
    13.                 self.skipkeys, _one_shot)
    14. \n \n
    \n \n
      \n
    1.         return _iterencode(o, 0)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2. def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
    3. \n \n
    4.         _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
    5. \n \n
    6.         ## HACK: hand-optimized bytecode; turn globals into locals
    7. \n \n
    8.         ValueError=ValueError,
    9. \n \n
    10.         dict=dict,
    11. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    _encoder
    <built-in function encode_basestring>
    _iterencode
    <_json.Encoder object at 0x7f0586377de0>
    _one_shot
    True
    floatstr
    <function JSONEncoder.iterencode.<locals>.floatstr at 0x7f0586ac9488>
    markers
    {139661702408232: <Reference: Reference object (012087345981)>,\n               139661711021056: OrderedDict([('reference',\n                                              <Reference: Reference object (012087345981)>),\n                                             ('characteristic_values',\n                                              [OrderedDict([('id', 4),\n                                                            ('choice', 'Asian'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'ethnicity'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 3),\n                                                            ('choice', None),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', 62.0),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', 9.0),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', 'kg'),\n                                                            ('category', 'body_weight'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 2),\n                                                            ('choice', 'homo sapiens'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'species'),\n                                                            ('group', 1)]),\n                                               OrderedDict([('id', 1),\n                                                            ('choice', 'M'),\n                                                            ('count', 14),\n                                                            ('value', None),\n                                                            ('mean', None),\n                                                            ('median', None),\n                                                            ('min', None),\n                                                            ('max', None),\n                                                            ('sd', None),\n                                                            ('se', None),\n                                                            ('cv', None),\n                                                            ('unit', None),\n                                                            ('category', 'sex'),\n                                                            ('group', 1)])]),\n                                             ('name', 'Seng2009-S_NCNS'),\n                                             ('description',\n                                              '59 healthy adult Asian volunteers were '\n                                              'included. In what follows, a non-caffeine '\n                                              'consumer (NCCS) refers to an individual who '\n                                         ... <trimmed 18057 bytes string>
    o
    {'comment': None,\n               'description': None,\n               'groups': [OrderedDict([('reference',\n                                        <Reference: Reference object (012087345981)>),\n                                       ('characteristic_values',\n                                        [OrderedDict([('id', 4),\n                                                      ('choice', 'Asian'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'ethnicity'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 3),\n                                                      ('choice', None),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', 62.0),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', 9.0),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', 'kg'),\n                                                      ('category', 'body_weight'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 2),\n                                                      ('choice', 'homo sapiens'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'species'),\n                                                      ('group', 1)]),\n                                         OrderedDict([('id', 1),\n                                                      ('choice', 'M'),\n                                                      ('count', 14),\n                                                      ('value', None),\n                                                      ('mean', None),\n                                                      ('median', None),\n                                                      ('min', None),\n                                                      ('max', None),\n                                                      ('sd', None),\n                                                      ('se', None),\n                                                      ('cv', None),\n                                                      ('unit', None),\n                                                      ('category', 'sex'),\n                                                      ('group', 1)])]),\n                                       ('name', 'Seng2009-S_NCNS'),\n                                       ('description',\n                                        '59 healthy adult Asian volunteers were included. In '\n                                        'what follows, a non-caffeine consumer (NCCS) refers '\n                                        'to an individual who consumed beverages\\\n              '\n                                        '(coffee or tea) containing <=200 mg of caffeine per '\n                                        'day, and a regular caffeine consumer to one who '\n                                        'consumed more >200 mg. A cup (150 mL) of coffee or '\n                                        'tea is equivalent to approximately a caffeine dose '\n                                        'of 70 and 25 mg respectively (9). Additionally, a '\n                                ... <trimmed 4888 bytes string>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/site-packages/rest_framework/utils/encoders.py in default\n \n \n
    \n \n
      \n \n
    1.         elif hasattr(obj, '__getitem__'):
    2. \n \n
    3.             try:
    4. \n \n
    5.                 return dict(obj)
    6. \n \n
    7.             except Exception:
    8. \n \n
    9.                 pass
    10. \n \n
    11.         elif hasattr(obj, '__iter__'):
    12. \n \n
    13.             return tuple(item for item in obj)
    14. \n \n
    \n \n
      \n
    1.         return super(JSONEncoder, self).default(obj)
      ...
    2. \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    __class__
    <class 'rest_framework.utils.encoders.JSONEncoder'>
    obj
    <Reference: Reference object (012087345981)>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n \n
  • \n /usr/local/lib/python3.6/json/encoder.py in default\n \n \n
    \n \n
      \n \n
    1.                 else:
    2. \n \n
    3.                     return list(iterable)
    4. \n \n
    5.                 # Let the base class default method raise the TypeError
    6. \n \n
    7.                 return JSONEncoder.default(self, o)
    8. \n \n
    9. \n \n
    10.         """
    11. \n \n
    12.         raise TypeError("Object of type '%s' is not JSON serializable" %
    13. \n \n
    \n \n
      \n
    1.                         o.__class__.__name__)
      ...
    2. \n
    \n \n
      \n \n
    1. \n \n
    2.     def encode(self, o):
    3. \n \n
    4.         """Return a JSON string representation of a Python data structure.
    5. \n \n
    6. \n \n
    7.         >>> from json.encoder import JSONEncoder
    8. \n \n
    9.         >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
    10. \n \n
    \n \n
    \n \n \n \n
    \n \n Local vars\n \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    VariableValue
    o
    <Reference: Reference object (012087345981)>
    self
    <rest_framework.utils.encoders.JSONEncoder object at 0x7f0586abfd30>
    \n \n
  • \n \n
\n
\n
\n \n
\n \n \n \n \n \n

\n \n
\n
\n
\n \n \n \n
\n

Request information

\n \n \n \n

USER

\n

AnonymousUser

\n \n \n

GET

\n \n

No GET data

\n \n \n

POST

\n \n

No POST data

\n \n

FILES

\n \n

No FILES data

\n \n \n \n

COOKIES

\n \n

No cookie data

\n \n \n

META

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
VariableValue
CONTENT_LENGTH
'1292'
CONTENT_TYPE
'application/json'
DJANGO_CONFIGURATION
'Local'
DJANGO_SECRET_KEY
'local'
DJANGO_SETTINGS_MODULE
'pkdb_app.config'
GATEWAY_INTERFACE
'CGI/1.1'
GPG_KEY
'0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D'
HOME
'/root'
HOSTNAME
'83fb6011203b'
HTTP_ACCEPT
'application/coreapi+json, application/vnd.coreapi+json, */*'
HTTP_ACCEPT_ENCODING
'gzip, deflate'
HTTP_CONNECTION
'keep-alive'
HTTP_HOST
'0.0.0.0:8000'
HTTP_USER_AGENT
'coreapi'
LANG
'C.UTF-8'
PATH
'/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PATH_INFO
'/api/v1/studies/'
PWD
'/code'
PYTHONUNBUFFERED
'1'
PYTHON_PIP_VERSION
'10.0.1'
PYTHON_VERSION
'3.6.6'
QUERY_STRING
''
REMOTE_ADDR
'172.22.0.1'
REMOTE_HOST
''
REQUEST_METHOD
'POST'
RUN_MAIN
'true'
SCRIPT_NAME
''
SERVER_NAME
'83fb6011203b'
SERVER_PORT
'8000'
SERVER_PROTOCOL
'HTTP/1.1'
SERVER_SOFTWARE
'WSGIServer/0.2'
SHLVL
'1'
TZ
'UTC'
_
'./manage.py'
wsgi.errors
<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
wsgi.file_wrapper
''
wsgi.input
<_io.BufferedReader name=5>
wsgi.multiprocess
False
wsgi.multithread
True
wsgi.run_once
False
wsgi.url_scheme
'http'
wsgi.version
(1, 0)
\n \n \n

Settings

\n

Using settings module pkdb_app.config

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
SettingValue
ABSOLUTE_URL_OVERRIDES
{}
ADMINS
(('Author', 'janekg89@hotmail.de'),)
ALLOWED_HOSTS
['*']
APPEND_SLASH
False
AUTHENTICATION_BACKENDS
['django.contrib.auth.backends.ModelBackend']
AUTH_PASSWORD_VALIDATORS
'********************'
AUTH_USER_MODEL
'users.User'
CACHES
{'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
CACHE_MIDDLEWARE_ALIAS
'default'
CACHE_MIDDLEWARE_KEY_PREFIX
'********************'
CACHE_MIDDLEWARE_SECONDS
600
CONFIGURATION
'pkdb_app.config.Local'
CSRF_COOKIE_AGE
31449600
CSRF_COOKIE_DOMAIN
None
CSRF_COOKIE_HTTPONLY
False
CSRF_COOKIE_NAME
'csrftoken'
CSRF_COOKIE_PATH
'/'
CSRF_COOKIE_SECURE
False
CSRF_FAILURE_VIEW
'django.views.csrf.csrf_failure'
CSRF_HEADER_NAME
'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS
[]
CSRF_USE_SESSIONS
False
DATABASES
{'default': {'ATOMIC_REQUESTS': False,\n                           'AUTOCOMMIT': True,\n                           'CONN_MAX_AGE': 600,\n                           'ENGINE': 'django.db.backends.postgresql_psycopg2',\n                           'HOST': 'postgres',\n                           'NAME': 'postgres',\n                           'OPTIONS': {},\n                           'PASSWORD': '********************',\n                           'PORT': 5432,\n                           'TEST': {'CHARSET': None,\n                                    'COLLATION': None,\n                                    'MIRROR': None,\n                                    'NAME': None},\n                           'TIME_ZONE': None,\n                           'USER': 'postgres'}}
DATABASE_ROUTERS
[]
DATA_UPLOAD_MAX_MEMORY_SIZE
2621440
DATA_UPLOAD_MAX_NUMBER_FIELDS
1000
DATETIME_FORMAT
'N j, Y, P'
DATETIME_INPUT_FORMATS
['%Y-%m-%d %H:%M:%S',\n               '%Y-%m-%d %H:%M:%S.%f',\n               '%Y-%m-%d %H:%M',\n               '%Y-%m-%d',\n               '%m/%d/%Y %H:%M:%S',\n               '%m/%d/%Y %H:%M:%S.%f',\n               '%m/%d/%Y %H:%M',\n               '%m/%d/%Y',\n               '%m/%d/%y %H:%M:%S',\n               '%m/%d/%y %H:%M:%S.%f',\n               '%m/%d/%y %H:%M',\n               '%m/%d/%y']
DATE_FORMAT
'N j, Y'
DATE_INPUT_FORMATS
['%Y-%m-%d',\n               '%m/%d/%Y',\n               '%m/%d/%y',\n               '%b %d %Y',\n               '%b %d, %Y',\n               '%d %b %Y',\n               '%d %b, %Y',\n               '%B %d %Y',\n               '%B %d, %Y',\n               '%d %B %Y',\n               '%d %B, %Y']
DEBUG
True
DEBUG_PROPAGATE_EXCEPTIONS
False
DECIMAL_SEPARATOR
'.'
DEFAULT_CHARSET
'utf-8'
DEFAULT_CONTENT_TYPE
'text/html'
DEFAULT_EXCEPTION_REPORTER_FILTER
'django.views.debug.SafeExceptionReporterFilter'
DEFAULT_FILE_STORAGE
'django.core.files.storage.FileSystemStorage'
DEFAULT_FROM_EMAIL
'webmaster@localhost'
DEFAULT_INDEX_TABLESPACE
''
DEFAULT_TABLESPACE
''
DISALLOWED_USER_AGENTS
[]
DOTENV_LOADED
None
EMAIL_BACKEND
'django.core.mail.backends.console.EmailBackend'
EMAIL_HOST
'localhost'
EMAIL_HOST_PASSWORD
'********************'
EMAIL_HOST_USER
''
EMAIL_PORT
1025
EMAIL_SSL_CERTFILE
None
EMAIL_SSL_KEYFILE
'********************'
EMAIL_SUBJECT_PREFIX
'[Django] '
EMAIL_TIMEOUT
None
EMAIL_USE_LOCALTIME
False
EMAIL_USE_SSL
False
EMAIL_USE_TLS
False
FILE_CHARSET
'utf-8'
FILE_UPLOAD_DIRECTORY_PERMISSIONS
None
FILE_UPLOAD_HANDLERS
['django.core.files.uploadhandler.MemoryFileUploadHandler',\n               'django.core.files.uploadhandler.TemporaryFileUploadHandler']
FILE_UPLOAD_MAX_MEMORY_SIZE
2621440
FILE_UPLOAD_PERMISSIONS
None
FILE_UPLOAD_TEMP_DIR
None
FIRST_DAY_OF_WEEK
0
FIXTURE_DIRS
[]
FORCE_SCRIPT_NAME
None
FORMAT_MODULE_PATH
None
FORM_RENDERER
'django.forms.renderers.DjangoTemplates'
IGNORABLE_404_URLS
[]
INSTALLED_APPS
('django.contrib.admin',\n               'django.contrib.auth',\n               'django.contrib.contenttypes',\n               'django.contrib.sessions',\n               'django.contrib.messages',\n               'django.contrib.staticfiles',\n               'rest_framework',\n               'rest_framework.authtoken',\n               'django_filters',\n               'rest_framework_swagger',\n               'pkdb_app.users',\n               'pkdb_app.studies',\n               'pkdb_app.subjects',\n               'pkdb_app.interventions',\n               'django_nose')
INTERNAL_IPS
[]
LANGUAGES
[('af', 'Afrikaans'),\n               ('ar', 'Arabic'),\n               ('ast', 'Asturian'),\n               ('az', 'Azerbaijani'),\n               ('bg', 'Bulgarian'),\n               ('be', 'Belarusian'),\n               ('bn', 'Bengali'),\n               ('br', 'Breton'),\n               ('bs', 'Bosnian'),\n               ('ca', 'Catalan'),\n               ('cs', 'Czech'),\n               ('cy', 'Welsh'),\n               ('da', 'Danish'),\n               ('de', 'German'),\n               ('dsb', 'Lower Sorbian'),\n               ('el', 'Greek'),\n               ('en', 'English'),\n               ('en-au', 'Australian English'),\n               ('en-gb', 'British English'),\n               ('eo', 'Esperanto'),\n               ('es', 'Spanish'),\n               ('es-ar', 'Argentinian Spanish'),\n               ('es-co', 'Colombian Spanish'),\n               ('es-mx', 'Mexican Spanish'),\n               ('es-ni', 'Nicaraguan Spanish'),\n               ('es-ve', 'Venezuelan Spanish'),\n               ('et', 'Estonian'),\n               ('eu', 'Basque'),\n               ('fa', 'Persian'),\n               ('fi', 'Finnish'),\n               ('fr', 'French'),\n               ('fy', 'Frisian'),\n               ('ga', 'Irish'),\n               ('gd', 'Scottish Gaelic'),\n               ('gl', 'Galician'),\n               ('he', 'Hebrew'),\n               ('hi', 'Hindi'),\n               ('hr', 'Croatian'),\n               ('hsb', 'Upper Sorbian'),\n               ('hu', 'Hungarian'),\n               ('ia', 'Interlingua'),\n               ('id', 'Indonesian'),\n               ('io', 'Ido'),\n               ('is', 'Icelandic'),\n               ('it', 'Italian'),\n               ('ja', 'Japanese'),\n               ('ka', 'Georgian'),\n               ('kab', 'Kabyle'),\n               ('kk', 'Kazakh'),\n               ('km', 'Khmer'),\n               ('kn', 'Kannada'),\n               ('ko', 'Korean'),\n               ('lb', 'Luxembourgish'),\n               ('lt', 'Lithuanian'),\n               ('lv', 'Latvian'),\n               ('mk', 'Macedonian'),\n               ('ml', 'Malayalam'),\n               ('mn', 'Mongolian'),\n               ('mr', 'Marathi'),\n               ('my', 'Burmese'),\n               ('nb', 'Norwegian Bokm\\u00e5l'),\n               ('ne', 'Nepali'),\n               ('nl', 'Dutch'),\n               ('nn', 'Norwegian Nynorsk'),\n               ('os', 'Ossetic'),\n               ('pa', 'Punjabi'),\n               ('pl', 'Polish'),\n               ('pt', 'Portuguese'),\n               ('pt-br', 'Brazilian Portuguese'),\n               ('ro', 'Romanian'),\n               ('ru', 'Russian'),\n               ('sk', 'Slovak'),\n               ('sl', 'Slovenian'),\n               ('sq', 'Albanian'),\n               ('sr', 'Serbian'),\n               ('sr-latn', 'Serbian Latin'),\n               ('sv', 'Swedish'),\n               ('sw', 'Swahili'),\n               ('ta', 'Tamil'),\n               ('te', 'Telugu'),\n               ('th', 'Thai'),\n               ('tr', 'Turkish'),\n               ('tt', 'Tatar'),\n               ('udm', 'Udmurt'),\n               ('uk', 'Ukrainian'),\n               ('ur', 'Urdu'),\n               ('vi', 'Vietnamese'),\n               ('zh-hans', 'Simplified Chinese'),\n               ('zh-hant', 'Traditional Chinese')]
LANGUAGES_BIDI
['he', 'ar', 'fa', 'ur']
LANGUAGE_CODE
'en-us'
LANGUAGE_COOKIE_AGE
None
LANGUAGE_COOKIE_DOMAIN
None
LANGUAGE_COOKIE_NAME
'django_language'
LANGUAGE_COOKIE_PATH
'/'
LOCALE_PATHS
[]
LOGGING
{'disable_existing_loggers': False,\n               'filters': {'require_debug_true': {'()': 'django.utils.log.RequireDebugTrue'}},\n               'formatters': {'django.server': {'()': 'django.utils.log.ServerFormatter',\n                                                'format': '[%(server_time)s] %(message)s'},\n                              'simple': {'format': '%(levelname)s %(message)s'},\n                              'verbose': {'format': '%(levelname)s %(asctime)s %(module)s '\n                                                    '%(process)d %(thread)d %(message)s'}},\n               'handlers': {'console': {'class': 'logging.StreamHandler',\n                                        'formatter': 'simple',\n                                        'level': 'DEBUG'},\n                            'django.server': {'class': 'logging.StreamHandler',\n                                              'formatter': 'django.server',\n                                              'level': 'INFO'},\n                            'mail_admins': {'class': 'django.utils.log.AdminEmailHandler',\n                                            'level': 'ERROR'}},\n               'loggers': {'django': {'handlers': ['console'], 'propagate': True},\n                           'django.db.backends': {'handlers': ['console'], 'level': 'INFO'},\n                           'django.request': {'handlers': ['mail_admins', 'console'],\n                                              'level': 'ERROR',\n                                              'propagate': False},\n                           'django.server': {'handlers': ['django.server'],\n                                             'level': 'INFO',\n                                             'propagate': False}},\n               'version': 1}
LOGGING_CONFIG
'logging.config.dictConfig'
LOGIN_REDIRECT_URL
'/'
LOGIN_URL
'rest_framework:login'
LOGOUT_REDIRECT_URL
None
LOGOUT_URL
'rest_framework:logout'
MANAGERS
[]
MEDIA_ROOT
'/code/media'
MEDIA_URL
'/media/'
MESSAGE_STORAGE
'django.contrib.messages.storage.fallback.FallbackStorage'
MIDDLEWARE
('django.middleware.security.SecurityMiddleware',\n               'django.contrib.sessions.middleware.SessionMiddleware',\n               'django.middleware.common.CommonMiddleware',\n               'django.middleware.csrf.CsrfViewMiddleware',\n               'django.contrib.auth.middleware.AuthenticationMiddleware',\n               'django.contrib.messages.middleware.MessageMiddleware',\n               'django.middleware.clickjacking.XFrameOptionsMiddleware')
MIGRATION_MODULES
{}
MONTH_DAY_FORMAT
'F j'
NOSE_ARGS
['/code/pkdb_app',\n               '-s',\n               '--nologcapture',\n               '--with-coverage',\n               '--with-progressive',\n               '--cover-package=pkdb']
NUMBER_GROUPING
0
PASSWORD_HASHERS
'********************'
PASSWORD_RESET_TIMEOUT_DAYS
'********************'
PREPEND_WWW
False
REST_FRAMEWORK
{'DATETIME_FORMAT': '%Y-%m-%dT%H:%M:%S%z',\n               'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.SessionAuthentication',),\n               'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),\n               'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',\n               'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'],\n               'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer',\n                                            'rest_framework.renderers.BrowsableAPIRenderer'),\n               'PAGE_SIZE': 10}
ROOT_URLCONF
'pkdb_app.urls'
SECRET_KEY
'********************'
SECURE_BROWSER_XSS_FILTER
False
SECURE_CONTENT_TYPE_NOSNIFF
False
SECURE_HSTS_INCLUDE_SUBDOMAINS
False
SECURE_HSTS_PRELOAD
False
SECURE_HSTS_SECONDS
0
SECURE_PROXY_SSL_HEADER
None
SECURE_REDIRECT_EXEMPT
[]
SECURE_SSL_HOST
None
SECURE_SSL_REDIRECT
False
SERVER_EMAIL
'root@localhost'
SESSION_CACHE_ALIAS
'default'
SESSION_COOKIE_AGE
1209600
SESSION_COOKIE_DOMAIN
None
SESSION_COOKIE_HTTPONLY
True
SESSION_COOKIE_NAME
'sessionid'
SESSION_COOKIE_PATH
'/'
SESSION_COOKIE_SECURE
False
SESSION_ENGINE
'django.contrib.sessions.backends.db'
SESSION_EXPIRE_AT_BROWSER_CLOSE
False
SESSION_FILE_PATH
None
SESSION_SAVE_EVERY_REQUEST
False
SESSION_SERIALIZER
'django.contrib.sessions.serializers.JSONSerializer'
SETTINGS_MODULE
'pkdb_app.config'
SHORT_DATETIME_FORMAT
'm/d/Y P'
SHORT_DATE_FORMAT
'm/d/Y'
SIGNING_BACKEND
'django.core.signing.TimestampSigner'
SILENCED_SYSTEM_CHECKS
[]
STATICFILES_DIRS
[]
STATICFILES_FINDERS
('django.contrib.staticfiles.finders.FileSystemFinder',\n               'django.contrib.staticfiles.finders.AppDirectoriesFinder')
STATICFILES_STORAGE
'django.contrib.staticfiles.storage.StaticFilesStorage'
STATIC_ROOT
'/code/static'
STATIC_URL
'/static/'
SWAGGER_SETTINGS
{'APIS_SORTER': '********************',\n               'DOC_EXPANSION': 'list',\n               'LOGIN_URL': 'rest_framework:login',\n               'LOGOUT_URL': 'rest_framework:logout',\n               'SECURITY_DEFINITIONS': {'basic': {'type': 'basic'}},\n               'USE_SESSION_AUTH': True}
TEMPLATES
[{'APP_DIRS': True,\n                'BACKEND': 'django.template.backends.django.DjangoTemplates',\n                'DIRS': [],\n                'OPTIONS': {'context_processors': ['django.template.context_processors.debug',\n                                                   'django.template.context_processors.request',\n                                                   'django.contrib.auth.context_processors.auth',\n                                                   'django.contrib.messages.context_processors.messages']}}]
TEST_NON_SERIALIZED_APPS
[]
TEST_RUNNER
'django_nose.NoseTestSuiteRunner'
THOUSAND_SEPARATOR
','
TIME_FORMAT
'P'
TIME_INPUT_FORMATS
['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
TIME_ZONE
'UTC'
USE_ETAGS
False
USE_I18N
False
USE_L10N
True
USE_THOUSAND_SEPARATOR
False
USE_TZ
True
USE_X_FORWARDED_HOST
False
USE_X_FORWARDED_PORT
False
WSGI_APPLICATION
'pkdb_app.wsgi.application'
X_FRAME_OPTIONS
'SAMEORIGIN'
YEAR_MONTH_FORMAT
'F Y'
\n \n
\n \n
\n

\n You're seeing this error because you have DEBUG = True in your\n Django settings file. Change that to False, and Django will\n display a standard page generated by the handler for this status code.\n

\n
\n \n \n \n \"" - ] + "data": { + "text/plain": [ + "OrderedDict([('sid', '16198659'),\n", + " ('name', 'Granfors2005'),\n", + " ('groups',\n", + " [OrderedDict([('characteristic_values',\n", + " [OrderedDict([('id', 48),\n", + " ('count', 15),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 49),\n", + " ('count', 15),\n", + " ('choice', 'Y'),\n", + " ('category', 'oral_contraceptives'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 50),\n", + " ('count', 15),\n", + " ('choice', 'homo sapiens'),\n", + " ('category', 'species'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 51),\n", + " ('count', 15),\n", + " ('mean', 57.0),\n", + " ('min', 48.0),\n", + " ('max', 63.0),\n", + " ('sd', 6.0),\n", + " ('unit', 'kg'),\n", + " ('category', 'body_weight'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 52),\n", + " ('count', 15),\n", + " ('choice', 'N'),\n", + " ('category', 'smoking'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 53),\n", + " ('count', 15),\n", + " ('choice', 'Y'),\n", + " ('category', 'healthy'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 54),\n", + " ('count', 15),\n", + " ('mean', 22.0),\n", + " ('min', 18.0),\n", + " ('max', 25.0),\n", + " ('sd', 2.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('group', 3)])]),\n", + " ('name', 'Granfors2005-S2'),\n", + " ('description',\n", + " 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.'),\n", + " ('count', 15)]),\n", + " OrderedDict([('characteristic_values',\n", + " [OrderedDict([('id', 41),\n", + " ('count', 15),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 42),\n", + " ('count', 15),\n", + " ('choice', 'N'),\n", + " ('category', 'oral_contraceptives'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 43),\n", + " ('count', 15),\n", + " ('choice', 'homo sapiens'),\n", + " ('category', 'species'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 44),\n", + " ('count', 15),\n", + " ('mean', 62.0),\n", + " ('min', 52.0),\n", + " ('max', 74.0),\n", + " ('sd', 10.0),\n", + " ('unit', 'kg'),\n", + " ('category', 'body_weight'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 45),\n", + " ('count', 15),\n", + " ('choice', 'N'),\n", + " ('category', 'smoking'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 46),\n", + " ('count', 15),\n", + " ('choice', 'Y'),\n", + " ('category', 'healthy'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 47),\n", + " ('count', 15),\n", + " ('mean', 22.0),\n", + " ('min', 19.0),\n", + " ('max', 26.0),\n", + " ('sd', 2.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('group', 2)])]),\n", + " ('name', 'Granfors2005-S1'),\n", + " ('description',\n", + " 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.'),\n", + " ('count', 15)])]),\n", + " ('reference', '16198659')])" + ] + }, + "execution_count": 534, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ diff --git a/pkdb_app/data_management/create_master.py b/pkdb_app/data_management/create_reference.py similarity index 75% rename from pkdb_app/data_management/create_master.py rename to pkdb_app/data_management/create_reference.py index 641132bc..98178f84 100644 --- a/pkdb_app/data_management/create_master.py +++ b/pkdb_app/data_management/create_reference.py @@ -2,6 +2,7 @@ Creates json files in master folder """ import os +import shutil import csv import sys import bonobo @@ -18,6 +19,8 @@ DATABASEPATH = os.path.join(BASEPATH, "data") REFERENCESPATH = os.path.join(DATABASEPATH, "caffeine", "Studies.tsv") SUBJECTSPATH = os.path.join(DATABASEPATH, "caffeine", "Subjects.tsv") +LITERATUREPATH = os.path.join(DATABASEPATH, "caffeine", "literature") + PHARMACOKINETICSPATH = os.path.join(DATABASEPATH, "caffeine", "Pharmacokinetics.tsv") INTERVENTIONSPATH = os.path.join(DATABASEPATH, "caffeine", "Interventions.tsv") DOSINGPATH = os.path.join(DATABASEPATH, "caffeine", "Dosing.tsv") @@ -25,6 +28,11 @@ REFERENCESMASTERPATH = os.path.join(MASTERPATH, "Studies") +def ensure_dir(file_path): + directory = os.path.dirname(file_path) + if not os.path.exists(directory): + os.makedirs(directory) + def extract_references(path): reader = csv.DictReader(open(path), delimiter='\t') for line in reader: @@ -33,16 +41,18 @@ def extract_references(path): def pmid_to_int(d): d['pmid'] = int(d['pmid']) + d['sid'] = int(d['pmid']) + yield d def add_reference_sid(d): sid = str(d["study"]) - yield {**d , 'sid': sid} + yield {**d , 'name': sid} def add_reference_path(d): - reference_path = os.path.join(REFERENCESMASTERPATH, d['sid']) + reference_path = os.path.join(REFERENCESMASTERPATH, d['name']) return {**d, "reference_path":reference_path} @@ -58,10 +68,12 @@ def xml_to_data(d): yield {**d, 'data': ET.fromstring(d['xml'])} + def create_json(d): json_dict = {} - json_dict["groups"] = [] + #json_dict["groups"] = [] json_dict["pmid"] = d["pmid"] + json_dict["name"] = d["name"] json_dict["sid"] = d["sid"] for date in d["data"].iter("DateCompleted"): year = date.find('Year').text @@ -100,10 +112,30 @@ def add_doi(d): return {"json":json_dict, "reference_path": d["reference_path"]} def save_json(d): - json_file = os.path.join(d["reference_path"],"data.json") + json_file = os.path.join(d["reference_path"],"reference.json") + ensure_dir(json_file) with open(json_file, 'w') as fp: json.dump(d['json'],fp, indent=4) +def add_resources(d): + """ + inputs the result of "add_reference_path()" from add reference path + :param d: + :return: + """ + for file in os.listdir(LITERATUREPATH): + if file.startswith(d['name']): + src = os.path.join(LITERATUREPATH,file) + dst = os.path.join(d["reference_path"],file) + ensure_dir(dst) + shutil.copy(src,dst) + + + +collect_reference = [extract_references(REFERENCESPATH), + pmid_to_int, + add_reference_sid, + add_reference_path,] def get_graph(**options): """ Bonobo execution graph. @@ -112,17 +144,21 @@ def get_graph(**options): :return: """ graph = bonobo.Graph() + + #adds reference to + graph.add_chain(*collect_reference) + graph.add_chain( - extract_references(REFERENCESPATH), - pmid_to_int, - add_reference_sid, - add_reference_path, load_from_biopython, xml_to_data, create_json, add_doi, save_json, - ) + _input= add_reference_path) + + + graph.add_chain(add_resources, _input= add_reference_path) + return graph diff --git a/pkdb_app/data_management/create_subjects.py b/pkdb_app/data_management/create_study.py similarity index 68% rename from pkdb_app/data_management/create_subjects.py rename to pkdb_app/data_management/create_study.py index 9f955ba7..75de553e 100644 --- a/pkdb_app/data_management/create_subjects.py +++ b/pkdb_app/data_management/create_study.py @@ -1,36 +1,36 @@ """ Creates json files in master folder """ -from fill_database import get_reference_json_path,open_json -from create_master import SUBJECTSPATH, save_json, add_reference_path +from create_reference import collect_reference, add_reference_path, SUBJECTSPATH, ensure_dir from categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE import bonobo import pandas as pd import numpy as np -import math +import json +import os -def subjects_load(json_reference): +def study_load(reference): data_pd = pd.read_csv(SUBJECTSPATH,delimiter='\t') - this_data = data_pd[data_pd["reference"] == json_reference["json"]["sid"]] - json = {**json_reference["json"]} + this_data = data_pd[data_pd["reference"] == reference["name"]] + json = {"sid": reference["sid"]} + json["name"] = reference["name"] + json["reference"] = reference["sid"] json["groups"] = [] - for name, row in this_data.iterrows(): - yield {"json": json, "group": row.to_dict()} - - + for name, row in this_data.iterrows(): + yield {"json": json, "group": row.to_dict(),"reference": reference} def add_subject_to_json(data): group = {} group["count"] = data["group"]["count"] - group["sid"] = f'{data["json"]["sid"]}-{data["group"]["groups"]}' + group["name"] = f'{data["json"]["name"]}-{data["group"]["groups"]}' group["description"] = data["group"]["description"] group["characteristic_values"] = add_characteristic_values(data["group"]) json = {**data["json"]} json["groups"].append(group) - return {"json":json, "reference_path":add_reference_path(json)["reference_path"]} + return {"json":json, "study_path":data["reference"]["reference_path"]} def add_characteristic_values(group): @@ -39,12 +39,13 @@ def add_characteristic_values(group): for characteristics_value in process_characteristic_values(group,category): temp_characteristics_value = {**characteristics_value} for key in ["category","count"]: - temp_characteristics_value.pop(key) - if not all(value is None for value in temp_characteristics_value.values()): + temp_characteristics_value.pop(key,None) + if not all(value is None for value in temp_characteristics_value.values()): characteristics_values.append(characteristics_value) return characteristics_values + def remove_nans(group): for key, value in group.items(): if value is np.NaN: @@ -61,11 +62,13 @@ def remove_nans(group): group[key] = None - +def clean_dict(d): + return {k: v for k, v in d.items() if v is not None} def process_characteristic_values(group,category): remove_nans(group) + this_value = str(group.get(category,"")) if "|" in this_value: @@ -74,18 +77,19 @@ def process_characteristic_values(group,category): for count_and_choice in counts_and_choices: count , choice = count_and_choice.split() this_group = {**group} - this_group["count"] = count - this_group[category] = choice + this_group["new_count"] = count + this_group[category] = choice characteristic_values += process_characteristic_values(this_group,category) return characteristic_values elif this_value.strip().replace('.','',1).isdigit() or CHARACTERISTIC_DTYPE[category] == "numeric": numeric_data = {} numeric_data["category"] = category - #numeric_data["choice"] = None - numeric_data["count"] = group["count"] - if numeric_data["count"] > 1: + if "new_count" in group: + numeric_data["count"] = group["new_count"] + + if group["count"] > 1: numeric_data["mean"] = group.get(category, None) numeric_data["median"] = group.get(f"{category}_median",None) numeric_data["min"] = group.get(f"{category}_min",None) @@ -97,22 +101,28 @@ def process_characteristic_values(group,category): else: numeric_data["float"] = group.get(category, None) - return [numeric_data] + return [clean_dict(numeric_data)] else: categorical_data = {} - categorical_data["count"] = group.get("count",None) + if "new_count" in group: + categorical_data["count"] = group["new_count"] + categorical_data["category"] = category categorical_data["choice"] = group.get(category,None) - return [categorical_data] - + return [clean_dict(categorical_data)] +def save_json(d): + json_file = os.path.join(d["study_path"],"study.json") + ensure_dir(json_file) + with open(json_file, 'w') as fp: + json.dump(d['json'],fp, indent=4) @@ -120,13 +130,17 @@ def process_characteristic_values(group,category): def get_graph(**options): graph = bonobo.Graph() - # add studies + + # add reference information + graph.add_chain(*collect_reference) + graph.add_chain() + + #add studies graph.add_chain( - get_reference_json_path, - open_json, - subjects_load, + study_load, add_subject_to_json, save_json, + _input=add_reference_path, ) return graph diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 46fbdf3e..7f15b047 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -2,7 +2,7 @@ import bonobo import coreapi import json -from create_master import REFERENCESMASTERPATH +from create_reference import REFERENCESMASTERPATH client = coreapi.Client() document = client.get("http://0.0.0.0:8000/") @@ -10,30 +10,50 @@ def get_reference_json_path(): for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): - if "data.json" in files: - yield os.path.join(root, 'data.json') + if "reference.json" in files: + yield os.path.join(root, 'reference.json') +def get_study_json_path(): + for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): + if "study.json" in files: + yield os.path.join(root, 'study.json') -def open_json(d): +def open_reference(d): with open(d) as f: json_dict = json.loads(f.read()) return {"json":json_dict, "reference_path":d} +def open_study(d): + with open(d) as f: + json_dict = json.loads(f.read()) + return {"json":json_dict, "study_path":d} def upload_reference(json_reference): client.action(document, ["references", "create"], params=json_reference["json"]) +def upload_study(json_study): + client.action(document, ["studies", "create"], params=json_study["json"]) -def get_graph(**options): +def get_graph_references(**options): graph = bonobo.Graph() # add studies graph.add_chain( get_reference_json_path, - open_json, + open_reference, upload_reference, ) return graph +def get_graph_study(**options): + graph = bonobo.Graph() + # add studies + graph.add_chain( + get_study_json_path, + open_study, + upload_study, + ) + return graph + def get_services(**options): return {} @@ -42,4 +62,6 @@ def get_services(**options): if __name__ == '__main__': parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: - bonobo.run(get_graph(**options), services=get_services(**options)) + bonobo.run(get_graph_references(**options), services=get_services(**options)) + bonobo.run(get_graph_study(**options), services=get_services(**options)) + diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 8ecd34a1..070609cf 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -10,6 +10,7 @@ def update_or_create(self, *args, **kwargs): group, created = super(GroupManager, self).update_or_create(*args, **kwargs) group.characteristic_values.all().delete() for characteristic_value in characteristic_values: + characteristic_value["count"] = characteristic_value.get("count",group.count) group.characteristic_values.create(**characteristic_value) group.save() diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index e12a5166..d18491c0 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -8,6 +8,8 @@ class CharacteristicValueSerializer(serializers.ModelSerializer): + count = serializers.IntegerField(required=False) + class Meta: model = CharacteristicValue fields = "__all__" @@ -29,6 +31,12 @@ def create(self, validated_data): return group def to_representation(self, instance): + """ + this method reduces the serialized output to not non-values. + :param instance: + :return: + """ result = super().to_representation(instance) return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + From afe3d2b30a63c62500bb502d10f0822e9d4d900f Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Jul 2018 14:46:10 +0200 Subject: [PATCH 020/115] working on schemas --- docs/api/api.ipynb | 85 +++++++++++++++++++++++ pkdb_app/data_management/fill_database.py | 4 ++ pkdb_app/data_management/schemas.py | 16 +++++ requirements.txt | 2 +- 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 pkdb_app/data_management/schemas.py diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index 25d09d80..d03da387 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -751,6 +751,91 @@ "client.action(document, [\"groups\", \"create\"], params=group_dict)" ] }, + { + "cell_type": "code", + "execution_count": 538, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[int, str, str, str, str, str, str, list, str]" + ] + }, + "execution_count": 538, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[type(item) for item in reference_dict.values()]" + ] + }, + { + "cell_type": "code", + "execution_count": 541, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'pmid': 12087394589,\n", + " 'sid': '012087345981',\n", + " 'name': 'Haller2002',\n", + " 'date': '2002-07-18',\n", + " 'journal': 'Clinical pharmacology and therapeutics',\n", + " 'title': 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.',\n", + " 'abstract': 'Botanical stimgle dose.',\n", + " 'authors': [{'first_name': 'Christine asdin', 'last_name': 'Haller'},\n", + " {'first_name': 'Peyton', 'last_name': 'Jacob'},\n", + " {'first_name': 'Neal L', 'last_name': 'Benowitz'}],\n", + " 'doi': ''}" + ] + }, + "execution_count": 541, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reference_dict" + ] + }, + { + "cell_type": "code", + "execution_count": 540, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{}" + ] + }, + "execution_count": 540, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from jsonschema import validate\n", + "reference_schema = {\n", + " \"pmid\": {\"type\" : \"number\"},\n", + " \"name\": {\"type\" : \"string\"},\n", + " \"sid\": {\"type\" : \"number\"},\n", + " \"date\": {\"type\" : \"string\"},\n", + " \"journal\": {\"type\" : \"string\"},\n", + " # \"title\": {\"type\" : \"string\"},\n", + " \"abstract\": {\"type\" : \"string\"},\n", + " \"authors\": {\"type\" : \"array\"},\n", + " \"doi\": {\"type\" : \"string\"}\n", + "}\n", + "\n", + "validate(reference_dict,reference_schema)\n", + "\n", + "{}" + ] + }, { "cell_type": "code", "execution_count": 359, diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 7f15b047..455b1572 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -3,6 +3,8 @@ import coreapi import json from create_reference import REFERENCESMASTERPATH +from jsonschema import validate +from schemas import reference_schema client = coreapi.Client() document = client.get("http://0.0.0.0:8000/") @@ -25,10 +27,12 @@ def open_reference(d): def open_study(d): with open(d) as f: + json_dict = json.loads(f.read()) return {"json":json_dict, "study_path":d} def upload_reference(json_reference): + validate(json_reference["json"],reference_schema) client.action(document, ["references", "create"], params=json_reference["json"]) def upload_study(json_study): diff --git a/pkdb_app/data_management/schemas.py b/pkdb_app/data_management/schemas.py new file mode 100644 index 00000000..76125649 --- /dev/null +++ b/pkdb_app/data_management/schemas.py @@ -0,0 +1,16 @@ + +reference_schema = { + "properties": { + "pmid": {"type": "number"}, + "name": {"type": "string"}, + "sid": {"type": ["number", "string"]}, + "date": {"type": "string"}, + "journal": {"type": "string"}, + "title": {"type": "string"}, + "abstract": {"type": "string"}, + "authors": {"type": "array"}, + "doi": {"type": "string"} + + } + +} diff --git a/requirements.txt b/requirements.txt index dff5a6a1..32ea5f91 100644 --- a/requirements.txt +++ b/requirements.txt @@ -44,4 +44,4 @@ bonobo-docker biopython ipykernel pandas - +jsonschema From 886859a8eb9fd309d9ec1e707bd841d00f533e02 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Tue, 24 Jul 2018 16:29:06 +0200 Subject: [PATCH 021/115] additional categorials and inclusion/exclusion criteria --- README.md | 13 ++--- pkdb_app/categoricals.py | 94 +++++++++++++++++++++++++------------ pkdb_app/studies/models.py | 11 ++--- pkdb_app/subjects/models.py | 25 +++++++++- 4 files changed, 98 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 752cdf1f..38960ff4 100644 --- a/README.md +++ b/README.md @@ -53,23 +53,24 @@ docker-compose run --rm web ./manage.py createsuperuser # Update after code change ``` +# reset migrations +sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete + +# rebuild container docker-compose down docker-compose up --build ``` -reset migrations -``` -sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete -``` + # Fill database +From console use the following ``` workon pkdb (pkdb) pip install -r requirements.txt --upgrade (pkdb) python ./pkdb_app/data_management/fill_database.py - -docker-compose run --rm web ./data_management/fill_database.py ``` + # Connect database pycharm ``` DataSource -> postgres diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 02f95aa5..cc27719c 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -7,22 +7,30 @@ In the future the relationship between the characteristics could be implemented via an ontology which represents the relationship between the differnent values. + + +units on CharacteristicType is an ordered iteratable, with the first unit being the default unit. + """ # TODO: How to handle the genetic information? Genetic variants? from collections import namedtuple -CharacteristicType = namedtuple("CharacteristicType", ["value", "category", "dtype", "choices"]) +CharacteristicType = namedtuple("CharacteristicType", ["value", "category", "dtype", "choices", "units"]) UnitType = namedtuple("UnitType", ["name"]) # TODO: lookup units package and proper units handling (units conversion, default units, ...) UNIT_DATA = [ UnitType('-'), - UnitType('cm'), UnitType('m'), + UnitType('cm'), + UnitType('m'), UnitType('kg'), UnitType('yr'), UnitType('kg/m^2'), UnitType('1/day'), + UnitType('IU/I'), + UnitType('mg/dl'), + UnitType('g/dl') ] UNITS_CHOICES = [(utype.name, utype.name) for utype in UNIT_DATA] @@ -41,44 +49,76 @@ NO = 'N' BOOLEAN_CHOICES = [YES, NO] +# categories +DEMOGRAPHICS = "Demographics" # age, sex, ethnicity +ANTHROPOMETRY = "Anthropometry" # height, weight, waist bmi +SPECIES = "Species" +BIOCHEMICAL_DATA = "Biochemical data" +HEMATOLOGY_DATA = "Hematology data" + + +INCLUSION_CRITERIA = "InclusionCriteria" +EXCLUSION_CRITERIA = "ExclusionCriteria" +GROUP_CRITERIA = "GroupCriteria" +CHARACTERISTIC_VALUE_TYPES = [INCLUSION_CRITERIA, EXCLUSION_CRITERIA, GROUP_CRITERIA] +CHARACTERISTIC_VALUE_CHOICES = [(t.name, t.name) for t in CHARACTERISTIC_VALUE_TYPES] + + +STUDY_DESIGN_DATA = [ + "single group (interventional study)", + "parallel group (interventional study)", + "crossover (interventional study)", + "cohort (oberservational study)", + "case control (oberservational study)", +] +STUDY_DESIGN_CHOICES = [(t.name, t.name) for t in STUDY_DESIGN_DATA] + COMMON_DATA = [ # Medication - CharacteristicType('oral_contraceptives', 'Contraceptives', BOOLEAN_TYPE, BOOLEAN_CHOICES), - CharacteristicType('oral_contraceptives_amount', 'Contraceptives', NUMERIC_TYPE, None), - CharacteristicType('medication', 'Medication', CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"]), # ? dosing + CharacteristicType('oral_contraceptives', 'Contraceptives', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('oral_contraceptives_amount', 'Contraceptives', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('medication', 'Medication', CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"], ["-"]), # ? dosing # Lifestyle - CharacteristicType('caffeine', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES), - CharacteristicType('caffeine_amount', 'Lifestyle', NUMERIC_TYPE, None), + CharacteristicType('caffeine', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('caffeine_amount', 'Lifestyle', NUMERIC_TYPE, None, ["-"]), ] -CHARACTERISTIC_DATA = COMMON_DATA+ [ +CHARACTERISTIC_DATA = COMMON_DATA + [ # Antropmetrical information - CharacteristicType('species', 'Species', CATEGORIAL_TYPE, ["Homo sapiens"]), - CharacteristicType('height', 'BodyParameter', NUMERIC_TYPE, None), - CharacteristicType('body_weight', 'BodyParameter', NUMERIC_TYPE, None), - CharacteristicType('age', 'BodyParameter', NUMERIC_TYPE, None), - CharacteristicType('sex', 'BodyParameter', CATEGORIAL_TYPE, ["M", "F"]), - CharacteristicType('bmi', 'BodyParameter', NUMERIC_TYPE, None), - CharacteristicType('waist_circumference', 'BodyParameter', NUMERIC_TYPE, None), - CharacteristicType('ethnicity', 'Ethnicity', CATEGORIAL_TYPE, ["african", "afroamerican", "asian", "caucasian"]), + CharacteristicType('species', SPECIES, CATEGORIAL_TYPE, ["Homo sapiens"], ["-"]), + CharacteristicType('height', ANTHROPOMETRY, NUMERIC_TYPE, None, ["cm", 'm']), + CharacteristicType('weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["kg"]), + CharacteristicType('bmi', ANTHROPOMETRY, NUMERIC_TYPE, None, ["kg/m^2"]), + CharacteristicType('waist_circumference', ANTHROPOMETRY, NUMERIC_TYPE, None, ["cm"]), + CharacteristicType('liver_weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), + CharacteristicType('kidney_weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), + + CharacteristicType('age', DEMOGRAPHICS, NUMERIC_TYPE, None, ["yr"]), + CharacteristicType('sex', DEMOGRAPHICS, CATEGORIAL_TYPE, ["M", "F"], ["-"]), + CharacteristicType('ethnicity', DEMOGRAPHICS, CATEGORIAL_TYPE, ["African", "Afroamerican", "Asian", "Caucasian"], ["-"]), + # Disease (status) - CharacteristicType('healthy', "Health status", BOOLEAN_TYPE, BOOLEAN_CHOICES), - CharacteristicType('disease', "Disease", CATEGORIAL_TYPE, ["cirrhosis"]), + CharacteristicType('healthy', "Health status", BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('disease', "Disease", CATEGORIAL_TYPE, ["cirrhosis"], ["-"]), # Lifestyle - CharacteristicType('smoking', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES), - CharacteristicType('smoking_amount', 'Lifestyle', NUMERIC_TYPE, None), - CharacteristicType('alcohol', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES), - CharacteristicType('alcohol_amount', 'Lifestyle', NUMERIC_TYPE, None), + CharacteristicType('smoking', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('smoking_amount', 'Lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('alcohol', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('alcohol_amount', 'Lifestyle', NUMERIC_TYPE, None, ["-"]), + # Biochemical data + CharacteristicType('ALT', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["IU/I"]), + CharacteristicType('AST', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["IU/I"]), + CharacteristicType('Albumin', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["g/dl"]), # Study protocol - CharacteristicType('overnight_fast', 'Study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES), - CharacteristicType('alcohol_abstinence', 'Study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES), + CharacteristicType('overnight_fast', 'Study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('alcohol_abstinence', 'Study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), # Medication @@ -91,11 +131,7 @@ # class, value, dtype (numeric, boolean, categorial), choices PROTOCOL_DATA = [ - - CharacteristicType('dosing', 'Dosing', NUMERIC_TYPE, None), - - - + CharacteristicType('dosing', 'Dosing', NUMERIC_TYPE, None, ["-"]), ] def dict_and_choices(data): diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index c6e377d2..9b6d29b1 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -4,6 +4,7 @@ from django.db import models from pkdb_app.utils import CHAR_MAX_LENGTH from pkdb_app.behaviours import Sidable, Describable, Commentable +from pkdb_app.categoricals import STUDY_DESIGN_CHOICES class Author(models.Model): @@ -32,7 +33,6 @@ class Reference(models.Model): This is the main class describing the publication or reference which describes the study. In most cases this is a published paper, but could be a thesis or unpublished. """ - pmid = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) #optional sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key=True, default=pmid) name = models.CharField(max_length=CHAR_MAX_LENGTH) @@ -45,19 +45,14 @@ class Reference(models.Model): authors = models.ManyToManyField(Author, blank=True, related_name='references') - - - - class Study(Sidable, Commentable, Describable, models.Model): """ Single clinical study. Mainly reported as a single publication. - """ - reference = models.ForeignKey(Reference, on_delete=True, to_field="sid",db_column="reference_sid", related_name='studies', null=True, blank=True) + reference = models.ForeignKey(Reference, on_delete=True, to_field="sid", db_column="reference_sid", related_name='studies', null=True, blank=True) name = models.CharField(max_length=CHAR_MAX_LENGTH) - #todo:study design, observational sudy ... + design = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True, choices=STUDY_DESIGN_CHOICES) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 89eea4d7..2f0a8722 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -10,7 +10,8 @@ from ..studies.models import Study, Reference from ..behaviours import Sidable, Describable, Valueable -from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES +from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, CHARACTERISTIC_VALUE_CHOICES, GROUP_CRITERIA, \ + INCLUSION_CRITERIA, EXCLUSION_CRITERIA from ..utils import CHAR_MAX_LENGTH from .managers import GroupManager @@ -47,7 +48,17 @@ def reference(self): class Characteristic(models.Model): """ Characteristic. - Characteristics are used to store the information about subjects. + + Characteristics are used to store information about a group of subjects. + Such a group is defined by + - Inclusion criteria, which define general characteristics (often via cutoffs, i.e. min or max) of which + subjects are in a group. + - Exclusion criteria, analogue to inclusion criteria but defines which subjects are excluded. + - Group criteria, concrete properties/characteristics of the group of subjects. + + The type of characteristic is defined via the cvtype. + When group characterists are curated it is important to specify the inclusion/exclusion criteria in + addition to the group criteria. """ category = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) @@ -73,7 +84,15 @@ class CharacteristicValue(Valueable, Characteristic): This stores the raw information. Derived values can be calculated. """ group = models.ForeignKey(Group, related_name="characteristic_values", null=True, on_delete=True) + cvtype = models.CharField(choices=CHARACTERISTIC_VALUE_CHOICES, max_length=CHAR_MAX_LENGTH, default=GROUP_CRITERIA) + + @property + def is_inclusion(self): + return self.cvtype == INCLUSION_CRITERIA + @property + def is_exclusion(self): + return self.cvtype == EXCLUSION_CRITERIA #def validate(self): # """ Check that choices are valid. I.e. that choice is allowed choice from choices for @@ -90,6 +109,8 @@ class CharacteristicValue(Valueable, Characteristic): class ProcessedCharacteristicValue(Valueable, Characteristic, models.Model): """ Processed and normalized data (calculated on change from corresponding raw CharacteristicValue. + + - convert exclusion to inclusion criteria """ raw = models.ForeignKey(CharacteristicValue, null=True, on_delete=True) # method field? for different processing? From fa1bf048193bec2249f916d880e528877b053be3 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Tue, 24 Jul 2018 17:18:10 +0200 Subject: [PATCH 022/115] work on protocol --- pkdb_app/interventions/models.py | 81 +++++++++++++++----------------- pkdb_app/studies/models.py | 10 ++++ 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 4d178b27..c51e0233 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -25,13 +25,12 @@ # Simple pharmacokinetics - # How to represent the dosing? # Add separate class? extension of model? -class Protocol: - """ Selection of things which were done to the group. +class Protocol(models.Model): + """ List of things/steps which were done to the group. """ group = models.ForeignKey(Group, related_name='intervention', on_delete=True) @@ -43,18 +42,23 @@ class ProtocolStep(Sidable, Describable, models.Model): """ What is done to the group, single step. - dosing of certain substance, e.g. caffeine oral - - smoking cessation - - sports, ... - - + - sports / lifestyle change + - medication + - ... + + Examples: + Two groups (parallel group design), one group control, other group gets medication, e.g., oral contraceptives, than pharmacokinetics of caffeine measured. + -> 2 protocol + - protocol 1 (linked to control group): MedicationStep (caffeine) + - protocol 2 (linked to intervention group): MedicationStep (oral contraceptives), MedicationStep (caffeine) + """ # TODO: MedicationStep & LifestyleStep # FIXME: Important to find the subset of dosing protocols - category = models.IntegerField(choices=PROTOCOL_CHOICES) - @property def Intervention_data(self): """ Returns the full information about the characteristic. @@ -70,9 +74,12 @@ def choices(self): class Meta: abstract = True -''' class MedicationStep(Valueable, ProtocolStep): # choices, dose, unit (per_bodyweitght is not important) + """ Dosing. + + The actual dosing is stored in the Valueable. + """ substance: # what was given [' route: # where ['oral', 'iv'] @@ -82,49 +89,27 @@ class MedicationStep(Valueable, ProtocolStep): # choices, dose, unit (per_bodyw form_details: # h details -class Substance(Ontologable): - """ +class Substance(models.Model): + """ Substances have to be in a different table, so that + than be uniquely defined. + + Has to be extended via ontology (Ontologable) + """ name # example caffeine # ontologies: has set of defined values: is, CHEBI:27732 -class ProtocolValue(Valueable, Protocol): - pass - - #def validate(self): - # """ Check that choices are valid. I.e. that choice is allowed choice from choices for - # Interventions. - - # Add checks for individuals and groups. For instance if count==1 than value must be filled, - # but not entries in mean, median, ... - - # :return: - # """ - # raise NotImplemented - -class DatasetFile(): - """ Table or figure from where the data comes from. - - """ - file = models.FileField(upload_to="output", null=True, blank=True) # table or figure - +# ----------------- +# RESULTS +# ----------------- # Create your models here. class Output(Sidable, Describable, models.Model): """ Storage of data sets. """ protocol = models.ForeignKey(Protocol) - file = models.ForeignKey(DatasetFile) - - -class Timecourse(Output): - """ Storing of time course data. - - Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). - """ - data = models.BinaryField() - - + # files from which the data was extracted, these have to be linked to the study already should be PNG or NONE + files = models.ForeignKey(DataFile) class Pharmacokinetics(Output, Valueable): """ Measured value (calculated value via ProcessedPharmacokinetics) @@ -135,13 +120,23 @@ class Pharmacokinetics(Output, Valueable): tissue # where was it measured +class Timecourse(Output): + """ Storing of time course data. + + Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). + """ + substance + tissue + data = models.ForeignKey(DataFile) # link to the CSV + + +''' class ProcessedPharmacokinetics(): """ Calculated from pharmacokinetics or timecourse data. """ rawid = models.ForeignKey(Pharmacokinetics) type # ['normalized', 'timecourse-derived'] - ''' diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 9b6d29b1..03cc70bf 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -54,7 +54,17 @@ class Study(Sidable, Commentable, Describable, models.Model): name = models.CharField(max_length=CHAR_MAX_LENGTH) design = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True, choices=STUDY_DESIGN_CHOICES) + # TODO: substances, e.g. caffeine, acetaminophen + # TODO: datafiles (DataFile) +# TODO: substances here +class DataFile(models.Model): + """ Table or figure from where the data comes from (png). + + This should be in a separate class, so that they can be easily displayed/filtered/... + """ + file = models.FileField(upload_to="output", null=True, blank=True) # table or figure + filetype # XLSX, PNG, CSV \ No newline at end of file From 96810b725153e3ff59de096f046e05b83ee11c58 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Tue, 24 Jul 2018 17:21:03 +0200 Subject: [PATCH 023/115] categorial choice added --- pkdb_app/categoricals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index cc27719c..4e2a6860 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -132,6 +132,7 @@ # class, value, dtype (numeric, boolean, categorial), choices PROTOCOL_DATA = [ CharacteristicType('dosing', 'Dosing', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('smoking_cessation', 'Lifestyle', NUMERIC_TYPE, None, ["-"]), ] def dict_and_choices(data): From 2a15a2d1517c47cbb3b28a6db739165f24944b32 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Jul 2018 18:08:45 +0200 Subject: [PATCH 024/115] added intervention model, however not fully functional --- docs/api/api.ipynb | 34 +++++++++++------- pkdb_app/categoricals.py | 4 +-- pkdb_app/interventions/models.py | 61 ++++++++++++++++++-------------- pkdb_app/studies/models.py | 22 ++++++------ pkdb_app/subjects/managers.py | 2 +- 5 files changed, 68 insertions(+), 55 deletions(-) diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index d03da387..de7219c9 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -373,7 +373,9 @@ { "cell_type": "code", "execution_count": 517, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "# Create study\n", @@ -803,7 +805,7 @@ }, { "cell_type": "code", - "execution_count": 540, + "execution_count": 543, "metadata": {}, "outputs": [ { @@ -812,7 +814,7 @@ "{}" ] }, - "execution_count": 540, + "execution_count": 543, "metadata": {}, "output_type": "execute_result" } @@ -820,15 +822,19 @@ "source": [ "from jsonschema import validate\n", "reference_schema = {\n", - " \"pmid\": {\"type\" : \"number\"},\n", - " \"name\": {\"type\" : \"string\"},\n", - " \"sid\": {\"type\" : \"number\"},\n", - " \"date\": {\"type\" : \"string\"},\n", - " \"journal\": {\"type\" : \"string\"},\n", - " # \"title\": {\"type\" : \"string\"},\n", - " \"abstract\": {\"type\" : \"string\"},\n", - " \"authors\": {\"type\" : \"array\"},\n", - " \"doi\": {\"type\" : \"string\"}\n", + " \"properties\":{\n", + " \"pmid\": {\"type\" : \"number\"},\n", + " \"name\": {\"type\" : \"string\"},\n", + " \"sid\": {\"type\" : [\"number\",\"string\"]},\n", + " \"date\": {\"type\" : \"string\"},\n", + " \"journal\": {\"type\" : \"string\"},\n", + " \"title\": {\"type\" : \"string\"},\n", + " \"abstract\": {\"type\" : \"string\"},\n", + " \"authors\": {\"type\" : \"array\"},\n", + " \"doi\": {\"type\" : \"string\"}\n", + " \n", + " }\n", + " \n", "}\n", "\n", "validate(reference_dict,reference_schema)\n", @@ -852,7 +858,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "client.action(document, [\"references\", \"list\"])" diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 4e2a6860..0c72e467 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -61,7 +61,7 @@ EXCLUSION_CRITERIA = "ExclusionCriteria" GROUP_CRITERIA = "GroupCriteria" CHARACTERISTIC_VALUE_TYPES = [INCLUSION_CRITERIA, EXCLUSION_CRITERIA, GROUP_CRITERIA] -CHARACTERISTIC_VALUE_CHOICES = [(t.name, t.name) for t in CHARACTERISTIC_VALUE_TYPES] +CHARACTERISTIC_VALUE_CHOICES = [(t, t) for t in CHARACTERISTIC_VALUE_TYPES] STUDY_DESIGN_DATA = [ @@ -71,7 +71,7 @@ "cohort (oberservational study)", "case control (oberservational study)", ] -STUDY_DESIGN_CHOICES = [(t.name, t.name) for t in STUDY_DESIGN_DATA] +STUDY_DESIGN_CHOICES = [(t, t) for t in STUDY_DESIGN_DATA] COMMON_DATA = [ diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index c51e0233..bd6b8474 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -8,6 +8,7 @@ from ..behaviours import Sidable, Describable, Valueable from ..categoricals import PROTOCOL_CHOICES, UNITS_CHOICES from ..subjects.models import Group +from ..studies.models import DataFile from ..utils import CHAR_MAX_LENGTH # ------------------------------------------------- @@ -29,13 +30,6 @@ # Add separate class? extension of model? -class Protocol(models.Model): - """ List of things/steps which were done to the group. - - """ - group = models.ForeignKey(Group, related_name='intervention', on_delete=True) - # set of protocols - # name (control, fluvoxamine, control-fluvo, fluvo-control) class ProtocolStep(Sidable, Describable, models.Model): @@ -80,14 +74,28 @@ class MedicationStep(Valueable, ProtocolStep): # choices, dose, unit (per_bodyw The actual dosing is stored in the Valueable. """ + substance = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) #substance: # what was given [' + route = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # route: # where ['oral', 'iv'] + application = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # application: # how timing ['single dose', 'multiple doses', 'continuous injection'] + application_time = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) + form = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # form: # how medication [capusle, tablete] + form_details = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) #form_details: # h details + +class ProcessedMedicationStep(Valueable, ProtocolStep): + """ Calculated from medicationstep + """ + raw = models.ForeignKey(MedicationStep, null=True, on_delete=True) - substance: # what was given [' - route: # where ['oral', 'iv'] - application: # how timing ['single dose', 'multiple doses', 'continuous injection'] - application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) - form: # how medication [capusle, tablete] - form_details: # h details +class Protocol(models.Model): + """ List of things/steps which were done to the group. + + """ + group = models.ForeignKey(Group, related_name='intervention', on_delete=True) + protokol_steps = models.ManyToManyField(MedicationStep) + name = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) + # set of protocols + # name (control, fluvoxamine, control-fluvo, fluvo-control) class Substance(models.Model): """ Substances have to be in a different table, so that @@ -96,7 +104,8 @@ class Substance(models.Model): Has to be extended via ontology (Ontologable) """ - name # example caffeine + name = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) + #name # example caffeine # ontologies: has set of defined values: is, CHEBI:27732 @@ -107,17 +116,17 @@ class Substance(models.Model): # Create your models here. class Output(Sidable, Describable, models.Model): """ Storage of data sets. """ - protocol = models.ForeignKey(Protocol) + protocol = models.ForeignKey(Protocol,on_delete=True) # files from which the data was extracted, these have to be linked to the study already should be PNG or NONE - files = models.ForeignKey(DataFile) + files = models.ForeignKey(DataFile, on_delete=True) class Pharmacokinetics(Output, Valueable): """ Measured value (calculated value via ProcessedPharmacokinetics) category: [clearance, vd, thalf, cmax, ...] """ - substance = models.ForeignKey(Substance) - tissue # where was it measured + substance = models.ForeignKey(Substance, on_delete=True) + #tissue # where was it measured class Timecourse(Output): @@ -125,19 +134,17 @@ class Timecourse(Output): Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). """ - substance - tissue - data = models.ForeignKey(DataFile) # link to the CSV + #substance + #tissue + data = models.ForeignKey(DataFile, on_delete=True) # link to the CSV -''' -class ProcessedPharmacokinetics(): +class ProcessedPharmacokinetics(Valueable): """ Calculated from pharmacokinetics or timecourse data. - """ - rawid = models.ForeignKey(Pharmacokinetics) - type # ['normalized', 'timecourse-derived'] -''' + raw = models.ForeignKey(Pharmacokinetics, null=True, on_delete=True) + type = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # ['normalized', 'timecourse-derived'] + diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 03cc70bf..ce20dfa1 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -15,11 +15,6 @@ def __str__(self): return '%s %s' % (self.id, self.first_name, self.last_name) -class Files(models.Model): - name = models.CharField(max_length=CHAR_MAX_LENGTH) - file = models.FileField(null=True, blank=True) - - class KeyWord(models.Model): """ This class describes the keyowrds / tags of a publication or any other reference. @@ -45,6 +40,15 @@ class Reference(models.Model): authors = models.ManyToManyField(Author, blank=True, related_name='references') +class DataFile(models.Model): + """ Table or figure from where the data comes from (png). + + This should be in a separate class, so that they can be easily displayed/filtered/... + """ + + file = models.FileField(upload_to="output", null=True, blank=True) # table or figure + filetype = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # XLSX, PNG, CSV + class Study(Sidable, Commentable, Describable, models.Model): """ Single clinical study. @@ -53,6 +57,7 @@ class Study(Sidable, Commentable, Describable, models.Model): reference = models.ForeignKey(Reference, on_delete=True, to_field="sid", db_column="reference_sid", related_name='studies', null=True, blank=True) name = models.CharField(max_length=CHAR_MAX_LENGTH) design = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True, choices=STUDY_DESIGN_CHOICES) + raw_data = models.ManyToManyField(DataFile) # TODO: substances, e.g. caffeine, acetaminophen # TODO: datafiles (DataFile) @@ -61,10 +66,3 @@ class Study(Sidable, Commentable, Describable, models.Model): # TODO: substances here -class DataFile(models.Model): - """ Table or figure from where the data comes from (png). - - This should be in a separate class, so that they can be easily displayed/filtered/... - """ - file = models.FileField(upload_to="output", null=True, blank=True) # table or figure - filetype # XLSX, PNG, CSV \ No newline at end of file diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 070609cf..9a38ff96 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -10,7 +10,7 @@ def update_or_create(self, *args, **kwargs): group, created = super(GroupManager, self).update_or_create(*args, **kwargs) group.characteristic_values.all().delete() for characteristic_value in characteristic_values: - characteristic_value["count"] = characteristic_value.get("count",group.count) + characteristic_value["count"] = characteristic_value.get("count",group.count) group.characteristic_values.create(**characteristic_value) group.save() From e5a8c8b98855f19138c0f9228afd7f654199be21 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 25 Jul 2018 11:50:24 +0200 Subject: [PATCH 025/115] working on intervention serializer --- docs/api/api.ipynb | 1731 ++++++++++++++++++++++--- pkdb_app/interventions/models.py | 2 +- pkdb_app/interventions/serializers.py | 18 + pkdb_app/subjects/serializers.py | 5 +- 4 files changed, 1545 insertions(+), 211 deletions(-) create mode 100644 pkdb_app/interventions/serializers.py diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index de7219c9..d95e0465 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -13,7 +13,7 @@ }, { "cell_type": "code", - "execution_count": 500, + "execution_count": 544, "metadata": { "collapsed": true }, @@ -24,7 +24,7 @@ }, { "cell_type": "code", - "execution_count": 501, + "execution_count": 545, "metadata": { "collapsed": true }, @@ -40,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": 502, + "execution_count": 546, "metadata": { "collapsed": true }, @@ -51,7 +51,7 @@ }, { "cell_type": "code", - "execution_count": 503, + "execution_count": 547, "metadata": { "collapsed": true }, @@ -71,7 +71,7 @@ }, { "cell_type": "code", - "execution_count": 504, + "execution_count": 548, "metadata": { "collapsed": true }, @@ -85,7 +85,7 @@ }, { "cell_type": "code", - "execution_count": 505, + "execution_count": 549, "metadata": {}, "outputs": [ { @@ -106,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 506, + "execution_count": 550, "metadata": {}, "outputs": [ { @@ -124,18 +124,18 @@ " }\n", " characteristic_values: {\n", " list([page], [choice], [count], [category], [search])\n", - " create(count, category, [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [group])\n", + " create(category, [count], [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [cvtype], [group])\n", " read(id, [choice], [count], [category], [search])\n", - " update(id, count, category, [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [group], [choice], [count], [category], [search])\n", - " partial_update(id, [choice], [count], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [category], [group], [choice], [count], [category], [search])\n", + " update(id, category, [count], [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [cvtype], [group], [choice], [count], [category], [search])\n", + " partial_update(id, [count], [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [category], [cvtype], [group], [choice], [count], [category], [search])\n", " delete(id, [choice], [count], [category], [search])\n", " }\n", " groups: {\n", " list([page], [description], [search])\n", - " create(characteristic_values, name, count, [description])\n", + " create(name, count, characteristic_values, intervention, [description])\n", " read(id, [description], [search])\n", - " update(id, characteristic_values, name, count, [description], [description], [search])\n", - " partial_update(id, [characteristic_values], [name], [description], [count], [description], [search])\n", + " update(id, name, count, characteristic_values, intervention, [description], [description], [search])\n", + " partial_update(id, [name], [count], [description], [characteristic_values], [intervention], [description], [search])\n", " delete(id, [description], [search])\n", " }\n", " references: {\n", @@ -172,7 +172,7 @@ }, { "cell_type": "code", - "execution_count": 507, + "execution_count": 551, "metadata": {}, "outputs": [ { @@ -180,10 +180,61 @@ "output_type": "stream", "text": [ "{\n", - " \"count\": 0,\n", - " \"next\": null,\n", + " \"count\": 108,\n", + " \"next\": \"http://0.0.0.0:8000/api/v1/authors/?page=2\",\n", " \"previous\": null,\n", - " \"results\": []\n", + " \"results\": [\n", + " {\n", + " \"id\": 1,\n", + " \"first_name\": \"Lucek\",\n", + " \"last_name\": \"Grzegorzewski\"\n", + " },\n", + " {\n", + " \"id\": 2,\n", + " \"first_name\": \"Christine asdin\",\n", + " \"last_name\": \"Haller\"\n", + " },\n", + " {\n", + " \"id\": 43,\n", + " \"first_name\": \"W\",\n", + " \"last_name\": \"Zilly\"\n", + " },\n", + " {\n", + " \"id\": 78,\n", + " \"first_name\": \"A H\",\n", + " \"last_name\": \"Neims\"\n", + " },\n", + " {\n", + " \"id\": 79,\n", + " \"first_name\": \"M\",\n", + " \"last_name\": \"Bonati\"\n", + " },\n", + " {\n", + " \"id\": 44,\n", + " \"first_name\": \"E\",\n", + " \"last_name\": \"Richter\"\n", + " },\n", + " {\n", + " \"id\": 80,\n", + " \"first_name\": \"R\",\n", + " \"last_name\": \"Latini\"\n", + " },\n", + " {\n", + " \"id\": 81,\n", + " \"first_name\": \"F\",\n", + " \"last_name\": \"Galletti\"\n", + " },\n", + " {\n", + " \"id\": 45,\n", + " \"first_name\": \"K-Y\",\n", + " \"last_name\": \"Seng\"\n", + " },\n", + " {\n", + " \"id\": 46,\n", + " \"first_name\": \"C-Y\",\n", + " \"last_name\": \"Fun\"\n", + " }\n", + " ]\n", "}\n" ] } @@ -202,7 +253,7 @@ }, { "cell_type": "code", - "execution_count": 508, + "execution_count": 552, "metadata": {}, "outputs": [ { @@ -250,7 +301,7 @@ }, { "cell_type": "code", - "execution_count": 510, + "execution_count": 553, "metadata": {}, "outputs": [ { @@ -258,14 +309,34 @@ "output_type": "stream", "text": [ "{\n", - " \"count\": 1,\n", + " \"count\": 5,\n", " \"next\": null,\n", " \"previous\": null,\n", " \"results\": [\n", " {\n", + " \"id\": 6,\n", + " \"first_name\": \"L\",\n", + " \"last_name\": \"Granit\"\n", + " },\n", + " {\n", + " \"id\": 55,\n", + " \"first_name\": \"D J\",\n", + " \"last_name\": \"Greenblatt\"\n", + " },\n", + " {\n", + " \"id\": 11,\n", + " \"first_name\": \"Marika T\",\n", + " \"last_name\": \"Granfors\"\n", + " },\n", + " {\n", " \"id\": 1,\n", " \"first_name\": \"Lucek\",\n", " \"last_name\": \"Grzegorzewski\"\n", + " },\n", + " {\n", + " \"id\": 38,\n", + " \"first_name\": \"David J\",\n", + " \"last_name\": \"Greenblatt\"\n", " }\n", " ]\n", "}\n" @@ -281,7 +352,7 @@ }, { "cell_type": "code", - "execution_count": 511, + "execution_count": 554, "metadata": {}, "outputs": [ { @@ -305,11 +376,10 @@ " ('last_name', 'Jacob')]),\n", " OrderedDict([('id', 4),\n", " ('first_name', 'Neal L'),\n", - " ('last_name', 'Benowitz')])]),\n", - " ('pdf', None)])" + " ('last_name', 'Benowitz')])])])" ] }, - "execution_count": 511, + "execution_count": 554, "metadata": {}, "output_type": "execute_result" } @@ -349,19 +419,1414 @@ }, { "cell_type": "code", - "execution_count": 512, + "execution_count": 555, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "OrderedDict([('count', 0),\n", - " ('next', None),\n", + "OrderedDict([('count', 26),\n", + " ('next', 'http://0.0.0.0:8000/api/v1/studies/?page=2'),\n", " ('previous', None),\n", - " ('results', [])])" + " ('results',\n", + " [OrderedDict([('sid', '19023902'),\n", + " ('name', 'test'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'Seng2009-S_NCNS'),\n", + " ('count', 14),\n", + " ('description',\n", + " '59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean ± SD) 21 ± 2 years, body weight 62 ± 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 ± 4 years, body weight 69 ± 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 ± 4 cigarettes daily, age 23 ± 5 years, body weight 71 ± 19 kg).'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 9),\n", + " ('count', 14),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 1)]),\n", + " OrderedDict([('id', 10),\n", + " ('count', 14),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 1)]),\n", + " OrderedDict([('id', 11),\n", + " ('count', 14),\n", + " ('mean', 62.0),\n", + " ('sd', 9.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 1)]),\n", + " OrderedDict([('id', 12),\n", + " ('count', 14),\n", + " ('choice', 'Asian'),\n", + " ('category',\n", + " 'ethnicity'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 1)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '012087345981')]),\n", + " OrderedDict([('sid', '16198659'),\n", + " ('name', 'Granfors2005'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'Granfors2005-S2'),\n", + " ('count', 15),\n", + " ('description',\n", + " 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1853),\n", + " ('count', 15),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 1854),\n", + " ('count', 15),\n", + " ('mean', 57.0),\n", + " ('min', 48.0),\n", + " ('max', 63.0),\n", + " ('sd', 6.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 1855),\n", + " ('count', 15),\n", + " ('mean', 22.0),\n", + " ('min', 18.0),\n", + " ('max', 25.0),\n", + " ('sd', 2.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 1856),\n", + " ('count', 15),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 1857),\n", + " ('count', 15),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 1858),\n", + " ('count', 15),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 3)]),\n", + " OrderedDict([('id', 1859),\n", + " ('count', 15),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 3)])]),\n", + " ('intervention', [])]),\n", + " OrderedDict([('name', 'Granfors2005-S1'),\n", + " ('count', 15),\n", + " ('description',\n", + " 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1846),\n", + " ('count', 15),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 1847),\n", + " ('count', 15),\n", + " ('mean', 62.0),\n", + " ('min', 52.0),\n", + " ('max', 74.0),\n", + " ('sd', 10.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 1848),\n", + " ('count', 15),\n", + " ('mean', 22.0),\n", + " ('min', 19.0),\n", + " ('max', 26.0),\n", + " ('sd', 2.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 1849),\n", + " ('count', 15),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 1850),\n", + " ('count', 15),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 1851),\n", + " ('count', 15),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 2)]),\n", + " OrderedDict([('id', 1852),\n", + " ('count', 15),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 2)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '16198659')]),\n", + " OrderedDict([('sid', '6734043'),\n", + " ('name', 'ZylberKatz1984'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'ZylberKatz1984-S2'),\n", + " ('count', 3),\n", + " ('description',\n", + " 'Subjects were 7 healthy men and 5 women ranging in age from 22 to 47 years. All were nonsmokers and reported only casual alcohol consumption, and none were taking any medication. Habitual daily coffee intake varied from 1 to 6 cups. Results of blood biochemistry (SMAC12) were normal in all.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1814),\n", + " ('count', 3),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 5)]),\n", + " OrderedDict([('id', 1815),\n", + " ('count', 3),\n", + " ('mean', 70.33),\n", + " ('min', 58.0),\n", + " ('max', 91.0),\n", + " ('sd', 14.7),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 5)]),\n", + " OrderedDict([('id', 1816),\n", + " ('count', 3),\n", + " ('mean', 27.33),\n", + " ('min', 24.0),\n", + " ('max', 30.0),\n", + " ('sd', 2.49),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 5)]),\n", + " OrderedDict([('id', 1817),\n", + " ('count', 3),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 5)]),\n", + " OrderedDict([('id', 1818),\n", + " ('count', 3),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 5)]),\n", + " OrderedDict([('id', 1819),\n", + " ('count', 3),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 5)]),\n", + " OrderedDict([('id', 1820),\n", + " ('count', 2),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 5)]),\n", + " OrderedDict([('id', 1821),\n", + " ('count', 1),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 5)])]),\n", + " ('intervention', [])]),\n", + " OrderedDict([('name', 'ZylberKatz1984-S1'),\n", + " ('count', 5),\n", + " ('description',\n", + " 'Subjects were 7 healthy men and 5 women ranging in age from 22 to 47 years. All were nonsmokers and reported only casual alcohol consumption, and none were taking any medication. Habitual daily coffee intake varied from 1 to 6 cups. Results of blood biochemistry (SMAC12) were normal in all.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1806),\n", + " ('count', 5),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 4)]),\n", + " OrderedDict([('id', 1807),\n", + " ('count', 5),\n", + " ('mean', 76.2),\n", + " ('min', 60.0),\n", + " ('max', 88.0),\n", + " ('sd', 12.1),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 4)]),\n", + " OrderedDict([('id', 1808),\n", + " ('count', 5),\n", + " ('mean', 41.6),\n", + " ('min', 29.0),\n", + " ('max', 47.0),\n", + " ('sd', 6.44),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 4)]),\n", + " OrderedDict([('id', 1809),\n", + " ('count', 5),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 4)]),\n", + " OrderedDict([('id', 1810),\n", + " ('count', 5),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 4)]),\n", + " OrderedDict([('id', 1811),\n", + " ('count', 5),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 4)]),\n", + " OrderedDict([('id', 1812),\n", + " ('count', 3),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 4)]),\n", + " OrderedDict([('id', 1813),\n", + " ('count', 2),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 4)])]),\n", + " ('intervention', [])]),\n", + " OrderedDict([('name', 'ZylberKatz1984-S3'),\n", + " ('count', 4),\n", + " ('description',\n", + " 'Subjects were 7 healthy men and 5 women ranging in age from 22 to 47 years. All were nonsmokers and reported only casual alcohol consumption, and none were taking any medication. Habitual daily coffee intake varied from 1 to 6 cups. Results of blood biochemistry (SMAC12) were normal in all.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1822),\n", + " ('count', 4),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 6)]),\n", + " OrderedDict([('id', 1823),\n", + " ('count', 4),\n", + " ('mean', 62.75),\n", + " ('min', 46.0),\n", + " ('max', 75.0),\n", + " ('sd', 10.9),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 6)]),\n", + " OrderedDict([('id', 1824),\n", + " ('count', 4),\n", + " ('mean', 27.25),\n", + " ('min', 22.0),\n", + " ('max', 31.0),\n", + " ('sd', 3.56),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 6)]),\n", + " OrderedDict([('id', 1825),\n", + " ('count', 4),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 6)]),\n", + " OrderedDict([('id', 1826),\n", + " ('count', 4),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 6)]),\n", + " OrderedDict([('id', 1827),\n", + " ('count', 4),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 6)]),\n", + " OrderedDict([('id', 1828),\n", + " ('count', 2),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 6)]),\n", + " OrderedDict([('id', 1829),\n", + " ('count', 2),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 6)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '6734043')]),\n", + " OrderedDict([('sid', '6832208'),\n", + " ('name', 'Blanchard1983a'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'Blanchard1983a-S1'),\n", + " ('count', 10),\n", + " ('description',\n", + " '10 healthy adult male volunteers, aged 18.8 to 30.0 years;\\nHealthy adult male Caucasian volunteers. None of the subjects were taking any prescription or non-presecription medication at time of the study.\\nEach subject was fasted from the previous evening until at least 2h after the administration of the oral dose.\\nSubjects were instructed to abstain from caffeine-containing food and beverages, tobacco (9 of the 10 subjects were non-smokers) and alcohol from 72h before, until 24h after caffeine administration.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1830),\n", + " ('count', 10),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 7)]),\n", + " OrderedDict([('id', 1831),\n", + " ('count', 10),\n", + " ('mean', 79.5),\n", + " ('min', 64.0),\n", + " ('max', 106.0),\n", + " ('se', 3.9),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 7)]),\n", + " OrderedDict([('id', 1832),\n", + " ('count', 10),\n", + " ('mean', 21.8),\n", + " ('min', 18.8),\n", + " ('max', 30.0),\n", + " ('se', 1.1),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 7)]),\n", + " OrderedDict([('id', 1833),\n", + " ('count', 10),\n", + " ('choice',\n", + " 'Caucasian'),\n", + " ('category',\n", + " 'ethnicity'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 7)]),\n", + " OrderedDict([('id', 1834),\n", + " ('count', 10),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 7)]),\n", + " OrderedDict([('id', 1835),\n", + " ('count', 10),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 7)]),\n", + " OrderedDict([('id', 1836),\n", + " ('count', 10),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 7)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '6832208')]),\n", + " OrderedDict([('sid', '12087345'),\n", + " ('name', 'Haller2002'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'Haller2002-S1'),\n", + " ('count', 8),\n", + " ('description',\n", + " 'Eight healthy volunteers (5 women and 3 men) from 25 to 38 years old participated in the study. Eligibility for the study was determined on the basis of medical history, brief physical examination, and screening laboratory tests that included complete blood count, serum chemistry values to assess liver and renal function, urine toxicology testing for drugs of abuse, and a urine pregnancy test for women. Exclusion criteria included any person with obesity (body mass index 30), or a history of heart, thyroid, liver, kidney, or psychiatric disease, diabetes, central nervous system disorders, prostate hypertrophy, narrow angle glaucoma, or pregnancy or lactation. Any person with recent use (previous 1 month) of any product that contained ephedrine alkaloids or with a history of illicit substance use within the previous year was excluded. Smokers and heavy users of caffeine (4 cups of coffee per day) were excluded. Participants were not taking any medications that would cause changes in heart rate or blood pressure.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1837),\n", + " ('count', 8),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 8)]),\n", + " OrderedDict([('id', 1838),\n", + " ('count', 8),\n", + " ('mean', 68.49),\n", + " ('min', 52.0),\n", + " ('max', 88.9),\n", + " ('sd', 12.24),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 8)]),\n", + " OrderedDict([('id', 1839),\n", + " ('count', 8),\n", + " ('min', 25.0),\n", + " ('max', 38.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 8)]),\n", + " OrderedDict([('id', 1840),\n", + " ('count', 8),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 8)]),\n", + " OrderedDict([('id', 1841),\n", + " ('count', 2),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 8)]),\n", + " OrderedDict([('id', 1842),\n", + " ('count', 5),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 8)]),\n", + " OrderedDict([('id', 1843),\n", + " ('count', 8),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 8)]),\n", + " OrderedDict([('id', 1844),\n", + " ('count', 3),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 8)]),\n", + " OrderedDict([('id', 1845),\n", + " ('count', 5),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 8)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '12087345')]),\n", + " OrderedDict([('sid', '6420303'),\n", + " ('name', 'Renner1984'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'Renner1984-S1'),\n", + " ('count', 10),\n", + " ('description',\n", + " '10 healthy volunteers (information in table 2)'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1860),\n", + " ('count', 4),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 9)]),\n", + " OrderedDict([('id', 1861),\n", + " ('count', 6),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 9)]),\n", + " OrderedDict([('id', 1862),\n", + " ('count', 10),\n", + " ('mean', 74.0),\n", + " ('min', 58.0),\n", + " ('max', 86.0),\n", + " ('sd', 10.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 9)]),\n", + " OrderedDict([('id', 1863),\n", + " ('count', 10),\n", + " ('mean', 38.0),\n", + " ('min', 27.0),\n", + " ('max', 56.0),\n", + " ('sd', 11.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 9)]),\n", + " OrderedDict([('id', 1864),\n", + " ('count', 10),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 9)]),\n", + " OrderedDict([('id', 1865),\n", + " ('count', 10),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 9)]),\n", + " OrderedDict([('id', 1866),\n", + " ('count', 10),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 9)]),\n", + " OrderedDict([('id', 1867),\n", + " ('count', 10),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 9)])]),\n", + " ('intervention', [])]),\n", + " OrderedDict([('name', 'Renner1984-S2'),\n", + " ('count', 8),\n", + " ('description',\n", + " '8 patients with cirrhotic liver disease (information in table 1)'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1868),\n", + " ('count', 5),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 10)]),\n", + " OrderedDict([('id', 1869),\n", + " ('count', 3),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 10)]),\n", + " OrderedDict([('id', 1870),\n", + " ('count', 8),\n", + " ('mean', 66.0),\n", + " ('min', 41.0),\n", + " ('max', 100.0),\n", + " ('sd', 18.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 10)]),\n", + " OrderedDict([('id', 1871),\n", + " ('count', 8),\n", + " ('mean', 55.0),\n", + " ('min', 34.0),\n", + " ('max', 66.0),\n", + " ('sd', 10.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 10)]),\n", + " OrderedDict([('id', 1872),\n", + " ('count', 8),\n", + " ('choice',\n", + " 'cirrhotic liver disease'),\n", + " ('category',\n", + " 'disease'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 10)]),\n", + " OrderedDict([('id', 1873),\n", + " ('count', 8),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 10)]),\n", + " OrderedDict([('id', 1874),\n", + " ('count', 8),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 10)]),\n", + " OrderedDict([('id', 1875),\n", + " ('count', 6),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 10)]),\n", + " OrderedDict([('id', 1876),\n", + " ('count', 2),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 10)])]),\n", + " ('intervention', [])]),\n", + " OrderedDict([('name', 'Renner1984-S3'),\n", + " ('count', 7),\n", + " ('description',\n", + " '7 patients with PBC (information in table 1)'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1877),\n", + " ('count', 7),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 11)]),\n", + " OrderedDict([('id', 1878),\n", + " ('count', 7),\n", + " ('mean', 57.0),\n", + " ('min', 49.0),\n", + " ('max', 68.0),\n", + " ('sd', 8.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 11)]),\n", + " OrderedDict([('id', 1879),\n", + " ('count', 7),\n", + " ('mean', 56.0),\n", + " ('min', 42.0),\n", + " ('max', 73.0),\n", + " ('sd', 13.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 11)]),\n", + " OrderedDict([('id', 1880),\n", + " ('count', 7),\n", + " ('choice', 'PBC'),\n", + " ('category',\n", + " 'disease'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 11)]),\n", + " OrderedDict([('id', 1881),\n", + " ('count', 7),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 11)]),\n", + " OrderedDict([('id', 1882),\n", + " ('count', 7),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 11)]),\n", + " OrderedDict([('id', 1883),\n", + " ('count', 7),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 11)])]),\n", + " ('intervention', [])]),\n", + " OrderedDict([('name', 'Renner1984-S4'),\n", + " ('count', 11),\n", + " ('description',\n", + " '11 patients with miscellaneous liver disease (information in table 1)'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1884),\n", + " ('count', 9),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 12)]),\n", + " OrderedDict([('id', 1885),\n", + " ('count', 2),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 12)]),\n", + " OrderedDict([('id', 1886),\n", + " ('count', 11),\n", + " ('mean', 81.0),\n", + " ('min', 55.0),\n", + " ('max', 118.0),\n", + " ('sd', 19.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 12)]),\n", + " OrderedDict([('id', 1887),\n", + " ('count', 11),\n", + " ('mean', 52.0),\n", + " ('min', 24.0),\n", + " ('max', 71.0),\n", + " ('sd', 12.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 12)]),\n", + " OrderedDict([('id', 1888),\n", + " ('count', 11),\n", + " ('choice',\n", + " 'Miscellaneous Liver Disease'),\n", + " ('category',\n", + " 'disease'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 12)]),\n", + " OrderedDict([('id', 1889),\n", + " ('count', 11),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 12)]),\n", + " OrderedDict([('id', 1890),\n", + " ('count', 11),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 12)]),\n", + " OrderedDict([('id', 1891),\n", + " ('count', 9),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 12)]),\n", + " OrderedDict([('id', 1892),\n", + " ('count', 2),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 12)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '6420303')]),\n", + " OrderedDict([('sid', '7371463'),\n", + " ('name', 'Desmond1980'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'Desmond1980-S1'),\n", + " ('count', 15),\n", + " ('description',\n", + " '15 healthy male subjects, age range 18-71 years (13 nonsmokers), with normal clinical history, physical examination, and SMA12 profile were studied'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1893),\n", + " ('count', 13),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 13)]),\n", + " OrderedDict([('id', 1894),\n", + " ('count', 2),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 13)]),\n", + " OrderedDict([('id', 1895),\n", + " ('count', 15),\n", + " ('min', 18.0),\n", + " ('max', 71.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 13)]),\n", + " OrderedDict([('id', 1896),\n", + " ('count', 15),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 13)]),\n", + " OrderedDict([('id', 1897),\n", + " ('count', 15),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 13)]),\n", + " OrderedDict([('id', 1898),\n", + " ('count', 15),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 13)]),\n", + " OrderedDict([('id', 1899),\n", + " ('count', 15),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 13)])]),\n", + " ('intervention', [])]),\n", + " OrderedDict([('name', 'Desmond1980-S2'),\n", + " ('count', 10),\n", + " ('description',\n", + " '10 male patients with cirrhosis, age range 42-60 years (6 non-smokers), were also studied. 6 subjects had alcoholic cirrhosis and 4 had postnecrotic cirrhosis; the diagnosis was established by clinical and biochemical criteria and confirmed by percutaneous liver biopsy in 9. All subjects abstained from caffeine-containing beverages and medication for at least 3 days prior to the study.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1900),\n", + " ('count', 6),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 1901),\n", + " ('count', 4),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 1902),\n", + " ('count', 10),\n", + " ('min', 42.0),\n", + " ('max', 65.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 1903),\n", + " ('count', 10),\n", + " ('choice',\n", + " 'cirrhosis'),\n", + " ('category',\n", + " 'disease'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 1904),\n", + " ('count', 10),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 1905),\n", + " ('count', 10),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 1906),\n", + " ('count', 10),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 1907),\n", + " ('count', 10),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 14)])]),\n", + " ('intervention', [])]),\n", + " OrderedDict([('name', 'Desmond1980-S3'),\n", + " ('count', 8),\n", + " ('description',\n", + " 'Subset of 8 from 10 cirrhosis patients. 10 male patients with cirrhosis, age range 42-60 years (6 non-smokers), were also studied. 6 subjects had alcoholic cirrhosis and 4 had postnecrotic cirrhosis; the diagnosis was established by clinical and biochemical criteria and confirmed by percutaneous liver biopsy in 9. All subjects abstained from caffeine-containing beverages and medication for at least 3 days prior to the study.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1908),\n", + " ('count', 8),\n", + " ('choice', 'Mixed'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 15)]),\n", + " OrderedDict([('id', 1909),\n", + " ('count', 8),\n", + " ('mean', 71.5),\n", + " ('min', 48.0),\n", + " ('max', 84.0),\n", + " ('sd', 11.1),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 15)]),\n", + " OrderedDict([('id', 1910),\n", + " ('count', 8),\n", + " ('mean', 49.6),\n", + " ('min', 42.0),\n", + " ('max', 60.0),\n", + " ('sd', 6.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 15)]),\n", + " OrderedDict([('id', 1911),\n", + " ('count', 8),\n", + " ('choice',\n", + " 'cirrhosis'),\n", + " ('category',\n", + " 'disease'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 15)]),\n", + " OrderedDict([('id', 1912),\n", + " ('count', 8),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 15)]),\n", + " OrderedDict([('id', 1913),\n", + " ('count', 8),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'oral_contraceptives'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 15)]),\n", + " OrderedDict([('id', 1914),\n", + " ('count', 8),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 15)]),\n", + " OrderedDict([('id', 1915),\n", + " ('count', 8),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 15)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '7371463')]),\n", + " OrderedDict([('sid', '4029248'),\n", + " ('name', 'Abernethy1985'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'Abernethy1985-S1'),\n", + " ('count', 9),\n", + " ('description',\n", + " 'The subjects were 18 healthy women, 23 to 30 years supplementation. The subjects were divided into two groups each of 9 for the study. One group consisted of women taking a low-dose oestrogen (50 µg or less of the oestrogen component) oral contraceptive steroid for at least 3 months and no other medication (OCS group). The other group comprised 9 women of similar age not taking any medication. In each group 8 women were Caucasian, and t was Black. History, physical and laboratory examination indicated that all subjects were in good health. All subjects were asked to abstain from caffeine consumption 48 hours prior to the study.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1916),\n", + " ('count', 9),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 16)]),\n", + " OrderedDict([('id', 1917),\n", + " ('count', 9),\n", + " ('mean', 59.0),\n", + " ('se', 2.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 16)]),\n", + " OrderedDict([('id', 1918),\n", + " ('count', 9),\n", + " ('mean', 26.0),\n", + " ('min', 23.0),\n", + " ('max', 30.0),\n", + " ('se', 1.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 16)]),\n", + " OrderedDict([('id', 1919),\n", + " ('count', 8),\n", + " ('choice',\n", + " 'Caucasian'),\n", + " ('category',\n", + " 'ethnicity'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 16)]),\n", + " OrderedDict([('id', 1920),\n", + " ('count', 1),\n", + " ('choice', 'Black'),\n", + " ('category',\n", + " 'ethnicity'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 16)]),\n", + " OrderedDict([('id', 1921),\n", + " ('count', 9),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 16)]),\n", + " OrderedDict([('id', 1922),\n", + " ('count', 9),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 16)]),\n", + " OrderedDict([('id', 1923),\n", + " ('count', 9),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 16)])]),\n", + " ('intervention', [])]),\n", + " OrderedDict([('name', 'Abernethy1985-S2'),\n", + " ('count', 9),\n", + " ('description',\n", + " 'The subjects were 18 healthy women, 23 to 30 years supplementation. The subjects were divided into two groups each of 9 for the study. One group consisted of women taking a low-dose oestrogen (50 µg or less of the oestrogen component) oral contraceptive steroid for at least 3 months and no other medication (OCS group). The other group comprised 9 women of similar age not taking any medication. In each group 8 women were Caucasian, and t was Black. History, physical and laboratory examination indicated that all subjects were in good health. All subjects were asked to abstain from caffeine consumption 48 hours prior to the study.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1924),\n", + " ('count', 9),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 17)]),\n", + " OrderedDict([('id', 1925),\n", + " ('count', 9),\n", + " ('mean', 58.0),\n", + " ('se', 3.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 17)]),\n", + " OrderedDict([('id', 1926),\n", + " ('count', 9),\n", + " ('mean', 26.0),\n", + " ('min', 23.0),\n", + " ('max', 30.0),\n", + " ('se', 1.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 17)]),\n", + " OrderedDict([('id', 1927),\n", + " ('count', 8),\n", + " ('choice',\n", + " 'Caucasian'),\n", + " ('category',\n", + " 'ethnicity'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 17)]),\n", + " OrderedDict([('id', 1928),\n", + " ('count', 1),\n", + " ('choice', 'Black'),\n", + " ('category',\n", + " 'ethnicity'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 17)]),\n", + " OrderedDict([('id', 1929),\n", + " ('count', 9),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 17)]),\n", + " OrderedDict([('id', 1930),\n", + " ('count', 9),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 17)]),\n", + " OrderedDict([('id', 1931),\n", + " ('count', 9),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 17)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '4029248')]),\n", + " OrderedDict([('sid', '10073324'),\n", + " ('name', 'Amchin1999'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'Amchin1999-S1'),\n", + " ('count', 15),\n", + " ('description',\n", + " '16 healthy volunteers (nine males and seven females) were enrolled in this study. Mean (range) age, weight, and height for the subjects were 31.1 years (21 to 41 years), 70.5 kg (47 to 93 kg), and 172 cm (157 to 183cm), respectively. Screening of sub jects, within 2 weeks of study initiation, consisted of a medical history; physical examination, including a 12- lead electrocardiogram (ECG); clinical laboratory tests; urinary drug screen; vital signs; ethanol breath test; and serum pregnancy test (females only). Exclusion criteria included women of child bearing potential or use of tobacco products within 6 months, prescription drugs within 14 days, non prescrip tion drugs within 7 days, or investigational drugs or drugs known to induce or inhibit hepatic enzymes within 30 days of study drug administration. Subjects who routinely consumed more than five 8-ounce cups of coffee (or caffeine equivalent) per day were excluded from the study. Caffeine and xanthene- containing beverages and foods, as well as charcoal- grilled foods, were strictly prohibited from the even ing of Day –2 through the morn ing of Day 9. Alcohol was prohibited from 7 days prior to the study and through out the study.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1932),\n", + " ('count', 15),\n", + " ('choice', 'N'),\n", + " ('category',\n", + " 'smoking'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 18)]),\n", + " OrderedDict([('id', 1933),\n", + " ('count', 15),\n", + " ('mean', 70.5),\n", + " ('min', 47.0),\n", + " ('max', 93.0),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'body_weight'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 18)]),\n", + " OrderedDict([('id', 1934),\n", + " ('count', 15),\n", + " ('mean', 31.1),\n", + " ('min', 21.0),\n", + " ('max', 41.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 18)]),\n", + " OrderedDict([('id', 1935),\n", + " ('count', 15),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 18)]),\n", + " OrderedDict([('id', 1936),\n", + " ('count', 15),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 18)]),\n", + " OrderedDict([('id', 1937),\n", + " ('count', 15),\n", + " ('mean', 172.0),\n", + " ('min', 157.0),\n", + " ('max', 183.0),\n", + " ('unit', 'cm'),\n", + " ('category',\n", + " 'height'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 18)]),\n", + " OrderedDict([('id', 1938),\n", + " ('count', 8),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 18)]),\n", + " OrderedDict([('id', 1939),\n", + " ('count', 7),\n", + " ('choice', 'F'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 18)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '10073324')]),\n", + " OrderedDict([('sid', '2589393'),\n", + " ('name', 'Harder1989'),\n", + " ('groups',\n", + " [OrderedDict([('name', 'Harder1989-S1'),\n", + " ('count', 12),\n", + " ('description',\n", + " 'In two consecutive studies, each in 12 healthy male volunteers (age 20-40 years), the pharmacokinetics of caffeine and its major metabolite paraxanthine alone and at the end of 4 days of treatment with several quinolones (Table 1) were investigated. Thine- free diet (no tea, coffee or chocolate) from 36 h before the first dose of caffeine until the end of the second sampling period.'),\n", + " ('characteristic_values',\n", + " [OrderedDict([('id', 1940),\n", + " ('count', 12),\n", + " ('min', 20.0),\n", + " ('max', 40.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 19)]),\n", + " OrderedDict([('id', 1941),\n", + " ('count', 12),\n", + " ('choice', 'Y'),\n", + " ('category',\n", + " 'healthy'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 19)]),\n", + " OrderedDict([('id', 1942),\n", + " ('count', 12),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('category',\n", + " 'species'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 19)]),\n", + " OrderedDict([('id', 1943),\n", + " ('count', 12),\n", + " ('choice', 'M'),\n", + " ('category', 'sex'),\n", + " ('cvtype',\n", + " 'GroupCriteria'),\n", + " ('group', 19)])]),\n", + " ('intervention', [])])]),\n", + " ('reference', '2589393')])])])" ] }, - "execution_count": 512, + "execution_count": 555, "metadata": {}, "output_type": "execute_result" } @@ -372,7 +1837,7 @@ }, { "cell_type": "code", - "execution_count": 517, + "execution_count": 556, "metadata": { "collapsed": true }, @@ -423,7 +1888,7 @@ }, { "cell_type": "code", - "execution_count": 533, + "execution_count": 557, "metadata": { "collapsed": true }, @@ -526,117 +1991,21 @@ }, { "cell_type": "code", - "execution_count": 534, + "execution_count": 558, "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "OrderedDict([('sid', '16198659'),\n", - " ('name', 'Granfors2005'),\n", - " ('groups',\n", - " [OrderedDict([('characteristic_values',\n", - " [OrderedDict([('id', 48),\n", - " ('count', 15),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 49),\n", - " ('count', 15),\n", - " ('choice', 'Y'),\n", - " ('category', 'oral_contraceptives'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 50),\n", - " ('count', 15),\n", - " ('choice', 'homo sapiens'),\n", - " ('category', 'species'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 51),\n", - " ('count', 15),\n", - " ('mean', 57.0),\n", - " ('min', 48.0),\n", - " ('max', 63.0),\n", - " ('sd', 6.0),\n", - " ('unit', 'kg'),\n", - " ('category', 'body_weight'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 52),\n", - " ('count', 15),\n", - " ('choice', 'N'),\n", - " ('category', 'smoking'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 53),\n", - " ('count', 15),\n", - " ('choice', 'Y'),\n", - " ('category', 'healthy'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 54),\n", - " ('count', 15),\n", - " ('mean', 22.0),\n", - " ('min', 18.0),\n", - " ('max', 25.0),\n", - " ('sd', 2.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('group', 3)])]),\n", - " ('name', 'Granfors2005-S2'),\n", - " ('description',\n", - " 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.'),\n", - " ('count', 15)]),\n", - " OrderedDict([('characteristic_values',\n", - " [OrderedDict([('id', 41),\n", - " ('count', 15),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 42),\n", - " ('count', 15),\n", - " ('choice', 'N'),\n", - " ('category', 'oral_contraceptives'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 43),\n", - " ('count', 15),\n", - " ('choice', 'homo sapiens'),\n", - " ('category', 'species'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 44),\n", - " ('count', 15),\n", - " ('mean', 62.0),\n", - " ('min', 52.0),\n", - " ('max', 74.0),\n", - " ('sd', 10.0),\n", - " ('unit', 'kg'),\n", - " ('category', 'body_weight'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 45),\n", - " ('count', 15),\n", - " ('choice', 'N'),\n", - " ('category', 'smoking'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 46),\n", - " ('count', 15),\n", - " ('choice', 'Y'),\n", - " ('category', 'healthy'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 47),\n", - " ('count', 15),\n", - " ('mean', 22.0),\n", - " ('min', 19.0),\n", - " ('max', 26.0),\n", - " ('sd', 2.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('group', 2)])]),\n", - " ('name', 'Granfors2005-S1'),\n", - " ('description',\n", - " 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.'),\n", - " ('count', 15)])]),\n", - " ('reference', '16198659')])" - ] - }, - "execution_count": 534, - "metadata": {}, - "output_type": "execute_result" + "ename": "ErrorMessage", + "evalue": "\n groups: [\n {\n characteristic_values: [\n {},\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {},\n {},\n {}\n ]\n intervention: [\n \"This field is required.\"\n ]\n },\n {\n characteristic_values: [\n {},\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {},\n {},\n {}\n ]\n intervention: [\n \"This field is required.\"\n ]\n }\n ]", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"studies\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mErrorMessage\u001b[0m: \n groups: [\n {\n characteristic_values: [\n {},\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {},\n {},\n {}\n ]\n intervention: [\n \"This field is required.\"\n ]\n },\n {\n characteristic_values: [\n {},\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {},\n {},\n {}\n ]\n intervention: [\n \"This field is required.\"\n ]\n }\n ]" + ] } ], "source": [ @@ -645,78 +2014,21 @@ }, { "cell_type": "code", - "execution_count": 495, + "execution_count": 562, "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "OrderedDict([('characteristic_values',\n", - " [OrderedDict([('id', 24),\n", - " ('choice', 'Asian'),\n", - " ('count', 14),\n", - " ('value', None),\n", - " ('mean', None),\n", - " ('median', None),\n", - " ('min', None),\n", - " ('max', None),\n", - " ('sd', None),\n", - " ('se', None),\n", - " ('cv', None),\n", - " ('unit', None),\n", - " ('category', 'ethnicity'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 23),\n", - " ('choice', None),\n", - " ('count', 14),\n", - " ('value', None),\n", - " ('mean', 62.0),\n", - " ('median', None),\n", - " ('min', None),\n", - " ('max', None),\n", - " ('sd', 9.0),\n", - " ('se', None),\n", - " ('cv', None),\n", - " ('unit', 'kg'),\n", - " ('category', 'body_weight'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 22),\n", - " ('choice', 'homo sapiens'),\n", - " ('count', 14),\n", - " ('value', None),\n", - " ('mean', None),\n", - " ('median', None),\n", - " ('min', None),\n", - " ('max', None),\n", - " ('sd', None),\n", - " ('se', None),\n", - " ('cv', None),\n", - " ('unit', None),\n", - " ('category', 'species'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 21),\n", - " ('choice', 'M'),\n", - " ('count', 14),\n", - " ('value', None),\n", - " ('mean', None),\n", - " ('median', None),\n", - " ('min', None),\n", - " ('max', None),\n", - " ('sd', None),\n", - " ('se', None),\n", - " ('cv', None),\n", - " ('unit', None),\n", - " ('category', 'sex'),\n", - " ('group', 3)])]),\n", - " ('name', 'Seng2009-S_NCNSlalsöd'),\n", - " ('description',\n", - " '59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean ± SD) 21 ± 2 years, body weight 62 ± 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 ± 4 years, body weight 69 ± 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 ± 4 cigarettes daily, age 23 ± 5 years, body weight 71 ± 19 kg).'),\n", - " ('count', 14)])" - ] - }, - "execution_count": 495, - "metadata": {}, - "output_type": "execute_result" + "ename": "ErrorMessage", + "evalue": "\n characteristic_values: [\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {}\n ]", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;34m\"intervention\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m }\n\u001b[0;32m---> 32\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"groups\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mgroup_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mErrorMessage\u001b[0m: \n characteristic_values: [\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {}\n ]" + ] } ], "source": [ @@ -748,7 +2060,8 @@ " \"choice\": \"Asian\"\n", " },\n", " \n", - " ]\n", + " ],\n", + " \"intervention\":[],\n", " }\n", "client.action(document, [\"groups\", \"create\"], params=group_dict)" ] diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index bd6b8474..e0b292e8 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -91,7 +91,7 @@ class Protocol(models.Model): """ List of things/steps which were done to the group. """ - group = models.ForeignKey(Group, related_name='intervention', on_delete=True) + group = models.ForeignKey(Group, related_name='interventions', on_delete=True) protokol_steps = models.ManyToManyField(MedicationStep) name = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # set of protocols diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py new file mode 100644 index 00000000..8d53818a --- /dev/null +++ b/pkdb_app/interventions/serializers.py @@ -0,0 +1,18 @@ +from rest_framework import serializers +from .models import Protocol, MedicationStep +from ..serializers import BaseSerializer + + +class MedicationStepSerializer(BaseSerializer): + class Meta: + model = MedicationStep + fields = "__all__" + + +class ProtocolSerializer(BaseSerializer): + protokol_steps = MedicationStepSerializer(many=True, read_only=False) + + class Meta: + model = Protocol + fields = "__all__" + diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index d18491c0..fc7d8a7c 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,5 +1,6 @@ from rest_framework import serializers from .models import Group, CharacteristicValue +from ..interventions.serializers import ProtocolSerializer from ..studies.models import Reference from ..serializers import BaseSerializer BASE_FIELDS = () @@ -21,10 +22,12 @@ def to_representation(self, instance): class GroupSerializer(serializers.ModelSerializer): characteristic_values = CharacteristicValueSerializer(many=True, read_only=False) + interventions = ProtocolSerializer(many=True, read_only=False) class Meta: model = Group - fields = BASE_FIELDS + ( 'characteristic_values', 'name', 'description', 'count',) + fields = BASE_FIELDS + ( 'name', 'count','description','characteristic_values', 'intervention') + def create(self, validated_data): group , _ = Group.objects.update_or_create(name=validated_data["name"], defaults=validated_data) From c7847343d922b9cb8e18c753a83b1c9dbd40c6a3 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 26 Jul 2018 09:26:33 +0200 Subject: [PATCH 026/115] tmp libre office files removed --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index eb5c4b52..63d0d998 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ __pycache__/ *.so # open/libre office -.ods# +*.ods# # Distribution / packaging From e9d8673198fe604afffed107a7073e9041408bac Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 30 Jul 2018 17:07:12 +0200 Subject: [PATCH 027/115] closes #9 , individual set is still missing, the rest works --- pkdb_app/categoricals.py | 2 + pkdb_app/data_management/add_groups.py | 116 +++++++++++++ pkdb_app/data_management/add_intervention.py | 69 ++++++++ pkdb_app/data_management/add_output.py | 66 ++++++++ .../data_management/create_master_json.py | 147 ---------------- pkdb_app/data_management/create_reference.py | 12 +- pkdb_app/data_management/create_study.py | 157 ------------------ pkdb_app/data_management/fill_database.py | 17 +- pkdb_app/data_management/initialize_study.py | 64 +++++++ pkdb_app/interventions/models.py | 19 ++- pkdb_app/utils.py | 23 +++ 11 files changed, 370 insertions(+), 322 deletions(-) create mode 100644 pkdb_app/data_management/add_groups.py create mode 100644 pkdb_app/data_management/add_intervention.py create mode 100644 pkdb_app/data_management/add_output.py delete mode 100644 pkdb_app/data_management/create_master_json.py delete mode 100644 pkdb_app/data_management/create_study.py create mode 100644 pkdb_app/data_management/initialize_study.py diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 0c72e467..a859843d 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -45,6 +45,7 @@ BOOLEAN_TYPE = 'boolean' NUMERIC_TYPE = 'numeric' CATEGORIAL_TYPE = 'categorial' +STRING_TYPE = "string" # can be a free string, no limitations compared to categorial YES = "Y" NO = 'N' BOOLEAN_CHOICES = [YES, NO] @@ -133,6 +134,7 @@ PROTOCOL_DATA = [ CharacteristicType('dosing', 'Dosing', NUMERIC_TYPE, None, ["-"]), CharacteristicType('smoking_cessation', 'Lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('female cycle', 'Cycle', STRING_TYPE, None, ["-"]), ] def dict_and_choices(data): diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py new file mode 100644 index 00000000..1ae19d6e --- /dev/null +++ b/pkdb_app/data_management/add_groups.py @@ -0,0 +1,116 @@ +import os +import sys + +import pandas as pd +import bonobo + +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) + +from pkdb_app.data_management.fill_database import get_study_json_path, open_study +from pkdb_app.data_management.initialize_study import save_study, study_filename +from pkdb_app.categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE +from pkdb_app.data_management.create_reference import SUBJECTSPATH + +from pkdb_app.utils import create_if_exists, clean_import + + +def add_groupset_to_study(study): + study_json = {**study["json"]} + subject_pd = pd.read_csv(SUBJECTSPATH,delimiter='\t',keep_default_na=False) + this_subject = subject_pd[subject_pd["reference"] == study_json["name"]] + this_subject.replace({'NA':None}, inplace=True) + + study_json["groupset"] = {} + try: + test = this_subject["description"].unique()[0] + study_json["groupset"]["description"] = '|'.join(this_subject["description"].unique()) + except IndexError: + print( f'{study_json["name"]}: has no group') + + study_json["groupset"]["groups"] = [] + + for group in this_subject.itertuples(): + yield {"json": study_json,"group": group._asdict(), "study_path": study["study_path"]} + + +def add_group_to_groupset(data): + #add groupsets + ####################################################### + group = {} + group["count"] = data["group"]["count"] + group["name"] = data["group"]["groups"] + group["description"] = data["group"]["description"] + group["characteristica"] = add_characteristic_values(data["group"]) + json = {**data["json"]} + json["groupset"]["groups"].append(group) + return {"json":json, "study_path":data["study_path"]} + +def add_characteristic_values(group): + characteristics_values = [] + for category in CHARACTERISTIC_CATEGORIES: + for characteristics_value in process_characteristic_values(group,category): + temp_characteristics_value = {**characteristics_value} + for key in ["category","count"]: + temp_characteristics_value.pop(key,None) + if not temp_characteristics_value == {}: + characteristics_values.append(characteristics_value) + return characteristics_values + +def process_characteristic_values(group,category): + this_value = str(group.get("category","")) + if this_value.strip().replace('.','',1).isdigit() or CHARACTERISTIC_DTYPE[category] == "numeric": + + numeric_data = {} + numeric_data["category"] = category + if "new_count" in group: + numeric_data["count"] = group["new_count"] + + if group["count"] > 1: + numeric_data = create_if_exists(group,category,numeric_data,"mean") + numeric_data = create_if_exists(group,f"{category}_median",numeric_data,"median") + numeric_data = create_if_exists(group,f"{category}_min",numeric_data,"min") + numeric_data = create_if_exists(group,f"{category}_max",numeric_data,"max") + numeric_data = create_if_exists(group,f"{category}_sd",numeric_data,"sd") + numeric_data = create_if_exists(group,f"{category}_se",numeric_data,"se") + numeric_data = create_if_exists(group,f"{category}_cv",numeric_data,"cv") + numeric_data = create_if_exists(group,f"{category}_unit",numeric_data,"unit") + + else: + numeric_data = create_if_exists(group,category,numeric_data,"float") + + + return [clean_import(numeric_data)] + + else: + categorical_data = {} + if "new_count" in group: + categorical_data["count"] = group["new_count"] + + + + categorical_data["category"] = category + categorical_data = create_if_exists(group, category, categorical_data, "choice") + + return [clean_import(categorical_data)] + +def get_graph_study(**options): + graph = bonobo.Graph() + # add studies + graph.add_chain( + get_study_json_path, + open_study, + add_groupset_to_study, + add_group_to_groupset, + save_study, + ) + return graph + +def get_services(**options): + return {} + + +if __name__ == '__main__': + parser = bonobo.get_argument_parser() + with bonobo.parse_args(parser) as options: + bonobo.run(get_graph_study(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/add_intervention.py b/pkdb_app/data_management/add_intervention.py new file mode 100644 index 00000000..bc3e737f --- /dev/null +++ b/pkdb_app/data_management/add_intervention.py @@ -0,0 +1,69 @@ +import bonobo +import pandas as pd +import os +import sys +import json + +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) + +from pkdb_app.data_management.fill_database import get_study_json_path, open_study +from pkdb_app.data_management.create_reference import DOSINGPATH, ensure_dir +from pkdb_app.data_management.initialize_study import save_study +from pkdb_app.utils import create_if_exists, clean_import + +def add_intervention_to_study(study): + dosing_pd = pd.read_csv(DOSINGPATH, delimiter='\t') + study_json = {**study["json"]} + study_json["interventionset"] = {} + this_interventions = dosing_pd[dosing_pd["study"] == study_json["name"]] + this_interventions.replace({'NA':None}, inplace=True) + + try: + test=this_interventions["dosing_details"].unique()[0] + study_json["interventionset"]["description"] = '|'.join(this_interventions["dosing_details"].unique()) + except IndexError: + print( f'{study_json["name"]}:has no Interventions') + + study_json["interventionset"]["interventions"] = [] + + for i, row in this_interventions.iterrows(): + intervention_json = {} + intervention_json["name"] = row["dosing"] + intervention_json["substance"] = row["substance"] + intervention_json["time"] = row["times"] + intervention_json["time_unit"] = row["times_unit"] + intervention_json["route"] = row["route"] + intervention_json["value"] = row["dose"] + intervention_json["unit"] = row["dose_unit"] + study_json["interventionset"]["interventions"].append(clean_import(intervention_json)) + + yield {"json":study_json,"study_path": study["study_path"]} + + + +def save_reference(d): + ensure_dir(d["interventions_file"]) + with open(d["interventions_file"], 'a') as fp: + json.dump(d['json'], fp, indent=4) + + +def get_graph_study(**options): + graph = bonobo.Graph() + # add studies + graph.add_chain( + get_study_json_path, + open_study, + add_intervention_to_study, + save_study, + ) + return graph + +def get_services(**options): + return {} + + +if __name__ == '__main__': + parser = bonobo.get_argument_parser() + with bonobo.parse_args(parser) as options: + bonobo.run(get_graph_study(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/add_output.py b/pkdb_app/data_management/add_output.py new file mode 100644 index 00000000..db70c80b --- /dev/null +++ b/pkdb_app/data_management/add_output.py @@ -0,0 +1,66 @@ +import bonobo +import pandas as pd +import os,sys +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) + + +from pkdb_app.data_management.fill_database import get_study_json_path, open_study +from pkdb_app.data_management.create_reference import PHARMACOKINETICSPATH +from pkdb_app.data_management.initialize_study import save_study +from pkdb_app.utils import create_if_exists, clean_import + + +def add_outputs_to_study(study): + dosing_pd = pd.read_csv(PHARMACOKINETICSPATH, delimiter='\t') + study_json = {**study["json"]} + study_json["outputset"] = {} + study_json["outputset"]["description"] = "" + study_json["outputset"]["outputs"] = [] + + study_output = dosing_pd[dosing_pd["study"] == study_json["name"]] + for name, data in study_output.groupby(["subjects", "dosing","substance"]): + output = {} + #output["name"] = '|'.join(name[:-1]) + output["group"] = name[0] + output["intervention"] = name[1] + + output["substance"] = name[2] + + for i, row in data.iterrows(): + + output["pktype"] = row["pktype"] + output["value"] = row["value"] + output['tissue'] = row["tissue"] + output['sd'] = row["sd"] + output['se'] = row["se"] + output['cv'] = row["cv"] + output['min'] = row["min"] + output['max'] = row["max"] + output['unit'] = row["unit"] + + study_json["outputset"]["outputs"].append(clean_import(output)) + + yield {"json":study_json,"study_path": study["study_path"]} + +def get_graph_study(**options): + graph = bonobo.Graph() + # add studies + graph.add_chain( + get_study_json_path, + open_study, + add_outputs_to_study, + save_study, + ) + return graph + +def get_services(**options): + return {} + + +if __name__ == '__main__': + parser = bonobo.get_argument_parser() + with bonobo.parse_args(parser) as options: + bonobo.run(get_graph_study(**options), services=get_services(**options)) + + diff --git a/pkdb_app/data_management/create_master_json.py b/pkdb_app/data_management/create_master_json.py deleted file mode 100644 index 882c57d1..00000000 --- a/pkdb_app/data_management/create_master_json.py +++ /dev/null @@ -1,147 +0,0 @@ -""" -TODO: check if still needed and remove - -""" - - -import os -import sys -import bonobo -import csv -from Bio import Entrez -import xml.etree.ElementTree as ET -import pandas as pd - -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..//')) -Master = os.path.join(BASEPATH,"Master") -if BASEPATH not in sys.path: - sys.path.append(BASEPATH) - -DATABASEPATH = os.path.join(BASEPATH, "data") -path_studies = os.path.join(DATABASEPATH, "caffeine", "Studies.tsv") -path_subjects = os.path.join(DATABASEPATH, "caffeine", "Subjects.tsv") -path_pharmacokinetics = os.path.join(DATABASEPATH, "caffeine", "Pharmacokinetics.tsv") -path_interventions = os.path.join(DATABASEPATH, "caffeine", "Interventions.tsv") -path_dosing = os.path.join(DATABASEPATH, "caffeine", "Dosing.tsv") -path_master = os.path.join(DATABASEPATH, "Master") -path_master_studies = os.path.join(path_master, "Studies") - - -def ensure_dir(file_path): - directory = os.path.dirname(file_path) - if not os.path.exists(directory): - os.makedirs(directory) - - -def extract_studies(path): - reader = csv.DictReader(open(path),delimiter='\t') - for line in reader: - yield dict(line) - - -def create_data(data_pd, file_name): - for n, d in data_pd.groupby("study"): - data_path = os.path.join(path_master_studies, n, file_name) - ensure_dir(data_path) - d.to_csv(data_path, sep="\t") - - -def split_into_study_folder(path,file_name): - data_pd = pd.read_csv(path,delimiter='\t') - create_data(data_pd, file_name) - for row in data_pd.iterrows(): - yield row - - -def pmid_to_int(d): - d['pmid'] = int(d['pmid']) - yield d - - -def add_study_sid(d): - sid = str(d["study"]) - yield {**d ,'sid':sid} - - -def create_study_folder(d): - study_path = os.path.join(path_master_studies,d['sid']) - ensure_dir(study_path) - yield {**d, "study_path":study_path} - - -def load_from_biopython(d): - Entrez.email = 'janekg89@hotmail.de' - handle = Entrez.efetch(db='pubmed', id=d['pmid'], retmode='xml') - all_info = handle.read() - handle.close() - yield {**d, 'xml': all_info} - - -def write_biopython_xml_to_file(d): - file_path = os.path.join(d["study_path"],f'{d["sid"]}.xml') - text_file = open(file_path, "w") - text_file.write(d["xml"]) - text_file.close() - yield {**d, 'data': ET.fromstring(d['xml'])} - - -def create_authors_file(d): - file_path = os.path.join(d["study_path"],"authors.csv") - - with open(file_path, 'w+') as f: - writer = csv.DictWriter(f, fieldnames=["first_name","last_name"]) - writer.writeheader() - yield {**d, "file_path":file_path} - - -def get_authors_from_study(d): - for author in d["data"].iter("Author"): - d1 = {} - d1["first_name"] = author.find("ForeName").text - d1["last_name"] = author.find("LastName").text - yield {"author": d1, "file_path": os.path.join(d["study_path"],"authors.csv")} - - -def write_authors(d): - with open(d["file_path"], 'a') as f: - writer = csv.DictWriter(f,fieldnames=["first_name","last_name"]) - writer.writerow(d["author"]) - - -def get_graph(**options): - graph = bonobo.Graph() - #add studies - graph.add_chain( - extract_studies(path_studies), - pmid_to_int, - add_study_sid, - create_study_folder, - load_from_biopython, - write_biopython_xml_to_file, - create_authors_file, - get_authors_from_study, - write_authors - ) - #add dosing - graph.add_chain( - split_into_study_folder(path_dosing,"Dosing.tsv"), - ) - #add subjects - graph.add_chain( - split_into_study_folder(path_subjects,"Subjects.tsv"), - ) - #add Pharmacokinetics - graph.add_chain( - split_into_study_folder(path_pharmacokinetics, "Pharmacokinetics.tsv"), - ) - return graph - - -def get_services(**options): - return {} - - -if __name__ == '__main__': - parser = bonobo.get_argument_parser() - with bonobo.parse_args(parser) as options: - bonobo.run(get_graph(**options), services=get_services(**options)) \ No newline at end of file diff --git a/pkdb_app/data_management/create_reference.py b/pkdb_app/data_management/create_reference.py index 98178f84..13c77498 100644 --- a/pkdb_app/data_management/create_reference.py +++ b/pkdb_app/data_management/create_reference.py @@ -11,7 +11,11 @@ import json import requests -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..//')) +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) +from pkdb_app.utils import ensure_dir + + Master = os.path.join(BASEPATH, "Master") if BASEPATH not in sys.path: sys.path.append(BASEPATH) @@ -28,10 +32,6 @@ REFERENCESMASTERPATH = os.path.join(MASTERPATH, "Studies") -def ensure_dir(file_path): - directory = os.path.dirname(file_path) - if not os.path.exists(directory): - os.makedirs(directory) def extract_references(path): reader = csv.DictReader(open(path), delimiter='\t') @@ -40,8 +40,8 @@ def extract_references(path): def pmid_to_int(d): - d['pmid'] = int(d['pmid']) d['sid'] = int(d['pmid']) + d['pmid'] = int(d['pmid']) yield d diff --git a/pkdb_app/data_management/create_study.py b/pkdb_app/data_management/create_study.py deleted file mode 100644 index 75de553e..00000000 --- a/pkdb_app/data_management/create_study.py +++ /dev/null @@ -1,157 +0,0 @@ -""" -Creates json files in master folder -""" -from create_reference import collect_reference, add_reference_path, SUBJECTSPATH, ensure_dir -from categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE -import bonobo -import pandas as pd -import numpy as np -import json -import os - - -def study_load(reference): - data_pd = pd.read_csv(SUBJECTSPATH,delimiter='\t') - this_data = data_pd[data_pd["reference"] == reference["name"]] - json = {"sid": reference["sid"]} - json["name"] = reference["name"] - json["reference"] = reference["sid"] - json["groups"] = [] - - for name, row in this_data.iterrows(): - yield {"json": json, "group": row.to_dict(),"reference": reference} - -def add_subject_to_json(data): - group = {} - group["count"] = data["group"]["count"] - group["name"] = f'{data["json"]["name"]}-{data["group"]["groups"]}' - group["description"] = data["group"]["description"] - group["characteristic_values"] = add_characteristic_values(data["group"]) - - json = {**data["json"]} - json["groups"].append(group) - return {"json":json, "study_path":data["reference"]["reference_path"]} - - -def add_characteristic_values(group): - characteristics_values = [] - for category in CHARACTERISTIC_CATEGORIES: - for characteristics_value in process_characteristic_values(group,category): - temp_characteristics_value = {**characteristics_value} - for key in ["category","count"]: - temp_characteristics_value.pop(key,None) - if not all(value is None for value in temp_characteristics_value.values()): - characteristics_values.append(characteristics_value) - - return characteristics_values - - -def remove_nans(group): - for key, value in group.items(): - if value is np.NaN: - group[key] = None - if str(value) == "nan": - group[key] = None - if str(value) == "": - group[key] = None - if str(value) == "NA": - group[key] = None - if str(value) == "None": - group[key] = None - if str(value) == "-": - group[key] = None - - -def clean_dict(d): - return {k: v for k, v in d.items() if v is not None} - - -def process_characteristic_values(group,category): - remove_nans(group) - - this_value = str(group.get(category,"")) - - if "|" in this_value: - characteristic_values = [] - counts_and_choices = this_value.split("|") - for count_and_choice in counts_and_choices: - count , choice = count_and_choice.split() - this_group = {**group} - this_group["new_count"] = count - this_group[category] = choice - characteristic_values += process_characteristic_values(this_group,category) - return characteristic_values - - elif this_value.strip().replace('.','',1).isdigit() or CHARACTERISTIC_DTYPE[category] == "numeric": - numeric_data = {} - numeric_data["category"] = category - - if "new_count" in group: - numeric_data["count"] = group["new_count"] - - if group["count"] > 1: - numeric_data["mean"] = group.get(category, None) - numeric_data["median"] = group.get(f"{category}_median",None) - numeric_data["min"] = group.get(f"{category}_min",None) - numeric_data["max"] = group.get(f"{category}_max",None) - numeric_data["sd"] = group.get(f"{category}_sd",None) - numeric_data["se"] = group.get(f"{category}_se",None) - numeric_data["cv"] = group.get(f"{category}_cv",None) - numeric_data["unit"] = group.get(f"{category}_unit",None) - else: - numeric_data["float"] = group.get(category, None) - - return [clean_dict(numeric_data)] - - - - else: - categorical_data = {} - if "new_count" in group: - categorical_data["count"] = group["new_count"] - - categorical_data["category"] = category - categorical_data["choice"] = group.get(category,None) - return [clean_dict(categorical_data)] - - - - - -def save_json(d): - json_file = os.path.join(d["study_path"],"study.json") - ensure_dir(json_file) - with open(json_file, 'w') as fp: - json.dump(d['json'],fp, indent=4) - - - - - -def get_graph(**options): - graph = bonobo.Graph() - - # add reference information - graph.add_chain(*collect_reference) - graph.add_chain() - - #add studies - graph.add_chain( - study_load, - add_subject_to_json, - save_json, - _input=add_reference_path, - ) - return graph - - - - -def get_services(**options): - return {} - - -if __name__ == '__main__': - parser = bonobo.get_argument_parser() - with bonobo.parse_args(parser) as options: - bonobo.run(get_graph(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 455b1572..073c89b9 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -1,13 +1,17 @@ -import os +import os, sys import bonobo import coreapi import json -from create_reference import REFERENCESMASTERPATH + +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) + +from pkdb_app.data_management.create_reference import REFERENCESMASTERPATH from jsonschema import validate -from schemas import reference_schema +from pkdb_app.data_management.schemas import reference_schema + + -client = coreapi.Client() -document = client.get("http://0.0.0.0:8000/") def get_reference_json_path(): @@ -64,6 +68,9 @@ def get_services(**options): if __name__ == '__main__': + client = coreapi.Client() + document = client.get("http://0.0.0.0:8000/") + parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: bonobo.run(get_graph_references(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/initialize_study.py b/pkdb_app/data_management/initialize_study.py new file mode 100644 index 00000000..918007d9 --- /dev/null +++ b/pkdb_app/data_management/initialize_study.py @@ -0,0 +1,64 @@ +""" +Creates study.py json files in master folder with group infrmation +""" + + + +import bonobo +import pandas as pd +import numpy as np +import json +import os +import sys + +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) + +from pkdb_app.data_management.create_reference import collect_reference, add_reference_path, ensure_dir + +MK = "Matthias König" +JG = "Jan Grzeogrzewski" +pkdb_version = 1.0 +study_filename = "study.json" + +def study_create(reference): + #create json for study + json = {"sid": reference["sid"]} + json["pkdb_version"] = pkdb_version + json["creator"] = MK + json["name"] = reference["name"] + json["reference"] = reference["sid"] + json["curators"] = [MK, JG] + study_path = os.path.join(reference["reference_path"],study_filename) + return {"json":json, "study_path":study_path} + + +def save_study(d): + json_file = os.path.join(d["study_path"]) + ensure_dir(json_file) + with open(json_file, 'w') as fp: + json.dump(d['json'],fp, indent=4,ensure_ascii=False) + + +def get_graph(**options): + graph = bonobo.Graph() + + # add reference information + graph.add_chain(*collect_reference) + + #add studies + graph.add_chain( + study_create, + save_study, + _input=add_reference_path, + ) + return graph + + +def get_services(**options): + return {} + +if __name__ == '__main__': + parser = bonobo.get_argument_parser() + with bonobo.parse_args(parser) as options: + bonobo.run(get_graph(**options), services=get_services(**options)) diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index e0b292e8..c8ffeba6 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -69,10 +69,11 @@ class Meta: abstract = True -class MedicationStep(Valueable, ProtocolStep): # choices, dose, unit (per_bodyweitght is not important) - """ Dosing. +class ValueProtocolStep(Valueable, ProtocolStep): # choices, dose, unit (per_bodyweitght is not important) + """ A concrete step/thing which is done to the group. - The actual dosing is stored in the Valueable. + In case of dosing/medication the actual dosing is stored in the Valueable. + In case of a step without dosing, e.g., lifestyle intervention only the category is used. """ substance = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) #substance: # what was given [' route = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # route: # where ['oral', 'iv'] @@ -81,18 +82,22 @@ class MedicationStep(Valueable, ProtocolStep): # choices, dose, unit (per_bodyw form = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # form: # how medication [capusle, tablete] form_details = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) #form_details: # h details -class ProcessedMedicationStep(Valueable, ProtocolStep): +class ProcessedValueProtocolStep(Valueable, ProtocolStep): """ Calculated from medicationstep """ - raw = models.ForeignKey(MedicationStep, null=True, on_delete=True) + raw = models.ForeignKey(ValueProtocolStep, null=True, on_delete=True) class Protocol(models.Model): - """ List of things/steps which were done to the group. + """ List of things/steps which were done to the group or changed within the group or + distinguishing the group (for instance different time in montly cycle). + - distinguishing operation on the group (! but does not change group characteristics !) + - giving medication + - FIXME: better naming of class """ group = models.ForeignKey(Group, related_name='interventions', on_delete=True) - protokol_steps = models.ManyToManyField(MedicationStep) + protocol_steps = models.ManyToManyField(ValueProtocolStep) name = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # set of protocols # name (control, fluvoxamine, control-fluvo, fluvo-control) diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index 7ba26b3e..e6ed9009 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -3,3 +3,26 @@ CHAR_MAX_LENGTH = 30 +def create_if_exists(src,src_key,dest,dest_key): + if src_key in src.keys(): + dest[dest_key] = src[src_key] + + return dest + + +def clean_import(data): + clean_dict = {} + for key, value in data.items(): + + if not str(value) in ["", "nan"]: + clean_dict[key] = value + + elif str(value) == "NA": + clean_dict[key] = None + + return clean_dict + +def ensure_dir(file_path): + directory = os.path.dirname(file_path) + if not os.path.exists(directory): + os.makedirs(directory) From b621472cf754914c61f6ee2932d93cc729a9d226 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 31 Jul 2018 10:03:15 +0200 Subject: [PATCH 028/115] refining json format --- CURATION.md | 202 ++++++++++++++++++ TODO.md | 18 +- pkdb_app/categoricals.py | 97 ++++----- pkdb_app/data_management/add_groups.py | 4 +- pkdb_app/data_management/add_intervention.py | 4 +- pkdb_app/data_management/add_output.py | 1 - pkdb_app/data_management/create_study_json.sh | 0 pkdb_app/data_management/initialize_study.py | 1 + pkdb_app/data_management/schemas.py | 5 + pkdb_app/interventions/models.py | 5 +- pkdb_app/subjects/models.py | 8 +- 11 files changed, 273 insertions(+), 72 deletions(-) create mode 100644 CURATION.md create mode 100644 pkdb_app/data_management/create_study_json.sh diff --git a/CURATION.md b/CURATION.md new file mode 100644 index 00000000..7226aec9 --- /dev/null +++ b/CURATION.md @@ -0,0 +1,202 @@ +# Curation information +Collection of resources and infromation on how experimental data +should be curated from manuscripts for upload/inclusion in PKDB. + +Most important point is to create valid JSON which can be accepted +by the model serializers, i.e. serializers which are defined +in +``` +serializers.py +studies/serializers.py +interventions/serializers.py +subjects/serializers.py +``` + +Additionally, the JSON files have to be conform to the JSON schema, +defined in + +## 1. PDF, Reference, Figures & Tables +* Create folder for study, name folder AuthorYear{a,b,c, ...} from hereon referred to as StudyName +* Get `PMID` (Pubmed id) for publication from https://www.ncbi.nlm.nih.gov/pubmed/ +* Download PDF in folder as StudyName.pdf +* Extract Figures with graphics program and save as StudyName_Fig[0-9]* or StudyName_Tab[0-9]* +* Digitized data should be stored in StudyName.xlsx + +## 2. Initial study information (`study.json`) +Fill in basic information for study, use the `PMID` for `sid` and `reference` field, use StudyName for `name` field. + +```json +{ + "sid": 10877011, + "pkdb_version": 1.0, + "creator": "mkoenig", + "name": "Akinyinka2000", + "reference": 10877011, + "curators": [ + "mkoenig", + "janekg" + ], + "substances": [ + "caffeine", + "acetaminophen" + ], + "comments": [ + ["mkoenig", "Comment on the study"] + ] +} +``` +* The `creator` and `curators` should map to existing data base users (but is no requirement for now). +* The `reference` field is optional. If no pubmed entry exist for publication a `reference.json` should be build manually. This will be documented later on. +* Substances define which substances are mentioned/studied in the study. + + +## 3. Curation of groups/groupset +The next step is curating the groups used in the study. The information is stored in the `groupset` of the following form. +```json +{ + "groupset": { + "description": "This is first part of description.||This is second part of description", + "characteristica": [ + { + "category": "species", + "choice": "homo sapiens" + }, + { + "category": "ethnicity", + "choice": "Black" + }, + { + "category": "sex", + "choice": null + }, + { + "category": "smoking", + "choice": "N" + } + ] + } +} +``` +* Descriptions are separated `||`. The identical separator is used for other parts of the JSON. +* The groups are defined via `characteristica`, shared characteristica of all groups are defined on the groupset. +* The allowed values for category and choice can be looked up in `categorials.py` for now. +* Values which are not defined in a characteristica have to be left empty. If the value is set to `null` this represents `NA` values. I.e., it was explicitly checked that the information was not available. This is especially important for the lifestyle characteristica and things like `ethnicity`. A list of characteristicas which should be checked will be provided (smoking, ethnicity, alcohol, contraceptives, ...) +* Characteristica which are specific to a group are defined in the group +```json +{ +"groups": [ + { + "count": 10, + "name": "S1", + "comments": [ + ["mkoenig", "This is a comment for the group."] + ], + "characteristica": [ + { + "category": "weight", + "mean": "59.8", + "min": "38", + "max": "82", + "sd": "12.3", + "se": null, + "unit": "kg" + }, + { + "category": "age", + "mean": "32.1", + "min": "18", + "max": "40", + "sd": "7.6", + "se": null, + "unit": "yr" + }, + { + "category": "healthy", + "choice": "Y" + } + ] + } + ] +} +``` +* names have to be unique within groupset and should be descriptive, e.g., smoker, nonsmoker, contraceptive. + +All available fields for characteristica on group and groupset are: +```json +{ + "count": "int", + "name": "string", // not on groupset, only on group + "category": "categorial", + // valueable field + "choice": "categorial|string", + "value": "double", + "mean": "double", + "median": "double", + "min": "double", + "max": "double", + "sd": "double", + "se": "double", + "cv": "double", + "unit": "categorial" +} +``` +* The `choice` field is used for categorials, the numerical values `mean`, `median`, ... for numerical values. +* If only a single value is provided this is stored in the `value` field. + +* Inclusion and exclusion criteria for study can be defined via the `ctype` on groupset or group with values in {`exclusion`, `inclusion`} + +## 4. Curation of interventions/interventionset +```json +{ + "interventionset": { + "description": "All patients and volunteers fasted overnight and, at 0800 hours, were given orally 300 mg caffeine dissolved in 150 ml water; food intake was allowed 3 h after administration of caffeine.", + "interventions": [ + { + "name": "D1", + "substance": "caffeine", + "time": "0", + "time_unit": "h", + "route": "oral", + "value": 300.0, + "unit": "mg" + } + ] + } +} +``` +All available fields for intervention and interventionset are: +```json +{ + + "name": "string", // not on groupset, only on group + "category": "categorial", + + "substance": "categorial (substance)", + "route": "categorial {oral, iv}", + "application": "categorial {'single dose', 'multiple doses', 'continuous injection'}", + "form": "categorial {'tablete', 'capsule', ...}", + "time": "double||double||double ...", + "time_unit": "categorial", + + // valueable field + "choice": "categorial|string", + "value": "double", + "mean": "double", + "median": "double", + "min": "double", + "max": "double", + "sd": "double", + "se": "double", + "cv": "double", + "unit": "categorial" +} +``` +* TODO: document after next iteration + +## 5. Curation of output/outputset + + +## Open issues +- individual set +- time course data +- column data \ No newline at end of file diff --git a/TODO.md b/TODO.md index 6c9f4508..ee648693 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,22 @@ +# Small Tasks +- move reused information on groupset and interventionset, e.g., + characteristica which are for all groups +- remove description from group & intervention +- add comments on group and intervention, groupset and intervention (serializer and data model) +- use usernames for name (shorter and faster) +- remove NA from errors +- add substances on study (from categorials list of substances) +- update names changed in categorials +- add value field on valuable +- remove choice from valuable + +- individualset similar to groupset (with characteristica on individualset for all individuals) + - first step list individual individually (no column mapping for now) + +- LATER: create list of allowed keywords and choices (for now looked up in categorials) + # Main Tasks -* import existing data sets (caffeine & acetaminophen) * web interface for display * export to excel files and CSVs * web interface for curation diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index a859843d..2a946eb7 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -51,75 +51,75 @@ BOOLEAN_CHOICES = [YES, NO] # categories -DEMOGRAPHICS = "Demographics" # age, sex, ethnicity -ANTHROPOMETRY = "Anthropometry" # height, weight, waist bmi -SPECIES = "Species" -BIOCHEMICAL_DATA = "Biochemical data" -HEMATOLOGY_DATA = "Hematology data" +DEMOGRAPHICS = "demographics" # age, sex, ethnicity +ANTHROPOMETRY = "anthropometry" # height, weight, waist bmi +SPECIES = "species" +BIOCHEMICAL_DATA = "biochemical data" +HEMATOLOGY_DATA = "hematology data" -INCLUSION_CRITERIA = "InclusionCriteria" -EXCLUSION_CRITERIA = "ExclusionCriteria" -GROUP_CRITERIA = "GroupCriteria" -CHARACTERISTIC_VALUE_TYPES = [INCLUSION_CRITERIA, EXCLUSION_CRITERIA, GROUP_CRITERIA] -CHARACTERISTIC_VALUE_CHOICES = [(t, t) for t in CHARACTERISTIC_VALUE_TYPES] +INCLUSION_CRITERIA = "inclusion" +EXCLUSION_CRITERIA = "exclusion" +GROUP_CRITERIA = "group" +CHARACTERISTICA_TYPES = [INCLUSION_CRITERIA, EXCLUSION_CRITERIA, GROUP_CRITERIA] +CHARACTERISTICA_CHOICES = [(t, t) for t in CHARACTERISTICA_TYPES] STUDY_DESIGN_DATA = [ - "single group (interventional study)", - "parallel group (interventional study)", - "crossover (interventional study)", - "cohort (oberservational study)", - "case control (oberservational study)", + "single group", # (interventional study) + "parallel group", # (interventional study) + "crossover", # (interventional study) + "cohort", # (oberservational study) + "case control", # (oberservational study) ] STUDY_DESIGN_CHOICES = [(t, t) for t in STUDY_DESIGN_DATA] COMMON_DATA = [ # Medication - CharacteristicType('oral_contraceptives', 'Contraceptives', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('oral_contraceptives_amount', 'Contraceptives', NUMERIC_TYPE, None, ["-"]), - CharacteristicType('medication', 'Medication', CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"], ["-"]), # ? dosing + CharacteristicType('oral contraceptives', 'contraceptives', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('oral contraceptives amount', 'contraceptives', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('medication', 'medication', CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"], ["-"]), # ? dosing # Lifestyle - CharacteristicType('caffeine', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('caffeine_amount', 'Lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('caffeine_amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), ] CHARACTERISTIC_DATA = COMMON_DATA + [ # Antropmetrical information - CharacteristicType('species', SPECIES, CATEGORIAL_TYPE, ["Homo sapiens"], ["-"]), + CharacteristicType('species', SPECIES, CATEGORIAL_TYPE, ["homo sapiens"], ["-"]), CharacteristicType('height', ANTHROPOMETRY, NUMERIC_TYPE, None, ["cm", 'm']), CharacteristicType('weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["kg"]), CharacteristicType('bmi', ANTHROPOMETRY, NUMERIC_TYPE, None, ["kg/m^2"]), - CharacteristicType('waist_circumference', ANTHROPOMETRY, NUMERIC_TYPE, None, ["cm"]), - CharacteristicType('liver_weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), - CharacteristicType('kidney_weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), + CharacteristicType('waist circumference', ANTHROPOMETRY, NUMERIC_TYPE, None, ["cm"]), + CharacteristicType('liver weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), + CharacteristicType('kidney weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), CharacteristicType('age', DEMOGRAPHICS, NUMERIC_TYPE, None, ["yr"]), CharacteristicType('sex', DEMOGRAPHICS, CATEGORIAL_TYPE, ["M", "F"], ["-"]), - CharacteristicType('ethnicity', DEMOGRAPHICS, CATEGORIAL_TYPE, ["African", "Afroamerican", "Asian", "Caucasian"], ["-"]), + CharacteristicType('ethnicity', DEMOGRAPHICS, CATEGORIAL_TYPE, ["african", "afroamerican", "asian", "caucasian"], ["-"]), # Disease (status) - CharacteristicType('healthy', "Health status", BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('disease', "Disease", CATEGORIAL_TYPE, ["cirrhosis"], ["-"]), + CharacteristicType('healthy', "health status", BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('disease', "disease", CATEGORIAL_TYPE, ["cirrhosis"], ["-"]), # Lifestyle - CharacteristicType('smoking', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('smoking_amount', 'Lifestyle', NUMERIC_TYPE, None, ["-"]), - CharacteristicType('alcohol', 'Lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('alcohol_amount', 'Lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('smoking', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('smoking amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('alcohol', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('alcohol amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), # Biochemical data CharacteristicType('ALT', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["IU/I"]), CharacteristicType('AST', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["IU/I"]), - CharacteristicType('Albumin', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["g/dl"]), + CharacteristicType('albumin', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["g/dl"]), # Study protocol - CharacteristicType('overnight_fast', 'Study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('alcohol_abstinence', 'Study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('overnight fast', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('alcohol abstinence', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), # Medication @@ -132,9 +132,9 @@ # class, value, dtype (numeric, boolean, categorial), choices PROTOCOL_DATA = [ - CharacteristicType('dosing', 'Dosing', NUMERIC_TYPE, None, ["-"]), - CharacteristicType('smoking_cessation', 'Lifestyle', NUMERIC_TYPE, None, ["-"]), - CharacteristicType('female cycle', 'Cycle', STRING_TYPE, None, ["-"]), + CharacteristicType('dosing', 'dosing', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('smoking cessation', 'lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('female cycle', 'cycle', STRING_TYPE, None, ["-"]), ] def dict_and_choices(data): @@ -153,29 +153,10 @@ def dict_and_choices(data): (1, "Other"), (2, "Dynamic Individual"), (3, "Dynamic Group"), - (4, "Static Single"), - (5, "Static Multiple"), + (4, "Static Individual"), + (5, "Static Group"), ) ''' -''' -class Dosing: - substance - route - form - dose - dose_unit - dose_bodyweight - times - -class Pharmacokinetics (CharacteristicValue): - group (intervention) - dosing - substance - source - entry -''' - - diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py index 1ae19d6e..2f6b5539 100644 --- a/pkdb_app/data_management/add_groups.py +++ b/pkdb_app/data_management/add_groups.py @@ -8,7 +8,7 @@ sys.path.append(BASEPATH) from pkdb_app.data_management.fill_database import get_study_json_path, open_study -from pkdb_app.data_management.initialize_study import save_study, study_filename +from pkdb_app.data_management.initialize_study import save_study, study_filename, SEPERATOR from pkdb_app.categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE from pkdb_app.data_management.create_reference import SUBJECTSPATH @@ -24,7 +24,7 @@ def add_groupset_to_study(study): study_json["groupset"] = {} try: test = this_subject["description"].unique()[0] - study_json["groupset"]["description"] = '|'.join(this_subject["description"].unique()) + study_json["groupset"]["description"] = SEPERATOR.join(this_subject["description"].unique()) except IndexError: print( f'{study_json["name"]}: has no group') diff --git a/pkdb_app/data_management/add_intervention.py b/pkdb_app/data_management/add_intervention.py index bc3e737f..00cd1b41 100644 --- a/pkdb_app/data_management/add_intervention.py +++ b/pkdb_app/data_management/add_intervention.py @@ -9,7 +9,7 @@ from pkdb_app.data_management.fill_database import get_study_json_path, open_study from pkdb_app.data_management.create_reference import DOSINGPATH, ensure_dir -from pkdb_app.data_management.initialize_study import save_study +from pkdb_app.data_management.initialize_study import save_study, SEPERATOR from pkdb_app.utils import create_if_exists, clean_import def add_intervention_to_study(study): @@ -21,7 +21,7 @@ def add_intervention_to_study(study): try: test=this_interventions["dosing_details"].unique()[0] - study_json["interventionset"]["description"] = '|'.join(this_interventions["dosing_details"].unique()) + study_json["interventionset"]["description"] = SEPERATOR.join(this_interventions["dosing_details"].unique()) except IndexError: print( f'{study_json["name"]}:has no Interventions') diff --git a/pkdb_app/data_management/add_output.py b/pkdb_app/data_management/add_output.py index db70c80b..9503685b 100644 --- a/pkdb_app/data_management/add_output.py +++ b/pkdb_app/data_management/add_output.py @@ -21,7 +21,6 @@ def add_outputs_to_study(study): study_output = dosing_pd[dosing_pd["study"] == study_json["name"]] for name, data in study_output.groupby(["subjects", "dosing","substance"]): output = {} - #output["name"] = '|'.join(name[:-1]) output["group"] = name[0] output["intervention"] = name[1] diff --git a/pkdb_app/data_management/create_study_json.sh b/pkdb_app/data_management/create_study_json.sh new file mode 100644 index 00000000..e69de29b diff --git a/pkdb_app/data_management/initialize_study.py b/pkdb_app/data_management/initialize_study.py index 918007d9..4df65ea8 100644 --- a/pkdb_app/data_management/initialize_study.py +++ b/pkdb_app/data_management/initialize_study.py @@ -20,6 +20,7 @@ JG = "Jan Grzeogrzewski" pkdb_version = 1.0 study_filename = "study.json" +SEPERATOR = "||" def study_create(reference): #create json for study diff --git a/pkdb_app/data_management/schemas.py b/pkdb_app/data_management/schemas.py index 76125649..e5f3ee7d 100644 --- a/pkdb_app/data_management/schemas.py +++ b/pkdb_app/data_management/schemas.py @@ -1,4 +1,9 @@ +""" +Definition of JSON schema for validation. +FIXME: this should be created programmatically and be exported +In the optimal case directly generated from the serializers. +""" reference_schema = { "properties": { "pmid": {"type": "number"}, diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index c8ffeba6..3c34e309 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -30,8 +30,6 @@ # Add separate class? extension of model? - - class ProtocolStep(Sidable, Describable, models.Model): """ What is done to the group, single step. @@ -79,8 +77,7 @@ class ValueProtocolStep(Valueable, ProtocolStep): # choices, dose, unit (per_bo route = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # route: # where ['oral', 'iv'] application = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # application: # how timing ['single dose', 'multiple doses', 'continuous injection'] application_time = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) - form = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # form: # how medication [capusle, tablete] - form_details = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) #form_details: # h details + form = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # form: # how medication [capsule, tablete] class ProcessedValueProtocolStep(Valueable, ProtocolStep): """ Calculated from medicationstep diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 2f0a8722..fc45dfcd 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -10,7 +10,7 @@ from ..studies.models import Study, Reference from ..behaviours import Sidable, Describable, Valueable -from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, CHARACTERISTIC_VALUE_CHOICES, GROUP_CRITERIA, \ +from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, CHARACTERISTICA_CHOICES, GROUP_CRITERIA, \ INCLUSION_CRITERIA, EXCLUSION_CRITERIA from ..utils import CHAR_MAX_LENGTH from .managers import GroupManager @@ -84,15 +84,15 @@ class CharacteristicValue(Valueable, Characteristic): This stores the raw information. Derived values can be calculated. """ group = models.ForeignKey(Group, related_name="characteristic_values", null=True, on_delete=True) - cvtype = models.CharField(choices=CHARACTERISTIC_VALUE_CHOICES, max_length=CHAR_MAX_LENGTH, default=GROUP_CRITERIA) + ctype = models.CharField(choices=CHARACTERISTICA_CHOICES, max_length=CHAR_MAX_LENGTH, default=GROUP_CRITERIA) @property def is_inclusion(self): - return self.cvtype == INCLUSION_CRITERIA + return self.ctype == INCLUSION_CRITERIA @property def is_exclusion(self): - return self.cvtype == EXCLUSION_CRITERIA + return self.ctype == EXCLUSION_CRITERIA #def validate(self): # """ Check that choices are valid. I.e. that choice is allowed choice from choices for From 634b8abd8b41daa4da6910b7a817903aadfb0b71 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 31 Jul 2018 17:22:42 +0200 Subject: [PATCH 029/115] working on json: moved common characterista to groupset,added individualset and output dynamics --- pkdb_app/data_management/add_groups.py | 77 ++++++++++++++++++- pkdb_app/data_management/add_output.py | 30 +++++++- pkdb_app/data_management/create_reference.py | 3 + pkdb_app/data_management/create_study_json.sh | 2 + pkdb_app/data_management/initialize_study.py | 10 ++- 5 files changed, 115 insertions(+), 7 deletions(-) mode change 100644 => 100755 pkdb_app/data_management/create_study_json.sh diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py index 2f6b5539..67c455e5 100644 --- a/pkdb_app/data_management/add_groups.py +++ b/pkdb_app/data_management/add_groups.py @@ -1,6 +1,6 @@ import os import sys - +from pprint import pprint import pandas as pd import bonobo @@ -10,7 +10,7 @@ from pkdb_app.data_management.fill_database import get_study_json_path, open_study from pkdb_app.data_management.initialize_study import save_study, study_filename, SEPERATOR from pkdb_app.categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE -from pkdb_app.data_management.create_reference import SUBJECTSPATH +from pkdb_app.data_management.create_reference import SUBJECTSPATH, INDIVIDUALPATH from pkdb_app.utils import create_if_exists, clean_import @@ -28,6 +28,8 @@ def add_groupset_to_study(study): except IndexError: print( f'{study_json["name"]}: has no group') + if len(this_subject) > 1: + study_json["groupset"]["characteristica"] = [] study_json["groupset"]["groups"] = [] for group in this_subject.itertuples(): @@ -40,12 +42,59 @@ def add_group_to_groupset(data): group = {} group["count"] = data["group"]["count"] group["name"] = data["group"]["groups"] - group["description"] = data["group"]["description"] + #group["description"] = data["group"]["description"] group["characteristica"] = add_characteristic_values(data["group"]) json = {**data["json"]} json["groupset"]["groups"].append(group) return {"json":json, "study_path":data["study_path"]} +def add_characteristica_groupset(data): + this_data = {**data} + groups = this_data["json"]["groupset"]["groups"] + number_of_groups = len(groups) + + if number_of_groups > 1: + new_groups =[] + for group in groups: + new_chara = [] + for characteristica in group['characteristica']: + characteristica.pop("count",None) + new_chara.append(tuple(characteristica.items())) + new_groups.append(set(new_chara)) + + groupset_chara_tuples = set.intersection(*new_groups) + groupset_dict = [dict(x) for x in groupset_chara_tuples] + this_data["json"]["groupset"]["characteristica"] = groupset_dict + + new_groups = [group - groupset_chara_tuples for group in new_groups] + groups_dict = [list(map(dict,x)) for x in new_groups] + + for i, group in enumerate(groups_dict): + this_data["json"]["groupset"]["groups"][i]['characteristica'] = group + +def add_individual_set(data): + this_data = {**data} + individials_pd = pd.read_csv(INDIVIDUALPATH, delimiter='\t', keep_default_na=False) + this_individuals = individials_pd[individials_pd["study"] == this_data["json"]["name"]] + this_individuals.replace({'NA': None}, inplace=True) + + if len(this_individuals) > 0: + this_data["json"]["individualset"] = {} + + this_data["json"]["individualset"]["description"] = "" + this_data["json"]["individualset"]["individuals"] = [] + + for individuals in this_individuals.itertuples(): + print(individuals.data) + individuals_dict = {"data" :individuals.data, "figure" :individuals.figure} + this_data["json"]["individualset"]["individuals"].append(individuals_dict) + + + return this_data + + + + def add_characteristic_values(group): characteristics_values = [] for category in CHARACTERISTIC_CATEGORIES: @@ -106,6 +155,26 @@ def get_graph_study(**options): ) return graph + +def get_graph_groupset_chara(**options): + graph = bonobo.Graph() + graph.add_chain( + get_study_json_path, + open_study, + add_characteristica_groupset, + save_study, + ) + return graph + +def get_graph_groupset_individual(**options): + graph = bonobo.Graph() + graph.add_chain( + get_study_json_path, + open_study, + add_individual_set, + save_study, + ) + return graph def get_services(**options): return {} @@ -114,3 +183,5 @@ def get_services(**options): parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: bonobo.run(get_graph_study(**options), services=get_services(**options)) + bonobo.run(get_graph_groupset_chara(**options), services=get_services(**options)) + bonobo.run(get_graph_groupset_individual(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/add_output.py b/pkdb_app/data_management/add_output.py index 9503685b..b9285dfb 100644 --- a/pkdb_app/data_management/add_output.py +++ b/pkdb_app/data_management/add_output.py @@ -6,7 +6,7 @@ from pkdb_app.data_management.fill_database import get_study_json_path, open_study -from pkdb_app.data_management.create_reference import PHARMACOKINETICSPATH +from pkdb_app.data_management.create_reference import PHARMACOKINETICSPATH, DYNAMICALRESULTSPATH from pkdb_app.data_management.initialize_study import save_study from pkdb_app.utils import create_if_exists, clean_import @@ -42,6 +42,22 @@ def add_outputs_to_study(study): yield {"json":study_json,"study_path": study["study_path"]} +def add_dynamics_to_ouput(data): + this_data = {**data} + dynamics_pd = pd.read_csv(DYNAMICALRESULTSPATH, delimiter='\t', keep_default_na=False,encoding="utf-8") + this_dynamics = dynamics_pd[dynamics_pd["study"] == this_data["json"]["name"]] + this_dynamics.replace({'NA': None}, inplace=True) + + if len(this_dynamics) > 0: + this_data["json"]["outputset"]["dynamics"] = [] + for dynamics in this_dynamics.itertuples(): + print(dynamics.data) + dynamics_dict = {"data" :dynamics.data, "figure" :dynamics.figure} + this_data["json"]["outputset"]["dynamics"].append(dynamics_dict) + + + return this_data + def get_graph_study(**options): graph = bonobo.Graph() # add studies @@ -53,6 +69,17 @@ def get_graph_study(**options): ) return graph +def get_graph_dynamics(**options): + graph = bonobo.Graph() + # add studies + graph.add_chain( + get_study_json_path, + open_study, + add_dynamics_to_ouput, + save_study, + ) + return graph + def get_services(**options): return {} @@ -61,5 +88,6 @@ def get_services(**options): parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: bonobo.run(get_graph_study(**options), services=get_services(**options)) + bonobo.run(get_graph_dynamics(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/create_reference.py b/pkdb_app/data_management/create_reference.py index 13c77498..9078b549 100644 --- a/pkdb_app/data_management/create_reference.py +++ b/pkdb_app/data_management/create_reference.py @@ -31,6 +31,9 @@ MASTERPATH = os.path.join(DATABASEPATH, "Master") REFERENCESMASTERPATH = os.path.join(MASTERPATH, "Studies") +INDIVIDUALPATH = os.path.join(DATABASEPATH, "caffeine", "Individuals.tsv") +DYNAMICALRESULTSPATH = os.path.join(DATABASEPATH, "caffeine", "DynamicalResults.tsv") + def extract_references(path): diff --git a/pkdb_app/data_management/create_study_json.sh b/pkdb_app/data_management/create_study_json.sh old mode 100644 new mode 100755 index e69de29b..c0725be2 --- a/pkdb_app/data_management/create_study_json.sh +++ b/pkdb_app/data_management/create_study_json.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python initialize_study.py && python add_groups.py && python add_intervention.py && python add_output.py \ No newline at end of file diff --git a/pkdb_app/data_management/initialize_study.py b/pkdb_app/data_management/initialize_study.py index 4df65ea8..d252e01b 100644 --- a/pkdb_app/data_management/initialize_study.py +++ b/pkdb_app/data_management/initialize_study.py @@ -17,7 +17,10 @@ from pkdb_app.data_management.create_reference import collect_reference, add_reference_path, ensure_dir MK = "Matthias König" +MK_u = "mkoenig" +JG_u = "janekg" JG = "Jan Grzeogrzewski" +SUBSTANCES = ["caffeine",] pkdb_version = 1.0 study_filename = "study.json" SEPERATOR = "||" @@ -26,10 +29,11 @@ def study_create(reference): #create json for study json = {"sid": reference["sid"]} json["pkdb_version"] = pkdb_version - json["creator"] = MK + json["creator"] = MK_u json["name"] = reference["name"] + json["substances"] = SUBSTANCES json["reference"] = reference["sid"] - json["curators"] = [MK, JG] + json["curators"] = [MK_u, JG_u] study_path = os.path.join(reference["reference_path"],study_filename) return {"json":json, "study_path":study_path} @@ -38,7 +42,7 @@ def save_study(d): json_file = os.path.join(d["study_path"]) ensure_dir(json_file) with open(json_file, 'w') as fp: - json.dump(d['json'],fp, indent=4,ensure_ascii=False) + json.dump(d['json'],fp, indent=4, ensure_ascii=False,) def get_graph(**options): From fea0d9558fc90d1499920a60663c50ab1bcbd65e Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 31 Jul 2018 17:31:56 +0200 Subject: [PATCH 030/115] added idea to curation --- CURATION.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CURATION.md b/CURATION.md index 7226aec9..b5705f48 100644 --- a/CURATION.md +++ b/CURATION.md @@ -192,6 +192,7 @@ All available fields for intervention and interventionset are: } ``` * TODO: document after next iteration +* Question: maybe remove individuals and dynamics and add something like `extern/table/mapping`. There you add mappings. ## 5. Curation of output/outputset From 6395b7547cb7a3854c13fad797485a4d5255ef16 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 1 Aug 2018 09:52:30 +0200 Subject: [PATCH 031/115] before work --- pkdb_app/categoricals.py | 3 ++- pkdb_app/data_management/add_groups.py | 13 ++++++++++--- pkdb_app/data_management/fill_database.py | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 2a946eb7..3a3497bb 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -83,7 +83,7 @@ # Lifestyle CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('caffeine_amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('caffeine amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), ] CHARACTERISTIC_DATA = COMMON_DATA + [ @@ -144,6 +144,7 @@ def dict_and_choices(data): CHARACTERISTIC_DTYPE = {item.value : item.dtype for item in CHARACTERISTIC_DATA} CHARACTERISTIC_CATEGORIES = set([item.value for item in CHARACTERISTIC_DATA]) +CHARACTERISTIC_CATEGORIES_UNDERSCORE = set([c.replace(' ', '_') for c in CHARACTERISTIC_CATEGORIES]) CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES = dict_and_choices(CHARACTERISTIC_DATA) PROTOCOL_DICT, PROTOCOL_CHOICES = dict_and_choices(PROTOCOL_DATA) diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py index 67c455e5..4ffa4c82 100644 --- a/pkdb_app/data_management/add_groups.py +++ b/pkdb_app/data_management/add_groups.py @@ -20,7 +20,7 @@ def add_groupset_to_study(study): subject_pd = pd.read_csv(SUBJECTSPATH,delimiter='\t',keep_default_na=False) this_subject = subject_pd[subject_pd["reference"] == study_json["name"]] this_subject.replace({'NA':None}, inplace=True) - + this_subject.columns = [c.replace('_', ' ') for c in this_subject.columns] study_json["groupset"] = {} try: test = this_subject["description"].unique()[0] @@ -32,8 +32,11 @@ def add_groupset_to_study(study): study_json["groupset"]["characteristica"] = [] study_json["groupset"]["groups"] = [] - for group in this_subject.itertuples(): - yield {"json": study_json,"group": group._asdict(), "study_path": study["study_path"]} + for group in this_subject.iterrows(): + #todo: hier weitermachen + print(group) + print(group.to_dict("records")) + yield {"json": study_json,"group": group.to_dict(), "study_path": study["study_path"]} def add_group_to_groupset(data): @@ -72,6 +75,9 @@ def add_characteristica_groupset(data): for i, group in enumerate(groups_dict): this_data["json"]["groupset"]["groups"][i]['characteristica'] = group + return this_data + + def add_individual_set(data): this_data = {**data} individials_pd = pd.read_csv(INDIVIDUALPATH, delimiter='\t', keep_default_na=False) @@ -96,6 +102,7 @@ def add_individual_set(data): def add_characteristic_values(group): + group characteristics_values = [] for category in CHARACTERISTIC_CATEGORIES: for characteristics_value in process_characteristic_values(group,category): diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 073c89b9..9f94e273 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -74,5 +74,5 @@ def get_services(**options): parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: bonobo.run(get_graph_references(**options), services=get_services(**options)) - bonobo.run(get_graph_study(**options), services=get_services(**options)) + #bonobo.run(get_graph_study(**options), services=get_services(**options)) From eeca8794edc45ee29014e0f83c83f70d4538d19c Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 1 Aug 2018 18:18:40 +0200 Subject: [PATCH 032/115] first version of json were al informations are inetgrated, now I go over to model and serializer --- CURATION.md | 3 +- TODO.md | 92 ++++++++++++++++++-- pkdb_app/behaviours.py | 3 +- pkdb_app/categoricals.py | 16 ++++ pkdb_app/data_management/add_groups.py | 52 ++++++----- pkdb_app/data_management/add_intervention.py | 2 +- pkdb_app/data_management/add_output.py | 60 +++++++------ pkdb_app/data_management/create_reference.py | 3 +- pkdb_app/data_management/fill_database.py | 16 +++- pkdb_app/data_management/initialize_study.py | 3 +- pkdb_app/interventions/models.py | 36 +++++--- pkdb_app/studies/models.py | 36 ++++---- pkdb_app/studies/serializers.py | 6 +- pkdb_app/subjects/models.py | 29 ++++-- pkdb_app/subjects/serializers.py | 4 +- pkdb_app/urls.py | 2 +- 16 files changed, 256 insertions(+), 107 deletions(-) diff --git a/CURATION.md b/CURATION.md index b5705f48..8b1d1933 100644 --- a/CURATION.md +++ b/CURATION.md @@ -31,6 +31,7 @@ Fill in basic information for study, use the `PMID` for `sid` and `reference` fi "pkdb_version": 1.0, "creator": "mkoenig", "name": "Akinyinka2000", + "design":"parallel group", "reference": 10877011, "curators": [ "mkoenig", @@ -192,7 +193,7 @@ All available fields for intervention and interventionset are: } ``` * TODO: document after next iteration -* Question: maybe remove individuals and dynamics and add something like `extern/table/mapping`. There you add mappings. +* Question: maybe remove individuals and dynamics and add something like `extern/table/mapping`. There you could add mappings. ## 5. Curation of output/outputset diff --git a/TODO.md b/TODO.md index ee648693..3fb0bd78 100644 --- a/TODO.md +++ b/TODO.md @@ -1,20 +1,45 @@ # Small Tasks +- change how to write characteristicy ("choice": "Y(3)||N(1)") + - move reused information on groupset and interventionset, e.g., - characteristica which are for all groups -- remove description from group & intervention + characteristica which are for all groups ✅ +- remove description from group & intervention ✅ + - add comments on group and intervention, groupset and intervention (serializer and data model) -- use usernames for name (shorter and faster) -- remove NA from errors -- add substances on study (from categorials list of substances) -- update names changed in categorials -- add value field on valuable -- remove choice from valuable +- use usernames for name (shorter and faster) ✅ +- remove NA from errors ✅ +- add substances on study (from categorials list of substances) ✅ +- update names changed in categorials ✅ +- add value field on valuable ✅, make sure means are stored as mean (i.e. values from a group with more than 1 subject) + +- remove choice from valuable ✅ + +- add design to studies ✅ + +- API endpoints + - reference + - study (complete JSON) + - groupset () + - group + - characteristica + - individualset + - interventionset + - intervention + - outputset + - output +- Documentation API (Swagger DRF/Open API) + (- show required fields & choices of choice fields if possible, test description for fields) + +- Group Timecourse with column selection based on Akinyinka2000_Fig1 & Akinyinka2000_Fig2 - individualset similar to groupset (with characteristica on individualset for all individuals) - first step list individual individually (no column mapping for now) - LATER: create list of allowed keywords and choices (for now looked up in categorials) +#Questions Janek: +- do we need description on study? For now it is in. + # Main Tasks * web interface for display @@ -26,3 +51,54 @@ Have a look at genetic variants https://www.pharmvar.org/ https://www.pharmvar.org/gene/CYP1A1 + +## timescource example +```json +{ +"timecourse": [ + { + "group": "col==subjects", + "intervention": "D1", + "source": "Akinyinka2000_Fig1.csv", + "format": "TSV", + "figure": "Akinyinka2000_Fig1.png", + "substance": "caffeine", + "tissue": "plasma", + "pktype": "concentration", + "times": "col==time", + "values": "col==caf", + "sd": "col==caf_sd", + "unit": "µg/ml" + }, + { + "group": "col==subjects", + "intervention": "D1", + "source": "Akinyinka2000_Fig1.csv", + "format": "TSV", + "figure": "Akinyinka2000_Fig2.png", + "substance": "paraxanthine", + "tissue": "plasma", + "pktype": "concentration", + "times": "col==time", + "values": "col==px", + "sd": "col==px_sd", + "unit": "µg/ml" + }, + { + "group": "col==subjects", + "intervention": "D1", + "source": "Akinyinka2000_Fig1.csv", + "format": "TSV", + "figure": "Akinyinka2000_Fig1.png && Akinyinka2000_Fig2.png", + "substance": "paraxanthine && caffeine", + "tissue": "plasma", + "pktype": "ratio", + "times": "col==time", + "values": "col==px_caf", + "sd": "col==px_caf_sd", + "unit": "-" + } + ] +} +``` + \ No newline at end of file diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index 2bb0f17c..9edbba57 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -59,8 +59,7 @@ class Valueable(models.Model): In addition all the statistical values are stored. """ - choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, - blank=True) # check in validation that allowed choice + count = models.IntegerField() # how many participants in characteristics value = models.FloatField(null=True, blank=True) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 3a3497bb..00b03021 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -12,6 +12,13 @@ units on CharacteristicType is an ordered iteratable, with the first unit being the default unit. """ +CURRENT_VERSION = [1.0] +VERSIONS = [1.0,] +#considering: to maintain serializers of serval versions of the json file. The version would be read from the json file and the respective +#serializer would be selected. + + + # TODO: How to handle the genetic information? Genetic variants? @@ -74,6 +81,15 @@ ] STUDY_DESIGN_CHOICES = [(t, t) for t in STUDY_DESIGN_DATA] +SUBSTANCES_DATA = [ + "ibuprofen", + "paracetamol", + "aspirin", + "caffeine", + "acetaminophen", +] +SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] + COMMON_DATA = [ # Medication diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py index 4ffa4c82..ea5b3933 100644 --- a/pkdb_app/data_management/add_groups.py +++ b/pkdb_app/data_management/add_groups.py @@ -11,7 +11,6 @@ from pkdb_app.data_management.initialize_study import save_study, study_filename, SEPERATOR from pkdb_app.categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE from pkdb_app.data_management.create_reference import SUBJECTSPATH, INDIVIDUALPATH - from pkdb_app.utils import create_if_exists, clean_import @@ -19,8 +18,8 @@ def add_groupset_to_study(study): study_json = {**study["json"]} subject_pd = pd.read_csv(SUBJECTSPATH,delimiter='\t',keep_default_na=False) this_subject = subject_pd[subject_pd["reference"] == study_json["name"]] - this_subject.replace({'NA':None}, inplace=True) - this_subject.columns = [c.replace('_', ' ') for c in this_subject.columns] + this_subject = this_subject.replace({'NA':None}) + #this_subject.columns = [c.replace('_', ' ') for c in this_subject.columns] study_json["groupset"] = {} try: test = this_subject["description"].unique()[0] @@ -32,21 +31,25 @@ def add_groupset_to_study(study): study_json["groupset"]["characteristica"] = [] study_json["groupset"]["groups"] = [] - for group in this_subject.iterrows(): - #todo: hier weitermachen - print(group) - print(group.to_dict("records")) - yield {"json": study_json,"group": group.to_dict(), "study_path": study["study_path"]} + for group in this_subject.itertuples(): + #print(group.reset_index().to_dict()) + #print(group) + #print(group.to_dict("records")) + yield {"json": study_json,"group": group._asdict(), "study_path": study["study_path"]} def add_group_to_groupset(data): + + data_group = { k.replace('_', ' '):v for k,v in data["group"].items()} + print(data_group) #add groupsets ####################################################### group = {} + group["count"] = data["group"]["count"] group["name"] = data["group"]["groups"] #group["description"] = data["group"]["description"] - group["characteristica"] = add_characteristic_values(data["group"]) + group["characteristica"] = add_characteristic_values(data_group) json = {**data["json"]} json["groupset"]["groups"].append(group) return {"json":json, "study_path":data["study_path"]} @@ -91,8 +94,16 @@ def add_individual_set(data): this_data["json"]["individualset"]["individuals"] = [] for individuals in this_individuals.itertuples(): - print(individuals.data) - individuals_dict = {"data" :individuals.data, "figure" :individuals.figure} + individuals_dict_raw = individuals._asdict() + individuals_dict_raw = {k.replace('_', ' '): v for k, v in individuals_dict_raw.items()} + + individuals_dict = {} + individuals_dict["name"] = individuals_dict_raw["name"] + individuals_dict["group"] = individuals_dict_raw["group"] + individuals_dict["source"] = individuals_dict_raw["source"] + individuals_dict["format"] = individuals_dict_raw["format"] + individuals_dict["figure"] = individuals_dict_raw["figure"] + individuals_dict['characteristica'] = add_characteristic_values(individuals_dict_raw) this_data["json"]["individualset"]["individuals"].append(individuals_dict) @@ -102,7 +113,6 @@ def add_individual_set(data): def add_characteristic_values(group): - group characteristics_values = [] for category in CHARACTERISTIC_CATEGORIES: for characteristics_value in process_characteristic_values(group,category): @@ -113,28 +123,30 @@ def add_characteristic_values(group): characteristics_values.append(characteristics_value) return characteristics_values + def process_characteristic_values(group,category): this_value = str(group.get("category","")) if this_value.strip().replace('.','',1).isdigit() or CHARACTERISTIC_DTYPE[category] == "numeric": numeric_data = {} numeric_data["category"] = category + group["count"] = group.get("count",1) if "new_count" in group: numeric_data["count"] = group["new_count"] if group["count"] > 1: numeric_data = create_if_exists(group,category,numeric_data,"mean") - numeric_data = create_if_exists(group,f"{category}_median",numeric_data,"median") - numeric_data = create_if_exists(group,f"{category}_min",numeric_data,"min") - numeric_data = create_if_exists(group,f"{category}_max",numeric_data,"max") - numeric_data = create_if_exists(group,f"{category}_sd",numeric_data,"sd") - numeric_data = create_if_exists(group,f"{category}_se",numeric_data,"se") - numeric_data = create_if_exists(group,f"{category}_cv",numeric_data,"cv") - numeric_data = create_if_exists(group,f"{category}_unit",numeric_data,"unit") + numeric_data = create_if_exists(group,f"{category} median",numeric_data,"median") + numeric_data = create_if_exists(group,f"{category} min",numeric_data,"min") + numeric_data = create_if_exists(group,f"{category} max",numeric_data,"max") + numeric_data = create_if_exists(group,f"{category} sd",numeric_data,"sd") + numeric_data = create_if_exists(group,f"{category} se",numeric_data,"se") + numeric_data = create_if_exists(group,f"{category} cv",numeric_data,"cv") else: - numeric_data = create_if_exists(group,category,numeric_data,"float") + numeric_data = create_if_exists(group,category,numeric_data,"value") + numeric_data = create_if_exists(group, f"{category} unit", numeric_data, "unit") return [clean_import(numeric_data)] diff --git a/pkdb_app/data_management/add_intervention.py b/pkdb_app/data_management/add_intervention.py index 00cd1b41..de9cbd57 100644 --- a/pkdb_app/data_management/add_intervention.py +++ b/pkdb_app/data_management/add_intervention.py @@ -20,7 +20,7 @@ def add_intervention_to_study(study): this_interventions.replace({'NA':None}, inplace=True) try: - test=this_interventions["dosing_details"].unique()[0] + test = this_interventions["dosing_details"].unique()[0] study_json["interventionset"]["description"] = SEPERATOR.join(this_interventions["dosing_details"].unique()) except IndexError: print( f'{study_json["name"]}:has no Interventions') diff --git a/pkdb_app/data_management/add_output.py b/pkdb_app/data_management/add_output.py index b9285dfb..6eedfe44 100644 --- a/pkdb_app/data_management/add_output.py +++ b/pkdb_app/data_management/add_output.py @@ -6,17 +6,20 @@ from pkdb_app.data_management.fill_database import get_study_json_path, open_study -from pkdb_app.data_management.create_reference import PHARMACOKINETICSPATH, DYNAMICALRESULTSPATH +from pkdb_app.data_management.create_reference import PHARMACOKINETICSPATH, TIMECOURSEPATH, OUTPUTINDIVIDUALPATH from pkdb_app.data_management.initialize_study import save_study from pkdb_app.utils import create_if_exists, clean_import - -def add_outputs_to_study(study): - dosing_pd = pd.read_csv(PHARMACOKINETICSPATH, delimiter='\t') +def inizialize_output(study): study_json = {**study["json"]} study_json["outputset"] = {} study_json["outputset"]["description"] = "" study_json["outputset"]["outputs"] = [] + yield {"json": study_json, "study_path": study["study_path"]} + +def add_outputs_to_study(study): + dosing_pd = pd.read_csv(PHARMACOKINETICSPATH, delimiter='\t') + study_json = {**study["json"]} study_output = dosing_pd[dosing_pd["study"] == study_json["name"]] for name, data in study_output.groupby(["subjects", "dosing","substance"]): @@ -42,44 +45,50 @@ def add_outputs_to_study(study): yield {"json":study_json,"study_path": study["study_path"]} -def add_dynamics_to_ouput(data): +def add_timecourse_to_ouput(data): this_data = {**data} - dynamics_pd = pd.read_csv(DYNAMICALRESULTSPATH, delimiter='\t', keep_default_na=False,encoding="utf-8") - this_dynamics = dynamics_pd[dynamics_pd["study"] == this_data["json"]["name"]] - this_dynamics.replace({'NA': None}, inplace=True) + timecourse_pd = pd.read_csv(TIMECOURSEPATH, delimiter='\t', keep_default_na=False, encoding="utf-8") + this_timecourse = timecourse_pd[timecourse_pd["study"] == this_data["json"]["name"]] + this_timecourse.replace({'NA': None}, inplace=True) - if len(this_dynamics) > 0: - this_data["json"]["outputset"]["dynamics"] = [] - for dynamics in this_dynamics.itertuples(): - print(dynamics.data) - dynamics_dict = {"data" :dynamics.data, "figure" :dynamics.figure} - this_data["json"]["outputset"]["dynamics"].append(dynamics_dict) + if len(this_timecourse) > 0: + this_data["json"]["outputset"]["timecourse"] = [] + for timecourse in this_timecourse.itertuples(index=False): + timecourse_dict = timecourse._asdict() + timecourse_dict.pop("study") + this_data["json"]["outputset"]["timecourse"].append(timecourse_dict) return this_data +def add_individualmapping_to_ouput(data): + this_data = {**data} + individuals_output_pd = pd.read_csv(OUTPUTINDIVIDUALPATH, delimiter='\t', keep_default_na=False, encoding="utf-8") + this_individuals_output = individuals_output_pd[individuals_output_pd["study"] == this_data["json"]["name"]] + this_individuals_output.replace({'NA': None}, inplace=True) + + if len(this_individuals_output) > 0: + for individuals_output in this_individuals_output.itertuples(index=False): + individuals_output_dict = individuals_output._asdict() + individuals_output_dict.pop("study") + this_data["json"]["outputset"]["outputs"].append(individuals_output_dict) + return this_data + + def get_graph_study(**options): graph = bonobo.Graph() # add studies graph.add_chain( get_study_json_path, open_study, + inizialize_output, + add_individualmapping_to_ouput, + add_timecourse_to_ouput, add_outputs_to_study, save_study, ) return graph -def get_graph_dynamics(**options): - graph = bonobo.Graph() - # add studies - graph.add_chain( - get_study_json_path, - open_study, - add_dynamics_to_ouput, - save_study, - ) - return graph - def get_services(**options): return {} @@ -88,6 +97,5 @@ def get_services(**options): parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: bonobo.run(get_graph_study(**options), services=get_services(**options)) - bonobo.run(get_graph_dynamics(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/create_reference.py b/pkdb_app/data_management/create_reference.py index 9078b549..4b9d43ff 100644 --- a/pkdb_app/data_management/create_reference.py +++ b/pkdb_app/data_management/create_reference.py @@ -32,7 +32,8 @@ REFERENCESMASTERPATH = os.path.join(MASTERPATH, "Studies") INDIVIDUALPATH = os.path.join(DATABASEPATH, "caffeine", "Individuals.tsv") -DYNAMICALRESULTSPATH = os.path.join(DATABASEPATH, "caffeine", "DynamicalResults.tsv") +TIMECOURSEPATH = os.path.join(DATABASEPATH, "caffeine", "Timecourse.tsv") +OUTPUTINDIVIDUALPATH = os.path.join(DATABASEPATH, "caffeine", "OutputIndividuals.tsv") diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 9f94e273..526edca6 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -17,7 +17,10 @@ def get_reference_json_path(): for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "reference.json" in files: - yield os.path.join(root, 'reference.json') + json_file = os.path.join(root, 'reference.json') + pdf_file = f"{os.path.dirname(json_file)}.pdf" + + yield {"json":json_file , "pdf": pdf_file} def get_study_json_path(): for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): @@ -25,18 +28,23 @@ def get_study_json_path(): yield os.path.join(root, 'study.json') def open_reference(d): - with open(d) as f: + + with open(d["json"]) as f: json_dict = json.loads(f.read()) - return {"json":json_dict, "reference_path":d} + with open(d["pdf"],'rb') as f: + pdf = f + + json_dict["pdf"] = pdf + return {"json":json_dict, "reference_path":d["json"]} def open_study(d): with open(d) as f: - json_dict = json.loads(f.read()) return {"json":json_dict, "study_path":d} def upload_reference(json_reference): validate(json_reference["json"],reference_schema) + client.action(document, ["references", "create"], params=json_reference["json"]) def upload_study(json_study): diff --git a/pkdb_app/data_management/initialize_study.py b/pkdb_app/data_management/initialize_study.py index d252e01b..11c35734 100644 --- a/pkdb_app/data_management/initialize_study.py +++ b/pkdb_app/data_management/initialize_study.py @@ -31,9 +31,10 @@ def study_create(reference): json["pkdb_version"] = pkdb_version json["creator"] = MK_u json["name"] = reference["name"] - json["substances"] = SUBSTANCES + json["design"] = "" json["reference"] = reference["sid"] json["curators"] = [MK_u, JG_u] + json["substances"] = SUBSTANCES study_path = os.path.join(reference["reference_path"],study_filename) return {"json":json, "study_path":study_path} diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 3c34e309..91773f31 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -6,9 +6,9 @@ from django.db import models from ..behaviours import Sidable, Describable, Valueable -from ..categoricals import PROTOCOL_CHOICES, UNITS_CHOICES +from ..categoricals import PROTOCOL_CHOICES, UNITS_CHOICES, SUBSTANCES_DATA_CHOICES from ..subjects.models import Group -from ..studies.models import DataFile +from ..studies.models import DataFile, Substance from ..utils import CHAR_MAX_LENGTH # ------------------------------------------------- @@ -46,10 +46,11 @@ class ProtocolStep(Sidable, Describable, models.Model): - protocol 2 (linked to intervention group): MedicationStep (oral contraceptives), MedicationStep (caffeine) """ - # TODO: MedicationStep & LifestyleStep # FIXME: Important to find the subset of dosing protocols category = models.IntegerField(choices=PROTOCOL_CHOICES) + choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, + blank=True) # check in validation that allowed choice @property def Intervention_data(self): @@ -99,16 +100,7 @@ class Protocol(models.Model): # set of protocols # name (control, fluvoxamine, control-fluvo, fluvo-control) -class Substance(models.Model): - """ Substances have to be in a different table, so that - than be uniquely defined. - - Has to be extended via ontology (Ontologable) - """ - name = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) - #name # example caffeine - # ontologies: has set of defined values: is, CHEBI:27732 # ----------------- @@ -127,6 +119,8 @@ class Pharmacokinetics(Output, Valueable): category: [clearance, vd, thalf, cmax, ...] """ + choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, + blank=True) # check in validation that allowed choice substance = models.ForeignKey(Substance, on_delete=True) #tissue # where was it measured @@ -148,6 +142,24 @@ class ProcessedPharmacokinetics(Valueable): type = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # ['normalized', 'timecourse-derived'] +##################################### +#new +class Substance(models.Model): + """ Substances have to be in a different table, so that + than be uniquely defined. + + Has to be extended via ontology (Ontologable) + + """ + name = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True, choices=SUBSTANCES_DATA_CHOICES) + + #name # example caffeine + # ontologies: has set of defined values: is, CHEBI:27732 + +class Intervension(models.Model): + models.ForeignKey(Substance, on_delete=False) +class InterventionSet(Describable, models.model): + interventions = models.ForeignKey(Intervension, on_delete=True) diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index ce20dfa1..e7c4a2fd 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -2,10 +2,12 @@ Django model for Study. """ from django.db import models + +from pkdb_app.interventions.models import Substance from pkdb_app.utils import CHAR_MAX_LENGTH from pkdb_app.behaviours import Sidable, Describable, Commentable -from pkdb_app.categoricals import STUDY_DESIGN_CHOICES - +from pkdb_app.categoricals import STUDY_DESIGN_CHOICES, CURRENT_VERSION +from pkdb_app.users.models import User class Author(models.Model): first_name = models.CharField(max_length=30, blank=True) @@ -15,14 +17,6 @@ def __str__(self): return '%s %s' % (self.id, self.first_name, self.last_name) -class KeyWord(models.Model): - """ - This class describes the keyowrds / tags of a publication or any other reference. - """ - #name = models.IntegerField(choices=KEY_WORD_CHOICES) - name = models.CharField(max_length=CHAR_MAX_LENGTH) - - class Reference(models.Model): """ This is the main class describing the publication or reference which describes the study. @@ -49,20 +43,28 @@ class DataFile(models.Model): file = models.FileField(upload_to="output", null=True, blank=True) # table or figure filetype = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # XLSX, PNG, CSV + class Study(Sidable, Commentable, Describable, models.Model): """ Single clinical study. Mainly reported as a single publication. """ - reference = models.ForeignKey(Reference, on_delete=True, to_field="sid", db_column="reference_sid", related_name='studies', null=True, blank=True) + # FIXME: Do we need descciption here? + pkdb_version = models.IntegerField(default=CURRENT_VERSION) + creator = models.ForeignKey(User,on_delete=False) # any creator needs an account. name = models.CharField(max_length=CHAR_MAX_LENGTH) design = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True, choices=STUDY_DESIGN_CHOICES) - raw_data = models.ManyToManyField(DataFile) - - # TODO: substances, e.g. caffeine, acetaminophen - # TODO: datafiles (DataFile) - + reference = models.ForeignKey(Reference, on_delete=True, to_field="sid", db_column="reference_sid", related_name='studies', null=True, blank=True) + curators = models.ManyToManyField(User) # any curator needs an account. + substances = models.ManyToManyField(Substance) + raw_data = models.ManyToManyField(DataFile) # FIXME: is this the right name? -# TODO: substances here +#TODO: Not shure if later is even needed (not included yet) +class KeyWord(models.Model): + """ + This class describes the keyowrds / tags of a publication or any other reference. + """ + #name = models.IntegerField(choices=KEY_WORD_CHOICES) + name = models.CharField(max_length=CHAR_MAX_LENGTH) diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 72562c14..48836f3c 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -29,7 +29,7 @@ class ReferenceSerializer(BaseSerializer): class Meta: model = Reference - fields = BASE_FIELDS + ('pmid', 'sid', 'name', 'doi', 'title','abstract','journal', 'date', 'authors', 'pdf') + fields = BASE_FIELDS + ('pmid', 'sid', 'name', 'doi', 'title','abstract', 'journal', 'date', 'authors', 'pdf') def create(self, validated_data): @@ -60,11 +60,11 @@ def update(self, instance, validated_data): class StudySerializer(BaseSerializer): #reference = ReferenceSerializer(read_only=False) reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all()) - groups = GroupSerializer(many=True, read_only=False) + groupset = GroupSerializer(many=True, read_only=False) class Meta: model = Study - fields = BASE_FIELDS + ('sid','comment','name','description', 'groups', 'reference') + fields = BASE_FIELDS + ('sid','comment','name','description', 'groupset', 'reference') def create(self, validated_data): diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index fc45dfcd..960e0f84 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -30,20 +30,27 @@ # Idea: GroupSet +class GroupSet(Describable,models.Model): + study = models.ForeignKey(Study, on_delete=True, related_name='groups',to_field="sid", db_column="study_sid",null=True, blank=True) + -class Group(Describable, models.Model): + @property + def reference(self): + return self.study.reference + +class Group(models.Model): """ Individual or group of people. Groups are defined via their characteristics. """ + groupset = models.ForeignKey(GroupSet,on_delete=True, related_name="groups") name = models.CharField(max_length=CHAR_MAX_LENGTH) - study = models.ForeignKey(Study, on_delete=True, related_name='groups',to_field="sid", db_column="study_sid",null=True, blank=True) count = models.IntegerField() # number of people/animals/objects in group objects = GroupManager() @property def reference(self): - return self.study.reference + return self.groupset.reference class Characteristic(models.Model): @@ -61,7 +68,8 @@ class Characteristic(models.Model): addition to the group criteria. """ category = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) - + choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, + blank=True) # check in validation that allowed choice @property def characteristic_data(self): """ Returns the full information about the characteristic. @@ -78,12 +86,13 @@ class Meta: abstract = True -class CharacteristicValue(Valueable, Characteristic): +class Characteristica(Valueable, Characteristic): """ This is the concrete selection/information of the characteristics. This stores the raw information. Derived values can be calculated. """ - group = models.ForeignKey(Group, related_name="characteristic_values", null=True, on_delete=True) + groupset = models.ForeignKey(GroupSet, related_name="characteristica", null=True, on_delete=True) + group = models.ForeignKey(Group, related_name="characteristica", null=True, on_delete=True) ctype = models.CharField(choices=CHARACTERISTICA_CHOICES, max_length=CHAR_MAX_LENGTH, default=GROUP_CRITERIA) @property @@ -106,13 +115,17 @@ def is_exclusion(self): # raise NotImplemented -class ProcessedCharacteristicValue(Valueable, Characteristic, models.Model): +class CleanCharacteristica(Valueable, Characteristic, models.Model): """ Processed and normalized data (calculated on change from corresponding raw CharacteristicValue. - convert exclusion to inclusion criteria """ - raw = models.ForeignKey(CharacteristicValue, null=True, on_delete=True) + raw = models.ForeignKey(Characteristica, related_name="clean", null=True, on_delete=True) + + + + # method field? for different processing? # TODO: add methods for doing the processing & automatic update if corresponding diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index fc7d8a7c..d5d8353c 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from .models import Group, CharacteristicValue +from .models import Group, Characteristica from ..interventions.serializers import ProtocolSerializer from ..studies.models import Reference from ..serializers import BaseSerializer @@ -12,7 +12,7 @@ class CharacteristicValueSerializer(serializers.ModelSerializer): count = serializers.IntegerField(required=False) class Meta: - model = CharacteristicValue + model = Characteristica fields = "__all__" def to_representation(self, instance): diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index 03b612f4..ad129ce5 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -25,7 +25,7 @@ #router.register('intervention',InterventionsViewSet,base_name="intervention") -schema_view = get_swagger_view(title='PkBD API') +schema_view = get_swagger_view(title='PKDB API') From 5a027fb035d04983158d19c95253bd91ed9e3ba7 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 4 Aug 2018 15:27:55 +0200 Subject: [PATCH 033/115] close before finishing model and serializer --- CURATION.md | 1 - docs/api/api.ipynb | 2096 +++++------------ pkdb_app/behaviours.py | 32 +- pkdb_app/categoricals.py | 65 +- pkdb_app/comments/__init__.py | 0 pkdb_app/comments/admin.py | 3 + pkdb_app/comments/apps.py | 5 + pkdb_app/comments/migrations/0001_initial.py | 33 + .../migrations/0002_auto_20180803_1409.py | 32 + .../comments/migrations/0003_comment_user.py | 22 + pkdb_app/comments/migrations/__init__.py | 0 pkdb_app/comments/models.py | 35 + pkdb_app/comments/tests.py | 3 + pkdb_app/comments/views.py | 3 + pkdb_app/config/common.py | 4 + pkdb_app/data_management/fill_database.py | 39 +- pkdb_app/interventions/models.py | 189 +- pkdb_app/interventions/serializers.py | 19 +- pkdb_app/serializers.py | 2 + pkdb_app/studies/models.py | 39 +- pkdb_app/studies/serializers.py | 101 +- pkdb_app/studies/views.py | 28 +- pkdb_app/subjects/managers.py | 32 +- pkdb_app/subjects/models.py | 108 +- pkdb_app/subjects/serializers.py | 37 +- pkdb_app/subjects/views.py | 8 +- pkdb_app/urls.py | 9 +- pkdb_app/views.py | 1 + requirements.txt | 2 + 29 files changed, 1191 insertions(+), 1757 deletions(-) create mode 100644 pkdb_app/comments/__init__.py create mode 100644 pkdb_app/comments/admin.py create mode 100644 pkdb_app/comments/apps.py create mode 100644 pkdb_app/comments/migrations/0001_initial.py create mode 100644 pkdb_app/comments/migrations/0002_auto_20180803_1409.py create mode 100644 pkdb_app/comments/migrations/0003_comment_user.py create mode 100644 pkdb_app/comments/migrations/__init__.py create mode 100644 pkdb_app/comments/models.py create mode 100644 pkdb_app/comments/tests.py create mode 100644 pkdb_app/comments/views.py diff --git a/CURATION.md b/CURATION.md index 8b1d1933..b5b52ee4 100644 --- a/CURATION.md +++ b/CURATION.md @@ -193,7 +193,6 @@ All available fields for intervention and interventionset are: } ``` * TODO: document after next iteration -* Question: maybe remove individuals and dynamics and add something like `extern/table/mapping`. There you could add mappings. ## 5. Curation of output/outputset diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index d95e0465..423ad9db 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -13,7 +13,7 @@ }, { "cell_type": "code", - "execution_count": 544, + "execution_count": 529, "metadata": { "collapsed": true }, @@ -24,10 +24,8 @@ }, { "cell_type": "code", - "execution_count": 545, - "metadata": { - "collapsed": true - }, + "execution_count": 620, + "metadata": {}, "outputs": [], "source": [ "# import libraries\n", @@ -35,33 +33,98 @@ "import requests\n", "import json\n", "from pprint import pprint\n", - "from requests.auth import HTTPBasicAuth" + "from requests.auth import HTTPBasicAuth\n", + "import base64" ] }, { "cell_type": "code", - "execution_count": 546, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 621, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"detail\":\"Invalid token.\"}'" + ] + }, + "execution_count": 621, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "#response = requests.get('http://0.0.0.0:8000/', auth=HTTPBasicAuth('janek', 'test'))" + "s = requests.Session()\n", + "#s.auth = ('janekg89', 'aterfall89')\n", + "#s.headers.update({'x-test': 'true'})\n", + "headers={\"Authorization\": 'Token 536279e6b11390bb68e942ea592687e28b4ea92e'}\n", + "s.headers.update(headers)\n", + "response = s.get('http://0.0.0.0:8000/api/v1/users/')\n", + "\n", + "response.text\n", + "#response.headers" ] }, { "cell_type": "code", - "execution_count": 547, + "execution_count": 622, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"detail\":\"Invalid token.\"}'" + ] + }, + "execution_count": 622, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "response = s.get('http://0.0.0.0:8000/api/v1/users/')\n", + "response.text" + ] + }, + { + "cell_type": "code", + "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 623, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "b'\\n\\n\\n\\n \\n \\n 403 Forbidden\\n \\n\\n\\n
\\n

Forbidden (403)

\\n

CSRF verification failed. Request aborted.

\\n\\n\\n

You are seeing this message because this site requires a CSRF cookie when submitting forms. This cookie is required for security reasons, to ensure that your browser is not being hijacked by third parties.

\\n

If you have configured your browser to disable cookies, please re-enable them, at least for this site, or for 'same-origin' requests.

\\n\\n
\\n\\n
\\n

Help

\\n \\n

Reason given for failure:

\\n
\\n    CSRF cookie not set.\\n    
\\n \\n\\n

In general, this can occur when there is a genuine Cross Site Request Forgery, or when\\n Django\\'s\\n CSRF mechanism has not been used correctly. For POST forms, you need to\\n ensure:

\\n\\n
    \\n
  • Your browser is accepting cookies.
  • \\n\\n
  • The view function passes a request to the template\\'s render\\n method.
  • \\n\\n
  • In the template, there is a {% csrf_token\\n %} template tag inside each POST form that\\n targets an internal URL.
  • \\n\\n
  • If you are not using CsrfViewMiddleware, then you must use\\n csrf_protect on any views that use the csrf_token\\n template tag, as well as those that accept the POST data.
  • \\n\\n
  • The form has a valid CSRF token. After logging in in another browser\\n tab or hitting the back button after a login, you may need to reload the\\n page with the form, because the token is rotated after a login.
  • \\n
\\n\\n

You\\'re seeing the help section of this page because you have DEBUG =\\n True in your Django settings file. Change that to False,\\n and only the initial error message will be displayed.

\\n\\n

You can customize this page using the CSRF_FAILURE_VIEW setting.

\\n
\\n\\n\\n\\n'" + ] + }, + "execution_count": 623, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "#r = requests.post(\"http://0.0.0.0:8000/api-auth/login/?next=/api/v1/\", data={'username': 'janek', 'password': 'test'})\n", + "#r = requests.post(\"http://0.0.0.0:8000/api-auth/login/?next=/api/v1/\", data={'username': 'janekg89', 'password': 'aterfall89'})\n", "#print(r.status_code, r.reason)\n", - "#r.json()[\"token\"]" + "#r.json()[\"token\"]\n", + "r.content" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -71,7 +134,7 @@ }, { "cell_type": "code", - "execution_count": 548, + "execution_count": 624, "metadata": { "collapsed": true }, @@ -85,14 +148,14 @@ }, { "cell_type": "code", - "execution_count": 549, + "execution_count": 625, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "PkBD API\n", + "PKDB API\n", "http://0.0.0.0:8000/\n" ] } @@ -106,14 +169,14 @@ }, { "cell_type": "code", - "execution_count": 550, + "execution_count": 626, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", " authors: {\n", " list([page], [first_name], [last_name], [search])\n", " create([first_name], [last_name])\n", @@ -122,36 +185,20 @@ " partial_update(id, [first_name], [last_name], [first_name], [last_name], [search])\n", " delete(id, [first_name], [last_name], [search])\n", " }\n", - " characteristic_values: {\n", - " list([page], [choice], [count], [category], [search])\n", - " create(category, [count], [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [cvtype], [group])\n", - " read(id, [choice], [count], [category], [search])\n", - " update(id, category, [count], [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [cvtype], [group], [choice], [count], [category], [search])\n", - " partial_update(id, [count], [choice], [value], [mean], [median], [min], [max], [sd], [se], [cv], [unit], [category], [cvtype], [group], [choice], [count], [category], [search])\n", - " delete(id, [choice], [count], [category], [search])\n", - " }\n", - " groups: {\n", - " list([page], [description], [search])\n", - " create(name, count, characteristic_values, intervention, [description])\n", - " read(id, [description], [search])\n", - " update(id, name, count, characteristic_values, intervention, [description], [description], [search])\n", - " partial_update(id, [name], [count], [description], [characteristic_values], [intervention], [description], [search])\n", - " delete(id, [description], [search])\n", - " }\n", " references: {\n", " list([page], [sid], [search])\n", - " create(name, title, date, authors, [pmid], [sid], [doi], [abstract], [journal], [pdf])\n", + " create(sid, name, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf])\n", " read(sid, [sid], [search])\n", - " update(sid, name, title, date, authors, [pmid], [sid], [doi], [abstract], [journal], [pdf], [sid], [search])\n", + " update(sid, sid, name, title, date, authors, [pmid], [doi], [abstract], [journal], [pdf], [sid], [search])\n", " partial_update(sid, [pmid], [sid], [name], [doi], [title], [abstract], [journal], [date], [authors], [pdf], [sid], [search])\n", " delete(sid, [sid], [search])\n", " }\n", " studies: {\n", " list([page], [sid], [search])\n", - " create(sid, name, groups, reference, [comment], [description])\n", + " create(sid, name, [creator], [pkdb_version], [design], [reference], [curators], [groupset], [substances])\n", " read(sid, [sid], [search])\n", - " update(sid, sid, name, groups, reference, [comment], [description], [sid], [search])\n", - " partial_update(sid, [sid], [comment], [name], [description], [groups], [reference], [sid], [search])\n", + " update(sid, sid, name, [creator], [pkdb_version], [design], [reference], [curators], [groupset], [substances], [sid], [search])\n", + " partial_update(sid, [sid], [name], [creator], [pkdb_version], [design], [reference], [curators], [groupset], [substances], [sid], [search])\n", " delete(sid, [sid], [search])\n", " }\n" ] @@ -162,6 +209,137 @@ "print(document)" ] }, + { + "cell_type": "code", + "execution_count": 628, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'sid': 12087345, 'name': 'Haller2002', 'pkdb_version': 1.0, 'design': '', 'reference': 12087345, 'groupset': {'description': 'Eight healthy volunteers (5 women and 3 men) from 25 to 38 years old participated in the study. Eligibility for the study was determined on the basis of medical history, brief physical examination, and screening laboratory tests that included complete blood count, serum chemistry values to assess liver and renal function, urine toxicology testing for drugs of abuse, and a urine pregnancy test for women. Exclusion criteria included any person with obesity (body mass index 30), or a history of heart, thyroid, liver, kidney, or psychiatric disease, diabetes, central nervous system disorders, prostate hypertrophy, narrow angle glaucoma, or pregnancy or lactation. Any person with recent use (previous 1 month) of any product that contained ephedrine alkaloids or with a history of illicit substance use within the previous year was excluded. Smokers and heavy users of caffeine (4 cups of coffee per day) were excluded. Participants were not taking any medications that would cause changes in heart rate or blood pressure.', 'groups': [{'count': 8, 'name': 'S1', 'characteristica': [{'category': 'healthy', 'choice': 'Y'}, {'category': 'weight', 'mean': '68.49', 'min': '52', 'max': '88.9', 'sd': '12.24', 'unit': 'kg'}, {'category': 'ethnicity', 'choice': None}, {'category': 'oral contraceptives', 'choice': '2 Y || 5 N'}, {'category': 'age', 'mean': None, 'min': '25', 'max': '38', 'unit': 'yr'}, {'category': 'sex', 'choice': '3 M || 5 F'}, {'category': 'smoking', 'choice': 'N'}, {'category': 'species', 'choice': 'homo sapiens'}]}]}}\n" + ] + }, + { + "data": { + "text/plain": [ + "OrderedDict([('sid', '12087345'),\n", + " ('name', 'Haller2002'),\n", + " ('pkdb_version', 1),\n", + " ('design', ''),\n", + " ('reference', '12087345'),\n", + " ('curators', []),\n", + " ('groupset',\n", + " OrderedDict([('description',\n", + " 'Eight healthy volunteers (5 women and 3 men) from 25 to 38 years old participated in the study. Eligibility for the study was determined on the basis of medical history, brief physical examination, and screening laboratory tests that included complete blood count, serum chemistry values to assess liver and renal function, urine toxicology testing for drugs of abuse, and a urine pregnancy test for women. Exclusion criteria included any person with obesity (body mass index 30), or a history of heart, thyroid, liver, kidney, or psychiatric disease, diabetes, central nervous system disorders, prostate hypertrophy, narrow angle glaucoma, or pregnancy or lactation. Any person with recent use (previous 1 month) of any product that contained ephedrine alkaloids or with a history of illicit substance use within the previous year was excluded. Smokers and heavy users of caffeine (4 cups of coffee per day) were excluded. Participants were not taking any medications that would cause changes in heart rate or blood pressure.'),\n", + " ('characteristica', []),\n", + " ('groups',\n", + " [OrderedDict([('name', 'S1'),\n", + " ('count', 8),\n", + " ('characteristica',\n", + " [OrderedDict([('id', 105),\n", + " ('count', 8),\n", + " ('category',\n", + " 'healthy'),\n", + " ('choice', 'Y'),\n", + " ('ctype', 'group'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 106),\n", + " ('count', 8),\n", + " ('mean', 68.49),\n", + " ('min', 52.0),\n", + " ('max', 88.9),\n", + " ('sd', 12.24),\n", + " ('unit', 'kg'),\n", + " ('category',\n", + " 'weight'),\n", + " ('ctype', 'group'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 107),\n", + " ('count', 8),\n", + " ('category',\n", + " 'ethnicity'),\n", + " ('ctype', 'group'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 108),\n", + " ('count', 8),\n", + " ('category',\n", + " 'oral contraceptives'),\n", + " ('choice',\n", + " '2 Y || 5 N'),\n", + " ('ctype', 'group'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 109),\n", + " ('count', 8),\n", + " ('min', 25.0),\n", + " ('max', 38.0),\n", + " ('unit', 'yr'),\n", + " ('category', 'age'),\n", + " ('ctype', 'group'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 110),\n", + " ('count', 8),\n", + " ('category', 'sex'),\n", + " ('choice',\n", + " '3 M || 5 F'),\n", + " ('ctype', 'group'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 111),\n", + " ('count', 8),\n", + " ('category',\n", + " 'smoking'),\n", + " ('choice', 'N'),\n", + " ('ctype', 'group'),\n", + " ('group', 14)]),\n", + " OrderedDict([('id', 112),\n", + " ('count', 8),\n", + " ('category',\n", + " 'species'),\n", + " ('choice',\n", + " 'homo sapiens'),\n", + " ('ctype', 'group'),\n", + " ('group',\n", + " 14)])])])])])),\n", + " ('substances', [])])" + ] + }, + "execution_count": 628, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from coreapi.utils import File\n", + "import json\n", + "with open ('/home/janekg89/Develop/Pycharm_Projects/pkdb/data/Master/Studies/Haller2002/study.json') as file:\n", + " study_dict = json.loads(file.read())\n", + "#client.action(document,[\"references\", \"create\"], params=reference_dict)\n", + "study_partial = {}\n", + "study_partial[\"sid\"] = study_dict[\"sid\"]\n", + "study_partial[\"name\"] =study_dict[\"name\"]\n", + "study_partial[\"pkdb_version\"] = study_dict[\"pkdb_version\"]\n", + "study_partial[\"design\"] = study_dict[\"design\"]\n", + "#study_partial[\"substances\"] = study_dict.get(\"substances\", [])\n", + "study_partial[\"reference\"] = study_dict[\"reference\"]\n", + "#study_partial[\"curators\"] = study_dict[\"curators\"]\n", + "#study_partial[\"creator\"] = study_dict[\"creator\"]\n", + "study_partial[\"groupset\"] = study_dict[\"groupset\"]\n", + "\n", + "print(study_partial)\n", + "\n", + "client.action(document,[\"studies\", \"create\"], params=study_partial)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + " \n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -172,7 +350,7 @@ }, { "cell_type": "code", - "execution_count": 551, + "execution_count": 546, "metadata": {}, "outputs": [ { @@ -180,59 +358,59 @@ "output_type": "stream", "text": [ "{\n", - " \"count\": 108,\n", + " \"count\": 106,\n", " \"next\": \"http://0.0.0.0:8000/api/v1/authors/?page=2\",\n", " \"previous\": null,\n", " \"results\": [\n", " {\n", - " \"id\": 1,\n", - " \"first_name\": \"Lucek\",\n", - " \"last_name\": \"Grzegorzewski\"\n", + " \"id\": 85,\n", + " \"first_name\": \"L\",\n", + " \"last_name\": \"Henschel\"\n", " },\n", " {\n", - " \"id\": 2,\n", - " \"first_name\": \"Christine asdin\",\n", - " \"last_name\": \"Haller\"\n", + " \"id\": 86,\n", + " \"first_name\": \"A\",\n", + " \"last_name\": \"B\\u00f6rner\"\n", " },\n", " {\n", - " \"id\": 43,\n", - " \"first_name\": \"W\",\n", - " \"last_name\": \"Zilly\"\n", + " \"id\": 42,\n", + " \"first_name\": \"E\",\n", + " \"last_name\": \"Richter\"\n", " },\n", " {\n", - " \"id\": 78,\n", - " \"first_name\": \"A H\",\n", - " \"last_name\": \"Neims\"\n", + " \"id\": 43,\n", + " \"first_name\": \"K-Y\",\n", + " \"last_name\": \"Seng\"\n", " },\n", " {\n", - " \"id\": 79,\n", - " \"first_name\": \"M\",\n", - " \"last_name\": \"Bonati\"\n", + " \"id\": 44,\n", + " \"first_name\": \"C-Y\",\n", + " \"last_name\": \"Fun\"\n", " },\n", " {\n", - " \"id\": 44,\n", - " \"first_name\": \"E\",\n", - " \"last_name\": \"Richter\"\n", + " \"id\": 45,\n", + " \"first_name\": \"Y-L\",\n", + " \"last_name\": \"Law\"\n", " },\n", " {\n", - " \"id\": 80,\n", + " \"id\": 87,\n", " \"first_name\": \"R\",\n", - " \"last_name\": \"Latini\"\n", + " \"last_name\": \"Vollanth\"\n", " },\n", " {\n", - " \"id\": 81,\n", - " \"first_name\": \"F\",\n", - " \"last_name\": \"Galletti\"\n", + " \"id\": 46,\n", + " \"first_name\": \"W-M\",\n", + " \"last_name\": \"Lim\"\n", " },\n", " {\n", - " \"id\": 45,\n", - " \"first_name\": \"K-Y\",\n", - " \"last_name\": \"Seng\"\n", + " \"id\": 47,\n", + " \"first_name\": \"W\",\n", + " \"last_name\": \"Fan\"\n", " },\n", " {\n", - " \"id\": 46,\n", - " \"first_name\": \"C-Y\",\n", - " \"last_name\": \"Fun\"\n", + " \"id\": 48,\n", + " \"first_name\": \"C-L\",\n", + " \"last_name\": \"Lim\"\n", " }\n", " ]\n", "}\n" @@ -253,14 +431,14 @@ }, { "cell_type": "code", - "execution_count": 552, + "execution_count": 547, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "OrderedDict([('id', 1), ('first_name', 'Lucek'), ('last_name', 'Grzegorzewski')])\n" + "OrderedDict([('id', 107), ('first_name', 'Lucek'), ('last_name', 'Grzegorzewski')])\n" ] } ], @@ -271,7 +449,7 @@ }, { "cell_type": "code", - "execution_count": 509, + "execution_count": 548, "metadata": {}, "outputs": [ { @@ -284,7 +462,7 @@ " \"previous\": null,\n", " \"results\": [\n", " {\n", - " \"id\": 1,\n", + " \"id\": 107,\n", " \"first_name\": \"Lucek\",\n", " \"last_name\": \"Grzegorzewski\"\n", " }\n", @@ -301,7 +479,7 @@ }, { "cell_type": "code", - "execution_count": 553, + "execution_count": 549, "metadata": {}, "outputs": [ { @@ -314,29 +492,29 @@ " \"previous\": null,\n", " \"results\": [\n", " {\n", - " \"id\": 6,\n", + " \"id\": 2,\n", " \"first_name\": \"L\",\n", " \"last_name\": \"Granit\"\n", " },\n", " {\n", - " \"id\": 55,\n", - " \"first_name\": \"D J\",\n", - " \"last_name\": \"Greenblatt\"\n", - " },\n", - " {\n", - " \"id\": 11,\n", + " \"id\": 9,\n", " \"first_name\": \"Marika T\",\n", " \"last_name\": \"Granfors\"\n", " },\n", " {\n", - " \"id\": 1,\n", - " \"first_name\": \"Lucek\",\n", - " \"last_name\": \"Grzegorzewski\"\n", + " \"id\": 36,\n", + " \"first_name\": \"David J\",\n", + " \"last_name\": \"Greenblatt\"\n", " },\n", " {\n", - " \"id\": 38,\n", - " \"first_name\": \"David J\",\n", + " \"id\": 53,\n", + " \"first_name\": \"D J\",\n", " \"last_name\": \"Greenblatt\"\n", + " },\n", + " {\n", + " \"id\": 107,\n", + " \"first_name\": \"Lucek\",\n", + " \"last_name\": \"Grzegorzewski\"\n", " }\n", " ]\n", "}\n" @@ -352,7 +530,7 @@ }, { "cell_type": "code", - "execution_count": 554, + "execution_count": 550, "metadata": {}, "outputs": [ { @@ -368,18 +546,18 @@ " ('journal', 'Clinical pharmacology and therapeutics'),\n", " ('date', '2002-07-18'),\n", " ('authors',\n", - " [OrderedDict([('id', 2),\n", + " [OrderedDict([('id', 108),\n", " ('first_name', 'Christine asdin'),\n", " ('last_name', 'Haller')]),\n", - " OrderedDict([('id', 3),\n", + " OrderedDict([('id', 7),\n", " ('first_name', 'Peyton'),\n", " ('last_name', 'Jacob')]),\n", - " OrderedDict([('id', 4),\n", + " OrderedDict([('id', 8),\n", " ('first_name', 'Neal L'),\n", " ('last_name', 'Benowitz')])])])" ] }, - "execution_count": 554, + "execution_count": 550, "metadata": {}, "output_type": "execute_result" } @@ -413,1420 +591,56 @@ " }\n", " \n", "\n", - "\n", - "client.action(document, [\"references\", \"create\"], params=reference_dict)" + "client.action(document, [\"references\", \"create\"], params=reference_dict,)" ] }, { "cell_type": "code", - "execution_count": 555, + "execution_count": 464, + "metadata": {}, + "outputs": [ + { + "ename": "ErrorMessage", + "evalue": "\n message: \"TypeError at /api/v1/studies/\n string indices must be integers\n \n Request Method: POST\n Request URL: http://0.0.0.0:8000/api/v1/studies/\n Django Version: 2.0.6\n Python Executable: /usr/local/bin/python\n Python Version: 3.6.6\n Python Path: ['/code', '/usr/local/lib/python36.zip', '/usr/local/lib/python3.6', '/usr/local/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/site-packages']\n Server time: Fri, 3 Aug 2018 13:18:50 +0000\n Installed Applications:\n ('django.contrib.admin',\n 'django.contrib.auth',\n 'django.contrib.contenttypes',\n 'django.contrib.sessions',\n 'django.contrib.messages',\n 'django.contrib.staticfiles',\n 'rest_framework',\n 'rest_framework.authtoken',\n 'django_filters',\n 'rest_framework_swagger',\n 'pkdb_app.users',\n 'pkdb_app.studies',\n 'pkdb_app.subjects',\n 'pkdb_app.interventions',\n 'pkdb_app.comments',\n 'django_nose')\n Installed Middleware:\n ('django.middleware.security.SecurityMiddleware',\n 'django.contrib.sessions.middleware.SessionMiddleware',\n 'django.middleware.common.CommonMiddleware',\n 'django.middleware.csrf.CsrfViewMiddleware',\n 'django.contrib.auth.middleware.AuthenticationMiddleware',\n 'django.contrib.messages.middleware.MessageMiddleware',\n 'django.middleware.clickjacking.XFrameOptionsMiddleware')\n \n \n Traceback:\n \n File \\\"/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py\\\" in inner\n 35. response = get_response(request)\n \n File \\\"/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py\\\" in _get_response\n 128. response = self.process_exception_by_middleware(e, request)\n \n File \\\"/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py\\\" in _get_response\n 126. response = wrapped_callback(request, *callback_args, **callback_kwargs)\n \n File \\\"/usr/local/lib/python3.6/site-packages/django/views/decorators/csrf.py\\\" in wrapped_view\n 54. return view_func(*args, **kwargs)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/viewsets.py\\\" in view\n 103. return self.dispatch(request, *args, **kwargs)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/views.py\\\" in dispatch\n 483. response = self.handle_exception(exc)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/views.py\\\" in handle_exception\n 443. self.raise_uncaught_exception(exc)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/views.py\\\" in dispatch\n 480. response = handler(request, *args, **kwargs)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/mixins.py\\\" in create\n 21. self.perform_create(serializer)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/mixins.py\\\" in perform_create\n 26. serializer.save()\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/serializers.py\\\" in save\n 209. self.instance = self.update(self.instance, validated_data)\n \n File \\\"/code/pkdb_app/studies/serializers.py\\\" in update\n 115. GroupSet.objects.update_or_create(name=group[\\\"name\\\"], study=instance, defaults=group)\n \n Exception Type: TypeError at /api/v1/studies/\n Exception Value: string indices must be integers\n Request information:\n USER: AnonymousUser\n \n GET: No GET data\n \n POST: No POST data\n \n FILES: No FILES data\n \n COOKIES: No cookie data\n \n META:\n CONTENT_LENGTH = '1727'\n CONTENT_TYPE = 'application/json'\n DJANGO_CONFIGURATION = 'Local'\n DJANGO_SECRET_KEY = 'local'\n DJANGO_SETTINGS_MODULE = 'pkdb_app.config'\n GATEWAY_INTERFACE = 'CGI/1.1'\n GPG_KEY = '0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D'\n HOME = '/root'\n HOSTNAME = 'e6c4922496b5'\n HTTP_ACCEPT = 'application/coreapi+json, application/vnd.coreapi+json, */*'\n HTTP_ACCEPT_ENCODING = 'gzip, deflate'\n HTTP_CONNECTION = 'keep-alive'\n HTTP_HOST = '0.0.0.0:8000'\n HTTP_USER_AGENT = 'coreapi'\n LANG = 'C.UTF-8'\n PATH = '/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'\n PATH_INFO = '/api/v1/studies/'\n PWD = '/code'\n PYTHONUNBUFFERED = '1'\n PYTHON_PIP_VERSION = '10.0.1'\n PYTHON_VERSION = '3.6.6'\n QUERY_STRING = ''\n REMOTE_ADDR = '172.20.0.1'\n REMOTE_HOST = ''\n REQUEST_METHOD = 'POST'\n RUN_MAIN = 'true'\n SCRIPT_NAME = ''\n SERVER_NAME = 'e6c4922496b5'\n SERVER_PORT = '8000'\n SERVER_PROTOCOL = 'HTTP/1.1'\n SERVER_SOFTWARE = 'WSGIServer/0.2'\n SHLVL = '1'\n TZ = 'UTC'\n _ = './manage.py'\n wsgi.errors = <_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>\n wsgi.file_wrapper = ''\n wsgi.input = <_io.BufferedReader name=5>\n wsgi.multiprocess = False\n wsgi.multithread = True\n wsgi.run_once = False\n wsgi.url_scheme = 'http'\n wsgi.version = '(1, 0)'\n \n Settings:\n Using settings module pkdb_app.config\n ABSOLUTE_URL_OVERRIDES = {}\n ADMINS = \\\"(('Author', 'janekg89@hotmail.de'),)\\\"\n ALLOWED_HOSTS = ['*']\n APPEND_SLASH = False\n AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend']\n AUTH_PASSWORD_VALIDATORS = '********************'\n AUTH_USER_MODEL = 'users.User'\n CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}\n CACHE_MIDDLEWARE_ALIAS = 'default'\n CACHE_MIDDLEWARE_KEY_PREFIX = '********************'\n CACHE_MIDDLEWARE_SECONDS = 600\n CONFIGURATION = 'pkdb_app.config.Local'\n CSRF_COOKIE_AGE = 31449600\n CSRF_COOKIE_DOMAIN = None\n CSRF_COOKIE_HTTPONLY = False\n CSRF_COOKIE_NAME = 'csrftoken'\n CSRF_COOKIE_PATH = '/'\n CSRF_COOKIE_SECURE = False\n CSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure'\n CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'\n CSRF_TRUSTED_ORIGINS = []\n CSRF_USE_SESSIONS = False\n DATABASES = {'default': {'NAME': 'postgres', 'USER': 'postgres', 'PASSWORD': '********************', 'HOST': 'postgres', 'PORT': 5432, 'CONN_MAX_AGE': 600, 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'OPTIONS': {}, 'TIME_ZONE': None, 'TEST': {'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}}}\n DATABASE_ROUTERS = []\n DATA_UPLOAD_MAX_MEMORY_SIZE = 2621440\n DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000\n DATETIME_FORMAT = 'N j, Y, P'\n DATETIME_INPUT_FORMATS = ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M:%S.%f', '%m/%d/%Y %H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M:%S.%f', '%m/%d/%y %H:%M', '%m/%d/%y']\n DATE_FORMAT = 'N j, Y'\n DATE_INPUT_FORMATS = ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y', '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y', '%B %d, %Y', '%d %B %Y', '%d %B, %Y']\n DEBUG = True\n DEBUG_PROPAGATE_EXCEPTIONS = False\n DECIMAL_SEPARATOR = '.'\n DEFAULT_CHARSET = 'utf-8'\n DEFAULT_CONTENT_TYPE = 'text/html'\n DEFAULT_EXCEPTION_REPORTER_FILTER = 'django.views.debug.SafeExceptionReporterFilter'\n DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'\n DEFAULT_FROM_EMAIL = 'webmaster@localhost'\n DEFAULT_INDEX_TABLESPACE = ''\n DEFAULT_TABLESPACE = ''\n DISALLOWED_USER_AGENTS = []\n DOTENV_LOADED = None\n EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'\n EMAIL_HOST = 'localhost'\n EMAIL_HOST_PASSWORD = '********************'\n EMAIL_HOST_USER = ''\n EMAIL_PORT = 1025\n EMAIL_SSL_CERTFILE = None\n EMAIL_SSL_KEYFILE = '********************'\n EMAIL_SUBJECT_PREFIX = '[Django] '\n EMAIL_TIMEOUT = None\n EMAIL_USE_LOCALTIME = False\n EMAIL_USE_SSL = False\n EMAIL_USE_TLS = False\n FILE_CHARSET = 'utf-8'\n FILE_UPLOAD_DIRECTORY_PERMISSIONS = None\n FILE_UPLOAD_HANDLERS = ['django.core.files.uploadhandler.MemoryFileUploadHandler', 'django.core.files.uploadhandler.TemporaryFileUploadHandler']\n FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440\n FILE_UPLOAD_PERMISSIONS = None\n FILE_UPLOAD_TEMP_DIR = None\n FIRST_DAY_OF_WEEK = 0\n FIXTURE_DIRS = []\n FORCE_SCRIPT_NAME = None\n FORMAT_MODULE_PATH = None\n FORM_RENDERER = 'django.forms.renderers.DjangoTemplates'\n IGNORABLE_404_URLS = []\n INSTALLED_APPS = \\\"('django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', 'django_filters', 'rest_framework_swagger', 'pkdb_app.users', 'pkdb_app.studies', 'pkdb_app.subjects', 'pkdb_app.interventions', 'pkdb_app.comments', 'django_nose')\\\"\n INTERNAL_IPS = []\n LANGUAGES = [('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('dsb', 'Lower Sorbian'), ('el', 'Greek'), ('en', 'English'), ('en-au', 'Australian English'), ('en-gb', 'British English'), ('eo', 'Esperanto'), ('es', 'Spanish'), ('es-ar', 'Argentinian Spanish'), ('es-co', 'Colombian Spanish'), ('es-mx', 'Mexican Spanish'), ('es-ni', 'Nicaraguan Spanish'), ('es-ve', 'Venezuelan Spanish'), ('et', 'Estonian'), ('eu', 'Basque'), ('fa', 'Persian'), ('fi', 'Finnish'), ('fr', 'French'), ('fy', 'Frisian'), ('ga', 'Irish'), ('gd', 'Scottish Gaelic'), ('gl', 'Galician'), ('he', 'Hebrew'), ('hi', 'Hindi'), ('hr', 'Croatian'), ('hsb', 'Upper Sorbian'), ('hu', 'Hungarian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kab', 'Kabyle'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokm\\u00e5l'), ('ne', 'Nepali'), ('nl', 'Dutch'), ('nn', 'Norwegian Nynorsk'), ('os', 'Ossetic'), ('pa', 'Punjabi'), ('pl', 'Polish'), ('pt', 'Portuguese'), ('pt-br', 'Brazilian Portuguese'), ('ro', 'Romanian'), ('ru', 'Russian'), ('sk', 'Slovak'), ('sl', 'Slovenian'), ('sq', 'Albanian'), ('sr', 'Serbian'), ('sr-latn', 'Serbian Latin'), ('sv', 'Swedish'), ('sw', 'Swahili'), ('ta', 'Tamil'), ('te', 'Telugu'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')]\n LANGUAGES_BIDI = ['he', 'ar', 'fa', 'ur']\n LANGUAGE_CODE = 'en-us'\n LANGUAGE_COOKIE_AGE = None\n LANGUAGE_COOKIE_DOMAIN = None\n LANGUAGE_COOKIE_NAME = 'django_language'\n LANGUAGE_COOKIE_PATH = '/'\n LOCALE_PATHS = []\n LOGGING = {'version': 1, 'disable_existing_loggers': False, 'formatters': {'django.server': {'()': 'django.utils.log.ServerFormatter', 'format': '[%(server_time)s] %(message)s'}, 'verbose': {'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'}, 'simple': {'format': '%(levelname)s %(message)s'}}, 'filters': {'require_debug_true': {'()': 'django.utils.log.RequireDebugTrue'}}, 'handlers': {'django.server': {'level': 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'django.server'}, 'console': {'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'simple'}, 'mail_admins': {'level': 'ERROR', 'class': 'django.utils.log.AdminEmailHandler'}}, 'loggers': {'django': {'handlers': ['console'], 'propagate': True}, 'django.server': {'handlers': ['django.server'], 'level': 'INFO', 'propagate': False}, 'django.request': {'handlers': ['mail_admins', 'console'], 'level': 'ERROR', 'propagate': False}, 'django.db.backends': {'handlers': ['console'], 'level': 'INFO'}}}\n LOGGING_CONFIG = 'logging.config.dictConfig'\n LOGIN_REDIRECT_URL = '/'\n LOGIN_URL = 'rest_framework:login'\n LOGOUT_REDIRECT_URL = None\n LOGOUT_URL = 'rest_framework:logout'\n MANAGERS = []\n MEDIA_ROOT = '/code/media'\n MEDIA_URL = '/media/'\n MESSAGE_STORAGE = 'django.contrib.messages.storage.fallback.FallbackStorage'\n MIDDLEWARE = \\\"('django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware')\\\"\n MIGRATION_MODULES = {}\n MONTH_DAY_FORMAT = 'F j'\n NOSE_ARGS = ['/code/pkdb_app', '-s', '--nologcapture', '--with-coverage', '--with-progressive', '--cover-package=pkdb']\n NUMBER_GROUPING = 0\n PASSWORD_HASHERS = '********************'\n PASSWORD_RESET_TIMEOUT_DAYS = '********************'\n PREPEND_WWW = False\n REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10, 'DATETIME_FORMAT': '%Y-%m-%dT%H:%M:%S%z', 'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer'), 'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'], 'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication'), 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)}\n ROOT_URLCONF = 'pkdb_app.urls'\n SECRET_KEY = '********************'\n SECURE_BROWSER_XSS_FILTER = False\n SECURE_CONTENT_TYPE_NOSNIFF = False\n SECURE_HSTS_INCLUDE_SUBDOMAINS = False\n SECURE_HSTS_PRELOAD = False\n SECURE_HSTS_SECONDS = 0\n SECURE_PROXY_SSL_HEADER = None\n SECURE_REDIRECT_EXEMPT = []\n SECURE_SSL_HOST = None\n SECURE_SSL_REDIRECT = False\n SERVER_EMAIL = 'root@localhost'\n SESSION_CACHE_ALIAS = 'default'\n SESSION_COOKIE_AGE = 1209600\n SESSION_COOKIE_DOMAIN = None\n SESSION_COOKIE_HTTPONLY = True\n SESSION_COOKIE_NAME = 'sessionid'\n SESSION_COOKIE_PATH = '/'\n SESSION_COOKIE_SECURE = False\n SESSION_ENGINE = 'django.contrib.sessions.backends.db'\n SESSION_EXPIRE_AT_BROWSER_CLOSE = False\n SESSION_FILE_PATH = None\n SESSION_SAVE_EVERY_REQUEST = False\n SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'\n SETTINGS_MODULE = 'pkdb_app.config'\n SHORT_DATETIME_FORMAT = 'm/d/Y P'\n SHORT_DATE_FORMAT = 'm/d/Y'\n SIGNING_BACKEND = 'django.core.signing.TimestampSigner'\n SILENCED_SYSTEM_CHECKS = []\n STATICFILES_DIRS = []\n STATICFILES_FINDERS = \\\"('django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder')\\\"\n STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'\n STATIC_ROOT = '/code/static'\n STATIC_URL = '/static/'\n SWAGGER_SETTINGS = {'LOGIN_URL': 'rest_framework:login', 'LOGOUT_URL': 'rest_framework:logout', 'USE_SESSION_AUTH': True, 'DOC_EXPANSION': 'list', 'APIS_SORTER': '********************', 'SECURITY_DEFINITIONS': {'basic': {'type': 'basic'}}}\n TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': {'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages']}}]\n TEST_NON_SERIALIZED_APPS = []\n TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'\n THOUSAND_SEPARATOR = ','\n TIME_FORMAT = 'P'\n TIME_INPUT_FORMATS = ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']\n TIME_ZONE = 'UTC'\n USE_ETAGS = False\n USE_I18N = False\n USE_L10N = True\n USE_THOUSAND_SEPARATOR = False\n USE_TZ = True\n USE_X_FORWARDED_HOST = False\n USE_X_FORWARDED_PORT = False\n WSGI_APPLICATION = 'pkdb_app.wsgi.application'\n X_FRAME_OPTIONS = 'SAMEORIGIN'\n YEAR_MONTH_FORMAT = 'F Y'\n \n \n You're seeing this error because you have DEBUG = True in your\n Django settings file. Change that to False, and Django will\n display a standard page generated by the handler for this status code.\n \n \"", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0mstudy_partial\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"groupset\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstudy_dict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"groupset\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"studies\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_partial\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mErrorMessage\u001b[0m: \n message: \"TypeError at /api/v1/studies/\n string indices must be integers\n \n Request Method: POST\n Request URL: http://0.0.0.0:8000/api/v1/studies/\n Django Version: 2.0.6\n Python Executable: /usr/local/bin/python\n Python Version: 3.6.6\n Python Path: ['/code', '/usr/local/lib/python36.zip', '/usr/local/lib/python3.6', '/usr/local/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/site-packages']\n Server time: Fri, 3 Aug 2018 13:18:50 +0000\n Installed Applications:\n ('django.contrib.admin',\n 'django.contrib.auth',\n 'django.contrib.contenttypes',\n 'django.contrib.sessions',\n 'django.contrib.messages',\n 'django.contrib.staticfiles',\n 'rest_framework',\n 'rest_framework.authtoken',\n 'django_filters',\n 'rest_framework_swagger',\n 'pkdb_app.users',\n 'pkdb_app.studies',\n 'pkdb_app.subjects',\n 'pkdb_app.interventions',\n 'pkdb_app.comments',\n 'django_nose')\n Installed Middleware:\n ('django.middleware.security.SecurityMiddleware',\n 'django.contrib.sessions.middleware.SessionMiddleware',\n 'django.middleware.common.CommonMiddleware',\n 'django.middleware.csrf.CsrfViewMiddleware',\n 'django.contrib.auth.middleware.AuthenticationMiddleware',\n 'django.contrib.messages.middleware.MessageMiddleware',\n 'django.middleware.clickjacking.XFrameOptionsMiddleware')\n \n \n Traceback:\n \n File \\\"/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py\\\" in inner\n 35. response = get_response(request)\n \n File \\\"/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py\\\" in _get_response\n 128. response = self.process_exception_by_middleware(e, request)\n \n File \\\"/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py\\\" in _get_response\n 126. response = wrapped_callback(request, *callback_args, **callback_kwargs)\n \n File \\\"/usr/local/lib/python3.6/site-packages/django/views/decorators/csrf.py\\\" in wrapped_view\n 54. return view_func(*args, **kwargs)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/viewsets.py\\\" in view\n 103. return self.dispatch(request, *args, **kwargs)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/views.py\\\" in dispatch\n 483. response = self.handle_exception(exc)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/views.py\\\" in handle_exception\n 443. self.raise_uncaught_exception(exc)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/views.py\\\" in dispatch\n 480. response = handler(request, *args, **kwargs)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/mixins.py\\\" in create\n 21. self.perform_create(serializer)\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/mixins.py\\\" in perform_create\n 26. serializer.save()\n \n File \\\"/usr/local/lib/python3.6/site-packages/rest_framework/serializers.py\\\" in save\n 209. self.instance = self.update(self.instance, validated_data)\n \n File \\\"/code/pkdb_app/studies/serializers.py\\\" in update\n 115. GroupSet.objects.update_or_create(name=group[\\\"name\\\"], study=instance, defaults=group)\n \n Exception Type: TypeError at /api/v1/studies/\n Exception Value: string indices must be integers\n Request information:\n USER: AnonymousUser\n \n GET: No GET data\n \n POST: No POST data\n \n FILES: No FILES data\n \n COOKIES: No cookie data\n \n META:\n CONTENT_LENGTH = '1727'\n CONTENT_TYPE = 'application/json'\n DJANGO_CONFIGURATION = 'Local'\n DJANGO_SECRET_KEY = 'local'\n DJANGO_SETTINGS_MODULE = 'pkdb_app.config'\n GATEWAY_INTERFACE = 'CGI/1.1'\n GPG_KEY = '0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D'\n HOME = '/root'\n HOSTNAME = 'e6c4922496b5'\n HTTP_ACCEPT = 'application/coreapi+json, application/vnd.coreapi+json, */*'\n HTTP_ACCEPT_ENCODING = 'gzip, deflate'\n HTTP_CONNECTION = 'keep-alive'\n HTTP_HOST = '0.0.0.0:8000'\n HTTP_USER_AGENT = 'coreapi'\n LANG = 'C.UTF-8'\n PATH = '/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'\n PATH_INFO = '/api/v1/studies/'\n PWD = '/code'\n PYTHONUNBUFFERED = '1'\n PYTHON_PIP_VERSION = '10.0.1'\n PYTHON_VERSION = '3.6.6'\n QUERY_STRING = ''\n REMOTE_ADDR = '172.20.0.1'\n REMOTE_HOST = ''\n REQUEST_METHOD = 'POST'\n RUN_MAIN = 'true'\n SCRIPT_NAME = ''\n SERVER_NAME = 'e6c4922496b5'\n SERVER_PORT = '8000'\n SERVER_PROTOCOL = 'HTTP/1.1'\n SERVER_SOFTWARE = 'WSGIServer/0.2'\n SHLVL = '1'\n TZ = 'UTC'\n _ = './manage.py'\n wsgi.errors = <_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>\n wsgi.file_wrapper = ''\n wsgi.input = <_io.BufferedReader name=5>\n wsgi.multiprocess = False\n wsgi.multithread = True\n wsgi.run_once = False\n wsgi.url_scheme = 'http'\n wsgi.version = '(1, 0)'\n \n Settings:\n Using settings module pkdb_app.config\n ABSOLUTE_URL_OVERRIDES = {}\n ADMINS = \\\"(('Author', 'janekg89@hotmail.de'),)\\\"\n ALLOWED_HOSTS = ['*']\n APPEND_SLASH = False\n AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend']\n AUTH_PASSWORD_VALIDATORS = '********************'\n AUTH_USER_MODEL = 'users.User'\n CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}\n CACHE_MIDDLEWARE_ALIAS = 'default'\n CACHE_MIDDLEWARE_KEY_PREFIX = '********************'\n CACHE_MIDDLEWARE_SECONDS = 600\n CONFIGURATION = 'pkdb_app.config.Local'\n CSRF_COOKIE_AGE = 31449600\n CSRF_COOKIE_DOMAIN = None\n CSRF_COOKIE_HTTPONLY = False\n CSRF_COOKIE_NAME = 'csrftoken'\n CSRF_COOKIE_PATH = '/'\n CSRF_COOKIE_SECURE = False\n CSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure'\n CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'\n CSRF_TRUSTED_ORIGINS = []\n CSRF_USE_SESSIONS = False\n DATABASES = {'default': {'NAME': 'postgres', 'USER': 'postgres', 'PASSWORD': '********************', 'HOST': 'postgres', 'PORT': 5432, 'CONN_MAX_AGE': 600, 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'OPTIONS': {}, 'TIME_ZONE': None, 'TEST': {'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}}}\n DATABASE_ROUTERS = []\n DATA_UPLOAD_MAX_MEMORY_SIZE = 2621440\n DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000\n DATETIME_FORMAT = 'N j, Y, P'\n DATETIME_INPUT_FORMATS = ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M:%S.%f', '%m/%d/%Y %H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M:%S.%f', '%m/%d/%y %H:%M', '%m/%d/%y']\n DATE_FORMAT = 'N j, Y'\n DATE_INPUT_FORMATS = ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y', '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y', '%B %d, %Y', '%d %B %Y', '%d %B, %Y']\n DEBUG = True\n DEBUG_PROPAGATE_EXCEPTIONS = False\n DECIMAL_SEPARATOR = '.'\n DEFAULT_CHARSET = 'utf-8'\n DEFAULT_CONTENT_TYPE = 'text/html'\n DEFAULT_EXCEPTION_REPORTER_FILTER = 'django.views.debug.SafeExceptionReporterFilter'\n DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'\n DEFAULT_FROM_EMAIL = 'webmaster@localhost'\n DEFAULT_INDEX_TABLESPACE = ''\n DEFAULT_TABLESPACE = ''\n DISALLOWED_USER_AGENTS = []\n DOTENV_LOADED = None\n EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'\n EMAIL_HOST = 'localhost'\n EMAIL_HOST_PASSWORD = '********************'\n EMAIL_HOST_USER = ''\n EMAIL_PORT = 1025\n EMAIL_SSL_CERTFILE = None\n EMAIL_SSL_KEYFILE = '********************'\n EMAIL_SUBJECT_PREFIX = '[Django] '\n EMAIL_TIMEOUT = None\n EMAIL_USE_LOCALTIME = False\n EMAIL_USE_SSL = False\n EMAIL_USE_TLS = False\n FILE_CHARSET = 'utf-8'\n FILE_UPLOAD_DIRECTORY_PERMISSIONS = None\n FILE_UPLOAD_HANDLERS = ['django.core.files.uploadhandler.MemoryFileUploadHandler', 'django.core.files.uploadhandler.TemporaryFileUploadHandler']\n FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440\n FILE_UPLOAD_PERMISSIONS = None\n FILE_UPLOAD_TEMP_DIR = None\n FIRST_DAY_OF_WEEK = 0\n FIXTURE_DIRS = []\n FORCE_SCRIPT_NAME = None\n FORMAT_MODULE_PATH = None\n FORM_RENDERER = 'django.forms.renderers.DjangoTemplates'\n IGNORABLE_404_URLS = []\n INSTALLED_APPS = \\\"('django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', 'django_filters', 'rest_framework_swagger', 'pkdb_app.users', 'pkdb_app.studies', 'pkdb_app.subjects', 'pkdb_app.interventions', 'pkdb_app.comments', 'django_nose')\\\"\n INTERNAL_IPS = []\n LANGUAGES = [('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('dsb', 'Lower Sorbian'), ('el', 'Greek'), ('en', 'English'), ('en-au', 'Australian English'), ('en-gb', 'British English'), ('eo', 'Esperanto'), ('es', 'Spanish'), ('es-ar', 'Argentinian Spanish'), ('es-co', 'Colombian Spanish'), ('es-mx', 'Mexican Spanish'), ('es-ni', 'Nicaraguan Spanish'), ('es-ve', 'Venezuelan Spanish'), ('et', 'Estonian'), ('eu', 'Basque'), ('fa', 'Persian'), ('fi', 'Finnish'), ('fr', 'French'), ('fy', 'Frisian'), ('ga', 'Irish'), ('gd', 'Scottish Gaelic'), ('gl', 'Galician'), ('he', 'Hebrew'), ('hi', 'Hindi'), ('hr', 'Croatian'), ('hsb', 'Upper Sorbian'), ('hu', 'Hungarian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kab', 'Kabyle'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokm\\u00e5l'), ('ne', 'Nepali'), ('nl', 'Dutch'), ('nn', 'Norwegian Nynorsk'), ('os', 'Ossetic'), ('pa', 'Punjabi'), ('pl', 'Polish'), ('pt', 'Portuguese'), ('pt-br', 'Brazilian Portuguese'), ('ro', 'Romanian'), ('ru', 'Russian'), ('sk', 'Slovak'), ('sl', 'Slovenian'), ('sq', 'Albanian'), ('sr', 'Serbian'), ('sr-latn', 'Serbian Latin'), ('sv', 'Swedish'), ('sw', 'Swahili'), ('ta', 'Tamil'), ('te', 'Telugu'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')]\n LANGUAGES_BIDI = ['he', 'ar', 'fa', 'ur']\n LANGUAGE_CODE = 'en-us'\n LANGUAGE_COOKIE_AGE = None\n LANGUAGE_COOKIE_DOMAIN = None\n LANGUAGE_COOKIE_NAME = 'django_language'\n LANGUAGE_COOKIE_PATH = '/'\n LOCALE_PATHS = []\n LOGGING = {'version': 1, 'disable_existing_loggers': False, 'formatters': {'django.server': {'()': 'django.utils.log.ServerFormatter', 'format': '[%(server_time)s] %(message)s'}, 'verbose': {'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'}, 'simple': {'format': '%(levelname)s %(message)s'}}, 'filters': {'require_debug_true': {'()': 'django.utils.log.RequireDebugTrue'}}, 'handlers': {'django.server': {'level': 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'django.server'}, 'console': {'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'simple'}, 'mail_admins': {'level': 'ERROR', 'class': 'django.utils.log.AdminEmailHandler'}}, 'loggers': {'django': {'handlers': ['console'], 'propagate': True}, 'django.server': {'handlers': ['django.server'], 'level': 'INFO', 'propagate': False}, 'django.request': {'handlers': ['mail_admins', 'console'], 'level': 'ERROR', 'propagate': False}, 'django.db.backends': {'handlers': ['console'], 'level': 'INFO'}}}\n LOGGING_CONFIG = 'logging.config.dictConfig'\n LOGIN_REDIRECT_URL = '/'\n LOGIN_URL = 'rest_framework:login'\n LOGOUT_REDIRECT_URL = None\n LOGOUT_URL = 'rest_framework:logout'\n MANAGERS = []\n MEDIA_ROOT = '/code/media'\n MEDIA_URL = '/media/'\n MESSAGE_STORAGE = 'django.contrib.messages.storage.fallback.FallbackStorage'\n MIDDLEWARE = \\\"('django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware')\\\"\n MIGRATION_MODULES = {}\n MONTH_DAY_FORMAT = 'F j'\n NOSE_ARGS = ['/code/pkdb_app', '-s', '--nologcapture', '--with-coverage', '--with-progressive', '--cover-package=pkdb']\n NUMBER_GROUPING = 0\n PASSWORD_HASHERS = '********************'\n PASSWORD_RESET_TIMEOUT_DAYS = '********************'\n PREPEND_WWW = False\n REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10, 'DATETIME_FORMAT': '%Y-%m-%dT%H:%M:%S%z', 'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer'), 'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'], 'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication'), 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)}\n ROOT_URLCONF = 'pkdb_app.urls'\n SECRET_KEY = '********************'\n SECURE_BROWSER_XSS_FILTER = False\n SECURE_CONTENT_TYPE_NOSNIFF = False\n SECURE_HSTS_INCLUDE_SUBDOMAINS = False\n SECURE_HSTS_PRELOAD = False\n SECURE_HSTS_SECONDS = 0\n SECURE_PROXY_SSL_HEADER = None\n SECURE_REDIRECT_EXEMPT = []\n SECURE_SSL_HOST = None\n SECURE_SSL_REDIRECT = False\n SERVER_EMAIL = 'root@localhost'\n SESSION_CACHE_ALIAS = 'default'\n SESSION_COOKIE_AGE = 1209600\n SESSION_COOKIE_DOMAIN = None\n SESSION_COOKIE_HTTPONLY = True\n SESSION_COOKIE_NAME = 'sessionid'\n SESSION_COOKIE_PATH = '/'\n SESSION_COOKIE_SECURE = False\n SESSION_ENGINE = 'django.contrib.sessions.backends.db'\n SESSION_EXPIRE_AT_BROWSER_CLOSE = False\n SESSION_FILE_PATH = None\n SESSION_SAVE_EVERY_REQUEST = False\n SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'\n SETTINGS_MODULE = 'pkdb_app.config'\n SHORT_DATETIME_FORMAT = 'm/d/Y P'\n SHORT_DATE_FORMAT = 'm/d/Y'\n SIGNING_BACKEND = 'django.core.signing.TimestampSigner'\n SILENCED_SYSTEM_CHECKS = []\n STATICFILES_DIRS = []\n STATICFILES_FINDERS = \\\"('django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder')\\\"\n STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'\n STATIC_ROOT = '/code/static'\n STATIC_URL = '/static/'\n SWAGGER_SETTINGS = {'LOGIN_URL': 'rest_framework:login', 'LOGOUT_URL': 'rest_framework:logout', 'USE_SESSION_AUTH': True, 'DOC_EXPANSION': 'list', 'APIS_SORTER': '********************', 'SECURITY_DEFINITIONS': {'basic': {'type': 'basic'}}}\n TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': {'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages']}}]\n TEST_NON_SERIALIZED_APPS = []\n TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'\n THOUSAND_SEPARATOR = ','\n TIME_FORMAT = 'P'\n TIME_INPUT_FORMATS = ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']\n TIME_ZONE = 'UTC'\n USE_ETAGS = False\n USE_I18N = False\n USE_L10N = True\n USE_THOUSAND_SEPARATOR = False\n USE_TZ = True\n USE_X_FORWARDED_HOST = False\n USE_X_FORWARDED_PORT = False\n WSGI_APPLICATION = 'pkdb_app.wsgi.application'\n X_FRAME_OPTIONS = 'SAMEORIGIN'\n YEAR_MONTH_FORMAT = 'F Y'\n \n \n You're seeing this error because you have DEBUG = True in your\n Django settings file. Change that to False, and Django will\n display a standard page generated by the handler for this status code.\n \n \"" + ] + } + ], + "source": [ + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 264, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "OrderedDict([('count', 26),\n", - " ('next', 'http://0.0.0.0:8000/api/v1/studies/?page=2'),\n", + "OrderedDict([('count', 0),\n", + " ('next', None),\n", " ('previous', None),\n", - " ('results',\n", - " [OrderedDict([('sid', '19023902'),\n", - " ('name', 'test'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'Seng2009-S_NCNS'),\n", - " ('count', 14),\n", - " ('description',\n", - " '59 healthy adult Asian volunteers were included. In what follows, a non-caffeine consumer (NCCS) refers to an individual who consumed beverages\\n(coffee or tea) containing <=200 mg of caffeine per day, and a regular caffeine consumer to one who consumed more >200 mg. A cup (150 mL) of coffee or tea is equivalent to approximately a caffeine dose of 70 and 25 mg respectively (9). Additionally, a non-smoker refers to an individual who did not smoke for at least 6 months prior to dosing. The study population consisted of 14 non-caffeine consumers, non-smokers (NCNS) [age (mean ± SD) 21 ± 2 years, body weight 62 ± 9 kg), 15 caffeine consumers, non smokers (CNS) (age 24 ± 4 years, body weight 69 ± 12 kg), and 30 caffeine consumer, smokers (CS) (actual consumption 10 ± 4 cigarettes daily, age 23 ± 5 years, body weight 71 ± 19 kg).'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 9),\n", - " ('count', 14),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 1)]),\n", - " OrderedDict([('id', 10),\n", - " ('count', 14),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 1)]),\n", - " OrderedDict([('id', 11),\n", - " ('count', 14),\n", - " ('mean', 62.0),\n", - " ('sd', 9.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 1)]),\n", - " OrderedDict([('id', 12),\n", - " ('count', 14),\n", - " ('choice', 'Asian'),\n", - " ('category',\n", - " 'ethnicity'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 1)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '012087345981')]),\n", - " OrderedDict([('sid', '16198659'),\n", - " ('name', 'Granfors2005'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'Granfors2005-S2'),\n", - " ('count', 15),\n", - " ('description',\n", - " 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1853),\n", - " ('count', 15),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 1854),\n", - " ('count', 15),\n", - " ('mean', 57.0),\n", - " ('min', 48.0),\n", - " ('max', 63.0),\n", - " ('sd', 6.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 1855),\n", - " ('count', 15),\n", - " ('mean', 22.0),\n", - " ('min', 18.0),\n", - " ('max', 25.0),\n", - " ('sd', 2.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 1856),\n", - " ('count', 15),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 1857),\n", - " ('count', 15),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 1858),\n", - " ('count', 15),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 3)]),\n", - " OrderedDict([('id', 1859),\n", - " ('count', 15),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 3)])]),\n", - " ('intervention', [])]),\n", - " OrderedDict([('name', 'Granfors2005-S1'),\n", - " ('count', 15),\n", - " ('description',\n", - " 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1846),\n", - " ('count', 15),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 1847),\n", - " ('count', 15),\n", - " ('mean', 62.0),\n", - " ('min', 52.0),\n", - " ('max', 74.0),\n", - " ('sd', 10.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 1848),\n", - " ('count', 15),\n", - " ('mean', 22.0),\n", - " ('min', 19.0),\n", - " ('max', 26.0),\n", - " ('sd', 2.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 1849),\n", - " ('count', 15),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 1850),\n", - " ('count', 15),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 1851),\n", - " ('count', 15),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 2)]),\n", - " OrderedDict([('id', 1852),\n", - " ('count', 15),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 2)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '16198659')]),\n", - " OrderedDict([('sid', '6734043'),\n", - " ('name', 'ZylberKatz1984'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'ZylberKatz1984-S2'),\n", - " ('count', 3),\n", - " ('description',\n", - " 'Subjects were 7 healthy men and 5 women ranging in age from 22 to 47 years. All were nonsmokers and reported only casual alcohol consumption, and none were taking any medication. Habitual daily coffee intake varied from 1 to 6 cups. Results of blood biochemistry (SMAC12) were normal in all.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1814),\n", - " ('count', 3),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 5)]),\n", - " OrderedDict([('id', 1815),\n", - " ('count', 3),\n", - " ('mean', 70.33),\n", - " ('min', 58.0),\n", - " ('max', 91.0),\n", - " ('sd', 14.7),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 5)]),\n", - " OrderedDict([('id', 1816),\n", - " ('count', 3),\n", - " ('mean', 27.33),\n", - " ('min', 24.0),\n", - " ('max', 30.0),\n", - " ('sd', 2.49),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 5)]),\n", - " OrderedDict([('id', 1817),\n", - " ('count', 3),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 5)]),\n", - " OrderedDict([('id', 1818),\n", - " ('count', 3),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 5)]),\n", - " OrderedDict([('id', 1819),\n", - " ('count', 3),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 5)]),\n", - " OrderedDict([('id', 1820),\n", - " ('count', 2),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 5)]),\n", - " OrderedDict([('id', 1821),\n", - " ('count', 1),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 5)])]),\n", - " ('intervention', [])]),\n", - " OrderedDict([('name', 'ZylberKatz1984-S1'),\n", - " ('count', 5),\n", - " ('description',\n", - " 'Subjects were 7 healthy men and 5 women ranging in age from 22 to 47 years. All were nonsmokers and reported only casual alcohol consumption, and none were taking any medication. Habitual daily coffee intake varied from 1 to 6 cups. Results of blood biochemistry (SMAC12) were normal in all.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1806),\n", - " ('count', 5),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 4)]),\n", - " OrderedDict([('id', 1807),\n", - " ('count', 5),\n", - " ('mean', 76.2),\n", - " ('min', 60.0),\n", - " ('max', 88.0),\n", - " ('sd', 12.1),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 4)]),\n", - " OrderedDict([('id', 1808),\n", - " ('count', 5),\n", - " ('mean', 41.6),\n", - " ('min', 29.0),\n", - " ('max', 47.0),\n", - " ('sd', 6.44),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 4)]),\n", - " OrderedDict([('id', 1809),\n", - " ('count', 5),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 4)]),\n", - " OrderedDict([('id', 1810),\n", - " ('count', 5),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 4)]),\n", - " OrderedDict([('id', 1811),\n", - " ('count', 5),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 4)]),\n", - " OrderedDict([('id', 1812),\n", - " ('count', 3),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 4)]),\n", - " OrderedDict([('id', 1813),\n", - " ('count', 2),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 4)])]),\n", - " ('intervention', [])]),\n", - " OrderedDict([('name', 'ZylberKatz1984-S3'),\n", - " ('count', 4),\n", - " ('description',\n", - " 'Subjects were 7 healthy men and 5 women ranging in age from 22 to 47 years. All were nonsmokers and reported only casual alcohol consumption, and none were taking any medication. Habitual daily coffee intake varied from 1 to 6 cups. Results of blood biochemistry (SMAC12) were normal in all.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1822),\n", - " ('count', 4),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 6)]),\n", - " OrderedDict([('id', 1823),\n", - " ('count', 4),\n", - " ('mean', 62.75),\n", - " ('min', 46.0),\n", - " ('max', 75.0),\n", - " ('sd', 10.9),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 6)]),\n", - " OrderedDict([('id', 1824),\n", - " ('count', 4),\n", - " ('mean', 27.25),\n", - " ('min', 22.0),\n", - " ('max', 31.0),\n", - " ('sd', 3.56),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 6)]),\n", - " OrderedDict([('id', 1825),\n", - " ('count', 4),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 6)]),\n", - " OrderedDict([('id', 1826),\n", - " ('count', 4),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 6)]),\n", - " OrderedDict([('id', 1827),\n", - " ('count', 4),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 6)]),\n", - " OrderedDict([('id', 1828),\n", - " ('count', 2),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 6)]),\n", - " OrderedDict([('id', 1829),\n", - " ('count', 2),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 6)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '6734043')]),\n", - " OrderedDict([('sid', '6832208'),\n", - " ('name', 'Blanchard1983a'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'Blanchard1983a-S1'),\n", - " ('count', 10),\n", - " ('description',\n", - " '10 healthy adult male volunteers, aged 18.8 to 30.0 years;\\nHealthy adult male Caucasian volunteers. None of the subjects were taking any prescription or non-presecription medication at time of the study.\\nEach subject was fasted from the previous evening until at least 2h after the administration of the oral dose.\\nSubjects were instructed to abstain from caffeine-containing food and beverages, tobacco (9 of the 10 subjects were non-smokers) and alcohol from 72h before, until 24h after caffeine administration.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1830),\n", - " ('count', 10),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 7)]),\n", - " OrderedDict([('id', 1831),\n", - " ('count', 10),\n", - " ('mean', 79.5),\n", - " ('min', 64.0),\n", - " ('max', 106.0),\n", - " ('se', 3.9),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 7)]),\n", - " OrderedDict([('id', 1832),\n", - " ('count', 10),\n", - " ('mean', 21.8),\n", - " ('min', 18.8),\n", - " ('max', 30.0),\n", - " ('se', 1.1),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 7)]),\n", - " OrderedDict([('id', 1833),\n", - " ('count', 10),\n", - " ('choice',\n", - " 'Caucasian'),\n", - " ('category',\n", - " 'ethnicity'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 7)]),\n", - " OrderedDict([('id', 1834),\n", - " ('count', 10),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 7)]),\n", - " OrderedDict([('id', 1835),\n", - " ('count', 10),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 7)]),\n", - " OrderedDict([('id', 1836),\n", - " ('count', 10),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 7)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '6832208')]),\n", - " OrderedDict([('sid', '12087345'),\n", - " ('name', 'Haller2002'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'Haller2002-S1'),\n", - " ('count', 8),\n", - " ('description',\n", - " 'Eight healthy volunteers (5 women and 3 men) from 25 to 38 years old participated in the study. Eligibility for the study was determined on the basis of medical history, brief physical examination, and screening laboratory tests that included complete blood count, serum chemistry values to assess liver and renal function, urine toxicology testing for drugs of abuse, and a urine pregnancy test for women. Exclusion criteria included any person with obesity (body mass index 30), or a history of heart, thyroid, liver, kidney, or psychiatric disease, diabetes, central nervous system disorders, prostate hypertrophy, narrow angle glaucoma, or pregnancy or lactation. Any person with recent use (previous 1 month) of any product that contained ephedrine alkaloids or with a history of illicit substance use within the previous year was excluded. Smokers and heavy users of caffeine (4 cups of coffee per day) were excluded. Participants were not taking any medications that would cause changes in heart rate or blood pressure.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1837),\n", - " ('count', 8),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 8)]),\n", - " OrderedDict([('id', 1838),\n", - " ('count', 8),\n", - " ('mean', 68.49),\n", - " ('min', 52.0),\n", - " ('max', 88.9),\n", - " ('sd', 12.24),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 8)]),\n", - " OrderedDict([('id', 1839),\n", - " ('count', 8),\n", - " ('min', 25.0),\n", - " ('max', 38.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 8)]),\n", - " OrderedDict([('id', 1840),\n", - " ('count', 8),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 8)]),\n", - " OrderedDict([('id', 1841),\n", - " ('count', 2),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 8)]),\n", - " OrderedDict([('id', 1842),\n", - " ('count', 5),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 8)]),\n", - " OrderedDict([('id', 1843),\n", - " ('count', 8),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 8)]),\n", - " OrderedDict([('id', 1844),\n", - " ('count', 3),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 8)]),\n", - " OrderedDict([('id', 1845),\n", - " ('count', 5),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 8)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '12087345')]),\n", - " OrderedDict([('sid', '6420303'),\n", - " ('name', 'Renner1984'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'Renner1984-S1'),\n", - " ('count', 10),\n", - " ('description',\n", - " '10 healthy volunteers (information in table 2)'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1860),\n", - " ('count', 4),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 9)]),\n", - " OrderedDict([('id', 1861),\n", - " ('count', 6),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 9)]),\n", - " OrderedDict([('id', 1862),\n", - " ('count', 10),\n", - " ('mean', 74.0),\n", - " ('min', 58.0),\n", - " ('max', 86.0),\n", - " ('sd', 10.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 9)]),\n", - " OrderedDict([('id', 1863),\n", - " ('count', 10),\n", - " ('mean', 38.0),\n", - " ('min', 27.0),\n", - " ('max', 56.0),\n", - " ('sd', 11.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 9)]),\n", - " OrderedDict([('id', 1864),\n", - " ('count', 10),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 9)]),\n", - " OrderedDict([('id', 1865),\n", - " ('count', 10),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 9)]),\n", - " OrderedDict([('id', 1866),\n", - " ('count', 10),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 9)]),\n", - " OrderedDict([('id', 1867),\n", - " ('count', 10),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 9)])]),\n", - " ('intervention', [])]),\n", - " OrderedDict([('name', 'Renner1984-S2'),\n", - " ('count', 8),\n", - " ('description',\n", - " '8 patients with cirrhotic liver disease (information in table 1)'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1868),\n", - " ('count', 5),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 10)]),\n", - " OrderedDict([('id', 1869),\n", - " ('count', 3),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 10)]),\n", - " OrderedDict([('id', 1870),\n", - " ('count', 8),\n", - " ('mean', 66.0),\n", - " ('min', 41.0),\n", - " ('max', 100.0),\n", - " ('sd', 18.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 10)]),\n", - " OrderedDict([('id', 1871),\n", - " ('count', 8),\n", - " ('mean', 55.0),\n", - " ('min', 34.0),\n", - " ('max', 66.0),\n", - " ('sd', 10.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 10)]),\n", - " OrderedDict([('id', 1872),\n", - " ('count', 8),\n", - " ('choice',\n", - " 'cirrhotic liver disease'),\n", - " ('category',\n", - " 'disease'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 10)]),\n", - " OrderedDict([('id', 1873),\n", - " ('count', 8),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 10)]),\n", - " OrderedDict([('id', 1874),\n", - " ('count', 8),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 10)]),\n", - " OrderedDict([('id', 1875),\n", - " ('count', 6),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 10)]),\n", - " OrderedDict([('id', 1876),\n", - " ('count', 2),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 10)])]),\n", - " ('intervention', [])]),\n", - " OrderedDict([('name', 'Renner1984-S3'),\n", - " ('count', 7),\n", - " ('description',\n", - " '7 patients with PBC (information in table 1)'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1877),\n", - " ('count', 7),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 11)]),\n", - " OrderedDict([('id', 1878),\n", - " ('count', 7),\n", - " ('mean', 57.0),\n", - " ('min', 49.0),\n", - " ('max', 68.0),\n", - " ('sd', 8.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 11)]),\n", - " OrderedDict([('id', 1879),\n", - " ('count', 7),\n", - " ('mean', 56.0),\n", - " ('min', 42.0),\n", - " ('max', 73.0),\n", - " ('sd', 13.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 11)]),\n", - " OrderedDict([('id', 1880),\n", - " ('count', 7),\n", - " ('choice', 'PBC'),\n", - " ('category',\n", - " 'disease'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 11)]),\n", - " OrderedDict([('id', 1881),\n", - " ('count', 7),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 11)]),\n", - " OrderedDict([('id', 1882),\n", - " ('count', 7),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 11)]),\n", - " OrderedDict([('id', 1883),\n", - " ('count', 7),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 11)])]),\n", - " ('intervention', [])]),\n", - " OrderedDict([('name', 'Renner1984-S4'),\n", - " ('count', 11),\n", - " ('description',\n", - " '11 patients with miscellaneous liver disease (information in table 1)'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1884),\n", - " ('count', 9),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 12)]),\n", - " OrderedDict([('id', 1885),\n", - " ('count', 2),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 12)]),\n", - " OrderedDict([('id', 1886),\n", - " ('count', 11),\n", - " ('mean', 81.0),\n", - " ('min', 55.0),\n", - " ('max', 118.0),\n", - " ('sd', 19.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 12)]),\n", - " OrderedDict([('id', 1887),\n", - " ('count', 11),\n", - " ('mean', 52.0),\n", - " ('min', 24.0),\n", - " ('max', 71.0),\n", - " ('sd', 12.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 12)]),\n", - " OrderedDict([('id', 1888),\n", - " ('count', 11),\n", - " ('choice',\n", - " 'Miscellaneous Liver Disease'),\n", - " ('category',\n", - " 'disease'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 12)]),\n", - " OrderedDict([('id', 1889),\n", - " ('count', 11),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 12)]),\n", - " OrderedDict([('id', 1890),\n", - " ('count', 11),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 12)]),\n", - " OrderedDict([('id', 1891),\n", - " ('count', 9),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 12)]),\n", - " OrderedDict([('id', 1892),\n", - " ('count', 2),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 12)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '6420303')]),\n", - " OrderedDict([('sid', '7371463'),\n", - " ('name', 'Desmond1980'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'Desmond1980-S1'),\n", - " ('count', 15),\n", - " ('description',\n", - " '15 healthy male subjects, age range 18-71 years (13 nonsmokers), with normal clinical history, physical examination, and SMA12 profile were studied'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1893),\n", - " ('count', 13),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 13)]),\n", - " OrderedDict([('id', 1894),\n", - " ('count', 2),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 13)]),\n", - " OrderedDict([('id', 1895),\n", - " ('count', 15),\n", - " ('min', 18.0),\n", - " ('max', 71.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 13)]),\n", - " OrderedDict([('id', 1896),\n", - " ('count', 15),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 13)]),\n", - " OrderedDict([('id', 1897),\n", - " ('count', 15),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 13)]),\n", - " OrderedDict([('id', 1898),\n", - " ('count', 15),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 13)]),\n", - " OrderedDict([('id', 1899),\n", - " ('count', 15),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 13)])]),\n", - " ('intervention', [])]),\n", - " OrderedDict([('name', 'Desmond1980-S2'),\n", - " ('count', 10),\n", - " ('description',\n", - " '10 male patients with cirrhosis, age range 42-60 years (6 non-smokers), were also studied. 6 subjects had alcoholic cirrhosis and 4 had postnecrotic cirrhosis; the diagnosis was established by clinical and biochemical criteria and confirmed by percutaneous liver biopsy in 9. All subjects abstained from caffeine-containing beverages and medication for at least 3 days prior to the study.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1900),\n", - " ('count', 6),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 14)]),\n", - " OrderedDict([('id', 1901),\n", - " ('count', 4),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 14)]),\n", - " OrderedDict([('id', 1902),\n", - " ('count', 10),\n", - " ('min', 42.0),\n", - " ('max', 65.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 14)]),\n", - " OrderedDict([('id', 1903),\n", - " ('count', 10),\n", - " ('choice',\n", - " 'cirrhosis'),\n", - " ('category',\n", - " 'disease'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 14)]),\n", - " OrderedDict([('id', 1904),\n", - " ('count', 10),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 14)]),\n", - " OrderedDict([('id', 1905),\n", - " ('count', 10),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 14)]),\n", - " OrderedDict([('id', 1906),\n", - " ('count', 10),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 14)]),\n", - " OrderedDict([('id', 1907),\n", - " ('count', 10),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 14)])]),\n", - " ('intervention', [])]),\n", - " OrderedDict([('name', 'Desmond1980-S3'),\n", - " ('count', 8),\n", - " ('description',\n", - " 'Subset of 8 from 10 cirrhosis patients. 10 male patients with cirrhosis, age range 42-60 years (6 non-smokers), were also studied. 6 subjects had alcoholic cirrhosis and 4 had postnecrotic cirrhosis; the diagnosis was established by clinical and biochemical criteria and confirmed by percutaneous liver biopsy in 9. All subjects abstained from caffeine-containing beverages and medication for at least 3 days prior to the study.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1908),\n", - " ('count', 8),\n", - " ('choice', 'Mixed'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 15)]),\n", - " OrderedDict([('id', 1909),\n", - " ('count', 8),\n", - " ('mean', 71.5),\n", - " ('min', 48.0),\n", - " ('max', 84.0),\n", - " ('sd', 11.1),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 15)]),\n", - " OrderedDict([('id', 1910),\n", - " ('count', 8),\n", - " ('mean', 49.6),\n", - " ('min', 42.0),\n", - " ('max', 60.0),\n", - " ('sd', 6.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 15)]),\n", - " OrderedDict([('id', 1911),\n", - " ('count', 8),\n", - " ('choice',\n", - " 'cirrhosis'),\n", - " ('category',\n", - " 'disease'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 15)]),\n", - " OrderedDict([('id', 1912),\n", - " ('count', 8),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 15)]),\n", - " OrderedDict([('id', 1913),\n", - " ('count', 8),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'oral_contraceptives'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 15)]),\n", - " OrderedDict([('id', 1914),\n", - " ('count', 8),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 15)]),\n", - " OrderedDict([('id', 1915),\n", - " ('count', 8),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 15)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '7371463')]),\n", - " OrderedDict([('sid', '4029248'),\n", - " ('name', 'Abernethy1985'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'Abernethy1985-S1'),\n", - " ('count', 9),\n", - " ('description',\n", - " 'The subjects were 18 healthy women, 23 to 30 years supplementation. The subjects were divided into two groups each of 9 for the study. One group consisted of women taking a low-dose oestrogen (50 µg or less of the oestrogen component) oral contraceptive steroid for at least 3 months and no other medication (OCS group). The other group comprised 9 women of similar age not taking any medication. In each group 8 women were Caucasian, and t was Black. History, physical and laboratory examination indicated that all subjects were in good health. All subjects were asked to abstain from caffeine consumption 48 hours prior to the study.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1916),\n", - " ('count', 9),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 16)]),\n", - " OrderedDict([('id', 1917),\n", - " ('count', 9),\n", - " ('mean', 59.0),\n", - " ('se', 2.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 16)]),\n", - " OrderedDict([('id', 1918),\n", - " ('count', 9),\n", - " ('mean', 26.0),\n", - " ('min', 23.0),\n", - " ('max', 30.0),\n", - " ('se', 1.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 16)]),\n", - " OrderedDict([('id', 1919),\n", - " ('count', 8),\n", - " ('choice',\n", - " 'Caucasian'),\n", - " ('category',\n", - " 'ethnicity'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 16)]),\n", - " OrderedDict([('id', 1920),\n", - " ('count', 1),\n", - " ('choice', 'Black'),\n", - " ('category',\n", - " 'ethnicity'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 16)]),\n", - " OrderedDict([('id', 1921),\n", - " ('count', 9),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 16)]),\n", - " OrderedDict([('id', 1922),\n", - " ('count', 9),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 16)]),\n", - " OrderedDict([('id', 1923),\n", - " ('count', 9),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 16)])]),\n", - " ('intervention', [])]),\n", - " OrderedDict([('name', 'Abernethy1985-S2'),\n", - " ('count', 9),\n", - " ('description',\n", - " 'The subjects were 18 healthy women, 23 to 30 years supplementation. The subjects were divided into two groups each of 9 for the study. One group consisted of women taking a low-dose oestrogen (50 µg or less of the oestrogen component) oral contraceptive steroid for at least 3 months and no other medication (OCS group). The other group comprised 9 women of similar age not taking any medication. In each group 8 women were Caucasian, and t was Black. History, physical and laboratory examination indicated that all subjects were in good health. All subjects were asked to abstain from caffeine consumption 48 hours prior to the study.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1924),\n", - " ('count', 9),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 17)]),\n", - " OrderedDict([('id', 1925),\n", - " ('count', 9),\n", - " ('mean', 58.0),\n", - " ('se', 3.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 17)]),\n", - " OrderedDict([('id', 1926),\n", - " ('count', 9),\n", - " ('mean', 26.0),\n", - " ('min', 23.0),\n", - " ('max', 30.0),\n", - " ('se', 1.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 17)]),\n", - " OrderedDict([('id', 1927),\n", - " ('count', 8),\n", - " ('choice',\n", - " 'Caucasian'),\n", - " ('category',\n", - " 'ethnicity'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 17)]),\n", - " OrderedDict([('id', 1928),\n", - " ('count', 1),\n", - " ('choice', 'Black'),\n", - " ('category',\n", - " 'ethnicity'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 17)]),\n", - " OrderedDict([('id', 1929),\n", - " ('count', 9),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 17)]),\n", - " OrderedDict([('id', 1930),\n", - " ('count', 9),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 17)]),\n", - " OrderedDict([('id', 1931),\n", - " ('count', 9),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 17)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '4029248')]),\n", - " OrderedDict([('sid', '10073324'),\n", - " ('name', 'Amchin1999'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'Amchin1999-S1'),\n", - " ('count', 15),\n", - " ('description',\n", - " '16 healthy volunteers (nine males and seven females) were enrolled in this study. Mean (range) age, weight, and height for the subjects were 31.1 years (21 to 41 years), 70.5 kg (47 to 93 kg), and 172 cm (157 to 183cm), respectively. Screening of sub jects, within 2 weeks of study initiation, consisted of a medical history; physical examination, including a 12- lead electrocardiogram (ECG); clinical laboratory tests; urinary drug screen; vital signs; ethanol breath test; and serum pregnancy test (females only). Exclusion criteria included women of child bearing potential or use of tobacco products within 6 months, prescription drugs within 14 days, non prescrip tion drugs within 7 days, or investigational drugs or drugs known to induce or inhibit hepatic enzymes within 30 days of study drug administration. Subjects who routinely consumed more than five 8-ounce cups of coffee (or caffeine equivalent) per day were excluded from the study. Caffeine and xanthene- containing beverages and foods, as well as charcoal- grilled foods, were strictly prohibited from the even ing of Day –2 through the morn ing of Day 9. Alcohol was prohibited from 7 days prior to the study and through out the study.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1932),\n", - " ('count', 15),\n", - " ('choice', 'N'),\n", - " ('category',\n", - " 'smoking'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 18)]),\n", - " OrderedDict([('id', 1933),\n", - " ('count', 15),\n", - " ('mean', 70.5),\n", - " ('min', 47.0),\n", - " ('max', 93.0),\n", - " ('unit', 'kg'),\n", - " ('category',\n", - " 'body_weight'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 18)]),\n", - " OrderedDict([('id', 1934),\n", - " ('count', 15),\n", - " ('mean', 31.1),\n", - " ('min', 21.0),\n", - " ('max', 41.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 18)]),\n", - " OrderedDict([('id', 1935),\n", - " ('count', 15),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 18)]),\n", - " OrderedDict([('id', 1936),\n", - " ('count', 15),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 18)]),\n", - " OrderedDict([('id', 1937),\n", - " ('count', 15),\n", - " ('mean', 172.0),\n", - " ('min', 157.0),\n", - " ('max', 183.0),\n", - " ('unit', 'cm'),\n", - " ('category',\n", - " 'height'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 18)]),\n", - " OrderedDict([('id', 1938),\n", - " ('count', 8),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 18)]),\n", - " OrderedDict([('id', 1939),\n", - " ('count', 7),\n", - " ('choice', 'F'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 18)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '10073324')]),\n", - " OrderedDict([('sid', '2589393'),\n", - " ('name', 'Harder1989'),\n", - " ('groups',\n", - " [OrderedDict([('name', 'Harder1989-S1'),\n", - " ('count', 12),\n", - " ('description',\n", - " 'In two consecutive studies, each in 12 healthy male volunteers (age 20-40 years), the pharmacokinetics of caffeine and its major metabolite paraxanthine alone and at the end of 4 days of treatment with several quinolones (Table 1) were investigated. Thine- free diet (no tea, coffee or chocolate) from 36 h before the first dose of caffeine until the end of the second sampling period.'),\n", - " ('characteristic_values',\n", - " [OrderedDict([('id', 1940),\n", - " ('count', 12),\n", - " ('min', 20.0),\n", - " ('max', 40.0),\n", - " ('unit', 'yr'),\n", - " ('category', 'age'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 19)]),\n", - " OrderedDict([('id', 1941),\n", - " ('count', 12),\n", - " ('choice', 'Y'),\n", - " ('category',\n", - " 'healthy'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 19)]),\n", - " OrderedDict([('id', 1942),\n", - " ('count', 12),\n", - " ('choice',\n", - " 'homo sapiens'),\n", - " ('category',\n", - " 'species'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 19)]),\n", - " OrderedDict([('id', 1943),\n", - " ('count', 12),\n", - " ('choice', 'M'),\n", - " ('category', 'sex'),\n", - " ('cvtype',\n", - " 'GroupCriteria'),\n", - " ('group', 19)])]),\n", - " ('intervention', [])])]),\n", - " ('reference', '2589393')])])])" + " ('results', [])])" ] }, - "execution_count": 555, + "execution_count": 264, "metadata": {}, "output_type": "execute_result" } @@ -1837,7 +651,7 @@ }, { "cell_type": "code", - "execution_count": 556, + "execution_count": 163, "metadata": { "collapsed": true }, @@ -1888,7 +702,7 @@ }, { "cell_type": "code", - "execution_count": 557, + "execution_count": 15, "metadata": { "collapsed": true }, @@ -1991,20 +805,20 @@ }, { "cell_type": "code", - "execution_count": 558, + "execution_count": 16, "metadata": {}, "outputs": [ { - "ename": "ErrorMessage", - "evalue": "\n groups: [\n {\n characteristic_values: [\n {},\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {},\n {},\n {}\n ]\n intervention: [\n \"This field is required.\"\n ]\n },\n {\n characteristic_values: [\n {},\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {},\n {},\n {}\n ]\n intervention: [\n \"This field is required.\"\n ]\n }\n ]", + "ename": "ParameterError", + "evalue": "{'groups': 'Unknown parameter.'}", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"studies\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mErrorMessage\u001b[0m: \n groups: [\n {\n characteristic_values: [\n {},\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {},\n {},\n {}\n ]\n intervention: [\n \"This field is required.\"\n ]\n },\n {\n characteristic_values: [\n {},\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {},\n {},\n {}\n ]\n intervention: [\n \"This field is required.\"\n ]\n }\n ]" + "\u001b[0;31mParameterError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"studies\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstudy_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_lookup_link\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 165\u001b[0;31m \u001b[0m_validate_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0moverrides\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36m_validate_parameters\u001b[0;34m(link, parameters)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 80\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mParameterError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 81\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mParameterError\u001b[0m: {'groups': 'Unknown parameter.'}" ] } ], @@ -2014,20 +828,25 @@ }, { "cell_type": "code", - "execution_count": 562, + "execution_count": 17, "metadata": {}, "outputs": [ { - "ename": "ErrorMessage", - "evalue": "\n characteristic_values: [\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {}\n ]", + "ename": "LinkLookupError", + "evalue": "Index ['groups']['create'] did not reference a link. Key 'groups' was not found.", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mErrorMessage\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;34m\"intervention\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m }\n\u001b[0;32m---> 32\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"groups\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mgroup_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 385\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 386\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorMessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 387\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 388\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mErrorMessage\u001b[0m: \n characteristic_values: [\n {},\n {},\n {\n category: [\n \"\\\"body_weight\\\" is not a valid choice.\"\n ]\n },\n {}\n ]" + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36m_lookup_link\u001b[0;34m(document, keys)\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 34\u001b[0;31m \u001b[0mnode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 35\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mKeyError\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mIndexError\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/itypes.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 111\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__getitem__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 112\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_data\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 113\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mKeyError\u001b[0m: 'groups'", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[0;31mLinkLookupError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;34m\"intervention\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m }\n\u001b[0;32m---> 32\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m\"groups\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mgroup_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 161\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 162\u001b[0m \u001b[0;31m# Validate the keys and link parameters.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 163\u001b[0;31m \u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_lookup_link\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 165\u001b[0m \u001b[0m_validate_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36m_lookup_link\u001b[0;34m(document, keys)\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0mindex_string\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'[%s]'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0mrepr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstrip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'u'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mkey\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[0mmsg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'Index %s did not reference a link. Key %s was not found.'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 38\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mLinkLookupError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mindex_string\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrepr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstrip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'u'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 39\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mDocument\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0mancestor\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mLinkAncestor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0midx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mLinkLookupError\u001b[0m: Index ['groups']['create'] did not reference a link. Key 'groups' was not found." ] } ], @@ -2088,7 +907,7 @@ }, { "cell_type": "code", - "execution_count": 541, + "execution_count": 70, "metadata": {}, "outputs": [ { @@ -2101,13 +920,12 @@ " 'journal': 'Clinical pharmacology and therapeutics',\n", " 'title': 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.',\n", " 'abstract': 'Botanical stimgle dose.',\n", - " 'authors': [{'first_name': 'Christine asdin', 'last_name': 'Haller'},\n", - " {'first_name': 'Peyton', 'last_name': 'Jacob'},\n", - " {'first_name': 'Neal L', 'last_name': 'Benowitz'}],\n", - " 'doi': ''}" + " 'doi': '',\n", + " 'authors': [],\n", + " 'pdf': File(name='test.pdf', content=<_io.BufferedReader name='/home/janekg89/Develop/Pycharm_Projects/pkdb/data/Master/Studies/Kaplan1997/Kaplan1997.pdf'>, content_type='pdf')}" ] }, - "execution_count": 541, + "execution_count": 70, "metadata": {}, "output_type": "execute_result" } @@ -2132,74 +950,232 @@ "output_type": "execute_result" } ], - "source": [ - "from jsonschema import validate\n", - "reference_schema = {\n", - " \"properties\":{\n", - " \"pmid\": {\"type\" : \"number\"},\n", - " \"name\": {\"type\" : \"string\"},\n", - " \"sid\": {\"type\" : [\"number\",\"string\"]},\n", - " \"date\": {\"type\" : \"string\"},\n", - " \"journal\": {\"type\" : \"string\"},\n", - " \"title\": {\"type\" : \"string\"},\n", - " \"abstract\": {\"type\" : \"string\"},\n", - " \"authors\": {\"type\" : \"array\"},\n", - " \"doi\": {\"type\" : \"string\"}\n", - " \n", - " }\n", - " \n", - "}\n", - "\n", - "validate(reference_dict,reference_schema)\n", - "\n", - "{}" - ] + "source": [] }, { "cell_type": "code", - "execution_count": 359, + "execution_count": 65, "metadata": { "collapsed": true }, "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 367, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"pmid\":\"12087394589\",\"sid\":\"012087345981\",\"name\":\"Haller2002\",\"doi\":\"\",\"title\":\"Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.\",\"abstract\":\"Botanical stimgle dose.\",\"journal\":\"Clinical pharmacology and therapeutics\",\"date\":\"2002-07-18\",\"authors\":[{\"id\":2,\"first_name\":\"Christine asdin\",\"last_name\":\"Haller\"},{\"id\":3,\"first_name\":\"Peyton\",\"last_name\":\"Jacob\"},{\"id\":4,\"first_name\":\"Neal L\",\"last_name\":\"Benowitz\"}],\"pdf\":\"http://0.0.0.0:8000/media/study/Haller2002_AjG9ywf.pdf\"}'" + ] + }, + "execution_count": 367, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ + "from coreapi.utils import File\n", "import json\n", - "with open('/home/janekg89/Develop/Pycharm_Projects/pkdb/pkdb_app/data/Master/Studies/Kaplan1997/data.json') as f:\n", - " data = json.load(f)\n" + "import requests\n", + "pdf_dict = {}\n", + "pdf_dict['sid'] = '012087345981'\n", + "#pdf_dict[\"pdf\"] = \"\"\n", + "pdf_dict[\"title\"] = \"new\"\n", + "\n", + "pdf_dict = {\"pdf\" : open('/home/janekg89/Develop/Pycharm_Projects/pkdb/data/Master/Studies/Haller2002/Haller2002.pdf', 'rb')}\n", + " response = requests.patch(\"http://0.0.0.0:8000/api/v1/references/012087345981/\", files = pdf_dict)\n", + "\n", + "#client.action(document,[\"references\", \"create\"],multipart/form-data params=reference_dict)\n", + "response.text" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 353, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<_io.BufferedReader name='/home/janekg89/Develop/Pycharm_Projects/pkdb/data/Master/Studies/Haller2002/Haller2002.pdf'>" + ] + }, + "execution_count": 353, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "client.action(document, [\"references\", \"list\"])" + "reference_dict[\"pdf\"]" ] }, { "cell_type": "code", - "execution_count": 117, + "execution_count": 368, "metadata": {}, "outputs": [ { - "ename": "ParameterError", - "evalue": "{'groups': 'This parameter is required.'}", + "data": { + "text/plain": [ + "OrderedDict([('count', 5),\n", + " ('next', None),\n", + " ('previous', None),\n", + " ('results',\n", + " [OrderedDict([('pmid', ''),\n", + " ('sid', '678689769'),\n", + " ('name', '679876876'),\n", + " ('doi', ''),\n", + " ('title', 'gzugiuzg'),\n", + " ('abstract', ''),\n", + " ('journal', ''),\n", + " ('date', '2018-08-15'),\n", + " ('authors', [])]),\n", + " OrderedDict([('pmid', 'lpü'),\n", + " ('sid', 'gzuguz'),\n", + " ('name', 'gzuzguzg'),\n", + " ('doi', ''),\n", + " ('title', 'guz'),\n", + " ('abstract', ''),\n", + " ('journal', 'gzu'),\n", + " ('date', '2018-08-05'),\n", + " ('authors', []),\n", + " ('pdf',\n", + " 'http://0.0.0.0:8000/media/study/140217_Rose-Daten.xlsx')]),\n", + " OrderedDict([('pmid', ''),\n", + " ('sid', 'studies.Reference.pmid'),\n", + " ('name', 'Grzeogrzewski'),\n", + " ('doi', ''),\n", + " ('title', 'ghjjhghj'),\n", + " ('abstract', ''),\n", + " ('journal', ''),\n", + " ('date', '2018-08-16'),\n", + " ('authors', [])]),\n", + " OrderedDict([('pmid', ''),\n", + " ('sid', '90809uiouio'),\n", + " ('name', 'Grzeogrzewski'),\n", + " ('doi', ''),\n", + " ('title', 'ghjjhghj'),\n", + " ('abstract', ''),\n", + " ('journal', ''),\n", + " ('date', '2018-08-16'),\n", + " ('authors', []),\n", + " ('pdf',\n", + " 'http://0.0.0.0:8000/media/study/CHARME_BigData_application_registration.pdf')]),\n", + " OrderedDict([('pmid', '12087394589'),\n", + " ('sid', '012087345981'),\n", + " ('name', 'Haller2002'),\n", + " ('doi', ''),\n", + " ('title',\n", + " 'Pharmacology of ephedra alkaloids and caffeine after single-dose dietary supplement use.'),\n", + " ('abstract', 'Botanical stimgle dose.'),\n", + " ('journal',\n", + " 'Clinical pharmacology and therapeutics'),\n", + " ('date', '2002-07-18'),\n", + " ('authors',\n", + " [OrderedDict([('id', 2),\n", + " ('first_name', 'Christine asdin'),\n", + " ('last_name', 'Haller')]),\n", + " OrderedDict([('id', 3),\n", + " ('first_name', 'Peyton'),\n", + " ('last_name', 'Jacob')]),\n", + " OrderedDict([('id', 4),\n", + " ('first_name', 'Neal L'),\n", + " ('last_name', 'Benowitz')])]),\n", + " ('pdf',\n", + " 'http://0.0.0.0:8000/media/study/Haller2002_AjG9ywf.pdf')])])])" + ] + }, + "execution_count": 368, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "client.action(document,[\"references\", \"list\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "read of closed file", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mParameterError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"references\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_lookup_link\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalidate\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 165\u001b[0;31m \u001b[0m_validate_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0moverrides\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36m_validate_parameters\u001b[0;34m(link, parameters)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 80\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mParameterError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 81\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mParameterError\u001b[0m: {'groups': 'This parameter is required.'}" + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mclient\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"references\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"create\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mreference_dict\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mencoding\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"multipart/form-data\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/client.py\u001b[0m in \u001b[0;36maction\u001b[0;34m(self, document, keys, params, validate, overrides, action, encoding, transform)\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;31m# Perform the action, and return a new document.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0mtransport\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdetermine_transport\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransports\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 178\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtransport\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlink\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlink_ancestors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlink_ancestors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36mtransition\u001b[0;34m(self, link, decoders, params, link_ancestors, force_codec)\u001b[0m\n\u001b[1;32m 376\u001b[0m \u001b[0mheaders\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 377\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 378\u001b[0;31m \u001b[0mrequest\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_build_http_request\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msession\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheaders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mencoding\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 379\u001b[0m \u001b[0mresponse\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 380\u001b[0m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_decode_result\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdecoders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mforce_codec\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/coreapi/transports/http.py\u001b[0m in \u001b[0;36m_build_http_request\u001b[0;34m(session, url, method, headers, encoding, params)\u001b[0m\n\u001b[1;32m 229\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 230\u001b[0m \u001b[0mrequest\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrequests\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mRequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mopts\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 231\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprepare_request\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 232\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 233\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/requests/sessions.py\u001b[0m in \u001b[0;36mprepare_request\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 439\u001b[0m \u001b[0mauth\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmerge_setting\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mauth\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mauth\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 440\u001b[0m \u001b[0mcookies\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmerged_cookies\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 441\u001b[0;31m \u001b[0mhooks\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmerge_hooks\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhooks\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhooks\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 442\u001b[0m )\n\u001b[1;32m 443\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/requests/models.py\u001b[0m in \u001b[0;36mprepare\u001b[0;34m(self, method, url, headers, files, data, params, auth, cookies, hooks, json)\u001b[0m\n\u001b[1;32m 310\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprepare_headers\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 311\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprepare_cookies\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcookies\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 312\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprepare_body\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfiles\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mjson\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 313\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprepare_auth\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mauth\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 314\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/requests/models.py\u001b[0m in \u001b[0;36mprepare_body\u001b[0;34m(self, data, files, json)\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;31m# Multi-part file uploads.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 499\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfiles\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 500\u001b[0;31m \u001b[0;34m(\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcontent_type\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_encode_files\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfiles\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 501\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 502\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/requests/models.py\u001b[0m in \u001b[0;36m_encode_files\u001b[0;34m(files, data)\u001b[0m\n\u001b[1;32m 157\u001b[0m \u001b[0mfdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 158\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfp\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'read'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 159\u001b[0;31m \u001b[0mfdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 160\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mfp\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 161\u001b[0m \u001b[0;32mcontinue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: read of closed file" ] } ], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 320, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "pdf_dict = {}\n", + "pdf_dict['sid'] = '012087345981'\n", + "#pdf_dict[\"pdf\"] = \"\"\n", + "pdf_dict[\"title\"] = \"new\"" + ] + }, + { + "cell_type": "code", + "execution_count": 321, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'sid': '012087345981', 'title': 'new'}" + ] + }, + "execution_count": 321, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pdf_dict" + ] + }, + { + "cell_type": "code", + "execution_count": 324, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 324, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "client.action(document,[\"references\", \"create\"], params=data)" + "requests.patch(\"http://0.0.0.0:8000/api/v1/references/012087345981/\",json = pdf_dict)" ] }, { diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index 9edbba57..a8319db4 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -3,13 +3,15 @@ """ from django.db import models +from django.core.exceptions import ValidationError from pkdb_app.utils import CHAR_MAX_LENGTH from .categoricals import UNITS_CHOICES + class Sidable(models.Model): """ Model has an sid. """ - sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key = True) + sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key=True) class Meta: abstract = True @@ -29,11 +31,31 @@ class Meta: ''' -class Commentable(models.Model): - """ Model has a comment field. """ - comment = models.TextField(blank=True, null=True) + + + +class Blankable(models.Model): + # when creating the BlankAble class object it will add a __blank_together__ + # attribute corresponding to the same in {YourModel}.MyMeta.blank_together + def __new__(cls, *args, **kwargs): + new = super().__new__(cls) + if hasattr(cls, 'MyMeta'): + if hasattr(cls.MyMeta, 'blank_together'): + setattr(new, '__blank_together__', cls.MyMeta.blank_together) + return new + + def save(self, *args, **kwargs): + # returns False if any but not all of the __blank_together__ fields + # are not blank + not_blank_together = not (any([getattr(self, field, None) for field in getattr(self, '__not_blank_together__', None)]) and \ + not all([getattr(self, field, None) for field in getattr(self, '__not_blank_together__', None)])) + if not_blank_together: + raise ValidationError(f"{getattr(self, '__not_blank_together__', None)} one of them cannot be blank.") + return super().save(*args, **kwargs) class Meta: + # prevents Django from having some bad behavior surrounding + # inheritance of models that are not explicitly abstract abstract = True @@ -61,7 +83,7 @@ class Valueable(models.Model): - count = models.IntegerField() # how many participants in characteristics + count = models.IntegerField(null=True, blank=True) # how many participants in characteristics value = models.FloatField(null=True, blank=True) mean = models.FloatField(null=True, blank=True) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 00b03021..aca5ca69 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -17,17 +17,27 @@ #considering: to maintain serializers of serval versions of the json file. The version would be read from the json file and the respective #serializer would be selected. - - - # TODO: How to handle the genetic information? Genetic variants? from collections import namedtuple +def create_choices(list): + return [(utype, utype) for utype in list] + + CharacteristicType = namedtuple("CharacteristicType", ["value", "category", "dtype", "choices", "units"]) UnitType = namedtuple("UnitType", ["name"]) # TODO: lookup units package and proper units handling (units conversion, default units, ...) -UNIT_DATA = [ +UNIT_TIME = [ + UnitType('sec'), + UnitType('min'), + UnitType('h'), + UnitType('days'), +] +TIME_UNITS_CHOICES = [(utype.name, utype.name) for utype in UNIT_TIME] + + +UNIT_DATA = UNIT_TIME + [ UnitType('-'), UnitType('cm'), UnitType('m'), @@ -39,6 +49,8 @@ UnitType('mg/dl'), UnitType('g/dl') ] + + UNITS_CHOICES = [(utype.name, utype.name) for utype in UNIT_DATA] @@ -57,6 +69,24 @@ NO = 'N' BOOLEAN_CHOICES = [YES, NO] +INTERVENTION_ROUTE = [ +"oral", +"iv", +] +INTERVENTION_ROUTE_CHOICES = create_choices(INTERVENTION_ROUTE) +INTERVENTION_APPLICATION = [ + "single dose", + "multiple dose", + "continous injection", +] +INTERVENTION_APPLICATION_CHOICES = create_choices(INTERVENTION_APPLICATION) + +INTERVENTION_FORM = [ + "tablete", + "capsule", +] +INTERVENTION_FORM_CHOICES = create_choices(INTERVENTION_FORM) + # categories DEMOGRAPHICS = "demographics" # age, sex, ethnicity ANTHROPOMETRY = "anthropometry" # height, weight, waist bmi @@ -87,10 +117,16 @@ "aspirin", "caffeine", "acetaminophen", + "paraxanthine", + "paraxanthine/caffeine", + "theobromine", + "theophylline", ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] + + COMMON_DATA = [ # Medication CharacteristicType('oral contraceptives', 'contraceptives', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), @@ -144,7 +180,28 @@ ] PK_DATA = [ + "auc", + "concentration", + "clearance", + "vd", + "thalf", + "tmax", + "cmax", + "amount", + "kel", + "kabs", + "plasma_binding", + "clearance_unbound", + "ratio", + "clearance_tbc", ] +OUTPUT_TISSUE_DATA = [ + "saliva", + "plasma", + "urine", +] + +PK_DATA_CHOICES = create_choices(PK_DATA) # class, value, dtype (numeric, boolean, categorial), choices PROTOCOL_DATA = [ diff --git a/pkdb_app/comments/__init__.py b/pkdb_app/comments/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pkdb_app/comments/admin.py b/pkdb_app/comments/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/pkdb_app/comments/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/pkdb_app/comments/apps.py b/pkdb_app/comments/apps.py new file mode 100644 index 00000000..ff01b775 --- /dev/null +++ b/pkdb_app/comments/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CommentsConfig(AppConfig): + name = 'comments' diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py new file mode 100644 index 00000000..ee6e855b --- /dev/null +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -0,0 +1,33 @@ +# Generated by Django 2.0.6 on 2018-08-03 14:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('interventions', '0001_initial'), + ('subjects', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.DateTimeField(auto_created=True)), + ('text', models.TextField(blank=True, null=True)), + ('characteristica', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.Characteristica')), + ('group', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.Group')), + ('groupset', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.GroupSet')), + ('individual', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.Individual')), + ('individualset', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.IndividualSet')), + ('intervention', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.Intervention')), + ('interventionset', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.InterventionSet')), + ('output', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.Output')), + ('outputset', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.OutputSet')), + ], + ), + ] diff --git a/pkdb_app/comments/migrations/0002_auto_20180803_1409.py b/pkdb_app/comments/migrations/0002_auto_20180803_1409.py new file mode 100644 index 00000000..f81173a1 --- /dev/null +++ b/pkdb_app/comments/migrations/0002_auto_20180803_1409.py @@ -0,0 +1,32 @@ +# Generated by Django 2.0.6 on 2018-08-03 14:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('interventions', '0001_initial'), + ('comments', '0001_initial'), + ('studies', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='comment', + name='reference', + field=models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='studies.Reference'), + ), + migrations.AddField( + model_name='comment', + name='study', + field=models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='studies.Study'), + ), + migrations.AddField( + model_name='comment', + name='timecourse', + field=models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.Timecourse'), + ), + ] diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py new file mode 100644 index 00000000..29083716 --- /dev/null +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -0,0 +1,22 @@ +# Generated by Django 2.0.6 on 2018-08-03 14:09 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('comments', '0002_auto_20180803_1409'), + ] + + operations = [ + migrations.AddField( + model_name='comment', + name='user', + field=models.ForeignKey(on_delete=False, related_name='comments', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/pkdb_app/comments/migrations/__init__.py b/pkdb_app/comments/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pkdb_app/comments/models.py b/pkdb_app/comments/models.py new file mode 100644 index 00000000..5110f9e0 --- /dev/null +++ b/pkdb_app/comments/models.py @@ -0,0 +1,35 @@ +from django.db import models + +# Create your models here. +from pkdb_app.interventions.models import Intervention, InterventionSet, Timecourse, OutputSet, Output +from pkdb_app.studies.models import Reference, Study +from pkdb_app.subjects.models import Individual, IndividualSet, Characteristica, GroupSet, Group +from pkdb_app.users.models import User + + +class Comment(models.Model): + + text = models.TextField(blank=True, null=True) + user = models.ForeignKey(User, related_name="comments", on_delete=False) + time = models.DateTimeField(auto_created=True) + #### + + individual = models.ForeignKey(Individual,related_name="comments",blank=True, null=True, on_delete=False) + individualset = models.ForeignKey(IndividualSet,related_name="comments",blank=True, null=True, on_delete=False) + group = models.ForeignKey(Group,related_name="comments", blank=True, null=True,on_delete=False) + groupset = models.ForeignKey(GroupSet,related_name="comments",blank=True, null=True, on_delete=False) + characteristica = models.ForeignKey(Characteristica,related_name="comments",blank=True, null=True, on_delete=False) + + + output = models.ForeignKey(Output,related_name="comments",blank=True, null=True, on_delete=False) + outputset = models.ForeignKey(OutputSet,related_name="comments",blank=True, null=True, on_delete=False) + timecourse = models.ForeignKey(Timecourse,related_name="comments", blank=True, null=True,on_delete=False) + + intervention = models.ForeignKey(Intervention,related_name="comments",blank=True, null=True, on_delete=False) + interventionset = models.ForeignKey(InterventionSet,related_name="comments", blank=True, null=True,on_delete=False) + + + reference = models.ForeignKey(Reference,related_name="comments",blank=True, null=True, on_delete=False) + study = models.ForeignKey(Study, related_name="comments",blank=True, null=True,on_delete=False) + + diff --git a/pkdb_app/comments/tests.py b/pkdb_app/comments/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/pkdb_app/comments/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/pkdb_app/comments/views.py b/pkdb_app/comments/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/pkdb_app/comments/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index d0da02c1..58565957 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -31,6 +31,7 @@ class Common(Configuration): 'pkdb_app.studies', 'pkdb_app.subjects', 'pkdb_app.interventions', + 'pkdb_app.comments', ) @@ -203,6 +204,9 @@ class Common(Configuration): ], 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', + #'rest_framework.authentication.T' + 'rest_framework.authentication.TokenAuthentication', + ), 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',), } diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 526edca6..1b22d60a 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -2,6 +2,7 @@ import bonobo import coreapi import json +import requests BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) @@ -11,14 +12,21 @@ from pkdb_app.data_management.schemas import reference_schema +PASSWORD = "test" +Jan_G_U = {"username":"janekg","first_name":"Jan","last_name":"Grzegorzewski","email":"Janekg89@hotmail.de","password":PASSWORD} +Matthias_K = {"username":"mkoenig","first_name":"Matthias","last_name":"König","email":"konigmatt@googlemail.com","password":PASSWORD} +USERS = [Jan_G_U, Matthias_K] +def upload_user(USERS): + for user in USERS: + requests.post() def get_reference_json_path(): for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "reference.json" in files: json_file = os.path.join(root, 'reference.json') - pdf_file = f"{os.path.dirname(json_file)}.pdf" + pdf_file = os.path.join(root,f"{os.path.basename(root)}.pdf") yield {"json":json_file , "pdf": pdf_file} @@ -31,11 +39,7 @@ def open_reference(d): with open(d["json"]) as f: json_dict = json.loads(f.read()) - with open(d["pdf"],'rb') as f: - pdf = f - - json_dict["pdf"] = pdf - return {"json":json_dict, "reference_path":d["json"]} + return {"json":json_dict,"pdf":d["pdf"], "reference_path":d["json"]} def open_study(d): with open(d) as f: @@ -44,11 +48,28 @@ def open_study(d): def upload_reference(json_reference): validate(json_reference["json"],reference_schema) - client.action(document, ["references", "create"], params=json_reference["json"]) + with open(json_reference["pdf"],'rb') as f: + requests.patch(f'http://0.0.0.0:8000/api/v1/references/{json_reference["json"]["sid"]}/', files={"pdf":f}) + + def upload_study(json_study): - client.action(document, ["studies", "create"], params=json_study["json"]) + study_partial = {} + study_partial["sid"] = json_study["json"]["sid"] + study_partial["name"] = json_study["json"]["name"] + study_partial["pkdb_version"] = json_study["json"]["pkdb_version"] + study_partial["design"] = json_study["json"]["design"] + #study_partial["substances"] = json_study["json"]["substances"] + study_partial["reference"] = json_study["json"]["reference"] + #study_partial["curators"] = json_study["json"]["curators"] + #study_partial["creator"] = json_study["json"]["creator"] + study_partial["groupset"] = json_study["json"]["groupset"] + + + + + client.action(document, ["studies", "create"], params=study_partial) def get_graph_references(**options): graph = bonobo.Graph() @@ -82,5 +103,5 @@ def get_services(**options): parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: bonobo.run(get_graph_references(**options), services=get_services(**options)) - #bonobo.run(get_graph_study(**options), services=get_services(**options)) + bonobo.run(get_graph_study(**options), services=get_services(**options)) diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 91773f31..547eb3b2 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -5,10 +5,11 @@ """ from django.db import models -from ..behaviours import Sidable, Describable, Valueable -from ..categoricals import PROTOCOL_CHOICES, UNITS_CHOICES, SUBSTANCES_DATA_CHOICES -from ..subjects.models import Group -from ..studies.models import DataFile, Substance +from ..behaviours import Valueable, Describable +from ..categoricals import PROTOCOL_CHOICES, TIME_UNITS_CHOICES, \ + INTERVENTION_ROUTE_CHOICES, INTERVENTION_FORM_CHOICES, INTERVENTION_APPLICATION_CHOICES, PK_DATA_CHOICES, \ + SUBSTANCES_DATA_CHOICES +from ..subjects.models import Group, Individual, Set from ..utils import CHAR_MAX_LENGTH # ------------------------------------------------- @@ -29,31 +30,59 @@ # How to represent the dosing? # Add separate class? extension of model? +##################################### +#new +class DataFile(models.Model): + """ Table or figure from where the data comes from (png). + + This should be in a separate class, so that they can be easily displayed/filtered/... + """ + + file = models.FileField(upload_to="output", null=True, blank=True) # table or figure + filetype = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # XLSX, PNG, CSV + + +class Substance(models.Model): + """ Substances have to be in a different table, so that + than be uniquely defined. + + Has to be extended via ontology (Ontologable) -class ProtocolStep(Sidable, Describable, models.Model): - """ What is done to the group, single step. + """ + name = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True, choices=SUBSTANCES_DATA_CHOICES) + + #name # example caffeine + # ontologies: has set of defined values: is, CHEBI:27732 + +class InterventionSet(Set): + pass - - dosing of certain substance, e.g. caffeine oral - - smoking cessation - - sports / lifestyle change - - medication - - ... - Examples: - Two groups (parallel group design), one group control, other group gets medication, e.g., oral contraceptives, than pharmacokinetics of caffeine measured. - -> 2 protocol - - protocol 1 (linked to control group): MedicationStep (caffeine) - - protocol 2 (linked to intervention group): MedicationStep (oral contraceptives), MedicationStep (caffeine) +class Intervention(Valueable,models.Model): - """ + """ A concrete step/thing which is done to the group. + + In case of dosing/medication the actual dosing is stored in the Valueable. + In case of a step without dosing, e.g., lifestyle intervention only the category is used. + """ + name = models.CharField(max_length=CHAR_MAX_LENGTH) - # FIXME: Important to find the subset of dosing protocols + interventionset = models.ForeignKey(InterventionSet, related_name="interventions", on_delete=models.CASCADE) + substance = models.ForeignKey(Substance, null=True,blank=False, on_delete=False)#substance: # what was given [' + route = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_ROUTE_CHOICES)# route: # where ['oral', 'iv'] + form = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_FORM_CHOICES) + + application = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_APPLICATION_CHOICES) # application: # how timing ['single dose', 'multiple doses', 'continuous injection'] + application_time = models.FloatField(null=True,blank=False) #application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) + time_unit = models.CharField(max_length=CHAR_MAX_LENGTH,null=True,blank=True, choices=TIME_UNITS_CHOICES) + + ###### + #probably should be deleted category = models.IntegerField(choices=PROTOCOL_CHOICES) - choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, - blank=True) # check in validation that allowed choice + choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True,blank=True) @property - def Intervention_data(self): + def intervention_data(self): """ Returns the full information about the characteristic. :return: @@ -62,104 +91,102 @@ def Intervention_data(self): @property def choices(self): - return self.Intervention_data.choices + return self.intervention_data.choices + + +class CleanIntervention(Intervention): + """ Calculated from medicationstep + """ + raw = models.ForeignKey(Intervention, related_name="clean", on_delete=True) +# ----------------- +# RESULTS +# ----------------- + +# +class OutputSet(Set): + pass + +class BaseOutput(models.Model): + group = models.ForeignKey(Group, null=True, blank=True, on_delete=False) + individual = models.ForeignKey(Individual, null=True, blank=True, on_delete=False) + intervention = models.ForeignKey(Intervention, on_delete=False) + substance = models.ForeignKey(Substance, on_delete=False) + tissue = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES ,null=True, blank=True) class Meta: abstract = True -class ValueProtocolStep(Valueable, ProtocolStep): # choices, dose, unit (per_bodyweitght is not important) - """ A concrete step/thing which is done to the group. +class Output(Valueable,BaseOutput,models.Model): - In case of dosing/medication the actual dosing is stored in the Valueable. - In case of a step without dosing, e.g., lifestyle intervention only the category is used. - """ - substance = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) #substance: # what was given [' - route = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # route: # where ['oral', 'iv'] - application = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # application: # how timing ['single dose', 'multiple doses', 'continuous injection'] - application_time = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) - form = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # form: # how medication [capsule, tablete] + outputset = models.ForeignKey(OutputSet, related_name="outputs", on_delete=models.CASCADE) -class ProcessedValueProtocolStep(Valueable, ProtocolStep): - """ Calculated from medicationstep - """ - raw = models.ForeignKey(ValueProtocolStep, null=True, on_delete=True) + """ Storage of data sets. """ -class Protocol(models.Model): - """ List of things/steps which were done to the group or changed within the group or - distinguishing the group (for instance different time in montly cycle). - - distinguishing operation on the group (! but does not change group characteristics !) - - giving medication - - FIXME: better naming of class + pktype = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES) + time = models.FloatField(null=True,blank=True) + # files from which the data was extracted, these have to be linked to the study already should be PNG or NONE + files = models.ForeignKey(DataFile, on_delete=True) + +class Timecourse(BaseOutput): + """ Storing of time course data. + + Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). """ - group = models.ForeignKey(Group, related_name='interventions', on_delete=True) - protocol_steps = models.ManyToManyField(ValueProtocolStep) - name = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) - # set of protocols - # name (control, fluvoxamine, control-fluvo, fluvo-control) + #substance + #tissue + data = models.ForeignKey(DataFile, on_delete=True) # link to the CSV +class CleanOutput(Output): + raw = models.ForeignKey(Output, related_name="clean", null=True, on_delete=True) -# ----------------- -# RESULTS -# ----------------- +class CleanTimecourse(Timecourse): + raw = models.ForeignKey(Timecourse, related_name="clean", null=True, on_delete=True) + + +''' -# Create your models here. -class Output(Sidable, Describable, models.Model): - """ Storage of data sets. """ - protocol = models.ForeignKey(Protocol,on_delete=True) - # files from which the data was extracted, these have to be linked to the study already should be PNG or NONE - files = models.ForeignKey(DataFile, on_delete=True) class Pharmacokinetics(Output, Valueable): """ Measured value (calculated value via ProcessedPharmacokinetics) category: [clearance, vd, thalf, cmax, ...] """ - choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, - blank=True) # check in validation that allowed choice + choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) # check in validation that allowed choice substance = models.ForeignKey(Substance, on_delete=True) #tissue # where was it measured -class Timecourse(Output): - """ Storing of time course data. - Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). - """ - #substance - #tissue - data = models.ForeignKey(DataFile, on_delete=True) # link to the CSV -class ProcessedPharmacokinetics(Valueable): +class CleanPharmacokinetics(Valueable): """ Calculated from pharmacokinetics or timecourse data. """ raw = models.ForeignKey(Pharmacokinetics, null=True, on_delete=True) type = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # ['normalized', 'timecourse-derived'] -##################################### -#new -class Substance(models.Model): - """ Substances have to be in a different table, so that - than be uniquely defined. - - Has to be extended via ontology (Ontologable) - """ - name = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True, choices=SUBSTANCES_DATA_CHOICES) - #name # example caffeine - # ontologies: has set of defined values: is, CHEBI:27732 -class Intervension(models.Model): - models.ForeignKey(Substance, on_delete=False) +class Protocol(models.Model): + """ List of things/steps which were done to the group or changed within the group or + distinguishing the group (for instance different time in montly cycle). + - distinguishing operation on the group (! but does not change group characteristics !) + - giving medication + - FIXME: better naming of class -class InterventionSet(Describable, models.model): - interventions = models.ForeignKey(Intervension, on_delete=True) + """ + group = models.ForeignKey(Group, related_name='interventions', on_delete=True) + protocol_steps = models.ManyToManyField(ValueProtocolStep) + name = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) + # set of protocols + # name (control, fluvoxamine, control-fluvo, fluvo-control) +''' diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 8d53818a..dae088b9 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -1,8 +1,9 @@ from rest_framework import serializers -from .models import Protocol, MedicationStep -from ..serializers import BaseSerializer +from pkdb_app.interventions.models import Substance +from ..serializers import BaseSerializer +''' class MedicationStepSerializer(BaseSerializer): class Meta: model = MedicationStep @@ -16,3 +17,17 @@ class Meta: model = Protocol fields = "__all__" + +''' + + +class SubstanceSerializer(serializers.Serializer): + + class Meta: + model = Substance + fields = ["name"] + + + + + diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 90fb00b0..e016acf3 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -1,6 +1,8 @@ from rest_framework import serializers from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from collections import OrderedDict +# Get an instance of a logger + class BaseSerializer(serializers.ModelSerializer): diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index e7c4a2fd..d9dbbca1 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -3,18 +3,20 @@ """ from django.db import models -from pkdb_app.interventions.models import Substance -from pkdb_app.utils import CHAR_MAX_LENGTH -from pkdb_app.behaviours import Sidable, Describable, Commentable -from pkdb_app.categoricals import STUDY_DESIGN_CHOICES, CURRENT_VERSION -from pkdb_app.users.models import User +from pkdb_app.interventions.models import OutputSet, Substance, DataFile +from pkdb_app.subjects.models import GroupSet, IndividualSet +from ..utils import CHAR_MAX_LENGTH +from ..behaviours import Sidable +from ..categoricals import STUDY_DESIGN_CHOICES, CURRENT_VERSION +from ..users.models import User + class Author(models.Model): first_name = models.CharField(max_length=30, blank=True) last_name = models.CharField(max_length=150, blank=True) def __str__(self): - return '%s %s' % (self.id, self.first_name, self.last_name) + return '%s %s' % (self.first_name, self.last_name) class Reference(models.Model): @@ -23,7 +25,7 @@ class Reference(models.Model): In most cases this is a published paper, but could be a thesis or unpublished. """ pmid = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) #optional - sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key=True, default=pmid) + sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key=True) name = models.CharField(max_length=CHAR_MAX_LENGTH) doi = models.CharField(max_length=150, null=True, blank=True) #optional title = models.TextField() @@ -34,37 +36,32 @@ class Reference(models.Model): authors = models.ManyToManyField(Author, blank=True, related_name='references') -class DataFile(models.Model): - """ Table or figure from where the data comes from (png). - - This should be in a separate class, so that they can be easily displayed/filtered/... - """ - - file = models.FileField(upload_to="output", null=True, blank=True) # table or figure - filetype = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # XLSX, PNG, CSV -class Study(Sidable, Commentable, Describable, models.Model): +class Study(Sidable, models.Model): """ Single clinical study. Mainly reported as a single publication. """ - # FIXME: Do we need descciption here? pkdb_version = models.IntegerField(default=CURRENT_VERSION) - creator = models.ForeignKey(User,on_delete=False) # any creator needs an account. + creator = models.ForeignKey(User,related_name="studies",on_delete=False,null=True, blank=True) # any creator needs an account. name = models.CharField(max_length=CHAR_MAX_LENGTH) design = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True, choices=STUDY_DESIGN_CHOICES) reference = models.ForeignKey(Reference, on_delete=True, to_field="sid", db_column="reference_sid", related_name='studies', null=True, blank=True) curators = models.ManyToManyField(User) # any curator needs an account. substances = models.ManyToManyField(Substance) raw_data = models.ManyToManyField(DataFile) # FIXME: is this the right name? + groupset = models.OneToOneField(GroupSet, on_delete=models.CASCADE,null=True, blank=True) + individualset = models.OneToOneField(IndividualSet, on_delete=models.CASCADE,null=True, blank=True) + outputset = models.OneToOneField(OutputSet, on_delete=models.CASCADE,null=True, blank=True) -#TODO: Not shure if later is even needed (not included yet) + + +#not jet used class KeyWord(models.Model): """ This class describes the keyowrds / tags of a publication or any other reference. """ #name = models.IntegerField(choices=KEY_WORD_CHOICES) - name = models.CharField(max_length=CHAR_MAX_LENGTH) - + name = models.CharField(max_length=CHAR_MAX_LENGTH) \ No newline at end of file diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 48836f3c..d2e9549f 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -2,10 +2,16 @@ from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned +from pkdb_app.categoricals import SUBSTANCES_DATA +from pkdb_app.interventions.models import Substance +from pkdb_app.interventions.serializers import SubstanceSerializer +from pkdb_app.subjects.serializers import GroupSetSerializer +from pkdb_app.users.models import User +from pkdb_app.users.serializers import UserSerializer from .models import Reference, Author, Study - -from ..subjects.serializers import GroupSerializer -from ..subjects.models import Group +from django.core.exceptions import ObjectDoesNotExist +#from ..subjects.serializers import GroupSerializer +from ..subjects.models import Group, GroupSet from ..serializers import BaseSerializer from django.shortcuts import get_object_or_404 @@ -32,10 +38,10 @@ class Meta: fields = BASE_FIELDS + ('pmid', 'sid', 'name', 'doi', 'title','abstract', 'journal', 'date', 'authors', 'pdf') def create(self, validated_data): - authors_data = validated_data.pop('authors',[]) reference = Reference.objects.create(**validated_data) + for author_data in authors_data: author, _ = Author.objects.update_or_create(**author_data) reference.authors.add(author) @@ -52,40 +58,105 @@ def update(self, instance, validated_data): for author_data in authors_data: author, _ = Author.objects.update_or_create(**author_data) instance.authors.add(author) - instance.save() + + instance.save() return instance + + class StudySerializer(BaseSerializer): #reference = ReferenceSerializer(read_only=False) - reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all()) - groupset = GroupSerializer(many=True, read_only=False) + reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all(), required=False) + groupset = GroupSetSerializer(read_only=False, required=False) + curators = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username', many=True,required=False) + creator = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username',required=False) + #substances = SubstanceSerializer(slug_field='name', required=False,many=True) + substances = serializers.SlugRelatedField(queryset=Substance.objects.all(), slug_field='name',required=False, many=True) class Meta: model = Study - fields = BASE_FIELDS + ('sid','comment','name','description', 'groupset', 'reference') + fields = BASE_FIELDS + ('sid','name',"creator","pkdb_version","design",'reference',"curators", "groupset", "substances") def create(self, validated_data): - groups_data = validated_data.pop('groups', []) + substances_data = validated_data.pop('substances', []) + curators_data = validated_data.pop('curators', []) + groupset_data = validated_data.pop('groupset', None) + creator_data = validated_data.pop('creator', None) reference = validated_data.pop('reference') - study, _ = Study.objects.update_or_create(sid=validated_data["sid"], reference=reference, defaults=validated_data,) + #for substance in SUBSTANCES_DATA: + # Substance.objects.create(substance) + + + + try: + creator = User.objects.get(username=creator_data) + except ObjectDoesNotExist: + creator = None + + study, _ = Study.objects.update_or_create(sid=validated_data["sid"], reference=reference, creator=creator, defaults=validated_data,) + + if groupset_data is not None: + groupset, _ = GroupSet.objects.create(**groupset_data) + + groupset.save() + study.groupset = groupset - for group in groups_data: - Group.objects.update_or_create(name=group["name"], study=study, defaults=group) + for curator_data in curators_data: + try: + curator = User.objects.get(username=curator_data) + except ObjectDoesNotExist: + curator = None + study.curators.add(curator) + + for substance_data in substances_data: + try: + substance = User.objects.get(username=substance_data) + except ObjectDoesNotExist: + substance = None + study.substances.add(substance) study.save() return study def update(self, instance, validated_data): - groups_data = validated_data.pop('groups', []) + groupset_data = validated_data.pop('groupset',None) + curators_data = validated_data.pop('curators', []) + creator_data = validated_data.pop('creator', None) + + try: + creator = User.objects.get(username=creator_data) + except ObjectDoesNotExist: + creator = None + + instance.creator = creator + for name, value in validated_data.items(): setattr(instance, name, value) - for group in groups_data: - Group.objects.update_or_create(name=group["name"], study=instance, defaults=group) + instance.save() + + + if groupset_data is not None: + groupset , _= GroupSet.objects.create(**groupset_data) + + groupset.save() + instance.groupset = groupset + + instance.save() + + for curator_data in curators_data: + try: + curator = User.objects.get(username=curator_data) + except ObjectDoesNotExist: + curator = None + instance.curators.add(curator) + instance.save() + return instance + diff --git a/pkdb_app/studies/views.py b/pkdb_app/studies/views.py index b7e08c6b..221327a9 100644 --- a/pkdb_app/studies/views.py +++ b/pkdb_app/studies/views.py @@ -1,9 +1,11 @@ from .models import Author, Reference, Study from .serializers import AuthorSerializer, ReferenceSerializer, StudySerializer -from rest_framework import viewsets +from rest_framework import viewsets, generics import django_filters.rest_framework from rest_framework import filters - +from rest_framework.parsers import MultiPartParser, FormParser, JSONParser +from rest_framework.response import Response +from rest_framework import status, views class AuthorsViewSet(viewsets.ModelViewSet): @@ -17,7 +19,9 @@ class AuthorsViewSet(viewsets.ModelViewSet): class ReferencesViewSet(viewsets.ModelViewSet): queryset = Reference.objects.all() + parser_classes = (JSONParser,MultiPartParser, FormParser) serializer_class = ReferenceSerializer + lookup_field = "sid" filter_backends = (django_filters.rest_framework.DjangoFilterBackend,filters.SearchFilter,) filter_fields = ('sid',) @@ -25,6 +29,26 @@ class ReferencesViewSet(viewsets.ModelViewSet): search_fields = filter_fields +class FileUploadView(views.APIView): + def put(self, request, filename, format=None): + file_obj = request.FILES['file'] + + # do some stuff with uploaded file + return Response(status=204) + + """ + def post(self, request, *args, **kwargs): + file_serializer = ReferenceSerializer(data=request.data) + if file_serializer.is_valid(): + file_serializer.save() + return Response(file_serializer.data, status=status.HTTP_201_CREATED) + else: + return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST) + """ + + + + class StudyViewSet(viewsets.ModelViewSet): queryset = Study.objects.all() serializer_class = StudySerializer diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 9a38ff96..3ee61cbf 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -5,14 +5,34 @@ class GroupManager(models.Manager): - def update_or_create(self, *args, **kwargs): - characteristic_values = kwargs["defaults"].pop("characteristic_values", []) + def create(self, *args, **kwargs): + characteristica = kwargs.pop("characteristica", []) group, created = super(GroupManager, self).update_or_create(*args, **kwargs) - group.characteristic_values.all().delete() - for characteristic_value in characteristic_values: - characteristic_value["count"] = characteristic_value.get("count",group.count) - group.characteristic_values.create(**characteristic_value) + group.characteristica.all().delete() + for characteristica_single in characteristica: + characteristica_single["count"] = characteristica_single.get("count",group.count) + group.characteristica.create(**characteristica_single) group.save() return group, created + +class GroupSetManager(models.Manager): + def create(self, *args, **kwargs): + characteristica = kwargs.pop("characteristica", []) + groups = kwargs.pop("groups", []) + + groupset, created = super(GroupSetManager, self).update_or_create(*args, **kwargs) + groupset.characteristica.all().delete() + groupset.groups.all().delete() + + + for characteristica_single in characteristica: + groupset.characteristica.create(**characteristica_single) + + for group in groups: + groupset.groups.create(**group) + + groupset.save() + + return groupset, created diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 960e0f84..1ed88771 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -7,13 +7,11 @@ """ from django.db import models - -from ..studies.models import Study, Reference -from ..behaviours import Sidable, Describable, Valueable +from ..behaviours import Valueable, Describable from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, CHARACTERISTICA_CHOICES, GROUP_CRITERIA, \ INCLUSION_CRITERIA, EXCLUSION_CRITERIA from ..utils import CHAR_MAX_LENGTH -from .managers import GroupManager +from .managers import GroupManager, GroupSetManager # TODO: Add ExclusionCriteria as extra class on group | or via field ? @@ -29,21 +27,30 @@ -# Idea: GroupSet -class GroupSet(Describable,models.Model): - study = models.ForeignKey(Study, on_delete=True, related_name='groups',to_field="sid", db_column="study_sid",null=True, blank=True) +class Set(Describable, models.Model): + """ + abstarct class for all set classes + """ + @property def reference(self): - return self.study.reference + return self.reference + + class Meta: + abstract = True + +class GroupSet(Set): + objects = GroupSetManager() + class Group(models.Model): """ Individual or group of people. Groups are defined via their characteristics. """ - groupset = models.ForeignKey(GroupSet,on_delete=True, related_name="groups") + groupset = models.ForeignKey(GroupSet,on_delete=models.SET_NULL,null=True,related_name="groups") name = models.CharField(max_length=CHAR_MAX_LENGTH) count = models.IntegerField() # number of people/animals/objects in group objects = GroupManager() @@ -53,47 +60,52 @@ def reference(self): return self.groupset.reference -class Characteristic(models.Model): - """ Characteristic. +class IndividualSet(Set): + pass - Characteristics are used to store information about a group of subjects. - Such a group is defined by - - Inclusion criteria, which define general characteristics (often via cutoffs, i.e. min or max) of which - subjects are in a group. - - Exclusion criteria, analogue to inclusion criteria but defines which subjects are excluded. - - Group criteria, concrete properties/characteristics of the group of subjects. - The type of characteristic is defined via the cvtype. - When group characterists are curated it is important to specify the inclusion/exclusion criteria in - addition to the group criteria. +class Individual(models.Model): + """ Individual or group of people. + + Individuals are defined via their characteristics. """ - category = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) - choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, - blank=True) # check in validation that allowed choice - @property - def characteristic_data(self): - """ Returns the full information about the characteristic. + individualset = models.ForeignKey(IndividualSet,on_delete=models.CASCADE, related_name="individuals") + group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name="individuals") - :return: - """ - return CHARACTERISTIC_DICT[self.category] + name = models.CharField(max_length=CHAR_MAX_LENGTH) + + #objects = GroupManager() @property - def choices(self): - return self.characteristic_data.choices + def reference(self): + return self.individualset.reference - class Meta: - abstract = True +class Characteristica(Valueable, models.Model): + """ Characteristic. + + Characteristics are used to store information about a group of subjects. + Such a group is defined by + - Inclusion criteria, which define general characteristics (often via cutoffs, i.e. min or max) of which + subjects are in a group. + - Exclusion criteria, analogue to inclusion criteria but defines which subjects are excluded. + - Group criteria, concrete properties/characteristics of the group of subjects. + + The type of characteristic is defined via the cvtype. + When group characterists are curated it is important to specify the inclusion/exclusion criteria in + addition to the group criteria. -class Characteristica(Valueable, Characteristic): - """ This is the concrete selection/information of the characteristics. This stores the raw information. Derived values can be calculated. """ - groupset = models.ForeignKey(GroupSet, related_name="characteristica", null=True, on_delete=True) - group = models.ForeignKey(Group, related_name="characteristica", null=True, on_delete=True) - ctype = models.CharField(choices=CHARACTERISTICA_CHOICES, max_length=CHAR_MAX_LENGTH, default=GROUP_CRITERIA) + category = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) + choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True,blank=True) # check in validation that allowed choice + groupset = models.ForeignKey(GroupSet, related_name="characteristica", null=True, blank=True,on_delete=models.CASCADE) + group = models.ForeignKey(Group, related_name="characteristica", null=True, blank=True,on_delete=models.CASCADE) + individualset = models.ForeignKey(IndividualSet, related_name="characteristica", null=True,blank=True, on_delete=models.CASCADE) + individual = models.ForeignKey(Individual, related_name="characteristica", null=True,blank=True, on_delete=models.CASCADE) + ctype = models.CharField(choices=CHARACTERISTICA_CHOICES, max_length=CHAR_MAX_LENGTH, default=GROUP_CRITERIA) #this is for exclusion and inclustion + @property def is_inclusion(self): @@ -103,6 +115,19 @@ def is_inclusion(self): def is_exclusion(self): return self.ctype == EXCLUSION_CRITERIA + @property + def characteristic_data(self): + """ Returns the full information about the characteristic. + + :return: + """ + return CHARACTERISTIC_DICT[self.category] + + @property + def choices(self): + return self.characteristic_data.choices + + #def validate(self): # """ Check that choices are valid. I.e. that choice is allowed choice from choices for # characteristics. @@ -115,7 +140,7 @@ def is_exclusion(self): # raise NotImplemented -class CleanCharacteristica(Valueable, Characteristic, models.Model): +class CleanCharacteristica(Characteristica): """ Processed and normalized data (calculated on change from corresponding raw CharacteristicValue. @@ -123,11 +148,10 @@ class CleanCharacteristica(Valueable, Characteristic, models.Model): """ raw = models.ForeignKey(Characteristica, related_name="clean", null=True, on_delete=True) - - - # method field? for different processing? # TODO: add methods for doing the processing & automatic update if corresponding # Value is changed. # -> move to a ProcessedValuable + + diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index d5d8353c..9c4eea32 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,12 +1,44 @@ from rest_framework import serializers -from .models import Group, Characteristica -from ..interventions.serializers import ProtocolSerializer +from .models import Group, GroupSet,Individual,IndividualSet,Characteristica + from ..studies.models import Reference from ..serializers import BaseSerializer BASE_FIELDS = () from collections import OrderedDict +class CharacteristicaSerializer(serializers.ModelSerializer): + + count = serializers.IntegerField(required=False) + + class Meta: + model = Characteristica + fields = "__all__" + + def to_representation(self, instance): + result = super().to_representation(instance) + return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + + +class GroupSerializer(serializers.ModelSerializer): + characteristica = CharacteristicaSerializer(many=True,read_only=False, required=False) + + class Meta: + model = Group + fields = ["name","count","characteristica"] + +class GroupSetSerializer(serializers.ModelSerializer): + characteristica = CharacteristicaSerializer(many=True,read_only=False, required=False) + groups = GroupSerializer(many=True, read_only=False) + + class Meta: + model = GroupSet + fields = ["description","characteristica","groups"] + + + + +''' class CharacteristicValueSerializer(serializers.ModelSerializer): count = serializers.IntegerField(required=False) @@ -43,3 +75,4 @@ def to_representation(self, instance): return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) +''' diff --git a/pkdb_app/subjects/views.py b/pkdb_app/subjects/views.py index 2f111176..c6f11308 100644 --- a/pkdb_app/subjects/views.py +++ b/pkdb_app/subjects/views.py @@ -1,10 +1,10 @@ -from .models import Group, CharacteristicValue -from .serializers import GroupSerializer, CharacteristicValueSerializer +#from .models import Group, CharacteristicValue +#from .serializers import GroupSerializer, CharacteristicValueSerializer from rest_framework import viewsets import django_filters.rest_framework from rest_framework import filters - +""" class GroupsViewSet(viewsets.ModelViewSet): queryset = Group.objects.all() @@ -22,6 +22,8 @@ class CharacteristicValuesViewSet(viewsets.ModelViewSet): filter_fields = ( 'choice', 'count','category') search_fields = filter_fields +""" + #class InterventionsViewSet(viewsets.ModelViewSet): diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index ad129ce5..d397c5a6 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -7,8 +7,8 @@ from rest_framework_swagger.views import get_swagger_view from .users.views import UserViewSet, UserCreateViewSet -from .studies.views import AuthorsViewSet,ReferencesViewSet, StudyViewSet -from .subjects.views import GroupsViewSet,CharacteristicValuesViewSet +from .studies.views import AuthorsViewSet, ReferencesViewSet, StudyViewSet +#from .subjects.views import GroupsViewSet,CharacteristicValuesViewSet # views in User router = DefaultRouter() @@ -18,10 +18,11 @@ # views in studies router.register('authors',AuthorsViewSet,base_name="authors") router.register('references', ReferencesViewSet, base_name="references") + router.register('studies',StudyViewSet, base_name="studies") -router.register('groups', GroupsViewSet, base_name="groups") -router.register('characteristic_values', CharacteristicValuesViewSet, base_name="characteristic_values") +#router.register('groups', GroupsViewSet, base_name="groups") +#router.register('characteristic_values', CharacteristicValuesViewSet, base_name="characteristic_values") #router.register('intervention',InterventionsViewSet,base_name="intervention") diff --git a/pkdb_app/views.py b/pkdb_app/views.py index 94a7801a..3061544f 100644 --- a/pkdb_app/views.py +++ b/pkdb_app/views.py @@ -1,6 +1,7 @@ """ Views """ + from django.shortcuts import render from rest_framework_swagger.renderers import SwaggerUIRenderer,OpenAPIRenderer from rest_framework.decorators import api_view,renderer_classes,authentication_classes,permission_classes diff --git a/requirements.txt b/requirements.txt index 32ea5f91..5756f2af 100644 --- a/requirements.txt +++ b/requirements.txt @@ -45,3 +45,5 @@ biopython ipykernel pandas jsonschema +django-extra-fields +PyPDF2 \ No newline at end of file From dd013ac8536d38aa5ccc25b5e1255eaebf0e4c4e Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 5 Aug 2018 20:30:23 +0200 Subject: [PATCH 034/115] some weekendwork, wokring on serializer, parser || , --- docs/api/Untitled.ipynb | 199 ++++++++++++++++++ docs/api/api.ipynb | 74 ++++--- pkdb_app/comments/migrations/0001_initial.py | 4 +- .../migrations/0002_auto_20180803_1409.py | 32 --- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/data_management/add_groups.py | 1 + pkdb_app/data_management/fill_database.py | 32 ++- pkdb_app/interventions/admin.py | 14 ++ pkdb_app/interventions/managers.py | 18 ++ pkdb_app/interventions/models.py | 9 +- pkdb_app/interventions/serializers.py | 41 ++-- pkdb_app/interventions/views.py | 11 + pkdb_app/serializers.py | 53 ++++- pkdb_app/studies/admin.py | 6 + pkdb_app/studies/models.py | 6 +- pkdb_app/studies/serializers.py | 42 ++-- pkdb_app/subjects/managers.py | 8 +- pkdb_app/subjects/models.py | 2 +- pkdb_app/subjects/serializers.py | 29 ++- pkdb_app/urls.py | 3 + pkdb_app/users/views.py | 3 +- pkdb_app/utils.py | 1 - 22 files changed, 475 insertions(+), 117 deletions(-) create mode 100644 docs/api/Untitled.ipynb delete mode 100644 pkdb_app/comments/migrations/0002_auto_20180803_1409.py create mode 100644 pkdb_app/interventions/managers.py diff --git a/docs/api/Untitled.ipynb b/docs/api/Untitled.ipynb new file mode 100644 index 00000000..e8d59080 --- /dev/null +++ b/docs/api/Untitled.ipynb @@ -0,0 +1,199 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from itertools import repeat\n", + "data = {\n", + " \"name\": \"D_ENX2\",\n", + " \"substance\": \"enoxacin\",\n", + " \"time\": \"0||24||48||72\",\n", + " \"time_unit\": \"h\",\n", + " \"route\": \"oral||bla||hs\",\n", + " \"value\": 200.0,\n", + " \"unit\": \"mg\"\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "def number_characterististica(data):\n", + " for key, value in data.items():\n", + " values = value.split('||')\n", + " \n", + " if len(values) > 1:\n", + " return len(values)\n", + "\n", + "def list_chara(data):\n", + " n = number_characterististica(data)\n", + " datan = {}\n", + " for key, value in data.items():\n", + " #if type(value) == str: \n", + " try:\n", + " values = value.split('||')\n", + " values = list(map(str.strip, values))\n", + " \n", + " except AttributeError:\n", + " values = [value]\n", + " if len(values) == 1 :\n", + " values = values * n\n", + " \n", + " datan[key] = values\n", + " return datan\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'category': 'oral contraceptives', 'choice': '3 Y || 1 N'}\n" + ] + }, + { + "data": { + "text/plain": [ + "[{'category': 'oral contraceptives', 'choice': '3 Y'},\n", + " {'category': 'oral contraceptives', 'choice': '1 N'}]" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import pandas as pd\n", + "print(data)\n", + "pd.DataFrame(list_chara(data)).to_dict('records')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "data = {\n", + " \"category\": \"oral contraceptives\",\n", + " \"choice\": \"3 Y || 1 N\"\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'category': 'oral contraceptives'}, {'category': 'oral contraceptives'}]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.DataFrame(list_chara(data)).to_dict('records')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'category': ['oral contraceptives'], 'choice': ['3 Y', '1 N']}" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list_chara(data)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + " def number_raw(data):\n", + " for key, value in data.items():\n", + " values = value.split('||')\n", + " return len(values)\n", + "\n", + " def list_chara(data):\n", + " n = number_raw(data)\n", + " data_n = {}\n", + " for key, value in data.items():\n", + " # if type(value) == str:\n", + " try:\n", + " values = value.split('||')\n", + " values = list(map(str.strip, values))\n", + " except AttributeError:\n", + " values = [value]\n", + " if len(values) == 1:\n", + " values = values * n\n", + " data_n[key] = values\n", + " return data_n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pkdb-test", + "language": "python", + "name": "pkdb-test" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index 423ad9db..99e63ece 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -13,7 +13,7 @@ }, { "cell_type": "code", - "execution_count": 529, + "execution_count": 1, "metadata": { "collapsed": true }, @@ -24,8 +24,10 @@ }, { "cell_type": "code", - "execution_count": 620, - "metadata": {}, + "execution_count": 2, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "# import libraries\n", @@ -39,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 621, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -48,7 +50,7 @@ "'{\"detail\":\"Invalid token.\"}'" ] }, - "execution_count": 621, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -67,7 +69,7 @@ }, { "cell_type": "code", - "execution_count": 622, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -76,7 +78,7 @@ "'{\"detail\":\"Invalid token.\"}'" ] }, - "execution_count": 622, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -97,18 +99,19 @@ }, { "cell_type": "code", - "execution_count": 623, + "execution_count": 5, "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "b'\\n\\n\\n\\n \\n \\n 403 Forbidden\\n \\n\\n\\n
\\n

Forbidden (403)

\\n

CSRF verification failed. Request aborted.

\\n\\n\\n

You are seeing this message because this site requires a CSRF cookie when submitting forms. This cookie is required for security reasons, to ensure that your browser is not being hijacked by third parties.

\\n

If you have configured your browser to disable cookies, please re-enable them, at least for this site, or for 'same-origin' requests.

\\n\\n
\\n\\n
\\n

Help

\\n \\n

Reason given for failure:

\\n
\\n    CSRF cookie not set.\\n    
\\n \\n\\n

In general, this can occur when there is a genuine Cross Site Request Forgery, or when\\n Django\\'s\\n CSRF mechanism has not been used correctly. For POST forms, you need to\\n ensure:

\\n\\n
    \\n
  • Your browser is accepting cookies.
  • \\n\\n
  • The view function passes a request to the template\\'s render\\n method.
  • \\n\\n
  • In the template, there is a {% csrf_token\\n %} template tag inside each POST form that\\n targets an internal URL.
  • \\n\\n
  • If you are not using CsrfViewMiddleware, then you must use\\n csrf_protect on any views that use the csrf_token\\n template tag, as well as those that accept the POST data.
  • \\n\\n
  • The form has a valid CSRF token. After logging in in another browser\\n tab or hitting the back button after a login, you may need to reload the\\n page with the form, because the token is rotated after a login.
  • \\n
\\n\\n

You\\'re seeing the help section of this page because you have DEBUG =\\n True in your Django settings file. Change that to False,\\n and only the initial error message will be displayed.

\\n\\n

You can customize this page using the CSRF_FAILURE_VIEW setting.

\\n
\\n\\n\\n\\n'" - ] - }, - "execution_count": 623, - "metadata": {}, - "output_type": "execute_result" + "ename": "NameError", + "evalue": "name 'r' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;31m#print(r.status_code, r.reason)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;31m#r.json()[\"token\"]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcontent\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'r' is not defined" + ] } ], "source": [ @@ -121,7 +124,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [] }, @@ -134,7 +139,7 @@ }, { "cell_type": "code", - "execution_count": 624, + "execution_count": 6, "metadata": { "collapsed": true }, @@ -148,7 +153,7 @@ }, { "cell_type": "code", - "execution_count": 625, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -169,7 +174,7 @@ }, { "cell_type": "code", - "execution_count": 626, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -195,11 +200,22 @@ " }\n", " studies: {\n", " list([page], [sid], [search])\n", - " create(sid, name, [creator], [pkdb_version], [design], [reference], [curators], [groupset], [substances])\n", + " create(sid, name, [creator], [pkdb_version], [design], [reference], [curators], [groupset], [interventionset], [substances])\n", " read(sid, [sid], [search])\n", - " update(sid, sid, name, [creator], [pkdb_version], [design], [reference], [curators], [groupset], [substances], [sid], [search])\n", - " partial_update(sid, [sid], [name], [creator], [pkdb_version], [design], [reference], [curators], [groupset], [substances], [sid], [search])\n", + " update(sid, sid, name, [creator], [pkdb_version], [design], [reference], [curators], [groupset], [interventionset], [substances], [sid], [search])\n", + " partial_update(sid, [sid], [name], [creator], [pkdb_version], [design], [reference], [curators], [groupset], [interventionset], [substances], [sid], [search])\n", " delete(sid, [sid], [search])\n", + " }\n", + " substances: {\n", + " list([page])\n", + " create([name])\n", + " read(id)\n", + " update(id, [name])\n", + " partial_update(id, [name])\n", + " delete(id)\n", + " }\n", + " users: {\n", + " create(username, password, [first_name], [last_name], [email])\n", " }\n" ] } @@ -334,7 +350,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ " \n" @@ -1128,7 +1146,9 @@ { "cell_type": "code", "execution_count": 320, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "import requests\n", @@ -1495,9 +1515,9 @@ ], "metadata": { "kernelspec": { - "display_name": "pkdb", + "display_name": "pkdb-test", "language": "python", - "name": "pkdb" + "name": "pkdb-test" }, "language_info": { "codemirror_mode": { diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index ee6e855b..eafd971b 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-03 14:09 +# Generated by Django 2.0.6 on 2018-08-04 13:31 from django.db import migrations, models @@ -8,8 +8,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('interventions', '0001_initial'), ('subjects', '0001_initial'), + ('interventions', '0001_initial'), ] operations = [ diff --git a/pkdb_app/comments/migrations/0002_auto_20180803_1409.py b/pkdb_app/comments/migrations/0002_auto_20180803_1409.py deleted file mode 100644 index f81173a1..00000000 --- a/pkdb_app/comments/migrations/0002_auto_20180803_1409.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 2.0.6 on 2018-08-03 14:09 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('interventions', '0001_initial'), - ('comments', '0001_initial'), - ('studies', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='comment', - name='reference', - field=models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='studies.Reference'), - ), - migrations.AddField( - model_name='comment', - name='study', - field=models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='studies.Study'), - ), - migrations.AddField( - model_name='comment', - name='timecourse', - field=models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.Timecourse'), - ), - ] diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index 29083716..f26e37be 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-03 14:09 +# Generated by Django 2.0.6 on 2018-08-04 13:31 from django.conf import settings from django.db import migrations, models @@ -10,7 +10,7 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('comments', '0002_auto_20180803_1409'), + ('comments', '0002_auto_20180804_1331'), ] operations = [ diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py index ea5b3933..6626080c 100644 --- a/pkdb_app/data_management/add_groups.py +++ b/pkdb_app/data_management/add_groups.py @@ -55,6 +55,7 @@ def add_group_to_groupset(data): return {"json":json, "study_path":data["study_path"]} def add_characteristica_groupset(data): + this_data = {**data} groups = this_data["json"]["groupset"]["groups"] number_of_groups = len(groups) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 1b22d60a..117dec1f 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -10,7 +10,14 @@ from pkdb_app.data_management.create_reference import REFERENCESMASTERPATH from jsonschema import validate from pkdb_app.data_management.schemas import reference_schema - +import logging +import mondrian +from pkdb_app.categoricals import SUBSTANCES_DATA +# One line setup (excepthook=True tells mondrian to handle uncaught exceptions) +mondrian.setup(excepthook=True) +# Use logging, as usual. +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) PASSWORD = "test" Jan_G_U = {"username":"janekg","first_name":"Jan","last_name":"Grzegorzewski","email":"Janekg89@hotmail.de","password":PASSWORD} @@ -18,11 +25,10 @@ USERS = [Jan_G_U, Matthias_K] -def upload_user(USERS): - for user in USERS: - requests.post() + def get_reference_json_path(): + #fill_user_and_substances() for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "reference.json" in files: json_file = os.path.join(root, 'reference.json') @@ -54,23 +60,31 @@ def upload_reference(json_reference): +def fill_user_and_substances(): + + for substance in SUBSTANCES_DATA: + client.action(document, ["substances", "create"], params={"name":substance}) + for user in USERS: + client.action(document, ["users", "create"], params=user) + + def upload_study(json_study): study_partial = {} study_partial["sid"] = json_study["json"]["sid"] study_partial["name"] = json_study["json"]["name"] study_partial["pkdb_version"] = json_study["json"]["pkdb_version"] study_partial["design"] = json_study["json"]["design"] - #study_partial["substances"] = json_study["json"]["substances"] + study_partial["substances"] = json_study["json"]["substances"] study_partial["reference"] = json_study["json"]["reference"] - #study_partial["curators"] = json_study["json"]["curators"] - #study_partial["creator"] = json_study["json"]["creator"] + study_partial["curators"] = json_study["json"]["curators"] + study_partial["creator"] = json_study["json"]["creator"] study_partial["groupset"] = json_study["json"]["groupset"] + study_partial["interventionset"] = json_study["json"]["interventionset"] - client.action(document, ["studies", "create"], params=study_partial) - + data = client.action(document, ["studies", "create"], params=study_partial) def get_graph_references(**options): graph = bonobo.Graph() # add studies diff --git a/pkdb_app/interventions/admin.py b/pkdb_app/interventions/admin.py index 8c38f3f3..4a9b3996 100644 --- a/pkdb_app/interventions/admin.py +++ b/pkdb_app/interventions/admin.py @@ -1,3 +1,17 @@ from django.contrib import admin # Register your models here. +from pkdb_app.interventions.models import InterventionSet, Intervention, Substance + + +@admin.register(Intervention) +class InterventionAdmin(admin.ModelAdmin): + pass + +@admin.register(InterventionSet) +class InterventionSetAdmin(admin.ModelAdmin): + pass + +@admin.register(Substance) +class SubstanceAdmin(admin.ModelAdmin): + pass diff --git a/pkdb_app/interventions/managers.py b/pkdb_app/interventions/managers.py new file mode 100644 index 00000000..c90d283d --- /dev/null +++ b/pkdb_app/interventions/managers.py @@ -0,0 +1,18 @@ +""" +the managers can be used to overwrite class methods of the models module. +""" +from django.db import models + + +class InterventionSetManager(models.Manager): + def create(self, *args, **kwargs): + + interventions = kwargs.pop("interventions", []) + interventionset = super(InterventionSetManager, self).create(*args, **kwargs) + interventionset.interventions.all().delete() + + for intervention in interventions: + interventionset.interventions.create(**intervention) + interventionset.save() + + return interventionset diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 547eb3b2..bff543ef 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -5,6 +5,8 @@ """ from django.db import models + +from pkdb_app.interventions.managers import InterventionSetManager from ..behaviours import Valueable, Describable from ..categoricals import PROTOCOL_CHOICES, TIME_UNITS_CHOICES, \ INTERVENTION_ROUTE_CHOICES, INTERVENTION_FORM_CHOICES, INTERVENTION_APPLICATION_CHOICES, PK_DATA_CHOICES, \ @@ -54,8 +56,11 @@ class Substance(models.Model): #name # example caffeine # ontologies: has set of defined values: is, CHEBI:27732 + def __str__(self): + return self.name + class InterventionSet(Set): - pass + objects = InterventionSetManager() class Intervention(Valueable,models.Model): @@ -78,7 +83,7 @@ class Intervention(Valueable,models.Model): ###### #probably should be deleted - category = models.IntegerField(choices=PROTOCOL_CHOICES) + category = models.IntegerField(choices=PROTOCOL_CHOICES,null=True,blank=True) choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True,blank=True) @property diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index dae088b9..4704f644 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -1,33 +1,42 @@ from rest_framework import serializers -from pkdb_app.interventions.models import Substance -from ..serializers import BaseSerializer +from pkdb_app.interventions.models import Substance, InterventionSet, Intervention +from pkdb_app.serializers import ParserSerializer + + +class SubstanceSerializer(serializers.ModelSerializer): -''' -class MedicationStepSerializer(BaseSerializer): class Meta: - model = MedicationStep - fields = "__all__" + model = Substance + fields = ["name"] + def create(self, validated_data): + substance, created = Substance.objects.update_or_create(**validated_data) + return substance -class ProtocolSerializer(BaseSerializer): - protokol_steps = MedicationStepSerializer(many=True, read_only=False) - class Meta: - model = Protocol - fields = "__all__" +class InterventionSerializer(serializers.ModelSerializer): + class Meta: + model = Intervention + fields = ["name","route","form","application","application_time","time_unit"] -''' +class InterventionSetSerializer(ParserSerializer): -class SubstanceSerializer(serializers.Serializer): + interventions = InterventionSerializer(many=True , read_only=False) class Meta: - model = Substance - fields = ["name"] - + model = InterventionSet + fields = ["description","interventions"] + def to_internal_value(self, data): + """ + :param data: + :return: + """ + data = self.generic_parser(data,"interventions") + return super(InterventionSetSerializer, self).to_internal_value(data) diff --git a/pkdb_app/interventions/views.py b/pkdb_app/interventions/views.py index 91ea44a2..a1b6d9ee 100644 --- a/pkdb_app/interventions/views.py +++ b/pkdb_app/interventions/views.py @@ -1,3 +1,14 @@ +import django_filters from django.shortcuts import render # Create your views here. +from rest_framework import viewsets + +from pkdb_app.interventions.models import Substance +from pkdb_app.interventions.serializers import SubstanceSerializer + + +class SubstancesViewSet(viewsets.ModelViewSet): + + queryset = Substance.objects.all() + serializer_class = SubstanceSerializer diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index e016acf3..dfa8b6c4 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from collections import OrderedDict -# Get an instance of a logger +import pandas as pd @@ -31,6 +31,55 @@ def is_valid(self, raise_exception=False): # data={something} proceed as usual return super().is_valid(raise_exception) + + + def to_representation(self, instance): + result = super().to_representation(instance) + return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + +class ParserSerializer(serializers.ModelSerializer): + + def generic_parser(self,data,key): + + raw = data.get(key,[]) + + def number_raw(data): + for key, value in data.items(): + try: + values = value.split('||') + except AttributeError: + values = [value] + + if len(values) > 1: + return len(values) + return 1 + + + def list_chara(data): + n = number_raw(data) + data_n = {} + for key, value in data.items(): + # if type(value) == str: + try: + values = value.split('||') + values = list(map(str.strip, values)) + except AttributeError: + values = [value] + if len(values) == 1: + values = values * n + data_n[key] = values + return data_n + + cleaned = [] + for raw_single in raw: + raw_single = {k: v for k, v in raw_single.items() if v is not None} + #if any("||" in value for key, value in raw_single.items()): + print(list_chara(raw_single)) + cleaned += pd.DataFrame(list_chara(raw_single)).to_dict('records') + data[key] = cleaned + return data + def to_representation(self, instance): result = super().to_representation(instance) - return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) \ No newline at end of file + return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + diff --git a/pkdb_app/studies/admin.py b/pkdb_app/studies/admin.py index 8c38f3f3..7efa4a1e 100644 --- a/pkdb_app/studies/admin.py +++ b/pkdb_app/studies/admin.py @@ -1,3 +1,9 @@ from django.contrib import admin + # Register your models here. +from pkdb_app.studies.models import Study + +@admin.register(Study) +class StudyAdmin(admin.ModelAdmin): + pass diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index d9dbbca1..cd2191b6 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -3,7 +3,7 @@ """ from django.db import models -from pkdb_app.interventions.models import OutputSet, Substance, DataFile +from pkdb_app.interventions.models import OutputSet, Substance, DataFile, InterventionSet from pkdb_app.subjects.models import GroupSet, IndividualSet from ..utils import CHAR_MAX_LENGTH from ..behaviours import Sidable @@ -35,7 +35,8 @@ class Reference(models.Model): pdf = models.FileField(upload_to="study", null=True, blank=True) authors = models.ManyToManyField(Author, blank=True, related_name='references') - + def __str__(self): + return self.title class Study(Sidable, models.Model): @@ -52,6 +53,7 @@ class Study(Sidable, models.Model): substances = models.ManyToManyField(Substance) raw_data = models.ManyToManyField(DataFile) # FIXME: is this the right name? groupset = models.OneToOneField(GroupSet, on_delete=models.CASCADE,null=True, blank=True) + interventionset = models.OneToOneField(InterventionSet, on_delete=models.CASCADE,null=True, blank=True) individualset = models.OneToOneField(IndividualSet, on_delete=models.CASCADE,null=True, blank=True) outputset = models.OneToOneField(OutputSet, on_delete=models.CASCADE,null=True, blank=True) diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index d2e9549f..0a0a48e7 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -3,8 +3,8 @@ from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from pkdb_app.categoricals import SUBSTANCES_DATA -from pkdb_app.interventions.models import Substance -from pkdb_app.interventions.serializers import SubstanceSerializer +from pkdb_app.interventions.models import Substance, InterventionSet +from pkdb_app.interventions.serializers import SubstanceSerializer, InterventionSetSerializer from pkdb_app.subjects.serializers import GroupSetSerializer from pkdb_app.users.models import User from pkdb_app.users.serializers import UserSerializer @@ -67,19 +67,20 @@ def update(self, instance, validated_data): class StudySerializer(BaseSerializer): - #reference = ReferenceSerializer(read_only=False) reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all(), required=False) groupset = GroupSetSerializer(read_only=False, required=False) curators = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username', many=True,required=False) creator = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username',required=False) - #substances = SubstanceSerializer(slug_field='name', required=False,many=True) substances = serializers.SlugRelatedField(queryset=Substance.objects.all(), slug_field='name',required=False, many=True) + interventionset = InterventionSetSerializer(read_only=False, required=False) class Meta: model = Study - fields = BASE_FIELDS + ('sid','name',"creator","pkdb_version","design",'reference',"curators", "groupset", "substances") + fields = BASE_FIELDS + ('sid','name',"creator","pkdb_version","design",'reference',"curators", + "groupset", "interventionset","substances") def create(self, validated_data): + interventionset_data = validated_data.pop('interventionset',None) substances_data = validated_data.pop('substances', []) curators_data = validated_data.pop('curators', []) @@ -87,10 +88,6 @@ def create(self, validated_data): creator_data = validated_data.pop('creator', None) reference = validated_data.pop('reference') - #for substance in SUBSTANCES_DATA: - # Substance.objects.create(substance) - - try: creator = User.objects.get(username=creator_data) @@ -100,11 +97,17 @@ def create(self, validated_data): study, _ = Study.objects.update_or_create(sid=validated_data["sid"], reference=reference, creator=creator, defaults=validated_data,) if groupset_data is not None: - groupset, _ = GroupSet.objects.create(**groupset_data) + groupset = GroupSet.objects.create(**groupset_data) groupset.save() study.groupset = groupset + if interventionset_data is not None: + interventionset = InterventionSet.objects.create(**interventionset_data) + interventionset.save() + study.interventionset = interventionset + study.save() + for curator_data in curators_data: try: curator = User.objects.get(username=curator_data) @@ -114,7 +117,7 @@ def create(self, validated_data): for substance_data in substances_data: try: - substance = User.objects.get(username=substance_data) + substance = Substance.objects.get(name=substance_data) except ObjectDoesNotExist: substance = None study.substances.add(substance) @@ -124,6 +127,8 @@ def create(self, validated_data): def update(self, instance, validated_data): groupset_data = validated_data.pop('groupset',None) + interventionset_data = validated_data.pop('interventionset',None) + substances_data = validated_data.pop('substances', []) curators_data = validated_data.pop('curators', []) creator_data = validated_data.pop('creator', None) @@ -140,8 +145,14 @@ def update(self, instance, validated_data): instance.save() + if interventionset_data is not None: + interventionset = InterventionSet.objects.create(**interventionset_data) + interventionset.save() + instance.interventionset = interventionset + instance.save() + if groupset_data is not None: - groupset , _= GroupSet.objects.create(**groupset_data) + groupset = GroupSet.objects.create(**groupset_data) groupset.save() instance.groupset = groupset @@ -156,7 +167,12 @@ def update(self, instance, validated_data): instance.curators.add(curator) instance.save() - + for substance_data in substances_data: + try: + substance = Substance.objects.get(name=substance_data) + except ObjectDoesNotExist: + substance = None + instance.substances.add(substance) return instance diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 3ee61cbf..1854210d 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -7,7 +7,7 @@ class GroupManager(models.Manager): def create(self, *args, **kwargs): characteristica = kwargs.pop("characteristica", []) - group, created = super(GroupManager, self).update_or_create(*args, **kwargs) + group = super(GroupManager, self).create(*args, **kwargs) group.characteristica.all().delete() for characteristica_single in characteristica: characteristica_single["count"] = characteristica_single.get("count",group.count) @@ -15,14 +15,14 @@ def create(self, *args, **kwargs): group.save() - return group, created + return group class GroupSetManager(models.Manager): def create(self, *args, **kwargs): characteristica = kwargs.pop("characteristica", []) groups = kwargs.pop("groups", []) - groupset, created = super(GroupSetManager, self).update_or_create(*args, **kwargs) + groupset = super(GroupSetManager, self).create(*args, **kwargs) groupset.characteristica.all().delete() groupset.groups.all().delete() @@ -35,4 +35,4 @@ def create(self, *args, **kwargs): groupset.save() - return groupset, created + return groupset diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 1ed88771..db1f0ee2 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -99,7 +99,7 @@ class Characteristica(Valueable, models.Model): This stores the raw information. Derived values can be calculated. """ category = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) - choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True,blank=True) # check in validation that allowed choice + choice = models.CharField(max_length=CHAR_MAX_LENGTH*3, null=True,blank=True) # check in validation that allowed choice groupset = models.ForeignKey(GroupSet, related_name="characteristica", null=True, blank=True,on_delete=models.CASCADE) group = models.ForeignKey(Group, related_name="characteristica", null=True, blank=True,on_delete=models.CASCADE) individualset = models.ForeignKey(IndividualSet, related_name="characteristica", null=True,blank=True, on_delete=models.CASCADE) diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 9c4eea32..4a2ef564 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -2,11 +2,13 @@ from .models import Group, GroupSet,Individual,IndividualSet,Characteristica from ..studies.models import Reference -from ..serializers import BaseSerializer +from ..serializers import ParserSerializer + BASE_FIELDS = () from collections import OrderedDict + class CharacteristicaSerializer(serializers.ModelSerializer): count = serializers.IntegerField(required=False) @@ -20,14 +22,26 @@ def to_representation(self, instance): return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) -class GroupSerializer(serializers.ModelSerializer): +class GroupSerializer(ParserSerializer): characteristica = CharacteristicaSerializer(many=True,read_only=False, required=False) class Meta: model = Group fields = ["name","count","characteristica"] -class GroupSetSerializer(serializers.ModelSerializer): + + + def to_internal_value(self, data): + """ + + :param data: + :return: + """ + data = self.generic_parser(data,"characteristica") + return super(GroupSerializer, self).to_internal_value(data) + + +class GroupSetSerializer(ParserSerializer): characteristica = CharacteristicaSerializer(many=True,read_only=False, required=False) groups = GroupSerializer(many=True, read_only=False) @@ -35,6 +49,15 @@ class Meta: model = GroupSet fields = ["description","characteristica","groups"] + def to_internal_value(self, data): + """ + + :param data: + :return: + """ + data = self.generic_parser(data,"characteristica") + return super(GroupSetSerializer, self).to_internal_value(data) + diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index d397c5a6..88acb280 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -6,6 +6,7 @@ from rest_framework.routers import DefaultRouter from rest_framework_swagger.views import get_swagger_view +from .interventions.views import SubstancesViewSet from .users.views import UserViewSet, UserCreateViewSet from .studies.views import AuthorsViewSet, ReferencesViewSet, StudyViewSet #from .subjects.views import GroupsViewSet,CharacteristicValuesViewSet @@ -15,6 +16,8 @@ router.register(r'users', UserViewSet) router.register(r'users', UserCreateViewSet) +router.register('substances', SubstancesViewSet, base_name="substances") + # views in studies router.register('authors',AuthorsViewSet,base_name="authors") router.register('references', ReferencesViewSet, base_name="references") diff --git a/pkdb_app/users/views.py b/pkdb_app/users/views.py index 7b1e00a3..f5a31d81 100644 --- a/pkdb_app/users/views.py +++ b/pkdb_app/users/views.py @@ -24,6 +24,7 @@ class UserCreateViewSet(mixins.CreateModelMixin, """ queryset = User.objects.all() serializer_class = CreateUserSerializer - permission_classes = (IsAdminUser,) + #permission_classes = (IsAdminUser,) + permission_classes = (AllowAny,) diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index e6ed9009..c6cba393 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -6,7 +6,6 @@ def create_if_exists(src,src_key,dest,dest_key): if src_key in src.keys(): dest[dest_key] = src[src_key] - return dest From 43d3695c8e80e86e3d4e25bcd5d5773ae6f6332f Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 6 Aug 2018 19:49:43 +0200 Subject: [PATCH 035/115] working on serializer now added mapping and started with output --- .gitignore | 1 + README.md | 1 + docs/api/Untitled.ipynb | 265 +++++++++++++++++- pkdb_app/behaviours.py | 42 ++- pkdb_app/categoricals.py | 5 + pkdb_app/comments/migrations/0001_initial.py | 2 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/data_management/fill_database.py | 6 +- pkdb_app/interventions/models.py | 30 +- pkdb_app/interventions/serializers.py | 26 +- pkdb_app/serializers.py | 51 +++- pkdb_app/studies/models.py | 2 +- pkdb_app/studies/serializers.py | 129 +++++---- pkdb_app/subjects/managers.py | 31 ++ pkdb_app/subjects/models.py | 49 +++- pkdb_app/subjects/serializers.py | 95 +++++-- 16 files changed, 613 insertions(+), 126 deletions(-) diff --git a/.gitignore b/.gitignore index 63d0d998..28baabfb 100644 --- a/.gitignore +++ b/.gitignore @@ -118,3 +118,4 @@ pkdb_app/studies/migrations/00*.py pkdb_app/users/migrations/00*.py pkdb_app/subjects/migrations/00*.py pkdb_app/interventions/migrations/00*.py +pkdb_app/comments/migrations/00*.py diff --git a/README.md b/README.md index 38960ff4..bfe47d9d 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ docker-compose run --rm web ./manage.py createsuperuser ``` # reset migrations sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete +sudo rm -r media/study/ # rebuild container docker-compose down diff --git a/docs/api/Untitled.ipynb b/docs/api/Untitled.ipynb index e8d59080..dce6bb7b 100644 --- a/docs/api/Untitled.ipynb +++ b/docs/api/Untitled.ipynb @@ -23,7 +23,9 @@ { "cell_type": "code", "execution_count": 40, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "def number_characterististica(data):\n", @@ -165,6 +167,263 @@ " return data_n" ] }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "individuals = [\n", + " {\n", + " \"name\": \"col==subject\",\n", + " \"group\": \"col==group\",\n", + " \"source\": \"/home/janekg89/Develop/Pycharm_Projects/pkdb/data/Master/Studies/Akinyinka2000/Akinyinka2000_Tab1.csv\",\n", + " \"format\": \"TSV\",\n", + " \"figure\": \"/home/janekg89/Develop/Pycharm_Projects/pkdb/data/Master/Studies/Akinyinka2000/Akinyinka2000_Tab1.png\",\n", + " \"characteristica\": [\n", + " {\n", + " \"category\": \"weight\",\n", + " \"value\": \"col==weight\",\n", + " \"unit\": \"kg\"\n", + " },\n", + " {\n", + " \"category\": \"age\",\n", + " \"value\": \"col==age\",\n", + " \"unit\": \"yr\"\n", + " },\n", + " {\n", + " \"category\": \"sex\",\n", + " \"choice\": \"col==sex\"\n", + " }\n", + " ]}]" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import copy\n", + "def mapping_parser(mapping,table):\n", + "\n", + " resulting_keys = []\n", + " mapping[]\n", + " for key, value in mapping.items():\n", + " if \"==\" in value:\n", + " values = value.split(\"==\")\n", + " if not values[0].strip() == \"col\":\n", + " raise Exception(f\"Value provided does not match pattern 'col==', with key:{key} and value:{values}\")\n", + " resulting_keys.append(values[1].strip())\n", + "\n", + "\n", + " else:\n", + " table[key] = value\n", + " resulting_keys.append(key)\n", + "\n", + " #resulting_data = table[resulting_keys].to_dict(\"records\")\n", + " #return resulting_data\n", + " print(table)\n", + " return table[resulting_keys]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def mapping_parser(mapping,table):\n", + " category = mapping[\"category\"]\n", + " value" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " study subject status age gender weight t_half AUC px_caf \\\n", + "0 Akinyinka2000 1C control 40 M 60 5.7 47.8 0.60 \n", + "1 Akinyinka2000 2C control 28 M 38 7.0 76.2 0.54 \n", + "2 Akinyinka2000 3C control 39 M 68 8.5 69.1 0.25 \n", + "3 Akinyinka2000 4C control 42 M 82 4.1 19.5 0.53 \n", + "4 Akinyinka2000 5C control 37 F 56 14.8 96.3 0.30 \n", + "5 Akinyinka2000 6C control 23 M 52 10.0 86.7 0.33 \n", + "6 Akinyinka2000 7C control 33 M 54 7.4 28.2 0.43 \n", + "7 Akinyinka2000 8C control 18 M 56 4.2 47.3 0.63 \n", + "8 Akinyinka2000 9C control 29 M 58 6.6 43.2 0.62 \n", + "9 Akinyinka2000 10C control 32 M 74 4.0 42.0 0.53 \n", + "10 Akinyinka2000 1M malaria 15 M 58 7.1 51.6 0.42 \n", + "11 Akinyinka2000 2M malaria 16 M 44 6.0 66.4 0.41 \n", + "12 Akinyinka2000 3M malaria 17 F 75 24.4 150.6 0.13 \n", + "13 Akinyinka2000 4M malaria 18 M 46 7.3 45.7 0.52 \n", + "14 Akinyinka2000 5M malaria 12 F 25 8.5 25.1 0.18 \n", + "15 Akinyinka2000 6M malaria 18 M 58 5.5 25.8 0.35 \n", + "16 Akinyinka2000 7M malaria 15 F 35 8.2 64.9 0.55 \n", + "17 Akinyinka2000 8M malaria 20 F 45 8.0 88.4 0.49 \n", + "18 Akinyinka2000 9M malaria 15 F 35 9.7 102.1 0.10 \n", + "19 Akinyinka2000 10M malaria 12 M 32 10.2 126.3 0.22 \n", + "\n", + " Cl T parasite_counts category unit \n", + "0 1.74 NA NA weight kg \n", + "1 1.29 NA NA weight kg \n", + "2 1.06 NA NA weight kg \n", + "3 3.12 NA NA weight kg \n", + "4 0.95 NA NA weight kg \n", + "5 1.11 NA NA weight kg \n", + "6 3.27 NA NA weight kg \n", + "7 1.89 NA NA weight kg \n", + "8 2.00 NA NA weight kg \n", + "9 2.05 NA NA weight kg \n", + "10 1.67 37.6 8.8 weight kg \n", + "11 1.71 39.1 109.1 weight kg \n", + "12 0.44 39.7 65.6 weight kg \n", + "13 2.38 37.2 29.3 weight kg \n", + "14 7.97 38.5 180.0 weight kg \n", + "15 3.34 36.6 1382.7 weight kg \n", + "16 2.20 38.4 95.6 weight kg \n", + "17 1.26 37.8 33.4 weight kg \n", + "18 1.40 38.4 65.1 weight kg \n", + "19 1.24 38.0 56.5 weight kg \n", + " study subject status age gender weight t_half AUC px_caf \\\n", + "0 Akinyinka2000 1C control 40 M 60 5.7 47.8 0.60 \n", + "1 Akinyinka2000 2C control 28 M 38 7.0 76.2 0.54 \n", + "2 Akinyinka2000 3C control 39 M 68 8.5 69.1 0.25 \n", + "3 Akinyinka2000 4C control 42 M 82 4.1 19.5 0.53 \n", + "4 Akinyinka2000 5C control 37 F 56 14.8 96.3 0.30 \n", + "5 Akinyinka2000 6C control 23 M 52 10.0 86.7 0.33 \n", + "6 Akinyinka2000 7C control 33 M 54 7.4 28.2 0.43 \n", + "7 Akinyinka2000 8C control 18 M 56 4.2 47.3 0.63 \n", + "8 Akinyinka2000 9C control 29 M 58 6.6 43.2 0.62 \n", + "9 Akinyinka2000 10C control 32 M 74 4.0 42.0 0.53 \n", + "10 Akinyinka2000 1M malaria 15 M 58 7.1 51.6 0.42 \n", + "11 Akinyinka2000 2M malaria 16 M 44 6.0 66.4 0.41 \n", + "12 Akinyinka2000 3M malaria 17 F 75 24.4 150.6 0.13 \n", + "13 Akinyinka2000 4M malaria 18 M 46 7.3 45.7 0.52 \n", + "14 Akinyinka2000 5M malaria 12 F 25 8.5 25.1 0.18 \n", + "15 Akinyinka2000 6M malaria 18 M 58 5.5 25.8 0.35 \n", + "16 Akinyinka2000 7M malaria 15 F 35 8.2 64.9 0.55 \n", + "17 Akinyinka2000 8M malaria 20 F 45 8.0 88.4 0.49 \n", + "18 Akinyinka2000 9M malaria 15 F 35 9.7 102.1 0.10 \n", + "19 Akinyinka2000 10M malaria 12 M 32 10.2 126.3 0.22 \n", + "\n", + " Cl T parasite_counts category unit \n", + "0 1.74 NA NA age yr \n", + "1 1.29 NA NA age yr \n", + "2 1.06 NA NA age yr \n", + "3 3.12 NA NA age yr \n", + "4 0.95 NA NA age yr \n", + "5 1.11 NA NA age yr \n", + "6 3.27 NA NA age yr \n", + "7 1.89 NA NA age yr \n", + "8 2.00 NA NA age yr \n", + "9 2.05 NA NA age yr \n", + "10 1.67 37.6 8.8 age yr \n", + "11 1.71 39.1 109.1 age yr \n", + "12 0.44 39.7 65.6 age yr \n", + "13 2.38 37.2 29.3 age yr \n", + "14 7.97 38.5 180.0 age yr \n", + "15 3.34 36.6 1382.7 age yr \n", + "16 2.20 38.4 95.6 age yr \n", + "17 1.26 37.8 33.4 age yr \n", + "18 1.40 38.4 65.1 age yr \n", + "19 1.24 38.0 56.5 age yr \n", + " study subject status age gender weight t_half AUC px_caf \\\n", + "0 Akinyinka2000 1C control 40 M 60 5.7 47.8 0.60 \n", + "1 Akinyinka2000 2C control 28 M 38 7.0 76.2 0.54 \n", + "2 Akinyinka2000 3C control 39 M 68 8.5 69.1 0.25 \n", + "3 Akinyinka2000 4C control 42 M 82 4.1 19.5 0.53 \n", + "4 Akinyinka2000 5C control 37 F 56 14.8 96.3 0.30 \n", + "5 Akinyinka2000 6C control 23 M 52 10.0 86.7 0.33 \n", + "6 Akinyinka2000 7C control 33 M 54 7.4 28.2 0.43 \n", + "7 Akinyinka2000 8C control 18 M 56 4.2 47.3 0.63 \n", + "8 Akinyinka2000 9C control 29 M 58 6.6 43.2 0.62 \n", + "9 Akinyinka2000 10C control 32 M 74 4.0 42.0 0.53 \n", + "10 Akinyinka2000 1M malaria 15 M 58 7.1 51.6 0.42 \n", + "11 Akinyinka2000 2M malaria 16 M 44 6.0 66.4 0.41 \n", + "12 Akinyinka2000 3M malaria 17 F 75 24.4 150.6 0.13 \n", + "13 Akinyinka2000 4M malaria 18 M 46 7.3 45.7 0.52 \n", + "14 Akinyinka2000 5M malaria 12 F 25 8.5 25.1 0.18 \n", + "15 Akinyinka2000 6M malaria 18 M 58 5.5 25.8 0.35 \n", + "16 Akinyinka2000 7M malaria 15 F 35 8.2 64.9 0.55 \n", + "17 Akinyinka2000 8M malaria 20 F 45 8.0 88.4 0.49 \n", + "18 Akinyinka2000 9M malaria 15 F 35 9.7 102.1 0.10 \n", + "19 Akinyinka2000 10M malaria 12 M 32 10.2 126.3 0.22 \n", + "\n", + " Cl T parasite_counts category unit \n", + "0 1.74 NA NA sex yr \n", + "1 1.29 NA NA sex yr \n", + "2 1.06 NA NA sex yr \n", + "3 3.12 NA NA sex yr \n", + "4 0.95 NA NA sex yr \n", + "5 1.11 NA NA sex yr \n", + "6 3.27 NA NA sex yr \n", + "7 1.89 NA NA sex yr \n", + "8 2.00 NA NA sex yr \n", + "9 2.05 NA NA sex yr \n", + "10 1.67 37.6 8.8 sex yr \n", + "11 1.71 39.1 109.1 sex yr \n", + "12 0.44 39.7 65.6 sex yr \n", + "13 2.38 37.2 29.3 sex yr \n", + "14 7.97 38.5 180.0 sex yr \n", + "15 3.34 36.6 1382.7 sex yr \n", + "16 2.20 38.4 95.6 sex yr \n", + "17 1.26 37.8 33.4 sex yr \n", + "18 1.40 38.4 65.1 sex yr \n", + "19 1.24 38.0 56.5 sex yr \n" + ] + }, + { + "ename": "KeyError", + "evalue": "\"['sex'] not in index\"", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0mtable\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msrc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdelimiter\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdelimiter\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeep_default_na\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mcharacteristica_single_mapping\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcharacteristica_mapping\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m \u001b[0mcharacteristica_table\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmapping_parser\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcharacteristica_single_mapping\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mtable\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 11\u001b[0m \u001b[0;31m#individuals_table = mapping_parser(individual_mapping,table)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;31m#individuals_table[\"characteristica\"] = characteristica_table.to_dict('records')\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mmapping_parser\u001b[0;34m(mapping, table)\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;31m#return resulting_data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtable\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 21\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mtable\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mresulting_keys\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 2680\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mSeries\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndarray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mIndex\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2681\u001b[0m \u001b[0;31m# either boolean or fancy integer index\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2682\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_array\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2683\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mDataFrame\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2684\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_frame\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m_getitem_array\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 2724\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_take\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2725\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2726\u001b[0;31m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_convert_to_indexer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2727\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_take\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2728\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Envs/pkdb/lib/python3.6/site-packages/pandas/core/indexing.py\u001b[0m in \u001b[0;36m_convert_to_indexer\u001b[0;34m(self, obj, axis, is_setter)\u001b[0m\n\u001b[1;32m 1325\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mmask\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0many\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1326\u001b[0m raise KeyError('{mask} not in index'\n\u001b[0;32m-> 1327\u001b[0;31m .format(mask=objarr[mask]))\n\u001b[0m\u001b[1;32m 1328\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1329\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mcom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_values_from_object\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mKeyError\u001b[0m: \"['sex'] not in index\"" + ] + } + ], + "source": [ + "unpacked_individuals = []\n", + "ind =copy.deepcopy(individuals)\n", + "for individual in ind:\n", + " src = individual.pop(\"source\") # todo: upload data first and then have the data saved here not the path.\n", + " characteristica_mapping = individual.pop(\"characteristica\")\n", + " delimiter = \"\\t\"\n", + " individual_mapping = individual\n", + " table = pd.read_csv(src, delimiter=delimiter, keep_default_na=False)\n", + " for characteristica_single_mapping in characteristica_mapping:\n", + " characteristica_table = mapping_parser(characteristica_single_mapping,table)\n", + " #individuals_table = mapping_parser(individual_mapping,table)\n", + " #individuals_table[\"characteristica\"] = characteristica_table.to_dict('records')\n", + " #unpacked_individuals += individuals_table.to_dict('recods')" + ] + }, { "cell_type": "code", "execution_count": null, @@ -177,9 +436,9 @@ ], "metadata": { "kernelspec": { - "display_name": "pkdb-test", + "display_name": "pkdb", "language": "python", - "name": "pkdb-test" + "name": "pkdb" }, "language_info": { "codemirror_mode": { diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index a8319db4..91324271 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -74,15 +74,23 @@ class Hashable(models.Model): class Meta: abstract = True +class Sourceable(models.Model): + source = models.CharField(max_length=CHAR_MAX_LENGTH) # todo: to file_filed + figure = models.CharField(max_length=CHAR_MAX_LENGTH) # todo: to file_filed + format = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + + class Meta: + abstract = True + + @staticmethod + def fields(): + return ["source","figure","format"] class Valueable(models.Model): """ Add fields to store values. In addition all the statistical values are stored. """ - - - count = models.IntegerField(null=True, blank=True) # how many participants in characteristics value = models.FloatField(null=True, blank=True) @@ -99,5 +107,29 @@ class Valueable(models.Model): class Meta: abstract = True - # FIXME: all validation rules & methods should be on Valuable - # for instance, if choice set, other fields must be empty, ... \ No newline at end of file + @staticmethod + def fields(): + return ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", ] + + +class ValueableMap(models.Model): + count_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) # how many participants in characteristics + value_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + + mean_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + median_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + min_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + max_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + sd_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + se_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + cv_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + + unit_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + + class Meta: + abstract = True + + @staticmethod + def fields(): + return ["value_map", "mean_map", "median_map", "min_map", "max_map","sd_map", "se_map", "cv_map", "unit_map" ] + diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index aca5ca69..56bacc10 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -102,6 +102,11 @@ def create_choices(list): CHARACTERISTICA_CHOICES = [(t, t) for t in CHARACTERISTICA_TYPES] +FileFormat = namedtuple("FileFormat", ["name", "delimiter"]) + +FORMAT_MAPPING = {"TSV":FileFormat("TSV",'\t'), + "CSV":FileFormat("CSV",",")} + STUDY_DESIGN_DATA = [ "single group", # (interventional study) "parallel group", # (interventional study) diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index eafd971b..06e44150 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-04 13:31 +# Generated by Django 2.0.6 on 2018-08-06 15:57 from django.db import migrations, models diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index f26e37be..79a2f247 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-04 13:31 +# Generated by Django 2.0.6 on 2018-08-06 15:57 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('comments', '0002_auto_20180806_1557'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('comments', '0002_auto_20180804_1331'), ] operations = [ diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 117dec1f..849fe668 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -28,7 +28,7 @@ def get_reference_json_path(): - #fill_user_and_substances() + fill_user_and_substances() for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "reference.json" in files: json_file = os.path.join(root, 'reference.json') @@ -81,10 +81,12 @@ def upload_study(json_study): study_partial["groupset"] = json_study["json"]["groupset"] study_partial["interventionset"] = json_study["json"]["interventionset"] + study_partial["individualset"] = json_study["json"].get("individualset",None) + study_partial["outputset"] = json_study["json"].get("outputset",None) + client.action(document, ["studies", "create"], params=study_partial) - data = client.action(document, ["studies", "create"], params=study_partial) def get_graph_references(**options): graph = bonobo.Graph() # add studies diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index bff543ef..d1167421 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -7,7 +7,7 @@ from django.db import models from pkdb_app.interventions.managers import InterventionSetManager -from ..behaviours import Valueable, Describable +from ..behaviours import Valueable, Describable, ValueableMap, Sourceable from ..categoricals import PROTOCOL_CHOICES, TIME_UNITS_CHOICES, \ INTERVENTION_ROUTE_CHOICES, INTERVENTION_FORM_CHOICES, INTERVENTION_APPLICATION_CHOICES, PK_DATA_CHOICES, \ SUBSTANCES_DATA_CHOICES @@ -99,6 +99,10 @@ def choices(self): return self.intervention_data.choices + class Meta: + unique_together = ('interventionset', 'name') + + class CleanIntervention(Intervention): """ Calculated from medicationstep """ @@ -106,8 +110,8 @@ class CleanIntervention(Intervention): # ----------------- # RESULTS # ----------------- - # + class OutputSet(Set): pass @@ -121,8 +125,24 @@ class BaseOutput(models.Model): class Meta: abstract = True +class BaseOutputMap(models.Model): + group_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + individual_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + intervention_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + substance_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + tissue_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + + class Meta: + abstract = True + +class OutputMap(models.Model): + pktype_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + time_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) -class Output(Valueable,BaseOutput,models.Model): + class Meta: + abstract = True + +class Output(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseOutput,models.Model): outputset = models.ForeignKey(OutputSet, related_name="outputs", on_delete=models.CASCADE) @@ -132,7 +152,7 @@ class Output(Valueable,BaseOutput,models.Model): pktype = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES) time = models.FloatField(null=True,blank=True) # files from which the data was extracted, these have to be linked to the study already should be PNG or NONE - files = models.ForeignKey(DataFile, on_delete=True) + #files = models.ForeignKey(DataFile, on_delete=True) class Timecourse(BaseOutput): @@ -154,8 +174,6 @@ class CleanTimecourse(Timecourse): ''' - - class Pharmacokinetics(Output, Valueable): """ Measured value (calculated value via ProcessedPharmacokinetics) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 4704f644..e5da716d 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -1,7 +1,9 @@ from rest_framework import serializers -from pkdb_app.interventions.models import Substance, InterventionSet, Intervention +from pkdb_app.behaviours import Sourceable, Valueable, ValueableMap +from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet from pkdb_app.serializers import ParserSerializer +from pkdb_app.subjects.models import IndividualSet, Individual, Group class SubstanceSerializer(serializers.ModelSerializer): @@ -40,3 +42,25 @@ def to_internal_value(self, data): return super(InterventionSetSerializer, self).to_internal_value(data) +class OutputSerializer(serializers.ModelSerializer): + group = serializers.SlugRelatedField(queryset=Group.objects.all(), slug_field='name', read_only=False, + required=False, allow_null=True) + individual = serializers.SlugRelatedField(queryset=Individual.objects.all(), slug_field='name', read_only=False, + required=False, allow_null=True) + intervention = serializers.SlugRelatedField(queryset=Intervention.objects.all(), slug_field='name',read_only=False,required=False, allow_null=True) + substance = serializers.SlugRelatedField(queryset=Substance.objects.all(), slug_field='name',read_only=False,required=False, allow_null=True) + + class Meta: + model = Output + fields = Sourceable.fields() + Valueable.fields() + ValueableMap.fields() + ["pktype", "pktype_map", "time", + "time_map","group", "group_map", "individual", "individual_map", "intervention", "intervention_map", + "substance","substance_map","tissue", "tissue_map"] + + +class OutputSetSerializer(ParserSerializer): + outputs = OutputSerializer(many=True, read_only=False) + + + class Meta: + model = OutputSet + fields = ["outputs","description"] diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index dfa8b6c4..65b5dda9 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -2,7 +2,8 @@ from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from collections import OrderedDict import pandas as pd - +import string +from pkdb_app.categoricals import FORMAT_MAPPING class BaseSerializer(serializers.ModelSerializer): @@ -39,7 +40,8 @@ def to_representation(self, instance): class ParserSerializer(serializers.ModelSerializer): - def generic_parser(self,data,key): + @staticmethod + def generic_parser(data,key): raw = data.get(key,[]) @@ -58,6 +60,7 @@ def number_raw(data): def list_chara(data): n = number_raw(data) data_n = {} + for key, value in data.items(): # if type(value) == str: try: @@ -67,18 +70,56 @@ def list_chara(data): values = [value] if len(values) == 1: values = values * n - data_n[key] = values + + + if key == "name" and n > 1: + ialpha = iter(string.ascii_uppercase) + values = [f"{value}_{next(ialpha)}" for value in values] + + data_n[key] = values + return data_n cleaned = [] for raw_single in raw: raw_single = {k: v for k, v in raw_single.items() if v is not None} - #if any("||" in value for key, value in raw_single.items()): - print(list_chara(raw_single)) cleaned += pd.DataFrame(list_chara(raw_single)).to_dict('records') data[key] = cleaned return data + + @staticmethod + def mapping_parser(mapping,table): + + resulting_keys = [] + for key, value in mapping.items(): + if "==" in value: + values = value.split("==") + if not values[0].strip() == "col": + raise Exception(f"Value provided does not match pattern 'col==', with key:{key} and value:{values}") + resulting_keys.append(values[1].strip()) + + + else: + table[key] = value + resulting_keys.append(key) + + #resulting_data = table[resulting_keys].to_dict("records") + #return resulting_data + return table[resulting_keys] + + @staticmethod + def split_to_map(data): + splitted_data = {} + for key,value in data.items(): + if "==" in value: + splitted_data[f"{key}_map"] = data.get(key) + else: + splitted_data[key] = data.get(key) + return splitted_data + + + def to_representation(self, instance): result = super().to_representation(instance) return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index cd2191b6..b8d2a2df 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -49,7 +49,7 @@ class Study(Sidable, models.Model): name = models.CharField(max_length=CHAR_MAX_LENGTH) design = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True, choices=STUDY_DESIGN_CHOICES) reference = models.ForeignKey(Reference, on_delete=True, to_field="sid", db_column="reference_sid", related_name='studies', null=True, blank=True) - curators = models.ManyToManyField(User) # any curator needs an account. + curators = models.ManyToManyField(User) # any curator needs an account. substances = models.ManyToManyField(Substance) raw_data = models.ManyToManyField(DataFile) # FIXME: is this the right name? groupset = models.OneToOneField(GroupSet, on_delete=models.CASCADE,null=True, blank=True) diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 0a0a48e7..51b13278 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -3,15 +3,15 @@ from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from pkdb_app.categoricals import SUBSTANCES_DATA -from pkdb_app.interventions.models import Substance, InterventionSet -from pkdb_app.interventions.serializers import SubstanceSerializer, InterventionSetSerializer -from pkdb_app.subjects.serializers import GroupSetSerializer +from pkdb_app.interventions.models import Substance, InterventionSet, OutputSet +from pkdb_app.interventions.serializers import SubstanceSerializer, InterventionSetSerializer, OutputSetSerializer +from pkdb_app.subjects.serializers import GroupSetSerializer, IndividualSetSerializer from pkdb_app.users.models import User from pkdb_app.users.serializers import UserSerializer from .models import Reference, Author, Study from django.core.exceptions import ObjectDoesNotExist #from ..subjects.serializers import GroupSerializer -from ..subjects.models import Group, GroupSet +from ..subjects.models import Group, GroupSet, IndividualSet from ..serializers import BaseSerializer from django.shortcuts import get_object_or_404 @@ -67,55 +67,74 @@ def update(self, instance, validated_data): class StudySerializer(BaseSerializer): - reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all(), required=False) - groupset = GroupSetSerializer(read_only=False, required=False) - curators = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username', many=True,required=False) - creator = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username',required=False) - substances = serializers.SlugRelatedField(queryset=Substance.objects.all(), slug_field='name',required=False, many=True) - interventionset = InterventionSetSerializer(read_only=False, required=False) + reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all(), required=False,allow_null=True) + groupset = GroupSetSerializer(read_only=False, required=False,allow_null=True) + curators = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username', many=True,required=False,allow_null=True) + creator = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username',required=False,allow_null=True) + substances = serializers.SlugRelatedField(queryset=Substance.objects.all(), slug_field='name',required=False, many=True,allow_null=True) + interventionset = InterventionSetSerializer(read_only=False, required=False,allow_null=True) + individualset = IndividualSetSerializer(read_only=False, required=False, allow_null=True) + outputset =OutputSetSerializer(read_only=False, required=False, allow_null=True) class Meta: model = Study fields = BASE_FIELDS + ('sid','name',"creator","pkdb_version","design",'reference',"curators", - "groupset", "interventionset","substances") + "groupset", "interventionset","individualset","outputset","substances") - def create(self, validated_data): - interventionset_data = validated_data.pop('interventionset',None) - - substances_data = validated_data.pop('substances', []) - curators_data = validated_data.pop('curators', []) - groupset_data = validated_data.pop('groupset', None) - creator_data = validated_data.pop('creator', None) - reference = validated_data.pop('reference') + @staticmethod + def pop_relations(validated_data): + related = {} + related["interventionset_data"] = validated_data.pop('interventionset', None) + related["substances_data"] = validated_data.pop('substances', []) + related["curators_data"] = validated_data.pop('curators', []) + related["groupset_data"] = validated_data.pop('groupset', None) + related["individualset_data"] = validated_data.pop('individualset', None) + related["outputset_data"] = validated_data.pop('outputset', None) + related["creator_data"] = validated_data.pop('creator', None) + related["reference"] = validated_data.pop('reference') try: - creator = User.objects.get(username=creator_data) + related["creator"] = User.objects.get(username=related["creator_data"]) except ObjectDoesNotExist: - creator = None + related["creator"] = None - study, _ = Study.objects.update_or_create(sid=validated_data["sid"], reference=reference, creator=creator, defaults=validated_data,) + return related - if groupset_data is not None: - groupset = GroupSet.objects.create(**groupset_data) + @staticmethod + def create_relations(study, related): + if related["groupset_data"] is not None: + groupset = GroupSet.objects.create(**related["groupset_data"]) groupset.save() study.groupset = groupset - if interventionset_data is not None: - interventionset = InterventionSet.objects.create(**interventionset_data) + if related["individualset_data"] is not None: + individualset = IndividualSet.objects.create(**related["individualset_data"]) + + individualset.save() + study.individualset = individualset + + if related["interventionset_data"] is not None: + interventionset = InterventionSet.objects.create(**related["interventionset_data"]) interventionset.save() study.interventionset = interventionset study.save() - for curator_data in curators_data: + if related["outputset_data"] is not None: + outputset = OutputSet.objects.create(**related["outputset_data"]) + outputset.save() + study.outputset = outputset + study.save() + + for curator_data in related["curators_data"]: try: curator = User.objects.get(username=curator_data) except ObjectDoesNotExist: curator = None study.curators.add(curator) - for substance_data in substances_data: + for substance_data in related["substances_data"]: try: substance = Substance.objects.get(name=substance_data) except ObjectDoesNotExist: @@ -123,56 +142,36 @@ def create(self, validated_data): study.substances.add(substance) study.save() + return study - def update(self, instance, validated_data): - groupset_data = validated_data.pop('groupset',None) - interventionset_data = validated_data.pop('interventionset',None) - substances_data = validated_data.pop('substances', []) - curators_data = validated_data.pop('curators', []) - creator_data = validated_data.pop('creator', None) - try: - creator = User.objects.get(username=creator_data) - except ObjectDoesNotExist: - creator = None + def create(self, validated_data): + related = self.pop_relations(validated_data) - instance.creator = creator + study, _ = Study.objects.update_or_create(sid=validated_data["sid"], + reference=related["reference"], + creator=related["creator"], + defaults=validated_data,) - for name, value in validated_data.items(): - setattr(instance, name, value) + study = self.create_relations(study,related) - instance.save() + return study - if interventionset_data is not None: - interventionset = InterventionSet.objects.create(**interventionset_data) - interventionset.save() - instance.interventionset = interventionset - instance.save() + def update(self, instance, validated_data): - if groupset_data is not None: - groupset = GroupSet.objects.create(**groupset_data) + related = self.pop_relations(validated_data) - groupset.save() - instance.groupset = groupset - instance.save() - for curator_data in curators_data: - try: - curator = User.objects.get(username=curator_data) - except ObjectDoesNotExist: - curator = None - instance.curators.add(curator) - instance.save() + instance.creator = related["creator"] - for substance_data in substances_data: - try: - substance = Substance.objects.get(name=substance_data) - except ObjectDoesNotExist: - substance = None - instance.substances.add(substance) + for name, value in validated_data.items(): + setattr(instance, name, value) + + instance.save() + instance = self.create_relations(instance,related) return instance diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 1854210d..e11b9acf 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -36,3 +36,34 @@ def create(self, *args, **kwargs): groupset.save() return groupset + +class IndividualManager(models.Manager): + def create(self, *args, **kwargs): + characteristica = kwargs.pop("characteristica", []) + individual = super(IndividualManager, self).create(*args, **kwargs) + individual.characteristica.all().delete() + for characteristica_single in characteristica: + individual.characteristica.create(**characteristica_single) + individual.save() + return individual + + +class IndividualSetManager(models.Manager): + def create(self, *args, **kwargs): + characteristica = kwargs.pop("characteristica", []) + individuals = kwargs.pop("individuals", []) + + individualset = super(IndividualSetManager, self).create(*args, **kwargs) + individualset.characteristica.all().delete() + individualset.individuals.all().delete() + + + for characteristica_single in characteristica: + individualset.characteristica.create(**characteristica_single) + + for individual in individuals: + individualset.individuals.create(**individual) + + individualset.save() + + return individualset \ No newline at end of file diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index db1f0ee2..d31559aa 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -7,11 +7,11 @@ """ from django.db import models -from ..behaviours import Valueable, Describable +from ..behaviours import Valueable, Describable, ValueableMap, Sourceable from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, CHARACTERISTICA_CHOICES, GROUP_CRITERIA, \ INCLUSION_CRITERIA, EXCLUSION_CRITERIA from ..utils import CHAR_MAX_LENGTH -from .managers import GroupManager, GroupSetManager +from .managers import GroupManager, GroupSetManager, IndividualManager, IndividualSetManager # TODO: Add ExclusionCriteria as extra class on group | or via field ? @@ -59,29 +59,60 @@ class Group(models.Model): def reference(self): return self.groupset.reference + @property + def study(self): + return self.groupset.study + + class Meta: + unique_together = ('groupset', 'name') + class IndividualSet(Set): - pass + objects = IndividualSetManager() + +class IndividualMap(models.Model): + group_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + name_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) -class Individual(models.Model): + class Meta: + abstract = True + + +class Individual(IndividualMap,Sourceable,models.Model): """ Individual or group of people. Individuals are defined via their characteristics. """ individualset = models.ForeignKey(IndividualSet,on_delete=models.CASCADE, related_name="individuals") - group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name="individuals") + group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name="individuals",null=True, blank=True) + name = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + ############### + + objects = IndividualManager() - name = models.CharField(max_length=CHAR_MAX_LENGTH) - #objects = GroupManager() @property def reference(self): return self.individualset.reference + @property + def study(self): + return self.individualset.study + + def groups_in_study(self): + return self.study.groupset.groups + + class Meta: + unique_together = ('individualset','name','name_map','source') + + def __str__(self): + return self.name + + -class Characteristica(Valueable, models.Model): +class Characteristica(ValueableMap,Valueable, models.Model): """ Characteristic. Characteristics are used to store information about a group of subjects. @@ -102,8 +133,8 @@ class Characteristica(Valueable, models.Model): choice = models.CharField(max_length=CHAR_MAX_LENGTH*3, null=True,blank=True) # check in validation that allowed choice groupset = models.ForeignKey(GroupSet, related_name="characteristica", null=True, blank=True,on_delete=models.CASCADE) group = models.ForeignKey(Group, related_name="characteristica", null=True, blank=True,on_delete=models.CASCADE) - individualset = models.ForeignKey(IndividualSet, related_name="characteristica", null=True,blank=True, on_delete=models.CASCADE) individual = models.ForeignKey(Individual, related_name="characteristica", null=True,blank=True, on_delete=models.CASCADE) + individualset = models.ForeignKey(IndividualSet, related_name="characteristica", null=True,blank=True, on_delete=models.CASCADE) ctype = models.CharField(choices=CHARACTERISTICA_CHOICES, max_length=CHAR_MAX_LENGTH, default=GROUP_CRITERIA) #this is for exclusion and inclustion diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 4a2ef564..ab92c83d 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,4 +1,8 @@ +import pandas as pd from rest_framework import serializers + +from pkdb_app.behaviours import Sourceable +from pkdb_app.categoricals import FORMAT_MAPPING from .models import Group, GroupSet,Individual,IndividualSet,Characteristica from ..studies.models import Reference @@ -9,18 +13,29 @@ -class CharacteristicaSerializer(serializers.ModelSerializer): +class CharacteristicaSerializer(ParserSerializer): count = serializers.IntegerField(required=False) class Meta: model = Characteristica - fields = "__all__" + fields = ["category","choice","ctype","count","value","mean","median","min","max","sd","se","cv","unit", + "count_map","value_map","mean_map","median_map","min_map","max_map","sd_map","se_map","cv_map","unit_map"] + def to_representation(self, instance): result = super().to_representation(instance) return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + def to_internal_value(self, data): + """ + + :param data: + :return: + """ + data = self.split_to_map(data) + return super(CharacteristicaSerializer, self).to_internal_value(data) + class GroupSerializer(ParserSerializer): characteristica = CharacteristicaSerializer(many=True,read_only=False, required=False) @@ -30,7 +45,6 @@ class Meta: fields = ["name","count","characteristica"] - def to_internal_value(self, data): """ @@ -61,41 +75,70 @@ def to_internal_value(self, data): -''' -class CharacteristicValueSerializer(serializers.ModelSerializer): +class IndividualSerializer(ParserSerializer): + characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False,allow_null=True) + group = serializers.SlugRelatedField(queryset=Group.objects.all(), slug_field='name',read_only=False,required=False, allow_null=True) #todo: filter for only this study + + #todo:add figure - count = serializers.IntegerField(required=False) class Meta: - model = Characteristica - fields = "__all__" + model = Individual + fields = Sourceable.fields() + ["name","name_map", "group_map", "characteristica","group"] - def to_representation(self, instance): - result = super().to_representation(instance) - return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + def to_internal_value(self, data): + """ + + :param data: + :return: + """ + data = self.generic_parser(data, "characteristica") + data = self.split_to_map(data) + #data = self.parse_individuals(data) #todo: this has to be done on CleanIndividual + return super(IndividualSerializer, self).to_internal_value(data) -class GroupSerializer(serializers.ModelSerializer): - characteristic_values = CharacteristicValueSerializer(many=True, read_only=False) - interventions = ProtocolSerializer(many=True, read_only=False) + def parse_individuals(self,data): + try: + individuals = data + unpacked_individuals = [] + for individual in individuals: + src = individual.pop("source") # todo: upload data first and then have the data saved here not the path. + characteristica_mapping = individual.pop("characteristica") - class Meta: - model = Group - fields = BASE_FIELDS + ( 'name', 'count','description','characteristic_values', 'intervention') + delimiter = FORMAT_MAPPING[ individual.pop("format")].delimiter + individual_mapping = individual + table = pd.read_csv(src, delimiter=delimiter, keep_default_na=False) + characteristica_table = self.mapping_parser(characteristica_mapping,table) + individuals_table = self.mapping_parser(individual_mapping,table) + individuals_table["characteristica"] = characteristica_table.to_dict('records') + unpacked_individuals += individuals_table.to_dict('recods') + data = unpacked_individuals - def create(self, validated_data): - group , _ = Group.objects.update_or_create(name=validated_data["name"], defaults=validated_data) - return group - def to_representation(self, instance): + except KeyError: + pass + return data + + +class IndividualSetSerializer(ParserSerializer): + characteristica = CharacteristicaSerializer(many=True,read_only=False, required=False) + individuals = IndividualSerializer(many=True,read_only=False, required=False) + + + class Meta: + model = IndividualSet + fields = ["description", "individuals", "characteristica"] + + def to_internal_value(self, data): """ - this method reduces the serialized output to not non-values. - :param instance: + + :param data: :return: """ - result = super().to_representation(instance) - return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + data = self.generic_parser(data,"characteristica") + + return super(IndividualSetSerializer, self).to_internal_value(data) -''' From 559028ccdd71e545886849fbbd05ec2c715e4829 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 7 Aug 2018 21:07:07 +0200 Subject: [PATCH 036/115] still not ready with output serializing --- pkdb_app/behaviours.py | 32 +++--- pkdb_app/categoricals.py | 25 ++++- pkdb_app/comments/migrations/0001_initial.py | 4 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/data_management/fill_database.py | 8 +- pkdb_app/interventions/managers.py | 17 +++- pkdb_app/interventions/models.py | 18 ++-- pkdb_app/interventions/serializers.py | 99 ++++++++++++++++--- pkdb_app/serializers.py | 33 ++++++- pkdb_app/studies/serializers.py | 17 ++-- pkdb_app/subjects/serializers.py | 9 +- 11 files changed, 208 insertions(+), 58 deletions(-) diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index 91324271..8c0a7bb0 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -75,8 +75,8 @@ class Meta: abstract = True class Sourceable(models.Model): - source = models.CharField(max_length=CHAR_MAX_LENGTH) # todo: to file_filed - figure = models.CharField(max_length=CHAR_MAX_LENGTH) # todo: to file_filed + source = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) # todo: to file_filed + figure = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) # todo: to file_filed format = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) class Meta: @@ -92,24 +92,24 @@ class Valueable(models.Model): In addition all the statistical values are stored. """ count = models.IntegerField(null=True, blank=True) # how many participants in characteristics - value = models.FloatField(null=True, blank=True) + value = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) - mean = models.FloatField(null=True, blank=True) - median = models.FloatField(null=True, blank=True) - min = models.FloatField(null=True, blank=True) - max = models.FloatField(null=True, blank=True) - sd = models.FloatField(null=True, blank=True) - se = models.FloatField(null=True, blank=True) - cv = models.FloatField(null=True, blank=True) + mean = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) + median = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) + min = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) + max = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) + sd = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) + se = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) + cv = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH, null=True, blank=True) class Meta: abstract = True - @staticmethod - def fields(): - return ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", ] + #@staticmethod + #def fields(): + # return ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", ] class ValueableMap(models.Model): @@ -129,7 +129,7 @@ class ValueableMap(models.Model): class Meta: abstract = True - @staticmethod - def fields(): - return ["value_map", "mean_map", "median_map", "min_map", "max_map","sd_map", "se_map", "cv_map", "unit_map" ] + #@staticmethod + #def fields(): + # return ["value_map", "mean_map", "median_map", "min_map", "max_map","sd_map", "se_map", "cv_map", "unit_map" ] diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 56bacc10..4d47ea03 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -45,9 +45,20 @@ def create_choices(list): UnitType('yr'), UnitType('kg/m^2'), UnitType('1/day'), + UnitType('1/h'), UnitType('IU/I'), UnitType('mg/dl'), - UnitType('g/dl') + UnitType('g/dl'), + UnitType('l/kg'), + UnitType("ml/min/kg"), + UnitType("µg/ml*h"), + UnitType("µg/ml"), + UnitType("µg/ml"), + UnitType("mg"), + UnitType("ml/min/1.73m^2"), + + + ] @@ -126,6 +137,14 @@ def create_choices(list): "paraxanthine/caffeine", "theobromine", "theophylline", + "chlorozoxazone", + "lomefloxacin", + "AAMU", + "1U", + "17X", + "17U", + "37X", + "1X", ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] @@ -199,13 +218,15 @@ def create_choices(list): "clearance_unbound", "ratio", "clearance_tbc", + "caf_px_6h", ] OUTPUT_TISSUE_DATA = [ "saliva", "plasma", "urine", + "urine (24h)", ] - +OUTPUT_TISSUE_DATA_CHOICES = create_choices(OUTPUT_TISSUE_DATA) PK_DATA_CHOICES = create_choices(PK_DATA) # class, value, dtype (numeric, boolean, categorial), choices diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index 06e44150..705033f4 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-06 15:57 +# Generated by Django 2.0.6 on 2018-08-07 15:38 from django.db import migrations, models @@ -8,8 +8,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('subjects', '0001_initial'), ('interventions', '0001_initial'), + ('subjects', '0001_initial'), ] operations = [ diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index 79a2f247..846f87d7 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-06 15:57 +# Generated by Django 2.0.6 on 2018-08-07 15:38 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('comments', '0002_auto_20180806_1557'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('comments', '0002_auto_20180807_1538'), ] operations = [ diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 849fe668..7d4ae345 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -80,12 +80,16 @@ def upload_study(json_study): study_partial["creator"] = json_study["json"]["creator"] study_partial["groupset"] = json_study["json"]["groupset"] study_partial["interventionset"] = json_study["json"]["interventionset"] - study_partial["individualset"] = json_study["json"].get("individualset",None) - study_partial["outputset"] = json_study["json"].get("outputset",None) client.action(document, ["studies", "create"], params=study_partial) + if "outputset" in json_study["json"].keys(): + response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = {"outputset": json_study["json"].get("outputset")}) + if response.status_code == 400: + print(json_study["json"]["name"],response.text) + #study_partial["outputset"] = json_study["json"].get("outputset",None) + def get_graph_references(**options): graph = bonobo.Graph() diff --git a/pkdb_app/interventions/managers.py b/pkdb_app/interventions/managers.py index c90d283d..02888986 100644 --- a/pkdb_app/interventions/managers.py +++ b/pkdb_app/interventions/managers.py @@ -8,11 +8,26 @@ class InterventionSetManager(models.Manager): def create(self, *args, **kwargs): interventions = kwargs.pop("interventions", []) - interventionset = super(InterventionSetManager, self).create(*args, **kwargs) + + interventionset = super().create(*args, **kwargs) interventionset.interventions.all().delete() for intervention in interventions: interventionset.interventions.create(**intervention) interventionset.save() + return interventionset + +class OutputSetManager(models.Manager): + + def create(self, *args, **kwargs): + outputs = kwargs.pop("outputs", []) + outputset = super().create(*args, **kwargs) + outputset.outputs.all().delete() + + for output in outputs: + outputset.outputs.create(**output) + outputset.save() + + return outputset diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index d1167421..1234bf02 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -6,11 +6,11 @@ from django.db import models -from pkdb_app.interventions.managers import InterventionSetManager +from pkdb_app.interventions.managers import InterventionSetManager, OutputSetManager from ..behaviours import Valueable, Describable, ValueableMap, Sourceable from ..categoricals import PROTOCOL_CHOICES, TIME_UNITS_CHOICES, \ INTERVENTION_ROUTE_CHOICES, INTERVENTION_FORM_CHOICES, INTERVENTION_APPLICATION_CHOICES, PK_DATA_CHOICES, \ - SUBSTANCES_DATA_CHOICES + SUBSTANCES_DATA_CHOICES, OUTPUT_TISSUE_DATA_CHOICES from ..subjects.models import Group, Individual, Set from ..utils import CHAR_MAX_LENGTH @@ -78,7 +78,7 @@ class Intervention(Valueable,models.Model): form = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_FORM_CHOICES) application = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_APPLICATION_CHOICES) # application: # how timing ['single dose', 'multiple doses', 'continuous injection'] - application_time = models.FloatField(null=True,blank=False) #application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) + application_time = models.DecimalField(max_digits = 40,decimal_places=20,null=True,blank=False) #application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) time_unit = models.CharField(max_length=CHAR_MAX_LENGTH,null=True,blank=True, choices=TIME_UNITS_CHOICES) ###### @@ -113,14 +113,14 @@ class CleanIntervention(Intervention): # class OutputSet(Set): - pass + objects = OutputSetManager() class BaseOutput(models.Model): group = models.ForeignKey(Group, null=True, blank=True, on_delete=False) individual = models.ForeignKey(Individual, null=True, blank=True, on_delete=False) - intervention = models.ForeignKey(Intervention, on_delete=False) - substance = models.ForeignKey(Substance, on_delete=False) - tissue = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES ,null=True, blank=True) + intervention = models.ForeignKey(Intervention,null=True, blank=True, on_delete=False) + substance = models.ForeignKey(Substance, null=True, blank=True,on_delete=False) + tissue = models.CharField(max_length=CHAR_MAX_LENGTH,choices=OUTPUT_TISSUE_DATA_CHOICES ,null=True, blank=True) class Meta: abstract = True @@ -149,8 +149,8 @@ class Output(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseOutpu """ Storage of data sets. """ - pktype = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES) - time = models.FloatField(null=True,blank=True) + pktype = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES, null=True, blank=True) + time = models.DecimalField(max_digits = 40,decimal_places=20,null=True,blank=True) # files from which the data was extracted, these have to be linked to the study already should be PNG or NONE #files = models.ForeignKey(DataFile, on_delete=True) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index e5da716d..210888db 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -1,9 +1,12 @@ +from django.core.exceptions import ObjectDoesNotExist, ValidationError +from django.db.models import Q from rest_framework import serializers from pkdb_app.behaviours import Sourceable, Valueable, ValueableMap from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet from pkdb_app.serializers import ParserSerializer from pkdb_app.subjects.models import IndividualSet, Individual, Group +from pkdb_app.subjects.serializers import GroupSRField class SubstanceSerializer(serializers.ModelSerializer): @@ -17,16 +20,28 @@ def create(self, validated_data): return substance -class InterventionSerializer(serializers.ModelSerializer): +class InterventionSerializer(ParserSerializer): class Meta: model = Intervention fields = ["name","route","form","application","application_time","time_unit"] + def to_internal_value(self, data): + """ + + :param data: + :return: + """ + + data = self.split_to_map(data) + data = self.drop_blank(data) + data = self.strip(data) + return super().to_internal_value(data) + class InterventionSetSerializer(ParserSerializer): - interventions = InterventionSerializer(many=True , read_only=False) + interventions = InterventionSerializer(many=True , read_only=False,required=False, allow_null=True) class Meta: model = InterventionSet @@ -38,29 +53,89 @@ def to_internal_value(self, data): :param data: :return: """ - data = self.generic_parser(data,"interventions") + #data = self.generic_parser(data,"interventions") + #data = self.split_to_map(data) + #data = self.drop_blank(data) + #data = self.strip(data) return super(InterventionSetSerializer, self).to_internal_value(data) -class OutputSerializer(serializers.ModelSerializer): - group = serializers.SlugRelatedField(queryset=Group.objects.all(), slug_field='name', read_only=False, - required=False, allow_null=True) - individual = serializers.SlugRelatedField(queryset=Individual.objects.all(), slug_field='name', read_only=False, - required=False, allow_null=True) - intervention = serializers.SlugRelatedField(queryset=Intervention.objects.all(), slug_field='name',read_only=False,required=False, allow_null=True) - substance = serializers.SlugRelatedField(queryset=Substance.objects.all(), slug_field='name',read_only=False,required=False, allow_null=True) + +class OutputSerializer(ParserSerializer): + + group =serializers.PrimaryKeyRelatedField(queryset=Group.objects.all(), read_only=False,required=False, allow_null=True) + individual = serializers.PrimaryKeyRelatedField(queryset=Individual.objects.all(), read_only=False,required=False, allow_null=True) + intervention = serializers.PrimaryKeyRelatedField(queryset=Intervention.objects.all(),read_only=False,required=False, allow_null=True) + substance = serializers.SlugRelatedField(slug_field="name",queryset=Substance.objects.all(),read_only=False,required=False, allow_null=True) class Meta: model = Output - fields = Sourceable.fields() + Valueable.fields() + ValueableMap.fields() + ["pktype", "pktype_map", "time", + fields = ["source","figure","format"] + \ + ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", ] \ + +["value_map", "mean_map", "median_map", "min_map", "max_map","sd_map", "se_map", "cv_map", "unit_map" ]\ + + ["pktype", "pktype_map", "time", "time_map","group", "group_map", "individual", "individual_map", "intervention", "intervention_map", "substance","substance_map","tissue", "tissue_map"] + def to_internal_value(self, data): + """ + + :param data: + :return: + """ + + + #data = self.strip(data) + #data = self.generic_parser(data, "outputs") + study_sid = self.context['request'].path.split("/")[-2] + + if "group" in data : + if data["group"]: + try: + data["group"] = Group.objects.get(Q(groupset__study__sid=study_sid) & Q(name=data.get("group"))).pk + except ObjectDoesNotExist: + msg = f'group: {data.get("group")} in study: {study_sid} does not exist' + raise ValidationError(msg) + if "individual" in data: + if data["individual"]: + try: + data["individual"] = Individual.objects.get(Q(individualset__study__sid=study_sid) & Q(name=data.get("individual"))).pk + except ObjectDoesNotExist: + msg = f'individual: {data.get("individual")} in study: {study_sid} does not exist' + raise ValidationError(msg) + if "intervention" in data: + if data["intervention"]: + try: + data["intervention"] = Intervention.objects.get(Q(interventionset__study__sid=study_sid) & Q(name=data.get("intervention"))).pk + except ObjectDoesNotExist: + msg = f'intervention: {data.get("intervention")} in study: {study_sid} does not exist' + raise ValidationError(msg) + + data = self.split_to_map(data) + #data = self.drop_empty(data) + data = self.strip(data) + data = self.drop_blank(data) + print(data["value"]) + + return super().to_internal_value(data) + + class OutputSetSerializer(ParserSerializer): - outputs = OutputSerializer(many=True, read_only=False) + outputs = OutputSerializer(many=True, read_only=False, required=False, allow_null=True) class Meta: model = OutputSet fields = ["outputs","description"] + + def to_internal_value(self, data): + """ + + :param data: + :return: + """ + data = self.generic_parser(data, "outputs") + data = self.split_to_map(data) + + return super().to_internal_value(data) diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 65b5dda9..53287a35 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -15,6 +15,7 @@ class BaseSerializer(serializers.ModelSerializer): def is_valid(self, raise_exception=False): if "sid" in self.initial_data.keys(): sid = self.initial_data.get("sid") + self.context["study"] = sid try: # Try to get the object in question obj = self.Meta.model.objects.get(sid = sid) @@ -112,12 +113,36 @@ def mapping_parser(mapping,table): def split_to_map(data): splitted_data = {} for key,value in data.items(): - if "==" in value: - splitted_data[f"{key}_map"] = data.get(key) - else: - splitted_data[key] = data.get(key) + try: + if "==" in value: + splitted_data[f"{key}_map"] = data.get(key) + else: + splitted_data[key] = data.get(key) + except : + splitted_data[key] = data.get(key) + return splitted_data + @staticmethod + def drop_blank(data): + return {k: v for k, v in data.items() if v is not None} + + @staticmethod + def drop_empty(data): + return {k:v for k, v in data.items() if (not v and isinstance(v, str) )} + + + @staticmethod + def strip(data): + data_stripped = {} + + for k, v in data.items(): + if isinstance(v, str):# and not k=="name"): + v = v.strip() + data_stripped[k] = v + + + return data_stripped def to_representation(self, instance): diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 51b13278..d88bc1b1 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -67,7 +67,7 @@ def update(self, instance, validated_data): class StudySerializer(BaseSerializer): - reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all(), required=False,allow_null=True) + reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all(), required=False, allow_null=True) groupset = GroupSetSerializer(read_only=False, required=False,allow_null=True) curators = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username', many=True,required=False,allow_null=True) creator = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username',required=False,allow_null=True) @@ -81,6 +81,12 @@ class Meta: fields = BASE_FIELDS + ('sid','name',"creator","pkdb_version","design",'reference',"curators", "groupset", "interventionset","individualset","outputset","substances") + def to_internal_value(self, data): + sid = data.get("sid") + self.context["study"] = sid + + return super().to_internal_value(data) + @staticmethod def pop_relations(validated_data): related = {} @@ -92,13 +98,12 @@ def pop_relations(validated_data): related["outputset_data"] = validated_data.pop('outputset', None) related["creator_data"] = validated_data.pop('creator', None) - related["reference"] = validated_data.pop('reference') + related["reference"] = validated_data.pop('reference',None) try: related["creator"] = User.objects.get(username=related["creator_data"]) except ObjectDoesNotExist: related["creator"] = None - return related @staticmethod @@ -163,9 +168,8 @@ def update(self, instance, validated_data): related = self.pop_relations(validated_data) - - - instance.creator = related["creator"] + if related["creator"] is not None: + instance.creator = related["creator"] for name, value in validated_data.items(): setattr(instance, name, value) @@ -175,3 +179,4 @@ def update(self, instance, validated_data): return instance + diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index ab92c83d..c82e7836 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -73,11 +73,16 @@ def to_internal_value(self, data): return super(GroupSetSerializer, self).to_internal_value(data) - +class GroupSRField(serializers.SlugRelatedField): + def get_queryset(self): + study = self.context["study"] + queryset = Group.objects.filter(groupset__study__sid = study) + return queryset class IndividualSerializer(ParserSerializer): + characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False,allow_null=True) - group = serializers.SlugRelatedField(queryset=Group.objects.all(), slug_field='name',read_only=False,required=False, allow_null=True) #todo: filter for only this study + group = GroupSRField( slug_field='name',read_only=False,required=False, allow_null=True) #todo: filter for only this study #todo:add figure From d4bd6743007c9043b5265069dfec9a086359d868 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 8 Aug 2018 23:35:02 +0200 Subject: [PATCH 037/115] im principille the serializer is working! Add timecourse, changed representation to name on output and individuals --- pkdb_app/behaviours.py | 2 +- pkdb_app/categoricals.py | 11 ++- pkdb_app/comments/migrations/0001_initial.py | 4 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/data_management/add_groups.py | 2 +- pkdb_app/data_management/add_output.py | 18 +++-- pkdb_app/interventions/managers.py | 15 +++- pkdb_app/interventions/models.py | 21 ++++-- pkdb_app/interventions/serializers.py | 69 +++++++++++++------ pkdb_app/serializers.py | 26 +++++-- pkdb_app/subjects/serializers.py | 7 ++ pkdb_app/utils.py | 2 +- 12 files changed, 133 insertions(+), 48 deletions(-) diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index 8c0a7bb0..dd10ba3c 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -76,7 +76,7 @@ class Meta: class Sourceable(models.Model): source = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) # todo: to file_filed - figure = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) # todo: to file_filed + figure = models.CharField(max_length=CHAR_MAX_LENGTH*5,null=True, blank=True) # todo: to file_filed format = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) class Meta: diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 4d47ea03..94e60846 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -56,8 +56,14 @@ def create_choices(list): UnitType("µg/ml"), UnitType("mg"), UnitType("ml/min/1.73m^2"), - - + UnitType("µg/ml*h/kg"), + UnitType("l"), + UnitType("µmol/l*h"), + UnitType("ml/min"), + UnitType("mg/l*min"), + UnitType("ml/h/kg"), + UnitType("mg/l"), + UnitType("mg/l*h"), ] @@ -219,6 +225,7 @@ def create_choices(list): "ratio", "clearance_tbc", "caf_px_6h", + "auc24h", ] OUTPUT_TISSUE_DATA = [ "saliva", diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index 705033f4..6d2207d9 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-07 15:38 +# Generated by Django 2.0.6 on 2018-08-08 10:44 from django.db import migrations, models @@ -8,8 +8,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('interventions', '0001_initial'), ('subjects', '0001_initial'), + ('interventions', '0001_initial'), ] operations = [ diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index 846f87d7..4824b622 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-07 15:38 +# Generated by Django 2.0.6 on 2018-08-08 10:44 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('comments', '0002_auto_20180808_1044'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('comments', '0002_auto_20180807_1538'), ] operations = [ diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py index 6626080c..369a1135 100644 --- a/pkdb_app/data_management/add_groups.py +++ b/pkdb_app/data_management/add_groups.py @@ -105,7 +105,7 @@ def add_individual_set(data): individuals_dict["format"] = individuals_dict_raw["format"] individuals_dict["figure"] = individuals_dict_raw["figure"] individuals_dict['characteristica'] = add_characteristic_values(individuals_dict_raw) - this_data["json"]["individualset"]["individuals"].append(individuals_dict) + this_data["json"]["individualset"]["individuals"].append(clean_import(individuals_dict)) return this_data diff --git a/pkdb_app/data_management/add_output.py b/pkdb_app/data_management/add_output.py index 6eedfe44..bd71cecd 100644 --- a/pkdb_app/data_management/add_output.py +++ b/pkdb_app/data_management/add_output.py @@ -25,7 +25,9 @@ def add_outputs_to_study(study): for name, data in study_output.groupby(["subjects", "dosing","substance"]): output = {} output["group"] = name[0] - output["intervention"] = name[1] + interventions = name[1].split(",") + output["interventions"] = list(map(str.strip,interventions)) + output["substance"] = name[2] @@ -40,8 +42,7 @@ def add_outputs_to_study(study): output['min'] = row["min"] output['max'] = row["max"] output['unit'] = row["unit"] - - study_json["outputset"]["outputs"].append(clean_import(output)) + study_json["outputset"]["outputs"].append(clean_import(output)) yield {"json":study_json,"study_path": study["study_path"]} @@ -56,7 +57,11 @@ def add_timecourse_to_ouput(data): for timecourse in this_timecourse.itertuples(index=False): timecourse_dict = timecourse._asdict() timecourse_dict.pop("study") - this_data["json"]["outputset"]["timecourse"].append(timecourse_dict) + if ("interventions" in timecourse_dict and timecourse_dict["interventions"]): + timecourse_dict["interventions"] = list( + map(str.strip, timecourse_dict["interventions"].split(","))) + + this_data["json"]["outputset"]["timecourse"].append(clean_import(timecourse_dict)) return this_data @@ -71,7 +76,10 @@ def add_individualmapping_to_ouput(data): for individuals_output in this_individuals_output.itertuples(index=False): individuals_output_dict = individuals_output._asdict() individuals_output_dict.pop("study") - this_data["json"]["outputset"]["outputs"].append(individuals_output_dict) + if ("interventions" in individuals_output_dict and individuals_output_dict["interventions"]): + individuals_output_dict["interventions"] = list(map(str.strip,individuals_output_dict["interventions"].split(","))) + + this_data["json"]["outputset"]["outputs"].append(clean_import(individuals_output_dict)) return this_data diff --git a/pkdb_app/interventions/managers.py b/pkdb_app/interventions/managers.py index 02888986..f055942b 100644 --- a/pkdb_app/interventions/managers.py +++ b/pkdb_app/interventions/managers.py @@ -2,6 +2,7 @@ the managers can be used to overwrite class methods of the models module. """ from django.db import models +from django.apps import apps class InterventionSetManager(models.Manager): @@ -23,11 +24,23 @@ class OutputSetManager(models.Manager): def create(self, *args, **kwargs): outputs = kwargs.pop("outputs", []) + timecourses = kwargs.pop("timecourse", []) + outputset = super().create(*args, **kwargs) outputset.outputs.all().delete() for output in outputs: - outputset.outputs.create(**output) + intervention_ids = output.pop("interventions", []) + output_instance = outputset.outputs.create(**output) + output_instance.interventions.add(*intervention_ids) + output_instance.save() + outputset.save() + + for timecourse in timecourses: + intervention_ids = timecourse.pop("interventions", []) + timecourse_instance = outputset.timecourse.create(**timecourse) + timecourse_instance.interventions.add(*intervention_ids) + timecourse_instance.save() outputset.save() return outputset diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 1234bf02..7efcf53c 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -78,7 +78,7 @@ class Intervention(Valueable,models.Model): form = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_FORM_CHOICES) application = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_APPLICATION_CHOICES) # application: # how timing ['single dose', 'multiple doses', 'continuous injection'] - application_time = models.DecimalField(max_digits = 40,decimal_places=20,null=True,blank=False) #application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) + time = models.DecimalField(max_digits = 40,decimal_places=20,null=True,blank=False) #application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) time_unit = models.CharField(max_length=CHAR_MAX_LENGTH,null=True,blank=True, choices=TIME_UNITS_CHOICES) ###### @@ -102,6 +102,9 @@ def choices(self): class Meta: unique_together = ('interventionset', 'name') + def __str__(self): + return self.name + class CleanIntervention(Intervention): """ Calculated from medicationstep @@ -118,7 +121,8 @@ class OutputSet(Set): class BaseOutput(models.Model): group = models.ForeignKey(Group, null=True, blank=True, on_delete=False) individual = models.ForeignKey(Individual, null=True, blank=True, on_delete=False) - intervention = models.ForeignKey(Intervention,null=True, blank=True, on_delete=False) + #intervention = models.ForeignKey(Intervention,null=True, blank=True, on_delete=False) + interventions = models.ManyToManyField(Intervention) substance = models.ForeignKey(Substance, null=True, blank=True,on_delete=False) tissue = models.CharField(max_length=CHAR_MAX_LENGTH,choices=OUTPUT_TISSUE_DATA_CHOICES ,null=True, blank=True) @@ -128,7 +132,7 @@ class Meta: class BaseOutputMap(models.Model): group_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) individual_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - intervention_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + interventions_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) substance_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) tissue_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) @@ -144,25 +148,30 @@ class Meta: class Output(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseOutput,models.Model): - outputset = models.ForeignKey(OutputSet, related_name="outputs", on_delete=models.CASCADE) + outputset = models.ForeignKey(OutputSet, related_name="outputs", on_delete=models.CASCADE,null=True, blank=True) """ Storage of data sets. """ pktype = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES, null=True, blank=True) time = models.DecimalField(max_digits = 40,decimal_places=20,null=True,blank=True) + # files from which the data was extracted, these have to be linked to the study already should be PNG or NONE #files = models.ForeignKey(DataFile, on_delete=True) -class Timecourse(BaseOutput): +class Timecourse(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseOutput,models.Model): """ Storing of time course data. Store a binary blop of the data (json, pandas dataframe or similar, backwards compatible). """ #substance #tissue - data = models.ForeignKey(DataFile, on_delete=True) # link to the CSV + outputset = models.ForeignKey(OutputSet, related_name="timecourse", on_delete=models.CASCADE,null=True, blank=True) + + pktype = models.CharField(max_length=CHAR_MAX_LENGTH, choices=PK_DATA_CHOICES, null=True, blank=True) + time = models.DecimalField(max_digits=40, decimal_places=20, null=True, blank=True) + #data = models.ForeignKey(DataFile, on_delete=True) # link to the CSV class CleanOutput(Output): diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 210888db..d5c9832e 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -3,7 +3,7 @@ from rest_framework import serializers from pkdb_app.behaviours import Sourceable, Valueable, ValueableMap -from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet +from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet, Timecourse from pkdb_app.serializers import ParserSerializer from pkdb_app.subjects.models import IndividualSet, Individual, Group from pkdb_app.subjects.serializers import GroupSRField @@ -24,7 +24,7 @@ class InterventionSerializer(ParserSerializer): class Meta: model = Intervention - fields = ["name","route","form","application","application_time","time_unit"] + fields = ["name","route","form","application","time","time_unit","value"] def to_internal_value(self, data): """ @@ -32,7 +32,6 @@ def to_internal_value(self, data): :param data: :return: """ - data = self.split_to_map(data) data = self.drop_blank(data) data = self.strip(data) @@ -53,19 +52,19 @@ def to_internal_value(self, data): :param data: :return: """ - #data = self.generic_parser(data,"interventions") + data = self.generic_parser(data,"interventions") #data = self.split_to_map(data) #data = self.drop_blank(data) #data = self.strip(data) return super(InterventionSetSerializer, self).to_internal_value(data) - class OutputSerializer(ParserSerializer): + group = serializers.PrimaryKeyRelatedField(queryset=Group.objects.all(), read_only=False,required=False, allow_null=True) + individual = serializers.PrimaryKeyRelatedField(queryset=Individual.objects.all(), read_only=False, required=False, allow_null=True) + #intervention = serializers.PrimaryKeyRelatedField(queryset=Intervention.objects.all(),read_only=False,required=False, allow_null=True) + interventions = serializers.PrimaryKeyRelatedField(queryset=Intervention.objects.all(),many=True, read_only=False,required=False, allow_null=True) - group =serializers.PrimaryKeyRelatedField(queryset=Group.objects.all(), read_only=False,required=False, allow_null=True) - individual = serializers.PrimaryKeyRelatedField(queryset=Individual.objects.all(), read_only=False,required=False, allow_null=True) - intervention = serializers.PrimaryKeyRelatedField(queryset=Intervention.objects.all(),read_only=False,required=False, allow_null=True) substance = serializers.SlugRelatedField(slug_field="name",queryset=Substance.objects.all(),read_only=False,required=False, allow_null=True) class Meta: @@ -74,9 +73,10 @@ class Meta: ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", ] \ +["value_map", "mean_map", "median_map", "min_map", "max_map","sd_map", "se_map", "cv_map", "unit_map" ]\ + ["pktype", "pktype_map", "time", - "time_map","group", "group_map", "individual", "individual_map", "intervention", "intervention_map", + "time_map","group","group_map", "individual", "individual_map", "interventions", "interventions_map", "substance","substance_map","tissue", "tissue_map"] + def to_internal_value(self, data): """ @@ -88,6 +88,8 @@ def to_internal_value(self, data): #data = self.strip(data) #data = self.generic_parser(data, "outputs") study_sid = self.context['request'].path.split("/")[-2] + data = self.split_to_map(data) + if "group" in data : if data["group"]: @@ -103,31 +105,54 @@ def to_internal_value(self, data): except ObjectDoesNotExist: msg = f'individual: {data.get("individual")} in study: {study_sid} does not exist' raise ValidationError(msg) - if "intervention" in data: - if data["intervention"]: - try: - data["intervention"] = Intervention.objects.get(Q(interventionset__study__sid=study_sid) & Q(name=data.get("intervention"))).pk - except ObjectDoesNotExist: - msg = f'intervention: {data.get("intervention")} in study: {study_sid} does not exist' - raise ValidationError(msg) + if "interventions" in data: + if data["interventions"]: + interventions = [] + for internvention in data["interventions"]: + try: + interventions.append(Intervention.objects.get(Q(interventionset__study__sid=study_sid) & Q(name=internvention)).pk) + except ObjectDoesNotExist: + msg = f'intervention: {internvention} in study: {study_sid} does not exist' + raise ValidationError(msg) + data["interventions"] = interventions - data = self.split_to_map(data) - #data = self.drop_empty(data) data = self.strip(data) data = self.drop_blank(data) - print(data["value"]) + data = self.drop_empty(data) return super().to_internal_value(data) + def to_representation(self, instance): + rep = super().to_representation(instance) + if "group" in rep: + rep["group"] = instance.group.name + if "interventions" in rep: + rep["interventions"] = [intervention.name for intervention in instance.interventions.all()] + return rep + + +class TimecourseSerializer(OutputSerializer): + + class Meta: + model = Timecourse + fields = ["source", "figure", "format"] + \ + ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", ] \ + + ["value_map", "mean_map", "median_map", "min_map", "max_map", "sd_map", "se_map", "cv_map", + "unit_map"] \ + + ["pktype", "pktype_map", "time", + "time_map", "group", "group_map", "individual", "individual_map", "interventions", + "interventions_map", + "substance", "substance_map", "tissue", "tissue_map"] class OutputSetSerializer(ParserSerializer): outputs = OutputSerializer(many=True, read_only=False, required=False, allow_null=True) + timecourse = TimecourseSerializer(many=True, read_only=False, required=False, allow_null=True) class Meta: model = OutputSet - fields = ["outputs","description"] + fields = ["description","outputs","timecourse"] def to_internal_value(self, data): """ @@ -139,3 +164,7 @@ def to_internal_value(self, data): data = self.split_to_map(data) return super().to_internal_value(data) + + + + diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 53287a35..83d9f28d 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned +from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError from collections import OrderedDict import pandas as pd import string @@ -69,15 +69,20 @@ def list_chara(data): values = list(map(str.strip, values)) except AttributeError: values = [value] + + if (key == "name" and len(values) != n): + msg = f"names have to be splitted and not left as <{values}>. Otherwise UniqueConstrain is violated." + raise ValidationError(msg) + if len(values) == 1: values = values * n - if key == "name" and n > 1: - ialpha = iter(string.ascii_uppercase) - values = [f"{value}_{next(ialpha)}" for value in values] + #if key == "name" and n > 1: + # ialpha = iter(string.ascii_uppercase) + # values = [f"{value}_{next(ialpha)}" for value in values] - data_n[key] = values + data_n[key] = values return data_n @@ -129,8 +134,15 @@ def drop_blank(data): @staticmethod def drop_empty(data): - return {k:v for k, v in data.items() if (not v and isinstance(v, str) )} - + dropped_empty = {} + for k,v in data.items(): + if isinstance(v,str): + if not v: + print(V) + continue + dropped_empty[k] = v + #return {k:v for k, v in data.items() if (not v and isinstance(v, str))} + return dropped_empty @staticmethod def strip(data): diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index c82e7836..938aa68c 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -103,6 +103,13 @@ def to_internal_value(self, data): return super(IndividualSerializer, self).to_internal_value(data) + def to_representation(self, instance): + rep = super().to_representation(instance) + if "group" in rep: + rep["group"] = instance.group.name + + return rep + def parse_individuals(self,data): try: individuals = data diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index c6cba393..57d1c551 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -13,7 +13,7 @@ def clean_import(data): clean_dict = {} for key, value in data.items(): - if not str(value) in ["", "nan"]: + if not str(value).strip() in ["", "nan"]: clean_dict[key] = value elif str(value) == "NA": From feac760181bfc485c9937548035d3c49d50e24a4 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 8 Aug 2018 23:41:12 +0200 Subject: [PATCH 038/115] fixed small type in one study From 12c968f465e78dd2df4bdd51327258b6a6b7091f Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 9 Aug 2018 18:30:33 +0200 Subject: [PATCH 039/115] added quite alot of validations cleaned up data --- docs/api/api.ipynb | 4 +- pkdb_app/behaviours.py | 18 +-- pkdb_app/categoricals.py | 25 +++- pkdb_app/comments/migrations/0001_initial.py | 4 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/config/common.py | 8 +- pkdb_app/config/local.py | 2 + pkdb_app/data_management/add_intervention.py | 5 +- pkdb_app/data_management/fill_database.py | 9 +- pkdb_app/interventions/models.py | 4 +- pkdb_app/interventions/serializers.py | 4 +- pkdb_app/serializers.py | 88 ++++++++++-- pkdb_app/studies/serializers.py | 126 +++--------------- pkdb_app/subjects/serializers.py | 26 +++- pkdb_app/urls.py | 8 ++ pkdb_app/utils.py | 14 ++ requirements.txt | 4 +- 17 files changed, 205 insertions(+), 148 deletions(-) diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index 99e63ece..7b9cd1a8 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -1515,9 +1515,9 @@ ], "metadata": { "kernelspec": { - "display_name": "pkdb-test", + "display_name": "pkdb", "language": "python", - "name": "pkdb-test" + "name": "pkdb" }, "language_info": { "codemirror_mode": { diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index dd10ba3c..3da52ecf 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -92,15 +92,15 @@ class Valueable(models.Model): In addition all the statistical values are stored. """ count = models.IntegerField(null=True, blank=True) # how many participants in characteristics - value = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) - - mean = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) - median = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) - min = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) - max = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) - sd = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) - se = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) - cv = models.DecimalField(max_digits = 40,decimal_places=20, null=True, blank=True) + value = models.FloatField( null=True, blank=True) + mean = models.FloatField( null=True, blank=True) + median = models.FloatField( null=True, blank=True) + min = models.FloatField( null=True, blank=True) + max = models.FloatField( null=True, blank=True) + sd = models.FloatField( null=True, blank=True) + se = models.FloatField( null=True, blank=True) + cv = models.FloatField( null=True, blank=True) + unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH, null=True, blank=True) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 94e60846..7038ec93 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -64,6 +64,8 @@ def create_choices(list): UnitType("ml/h/kg"), UnitType("mg/l"), UnitType("mg/l*h"), + UnitType("mg/kg"), + UnitType("mg/day") ] @@ -84,7 +86,8 @@ def create_choices(list): STRING_TYPE = "string" # can be a free string, no limitations compared to categorial YES = "Y" NO = 'N' -BOOLEAN_CHOICES = [YES, NO] +M = "Mixed" +BOOLEAN_CHOICES = [YES, NO, M] INTERVENTION_ROUTE = [ "oral", @@ -101,6 +104,10 @@ def create_choices(list): INTERVENTION_FORM = [ "tablete", "capsule", + "2 100mg NO-DOZ tablets", + "capsules", + "2 capsules", + ] INTERVENTION_FORM_CHOICES = create_choices(INTERVENTION_FORM) @@ -151,6 +158,12 @@ def create_choices(list): "17U", "37X", "1X", + "enoxacin", + "ciprofloxacin", + "pipemidic acid", + "norfloxacin", + "ofloxacin", + "fluvoxamine", ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] @@ -165,7 +178,7 @@ def create_choices(list): # Lifestyle CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('caffeine amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('caffeine amount', 'lifestyle', NUMERIC_TYPE, None, ["mg/day"]), ] CHARACTERISTIC_DATA = COMMON_DATA + [ @@ -179,21 +192,22 @@ def create_choices(list): CharacteristicType('kidney weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), CharacteristicType('age', DEMOGRAPHICS, NUMERIC_TYPE, None, ["yr"]), - CharacteristicType('sex', DEMOGRAPHICS, CATEGORIAL_TYPE, ["M", "F"], ["-"]), + CharacteristicType('sex', DEMOGRAPHICS, CATEGORIAL_TYPE, ["M", "F", "Mixed"], ["-"]), CharacteristicType('ethnicity', DEMOGRAPHICS, CATEGORIAL_TYPE, ["african", "afroamerican", "asian", "caucasian"], ["-"]), # Disease (status) CharacteristicType('healthy', "health status", BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('disease', "disease", CATEGORIAL_TYPE, ["cirrhosis"], ["-"]), + CharacteristicType('disease', "disease", CATEGORIAL_TYPE, ["cirrhosis","plasmodium falciparum","alcoholic liver cirrhosis","cirrhotic liver disease","PBC","miscellaneous liver disease","schizophrenia"], ["-"]), # Lifestyle CharacteristicType('smoking', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('smoking amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('smoking amount', 'lifestyle', NUMERIC_TYPE, None, ["1/day"]), CharacteristicType('alcohol', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('alcohol amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), + # Biochemical data CharacteristicType('ALT', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["IU/I"]), CharacteristicType('AST', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["IU/I"]), @@ -208,7 +222,6 @@ def create_choices(list): # Genetics ??? # Requires storage of the variants and effects of clearance ] - PK_DATA = [ "auc", "concentration", diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index 6d2207d9..9c9a2804 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-08 10:44 +# Generated by Django 2.0.6 on 2018-08-09 13:29 from django.db import migrations, models @@ -8,8 +8,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('subjects', '0001_initial'), ('interventions', '0001_initial'), + ('subjects', '0001_initial'), ] operations = [ diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index 4824b622..c86553f0 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-08 10:44 +# Generated by Django 2.0.6 on 2018-08-09 13:29 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('comments', '0002_auto_20180808_1044'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('comments', '0002_auto_20180809_1329'), ] operations = [ diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index 58565957..fd883d51 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -26,6 +26,8 @@ class Common(Configuration): 'rest_framework.authtoken', # token authentication 'django_filters', # for filtering rest endpoints 'rest_framework_swagger', + 'debug_toolbar', + # Your apps 'pkdb_app.users', 'pkdb_app.studies', @@ -44,8 +46,13 @@ class Common(Configuration): 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'debug_toolbar.middleware.DebugToolbarMiddleware', ) + DEBUG_TOOLBAR_PATCH_SETTINGS = False + + INTERNAL_IPS = ('172.19.0.1',) + ALLOWED_HOSTS = ["*"] ROOT_URLCONF = 'pkdb_app.urls' SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') @@ -204,7 +211,6 @@ class Common(Configuration): ], 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', - #'rest_framework.authentication.T' 'rest_framework.authentication.TokenAuthentication', ), diff --git a/pkdb_app/config/local.py b/pkdb_app/config/local.py index f44d7892..6b9b2ac6 100755 --- a/pkdb_app/config/local.py +++ b/pkdb_app/config/local.py @@ -7,6 +7,8 @@ class Local(Common): + + DEBUG = True # Testing diff --git a/pkdb_app/data_management/add_intervention.py b/pkdb_app/data_management/add_intervention.py index de9cbd57..dc42b672 100644 --- a/pkdb_app/data_management/add_intervention.py +++ b/pkdb_app/data_management/add_intervention.py @@ -31,9 +31,10 @@ def add_intervention_to_study(study): intervention_json = {} intervention_json["name"] = row["dosing"] intervention_json["substance"] = row["substance"] - intervention_json["time"] = row["times"] - intervention_json["time_unit"] = row["times_unit"] + intervention_json["time"] = row["time"] + intervention_json["time_unit"] = row["time_unit"] intervention_json["route"] = row["route"] + intervention_json["form"] = row["form"] intervention_json["value"] = row["dose"] intervention_json["unit"] = row["dose_unit"] study_json["interventionset"]["interventions"].append(clean_import(intervention_json)) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 7d4ae345..b9710389 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -83,7 +83,12 @@ def upload_study(json_study): study_partial["individualset"] = json_study["json"].get("individualset",None) - client.action(document, ["studies", "create"], params=study_partial) + #client.action(document, ["studies", "create"], params=study_partial) + response = requests.post(f'http://0.0.0.0:8000/api/v1/studies/', + json=study_partial) + if response.status_code == 400: + print(json_study["json"]["name"],response.text) + if "outputset" in json_study["json"].keys(): response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = {"outputset": json_study["json"].get("outputset")}) if response.status_code == 400: @@ -122,6 +127,6 @@ def get_services(**options): parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: - bonobo.run(get_graph_references(**options), services=get_services(**options)) + #bonobo.run(get_graph_references(**options), services=get_services(**options)) bonobo.run(get_graph_study(**options), services=get_services(**options)) diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 7efcf53c..2d603d86 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -78,7 +78,7 @@ class Intervention(Valueable,models.Model): form = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_FORM_CHOICES) application = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_APPLICATION_CHOICES) # application: # how timing ['single dose', 'multiple doses', 'continuous injection'] - time = models.DecimalField(max_digits = 40,decimal_places=20,null=True,blank=False) #application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) + time = models.FloatField(null=True,blank=False) #application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) time_unit = models.CharField(max_length=CHAR_MAX_LENGTH,null=True,blank=True, choices=TIME_UNITS_CHOICES) ###### @@ -154,7 +154,7 @@ class Output(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseOutpu pktype = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES, null=True, blank=True) - time = models.DecimalField(max_digits = 40,decimal_places=20,null=True,blank=True) + time = models.FloatField(null=True,blank=True) # files from which the data was extracted, these have to be linked to the study already should be PNG or NONE #files = models.ForeignKey(DataFile, on_delete=True) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index d5c9832e..e38c35b5 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -21,10 +21,12 @@ def create(self, validated_data): class InterventionSerializer(ParserSerializer): + substance = serializers.SlugRelatedField(slug_field="name",queryset=Substance.objects.all(),read_only=False,required=False, allow_null=True) + class Meta: model = Intervention - fields = ["name","route","form","application","time","time_unit","value"] + fields = ["name","route","form","application","time","time_unit","value","unit","substance"] def to_internal_value(self, data): """ diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 83d9f28d..6084a0e4 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -1,10 +1,19 @@ +import re +from lark import UnexpectedCharacters, Lark + from rest_framework import serializers from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError -from collections import OrderedDict +from collections import OrderedDict, namedtuple import pandas as pd -import string -from pkdb_app.categoricals import FORMAT_MAPPING +from pkdb_app.interventions.models import Substance, InterventionSet, OutputSet +from pkdb_app.studies.models import Reference +from pkdb_app.subjects.models import GroupSet, IndividualSet +from pkdb_app.users.models import User +from pkdb_app.utils import get_or_val_error + + +RELATED_SETS = {"groupset":GroupSet ,"individualset": IndividualSet,"interventionset":InterventionSet,"outputset":OutputSet} class BaseSerializer(serializers.ModelSerializer): """ @@ -39,8 +48,40 @@ def to_representation(self, instance): result = super().to_representation(instance) return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) -class ParserSerializer(serializers.ModelSerializer): + @staticmethod + def create_relations(study, related): + for name,model in RELATED_SETS.items(): + if related[name] is not None: + instance = model.objects.create(**related[name]) + instance.save() + setattr(study,name,instance) + + for curator_data in related["curators"]: + curator = get_or_val_error(User, username=curator_data) + study.curators.add(curator) + + for substance_data in related["substances"]: + + substance = get_or_val_error(Substance, name=substance_data) + study.substances.add(substance) + + study.save() + + return study + + @staticmethod + def pop_relations(validated_data): + related_foreinkeys = RELATED_SETS.copy() + related_foreinkeys["reference"] = Reference + related_many2many = {"substances": Substance,"curators": User} + related_foreinkeys_dict = {name:validated_data.pop(name, None) for name,_ in related_foreinkeys.items()} + related_many2many_dict = {name:validated_data.pop(name, []) for name,_ in related_many2many.items()} + related = {**related_foreinkeys_dict,**related_many2many_dict} + return related + + +class ParserSerializer(serializers.ModelSerializer): @staticmethod def generic_parser(data,key): @@ -57,16 +98,33 @@ def number_raw(data): return len(values) return 1 + def split_string_count(string): + + l = Lark('''start: WORD "{{" NUMBER "}}" + %import common.NUMBER + %import common.WORD + + %ignore " " // Disregard spaces in text + ''') + + try: + data = l.parse(string) + # except UnexpectedCharacters as e: + # msg = f"{string} is not maching pattern:\{{(.?[0-9]+)\}}" + # raise ValidationError(str(e)) + except UnexpectedCharacters as e: + raise ValidationError(f"UnexpectedCharacters in {string}") + return data def list_chara(data): n = number_raw(data) data_n = {} for key, value in data.items(): - # if type(value) == str: try: values = value.split('||') values = list(map(str.strip, values)) + except AttributeError: values = [value] @@ -77,8 +135,21 @@ def list_chara(data): if len(values) == 1: values = values * n - - #if key == "name" and n > 1: + else: + values_n = [] + count_n = [] + for value in values: + if "{{" in value: + splitted_data = split_string_count(value) + values_n.append(splitted_data.children[0].value) + count_n.append(splitted_data.children[1].value) + else: + values_n.append(value) + count_n.append(data.get("count", "")) + values = values_n + data_n["count"] = count_n + + # if key == "name" and n > 1: # ialpha = iter(string.ascii_uppercase) # values = [f"{value}_{next(ialpha)}" for value in values] @@ -90,7 +161,9 @@ def list_chara(data): for raw_single in raw: raw_single = {k: v for k, v in raw_single.items() if v is not None} cleaned += pd.DataFrame(list_chara(raw_single)).to_dict('records') + data[key] = cleaned + return data @@ -138,7 +211,6 @@ def drop_empty(data): for k,v in data.items(): if isinstance(v,str): if not v: - print(V) continue dropped_empty[k] = v #return {k:v for k, v in data.items() if (not v and isinstance(v, str))} diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index d88bc1b1..208a8451 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -1,21 +1,12 @@ from rest_framework import serializers -from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned - -from pkdb_app.categoricals import SUBSTANCES_DATA -from pkdb_app.interventions.models import Substance, InterventionSet, OutputSet -from pkdb_app.interventions.serializers import SubstanceSerializer, InterventionSetSerializer, OutputSetSerializer -from pkdb_app.subjects.serializers import GroupSetSerializer, IndividualSetSerializer -from pkdb_app.users.models import User -from pkdb_app.users.serializers import UserSerializer +from pkdb_app.utils import update_or_create_multiple, get_or_val_error +from ..interventions.models import Substance +from ..interventions.serializers import InterventionSetSerializer, OutputSetSerializer +from ..subjects.serializers import GroupSetSerializer, IndividualSetSerializer +from ..users.models import User from .models import Reference, Author, Study -from django.core.exceptions import ObjectDoesNotExist -#from ..subjects.serializers import GroupSerializer -from ..subjects.models import Group, GroupSet, IndividualSet from ..serializers import BaseSerializer -from django.shortcuts import get_object_or_404 - -BASE_FIELDS = () class AuthorSerializer(serializers.ModelSerializer): @@ -35,37 +26,25 @@ class ReferenceSerializer(BaseSerializer): class Meta: model = Reference - fields = BASE_FIELDS + ('pmid', 'sid', 'name', 'doi', 'title','abstract', 'journal', 'date', 'authors', 'pdf') + fields = ('pmid', 'sid', 'name', 'doi', 'title','abstract', 'journal', 'date', 'authors', 'pdf') def create(self, validated_data): authors_data = validated_data.pop('authors',[]) reference = Reference.objects.create(**validated_data) - - - for author_data in authors_data: - author, _ = Author.objects.update_or_create(**author_data) - reference.authors.add(author) - reference.save() - + update_or_create_multiple(reference,authors_data,"authors") + reference.save() return reference def update(self, instance, validated_data): authors_data = validated_data.pop('authors',[]) - for name, value in validated_data.items(): setattr(instance, name, value) - - for author_data in authors_data: - author, _ = Author.objects.update_or_create(**author_data) - instance.authors.add(author) - + update_or_create_multiple(instance,authors_data,"authors") instance.save() - return instance - class StudySerializer(BaseSerializer): reference = serializers.PrimaryKeyRelatedField(queryset=Reference.objects.all(), required=False, allow_null=True) groupset = GroupSetSerializer(read_only=False, required=False,allow_null=True) @@ -78,98 +57,31 @@ class StudySerializer(BaseSerializer): class Meta: model = Study - fields = BASE_FIELDS + ('sid','name',"creator","pkdb_version","design",'reference',"curators", - "groupset", "interventionset","individualset","outputset","substances") - - def to_internal_value(self, data): - sid = data.get("sid") - self.context["study"] = sid - - return super().to_internal_value(data) - - @staticmethod - def pop_relations(validated_data): - related = {} - related["interventionset_data"] = validated_data.pop('interventionset', None) - related["substances_data"] = validated_data.pop('substances', []) - related["curators_data"] = validated_data.pop('curators', []) - related["groupset_data"] = validated_data.pop('groupset', None) - related["individualset_data"] = validated_data.pop('individualset', None) - related["outputset_data"] = validated_data.pop('outputset', None) - related["creator_data"] = validated_data.pop('creator', None) - - related["reference"] = validated_data.pop('reference',None) - - try: - related["creator"] = User.objects.get(username=related["creator_data"]) - except ObjectDoesNotExist: - related["creator"] = None - return related - - @staticmethod - def create_relations(study, related): - if related["groupset_data"] is not None: - groupset = GroupSet.objects.create(**related["groupset_data"]) - - groupset.save() - study.groupset = groupset - - if related["individualset_data"] is not None: - individualset = IndividualSet.objects.create(**related["individualset_data"]) - - individualset.save() - study.individualset = individualset - - if related["interventionset_data"] is not None: - interventionset = InterventionSet.objects.create(**related["interventionset_data"]) - interventionset.save() - study.interventionset = interventionset - study.save() - - if related["outputset_data"] is not None: - outputset = OutputSet.objects.create(**related["outputset_data"]) - outputset.save() - study.outputset = outputset - study.save() - - for curator_data in related["curators_data"]: - try: - curator = User.objects.get(username=curator_data) - except ObjectDoesNotExist: - curator = None - study.curators.add(curator) - - for substance_data in related["substances_data"]: - try: - substance = Substance.objects.get(name=substance_data) - except ObjectDoesNotExist: - substance = None - study.substances.add(substance) - - study.save() - - return study - + fields = ('sid','name',"creator","pkdb_version","design",'reference',"curators", + "groupset", "interventionset","individualset","outputset","substances") def create(self, validated_data): related = self.pop_relations(validated_data) + creator = validated_data.get("creator", None) + if creator: + validated_data["creator"] = get_or_val_error(User,username=creator) + study, _ = Study.objects.update_or_create(sid=validated_data["sid"], reference=related["reference"], - creator=related["creator"], defaults=validated_data,) study = self.create_relations(study,related) - - return study def update(self, instance, validated_data): related = self.pop_relations(validated_data) - if related["creator"] is not None: - instance.creator = related["creator"] + creator = validated_data.get("creator", None) + if creator: + validated_data["creator"] = get_or_val_error(User, username=creator) + for name, value in validated_data.items(): setattr(instance, name, value) diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 938aa68c..a3be2acd 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,11 +1,10 @@ import pandas as pd +from django.core.exceptions import ValidationError from rest_framework import serializers from pkdb_app.behaviours import Sourceable -from pkdb_app.categoricals import FORMAT_MAPPING +from pkdb_app.categoricals import FORMAT_MAPPING, CHARACTERISTIC_DICT, CATEGORIAL_TYPE, NUMERIC_TYPE, BOOLEAN_TYPE from .models import Group, GroupSet,Individual,IndividualSet,Characteristica - -from ..studies.models import Reference from ..serializers import ParserSerializer BASE_FIELDS = () @@ -34,6 +33,27 @@ def to_internal_value(self, data): :return: """ data = self.split_to_map(data) + characteristic = CHARACTERISTIC_DICT[data.get("category")] + choice = data.get("choice",None) + unit = data.get("unit",None) + + fields_require_unit = ["value","mean","median","min","max","sd","se","cv","value_map","mean_map","median_map","min_map","max_map","sd_map","se_map","cv_map"] + + if choice: + if (characteristic.dtype == CATEGORIAL_TYPE or characteristic.dtype == BOOLEAN_TYPE): + if not choice in characteristic.choices: + msg = f"{choice} is not part of {characteristic.choices} for {characteristic.value}" + raise ValidationError(msg) + + #if any(k in fields_require_unit for k in data.keys()): + elif characteristic.dtype == NUMERIC_TYPE: + if not unit in characteristic.units: + msg = f"{unit} is not allowed but required. For {characteristic.value} allowed units are {characteristic.units}" + raise ValidationError(msg) + + + + return super(CharacteristicaSerializer, self).to_internal_value(data) diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index 88acb280..fa0c7b56 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -5,6 +5,8 @@ from django.contrib import admin from rest_framework.routers import DefaultRouter from rest_framework_swagger.views import get_swagger_view +from django.conf import settings +from django.conf.urls import include, url from .interventions.views import SubstancesViewSet from .users.views import UserViewSet, UserCreateViewSet @@ -46,3 +48,9 @@ #re_path(r'^$', RedirectView.as_view(url=reverse_lazy('api-root'), permanent=False)), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + +if settings.DEBUG: + import debug_toolbar + urlpatterns = [ + url(r'^__debug__/', include(debug_toolbar.urls)), + ] + urlpatterns \ No newline at end of file diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index 57d1c551..7c1f0e29 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -1,5 +1,6 @@ import os +from django.core.exceptions import ValidationError CHAR_MAX_LENGTH = 30 @@ -25,3 +26,16 @@ def ensure_dir(file_path): directory = os.path.dirname(file_path) if not os.path.exists(directory): os.makedirs(directory) + + +def update_or_create_multiple(parent,children,related_name): + for child in children: + instance_cild = getattr(parent,related_name) + instance_cild.update_or_create(**child) + +def get_or_val_error(model, *args, **kwargs): + try: + return model.objects.get(*args, **kwargs) + except model.DoesNotExist: + msg = f"{model} instance with args:{args}, kwargs:{kwargs} does not exist" + return ValidationError(msg) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 5756f2af..0c056902 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,6 +25,7 @@ ipdb==0.11 ipython==6.4.0 mkdocs==0.17.4 flake8==3.5.0 +django-debug-toolbar # Testing mock==2.0.0 @@ -46,4 +47,5 @@ ipykernel pandas jsonschema django-extra-fields -PyPDF2 \ No newline at end of file +PyPDF2 +lark-parser \ No newline at end of file From 7d09eebd1f87fefc474fe95a7b7fde346d301ef0 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 10 Aug 2018 12:33:35 +0200 Subject: [PATCH 040/115] cleaning and representation --- pkdb_app/categoricals.py | 12 ++++---- pkdb_app/config/common.py | 2 +- pkdb_app/data_management/fill_database.py | 2 +- pkdb_app/interventions/serializers.py | 34 ++++++++--------------- pkdb_app/serializers.py | 7 +++-- pkdb_app/studies/serializers.py | 4 +-- pkdb_app/subjects/serializers.py | 23 ++++++++++----- pkdb_app/utils.py | 12 +++++++- 8 files changed, 55 insertions(+), 41 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 7038ec93..d815b237 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -86,8 +86,9 @@ def create_choices(list): STRING_TYPE = "string" # can be a free string, no limitations compared to categorial YES = "Y" NO = 'N' -M = "Mixed" -BOOLEAN_CHOICES = [YES, NO, M] +MIX = "Mixed" +NAN = "NAN" +BOOLEAN_CHOICES = [YES, NO, MIX,NAN] INTERVENTION_ROUTE = [ "oral", @@ -107,6 +108,7 @@ def create_choices(list): "2 100mg NO-DOZ tablets", "capsules", "2 capsules", + NAN, ] INTERVENTION_FORM_CHOICES = create_choices(INTERVENTION_FORM) @@ -192,13 +194,13 @@ def create_choices(list): CharacteristicType('kidney weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), CharacteristicType('age', DEMOGRAPHICS, NUMERIC_TYPE, None, ["yr"]), - CharacteristicType('sex', DEMOGRAPHICS, CATEGORIAL_TYPE, ["M", "F", "Mixed"], ["-"]), - CharacteristicType('ethnicity', DEMOGRAPHICS, CATEGORIAL_TYPE, ["african", "afroamerican", "asian", "caucasian"], ["-"]), + CharacteristicType('sex', DEMOGRAPHICS, CATEGORIAL_TYPE, ["M", "F", MIX,NAN], ["-"]), + CharacteristicType('ethnicity', DEMOGRAPHICS, CATEGORIAL_TYPE, ["african", "afroamerican", "asian", "caucasian",NAN], ["-"]), # Disease (status) CharacteristicType('healthy', "health status", BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('disease', "disease", CATEGORIAL_TYPE, ["cirrhosis","plasmodium falciparum","alcoholic liver cirrhosis","cirrhotic liver disease","PBC","miscellaneous liver disease","schizophrenia"], ["-"]), + CharacteristicType('disease', "disease", CATEGORIAL_TYPE, [NAN,"cirrhosis","plasmodium falciparum","alcoholic liver cirrhosis","cirrhotic liver disease","PBC","miscellaneous liver disease","schizophrenia"], ["-"]), # Lifestyle diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index fd883d51..2d759c03 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -51,7 +51,7 @@ class Common(Configuration): DEBUG_TOOLBAR_PATCH_SETTINGS = False - INTERNAL_IPS = ('172.19.0.1',) + INTERNAL_IPS = ('172.18.0.1',) ALLOWED_HOSTS = ["*"] ROOT_URLCONF = 'pkdb_app.urls' diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index b9710389..5f1a3184 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -127,6 +127,6 @@ def get_services(**options): parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: - #bonobo.run(get_graph_references(**options), services=get_services(**options)) + bonobo.run(get_graph_references(**options), services=get_services(**options)) bonobo.run(get_graph_study(**options), services=get_services(**options)) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index e38c35b5..64190364 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -1,12 +1,10 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db.models import Q from rest_framework import serializers - -from pkdb_app.behaviours import Sourceable, Valueable, ValueableMap from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet, Timecourse from pkdb_app.serializers import ParserSerializer -from pkdb_app.subjects.models import IndividualSet, Individual, Group -from pkdb_app.subjects.serializers import GroupSRField +from pkdb_app.subjects.models import Individual, Group +from pkdb_app.utils import un_map class SubstanceSerializer(serializers.ModelSerializer): @@ -39,11 +37,15 @@ def to_internal_value(self, data): data = self.strip(data) return super().to_internal_value(data) + def to_representation(self, instance): + rep = super().to_representation(instance) + return un_map(rep) + + class InterventionSetSerializer(ParserSerializer): interventions = InterventionSerializer(many=True , read_only=False,required=False, allow_null=True) - class Meta: model = InterventionSet fields = ["description","interventions"] @@ -55,18 +57,13 @@ def to_internal_value(self, data): :return: """ data = self.generic_parser(data,"interventions") - #data = self.split_to_map(data) - #data = self.drop_blank(data) - #data = self.strip(data) return super(InterventionSetSerializer, self).to_internal_value(data) class OutputSerializer(ParserSerializer): group = serializers.PrimaryKeyRelatedField(queryset=Group.objects.all(), read_only=False,required=False, allow_null=True) individual = serializers.PrimaryKeyRelatedField(queryset=Individual.objects.all(), read_only=False, required=False, allow_null=True) - #intervention = serializers.PrimaryKeyRelatedField(queryset=Intervention.objects.all(),read_only=False,required=False, allow_null=True) interventions = serializers.PrimaryKeyRelatedField(queryset=Intervention.objects.all(),many=True, read_only=False,required=False, allow_null=True) - substance = serializers.SlugRelatedField(slug_field="name",queryset=Substance.objects.all(),read_only=False,required=False, allow_null=True) class Meta: @@ -78,17 +75,8 @@ class Meta: "time_map","group","group_map", "individual", "individual_map", "interventions", "interventions_map", "substance","substance_map","tissue", "tissue_map"] - def to_internal_value(self, data): - """ - :param data: - :return: - """ - - - #data = self.strip(data) - #data = self.generic_parser(data, "outputs") study_sid = self.context['request'].path.split("/")[-2] data = self.split_to_map(data) @@ -130,7 +118,7 @@ def to_representation(self, instance): rep["group"] = instance.group.name if "interventions" in rep: rep["interventions"] = [intervention.name for intervention in instance.interventions.all()] - return rep + return un_map(rep) class TimecourseSerializer(OutputSerializer): @@ -146,19 +134,21 @@ class Meta: "interventions_map", "substance", "substance_map", "tissue", "tissue_map"] + def to_representation(self, instance): + rep = super().to_representation(instance) + return un_map(rep) + class OutputSetSerializer(ParserSerializer): outputs = OutputSerializer(many=True, read_only=False, required=False, allow_null=True) timecourse = TimecourseSerializer(many=True, read_only=False, required=False, allow_null=True) - class Meta: model = OutputSet fields = ["description","outputs","timecourse"] def to_internal_value(self, data): """ - :param data: :return: """ diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 6084a0e4..2a4073ae 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -43,11 +43,14 @@ def is_valid(self, raise_exception=False): return super().is_valid(raise_exception) - - def to_representation(self, instance): + """ + def to_representation(self, instance): result = super().to_representation(instance) return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + + """ + @staticmethod def create_relations(study, related): for name,model in RELATED_SETS.items(): diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 208a8451..7ae1e06c 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -57,8 +57,8 @@ class StudySerializer(BaseSerializer): class Meta: model = Study - fields = ('sid','name',"creator","pkdb_version","design",'reference',"curators", - "groupset", "interventionset","individualset","outputset","substances") + fields = ('sid',"pkdb_version","creator",'name',"design",'reference',"curators","substances", + "groupset","individualset","interventionset","outputset") def create(self, validated_data): related = self.pop_relations(validated_data) diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index a3be2acd..1bd211c2 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -4,6 +4,7 @@ from pkdb_app.behaviours import Sourceable from pkdb_app.categoricals import FORMAT_MAPPING, CHARACTERISTIC_DICT, CATEGORIAL_TYPE, NUMERIC_TYPE, BOOLEAN_TYPE +from pkdb_app.utils import un_map from .models import Group, GroupSet,Individual,IndividualSet,Characteristica from ..serializers import ParserSerializer @@ -24,7 +25,15 @@ class Meta: def to_representation(self, instance): result = super().to_representation(instance) - return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + if result["ctype"] == "group": + result.pop("ctype") + + return un_map(result) + + + + + def to_internal_value(self, data): """ @@ -36,8 +45,7 @@ def to_internal_value(self, data): characteristic = CHARACTERISTIC_DICT[data.get("category")] choice = data.get("choice",None) unit = data.get("unit",None) - - fields_require_unit = ["value","mean","median","min","max","sd","se","cv","value_map","mean_map","median_map","min_map","max_map","sd_map","se_map","cv_map"] + #fields_require_unit = ["value","mean","median","min","max","sd","se","cv","value_map","mean_map","median_map","min_map","max_map","sd_map","se_map","cv_map"] if choice: if (characteristic.dtype == CATEGORIAL_TYPE or characteristic.dtype == BOOLEAN_TYPE): @@ -53,7 +61,6 @@ def to_internal_value(self, data): - return super(CharacteristicaSerializer, self).to_internal_value(data) @@ -128,7 +135,8 @@ def to_representation(self, instance): if "group" in rep: rep["group"] = instance.group.name - return rep + + return un_map(rep) def parse_individuals(self,data): try: @@ -148,7 +156,6 @@ def parse_individuals(self,data): data = unpacked_individuals - except KeyError: pass return data @@ -173,4 +180,6 @@ def to_internal_value(self, data): return super(IndividualSetSerializer, self).to_internal_value(data) - + def to_representation(self, instance): + rep = super().to_representation(instance) + return un_map(rep) \ No newline at end of file diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index 7c1f0e29..fc47a3c3 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -38,4 +38,14 @@ def get_or_val_error(model, *args, **kwargs): return model.objects.get(*args, **kwargs) except model.DoesNotExist: msg = f"{model} instance with args:{args}, kwargs:{kwargs} does not exist" - return ValidationError(msg) \ No newline at end of file + return ValidationError(msg) + +def un_map(data): + cleaned_result = {} + for k, v in data.items(): + if "_map" in k: + k = k[:-4] + if v is None: + continue + cleaned_result[k] = v + return cleaned_result \ No newline at end of file From 34c91782d87b94b269eb3aa42aa3ebd957ff2c97 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 10 Aug 2018 18:36:47 +0200 Subject: [PATCH 041/115] added references of paracetamol and started with vue.js as frontend --- frontend/.babelrc | 17 + frontend/.editorconfig | 9 + frontend/.eslintignore | 4 + frontend/.eslintrc.js | 29 + frontend/.gitignore | 16 + frontend/.postcssrc.js | 10 + frontend/README.md | 27 + frontend/config/dev.env.js | 7 + frontend/config/index.js | 76 + frontend/config/prod.env.js | 4 + frontend/config/test.env.js | 7 + frontend/index.html | 12 + frontend/package-lock.json | 12791 ++++++++++++++++ frontend/package.json | 80 + frontend/src/App.vue | 23 + frontend/src/assets/logo.png | Bin 0 -> 6849 bytes frontend/src/main.js | 15 + frontend/src/router/index.js | 15 + frontend/static/.gitkeep | 0 .../e2e/custom-assertions/elementCount.js | 27 + frontend/test/e2e/nightwatch.conf.js | 46 + frontend/test/e2e/runner.js | 48 + frontend/test/e2e/specs/test.js | 19 + pkdb_app/categoricals.py | 9 +- pkdb_app/data_management/add_groups.py | 2 +- pkdb_app/data_management/add_intervention.py | 4 +- pkdb_app/data_management/add_output.py | 2 +- .../create_reference_acetaminophen.py | 175 + ...erence.py => create_reference_caffeine.py} | 21 +- pkdb_app/data_management/fill_database.py | 2 +- pkdb_app/data_management/initialize_study.py | 2 +- pkdb_app/interventions/models.py | 8 +- pkdb_app/interventions/serializers.py | 9 +- pkdb_app/subjects/managers.py | 8 +- pkdb_app/subjects/models.py | 28 - pkdb_app/subjects/serializers.py | 161 +- pkdb_app/utils.py | 23 + 37 files changed, 13567 insertions(+), 169 deletions(-) create mode 100644 frontend/.babelrc create mode 100644 frontend/.editorconfig create mode 100644 frontend/.eslintignore create mode 100644 frontend/.eslintrc.js create mode 100644 frontend/.gitignore create mode 100644 frontend/.postcssrc.js create mode 100644 frontend/README.md create mode 100644 frontend/config/dev.env.js create mode 100644 frontend/config/index.js create mode 100644 frontend/config/prod.env.js create mode 100644 frontend/config/test.env.js create mode 100644 frontend/index.html create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/src/App.vue create mode 100644 frontend/src/assets/logo.png create mode 100644 frontend/src/main.js create mode 100644 frontend/src/router/index.js create mode 100644 frontend/static/.gitkeep create mode 100644 frontend/test/e2e/custom-assertions/elementCount.js create mode 100644 frontend/test/e2e/nightwatch.conf.js create mode 100644 frontend/test/e2e/runner.js create mode 100644 frontend/test/e2e/specs/test.js create mode 100644 pkdb_app/data_management/create_reference_acetaminophen.py rename pkdb_app/data_management/{create_reference.py => create_reference_caffeine.py} (86%) diff --git a/frontend/.babelrc b/frontend/.babelrc new file mode 100644 index 00000000..d530c00f --- /dev/null +++ b/frontend/.babelrc @@ -0,0 +1,17 @@ +{ + "presets": [ + ["env", { + "modules": false, + "targets": { + "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] + } + }], + "stage-2" + ], + "plugins": ["transform-vue-jsx", "transform-runtime"], + "env": { + "test": { + "presets": ["env", "stage-2"] + } + } +} diff --git a/frontend/.editorconfig b/frontend/.editorconfig new file mode 100644 index 00000000..9d08a1a8 --- /dev/null +++ b/frontend/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/frontend/.eslintignore b/frontend/.eslintignore new file mode 100644 index 00000000..e1fcc9c4 --- /dev/null +++ b/frontend/.eslintignore @@ -0,0 +1,4 @@ +/build/ +/config/ +/dist/ +/*.js diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js new file mode 100644 index 00000000..22fdce86 --- /dev/null +++ b/frontend/.eslintrc.js @@ -0,0 +1,29 @@ +// https://eslint.org/docs/user-guide/configuring + +module.exports = { + root: true, + parserOptions: { + parser: 'babel-eslint' + }, + env: { + browser: true, + }, + extends: [ + // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention + // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. + 'plugin:vue/essential', + // https://github.com/standard/standard/blob/master/docs/RULES-en.md + 'standard' + ], + // required to lint *.vue files + plugins: [ + 'vue' + ], + // add your custom rules here + rules: { + // allow async-await + 'generator-star-spacing': 'off', + // allow debugger during development + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' + } +} diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 00000000..e82290f5 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,16 @@ +.DS_Store +node_modules/ +/dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +/test/e2e/reports/ +selenium-debug.log + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln diff --git a/frontend/.postcssrc.js b/frontend/.postcssrc.js new file mode 100644 index 00000000..eee3e92d --- /dev/null +++ b/frontend/.postcssrc.js @@ -0,0 +1,10 @@ +// https://github.com/michael-ciniawsky/postcss-load-config + +module.exports = { + "plugins": { + "postcss-import": {}, + "postcss-url": {}, + // to edit target browsers: use "browserslist" field in package.json + "autoprefixer": {} + } +} diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 00000000..4d2ca44a --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,27 @@ +# frontend + +> pkdb: pharmacokinetical data + +## Build Setup + +``` bash +# install dependencies +npm install + +# serve with hot reload at localhost:8080 +npm run dev + +# build for production with minification +npm run build + +# build for production and view the bundle analyzer report +npm run build --report + +# run e2e tests +npm run e2e + +# run all tests +npm test +``` + +For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). diff --git a/frontend/config/dev.env.js b/frontend/config/dev.env.js new file mode 100644 index 00000000..1e22973a --- /dev/null +++ b/frontend/config/dev.env.js @@ -0,0 +1,7 @@ +'use strict' +const merge = require('webpack-merge') +const prodEnv = require('./prod.env') + +module.exports = merge(prodEnv, { + NODE_ENV: '"development"' +}) diff --git a/frontend/config/index.js b/frontend/config/index.js new file mode 100644 index 00000000..926ab364 --- /dev/null +++ b/frontend/config/index.js @@ -0,0 +1,76 @@ +'use strict' +// Template version: 1.3.1 +// see http://vuejs-templates.github.io/webpack for documentation. + +const path = require('path') + +module.exports = { + dev: { + + // Paths + assetsSubDirectory: 'static', + assetsPublicPath: '/', + proxyTable: {}, + + // Various Dev Server settings + host: 'localhost', // can be overwritten by process.env.HOST + port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined + autoOpenBrowser: false, + errorOverlay: true, + notifyOnErrors: true, + poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- + + // Use Eslint Loader? + // If true, your code will be linted during bundling and + // linting errors and warnings will be shown in the console. + useEslint: true, + // If true, eslint errors and warnings will also be shown in the error overlay + // in the browser. + showEslintErrorsInOverlay: false, + + /** + * Source Maps + */ + + // https://webpack.js.org/configuration/devtool/#development + devtool: 'cheap-module-eval-source-map', + + // If you have problems debugging vue-files in devtools, + // set this to false - it *may* help + // https://vue-loader.vuejs.org/en/options.html#cachebusting + cacheBusting: true, + + cssSourceMap: true + }, + + build: { + // Template for index.html + index: path.resolve(__dirname, '../dist/index.html'), + + // Paths + assetsRoot: path.resolve(__dirname, '../dist'), + assetsSubDirectory: 'static', + assetsPublicPath: '/', + + /** + * Source Maps + */ + + productionSourceMap: true, + // https://webpack.js.org/configuration/devtool/#production + devtool: '#source-map', + + // Gzip off by default as many popular static hosts such as + // Surge or Netlify already gzip all static assets for you. + // Before setting to `true`, make sure to: + // npm install --save-dev compression-webpack-plugin + productionGzip: false, + productionGzipExtensions: ['js', 'css'], + + // Run the build command with an extra argument to + // View the bundle analyzer report after build finishes: + // `npm run build --report` + // Set to `true` or `false` to always turn it on or off + bundleAnalyzerReport: process.env.npm_config_report + } +} diff --git a/frontend/config/prod.env.js b/frontend/config/prod.env.js new file mode 100644 index 00000000..a6f99761 --- /dev/null +++ b/frontend/config/prod.env.js @@ -0,0 +1,4 @@ +'use strict' +module.exports = { + NODE_ENV: '"production"' +} diff --git a/frontend/config/test.env.js b/frontend/config/test.env.js new file mode 100644 index 00000000..c2824a30 --- /dev/null +++ b/frontend/config/test.env.js @@ -0,0 +1,7 @@ +'use strict' +const merge = require('webpack-merge') +const devEnv = require('./dev.env') + +module.exports = merge(devEnv, { + NODE_ENV: '"testing"' +}) diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 00000000..12bce148 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,12 @@ + + + + + + frontend + + +
+ + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 00000000..b44f7e8f --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,12791 @@ +{ + "name": "frontend", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", + "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "dev": true, + "requires": { + "@babel/highlight": "7.0.0-beta.44" + } + }, + "@babel/generator": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz", + "integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.44", + "jsesc": "^2.5.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", + "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz", + "integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "7.0.0-beta.44", + "@babel/template": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz", + "integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz", + "integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", + "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "@babel/template": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz", + "integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "lodash": "^4.2.0" + }, + "dependencies": { + "babylon": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", + "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==", + "dev": true + } + } + }, + "@babel/traverse": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz", + "integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/generator": "7.0.0-beta.44", + "@babel/helper-function-name": "7.0.0-beta.44", + "@babel/helper-split-export-declaration": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "debug": "^3.1.0", + "globals": "^11.1.0", + "invariant": "^2.2.0", + "lodash": "^4.2.0" + }, + "dependencies": { + "babylon": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", + "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz", + "integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", + "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", + "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", + "dev": true, + "requires": { + "acorn": "^4.0.3" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "agent-base": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "dev": true, + "requires": { + "extend": "~3.0.0", + "semver": "~5.0.1" + }, + "dependencies": { + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "dev": true + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assertion-error": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz", + "integrity": "sha1-x/hUOP3UZrx8oWq5DIFRN5el0js=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types": { + "version": "0.11.5", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.5.tgz", + "integrity": "sha512-oJjo+5e7/vEc2FBK8gUalV0pba4L3VdBIs2EKhOLHLcOd2FgQIVQN9xb0eZ9IjEWyAL7vq6fGJxOvVvdCHNyMw==", + "dev": true + }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", + "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "dev": true + }, + "autoprefixer": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", + "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", + "dev": true, + "requires": { + "browserslist": "^2.11.3", + "caniuse-lite": "^1.0.30000805", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^6.0.17", + "postcss-value-parser": "^3.2.3" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-eslint": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz", + "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/traverse": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "^1.0.0" + }, + "dependencies": { + "babylon": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", + "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-helper-bindify-decorators": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", + "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "dev": true, + "requires": { + "babel-helper-explode-assignable-expression": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-explode-class": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz", + "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=", + "dev": true, + "requires": { + "babel-helper-bindify-decorators": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-vue-jsx-merge-props": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", + "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==", + "dev": true + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-loader": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", + "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==", + "dev": true, + "requires": { + "find-cache-dir": "^1.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "dev": true + }, + "babel-plugin-syntax-async-generators": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", + "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", + "dev": true + }, + "babel-plugin-syntax-class-properties": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", + "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", + "dev": true + }, + "babel-plugin-syntax-decorators": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", + "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", + "dev": true + }, + "babel-plugin-syntax-dynamic-import": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", + "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", + "dev": true + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "dev": true + }, + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", + "dev": true + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "dev": true + }, + "babel-plugin-transform-async-generator-functions": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz", + "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-generators": "^6.5.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-functions": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-class-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", + "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-plugin-syntax-class-properties": "^6.8.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-decorators": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz", + "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=", + "dev": true, + "requires": { + "babel-helper-explode-class": "^6.24.1", + "babel-plugin-syntax-decorators": "^6.13.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "dev": true, + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", + "babel-plugin-syntax-exponentiation-operator": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "^0.10.0" + } + }, + "babel-plugin-transform-runtime": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz", + "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-vue-jsx": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-3.7.0.tgz", + "integrity": "sha512-W39X07/n3oJMQd8tALBO+440NraGSF//Lo1ydd/9Nme3+QiRGFBb1Q39T9iixh0jZPPbfv3so18tNoIgLatymw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "babel-preset-env": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", + "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-to-generator": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", + "babel-plugin-transform-es2015-for-of": "^6.23.0", + "babel-plugin-transform-es2015-function-name": "^6.22.0", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-umd": "^6.23.0", + "babel-plugin-transform-es2015-object-super": "^6.22.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", + "babel-plugin-transform-exponentiation-operator": "^6.22.0", + "babel-plugin-transform-regenerator": "^6.22.0", + "browserslist": "^3.2.6", + "invariant": "^2.2.2", + "semver": "^5.3.0" + }, + "dependencies": { + "browserslist": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" + } + } + } + }, + "babel-preset-stage-2": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", + "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=", + "dev": true, + "requires": { + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "babel-plugin-transform-class-properties": "^6.24.1", + "babel-plugin-transform-decorators": "^6.24.1", + "babel-preset-stage-3": "^6.24.1" + } + }, + "babel-preset-stage-3": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz", + "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=", + "dev": true, + "requires": { + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-generator-functions": "^6.24.1", + "babel-plugin-transform-async-to-generator": "^6.24.1", + "babel-plugin-transform-exponentiation-operator": "^6.24.1", + "babel-plugin-transform-object-rest-spread": "^6.22.0" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bfj-node4": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/bfj-node4/-/bfj-node4-5.3.1.tgz", + "integrity": "sha512-SOmOsowQWfXc7ybFARsK3C4MCOWzERaOMV/Fl3Tgjs+5dJWyzo3oa127jL44eMbQiAN17J7SvAs2TRxEScTUmg==", + "dev": true, + "requires": { + "bluebird": "^3.5.1", + "check-types": "^7.3.0", + "tryer": "^1.0.0" + } + }, + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "binary-extensions": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "dev": true + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.1", + "http-errors": "~1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "~2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "~1.6.15" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", + "dev": true + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "dev": true, + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": ">= 1.3.1 < 2" + } + } + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + }, + "dependencies": { + "array-flatten": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz", + "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=", + "dev": true + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", + "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000792", + "electron-to-chromium": "^1.3.30" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cacache": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", + "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "dev": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "^0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + } + } + }, + "caniuse-api": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz", + "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=", + "dev": true, + "requires": { + "browserslist": "^1.3.6", + "caniuse-db": "^1.0.30000529", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + }, + "dependencies": { + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "^1.0.30000639", + "electron-to-chromium": "^1.2.7" + } + } + } + }, + "caniuse-db": { + "version": "1.0.30000876", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000876.tgz", + "integrity": "sha512-HJRyA+FjkMz8ir9q0STdq50HpzYQjGFhasZZA67y5rd6CfOI3O7PZxe6IXcx8bZhMbvugkO30WyPq5QewmE8KQ==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30000874", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000874.tgz", + "integrity": "sha512-29nr1EPiHwrJTAHHsEmTt2h+55L8j2GNFdAcYPlRy2NX6iFz7ZZiepVI7kP/QqlnHLq3KvfWpbmGa0d063U09w==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chai-nightwatch": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/chai-nightwatch/-/chai-nightwatch-0.1.1.tgz", + "integrity": "sha1-HKVt52jTwIaP5/wvTTLC/olOa+k=", + "dev": true, + "requires": { + "assertion-error": "1.0.0", + "deep-eql": "0.1.3" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "check-types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-7.4.0.tgz", + "integrity": "sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg==", + "dev": true + }, + "chokidar": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", + "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.2.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "lodash.debounce": "^4.0.8", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.5" + } + }, + "chownr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", + "dev": true + }, + "chromedriver": { + "version": "2.41.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.41.0.tgz", + "integrity": "sha512-6O9HxvrSuHqmRlIgMzi0/05GsDNHqs8kaF5gNTIyaZNwRzb/RBUWH1xNNXKNxyhXSnGSalH8hWsKP5mc/npSQQ==", + "dev": true, + "requires": { + "del": "^3.0.0", + "extract-zip": "^1.6.7", + "kew": "^0.7.0", + "mkdirp": "^0.5.1", + "request": "^2.87.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "clap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", + "dev": true, + "requires": { + "chalk": "^1.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.11.tgz", + "integrity": "sha1-Ls3xRaujj1R0DybO/Q/z4D4SXWo=", + "dev": true, + "requires": { + "source-map": "0.5.x" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-spinners": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz", + "integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==", + "dev": true + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", + "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", + "dev": true, + "requires": { + "q": "^1.1.2" + } + }, + "coalescy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/coalescy/-/coalescy-1.0.0.tgz", + "integrity": "sha1-SwZYRrg2NhrabEtKSr9LwcrDG/E=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", + "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", + "dev": true, + "requires": { + "clone": "^1.0.2", + "color-convert": "^1.3.0", + "color-string": "^0.3.0" + } + }, + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "dev": true, + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", + "dev": true + }, + "color-string": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", + "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", + "dev": true, + "requires": { + "color-name": "^1.0.0" + } + }, + "colormin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", + "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=", + "dev": true, + "requires": { + "color": "^0.11.0", + "css-color-names": "0.0.4", + "has": "^1.0.1" + } + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", + "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "compressible": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz", + "integrity": "sha1-MmxfUH+7BV9UEWeCuWmoG2einac=", + "dev": true, + "requires": { + "mime-db": ">= 1.34.0 < 2" + } + }, + "compression": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz", + "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.14", + "debug": "2.6.9", + "on-headers": "~1.0.1", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "connect-history-api-fallback": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "consolidate": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz", + "integrity": "sha1-WiUEe8dvcwcmZ8jLUsmJiI9JTGM=", + "dev": true, + "requires": { + "bluebird": "^3.1.1" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", + "dev": true + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-webpack-plugin": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.5.2.tgz", + "integrity": "sha512-zmC33E8FFSq3AbflTvqvPvBo621H36Afsxlui91d+QyZxPIuXghfnTsa1CuqiAaCPgJoSUWfTFbKJnadZpKEbQ==", + "dev": true, + "requires": { + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "globby": "^7.1.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "minimatch": "^3.0.4", + "p-limit": "^1.0.0", + "serialize-javascript": "^1.4.0" + }, + "dependencies": { + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + } + } + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cosmiconfig": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz", + "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0", + "require-from-string": "^2.0.1" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + } + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-loader": { + "version": "0.28.11", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.11.tgz", + "integrity": "sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "css-selector-tokenizer": "^0.7.0", + "cssnano": "^3.10.0", + "icss-utils": "^2.1.0", + "loader-utils": "^1.0.2", + "lodash.camelcase": "^4.3.0", + "object-assign": "^4.1.1", + "postcss": "^5.0.6", + "postcss-modules-extract-imports": "^1.2.0", + "postcss-modules-local-by-default": "^1.2.0", + "postcss-modules-scope": "^1.1.0", + "postcss-modules-values": "^1.3.0", + "postcss-value-parser": "^3.3.0", + "source-list-map": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-selector-tokenizer": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz", + "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + }, + "dependencies": { + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + } + } + }, + "css-what": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "dev": true + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cssnano": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", + "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", + "dev": true, + "requires": { + "autoprefixer": "^6.3.1", + "decamelize": "^1.1.2", + "defined": "^1.0.0", + "has": "^1.0.1", + "object-assign": "^4.0.1", + "postcss": "^5.0.14", + "postcss-calc": "^5.2.0", + "postcss-colormin": "^2.1.8", + "postcss-convert-values": "^2.3.4", + "postcss-discard-comments": "^2.0.4", + "postcss-discard-duplicates": "^2.0.1", + "postcss-discard-empty": "^2.0.1", + "postcss-discard-overridden": "^0.1.1", + "postcss-discard-unused": "^2.2.1", + "postcss-filter-plugins": "^2.0.0", + "postcss-merge-idents": "^2.1.5", + "postcss-merge-longhand": "^2.0.1", + "postcss-merge-rules": "^2.0.3", + "postcss-minify-font-values": "^1.0.2", + "postcss-minify-gradients": "^1.0.1", + "postcss-minify-params": "^1.0.4", + "postcss-minify-selectors": "^2.0.4", + "postcss-normalize-charset": "^1.1.0", + "postcss-normalize-url": "^3.0.7", + "postcss-ordered-values": "^2.1.0", + "postcss-reduce-idents": "^2.2.2", + "postcss-reduce-initial": "^1.0.0", + "postcss-reduce-transforms": "^1.0.3", + "postcss-svgo": "^2.1.1", + "postcss-unique-selectors": "^2.0.2", + "postcss-value-parser": "^3.2.3", + "postcss-zindex": "^2.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "autoprefixer": { + "version": "6.7.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", + "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", + "dev": true, + "requires": { + "browserslist": "^1.7.6", + "caniuse-db": "^1.0.30000634", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^5.2.16", + "postcss-value-parser": "^3.2.3" + } + }, + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "^1.0.30000639", + "electron-to-chromium": "^1.2.7" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "csso": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", + "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", + "dev": true, + "requires": { + "clap": "^1.0.9", + "source-map": "^0.5.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cyclist": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "^0.10.9" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-uri-to-buffer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", + "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", + "dev": true + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "requires": { + "type-detect": "0.1.1" + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "^2.0.5", + "object-keys": "^1.0.8" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "degenerator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", + "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "dev": true, + "requires": { + "ast-types": "0.x.x", + "escodegen": "1.x.x", + "esprima": "3.x.x" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + } + } + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "detect-node": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", + "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=", + "dev": true + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + } + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-converter": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz", + "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=", + "dev": true, + "requires": { + "utila": "~0.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "~1.1.1", + "entities": "~1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", + "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "duplexify": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", + "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz", + "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.57.tgz", + "integrity": "sha512-YYpZlr6mzR8cK5VRmTZydEt5Mp+WMg1/syrO40PoQzl76vJ+oQchL2d3FmEcWzw3FYqJVYJP/kYYSzTa7FLXwg==", + "dev": true + }, + "elliptic": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", + "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "object-assign": "^4.0.1", + "tapable": "^0.2.7" + } + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.2.tgz", + "integrity": "sha512-E1fPutRDdIj/hohG0UpT5mayXNCxXP9d+snxFsPU9X0XgccOumKraa3juDMwTUyi7+Bu5+mCGagjg4IYeNbOdw==", + "dev": true, + "requires": { + "stackframe": "^1.0.4" + } + }, + "es-abstract": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "^1.1.1", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.1" + } + }, + "es5-ext": { + "version": "0.10.45", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz", + "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "1" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", + "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + } + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "eslint-config-standard": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", + "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "dev": true + }, + "eslint-friendly-formatter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-friendly-formatter/-/eslint-friendly-formatter-3.0.0.tgz", + "integrity": "sha1-J4h0Q1psRuwdlPoLH/SU4w7wQpA=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "coalescy": "1.0.0", + "extend": "^3.0.0", + "minimist": "^1.2.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + } + }, + "eslint-loader": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-1.9.0.tgz", + "integrity": "sha512-40aN976qSNPyb9ejTqjEthZITpls1SVKtwguahmH1dzGCwQU/vySE+xX33VZmD8csU0ahVNCtFlsPgKqRBiqgg==", + "dev": true, + "requires": { + "loader-fs-cache": "^1.0.0", + "loader-utils": "^1.0.2", + "object-assign": "^4.0.1", + "object-hash": "^1.1.4", + "rimraf": "^2.6.1" + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", + "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", + "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", + "dev": true, + "requires": { + "contains-path": "^0.1.0", + "debug": "^2.6.8", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.1", + "eslint-module-utils": "^2.2.0", + "has": "^1.0.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.3", + "read-pkg-up": "^2.0.0", + "resolve": "^1.6.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + } + } + }, + "eslint-plugin-node": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz", + "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==", + "dev": true, + "requires": { + "ignore": "^3.3.6", + "minimatch": "^3.0.4", + "resolve": "^1.3.3", + "semver": "5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz", + "integrity": "sha512-JiFL9UFR15NKpHyGii1ZcvmtIqa3UTwiDAGb8atSffe43qJ3+1czVGN6UtkklpcJ2DVnqvTMzEKRaJdBkAL2aQ==", + "dev": true + }, + "eslint-plugin-standard": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz", + "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==", + "dev": true + }, + "eslint-plugin-vue": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-4.7.1.tgz", + "integrity": "sha512-esETKhVMI7Vdli70Wt4bvAwnZBJeM0pxVX9Yb0wWKxdCJc2EADalVYK/q2FzMw8oKN0wPMdqVCKS8kmR89recA==", + "dev": true, + "requires": { + "vue-eslint-parser": "^2.0.3" + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "dev": true + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "eventsource": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", + "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", + "dev": true, + "requires": { + "original": ">=0.0.5" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "express": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.3", + "qs": "6.5.1", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "extract-text-webpack-plugin": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz", + "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", + "dev": true, + "requires": { + "async": "^2.4.1", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0", + "webpack-sources": "^1.0.1" + } + }, + "extract-zip": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", + "dev": true, + "requires": { + "concat-stream": "1.6.2", + "debug": "2.6.9", + "mkdirp": "0.5.1", + "yauzl": "2.4.1" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastparse": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", + "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "file-loader": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", + "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^0.4.5" + }, + "dependencies": { + "ajv": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.1" + } + }, + "ajv-keywords": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" + }, + "dependencies": { + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "flush-write-stream": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", + "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "follow-redirects": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.2.tgz", + "integrity": "sha512-kssLorP/9acIdpQ2udQVTiCS5LQmdEz9mvdIfDcl1gYX2tPKFADHSyFdvJS040XdFsPzemWtgI3q8mFVCxtX8A==", + "dev": true, + "requires": { + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "friendly-errors-webpack-plugin": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0.tgz", + "integrity": "sha512-K27M3VK30wVoOarP651zDmb93R9zF28usW4ocaK3mfQeIEI5BPht/EzZs5E8QLLwbLRJQMwscAjDxYPb1FuNiw==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "error-stack-parser": "^2.0.0", + "string-width": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", + "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.21", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "^2.1.0" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.1.10", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true, + "dev": true + } + } + }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-uri": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.2.tgz", + "integrity": "sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw==", + "dev": true, + "requires": { + "data-uri-to-buffer": "1", + "debug": "2", + "extend": "3", + "file-uri-to-path": "1", + "ftp": "~0.3.10", + "readable-stream": "2" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "gzip-size": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-4.1.0.tgz", + "integrity": "sha1-iuCWJX6r59acRb4rZ8RIEk/7UXw=", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^3.0.0" + } + }, + "handle-thing": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", + "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "^5.1.0", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", + "dev": true + }, + "hash.js": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", + "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "html-comment-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", + "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", + "dev": true + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "html-minifier": { + "version": "3.5.19", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.19.tgz", + "integrity": "sha512-Qr2JC9nsjK8oCrEmuB430ZIA8YWbF3D5LSjywD75FTuXmeqacwHgIM8wp3vHYzzPbklSjp53RdmDuzR4ub2HzA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.1.x", + "commander": "2.16.x", + "he": "1.1.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + } + }, + "html-webpack-plugin": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz", + "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=", + "dev": true, + "requires": { + "bluebird": "^3.4.7", + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "toposort": "^1.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "htmlparser2": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", + "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", + "dev": true, + "requires": { + "domelementtype": "1", + "domhandler": "2.1", + "domutils": "1.1", + "readable-stream": "1.0" + }, + "dependencies": { + "domutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", + "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "http-parser-js": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz", + "integrity": "sha1-O9bW/ebjFyyTNMOzO2wZPYD+ETc=", + "dev": true + }, + "http-proxy": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "dev": true, + "requires": { + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz", + "integrity": "sha1-zBzjjkU7+YSg93AtLdWcc9CBKEo=", + "dev": true, + "requires": { + "agent-base": "2", + "debug": "2", + "extend": "3" + } + }, + "http-proxy-middleware": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", + "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", + "dev": true, + "requires": { + "http-proxy": "^1.16.2", + "is-glob": "^3.1.0", + "lodash": "^4.17.2", + "micromatch": "^2.3.11" + }, + "dependencies": { + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + } + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true, + "requires": { + "agent-base": "2", + "debug": "2", + "extend": "3" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", + "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", + "dev": true, + "requires": { + "postcss": "^6.0.1" + } + }, + "ieee754": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "import-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", + "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", + "dev": true, + "requires": { + "pkg-dir": "^2.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "internal-ip": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", + "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", + "dev": true, + "requires": { + "meow": "^3.3.0" + } + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.0.1.tgz", + "integrity": "sha1-x+NWzeoiWucbNtcPLnGpK6TkJZA=", + "dev": true + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-svg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", + "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "js-base64": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.8.tgz", + "integrity": "sha512-hm2nYpDrwoO/OzBhdcqs/XGT6XjSuSSCVEpia+Kl2J6x4CYt5hISlVL/AYU1khoDXv0AQVgxtdJySb9gjAn56Q==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^2.6.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-loader": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true + }, + "killable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.0.tgz", + "integrity": "sha1-2ouEvUfeU5WHj5XWTQLyRJ/gXms=", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "last-call-webpack-plugin": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-2.1.2.tgz", + "integrity": "sha512-CZc+m2xZm51J8qSwdODeiiNeqh8CYkKEq6Rw8IkE4i/4yqf2cJhjQPsA6BtAV970ePRNhwEOXhy2U5xc5Jwh9Q==", + "dev": true, + "requires": { + "lodash": "^4.17.4", + "webpack-sources": "^1.0.1" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "loader-fs-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz", + "integrity": "sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=", + "dev": true, + "requires": { + "find-cache-dir": "^0.1.1", + "mkdirp": "0.5.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + } + } + }, + "loader-runner": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", + "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", + "dev": true + }, + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true + }, + "lodash._arraycopy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", + "integrity": "sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE=", + "dev": true + }, + "lodash._arrayeach": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", + "integrity": "sha1-urFWsqkNPxu9XGU0AzSeXlkz754=", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "lodash._baseclone": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", + "integrity": "sha1-MDUZv2OT/n5C802LYw73eU41Qrc=", + "dev": true, + "requires": { + "lodash._arraycopy": "^3.0.0", + "lodash._arrayeach": "^3.0.0", + "lodash._baseassign": "^3.0.0", + "lodash._basefor": "^3.0.0", + "lodash.isarray": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._basefor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", + "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=", + "dev": true + }, + "lodash._bindcallback": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash._stack": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lodash._stack/-/lodash._stack-4.1.3.tgz", + "integrity": "sha1-dRqnbBuWSwR+dtFPxyoJP8teLdA=", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.clone": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-3.0.3.tgz", + "integrity": "sha1-hGiMc9MrWpDKJWFpY/GJJSqZcEM=", + "dev": true, + "requires": { + "lodash._baseclone": "^3.0.0", + "lodash._bindcallback": "^3.0.0", + "lodash._isiterateecall": "^3.0.0" + } + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "^3.0.0", + "lodash._basecreate": "^3.0.0", + "lodash._isiterateecall": "^3.0.0" + } + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "lodash.defaultsdeep": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.3.2.tgz", + "integrity": "sha1-bBpYbmxWR7DmTi15gUG4g2FYvoo=", + "dev": true, + "requires": { + "lodash._baseclone": "^4.0.0", + "lodash._stack": "^4.0.0", + "lodash.isplainobject": "^4.0.0", + "lodash.keysin": "^4.0.0", + "lodash.mergewith": "^4.0.0", + "lodash.rest": "^4.0.0" + }, + "dependencies": { + "lodash._baseclone": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-4.5.7.tgz", + "integrity": "sha1-zkKt4IOE711i+nfDD2GkbmhvhDQ=", + "dev": true + } + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.keysin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-4.2.0.tgz", + "integrity": "sha1-jMP7NcLZSsxEOhhj4C+kB5nqbyg=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.mergewith": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", + "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", + "dev": true + }, + "lodash.rest": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/lodash.rest/-/lodash.rest-4.0.5.tgz", + "integrity": "sha1-lU73UEkmIDjJbR/Jiyj9r58Hcqo=", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "loglevel": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", + "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "math-expression-evaluator": { + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", + "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=", + "dev": true + }, + "math-random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "dev": true + }, + "md5.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "dev": true, + "requires": { + "mime-db": "~1.35.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mississippi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", + "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mkpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mkpath/-/mkpath-1.0.0.tgz", + "integrity": "sha1-67Opd+evHGg65v2hK1Raa6bFhT0=", + "dev": true + }, + "mocha-nightwatch": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/mocha-nightwatch/-/mocha-nightwatch-3.2.2.tgz", + "integrity": "sha1-kby5s73gV912d8eBJeSR5Y1mZHw=", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.5", + "glob": "7.0.5", + "growl": "1.9.2", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "glob": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz", + "integrity": "sha1-tCAqaQmbu00pKnwblbZoK2fr3JU=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "neo-async": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz", + "integrity": "sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA==", + "dev": true + }, + "netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nightwatch": { + "version": "0.9.21", + "resolved": "https://registry.npmjs.org/nightwatch/-/nightwatch-0.9.21.tgz", + "integrity": "sha1-nnlKdRS0/V9GYC02jlBRUjKrnpA=", + "dev": true, + "requires": { + "chai-nightwatch": "~0.1.x", + "ejs": "2.5.7", + "lodash.clone": "3.0.3", + "lodash.defaultsdeep": "4.3.2", + "minimatch": "3.0.3", + "mkpath": "1.0.0", + "mocha-nightwatch": "3.2.2", + "optimist": "0.6.1", + "proxy-agent": "2.0.0", + "q": "1.4.1" + }, + "dependencies": { + "minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + } + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + } + } + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-forge": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", + "dev": true + }, + "node-libs-browser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", + "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^1.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.0", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.10.3", + "vm-browserify": "0.0.4" + } + }, + "node-notifier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz", + "integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "semver": "^5.4.1", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-hash": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.0.tgz", + "integrity": "sha512-05KzQ70lSeGSrZJQXE5wNDiTkBJDlUT/myi6RX9dVIvz7a7Qh4oH93BQdiPMn27nldYvVQCKMUaM83AfizZlsQ==", + "dev": true + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "opener": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", + "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", + "dev": true + }, + "opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-Fjn7wyyadPAriuH2DHamDQw5B8GohEWbroBkKoPeP+vSF2PIAPI7WDihi8WieMRb/At4q7Ea7zTKaMDuSoIAAg==", + "dev": true, + "requires": { + "cssnano": "^3.4.0", + "last-call-webpack-plugin": "^2.1.2" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "ora": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-1.4.0.tgz", + "integrity": "sha512-iMK1DOQxzzh2MBlVsU42G80mnrvUhqsMh74phHtDlrcTZPK0pH6o7l7DRshK+0YsxDyEuaOkziVdvM3T0QTzpw==", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "cli-cursor": "^2.1.0", + "cli-spinners": "^1.0.1", + "log-symbols": "^2.1.0" + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pac-proxy-agent": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz", + "integrity": "sha512-QBELCWyLYPgE2Gj+4wUEiMscHrQ8nRPBzYItQNOHWavwBt25ohZHQC4qnd5IszdVVrFbLsQ+dPkm6eqdjJAmwQ==", + "dev": true, + "requires": { + "agent-base": "2", + "debug": "2", + "extend": "3", + "get-uri": "2", + "http-proxy-agent": "1", + "https-proxy-agent": "1", + "pac-resolver": "~2.0.0", + "raw-body": "2", + "socks-proxy-agent": "2" + } + }, + "pac-resolver": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-2.0.0.tgz", + "integrity": "sha1-mbiNLxk/ve78HJpSnB8yYKtSd80=", + "dev": true, + "requires": { + "co": "~3.0.6", + "degenerator": "~1.0.2", + "ip": "1.0.1", + "netmask": "~1.0.4", + "thunkify": "~2.1.1" + }, + "dependencies": { + "co": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/co/-/co-3.0.6.tgz", + "integrity": "sha1-FEXyJsXrlWE45oyawwFn6n0ua9o=", + "dev": true + } + } + }, + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "dev": true + }, + "parallel-transform": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", + "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "dev": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-asn1": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", + "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pbkdf2": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", + "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "portfinder": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.16.tgz", + "integrity": "sha512-icBXCFQxzlK2PMepOM0QeEdPPFSLAaXXeuKOv5AClJlMy1oVCBrkDGJ12IZYesI/BF8mpeVco3vRCmgeBb4+hw==", + "dev": true, + "requires": { + "async": "^1.5.2", + "debug": "^2.2.0", + "mkdirp": "0.5.x" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "postcss-calc": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", + "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", + "dev": true, + "requires": { + "postcss": "^5.0.2", + "postcss-message-helpers": "^2.0.0", + "reduce-css-calc": "^1.2.6" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-colormin": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", + "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=", + "dev": true, + "requires": { + "colormin": "^1.0.5", + "postcss": "^5.0.13", + "postcss-value-parser": "^3.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-convert-values": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz", + "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", + "dev": true, + "requires": { + "postcss": "^5.0.11", + "postcss-value-parser": "^3.1.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-discard-comments": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", + "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", + "dev": true, + "requires": { + "postcss": "^5.0.14" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-discard-duplicates": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz", + "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", + "dev": true, + "requires": { + "postcss": "^5.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-discard-empty": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", + "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", + "dev": true, + "requires": { + "postcss": "^5.0.14" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-discard-overridden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", + "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", + "dev": true, + "requires": { + "postcss": "^5.0.16" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-discard-unused": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", + "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", + "dev": true, + "requires": { + "postcss": "^5.0.14", + "uniqs": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-filter-plugins": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz", + "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==", + "dev": true, + "requires": { + "postcss": "^5.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-import": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz", + "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", + "dev": true, + "requires": { + "postcss": "^6.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-load-config": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz", + "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", + "dev": true, + "requires": { + "cosmiconfig": "^4.0.0", + "import-cwd": "^2.0.0" + } + }, + "postcss-load-options": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", + "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.0", + "object-assign": "^4.1.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "require-from-string": "^1.1.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "dev": true + } + } + }, + "postcss-load-plugins": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", + "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.1", + "object-assign": "^4.1.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "require-from-string": "^1.1.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "dev": true + } + } + }, + "postcss-loader": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.6.tgz", + "integrity": "sha512-hgiWSc13xVQAq25cVw80CH0l49ZKlAnU1hKPOdRrNj89bokRr/bZF2nT+hebPPF9c9xs8c3gw3Fr2nxtmXYnNg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^6.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^0.4.0" + }, + "dependencies": { + "ajv": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.1" + } + }, + "ajv-keywords": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "postcss-merge-idents": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", + "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", + "dev": true, + "requires": { + "has": "^1.0.1", + "postcss": "^5.0.10", + "postcss-value-parser": "^3.1.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-merge-longhand": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz", + "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", + "dev": true, + "requires": { + "postcss": "^5.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-merge-rules": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz", + "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=", + "dev": true, + "requires": { + "browserslist": "^1.5.2", + "caniuse-api": "^1.5.2", + "postcss": "^5.0.4", + "postcss-selector-parser": "^2.2.2", + "vendors": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "^1.0.30000639", + "electron-to-chromium": "^1.2.7" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-message-helpers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz", + "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=", + "dev": true + }, + "postcss-minify-font-values": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", + "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "postcss": "^5.0.4", + "postcss-value-parser": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-minify-gradients": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", + "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", + "dev": true, + "requires": { + "postcss": "^5.0.12", + "postcss-value-parser": "^3.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-minify-params": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", + "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.1", + "postcss": "^5.0.2", + "postcss-value-parser": "^3.0.2", + "uniqs": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-minify-selectors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", + "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.2", + "has": "^1.0.1", + "postcss": "^5.0.14", + "postcss-selector-parser": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz", + "integrity": "sha1-ZhQOzs447wa/DT41XWm/WdFB6oU=", + "dev": true, + "requires": { + "postcss": "^6.0.1" + } + }, + "postcss-modules-local-by-default": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", + "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", + "dev": true, + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + } + }, + "postcss-modules-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", + "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", + "dev": true, + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + } + }, + "postcss-modules-values": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", + "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", + "dev": true, + "requires": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^6.0.1" + } + }, + "postcss-normalize-charset": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", + "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", + "dev": true, + "requires": { + "postcss": "^5.0.5" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-normalize-url": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", + "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^1.4.0", + "postcss": "^5.0.14", + "postcss-value-parser": "^3.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-ordered-values": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz", + "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", + "dev": true, + "requires": { + "postcss": "^5.0.4", + "postcss-value-parser": "^3.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-reduce-idents": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", + "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", + "dev": true, + "requires": { + "postcss": "^5.0.4", + "postcss-value-parser": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-reduce-initial": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", + "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", + "dev": true, + "requires": { + "postcss": "^5.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-reduce-transforms": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", + "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", + "dev": true, + "requires": { + "has": "^1.0.1", + "postcss": "^5.0.8", + "postcss-value-parser": "^3.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-selector-parser": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz", + "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=", + "dev": true, + "requires": { + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "postcss-svgo": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", + "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", + "dev": true, + "requires": { + "is-svg": "^2.0.0", + "postcss": "^5.0.14", + "postcss-value-parser": "^3.2.3", + "svgo": "^0.7.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-unique-selectors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", + "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.1", + "postcss": "^5.0.4", + "uniqs": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-url": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-7.3.2.tgz", + "integrity": "sha512-QMV5mA+pCYZQcUEPQkmor9vcPQ2MT+Ipuu8qdi1gVxbNiIiErEGft+eny1ak19qALoBkccS5AHaCaCDzh7b9MA==", + "dev": true, + "requires": { + "mime": "^1.4.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.0", + "postcss": "^6.0.1", + "xxhashjs": "^0.2.1" + } + }, + "postcss-value-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", + "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", + "dev": true + }, + "postcss-zindex": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", + "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", + "dev": true, + "requires": { + "has": "^1.0.1", + "postcss": "^5.0.4", + "uniqs": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "prettier": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.2.tgz", + "integrity": "sha512-McHPg0n1pIke+A/4VcaS2en+pTNjy4xF+Uuq86u/5dyDO59/TtFZtQ708QIRkEZ3qwKz3GVkVa6mpxK/CpB8Rg==", + "dev": true + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "dev": true, + "requires": { + "renderkid": "^2.0.1", + "utila": "~0.4" + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "proxy-agent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-2.0.0.tgz", + "integrity": "sha1-V+tTR6qAXXTsaByyVknbo5yTNJk=", + "dev": true, + "requires": { + "agent-base": "2", + "debug": "2", + "extend": "3", + "http-proxy-agent": "1", + "https-proxy-agent": "1", + "lru-cache": "~2.6.5", + "pac-proxy-agent": "1", + "socks-proxy-agent": "2" + }, + "dependencies": { + "lru-cache": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz", + "integrity": "sha1-5W1jVBSO3o13B7WNFDIg/QjfD9U=", + "dev": true + } + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", + "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz", + "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==", + "dev": true + }, + "randomatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz", + "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "randombytes": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", + "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "dependencies": { + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "readable-stream": "^2.0.2", + "set-immediate-shim": "^1.0.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "dev": true, + "requires": { + "balanced-match": "^0.4.2", + "math-expression-evaluator": "^1.2.14", + "reduce-function-call": "^1.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + } + } + }, + "reduce-function-call": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", + "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", + "dev": true, + "requires": { + "balanced-match": "^0.4.2" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + } + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "renderkid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.1.tgz", + "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=", + "dev": true, + "requires": { + "css-select": "^1.1.0", + "dom-converter": "~0.1", + "htmlparser2": "~3.3.0", + "strip-ansi": "^3.0.0", + "utila": "~0.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "*" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "^5.0.0" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selenium-server": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/selenium-server/-/selenium-server-3.14.0.tgz", + "integrity": "sha512-+CCi1ED+7f36xpeGUqB8bWHde0To+9ZtegBHwWkbd9NsZcvANrtr8wlRNqHSD8yGmC0F7rixbgwiJEK9mTCLww==", + "dev": true + }, + "selfsigned": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.3.tgz", + "integrity": "sha512-vmZenZ+8Al3NLHkWnhBQ0x6BkML1eCP2xEi3JE+f3D9wW9fipD9NNJHYtE9XJM4TsPaHGZJIamrSI6MTg1dU2Q==", + "dev": true, + "requires": { + "node-forge": "0.7.5" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", + "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "smart-buffer": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", + "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "sockjs-client": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.4.tgz", + "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=", + "dev": true, + "requires": { + "debug": "^2.6.6", + "eventsource": "0.1.6", + "faye-websocket": "~0.11.0", + "inherits": "^2.0.1", + "json3": "^3.3.2", + "url-parse": "^1.1.8" + }, + "dependencies": { + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "socks": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", + "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=", + "dev": true, + "requires": { + "ip": "^1.1.4", + "smart-buffer": "^1.0.13" + }, + "dependencies": { + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + } + } + }, + "socks-proxy-agent": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz", + "integrity": "sha512-sFtmYqdUK5dAMh85H0LEVFUCO7OhJJe1/z2x/Z6mxp3s7/QPf1RkZmpZy+BpuU0bEjcV9npqKjq9Y3kwFUjnxw==", + "dev": true, + "requires": { + "agent-base": "2", + "extend": "3", + "socks": "~1.1.5" + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", + "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "dev": true + }, + "spdy": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", + "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", + "dev": true, + "requires": { + "debug": "^2.6.8", + "handle-thing": "^1.2.5", + "http-deceiver": "^1.2.7", + "safe-buffer": "^5.0.1", + "select-hose": "^2.0.0", + "spdy-transport": "^2.0.18" + } + }, + "spdy-transport": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.1.0.tgz", + "integrity": "sha512-bpUeGpZcmZ692rrTiqf9/2EUakI6/kXX1Rpe0ib/DyOzbiexVfXkw6GnvI9hVGvIwVaUhkaBojjCZwLNRGQg1g==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "detect-node": "^2.0.3", + "hpack.js": "^2.1.6", + "obuf": "^1.1.1", + "readable-stream": "^2.2.9", + "safe-buffer": "^5.0.1", + "wbuf": "^1.7.2" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", + "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "stackframe": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.0.4.tgz", + "integrity": "sha512-to7oADIniaYwS3MhtCa/sQhrxidCCQiF/qp4/m5iN3ipf0Y7Xlri0f6eG29r08aL7JYl8n32AF3Q5GYBZ7K8vw==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svgo": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", + "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "dev": true, + "requires": { + "coa": "~1.0.1", + "colors": "~1.1.2", + "csso": "~2.3.1", + "js-yaml": "~3.7.0", + "mkdirp": "~0.5.1", + "sax": "~1.2.1", + "whet.extend": "~0.9.9" + } + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "tapable": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", + "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + } + }, + "thunkify": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", + "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", + "dev": true + }, + "thunky": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz", + "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=", + "dev": true + }, + "time-stamp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.1.tgz", + "integrity": "sha512-KUnkvOWC3C+pEbwE/0u3CcmNpGCDqkYGYZOphe1QFxApYQkJ5g195TDBjgZch/zG6chU1NcabLwnM7BCpWAzTQ==", + "dev": true + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "punycode": "^1.4.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.7.tgz", + "integrity": "sha512-J0M2i1mQA+ze3EdN9SBi751DNdAXmeFLfJrd/MDIkRc3G3Gbb9OPVSx7GIQvVwfWxQARcYV2DTxIkMyDAk3o9Q==", + "dev": true, + "requires": { + "commander": "~2.16.0", + "source-map": "~0.6.1" + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "uglifyjs-webpack-plugin": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.7.tgz", + "integrity": "sha512-1VicfKhCYHLS8m1DCApqBhoulnASsEoJ/BvpUpP4zoNAPpKzdH+ghk0olGJMmwX2/jprK2j3hAHdUbczBSy2FA==", + "dev": true, + "requires": { + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "schema-utils": "^0.4.5", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "uglify-es": "^3.3.4", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.1" + } + }, + "ajv-keywords": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true + }, + "commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "uglify-es": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", + "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "dev": true, + "requires": { + "commander": "~2.13.0", + "source-map": "~0.6.1" + } + } + } + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-filename": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", + "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", + "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-loader": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.5.9.tgz", + "integrity": "sha512-B7QYFyvv+fOBqBVeefsxv6koWWtjmHaMFT6KZWti4KRw8YUD/hOU+3AECvXuzyVawIBx3z7zQRejXCDSO5kk1Q==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "mime": "1.3.x" + }, + "dependencies": { + "mime": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", + "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=", + "dev": true + } + } + }, + "url-parse": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.3.tgz", + "integrity": "sha512-rh+KuAW36YKo0vClhQzLLveoj8FwPJNu65xLb7Mrt+eZht0IPT0IXgSv8gcMegZ6NvjJUALf6Mf25POlMwD1Fw==", + "dev": true, + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", + "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "vue": { + "version": "2.5.17", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.5.17.tgz", + "integrity": "sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ==" + }, + "vue-eslint-parser": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz", + "integrity": "sha512-ZezcU71Owm84xVF6gfurBQUGg8WQ+WZGxgDEQu1IHFBZNx7BFZg3L1yHxrCBNNwbwFtE1GuvfJKMtb6Xuwc/Bw==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.2", + "esquery": "^1.0.0", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "vue-hot-reload-api": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz", + "integrity": "sha512-2j/t+wIbyVMP5NvctQoSUvLkYKoWAAk2QlQiilrM2a6/ulzFgdcLUJfTvs4XQ/3eZhHiBmmEojbjmM4AzZj8JA==", + "dev": true + }, + "vue-loader": { + "version": "13.7.2", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-13.7.2.tgz", + "integrity": "sha512-pgFWFsUjYO1v+J+3r7K0Q4lCp0eOyI24/q9j+cCudWyCTjgpjpcAa1MdwjlDUUettt9xkkUBbQ9fkAN1NC8t9w==", + "dev": true, + "requires": { + "consolidate": "^0.14.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "lru-cache": "^4.1.1", + "postcss": "^6.0.8", + "postcss-load-config": "^1.1.0", + "postcss-selector-parser": "^2.0.0", + "prettier": "^1.7.0", + "resolve": "^1.4.0", + "source-map": "^0.6.1", + "vue-hot-reload-api": "^2.2.0", + "vue-style-loader": "^3.0.0", + "vue-template-es2015-compiler": "^1.6.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "require-from-string": "^1.1.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "postcss-load-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", + "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.0", + "object-assign": "^4.1.0", + "postcss-load-options": "^1.2.0", + "postcss-load-plugins": "^2.3.0" + } + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "dev": true + } + } + }, + "vue-router": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.1.tgz", + "integrity": "sha512-vLLoY452L+JBpALMP5UHum9+7nzR9PeIBCghU9ZtJ1eWm6ieUI8Zb/DI3MYxH32bxkjzYV1LRjNv4qr8d+uX/w==" + }, + "vue-style-loader": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-3.1.2.tgz", + "integrity": "sha512-ICtVdK/p+qXWpdSs2alWtsXt9YnDoYjQe0w5616j9+/EhjoxZkbun34uWgsMFnC1MhrMMwaWiImz3K2jK1Yp2Q==", + "dev": true, + "requires": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + } + }, + "vue-template-compiler": { + "version": "2.5.17", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.5.17.tgz", + "integrity": "sha512-63uI4syCwtGR5IJvZM0LN5tVsahrelomHtCxvRkZPJ/Tf3ADm1U1wG6KWycK3qCfqR+ygM5vewUvmJ0REAYksg==", + "dev": true, + "requires": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, + "vue-template-es2015-compiler": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.6.0.tgz", + "integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==", + "dev": true + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webpack": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.12.0.tgz", + "integrity": "sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ==", + "dev": true, + "requires": { + "acorn": "^5.0.0", + "acorn-dynamic-import": "^2.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "async": "^2.1.2", + "enhanced-resolve": "^3.4.0", + "escope": "^3.6.0", + "interpret": "^1.0.0", + "json-loader": "^0.5.4", + "json5": "^0.5.1", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "mkdirp": "~0.5.0", + "node-libs-browser": "^2.0.0", + "source-map": "^0.5.3", + "supports-color": "^4.2.1", + "tapable": "^0.2.7", + "uglifyjs-webpack-plugin": "^0.4.6", + "watchpack": "^1.4.0", + "webpack-sources": "^1.0.1", + "yargs": "^8.0.2" + }, + "dependencies": { + "ajv": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.1" + } + }, + "ajv-keywords": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true, + "requires": { + "source-map": "^0.5.6", + "uglify-js": "^2.8.29", + "webpack-sources": "^1.0.1" + } + } + } + }, + "webpack-bundle-analyzer": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.13.1.tgz", + "integrity": "sha512-rwxyfecTAxoarCC9VlHlIpfQCmmJ/qWD5bpbjkof+7HrNhTNZIwZITxN6CdlYL2axGmwNUQ+tFgcSOiNXMf/sQ==", + "dev": true, + "requires": { + "acorn": "^5.3.0", + "bfj-node4": "^5.2.0", + "chalk": "^2.3.0", + "commander": "^2.13.0", + "ejs": "^2.5.7", + "express": "^4.16.2", + "filesize": "^3.5.11", + "gzip-size": "^4.1.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "opener": "^1.4.3", + "ws": "^4.0.0" + } + }, + "webpack-dev-middleware": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz", + "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==", + "dev": true, + "requires": { + "memory-fs": "~0.4.1", + "mime": "^1.5.0", + "path-is-absolute": "^1.0.0", + "range-parser": "^1.0.3", + "time-stamp": "^2.0.0" + } + }, + "webpack-dev-server": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.2.tgz", + "integrity": "sha512-zrPoX97bx47vZiAXfDrkw8pe9QjJ+lunQl3dypojyWwWr1M5I2h0VSrMPfTjopHQPRNn+NqfjcMmhoLcUJe2gA==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "array-includes": "^3.0.3", + "bonjour": "^3.5.0", + "chokidar": "^2.0.0", + "compression": "^1.5.2", + "connect-history-api-fallback": "^1.3.0", + "debug": "^3.1.0", + "del": "^3.0.0", + "express": "^4.16.2", + "html-entities": "^1.2.0", + "http-proxy-middleware": "~0.17.4", + "import-local": "^1.0.0", + "internal-ip": "1.2.0", + "ip": "^1.1.5", + "killable": "^1.0.0", + "loglevel": "^1.4.1", + "opn": "^5.1.0", + "portfinder": "^1.0.9", + "selfsigned": "^1.9.1", + "serve-index": "^1.7.2", + "sockjs": "0.3.19", + "sockjs-client": "1.1.4", + "spdy": "^3.4.1", + "strip-ansi": "^3.0.0", + "supports-color": "^5.1.0", + "webpack-dev-middleware": "1.12.2", + "yargs": "6.6.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^4.2.0" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + } + } + }, + "webpack-merge": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.4.tgz", + "integrity": "sha512-TmSe1HZKeOPey3oy1Ov2iS3guIZjWvMT2BBJDzzT5jScHTjVC3mpjJofgueEzaEd6ibhxRDD6MIblDr8tzh8iQ==", + "dev": true, + "requires": { + "lodash": "^4.17.5" + } + }, + "webpack-sources": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", + "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "whet.extend": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "worker-farm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", + "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "requires": { + "cuint": "^0.2.2" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + } + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "requires": { + "fd-slicer": "~1.0.1" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 00000000..7aedf76f --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,80 @@ +{ + "name": "frontend", + "version": "1.0.0", + "description": "pkdb: pharmacokinetical data", + "author": "Jan ", + "private": true, + "scripts": { + "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", + "start": "npm run dev", + "e2e": "node test/e2e/runner.js", + "test": "npm run e2e", + "lint": "eslint --ext .js,.vue src test/e2e/specs", + "build": "node build/build.js" + }, + "dependencies": { + "vue": "^2.5.2", + "vue-router": "^3.0.1" + }, + "devDependencies": { + "autoprefixer": "^7.1.2", + "babel-core": "^6.22.1", + "babel-eslint": "^8.2.1", + "babel-helper-vue-jsx-merge-props": "^2.0.3", + "babel-loader": "^7.1.1", + "babel-plugin-syntax-jsx": "^6.18.0", + "babel-plugin-transform-runtime": "^6.22.0", + "babel-plugin-transform-vue-jsx": "^3.5.0", + "babel-preset-env": "^1.3.2", + "babel-preset-stage-2": "^6.22.0", + "babel-register": "^6.22.0", + "chalk": "^2.0.1", + "chromedriver": "^2.27.2", + "copy-webpack-plugin": "^4.0.1", + "cross-spawn": "^5.0.1", + "css-loader": "^0.28.0", + "eslint": "^4.15.0", + "eslint-config-standard": "^10.2.1", + "eslint-friendly-formatter": "^3.0.0", + "eslint-loader": "^1.7.1", + "eslint-plugin-import": "^2.7.0", + "eslint-plugin-node": "^5.2.0", + "eslint-plugin-promise": "^3.4.0", + "eslint-plugin-standard": "^3.0.1", + "eslint-plugin-vue": "^4.0.0", + "extract-text-webpack-plugin": "^3.0.0", + "file-loader": "^1.1.4", + "friendly-errors-webpack-plugin": "^1.6.1", + "html-webpack-plugin": "^2.30.1", + "nightwatch": "^0.9.12", + "node-notifier": "^5.1.2", + "optimize-css-assets-webpack-plugin": "^3.2.0", + "ora": "^1.2.0", + "portfinder": "^1.0.13", + "postcss-import": "^11.0.0", + "postcss-loader": "^2.0.8", + "postcss-url": "^7.2.1", + "rimraf": "^2.6.0", + "selenium-server": "^3.0.1", + "semver": "^5.3.0", + "shelljs": "^0.7.6", + "uglifyjs-webpack-plugin": "^1.1.1", + "url-loader": "^0.5.8", + "vue-loader": "^13.3.0", + "vue-style-loader": "^3.0.1", + "vue-template-compiler": "^2.5.2", + "webpack": "^3.6.0", + "webpack-bundle-analyzer": "^2.9.0", + "webpack-dev-server": "^2.9.1", + "webpack-merge": "^4.1.0" + }, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 8" + ] +} diff --git a/frontend/src/App.vue b/frontend/src/App.vue new file mode 100644 index 00000000..d74c648e --- /dev/null +++ b/frontend/src/App.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/frontend/src/assets/logo.png b/frontend/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d2503fc2a44b5053b0837ebea6e87a2d339a43 GIT binary patch literal 6849 zcmaKRcUV(fvo}bjDT-7nLI_nlK}sT_69H+`qzVWDA|yaU?}j417wLi^B1KB1SLsC& zL0ag7$U(XW5YR7p&Ux?sP$d4lvMt8C^+TcQu4F zQqv!UF!I+kw)c0jhd6+g6oCr9P?7)?!qX1ui*iL{p}sKCAGuJ{{W)0z1pLF|=>h}& zt(2Lr0Z`2ig8<5i%Zk}cO5Fm=LByqGWaS`oqChZdEFmc`0hSb#gg|Aap^{+WKOYcj zHjINK)KDG%&s?Mt4CL(T=?;~U@bU2x_mLKN!#GJuK_CzbNw5SMEJorG!}_5;?R>@1 zSl)jns3WlU7^J%=(hUtfmuUCU&C3%8B5C^f5>W2Cy8jW3#{Od{lF1}|?c61##3dzA zsPlFG;l_FzBK}8>|H_Ru_H#!_7$UH4UKo3lKOA}g1(R&|e@}GINYVzX?q=_WLZCgh z)L|eJMce`D0EIwgRaNETDsr+?vQknSGAi=7H00r`QnI%oQnFxm`G2umXso9l+8*&Q z7WqF|$p49js$mdzo^BXpH#gURy=UO;=IMrYc5?@+sR4y_?d*~0^YP7d+y0{}0)zBM zIKVM(DBvICK#~7N0a+PY6)7;u=dutmNqK3AlsrUU9U`d;msiucB_|8|2kY=(7XA;G zwDA8AR)VCA#JOkxm#6oHNS^YVuOU;8p$N)2{`;oF|rQ?B~K$%rHDxXs+_G zF5|-uqHZvSzq}L;5Kcy_P+x0${33}Ofb6+TX&=y;;PkEOpz%+_bCw_{<&~ zeLV|!bP%l1qxywfVr9Z9JI+++EO^x>ZuCK);=$VIG1`kxK8F2M8AdC$iOe3cj1fo(ce4l-9 z7*zKy3={MixvUk=enQE;ED~7tv%qh&3lR<0m??@w{ILF|e#QOyPkFYK!&Up7xWNtL zOW%1QMC<3o;G9_S1;NkPB6bqbCOjeztEc6TsBM<(q9((JKiH{01+Ud=uw9B@{;(JJ z-DxI2*{pMq`q1RQc;V8@gYAY44Z!%#W~M9pRxI(R?SJ7sy7em=Z5DbuDlr@*q|25V)($-f}9c#?D%dU^RS<(wz?{P zFFHtCab*!rl(~j@0(Nadvwg8q|4!}L^>d?0al6}Rrv9$0M#^&@zjbfJy_n!%mVHK4 z6pLRIQ^Uq~dnyy$`ay51Us6WaP%&O;@49m&{G3z7xV3dLtt1VTOMYl3UW~Rm{Eq4m zF?Zl_v;?7EFx1_+#WFUXxcK78IV)FO>42@cm@}2I%pVbZqQ}3;p;sDIm&knay03a^ zn$5}Q$G!@fTwD$e(x-~aWP0h+4NRz$KlnO_H2c< z(XX#lPuW_%H#Q+c&(nRyX1-IadKR-%$4FYC0fsCmL9ky3 zKpxyjd^JFR+vg2!=HWf}2Z?@Td`0EG`kU?{8zKrvtsm)|7>pPk9nu@2^z96aU2<#` z2QhvH5w&V;wER?mopu+nqu*n8p~(%QkwSs&*0eJwa zMXR05`OSFpfyRb!Y_+H@O%Y z0=K^y6B8Gcbl?SA)qMP3Z+=C(?8zL@=74R=EVnE?vY!1BQy2@q*RUgRx4yJ$k}MnL zs!?74QciNb-LcG*&o<9=DSL>1n}ZNd)w1z3-0Pd^4ED1{qd=9|!!N?xnXjM!EuylY z5=!H>&hSofh8V?Jofyd!h`xDI1fYAuV(sZwwN~{$a}MX^=+0TH*SFp$vyxmUv7C*W zv^3Gl0+eTFgBi3FVD;$nhcp)ka*4gSskYIqQ&+M}xP9yLAkWzBI^I%zR^l1e?bW_6 zIn{mo{dD=)9@V?s^fa55jh78rP*Ze<3`tRCN4*mpO$@7a^*2B*7N_|A(Ve2VB|)_o z$=#_=aBkhe(ifX}MLT()@5?OV+~7cXC3r!%{QJxriXo9I%*3q4KT4Xxzyd{ z9;_%=W%q!Vw$Z7F3lUnY+1HZ*lO;4;VR2+i4+D(m#01OYq|L_fbnT;KN<^dkkCwtd zF7n+O7KvAw8c`JUh6LmeIrk4`F3o|AagKSMK3))_5Cv~y2Bb2!Ibg9BO7Vkz?pAYX zoI=B}+$R22&IL`NCYUYjrdhwjnMx_v=-Qcx-jmtN>!Zqf|n1^SWrHy zK|MwJ?Z#^>)rfT5YSY{qjZ&`Fjd;^vv&gF-Yj6$9-Dy$<6zeP4s+78gS2|t%Z309b z0^fp~ue_}i`U9j!<|qF92_3oB09NqgAoehQ`)<)dSfKoJl_A6Ec#*Mx9Cpd-p#$Ez z={AM*r-bQs6*z$!*VA4|QE7bf@-4vb?Q+pPKLkY2{yKsw{&udv_2v8{Dbd zm~8VAv!G~s)`O3|Q6vFUV%8%+?ZSVUa(;fhPNg#vab@J*9XE4#D%)$UU-T5`fwjz! z6&gA^`OGu6aUk{l*h9eB?opVdrHK>Q@U>&JQ_2pR%}TyOXGq_6s56_`U(WoOaAb+K zXQr#6H}>a-GYs9^bGP2Y&hSP5gEtW+GVC4=wy0wQk=~%CSXj=GH6q z-T#s!BV`xZVxm{~jr_ezYRpqqIcXC=Oq`b{lu`Rt(IYr4B91hhVC?yg{ol4WUr3v9 zOAk2LG>CIECZ-WIs0$N}F#eoIUEtZudc7DPYIjzGqDLWk_A4#(LgacooD z2K4IWs@N`Bddm-{%oy}!k0^i6Yh)uJ1S*90>|bm3TOZxcV|ywHUb(+CeX-o1|LTZM zwU>dY3R&U)T(}5#Neh?-CWT~@{6Ke@sI)uSuzoah8COy)w)B)aslJmp`WUcjdia-0 zl2Y}&L~XfA`uYQboAJ1;J{XLhYjH){cObH3FDva+^8ioOQy%Z=xyjGLmWMrzfFoH; zEi3AG`_v+%)&lDJE;iJWJDI@-X9K5O)LD~j*PBe(wu+|%ar~C+LK1+-+lK=t# z+Xc+J7qp~5q=B~rD!x78)?1+KUIbYr^5rcl&tB-cTtj+e%{gpZZ4G~6r15+d|J(ky zjg@@UzMW0k9@S#W(1H{u;Nq(7llJbq;;4t$awM;l&(2s+$l!Ay9^Ge|34CVhr7|BG z?dAR83smef^frq9V(OH+a+ki#q&-7TkWfFM=5bsGbU(8mC;>QTCWL5ydz9s6k@?+V zcjiH`VI=59P-(-DWXZ~5DH>B^_H~;4$)KUhnmGo*G!Tq8^LjfUDO)lASN*=#AY_yS zqW9UX(VOCO&p@kHdUUgsBO0KhXxn1sprK5h8}+>IhX(nSXZKwlNsjk^M|RAaqmCZB zHBolOHYBas@&{PT=R+?d8pZu zUHfyucQ`(umXSW7o?HQ3H21M`ZJal+%*)SH1B1j6rxTlG3hx1IGJN^M7{$j(9V;MZ zRKybgVuxKo#XVM+?*yTy{W+XHaU5Jbt-UG33x{u(N-2wmw;zzPH&4DE103HV@ER86 z|FZEmQb|&1s5#`$4!Cm}&`^{(4V}OP$bk`}v6q6rm;P!H)W|2i^e{7lTk2W@jo_9q z*aw|U7#+g59Fv(5qI`#O-qPj#@_P>PC#I(GSp3DLv7x-dmYK=C7lPF8a)bxb=@)B1 zUZ`EqpXV2dR}B&r`uM}N(TS99ZT0UB%IN|0H%DcVO#T%L_chrgn#m6%x4KE*IMfjX zJ%4veCEqbXZ`H`F_+fELMC@wuy_ch%t*+Z+1I}wN#C+dRrf2X{1C8=yZ_%Pt6wL_~ zZ2NN-hXOT4P4n$QFO7yYHS-4wF1Xfr-meG9Pn;uK51?hfel`d38k{W)F*|gJLT2#T z<~>spMu4(mul-8Q3*pf=N4DcI)zzjqAgbE2eOT7~&f1W3VsdD44Ffe;3mJp-V@8UC z)|qnPc12o~$X-+U@L_lWqv-RtvB~%hLF($%Ew5w>^NR82qC_0FB z)=hP1-OEx?lLi#jnLzH}a;Nvr@JDO-zQWd}#k^an$Kwml;MrD&)sC5b`s0ZkVyPkb zt}-jOq^%_9>YZe7Y}PhW{a)c39G`kg(P4@kxjcYfgB4XOOcmezdUI7j-!gs7oAo2o zx(Ph{G+YZ`a%~kzK!HTAA5NXE-7vOFRr5oqY$rH>WI6SFvWmahFav!CfRMM3%8J&c z*p+%|-fNS_@QrFr(at!JY9jCg9F-%5{nb5Bo~z@Y9m&SHYV`49GAJjA5h~h4(G!Se zZmK{Bo7ivCfvl}@A-ptkFGcWXAzj3xfl{evi-OG(TaCn1FAHxRc{}B|x+Ua1D=I6M z!C^ZIvK6aS_c&(=OQDZfm>O`Nxsw{ta&yiYPA~@e#c%N>>#rq)k6Aru-qD4(D^v)y z*>Rs;YUbD1S8^D(ps6Jbj0K3wJw>L4m)0e(6Pee3Y?gy9i0^bZO?$*sv+xKV?WBlh zAp*;v6w!a8;A7sLB*g-^<$Z4L7|5jXxxP1}hQZ<55f9<^KJ>^mKlWSGaLcO0=$jem zWyZkRwe~u{{tU63DlCaS9$Y4CP4f?+wwa(&1ou)b>72ydrFvm`Rj-0`kBJgK@nd(*Eh!(NC{F-@=FnF&Y!q`7){YsLLHf0_B6aHc# z>WIuHTyJwIH{BJ4)2RtEauC7Yq7Cytc|S)4^*t8Va3HR zg=~sN^tp9re@w=GTx$;zOWMjcg-7X3Wk^N$n;&Kf1RgVG2}2L-(0o)54C509C&77i zrjSi{X*WV=%C17((N^6R4Ya*4#6s_L99RtQ>m(%#nQ#wrRC8Y%yxkH;d!MdY+Tw@r zjpSnK`;C-U{ATcgaxoEpP0Gf+tx);buOMlK=01D|J+ROu37qc*rD(w`#O=3*O*w9?biwNoq3WN1`&Wp8TvKj3C z3HR9ssH7a&Vr<6waJrU zdLg!ieYz%U^bmpn%;(V%%ugMk92&?_XX1K@mwnVSE6!&%P%Wdi7_h`CpScvspMx?N zQUR>oadnG17#hNc$pkTp+9lW+MBKHRZ~74XWUryd)4yd zj98$%XmIL4(9OnoeO5Fnyn&fpQ9b0h4e6EHHw*l68j;>(ya`g^S&y2{O8U>1*>4zR zq*WSI_2o$CHQ?x0!wl9bpx|Cm2+kFMR)oMud1%n2=qn5nE&t@Fgr#=Zv2?}wtEz^T z9rrj=?IH*qI5{G@Rn&}^Z{+TW}mQeb9=8b<_a`&Cm#n%n~ zU47MvCBsdXFB1+adOO)03+nczfWa#vwk#r{o{dF)QWya9v2nv43Zp3%Ps}($lA02*_g25t;|T{A5snSY?3A zrRQ~(Ygh_ebltHo1VCbJb*eOAr;4cnlXLvI>*$-#AVsGg6B1r7@;g^L zFlJ_th0vxO7;-opU@WAFe;<}?!2q?RBrFK5U{*ai@NLKZ^};Ul}beukveh?TQn;$%9=R+DX07m82gP$=}Uo_%&ngV`}Hyv8g{u z3SWzTGV|cwQuFIs7ZDOqO_fGf8Q`8MwL}eUp>q?4eqCmOTcwQuXtQckPy|4F1on8l zP*h>d+cH#XQf|+6c|S{7SF(Lg>bR~l(0uY?O{OEVlaxa5@e%T&xju=o1`=OD#qc16 zSvyH*my(dcp6~VqR;o(#@m44Lug@~_qw+HA=mS#Z^4reBy8iV?H~I;{LQWk3aKK8$bLRyt$g?-' +}) diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js new file mode 100644 index 00000000..5fa7f9d3 --- /dev/null +++ b/frontend/src/router/index.js @@ -0,0 +1,15 @@ +import Vue from 'vue' +import Router from 'vue-router' +import HelloWorld from '@/components/HelloWorld' + +Vue.use(Router) + +export default new Router({ + routes: [ + { + path: '/', + name: 'HelloWorld', + component: HelloWorld + } + ] +}) diff --git a/frontend/static/.gitkeep b/frontend/static/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/frontend/test/e2e/custom-assertions/elementCount.js b/frontend/test/e2e/custom-assertions/elementCount.js new file mode 100644 index 00000000..818e6020 --- /dev/null +++ b/frontend/test/e2e/custom-assertions/elementCount.js @@ -0,0 +1,27 @@ +// A custom Nightwatch assertion. +// The assertion name is the filename. +// Example usage: +// +// browser.assert.elementCount(selector, count) +// +// For more information on custom assertions see: +// http://nightwatchjs.org/guide#writing-custom-assertions + +exports.assertion = function (selector, count) { + this.message = 'Testing if element <' + selector + '> has count: ' + count + this.expected = count + this.pass = function (val) { + return val === this.expected + } + this.value = function (res) { + return res.value + } + this.command = function (cb) { + var self = this + return this.api.execute(function (selector) { + return document.querySelectorAll(selector).length + }, [selector], function (res) { + cb.call(self, res) + }) + } +} diff --git a/frontend/test/e2e/nightwatch.conf.js b/frontend/test/e2e/nightwatch.conf.js new file mode 100644 index 00000000..f019c0ac --- /dev/null +++ b/frontend/test/e2e/nightwatch.conf.js @@ -0,0 +1,46 @@ +require('babel-register') +var config = require('../../config') + +// http://nightwatchjs.org/gettingstarted#settings-file +module.exports = { + src_folders: ['test/e2e/specs'], + output_folder: 'test/e2e/reports', + custom_assertions_path: ['test/e2e/custom-assertions'], + + selenium: { + start_process: true, + server_path: require('selenium-server').path, + host: '127.0.0.1', + port: 4444, + cli_args: { + 'webdriver.chrome.driver': require('chromedriver').path + } + }, + + test_settings: { + default: { + selenium_port: 4444, + selenium_host: 'localhost', + silent: true, + globals: { + devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) + } + }, + + chrome: { + desiredCapabilities: { + browserName: 'chrome', + javascriptEnabled: true, + acceptSslCerts: true + } + }, + + firefox: { + desiredCapabilities: { + browserName: 'firefox', + javascriptEnabled: true, + acceptSslCerts: true + } + } + } +} diff --git a/frontend/test/e2e/runner.js b/frontend/test/e2e/runner.js new file mode 100644 index 00000000..27220329 --- /dev/null +++ b/frontend/test/e2e/runner.js @@ -0,0 +1,48 @@ +// 1. start the dev server using production config +process.env.NODE_ENV = 'testing' + +const webpack = require('webpack') +const DevServer = require('webpack-dev-server') + +const webpackConfig = require('../../build/webpack.prod.conf') +const devConfigPromise = require('../../build/webpack.dev.conf') + +let server + +devConfigPromise.then(devConfig => { + const devServerOptions = devConfig.devServer + const compiler = webpack(webpackConfig) + server = new DevServer(compiler, devServerOptions) + const port = devServerOptions.port + const host = devServerOptions.host + return server.listen(port, host) +}) +.then(() => { + // 2. run the nightwatch test suite against it + // to run in additional browsers: + // 1. add an entry in test/e2e/nightwatch.conf.js under "test_settings" + // 2. add it to the --env flag below + // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` + // For more information on Nightwatch's config file, see + // http://nightwatchjs.org/guide#settings-file + let opts = process.argv.slice(2) + if (opts.indexOf('--config') === -1) { + opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) + } + if (opts.indexOf('--env') === -1) { + opts = opts.concat(['--env', 'chrome']) + } + + const spawn = require('cross-spawn') + const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) + + runner.on('exit', function (code) { + server.close() + process.exit(code) + }) + + runner.on('error', function (err) { + server.close() + throw err + }) +}) diff --git a/frontend/test/e2e/specs/test.js b/frontend/test/e2e/specs/test.js new file mode 100644 index 00000000..a7b1bd92 --- /dev/null +++ b/frontend/test/e2e/specs/test.js @@ -0,0 +1,19 @@ +// For authoring Nightwatch tests, see +// http://nightwatchjs.org/guide#usage + +module.exports = { + 'default e2e tests': function (browser) { + // automatically uses dev Server port from /config.index.js + // default: http://localhost:8080 + // see nightwatch.conf.js + const devServer = browser.globals.devServerURL + + browser + .url(devServer) + .waitForElementVisible('#app', 5000) + .assert.elementPresent('.hello') + .assert.containsText('h1', 'Welcome to Your Vue.js App') + .assert.elementCount('img', 1) + .end() + } +} diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index d815b237..03516d42 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -166,6 +166,8 @@ def create_choices(list): "norfloxacin", "ofloxacin", "fluvoxamine", + "alcohol", + ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] @@ -218,6 +220,7 @@ def create_choices(list): # Study protocol CharacteristicType('overnight fast', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('alcohol abstinence', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('abstinence', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, SUBSTANCES_DATA+["alcohol","food"]), # Medication @@ -252,8 +255,8 @@ def create_choices(list): PK_DATA_CHOICES = create_choices(PK_DATA) # class, value, dtype (numeric, boolean, categorial), choices -PROTOCOL_DATA = [ - CharacteristicType('dosing', 'dosing', NUMERIC_TYPE, None, ["-"]), +INTERVENTION_DATA = [ + CharacteristicType('dosing', 'dosing', NUMERIC_TYPE, None, ["mg","mg/kg"]), CharacteristicType('smoking cessation', 'lifestyle', NUMERIC_TYPE, None, ["-"]), CharacteristicType('female cycle', 'cycle', STRING_TYPE, None, ["-"]), ] @@ -267,7 +270,7 @@ def dict_and_choices(data): CHARACTERISTIC_CATEGORIES = set([item.value for item in CHARACTERISTIC_DATA]) CHARACTERISTIC_CATEGORIES_UNDERSCORE = set([c.replace(' ', '_') for c in CHARACTERISTIC_CATEGORIES]) CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES = dict_and_choices(CHARACTERISTIC_DATA) -PROTOCOL_DICT, PROTOCOL_CHOICES = dict_and_choices(PROTOCOL_DATA) +INTERVENTION_DICT, INTERVENTION_CHOICES = dict_and_choices(INTERVENTION_DATA) ''' diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py index 369a1135..388961dd 100644 --- a/pkdb_app/data_management/add_groups.py +++ b/pkdb_app/data_management/add_groups.py @@ -10,7 +10,7 @@ from pkdb_app.data_management.fill_database import get_study_json_path, open_study from pkdb_app.data_management.initialize_study import save_study, study_filename, SEPERATOR from pkdb_app.categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE -from pkdb_app.data_management.create_reference import SUBJECTSPATH, INDIVIDUALPATH +from pkdb_app.data_management.create_reference_caffeine import SUBJECTSPATH, INDIVIDUALPATH from pkdb_app.utils import create_if_exists, clean_import diff --git a/pkdb_app/data_management/add_intervention.py b/pkdb_app/data_management/add_intervention.py index dc42b672..d7b3d2ec 100644 --- a/pkdb_app/data_management/add_intervention.py +++ b/pkdb_app/data_management/add_intervention.py @@ -8,7 +8,7 @@ sys.path.append(BASEPATH) from pkdb_app.data_management.fill_database import get_study_json_path, open_study -from pkdb_app.data_management.create_reference import DOSINGPATH, ensure_dir +from pkdb_app.data_management.create_reference_caffeine import DOSINGPATH, ensure_dir from pkdb_app.data_management.initialize_study import save_study, SEPERATOR from pkdb_app.utils import create_if_exists, clean_import @@ -37,6 +37,8 @@ def add_intervention_to_study(study): intervention_json["form"] = row["form"] intervention_json["value"] = row["dose"] intervention_json["unit"] = row["dose_unit"] + intervention_json["category"] = row["category"] + study_json["interventionset"]["interventions"].append(clean_import(intervention_json)) yield {"json":study_json,"study_path": study["study_path"]} diff --git a/pkdb_app/data_management/add_output.py b/pkdb_app/data_management/add_output.py index bd71cecd..6188949a 100644 --- a/pkdb_app/data_management/add_output.py +++ b/pkdb_app/data_management/add_output.py @@ -6,7 +6,7 @@ from pkdb_app.data_management.fill_database import get_study_json_path, open_study -from pkdb_app.data_management.create_reference import PHARMACOKINETICSPATH, TIMECOURSEPATH, OUTPUTINDIVIDUALPATH +from pkdb_app.data_management.create_reference_caffeine import PHARMACOKINETICSPATH, TIMECOURSEPATH, OUTPUTINDIVIDUALPATH from pkdb_app.data_management.initialize_study import save_study from pkdb_app.utils import create_if_exists, clean_import diff --git a/pkdb_app/data_management/create_reference_acetaminophen.py b/pkdb_app/data_management/create_reference_acetaminophen.py new file mode 100644 index 00000000..fd36ad9e --- /dev/null +++ b/pkdb_app/data_management/create_reference_acetaminophen.py @@ -0,0 +1,175 @@ +""" +Creates json files in master folder +""" +import os +import shutil +import csv +import sys +import bonobo +import xml.etree.ElementTree as ET +from Bio import Entrez +import json +import requests + +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) +from pkdb_app.utils import ensure_dir + +SUBSTANCE = "acetaminophen" + +Master = os.path.join(BASEPATH, "Master") +if BASEPATH not in sys.path: + sys.path.append(BASEPATH) + +# important for this script +DATABASEPATH = os.path.join(BASEPATH, "data") +LITERATUREPATH = os.path.join(DATABASEPATH, SUBSTANCE, "literature") +MASTERPATH = os.path.join(DATABASEPATH, "Master") +REFERENCESMASTERPATH = os.path.join(MASTERPATH, "Studies") +REFERENCESPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Studies.tsv") + + +# important for other scripts +SUBJECTSPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Subjects.tsv") +PHARMACOKINETICSPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Pharmacokinetics.tsv") +INTERVENTIONSPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Interventions.tsv") +DOSINGPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Dosing.tsv") +INDIVIDUALPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Individuals.tsv") +TIMECOURSEPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Timecourse.tsv") +OUTPUTINDIVIDUALPATH = os.path.join(DATABASEPATH, SUBSTANCE, "OutputIndividuals.tsv") + +def extract_references(path): + reader = csv.DictReader(open(path), delimiter='\t') + for line in reader: + yield dict(line) + +def pmid_to_int(d): + d['sid'] = int(d['pmid']) + d['pmid'] = int(d['pmid']) + + yield d + + +def add_reference_sid(d): + sid = str(d["study"]) + yield {**d , 'name': sid} + + +def add_reference_path(d): + reference_path = os.path.join(REFERENCESMASTERPATH, d['name']) + return {**d, "reference_path":reference_path} + + +def load_from_biopython(d): + Entrez.email = 'janekg89@hotmail.de' + handle = Entrez.efetch(db='pubmed', id=d['pmid'], retmode='xml') + all_info = handle.read() + handle.close() + yield {**d, 'xml': all_info} + + +def xml_to_data(d): + yield {**d, 'data': ET.fromstring(d['xml'])} + + + +def create_json(d): + json_dict = {} + json_dict["pmid"] = d["pmid"] + json_dict["name"] = d["name"] + json_dict["sid"] = d["sid"] + for date in d["data"].iter("DateCompleted"): + year = date.find('Year').text + month = date.find('Month').text + day = date.find('Day').text + json_dict["date"] = f"{year}-{str(month).zfill(2)}-{str(day).zfill(2)}" + continue + for journal in d["data"].iter("Title"): + json_dict["journal"] = journal.text + continue + for title in d["data"].iter("ArticleTitle"): + json_dict["title"] = title.text + continue + for abstract in d["data"].iter("AbstractText"): + json_dict["abstract"] = abstract.text + continue + + authors = [] + for author in d["data"].iter("Author"): + author_dict = {} + author_dict["first_name"] = author.find("ForeName").text + author_dict["last_name"] = author.find("LastName").text + authors.append(author_dict) + json_dict["authors"] = authors + return {'json': json_dict, 'reference_path' : d["reference_path"]} + + +def add_doi(d): + json_dict = d["json"] + response = requests.get(f'https://www.ncbi.nlm.nih.gov/pmc/utils/idconv/v1.0/?tool=my_tool&email=my_email@example.com&ids={json_dict["pmid"]}') + pmcids = ET.fromstring(response.content) + for records in pmcids.iter("record"): + json_dict["doi"] = records.get('doi', "") + + + return {"json":json_dict, "reference_path": d["reference_path"]} + +def save_json(d): + json_file = os.path.join(d["reference_path"],"reference.json") + ensure_dir(json_file) + with open(json_file, 'w') as fp: + json.dump(d['json'],fp, indent=4) + +def add_resources(d): + """ + inputs the result of "add_reference_path()" from add reference path + :param d: + :return: + """ + for file in os.listdir(LITERATUREPATH): + if file.startswith(d['name']): + src = os.path.join(LITERATUREPATH,file) + dst = os.path.join(d["reference_path"],file) + ensure_dir(dst) + shutil.copy(src,dst) + + + +collect_reference = [extract_references(REFERENCESPATH), + pmid_to_int, + add_reference_sid, + add_reference_path,] + +def get_graph(**options): + """ Bonobo execution graph. + + :param options: + :return: + """ + graph = bonobo.Graph() + + #adds reference to + graph.add_chain(*collect_reference) + + graph.add_chain( + load_from_biopython, + xml_to_data, + create_json, + add_doi, + save_json, + _input= add_reference_path) + + + graph.add_chain(add_resources, _input= add_reference_path) + + return graph + + +def get_services(**options): + return {} + + +if __name__ == '__main__': + parser = bonobo.get_argument_parser() + with bonobo.parse_args(parser) as options: + bonobo.run(get_graph(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/create_reference.py b/pkdb_app/data_management/create_reference_caffeine.py similarity index 86% rename from pkdb_app/data_management/create_reference.py rename to pkdb_app/data_management/create_reference_caffeine.py index 4b9d43ff..c46a2d9d 100644 --- a/pkdb_app/data_management/create_reference.py +++ b/pkdb_app/data_management/create_reference_caffeine.py @@ -15,25 +15,24 @@ sys.path.append(BASEPATH) from pkdb_app.utils import ensure_dir +CAFFEINE = "caffeine" Master = os.path.join(BASEPATH, "Master") if BASEPATH not in sys.path: sys.path.append(BASEPATH) DATABASEPATH = os.path.join(BASEPATH, "data") -REFERENCESPATH = os.path.join(DATABASEPATH, "caffeine", "Studies.tsv") -SUBJECTSPATH = os.path.join(DATABASEPATH, "caffeine", "Subjects.tsv") -LITERATUREPATH = os.path.join(DATABASEPATH, "caffeine", "literature") - -PHARMACOKINETICSPATH = os.path.join(DATABASEPATH, "caffeine", "Pharmacokinetics.tsv") -INTERVENTIONSPATH = os.path.join(DATABASEPATH, "caffeine", "Interventions.tsv") -DOSINGPATH = os.path.join(DATABASEPATH, "caffeine", "Dosing.tsv") +REFERENCESPATH = os.path.join(DATABASEPATH, CAFFEINE, "Studies.tsv") +SUBJECTSPATH = os.path.join(DATABASEPATH, CAFFEINE, "Subjects.tsv") +LITERATUREPATH = os.path.join(DATABASEPATH, CAFFEINE, "literature") +PHARMACOKINETICSPATH = os.path.join(DATABASEPATH, CAFFEINE, "Pharmacokinetics.tsv") +INTERVENTIONSPATH = os.path.join(DATABASEPATH, CAFFEINE, "Interventions.tsv") +DOSINGPATH = os.path.join(DATABASEPATH, CAFFEINE, "Dosing.tsv") MASTERPATH = os.path.join(DATABASEPATH, "Master") REFERENCESMASTERPATH = os.path.join(MASTERPATH, "Studies") - -INDIVIDUALPATH = os.path.join(DATABASEPATH, "caffeine", "Individuals.tsv") -TIMECOURSEPATH = os.path.join(DATABASEPATH, "caffeine", "Timecourse.tsv") -OUTPUTINDIVIDUALPATH = os.path.join(DATABASEPATH, "caffeine", "OutputIndividuals.tsv") +INDIVIDUALPATH = os.path.join(DATABASEPATH, CAFFEINE, "Individuals.tsv") +TIMECOURSEPATH = os.path.join(DATABASEPATH, CAFFEINE, "Timecourse.tsv") +OUTPUTINDIVIDUALPATH = os.path.join(DATABASEPATH, CAFFEINE, "OutputIndividuals.tsv") diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 5f1a3184..7d7aaa67 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -7,7 +7,7 @@ BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from pkdb_app.data_management.create_reference import REFERENCESMASTERPATH +from pkdb_app.data_management.create_reference_caffeine import REFERENCESMASTERPATH from jsonschema import validate from pkdb_app.data_management.schemas import reference_schema import logging diff --git a/pkdb_app/data_management/initialize_study.py b/pkdb_app/data_management/initialize_study.py index 11c35734..a8aeaf0b 100644 --- a/pkdb_app/data_management/initialize_study.py +++ b/pkdb_app/data_management/initialize_study.py @@ -14,7 +14,7 @@ BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from pkdb_app.data_management.create_reference import collect_reference, add_reference_path, ensure_dir +from pkdb_app.data_management.create_reference_caffeine import collect_reference, add_reference_path, ensure_dir MK = "Matthias König" MK_u = "mkoenig" diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 2d603d86..d2d248a2 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -8,7 +8,7 @@ from pkdb_app.interventions.managers import InterventionSetManager, OutputSetManager from ..behaviours import Valueable, Describable, ValueableMap, Sourceable -from ..categoricals import PROTOCOL_CHOICES, TIME_UNITS_CHOICES, \ +from ..categoricals import INTERVENTION_CHOICES, TIME_UNITS_CHOICES, \ INTERVENTION_ROUTE_CHOICES, INTERVENTION_FORM_CHOICES, INTERVENTION_APPLICATION_CHOICES, PK_DATA_CHOICES, \ SUBSTANCES_DATA_CHOICES, OUTPUT_TISSUE_DATA_CHOICES from ..subjects.models import Group, Individual, Set @@ -83,8 +83,8 @@ class Intervention(Valueable,models.Model): ###### #probably should be deleted - category = models.IntegerField(choices=PROTOCOL_CHOICES,null=True,blank=True) - choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True,blank=True) + category = models.CharField(max_length=CHAR_MAX_LENGTH,choices=INTERVENTION_CHOICES,null=True,blank=True) + #choice = models.CharField(max_length=CHAR_MAX_LENGTH, null=True,blank=True) @property def intervention_data(self): @@ -92,7 +92,7 @@ def intervention_data(self): :return: """ - return PROTOCOL_CHOICES[self.category] + return INTERVENTION_CHOICES[self.category] @property def choices(self): diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 64190364..93c7fa88 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -4,7 +4,7 @@ from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet, Timecourse from pkdb_app.serializers import ParserSerializer from pkdb_app.subjects.models import Individual, Group -from pkdb_app.utils import un_map +from pkdb_app.utils import un_map, validate_input class SubstanceSerializer(serializers.ModelSerializer): @@ -24,7 +24,7 @@ class InterventionSerializer(ParserSerializer): class Meta: model = Intervention - fields = ["name","route","form","application","time","time_unit","value","unit","substance"] + fields = ["category","name","route","form","application","time","time_unit","value","unit","substance"] def to_internal_value(self, data): """ @@ -37,6 +37,11 @@ def to_internal_value(self, data): data = self.strip(data) return super().to_internal_value(data) + def validate(self,data): + validated_data = super().validate(data) + return validate_input(validated_data,"intervention") + + def to_representation(self, instance): rep = super().to_representation(instance) return un_map(rep) diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index e11b9acf..43c0f28e 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -10,13 +10,12 @@ def create(self, *args, **kwargs): group = super(GroupManager, self).create(*args, **kwargs) group.characteristica.all().delete() for characteristica_single in characteristica: - characteristica_single["count"] = characteristica_single.get("count",group.count) + characteristica_single["count"] = characteristica_single.get("count", group.count) group.characteristica.create(**characteristica_single) - group.save() - return group + class GroupSetManager(models.Manager): def create(self, *args, **kwargs): characteristica = kwargs.pop("characteristica", []) @@ -26,7 +25,6 @@ def create(self, *args, **kwargs): groupset.characteristica.all().delete() groupset.groups.all().delete() - for characteristica_single in characteristica: groupset.characteristica.create(**characteristica_single) @@ -37,6 +35,7 @@ def create(self, *args, **kwargs): return groupset + class IndividualManager(models.Manager): def create(self, *args, **kwargs): characteristica = kwargs.pop("characteristica", []) @@ -57,7 +56,6 @@ def create(self, *args, **kwargs): individualset.characteristica.all().delete() individualset.individuals.all().delete() - for characteristica_single in characteristica: individualset.characteristica.create(**characteristica_single) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index d31559aa..2c70a9be 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -5,7 +5,6 @@ How is different from things which will be measured? From the data structure this has to be handled very similar. """ - from django.db import models from ..behaviours import Valueable, Describable, ValueableMap, Sourceable from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, CHARACTERISTICA_CHOICES, GROUP_CRITERIA, \ @@ -13,22 +12,15 @@ from ..utils import CHAR_MAX_LENGTH from .managers import GroupManager, GroupSetManager, IndividualManager, IndividualSetManager - # TODO: Add ExclusionCriteria as extra class on group | or via field ? # Not clear what is best: The important thing is that stated exclusion criteria # must be encodable and be found as such (often via cutoffs) # - how to represent cutoff & negation - # - Exclusion/Inclusion # - Group # - Intervention - # - DataSets/Output - - - - class Set(Describable, models.Model): """ abstarct class for all set classes @@ -111,7 +103,6 @@ def __str__(self): return self.name - class Characteristica(ValueableMap,Valueable, models.Model): """ Characteristic. @@ -159,18 +150,6 @@ def choices(self): return self.characteristic_data.choices - #def validate(self): - # """ Check that choices are valid. I.e. that choice is allowed choice from choices for - # characteristics. - - # Add checks for individuals and groups. For instance if count==1 than value must be filled, - # but not entries in mean, median, ... - - # :return: - # """ - # raise NotImplemented - - class CleanCharacteristica(Characteristica): """ Processed and normalized data (calculated on change from corresponding raw CharacteristicValue. @@ -178,11 +157,4 @@ class CleanCharacteristica(Characteristica): - convert exclusion to inclusion criteria """ raw = models.ForeignKey(Characteristica, related_name="clean", null=True, on_delete=True) - - # method field? for different processing? - # TODO: add methods for doing the processing & automatic update if corresponding - # Value is changed. - # -> move to a ProcessedValuable - - diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 1bd211c2..7bc695de 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,185 +1,124 @@ -import pandas as pd -from django.core.exceptions import ValidationError from rest_framework import serializers - from pkdb_app.behaviours import Sourceable -from pkdb_app.categoricals import FORMAT_MAPPING, CHARACTERISTIC_DICT, CATEGORIAL_TYPE, NUMERIC_TYPE, BOOLEAN_TYPE -from pkdb_app.utils import un_map -from .models import Group, GroupSet,Individual,IndividualSet,Characteristica +from pkdb_app.utils import un_map, validate_input +from .models import Group, GroupSet, Individual, IndividualSet, Characteristica from ..serializers import ParserSerializer -BASE_FIELDS = () -from collections import OrderedDict - - class CharacteristicaSerializer(ParserSerializer): - count = serializers.IntegerField(required=False) class Meta: model = Characteristica - fields = ["category","choice","ctype","count","value","mean","median","min","max","sd","se","cv","unit", - "count_map","value_map","mean_map","median_map","min_map","max_map","sd_map","se_map","cv_map","unit_map"] - + fields = ["category", "choice", "ctype", "count", "value", "mean", "median", "min", "max", "sd", "se", "cv", + "unit", "count_map", "value_map", "mean_map", "median_map", "min_map", "max_map", "sd_map", "se_map", + "cv_map", "unit_map"] def to_representation(self, instance): result = super().to_representation(instance) if result["ctype"] == "group": result.pop("ctype") - return un_map(result) - - - - - def to_internal_value(self, data): - """ - - :param data: - :return: - """ data = self.split_to_map(data) - characteristic = CHARACTERISTIC_DICT[data.get("category")] - choice = data.get("choice",None) - unit = data.get("unit",None) - #fields_require_unit = ["value","mean","median","min","max","sd","se","cv","value_map","mean_map","median_map","min_map","max_map","sd_map","se_map","cv_map"] - - if choice: - if (characteristic.dtype == CATEGORIAL_TYPE or characteristic.dtype == BOOLEAN_TYPE): - if not choice in characteristic.choices: - msg = f"{choice} is not part of {characteristic.choices} for {characteristic.value}" - raise ValidationError(msg) - - #if any(k in fields_require_unit for k in data.keys()): - elif characteristic.dtype == NUMERIC_TYPE: - if not unit in characteristic.units: - msg = f"{unit} is not allowed but required. For {characteristic.value} allowed units are {characteristic.units}" - raise ValidationError(msg) - - - return super(CharacteristicaSerializer, self).to_internal_value(data) + def validate(self, attrs): + data = super().validate(attrs) + return validate_input(data, "characteristica") + class GroupSerializer(ParserSerializer): - characteristica = CharacteristicaSerializer(many=True,read_only=False, required=False) + characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) class Meta: model = Group - fields = ["name","count","characteristica"] - + fields = ["name", "count", "characteristica"] def to_internal_value(self, data): - """ - - :param data: - :return: - """ - data = self.generic_parser(data,"characteristica") + data = self.generic_parser(data, "characteristica") return super(GroupSerializer, self).to_internal_value(data) class GroupSetSerializer(ParserSerializer): - characteristica = CharacteristicaSerializer(many=True,read_only=False, required=False) + characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) groups = GroupSerializer(many=True, read_only=False) class Meta: model = GroupSet - fields = ["description","characteristica","groups"] + fields = ["description", "characteristica", "groups"] def to_internal_value(self, data): - """ - - :param data: - :return: - """ - data = self.generic_parser(data,"characteristica") + data = self.generic_parser(data, "characteristica") return super(GroupSetSerializer, self).to_internal_value(data) class GroupSRField(serializers.SlugRelatedField): def get_queryset(self): study = self.context["study"] - queryset = Group.objects.filter(groupset__study__sid = study) + queryset = Group.objects.filter(groupset__study__sid=study) return queryset -class IndividualSerializer(ParserSerializer): - - characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False,allow_null=True) - group = GroupSRField( slug_field='name',read_only=False,required=False, allow_null=True) #todo: filter for only this study - - #todo:add figure +class IndividualSerializer(ParserSerializer): + characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False, allow_null=True) + group = GroupSRField(slug_field='name', read_only=False, required=False, allow_null=True) class Meta: model = Individual - fields = Sourceable.fields() + ["name","name_map", "group_map", "characteristica","group"] + fields = Sourceable.fields() + ["name", "name_map", "group_map", "characteristica", "group"] def to_internal_value(self, data): - """ - - :param data: - :return: - """ data = self.generic_parser(data, "characteristica") data = self.split_to_map(data) - #data = self.parse_individuals(data) #todo: this has to be done on CleanIndividual - return super(IndividualSerializer, self).to_internal_value(data) def to_representation(self, instance): - rep = super().to_representation(instance) + rep = super().to_representation(instance) if "group" in rep: rep["group"] = instance.group.name - - return un_map(rep) + ''' def parse_individuals(self,data): - try: - individuals = data - unpacked_individuals = [] - for individual in individuals: - src = individual.pop("source") # todo: upload data first and then have the data saved here not the path. - characteristica_mapping = individual.pop("characteristica") - - delimiter = FORMAT_MAPPING[ individual.pop("format")].delimiter - individual_mapping = individual - table = pd.read_csv(src, delimiter=delimiter, keep_default_na=False) - characteristica_table = self.mapping_parser(characteristica_mapping,table) - individuals_table = self.mapping_parser(individual_mapping,table) - individuals_table["characteristica"] = characteristica_table.to_dict('records') - unpacked_individuals += individuals_table.to_dict('recods') - - data = unpacked_individuals - - except KeyError: - pass - return data + """ + later for parsing individuals from a dataset + """ + try: + individuals = data + unpacked_individuals = [] + for individual in individuals: + src = individual.pop("source") # todo: upload data first and then have the data saved here not the path. + characteristica_mapping = individual.pop("characteristica") + + delimiter = FORMAT_MAPPING[ individual.pop("format")].delimiter + individual_mapping = individual + table = pd.read_csv(src, delimiter=delimiter, keep_default_na=False) + characteristica_table = self.mapping_parser(characteristica_mapping,table) + individuals_table = self.mapping_parser(individual_mapping,table) + individuals_table["characteristica"] = characteristica_table.to_dict('records') + unpacked_individuals += individuals_table.to_dict('recods') + + data = unpacked_individuals + + except KeyError: + pass + return data + ''' class IndividualSetSerializer(ParserSerializer): - characteristica = CharacteristicaSerializer(many=True,read_only=False, required=False) - individuals = IndividualSerializer(many=True,read_only=False, required=False) - + characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) + individuals = IndividualSerializer(many=True, read_only=False, required=False) class Meta: model = IndividualSet fields = ["description", "individuals", "characteristica"] def to_internal_value(self, data): - """ - - :param data: - :return: - """ - data = self.generic_parser(data,"characteristica") - + data = self.generic_parser(data, "characteristica") return super(IndividualSetSerializer, self).to_internal_value(data) def to_representation(self, instance): - rep = super().to_representation(instance) - return un_map(rep) \ No newline at end of file + return un_map(super().to_representation(instance)) \ No newline at end of file diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index fc47a3c3..edda7c34 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -2,6 +2,8 @@ import os from django.core.exceptions import ValidationError +from pkdb_app.categoricals import CHARACTERISTIC_DICT, CATEGORIAL_TYPE, BOOLEAN_TYPE, NUMERIC_TYPE, INTERVENTION_DICT + CHAR_MAX_LENGTH = 30 def create_if_exists(src,src_key,dest,dest_key): @@ -40,6 +42,27 @@ def get_or_val_error(model, *args, **kwargs): msg = f"{model} instance with args:{args}, kwargs:{kwargs} does not exist" return ValidationError(msg) +def validate_input(data,model_name): + model_categoricals = {"characteristica":CHARACTERISTIC_DICT,"intervention":INTERVENTION_DICT} + category = data.get("category", None) + if category: + model_categorical = model_categoricals[model_name][data.get("category")] + choice = data.get("choice",None) + unit = data.get("unit",None) + + if choice: + if (model_categorical.dtype == CATEGORIAL_TYPE or model_categorical.dtype == BOOLEAN_TYPE): + if not choice in model_categorical.choices: + msg = f"{choice} is not part of {model_categorical.choices} for {model_categorical.value}" + raise ValidationError(msg) + + elif model_categorical.dtype == NUMERIC_TYPE: + if not unit in model_categorical.units: + msg = f"{unit} is not allowed but required. For {model_categorical.value} allowed units are {model_categorical.units}" + raise ValidationError(msg) + + return data + def un_map(data): cleaned_result = {} for k, v in data.items(): From 9c4c076a62c60fc62dbaa58721ce0d4d03d38b71 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 13 Aug 2018 23:54:35 +0200 Subject: [PATCH 042/115] working on files input and on frontend --- {frontend => client}/.babelrc | 3 +- {frontend => client}/.editorconfig | 0 {frontend => client}/.eslintignore | 1 + {frontend => client}/.eslintrc.js | 0 {frontend => client}/.gitignore | 1 + {frontend => client}/.postcssrc.js | 0 {frontend => client}/README.md | 5 +- {frontend => client}/config/dev.env.js | 0 {frontend => client}/config/index.js | 0 {frontend => client}/config/prod.env.js | 0 {frontend => client}/config/test.env.js | 0 {frontend => client}/index.html | 0 {frontend => client}/package-lock.json | 2936 ++++++++++++++--- {frontend => client}/package.json | 19 +- {frontend => client}/src/App.vue | 9 +- {frontend => client}/src/assets/logo.png | Bin client/src/components/Reference.vue | 43 + client/src/http/APIService.js | 22 + {frontend => client}/src/main.js | 2 - {frontend => client}/static/.gitkeep | 0 .../e2e/custom-assertions/elementCount.js | 0 .../test/e2e/nightwatch.conf.js | 0 {frontend => client}/test/e2e/runner.js | 0 {frontend => client}/test/e2e/specs/test.js | 0 client/test/unit/.eslintrc | 7 + client/test/unit/jest.conf.js | 29 + client/test/unit/setup.js | 3 + client/test/unit/specs/HelloWorld.spec.js | 11 + docker-compose.yml | 12 +- frontend/src/router/index.js | 15 - pkdb_app/comments/migrations/0001_initial.py | 2 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/config/common.py | 3 + pkdb_app/data_management/fill_database.py | 21 +- pkdb_app/interventions/models.py | 2 +- pkdb_app/interventions/serializers.py | 15 +- pkdb_app/interventions/views.py | 10 +- pkdb_app/studies/models.py | 4 +- pkdb_app/studies/serializers.py | 3 +- pkdb_app/urls.py | 3 +- requirements.txt | 2 +- 41 files changed, 2695 insertions(+), 492 deletions(-) rename {frontend => client}/.babelrc (66%) rename {frontend => client}/.editorconfig (100%) rename {frontend => client}/.eslintignore (58%) rename {frontend => client}/.eslintrc.js (100%) rename {frontend => client}/.gitignore (90%) rename {frontend => client}/.postcssrc.js (100%) rename {frontend => client}/README.md (92%) rename {frontend => client}/config/dev.env.js (100%) rename {frontend => client}/config/index.js (100%) rename {frontend => client}/config/prod.env.js (100%) rename {frontend => client}/config/test.env.js (100%) rename {frontend => client}/index.html (100%) rename {frontend => client}/package-lock.json (84%) rename {frontend => client}/package.json (81%) rename {frontend => client}/src/App.vue (70%) rename {frontend => client}/src/assets/logo.png (100%) create mode 100644 client/src/components/Reference.vue create mode 100644 client/src/http/APIService.js rename {frontend => client}/src/main.js (88%) rename {frontend => client}/static/.gitkeep (100%) rename {frontend => client}/test/e2e/custom-assertions/elementCount.js (100%) rename {frontend => client}/test/e2e/nightwatch.conf.js (100%) rename {frontend => client}/test/e2e/runner.js (100%) rename {frontend => client}/test/e2e/specs/test.js (100%) create mode 100644 client/test/unit/.eslintrc create mode 100644 client/test/unit/jest.conf.js create mode 100644 client/test/unit/setup.js create mode 100644 client/test/unit/specs/HelloWorld.spec.js delete mode 100644 frontend/src/router/index.js diff --git a/frontend/.babelrc b/client/.babelrc similarity index 66% rename from frontend/.babelrc rename to client/.babelrc index d530c00f..9390d164 100644 --- a/frontend/.babelrc +++ b/client/.babelrc @@ -11,7 +11,8 @@ "plugins": ["transform-vue-jsx", "transform-runtime"], "env": { "test": { - "presets": ["env", "stage-2"] + "presets": ["env", "stage-2"], + "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"] } } } diff --git a/frontend/.editorconfig b/client/.editorconfig similarity index 100% rename from frontend/.editorconfig rename to client/.editorconfig diff --git a/frontend/.eslintignore b/client/.eslintignore similarity index 58% rename from frontend/.eslintignore rename to client/.eslintignore index e1fcc9c4..e2192c5c 100644 --- a/frontend/.eslintignore +++ b/client/.eslintignore @@ -2,3 +2,4 @@ /config/ /dist/ /*.js +/test/unit/coverage/ diff --git a/frontend/.eslintrc.js b/client/.eslintrc.js similarity index 100% rename from frontend/.eslintrc.js rename to client/.eslintrc.js diff --git a/frontend/.gitignore b/client/.gitignore similarity index 90% rename from frontend/.gitignore rename to client/.gitignore index e82290f5..dfb4167f 100644 --- a/frontend/.gitignore +++ b/client/.gitignore @@ -4,6 +4,7 @@ node_modules/ npm-debug.log* yarn-debug.log* yarn-error.log* +/test/unit/coverage/ /test/e2e/reports/ selenium-debug.log diff --git a/frontend/.postcssrc.js b/client/.postcssrc.js similarity index 100% rename from frontend/.postcssrc.js rename to client/.postcssrc.js diff --git a/frontend/README.md b/client/README.md similarity index 92% rename from frontend/README.md rename to client/README.md index 4d2ca44a..c6fd5fc3 100644 --- a/frontend/README.md +++ b/client/README.md @@ -1,6 +1,6 @@ # frontend -> pkdb: pharmacokinetical data +> pkdb ## Build Setup @@ -17,6 +17,9 @@ npm run build # build for production and view the bundle analyzer report npm run build --report +# run unit tests +npm run unit + # run e2e tests npm run e2e diff --git a/frontend/config/dev.env.js b/client/config/dev.env.js similarity index 100% rename from frontend/config/dev.env.js rename to client/config/dev.env.js diff --git a/frontend/config/index.js b/client/config/index.js similarity index 100% rename from frontend/config/index.js rename to client/config/index.js diff --git a/frontend/config/prod.env.js b/client/config/prod.env.js similarity index 100% rename from frontend/config/prod.env.js rename to client/config/prod.env.js diff --git a/frontend/config/test.env.js b/client/config/test.env.js similarity index 100% rename from frontend/config/test.env.js rename to client/config/test.env.js diff --git a/frontend/index.html b/client/index.html similarity index 100% rename from frontend/index.html rename to client/index.html diff --git a/frontend/package-lock.json b/client/package-lock.json similarity index 84% rename from frontend/package-lock.json rename to client/package-lock.json index b44f7e8f..d4fb01f8 100644 --- a/frontend/package-lock.json +++ b/client/package-lock.json @@ -160,6 +160,30 @@ } } }, + "@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "dev": true + }, + "@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true + }, + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -193,6 +217,15 @@ } } }, + "acorn-globals": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.1.0.tgz", + "integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==", + "dev": true, + "requires": { + "acorn": "^5.0.0" + } + }, "acorn-jsx": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", @@ -255,6 +288,17 @@ "kind-of": "^3.0.2", "longest": "^1.0.1", "repeat-string": "^1.5.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "alphanum-sort": { @@ -263,6 +307,12 @@ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", "dev": true }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, "ansi-escapes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", @@ -300,6 +350,15 @@ "normalize-path": "^2.1.1" } }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -333,6 +392,12 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -452,6 +517,12 @@ "integrity": "sha512-oJjo+5e7/vEc2FBK8gUalV0pba4L3VdBIs2EKhOLHLcOd2FgQIVQN9xb0eZ9IjEWyAL7vq6fGJxOvVvdCHNyMw==", "dev": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", @@ -511,6 +582,15 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -796,6 +876,16 @@ "babel-template": "^6.24.1" } }, + "babel-jest": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-21.2.0.tgz", + "integrity": "sha512-O0W2qLoWu1QOoOGgxiR2JID4O6WSpxPiQanrkyi9SSlM0PJ60Ptzlck47lhtnr9YZO3zYOsxHwnyeWJ6AffoBQ==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "^4.0.0", + "babel-preset-jest": "^21.2.0" + } + }, "babel-loader": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", @@ -825,6 +915,56 @@ "babel-runtime": "^6.22.0" } }, + "babel-plugin-dynamic-import-node": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-1.2.0.tgz", + "integrity": "sha512-yeDwKaLgGdTpXL7RgGt5r6T4LmnTza/hUn5Ul8uZSGGMtEjYo13Nxai7SQaGCTEzUtg9Zq9qJn0EjEr7SeSlTQ==", + "dev": true, + "requires": { + "babel-plugin-syntax-dynamic-import": "^6.18.0" + } + }, + "babel-plugin-istanbul": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", + "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.13.0", + "find-up": "^2.1.0", + "istanbul-lib-instrument": "^1.10.1", + "test-exclude": "^4.2.1" + } + }, + "babel-plugin-jest-hoist": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz", + "integrity": "sha512-yi5QuiVyyvhBUDLP4ButAnhYzkdrUwWDtvUJv71hjH3fclhnZg4HkDeqaitcR2dZZx/E67kGkRcPVjtVu+SJfQ==", + "dev": true + }, + "babel-plugin-jsx-event-modifiers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-event-modifiers/-/babel-plugin-jsx-event-modifiers-2.0.5.tgz", + "integrity": "sha512-tWGnCk0whZ+nZcj9tYLw4+y08tPJXqaEjIxRJZS6DkUUae72Kz4BsoGpxt/Kow7mmgQJpvFCw8IPLSNh5rkZCg==", + "dev": true + }, + "babel-plugin-jsx-v-model": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-v-model/-/babel-plugin-jsx-v-model-2.0.3.tgz", + "integrity": "sha512-SIx3Y3XxwGEz56Q1atwr5GaZsxJ2IRYmn5dl38LFkaTAvjnbNQxsZHO+ylJPsd+Hmv+ixJBYYFEekPBTHwiGfQ==", + "dev": true, + "requires": { + "babel-plugin-syntax-jsx": "^6.18.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + } + }, + "babel-plugin-jsx-vue-functional": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-vue-functional/-/babel-plugin-jsx-vue-functional-2.1.0.tgz", + "integrity": "sha1-VjCgyG/hkE0owwRl5r8c9xI1ojk=", + "dev": true + }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", @@ -1268,6 +1408,16 @@ } } }, + "babel-preset-jest": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-21.2.0.tgz", + "integrity": "sha512-hm9cBnr2h3J7yXoTtAVV0zg+3vg0Q/gT2GYuzlreTU0EPkJRtlNgKJJ3tBKEn0+VjAi3JykV6xCJkuUYttEEfA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^21.2.0", + "babel-plugin-syntax-object-rest-spread": "^6.13.0" + } + }, "babel-preset-stage-2": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", @@ -1293,6 +1443,34 @@ "babel-plugin-transform-object-rest-spread": "^6.22.0" } }, + "babel-preset-vue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/babel-preset-vue/-/babel-preset-vue-1.2.1.tgz", + "integrity": "sha512-a/Z+6SJ4GXyAoCMfYidDH6OzXnccPNJ5nEaPMjALqCkP9SJkqxz9V0uUS//sGuWszcD8kibdwJRzU+brl8DdFQ==", + "dev": true, + "requires": { + "babel-helper-vue-jsx-merge-props": "^2.0.2", + "babel-plugin-jsx-event-modifiers": "^2.0.2", + "babel-plugin-jsx-v-model": "^2.0.1", + "babel-plugin-jsx-vue-functional": "^2.1.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "babel-plugin-transform-vue-jsx": "^3.5.0" + } + }, + "babel-preset-vue-app": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/babel-preset-vue-app/-/babel-preset-vue-app-1.3.2.tgz", + "integrity": "sha512-PLyyyVdrvgL4szMF7D5SuUhy85aBzy0+s5MO2QhpTwVqfW0qVaPFJi6K3d25CKz1nOV437JgpVvPj1W6tLGJ5g==", + "dev": true, + "requires": { + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0", + "babel-plugin-transform-runtime": "^6.15.0", + "babel-preset-env": "^1.6.0", + "babel-preset-vue": "^1.2.1", + "babel-runtime": "^6.20.0" + } + }, "babel-register": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", @@ -1424,12 +1602,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -1633,6 +1805,29 @@ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, + "browser-process-hrtime": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz", + "integrity": "sha1-Ql1opY00R/AqBKqJQYf86K+Le44=", + "dev": true + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, "browser-stdout": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", @@ -1720,6 +1915,15 @@ "electron-to-chromium": "^1.3.30" } }, + "bser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", + "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, "buffer": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", @@ -1885,11 +2089,20 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30000874", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000874.tgz", - "integrity": "sha512-29nr1EPiHwrJTAHHsEmTt2h+55L8j2GNFdAcYPlRy2NX6iFz7ZZiepVI7kP/QqlnHLq3KvfWpbmGa0d063U09w==", + "version": "1.0.30000876", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000876.tgz", + "integrity": "sha512-v+Q2afhJJ1oydQnEB4iHhxDz5x9lWPbRnQBQlM3FgtZxqLO8KDSdu4txUrFwC1Ws9I2kQi/QImkvj17NbVpNAg==", "dev": true }, + "capture-exit": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz", + "integrity": "sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28=", + "dev": true, + "requires": { + "rsvp": "^3.3.3" + } + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -1958,6 +2171,29 @@ "path-is-absolute": "^1.0.0", "readdirp": "^2.0.0", "upath": "^1.0.5" + }, + "dependencies": { + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + } } }, "chownr": { @@ -1979,6 +2215,12 @@ "request": "^2.87.0" } }, + "ci-info": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz", + "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==", + "dev": true + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -2227,6 +2469,12 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "compare-versions": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.3.0.tgz", + "integrity": "sha512-MAAAIOdi2s4Gl6rZ76PNcUa9IOYB+5ICdT41o5uMRf09aEu/F9RK+qhe8RjXNPwcTjGV7KU7h2P/fljThFVqyQ==", + "dev": true + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", @@ -2275,6 +2523,47 @@ "typedarray": "^0.0.6" } }, + "condense-newlines": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz", + "integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-whitespace": "^0.3.0", + "kind-of": "^3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "config-chain": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", + "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "connect-history-api-fallback": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", @@ -2390,6 +2679,12 @@ "pify": "^3.0.0", "slash": "^1.0.0" } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true } } }, @@ -2794,6 +3089,21 @@ } } }, + "cssom": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz", + "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==", + "dev": true + }, + "cssstyle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.0.0.tgz", + "integrity": "sha512-Bpuh47j2mRMY60X90mXaJAEtJwxvA2roZzbgwAXYhMbmwmakdRr4Cq9L5SkleKJNLOKqHIa2YWyOXDX3VgggSQ==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, "cuint": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", @@ -2839,6 +3149,25 @@ "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", "dev": true }, + "data-urls": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.0.tgz", + "integrity": "sha512-ai40PPQR0Fn1lD2PPie79CibnlMN2AYiDhwFX/rZHVsxbs5kNJSjegqXIprhouGXlRdEnfybva7kqRGnB6mypA==", + "dev": true, + "requires": { + "abab": "^1.0.4", + "whatwg-mimetype": "^2.0.0", + "whatwg-url": "^6.4.0" + }, + "dependencies": { + "abab": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", + "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", + "dev": true + } + } + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -2893,6 +3222,23 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, "define-properties": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", @@ -2941,12 +3287,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -2987,6 +3327,14 @@ "p-map": "^1.1.1", "pify": "^3.0.0", "rimraf": "^2.2.8" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "delayed-stream": { @@ -3026,6 +3374,12 @@ "repeating": "^2.0.0" } }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, "detect-node": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", @@ -3033,9 +3387,9 @@ "dev": true }, "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, "diffie-hellman": { @@ -3057,6 +3411,23 @@ "requires": { "arrify": "^1.0.1", "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "dns-equal": { @@ -3148,6 +3519,15 @@ "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", "dev": true }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, "domhandler": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", @@ -3196,6 +3576,30 @@ "safer-buffer": "^2.1.0" } }, + "editorconfig": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.13.3.tgz", + "integrity": "sha512-WkjsUNVCu+ITKDj73QDvi0trvpdDWdkDyHybDGSXPfekLCqwmpD7CP7iPbvBgosNuLcI96XTDwNa75JyFl7tEQ==", + "dev": true, + "requires": { + "bluebird": "^3.0.5", + "commander": "^2.9.0", + "lru-cache": "^3.2.0", + "semver": "^5.1.0", + "sigmund": "^1.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz", + "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=", + "dev": true, + "requires": { + "pseudomap": "^1.0.1" + } + } + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3320,9 +3724,9 @@ } }, "es5-ext": { - "version": "0.10.45", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz", - "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", + "version": "0.10.46", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz", + "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==", "dev": true, "requires": { "es6-iterator": "~2.0.3", @@ -3645,9 +4049,9 @@ } }, "eslint-plugin-import": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", - "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", + "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", "dev": true, "requires": { "contains-path": "^0.1.0", @@ -3671,29 +4075,77 @@ "esutils": "^2.0.2", "isarray": "^1.0.0" } - } - } - }, - "eslint-plugin-node": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz", - "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==", - "dev": true, - "requires": { - "ignore": "^3.3.6", - "minimatch": "^3.0.4", - "resolve": "^1.3.3", - "semver": "5.3.0" - }, - "dependencies": { - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true - } - } - }, + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz", + "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==", + "dev": true, + "requires": { + "ignore": "^3.3.6", + "minimatch": "^3.0.4", + "resolve": "^1.3.3", + "semver": "5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, "eslint-plugin-promise": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz", @@ -3824,6 +4276,15 @@ "safe-buffer": "^5.1.1" } }, + "exec-sh": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", + "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", + "dev": true, + "requires": { + "merge": "^1.2.0" + } + }, "execa": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", @@ -3839,6 +4300,12 @@ "strip-eof": "^1.0.0" } }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -3913,9 +4380,32 @@ "requires": { "isarray": "1.0.0" } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } } } }, + "expect": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-22.4.3.tgz", + "integrity": "sha512-XcNXEPehqn8b/jm8FYotdX0YrXn36qp4HWlrVT4ktwQas1l1LPxiVWncYnnL2eyMtKAmVIaG0XAp0QlrqJaxaA==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "jest-diff": "^22.4.3", + "jest-get-type": "^22.4.3", + "jest-matcher-utils": "^22.4.3", + "jest-message-util": "^22.4.3", + "jest-regex-util": "^22.4.3" + } + }, "express": { "version": "4.16.3", "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", @@ -4074,12 +4564,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -4146,6 +4630,15 @@ "websocket-driver": ">=0.5.1" } }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "^2.0.0" + } + }, "fd-slicer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", @@ -4238,6 +4731,16 @@ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", "dev": true }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, "filesize": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", @@ -4290,6 +4793,16 @@ } } }, + "find-babel-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.1.0.tgz", + "integrity": "sha1-rMAQQ6Z0n+w0Qpvmtk9ULrtdY1U=", + "dev": true, + "requires": { + "json5": "^0.5.1", + "path-exists": "^3.0.0" + } + }, "find-cache-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", @@ -4350,12 +4863,6 @@ "pify": "^2.0.0", "pinkie-promise": "^2.0.0" } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true } } }, @@ -4376,10 +4883,9 @@ } }, "follow-redirects": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.2.tgz", - "integrity": "sha512-kssLorP/9acIdpQ2udQVTiCS5LQmdEz9mvdIfDcl1gYX2tPKFADHSyFdvJS040XdFsPzemWtgI3q8mFVCxtX8A==", - "dev": true, + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.3.tgz", + "integrity": "sha512-Q19GwKpz/zVkwVzbEkICtentX0NKcCix7g1l3vNewCLZ6KwGAU7bdJEQEZb9NN0D9kapySzQPMrOuj6rvrLXnQ==", "requires": { "debug": "^3.1.0" }, @@ -4388,7 +4894,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -5168,15 +5673,6 @@ "is-glob": "^2.0.0" }, "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", @@ -5195,22 +5691,27 @@ } }, "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "^2.0.0" }, "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "^1.0.0" } } } @@ -5232,14 +5733,6 @@ "object-assign": "^4.0.1", "pify": "^2.0.0", "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } } }, "graceful-fs": { @@ -5274,6 +5767,14 @@ "requires": { "duplexer": "^0.1.1", "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "handle-thing": { @@ -5282,6 +5783,69 @@ "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=", "dev": true }, + "handlebars": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "dev": true, + "requires": { + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + } + } + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -5289,12 +5853,12 @@ "dev": true }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "dev": true, "requires": { - "ajv": "^5.1.0", + "ajv": "^5.3.0", "har-schema": "^2.0.0" } }, @@ -5431,6 +5995,15 @@ "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", "dev": true }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, "html-entities": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", @@ -5452,6 +6025,12 @@ "uglify-js": "3.4.x" } }, + "html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", + "dev": true + }, "html-webpack-plugin": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz", @@ -5646,6 +6225,15 @@ "is-extglob": "^2.1.0" } }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", @@ -5835,6 +6423,12 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, "inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", @@ -5929,6 +6523,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-arrayish": { @@ -5949,8 +6554,7 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-builtin-module": { "version": "1.0.0", @@ -5967,6 +6571,15 @@ "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", "dev": true }, + "is-ci": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz", + "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==", + "dev": true, + "requires": { + "ci-info": "^1.0.0" + } + }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", @@ -5974,6 +6587,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-date-object": { @@ -6049,6 +6673,12 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-generator-fn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", + "integrity": "sha1-lp1J4bszKfa7fwkIm+JleLLd1Go=", + "dev": true + }, "is-glob": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", @@ -6065,6 +6695,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-path-cwd": { @@ -6172,6 +6813,12 @@ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, + "is-whitespace": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz", + "integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38=", + "dev": true + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -6208,35 +6855,999 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, - "js-base64": { - "version": "2.4.8", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.8.tgz", - "integrity": "sha512-hm2nYpDrwoO/OzBhdcqs/XGT6XjSuSSCVEpia+Kl2J6x4CYt5hISlVL/AYU1khoDXv0AQVgxtdJySb9gjAn56Q==", - "dev": true - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "js-yaml": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", - "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^2.6.0" - } - }, - "jsbn": { + "istanbul-api": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.1.tgz", + "integrity": "sha512-duj6AlLcsWNwUpfyfHt0nWIeRiZpuShnP40YTxOGQgtaN8fd6JYSxsvxUphTDy8V5MfDXo4s/xVCIIvVCO808g==", + "dev": true, + "requires": { + "async": "^2.1.4", + "compare-versions": "^3.1.0", + "fileset": "^2.0.2", + "istanbul-lib-coverage": "^1.2.0", + "istanbul-lib-hook": "^1.2.0", + "istanbul-lib-instrument": "^1.10.1", + "istanbul-lib-report": "^1.1.4", + "istanbul-lib-source-maps": "^1.2.4", + "istanbul-reports": "^1.3.0", + "js-yaml": "^3.7.0", + "mkdirp": "^0.5.1", + "once": "^1.4.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz", + "integrity": "sha512-8O2T/3VhrQHn0XcJbP1/GN7kXMiRAlPi+fj3uEHrjBD8Oz7Py0prSC25C09NuAZS6bgW1NNKAvCSHZXB0irSGA==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.2.0", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "istanbul-lib-coverage": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", + "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.1.tgz", + "integrity": "sha512-eLAMkPG9FU0v5L02lIkcj/2/Zlz9OuluaXikdr5iStk8FDbSwAixTK9TkYxbF0eNnzAJTwM2fkV2A1tpsIp4Jg==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz", + "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", + "dev": true, + "requires": { + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.0", + "semver": "^5.3.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz", + "integrity": "sha512-Azqvq5tT0U09nrncK3q82e/Zjkxa4tkFZv7E6VcqP0QCPn6oNljDPfrZEC/umNXds2t7b8sRJfs6Kmpzt8m2kA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^1.2.0", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz", + "integrity": "sha512-fDa0hwU/5sDXwAklXgAoCJCOsFsBplVQ6WBldz5UwaqOzmDhUK4nfuR7/G//G2lERlblUNJB8P6e8cXq3a7MlA==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.1.2", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.3.0.tgz", + "integrity": "sha512-y2Z2IMqE1gefWUaVjrBm0mSKvUkaBy9Vqz8iwr/r40Y9hBbIteH5wqHG/9DLTfJ9xUnUT2j7A3+VVJ6EaYBllA==", + "dev": true, + "requires": { + "handlebars": "^4.0.3" + } + }, + "jest": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest/-/jest-22.4.4.tgz", + "integrity": "sha512-eBhhW8OS/UuX3HxgzNBSVEVhSuRDh39Z1kdYkQVWna+scpgsrD7vSeBI7tmEvsguPDMnfJodW28YBnhv/BzSew==", + "dev": true, + "requires": { + "import-local": "^1.0.0", + "jest-cli": "^22.4.4" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "jest-cli": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-22.4.4.tgz", + "integrity": "sha512-I9dsgkeyjVEEZj9wrGrqlH+8OlNob9Iptyl+6L5+ToOLJmHm4JwOPatin1b2Bzp5R5YRQJ+oiedx7o1H7wJzhA==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "import-local": "^1.0.0", + "is-ci": "^1.0.10", + "istanbul-api": "^1.1.14", + "istanbul-lib-coverage": "^1.1.1", + "istanbul-lib-instrument": "^1.8.0", + "istanbul-lib-source-maps": "^1.2.1", + "jest-changed-files": "^22.2.0", + "jest-config": "^22.4.4", + "jest-environment-jsdom": "^22.4.1", + "jest-get-type": "^22.1.0", + "jest-haste-map": "^22.4.2", + "jest-message-util": "^22.4.0", + "jest-regex-util": "^22.1.0", + "jest-resolve-dependencies": "^22.1.0", + "jest-runner": "^22.4.4", + "jest-runtime": "^22.4.4", + "jest-snapshot": "^22.4.0", + "jest-util": "^22.4.1", + "jest-validate": "^22.4.4", + "jest-worker": "^22.2.2", + "micromatch": "^2.3.11", + "node-notifier": "^5.2.1", + "realpath-native": "^1.0.0", + "rimraf": "^2.5.4", + "slash": "^1.0.0", + "string-length": "^2.0.0", + "strip-ansi": "^4.0.0", + "which": "^1.2.12", + "yargs": "^10.0.3" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "jest-changed-files": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-22.4.3.tgz", + "integrity": "sha512-83Dh0w1aSkUNFhy5d2dvqWxi/y6weDwVVLU6vmK0cV9VpRxPzhTeGimbsbRDSnEoszhF937M4sDLLeS7Cu/Tmw==", + "dev": true, + "requires": { + "throat": "^4.0.0" + } + }, + "jest-config": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-22.4.4.tgz", + "integrity": "sha512-9CKfo1GC4zrXSoMLcNeDvQBfgtqGTB1uP8iDIZ97oB26RCUb886KkKWhVcpyxVDOUxbhN+uzcBCeFe7w+Iem4A==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^22.4.1", + "jest-environment-node": "^22.4.1", + "jest-get-type": "^22.1.0", + "jest-jasmine2": "^22.4.4", + "jest-regex-util": "^22.1.0", + "jest-resolve": "^22.4.2", + "jest-util": "^22.4.1", + "jest-validate": "^22.4.4", + "pretty-format": "^22.4.0" + } + }, + "jest-diff": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-22.4.3.tgz", + "integrity": "sha512-/QqGvCDP5oZOF6PebDuLwrB2BMD8ffJv6TAGAdEVuDx1+uEgrHpSFrfrOiMRx2eJ1hgNjlQrOQEHetVwij90KA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff": "^3.2.0", + "jest-get-type": "^22.4.3", + "pretty-format": "^22.4.3" + } + }, + "jest-docblock": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-22.4.3.tgz", + "integrity": "sha512-uPKBEAw7YrEMcXueMKZXn/rbMxBiSv48fSqy3uEnmgOlQhSX+lthBqHb1fKWNVmFqAp9E/RsSdBfiV31LbzaOg==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-environment-jsdom": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-22.4.3.tgz", + "integrity": "sha512-FviwfR+VyT3Datf13+ULjIMO5CSeajlayhhYQwpzgunswoaLIPutdbrnfUHEMyJCwvqQFaVtTmn9+Y8WCt6n1w==", + "dev": true, + "requires": { + "jest-mock": "^22.4.3", + "jest-util": "^22.4.3", + "jsdom": "^11.5.1" + } + }, + "jest-environment-node": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-22.4.3.tgz", + "integrity": "sha512-reZl8XF6t/lMEuPWwo9OLfttyC26A5AMgDyEQ6DBgZuyfyeNUzYT8BFo6uxCCP/Av/b7eb9fTi3sIHFPBzmlRA==", + "dev": true, + "requires": { + "jest-mock": "^22.4.3", + "jest-util": "^22.4.3" + } + }, + "jest-get-type": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", + "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", + "dev": true + }, + "jest-haste-map": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-22.4.3.tgz", + "integrity": "sha512-4Q9fjzuPVwnaqGKDpIsCSoTSnG3cteyk2oNVjBX12HHOaF1oxql+uUiqZb5Ndu7g/vTZfdNwwy4WwYogLh29DQ==", + "dev": true, + "requires": { + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.1.11", + "jest-docblock": "^22.4.3", + "jest-serializer": "^22.4.3", + "jest-worker": "^22.4.3", + "micromatch": "^2.3.11", + "sane": "^2.0.0" + }, + "dependencies": { + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + } + } + }, + "jest-jasmine2": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-22.4.4.tgz", + "integrity": "sha512-nK3vdUl50MuH7vj/8at7EQVjPGWCi3d5+6aCi7Gxy/XMWdOdbH1qtO/LjKbqD8+8dUAEH+BVVh7HkjpCWC1CSw==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^22.4.0", + "graceful-fs": "^4.1.11", + "is-generator-fn": "^1.0.0", + "jest-diff": "^22.4.0", + "jest-matcher-utils": "^22.4.0", + "jest-message-util": "^22.4.0", + "jest-snapshot": "^22.4.0", + "jest-util": "^22.4.1", + "source-map-support": "^0.5.0" + }, + "dependencies": { + "source-map-support": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.8.tgz", + "integrity": "sha512-WqAEWPdb78u25RfKzOF0swBpY0dKrNdjc4GvLwm7ScX/o9bj8Eh/YL8mcMhBHYDGl87UkkSXDOFnW4G7GhWhGg==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "jest-leak-detector": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-22.4.3.tgz", + "integrity": "sha512-NZpR/Ls7+ndO57LuXROdgCGz2RmUdC541tTImL9bdUtU3WadgFGm0yV+Ok4Fuia/1rLAn5KaJ+i76L6e3zGJYQ==", + "dev": true, + "requires": { + "pretty-format": "^22.4.3" + } + }, + "jest-matcher-utils": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-22.4.3.tgz", + "integrity": "sha512-lsEHVaTnKzdAPR5t4B6OcxXo9Vy4K+kRRbG5gtddY8lBEC+Mlpvm1CJcsMESRjzUhzkz568exMV1hTB76nAKbA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-get-type": "^22.4.3", + "pretty-format": "^22.4.3" + } + }, + "jest-message-util": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-22.4.3.tgz", + "integrity": "sha512-iAMeKxhB3Se5xkSjU0NndLLCHtP4n+GtCqV0bISKA5dmOXQfEbdEmYiu2qpnWBDCQdEafNDDU6Q+l6oBMd/+BA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0-beta.35", + "chalk": "^2.0.1", + "micromatch": "^2.3.11", + "slash": "^1.0.0", + "stack-utils": "^1.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + } + } + }, + "jest-mock": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-22.4.3.tgz", + "integrity": "sha512-+4R6mH5M1G4NK16CKg9N1DtCaFmuxhcIqF4lQK/Q1CIotqMs/XBemfpDPeVZBFow6iyUNu6EBT9ugdNOTT5o5Q==", + "dev": true + }, + "jest-regex-util": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-22.4.3.tgz", + "integrity": "sha512-LFg1gWr3QinIjb8j833bq7jtQopiwdAs67OGfkPrvy7uNUbVMfTXXcOKXJaeY5GgjobELkKvKENqq1xrUectWg==", + "dev": true + }, + "jest-resolve": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-22.4.3.tgz", + "integrity": "sha512-u3BkD/MQBmwrOJDzDIaxpyqTxYH+XqAXzVJP51gt29H8jpj3QgKof5GGO2uPGKGeA1yTMlpbMs1gIQ6U4vcRhw==", + "dev": true, + "requires": { + "browser-resolve": "^1.11.2", + "chalk": "^2.0.1" + } + }, + "jest-resolve-dependencies": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-22.4.3.tgz", + "integrity": "sha512-06czCMVToSN8F2U4EvgSB1Bv/56gc7MpCftZ9z9fBgUQM7dzHGCMBsyfVA6dZTx8v0FDcnALf7hupeQxaBCvpA==", + "dev": true, + "requires": { + "jest-regex-util": "^22.4.3" + } + }, + "jest-runner": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-22.4.4.tgz", + "integrity": "sha512-5S/OpB51igQW9xnkM5Tgd/7ZjiAuIoiJAVtvVTBcEBiXBIFzWM3BAMPBM19FX68gRV0KWyFuGKj0EY3M3aceeQ==", + "dev": true, + "requires": { + "exit": "^0.1.2", + "jest-config": "^22.4.4", + "jest-docblock": "^22.4.0", + "jest-haste-map": "^22.4.2", + "jest-jasmine2": "^22.4.4", + "jest-leak-detector": "^22.4.0", + "jest-message-util": "^22.4.0", + "jest-runtime": "^22.4.4", + "jest-util": "^22.4.1", + "jest-worker": "^22.2.2", + "throat": "^4.0.0" + } + }, + "jest-runtime": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-22.4.4.tgz", + "integrity": "sha512-WRTj9m///npte1YjuphCYX7GRY/c2YvJImU9t7qOwFcqHr4YMzmX6evP/3Sehz5DKW2Vi8ONYPCFWe36JVXxfw==", + "dev": true, + "requires": { + "babel-core": "^6.0.0", + "babel-jest": "^22.4.4", + "babel-plugin-istanbul": "^4.1.5", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "exit": "^0.1.2", + "graceful-fs": "^4.1.11", + "jest-config": "^22.4.4", + "jest-haste-map": "^22.4.2", + "jest-regex-util": "^22.1.0", + "jest-resolve": "^22.4.2", + "jest-util": "^22.4.1", + "jest-validate": "^22.4.4", + "json-stable-stringify": "^1.0.1", + "micromatch": "^2.3.11", + "realpath-native": "^1.0.0", + "slash": "^1.0.0", + "strip-bom": "3.0.0", + "write-file-atomic": "^2.1.0", + "yargs": "^10.0.3" + }, + "dependencies": { + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "babel-jest": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.4.tgz", + "integrity": "sha512-A9NB6/lZhYyypR9ATryOSDcqBaqNdzq4U+CN+/wcMsLcmKkPxQEoTKLajGfd3IkxNyVBT8NewUK2nWyGbSzHEQ==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "^4.1.5", + "babel-preset-jest": "^22.4.4" + } + }, + "babel-plugin-jest-hoist": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.4.tgz", + "integrity": "sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ==", + "dev": true + }, + "babel-preset-jest": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.4.tgz", + "integrity": "sha512-+dxMtOFwnSYWfum0NaEc0O03oSdwBsjx4tMSChRDPGwu/4wSY6Q6ANW3wkjKpJzzguaovRs/DODcT4hbSN8yiA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^22.4.4", + "babel-plugin-syntax-object-rest-spread": "^6.13.0" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "jest-serializer": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-22.4.3.tgz", + "integrity": "sha512-uPaUAppx4VUfJ0QDerpNdF43F68eqKWCzzhUlKNDsUPhjOon7ZehR4C809GCqh765FoMRtTVUVnGvIoskkYHiw==", + "dev": true + }, + "jest-serializer-vue": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/jest-serializer-vue/-/jest-serializer-vue-0.3.0.tgz", + "integrity": "sha512-Id1x3XabYu2r6BnmTfGk2tY172BEqR+vAzSvPk4VF8HyVqwebxZQbqiZ/giAtCnRSqi6lzxuyvzQbwQ6bo6Hbg==", + "dev": true, + "requires": { + "pretty": "2.0.0" + } + }, + "jest-snapshot": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-22.4.3.tgz", + "integrity": "sha512-JXA0gVs5YL0HtLDCGa9YxcmmV2LZbwJ+0MfyXBBc5qpgkEYITQFJP7XNhcHFbUvRiniRpRbGVfJrOoYhhGE0RQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^22.4.3", + "jest-matcher-utils": "^22.4.3", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^22.4.3" + } + }, + "jest-util": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-22.4.3.tgz", + "integrity": "sha512-rfDfG8wyC5pDPNdcnAlZgwKnzHvZDu8Td2NJI/jAGKEGxJPYiE4F0ss/gSAkG4778Y23Hvbz+0GMrDJTeo7RjQ==", + "dev": true, + "requires": { + "callsites": "^2.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.11", + "is-ci": "^1.0.10", + "jest-message-util": "^22.4.3", + "mkdirp": "^0.5.1", + "source-map": "^0.6.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } + } + }, + "jest-validate": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-22.4.4.tgz", + "integrity": "sha512-dmlf4CIZRGvkaVg3fa0uetepcua44DHtktHm6rcoNVtYlpwe6fEJRkMFsaUVcFHLzbuBJ2cPw9Gl9TKfnzMVwg==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-config": "^22.4.4", + "jest-get-type": "^22.1.0", + "leven": "^2.1.0", + "pretty-format": "^22.4.0" + } + }, + "jest-worker": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-22.4.3.tgz", + "integrity": "sha512-B1ucW4fI8qVAuZmicFxI1R3kr2fNeYJyvIQ1rKcuLYnenFV5K5aMbxFj6J0i00Ju83S8jP2d7Dz14+AvbIHRYQ==", + "dev": true, + "requires": { + "merge-stream": "^1.0.1" + } + }, + "js-base64": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.8.tgz", + "integrity": "sha512-hm2nYpDrwoO/OzBhdcqs/XGT6XjSuSSCVEpia+Kl2J6x4CYt5hISlVL/AYU1khoDXv0AQVgxtdJySb9gjAn56Q==", + "dev": true + }, + "js-beautify": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.7.5.tgz", + "integrity": "sha512-9OhfAqGOrD7hoQBLJMTA+BKuKmoEtTJXzZ7WDF/9gvjtey1koVLuZqIY6c51aPDjbNdNtIXAkiWKVhziawE9Og==", + "dev": true, + "requires": { + "config-chain": "~1.1.5", + "editorconfig": "^0.13.2", + "mkdirp": "~0.5.0", + "nopt": "~3.0.1" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^2.6.0" + } + }, + "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true, "optional": true }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + } + }, "jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", @@ -6267,6 +7878,15 @@ "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", "dev": true }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -6291,6 +7911,12 @@ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "dev": true }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -6316,13 +7942,10 @@ "dev": true }, "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true }, "last-call-webpack-plugin": { "version": "2.1.2", @@ -6349,6 +7972,18 @@ "invert-kv": "^1.0.0" } }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -6360,23 +7995,16 @@ } }, "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" } }, "loader-fs-cache": { @@ -6650,6 +8278,12 @@ "integrity": "sha1-lU73UEkmIDjJbR/Jiyj9r58Hcqo=", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -6719,6 +8353,23 @@ "dev": true, "requires": { "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" } }, "map-cache": { @@ -6807,99 +8458,35 @@ "trim-newlines": "^1.0.0" }, "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } } } }, + "merge": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", + "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", + "dev": true + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -6925,14 +8512,6 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } } }, "miller-rabin": { @@ -7090,6 +8669,12 @@ "ms": "0.7.1" } }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, "glob": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz", @@ -7144,8 +8729,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "multicast-dns": { "version": "6.2.3", @@ -7193,14 +8777,6 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } } }, "natural-compare": { @@ -7277,12 +8853,36 @@ "lower-case": "^1.1.1" } }, + "node-cache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-4.2.0.tgz", + "integrity": "sha512-obRu6/f7S024ysheAjoYFEEBqqDWv4LOMNJEuO8vMeEw2AT4z+NCzO4hlc2lhI4vATzbCQv6kke9FVdx0RbCOw==", + "dev": true, + "requires": { + "clone": "2.x", + "lodash": "4.x" + }, + "dependencies": { + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + } + } + }, "node-forge": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", "dev": true }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, "node-libs-browser": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", @@ -7326,6 +8926,15 @@ "which": "^1.3.0" } }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -7395,10 +9004,16 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "nwsapi": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.8.tgz", + "integrity": "sha512-7RZ+qbFGiVc6v14Y8DSZjPN1wZPOaMbiiP4tzf5eNuyOITAeOIA3cMhjuKUypVIqBgCSg1KaSyAv8Ocq/0ZJ1A==", + "dev": true + }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, "object-assign": { @@ -7426,6 +9041,15 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } } } }, @@ -7450,6 +9074,16 @@ "isobject": "^3.0.0" } }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, "object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", @@ -7509,9 +9143,9 @@ } }, "opener": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", - "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.0.tgz", + "integrity": "sha512-MD4s/o61y2slS27zm2s4229V2gAUHX0/e3/XOmY/jsXwhysjjCIHN8lx7gqZCrZk19ym+HjCUWHeMKD7YJtKCQ==", "dev": true }, "opn": { @@ -7766,6 +9400,12 @@ "error-ex": "^1.2.0" } }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", @@ -7827,12 +9467,14 @@ "dev": true }, "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "pify": "^3.0.0" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pbkdf2": { @@ -7861,9 +9503,9 @@ "dev": true }, "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { @@ -7896,6 +9538,12 @@ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, "portfinder": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.16.tgz", @@ -10005,6 +11653,28 @@ "integrity": "sha512-McHPg0n1pIke+A/4VcaS2en+pTNjy4xF+Uuq86u/5dyDO59/TtFZtQ708QIRkEZ3qwKz3GVkVa6mpxK/CpB8Rg==", "dev": true }, + "pretty": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz", + "integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=", + "dev": true, + "requires": { + "condense-newlines": "^0.2.1", + "extend-shallow": "^2.0.1", + "js-beautify": "^1.6.12" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "pretty-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", @@ -10015,6 +11685,24 @@ "utila": "~0.4" } }, + "pretty-format": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.4.3.tgz", + "integrity": "sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -10045,6 +11733,12 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, "proxy-addr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", @@ -10091,6 +11785,12 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "dev": true + }, "public-encrypt": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", @@ -10187,12 +11887,6 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -10240,54 +11934,50 @@ "dev": true, "requires": { "pify": "^2.3.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } } }, "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "^2.0.0", + "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "dependencies": { - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "pify": "^2.0.0" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } } } }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -10315,6 +12005,15 @@ "set-immediate-shim": "^1.0.1" } }, + "realpath-native": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.1.tgz", + "integrity": "sha512-W14EcXuqUvKP8dkWkD7B95iMy77lpMnlFXbbk409bQtNCbeu0kvRE5reo+yIZ3JXxg6frbGsz2DLQ39lrCB40g==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -10507,31 +12206,51 @@ } }, "request": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "dev": true, "requires": { "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", + "aws4": "^1.8.0", "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "tough-cookie": "~2.3.3", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "uuid": "^3.3.2" + } + }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "dev": true, + "requires": { + "lodash": "^4.13.1" + } + }, + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "dev": true, + "requires": { + "request-promise-core": "1.1.1", + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" } }, "require-directory": { @@ -10650,6 +12369,12 @@ "inherits": "^2.0.1" } }, + "rsvp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", + "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", + "dev": true + }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", @@ -10704,6 +12429,31 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "sane": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/sane/-/sane-2.5.2.tgz", + "integrity": "sha1-tNwYYcIbQn6SlQej51HiosuKs/o=", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "capture-exit": "^1.2.0", + "exec-sh": "^0.2.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.3", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5", + "watch": "~0.18.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -10903,6 +12653,12 @@ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -11020,12 +12776,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -11036,6 +12786,17 @@ "dev": true, "requires": { "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "sockjs": { @@ -11261,6 +13022,12 @@ "safe-buffer": "^5.1.1" } }, + "stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", + "dev": true + }, "stackframe": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.0.4.tgz", @@ -11294,6 +13061,12 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, "stream-browserify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", @@ -11339,6 +13112,33 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -11385,10 +13185,13 @@ } }, "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } }, "strip-eof": { "version": "1.0.0", @@ -11420,6 +13223,12 @@ "has-flag": "^3.0.0" } }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", + "dev": true + }, "svgo": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", @@ -11435,6 +13244,12 @@ "whet.extend": "~0.9.9" } }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, "table": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", @@ -11455,12 +13270,31 @@ "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=", "dev": true }, + "test-exclude": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz", + "integrity": "sha512-qpqlP/8Zl+sosLxBcVKl9vYy26T9NPalxSzzCP/OY6K7j938ui2oKgo+kRZYfxAeIpLqpbVnsHq1tyV70E4lWQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "micromatch": "^3.1.8", + "object-assign": "^4.1.0", + "read-pkg-up": "^1.0.1", + "require-main-filename": "^1.0.1" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -11513,6 +13347,12 @@ "os-tmpdir": "~1.0.2" } }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", @@ -11532,6 +13372,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "to-regex": { @@ -11563,14 +13414,32 @@ "dev": true }, "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, "requires": { + "psl": "^1.1.24", "punycode": "^1.4.1" } }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", @@ -11589,6 +13458,26 @@ "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", "dev": true }, + "tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "requires": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", @@ -11946,6 +13835,16 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, "utila": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", @@ -12042,6 +13941,32 @@ "integrity": "sha512-2j/t+wIbyVMP5NvctQoSUvLkYKoWAAk2QlQiilrM2a6/ulzFgdcLUJfTvs4XQ/3eZhHiBmmEojbjmM4AzZj8JA==", "dev": true }, + "vue-jest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vue-jest/-/vue-jest-1.4.0.tgz", + "integrity": "sha512-X5YXTXcpklijK3wXG/CiW8Frkz+YPBjR+//FD5rcmlnmEelz+8AQpKA8vhbAHJx3gOhA2tkWt8XEjvxq1S0heg==", + "dev": true, + "requires": { + "babel-core": "^6.25.0", + "babel-preset-vue-app": "^1.3.1", + "chalk": "^2.1.0", + "find-babel-config": "^1.1.0", + "js-beautify": "^1.6.14", + "node-cache": "^4.1.1", + "object-assign": "^4.1.1", + "source-map": "^0.5.6", + "tsconfig": "^7.0.0", + "vue-template-es2015-compiler": "^1.5.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, "vue-loader": { "version": "13.7.2", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-13.7.2.tgz", @@ -12104,11 +14029,6 @@ } } }, - "vue-router": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.1.tgz", - "integrity": "sha512-vLLoY452L+JBpALMP5UHum9+7nzR9PeIBCghU9ZtJ1eWm6ieUI8Zb/DI3MYxH32bxkjzYV1LRjNv4qr8d+uX/w==" - }, "vue-style-loader": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-3.1.2.tgz", @@ -12135,6 +14055,42 @@ "integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==", "dev": true }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "watch": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", + "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", + "dev": true, + "requires": { + "exec-sh": "^0.2.0", + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", @@ -12155,6 +14111,12 @@ "minimalistic-assert": "^1.0.0" } }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, "webpack": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.12.0.tgz", @@ -12215,18 +14177,75 @@ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "supports-color": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", @@ -12271,6 +14290,82 @@ "uglify-js": "^2.8.29", "webpack-sources": "^1.0.1" } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + } + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } } } }, @@ -12292,6 +14387,18 @@ "mkdirp": "^0.5.1", "opener": "^1.4.3", "ws": "^4.0.0" + }, + "dependencies": { + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + } } }, "webpack-dev-middleware": { @@ -12368,16 +14475,6 @@ "ms": "2.0.0" } }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -12393,19 +14490,6 @@ "number-is-nan": "^1.0.0" } }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, "os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", @@ -12415,53 +14499,6 @@ "lcid": "^1.0.0" } }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -12473,15 +14510,6 @@ "strip-ansi": "^3.0.0" } }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, "which-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", @@ -12561,6 +14589,32 @@ "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", "dev": true }, + "whatwg-encoding": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.4.tgz", + "integrity": "sha512-vM9KWN6MP2mIHZ86ytcyIv7e8Cj3KTfO2nd2c8PFDqcI4bxFmQp83ibq4wadq7rL9l9sZV6o9B0LTt8ygGAAXg==", + "dev": true, + "requires": { + "iconv-lite": "0.4.23" + } + }, + "whatwg-mimetype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz", + "integrity": "sha512-FKxhYLytBQiUKjkYteN71fAUA3g6KpNXoho1isLiLSB3N1G4F35Q5vUxWfKFhBwi5IWF27VE6WxhrnnC+m0Mew==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, "whet.extend": { "version": "0.9.9", "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", @@ -12650,16 +14704,32 @@ "mkdirp": "^0.5.1" } }, + "write-file-atomic": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", + "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, "ws": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", - "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", "dev": true, "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0" + "async-limiter": "~1.0.0" } }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, "xregexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", @@ -12694,63 +14764,49 @@ "dev": true }, "yargs": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", - "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", + "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", "dev": true, "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", + "cliui": "^4.0.0", "decamelize": "^1.1.1", + "find-up": "^2.1.0", "get-caller-file": "^1.0.1", "os-locale": "^2.0.0", - "read-pkg-up": "^2.0.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", "string-width": "^2.0.0", "which-module": "^2.0.0", "y18n": "^3.2.1", - "yargs-parser": "^7.0.0" + "yargs-parser": "^8.1.0" }, "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } } }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "ansi-regex": "^3.0.0" } }, "y18n": { @@ -12762,9 +14818,9 @@ } }, "yargs-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", - "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", + "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", "dev": true, "requires": { "camelcase": "^4.1.0" diff --git a/frontend/package.json b/client/package.json similarity index 81% rename from frontend/package.json rename to client/package.json index 7aedf76f..dcee374e 100644 --- a/frontend/package.json +++ b/client/package.json @@ -1,28 +1,32 @@ { "name": "frontend", "version": "1.0.0", - "description": "pkdb: pharmacokinetical data", - "author": "Jan ", + "description": "pkdb ", + "author": "jan Grzegorzewski", "private": true, "scripts": { "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "start": "npm run dev", + "unit": "jest --config test/unit/jest.conf.js --coverage", "e2e": "node test/e2e/runner.js", - "test": "npm run e2e", - "lint": "eslint --ext .js,.vue src test/e2e/specs", + "test": "npm run unit && npm run e2e", + "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs", "build": "node build/build.js" }, "dependencies": { - "vue": "^2.5.2", - "vue-router": "^3.0.1" + "axios": "^0.18.0", + "vue": "^2.5.2" }, "devDependencies": { "autoprefixer": "^7.1.2", "babel-core": "^6.22.1", "babel-eslint": "^8.2.1", "babel-helper-vue-jsx-merge-props": "^2.0.3", + "babel-jest": "^21.0.2", "babel-loader": "^7.1.1", + "babel-plugin-dynamic-import-node": "^1.2.0", "babel-plugin-syntax-jsx": "^6.18.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", "babel-plugin-transform-runtime": "^6.22.0", "babel-plugin-transform-vue-jsx": "^3.5.0", "babel-preset-env": "^1.3.2", @@ -46,6 +50,8 @@ "file-loader": "^1.1.4", "friendly-errors-webpack-plugin": "^1.6.1", "html-webpack-plugin": "^2.30.1", + "jest": "^22.0.4", + "jest-serializer-vue": "^0.3.0", "nightwatch": "^0.9.12", "node-notifier": "^5.1.2", "optimize-css-assets-webpack-plugin": "^3.2.0", @@ -60,6 +66,7 @@ "shelljs": "^0.7.6", "uglifyjs-webpack-plugin": "^1.1.1", "url-loader": "^0.5.8", + "vue-jest": "^1.0.2", "vue-loader": "^13.3.0", "vue-style-loader": "^3.0.1", "vue-template-compiler": "^2.5.2", diff --git a/frontend/src/App.vue b/client/src/App.vue similarity index 70% rename from frontend/src/App.vue rename to client/src/App.vue index d74c648e..a80f105b 100644 --- a/frontend/src/App.vue +++ b/client/src/App.vue @@ -1,13 +1,16 @@ diff --git a/frontend/src/assets/logo.png b/client/src/assets/logo.png similarity index 100% rename from frontend/src/assets/logo.png rename to client/src/assets/logo.png diff --git a/client/src/components/Reference.vue b/client/src/components/Reference.vue new file mode 100644 index 00000000..a3185deb --- /dev/null +++ b/client/src/components/Reference.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/client/src/http/APIService.js b/client/src/http/APIService.js new file mode 100644 index 00000000..9ef2752c --- /dev/null +++ b/client/src/http/APIService.js @@ -0,0 +1,22 @@ +import axios from 'axios'; +const API_URL = 'http://localhost:8000'; +export class APIService{ + constructor(){ +} + + getReferences() { + const url = `${API_URL}/api/v1/references/`; + return axios.get(url).then(response => response.data); + } + + getReference(pk) { + const url = `${API_URL}/api/v1/references/${pk}`; + return axios.get(url).then(response => response.data); + } + + updateReference(product){ + const url = `${API_URL}/api/products/${product.pk}`; + return axios.put(url,product); + } +} + diff --git a/frontend/src/main.js b/client/src/main.js similarity index 88% rename from frontend/src/main.js rename to client/src/main.js index 417390e2..684ffacc 100644 --- a/frontend/src/main.js +++ b/client/src/main.js @@ -2,14 +2,12 @@ // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' -import router from './router' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', - router, components: { App }, template: '' }) diff --git a/frontend/static/.gitkeep b/client/static/.gitkeep similarity index 100% rename from frontend/static/.gitkeep rename to client/static/.gitkeep diff --git a/frontend/test/e2e/custom-assertions/elementCount.js b/client/test/e2e/custom-assertions/elementCount.js similarity index 100% rename from frontend/test/e2e/custom-assertions/elementCount.js rename to client/test/e2e/custom-assertions/elementCount.js diff --git a/frontend/test/e2e/nightwatch.conf.js b/client/test/e2e/nightwatch.conf.js similarity index 100% rename from frontend/test/e2e/nightwatch.conf.js rename to client/test/e2e/nightwatch.conf.js diff --git a/frontend/test/e2e/runner.js b/client/test/e2e/runner.js similarity index 100% rename from frontend/test/e2e/runner.js rename to client/test/e2e/runner.js diff --git a/frontend/test/e2e/specs/test.js b/client/test/e2e/specs/test.js similarity index 100% rename from frontend/test/e2e/specs/test.js rename to client/test/e2e/specs/test.js diff --git a/client/test/unit/.eslintrc b/client/test/unit/.eslintrc new file mode 100644 index 00000000..4d5d98f3 --- /dev/null +++ b/client/test/unit/.eslintrc @@ -0,0 +1,7 @@ +{ + "env": { + "jest": true + }, + "globals": { + } +} diff --git a/client/test/unit/jest.conf.js b/client/test/unit/jest.conf.js new file mode 100644 index 00000000..5f7da172 --- /dev/null +++ b/client/test/unit/jest.conf.js @@ -0,0 +1,29 @@ +const path = require('path') + +module.exports = { + rootDir: path.resolve(__dirname, '../../'), + moduleFileExtensions: [ + 'js', + 'json', + 'vue' + ], + moduleNameMapper: { + '^@/(.*)$': '/src/$1' + }, + transform: { + '^.+\\.js$': '/node_modules/babel-jest', + '.*\\.(vue)$': '/node_modules/vue-jest' + }, + testPathIgnorePatterns: [ + '/test/e2e' + ], + snapshotSerializers: ['/node_modules/jest-serializer-vue'], + setupFiles: ['/test/unit/setup'], + mapCoverage: true, + coverageDirectory: '/test/unit/coverage', + collectCoverageFrom: [ + 'src/**/*.{js,vue}', + '!src/main.js', + '!**/node_modules/**' + ] +} diff --git a/client/test/unit/setup.js b/client/test/unit/setup.js new file mode 100644 index 00000000..edbdbae8 --- /dev/null +++ b/client/test/unit/setup.js @@ -0,0 +1,3 @@ +import Vue from 'vue' + +Vue.config.productionTip = false diff --git a/client/test/unit/specs/HelloWorld.spec.js b/client/test/unit/specs/HelloWorld.spec.js new file mode 100644 index 00000000..cfb04537 --- /dev/null +++ b/client/test/unit/specs/HelloWorld.spec.js @@ -0,0 +1,11 @@ +import Vue from 'vue' +import HelloWorld from '@/components/HelloWorld' + +describe('HelloWorld.vue', () => { + it('should render correct contents', () => { + const Constructor = Vue.extend(HelloWorld) + const vm = new Constructor().$mount() + expect(vm.$el.querySelector('.hello h1').textContent) + .toEqual('Welcome to Your Vue.js App') + }) +}) diff --git a/docker-compose.yml b/docker-compose.yml index 2f6a29e6..7ac5164b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,6 @@ services: ports: - "5433:5432" environment: - POSTGRES_USER : postgres POSTGRES_PASSWORD: pass POSTGRES_DB: postgres @@ -38,3 +37,14 @@ services: - ./:/code ports: - "8001:8001" + + #client: + #build: ./client + #ports: + # - 8080:8080 + #volumes: + # - ./client:/data + #depends_on: + # - web + #environment: + # - API_URL=http://localhost:8081/ diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js deleted file mode 100644 index 5fa7f9d3..00000000 --- a/frontend/src/router/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import Vue from 'vue' -import Router from 'vue-router' -import HelloWorld from '@/components/HelloWorld' - -Vue.use(Router) - -export default new Router({ - routes: [ - { - path: '/', - name: 'HelloWorld', - component: HelloWorld - } - ] -}) diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index 9c9a2804..d09b2ad7 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-09 13:29 +# Generated by Django 2.0.6 on 2018-08-13 14:04 from django.db import migrations, models diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index c86553f0..6c37627b 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-09 13:29 +# Generated by Django 2.0.6 on 2018-08-13 14:04 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('comments', '0002_auto_20180813_1404'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('comments', '0002_auto_20180809_1329'), ] operations = [ diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index 2d759c03..d63b538b 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -27,6 +27,7 @@ class Common(Configuration): 'django_filters', # for filtering rest endpoints 'rest_framework_swagger', 'debug_toolbar', + 'corsheaders', # Your apps 'pkdb_app.users', @@ -41,6 +42,7 @@ class Common(Configuration): MIDDLEWARE = ( 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -50,6 +52,7 @@ class Common(Configuration): ) DEBUG_TOOLBAR_PATCH_SETTINGS = False + CORS_ORIGIN_WHITELIST = ('0.0.0.0:8080','localhost:8080') INTERNAL_IPS = ('172.18.0.1',) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 7d7aaa67..66665262 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -28,7 +28,7 @@ def get_reference_json_path(): - fill_user_and_substances() + #fill_user_and_substances() for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "reference.json" in files: json_file = os.path.join(root, 'reference.json') @@ -55,6 +55,8 @@ def open_study(d): def upload_reference(json_reference): validate(json_reference["json"],reference_schema) client.action(document, ["references", "create"], params=json_reference["json"]) + + with open(json_reference["pdf"],'rb') as f: requests.patch(f'http://0.0.0.0:8000/api/v1/references/{json_reference["json"]["sid"]}/', files={"pdf":f}) @@ -78,9 +80,7 @@ def upload_study(json_study): study_partial["reference"] = json_study["json"]["reference"] study_partial["curators"] = json_study["json"]["curators"] study_partial["creator"] = json_study["json"]["creator"] - study_partial["groupset"] = json_study["json"]["groupset"] - study_partial["interventionset"] = json_study["json"]["interventionset"] - study_partial["individualset"] = json_study["json"].get("individualset",None) + #client.action(document, ["studies", "create"], params=study_partial) @@ -89,6 +89,19 @@ def upload_study(json_study): if response.status_code == 400: print(json_study["json"]["name"],response.text) + #for file in json_study["json"].get("files",[]): + # with open(file, 'rb') as f: + # requests.patch(f'http://0.0.0.0:8000/api/v1/references/{json_reference["json"]["sid"]}/', files={"pdf": f}) + + study_partial2 = {} + study_partial2["groupset"] = json_study["json"]["groupset"] + study_partial2["interventionset"] = json_study["json"]["interventionset"] + study_partial2["individualset"] = json_study["json"].get("individualset", None) + + response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = study_partial2) + if response.status_code == 400: + print(json_study["json"]["name"], response.text) + if "outputset" in json_study["json"].keys(): response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = {"outputset": json_study["json"].get("outputset")}) if response.status_code == 400: diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index d2d248a2..4619ded3 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -40,7 +40,7 @@ class DataFile(models.Model): This should be in a separate class, so that they can be easily displayed/filtered/... """ - file = models.FileField(upload_to="output", null=True, blank=True) # table or figure + file = models.FileField(upload_to="data", null=True, blank=True) # table or figure filetype = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # XLSX, PNG, CSV diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 93c7fa88..98f14051 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -1,12 +1,18 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db.models import Q from rest_framework import serializers -from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet, Timecourse +from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet, Timecourse, \ + DataFile from pkdb_app.serializers import ParserSerializer from pkdb_app.subjects.models import Individual, Group from pkdb_app.utils import un_map, validate_input +class DataFileSerializer(serializers.ModelSerializer): + class Meta: + model = DataFile + fields = ["file","filetype"] + class SubstanceSerializer(serializers.ModelSerializer): class Meta: @@ -27,11 +33,6 @@ class Meta: fields = ["category","name","route","form","application","time","time_unit","value","unit","substance"] def to_internal_value(self, data): - """ - - :param data: - :return: - """ data = self.split_to_map(data) data = self.drop_blank(data) data = self.strip(data) @@ -41,13 +42,11 @@ def validate(self,data): validated_data = super().validate(data) return validate_input(validated_data,"intervention") - def to_representation(self, instance): rep = super().to_representation(instance) return un_map(rep) - class InterventionSetSerializer(ParserSerializer): interventions = InterventionSerializer(many=True , read_only=False,required=False, allow_null=True) diff --git a/pkdb_app/interventions/views.py b/pkdb_app/interventions/views.py index a1b6d9ee..64ef402b 100644 --- a/pkdb_app/interventions/views.py +++ b/pkdb_app/interventions/views.py @@ -4,11 +4,17 @@ # Create your views here. from rest_framework import viewsets -from pkdb_app.interventions.models import Substance -from pkdb_app.interventions.serializers import SubstanceSerializer +from pkdb_app.interventions.models import Substance, DataFile +from pkdb_app.interventions.serializers import SubstanceSerializer, DataFileSerializer class SubstancesViewSet(viewsets.ModelViewSet): queryset = Substance.objects.all() serializer_class = SubstanceSerializer + + +class DataFileViewSet(viewsets.ModelViewSet): + + queryset = DataFile.objects.all() + serializer_class = DataFileSerializer \ No newline at end of file diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index b8d2a2df..9b5dfb2c 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -51,12 +51,12 @@ class Study(Sidable, models.Model): reference = models.ForeignKey(Reference, on_delete=True, to_field="sid", db_column="reference_sid", related_name='studies', null=True, blank=True) curators = models.ManyToManyField(User) # any curator needs an account. substances = models.ManyToManyField(Substance) - raw_data = models.ManyToManyField(DataFile) # FIXME: is this the right name? + #raw_data = models.ManyToManyField(DataFile) # FIXME: is this the right name? groupset = models.OneToOneField(GroupSet, on_delete=models.CASCADE,null=True, blank=True) interventionset = models.OneToOneField(InterventionSet, on_delete=models.CASCADE,null=True, blank=True) individualset = models.OneToOneField(IndividualSet, on_delete=models.CASCADE,null=True, blank=True) outputset = models.OneToOneField(OutputSet, on_delete=models.CASCADE,null=True, blank=True) - + files = models.ManyToManyField(DataFile) diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 7ae1e06c..2fd9f67b 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -2,7 +2,7 @@ from pkdb_app.utils import update_or_create_multiple, get_or_val_error from ..interventions.models import Substance -from ..interventions.serializers import InterventionSetSerializer, OutputSetSerializer +from ..interventions.serializers import InterventionSetSerializer, OutputSetSerializer, DataFileSerializer from ..subjects.serializers import GroupSetSerializer, IndividualSetSerializer from ..users.models import User from .models import Reference, Author, Study @@ -54,6 +54,7 @@ class StudySerializer(BaseSerializer): interventionset = InterventionSetSerializer(read_only=False, required=False,allow_null=True) individualset = IndividualSetSerializer(read_only=False, required=False, allow_null=True) outputset =OutputSetSerializer(read_only=False, required=False, allow_null=True) + files = DataFileSerializer(read_only=False, required=False, allow_null=True, many=True) class Meta: model = Study diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index fa0c7b56..bdf590e6 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -8,7 +8,7 @@ from django.conf import settings from django.conf.urls import include, url -from .interventions.views import SubstancesViewSet +from .interventions.views import SubstancesViewSet, DataFileViewSet from .users.views import UserViewSet, UserCreateViewSet from .studies.views import AuthorsViewSet, ReferencesViewSet, StudyViewSet #from .subjects.views import GroupsViewSet,CharacteristicValuesViewSet @@ -19,6 +19,7 @@ router.register(r'users', UserCreateViewSet) router.register('substances', SubstancesViewSet, base_name="substances") +router.register('datafiles', DataFileViewSet, base_name="datafiles") # views in studies router.register('authors',AuthorsViewSet,base_name="authors") diff --git a/requirements.txt b/requirements.txt index 0c056902..638de48d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ Markdown==2.6.11 django-filter==1.1.0 coreapi django-rest-swagger - +django-cors-headers==2.4.0 # Developer Tools ipdb==0.11 ipython==6.4.0 From 1dcdb469b7a2347cd56e5ad929e4e708de39041c Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 14 Aug 2018 09:29:18 +0200 Subject: [PATCH 043/115] added build --- .gitignore | 2 +- client/build/build.js | 41 ++++++++ client/build/check-versions.js | 54 +++++++++++ client/build/logo.png | Bin 0 -> 6849 bytes client/build/utils.js | 101 ++++++++++++++++++++ client/build/vue-loader.conf.js | 22 +++++ client/build/webpack.base.conf.js | 92 ++++++++++++++++++ client/build/webpack.dev.conf.js | 95 +++++++++++++++++++ client/build/webpack.prod.conf.js | 149 ++++++++++++++++++++++++++++++ 9 files changed, 555 insertions(+), 1 deletion(-) create mode 100644 client/build/build.js create mode 100644 client/build/check-versions.js create mode 100644 client/build/logo.png create mode 100644 client/build/utils.js create mode 100644 client/build/vue-loader.conf.js create mode 100644 client/build/webpack.base.conf.js create mode 100755 client/build/webpack.dev.conf.js create mode 100644 client/build/webpack.prod.conf.js diff --git a/.gitignore b/.gitignore index 28baabfb..ed6984b4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ __pycache__/ # Distribution / packaging .Python -build/ +# build/ develop-eggs/ dist/ downloads/ diff --git a/client/build/build.js b/client/build/build.js new file mode 100644 index 00000000..8f2ad8ad --- /dev/null +++ b/client/build/build.js @@ -0,0 +1,41 @@ +'use strict' +require('./check-versions')() + +process.env.NODE_ENV = 'production' + +const ora = require('ora') +const rm = require('rimraf') +const path = require('path') +const chalk = require('chalk') +const webpack = require('webpack') +const config = require('../config') +const webpackConfig = require('./webpack.prod.conf') + +const spinner = ora('building for production...') +spinner.start() + +rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { + if (err) throw err + webpack(webpackConfig, (err, stats) => { + spinner.stop() + if (err) throw err + process.stdout.write(stats.toString({ + colors: true, + modules: false, + children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. + chunks: false, + chunkModules: false + }) + '\n\n') + + if (stats.hasErrors()) { + console.log(chalk.red(' Build failed with errors.\n')) + process.exit(1) + } + + console.log(chalk.cyan(' Build complete.\n')) + console.log(chalk.yellow( + ' Tip: built files are meant to be served over an HTTP server.\n' + + ' Opening index.html over file:// won\'t work.\n' + )) + }) +}) diff --git a/client/build/check-versions.js b/client/build/check-versions.js new file mode 100644 index 00000000..3ef972a0 --- /dev/null +++ b/client/build/check-versions.js @@ -0,0 +1,54 @@ +'use strict' +const chalk = require('chalk') +const semver = require('semver') +const packageConfig = require('../package.json') +const shell = require('shelljs') + +function exec (cmd) { + return require('child_process').execSync(cmd).toString().trim() +} + +const versionRequirements = [ + { + name: 'node', + currentVersion: semver.clean(process.version), + versionRequirement: packageConfig.engines.node + } +] + +if (shell.which('npm')) { + versionRequirements.push({ + name: 'npm', + currentVersion: exec('npm --version'), + versionRequirement: packageConfig.engines.npm + }) +} + +module.exports = function () { + const warnings = [] + + for (let i = 0; i < versionRequirements.length; i++) { + const mod = versionRequirements[i] + + if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { + warnings.push(mod.name + ': ' + + chalk.red(mod.currentVersion) + ' should be ' + + chalk.green(mod.versionRequirement) + ) + } + } + + if (warnings.length) { + console.log('') + console.log(chalk.yellow('To use this template, you must update following to modules:')) + console.log() + + for (let i = 0; i < warnings.length; i++) { + const warning = warnings[i] + console.log(' ' + warning) + } + + console.log() + process.exit(1) + } +} diff --git a/client/build/logo.png b/client/build/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d2503fc2a44b5053b0837ebea6e87a2d339a43 GIT binary patch literal 6849 zcmaKRcUV(fvo}bjDT-7nLI_nlK}sT_69H+`qzVWDA|yaU?}j417wLi^B1KB1SLsC& zL0ag7$U(XW5YR7p&Ux?sP$d4lvMt8C^+TcQu4F zQqv!UF!I+kw)c0jhd6+g6oCr9P?7)?!qX1ui*iL{p}sKCAGuJ{{W)0z1pLF|=>h}& zt(2Lr0Z`2ig8<5i%Zk}cO5Fm=LByqGWaS`oqChZdEFmc`0hSb#gg|Aap^{+WKOYcj zHjINK)KDG%&s?Mt4CL(T=?;~U@bU2x_mLKN!#GJuK_CzbNw5SMEJorG!}_5;?R>@1 zSl)jns3WlU7^J%=(hUtfmuUCU&C3%8B5C^f5>W2Cy8jW3#{Od{lF1}|?c61##3dzA zsPlFG;l_FzBK}8>|H_Ru_H#!_7$UH4UKo3lKOA}g1(R&|e@}GINYVzX?q=_WLZCgh z)L|eJMce`D0EIwgRaNETDsr+?vQknSGAi=7H00r`QnI%oQnFxm`G2umXso9l+8*&Q z7WqF|$p49js$mdzo^BXpH#gURy=UO;=IMrYc5?@+sR4y_?d*~0^YP7d+y0{}0)zBM zIKVM(DBvICK#~7N0a+PY6)7;u=dutmNqK3AlsrUU9U`d;msiucB_|8|2kY=(7XA;G zwDA8AR)VCA#JOkxm#6oHNS^YVuOU;8p$N)2{`;oF|rQ?B~K$%rHDxXs+_G zF5|-uqHZvSzq}L;5Kcy_P+x0${33}Ofb6+TX&=y;;PkEOpz%+_bCw_{<&~ zeLV|!bP%l1qxywfVr9Z9JI+++EO^x>ZuCK);=$VIG1`kxK8F2M8AdC$iOe3cj1fo(ce4l-9 z7*zKy3={MixvUk=enQE;ED~7tv%qh&3lR<0m??@w{ILF|e#QOyPkFYK!&Up7xWNtL zOW%1QMC<3o;G9_S1;NkPB6bqbCOjeztEc6TsBM<(q9((JKiH{01+Ud=uw9B@{;(JJ z-DxI2*{pMq`q1RQc;V8@gYAY44Z!%#W~M9pRxI(R?SJ7sy7em=Z5DbuDlr@*q|25V)($-f}9c#?D%dU^RS<(wz?{P zFFHtCab*!rl(~j@0(Nadvwg8q|4!}L^>d?0al6}Rrv9$0M#^&@zjbfJy_n!%mVHK4 z6pLRIQ^Uq~dnyy$`ay51Us6WaP%&O;@49m&{G3z7xV3dLtt1VTOMYl3UW~Rm{Eq4m zF?Zl_v;?7EFx1_+#WFUXxcK78IV)FO>42@cm@}2I%pVbZqQ}3;p;sDIm&knay03a^ zn$5}Q$G!@fTwD$e(x-~aWP0h+4NRz$KlnO_H2c< z(XX#lPuW_%H#Q+c&(nRyX1-IadKR-%$4FYC0fsCmL9ky3 zKpxyjd^JFR+vg2!=HWf}2Z?@Td`0EG`kU?{8zKrvtsm)|7>pPk9nu@2^z96aU2<#` z2QhvH5w&V;wER?mopu+nqu*n8p~(%QkwSs&*0eJwa zMXR05`OSFpfyRb!Y_+H@O%Y z0=K^y6B8Gcbl?SA)qMP3Z+=C(?8zL@=74R=EVnE?vY!1BQy2@q*RUgRx4yJ$k}MnL zs!?74QciNb-LcG*&o<9=DSL>1n}ZNd)w1z3-0Pd^4ED1{qd=9|!!N?xnXjM!EuylY z5=!H>&hSofh8V?Jofyd!h`xDI1fYAuV(sZwwN~{$a}MX^=+0TH*SFp$vyxmUv7C*W zv^3Gl0+eTFgBi3FVD;$nhcp)ka*4gSskYIqQ&+M}xP9yLAkWzBI^I%zR^l1e?bW_6 zIn{mo{dD=)9@V?s^fa55jh78rP*Ze<3`tRCN4*mpO$@7a^*2B*7N_|A(Ve2VB|)_o z$=#_=aBkhe(ifX}MLT()@5?OV+~7cXC3r!%{QJxriXo9I%*3q4KT4Xxzyd{ z9;_%=W%q!Vw$Z7F3lUnY+1HZ*lO;4;VR2+i4+D(m#01OYq|L_fbnT;KN<^dkkCwtd zF7n+O7KvAw8c`JUh6LmeIrk4`F3o|AagKSMK3))_5Cv~y2Bb2!Ibg9BO7Vkz?pAYX zoI=B}+$R22&IL`NCYUYjrdhwjnMx_v=-Qcx-jmtN>!Zqf|n1^SWrHy zK|MwJ?Z#^>)rfT5YSY{qjZ&`Fjd;^vv&gF-Yj6$9-Dy$<6zeP4s+78gS2|t%Z309b z0^fp~ue_}i`U9j!<|qF92_3oB09NqgAoehQ`)<)dSfKoJl_A6Ec#*Mx9Cpd-p#$Ez z={AM*r-bQs6*z$!*VA4|QE7bf@-4vb?Q+pPKLkY2{yKsw{&udv_2v8{Dbd zm~8VAv!G~s)`O3|Q6vFUV%8%+?ZSVUa(;fhPNg#vab@J*9XE4#D%)$UU-T5`fwjz! z6&gA^`OGu6aUk{l*h9eB?opVdrHK>Q@U>&JQ_2pR%}TyOXGq_6s56_`U(WoOaAb+K zXQr#6H}>a-GYs9^bGP2Y&hSP5gEtW+GVC4=wy0wQk=~%CSXj=GH6q z-T#s!BV`xZVxm{~jr_ezYRpqqIcXC=Oq`b{lu`Rt(IYr4B91hhVC?yg{ol4WUr3v9 zOAk2LG>CIECZ-WIs0$N}F#eoIUEtZudc7DPYIjzGqDLWk_A4#(LgacooD z2K4IWs@N`Bddm-{%oy}!k0^i6Yh)uJ1S*90>|bm3TOZxcV|ywHUb(+CeX-o1|LTZM zwU>dY3R&U)T(}5#Neh?-CWT~@{6Ke@sI)uSuzoah8COy)w)B)aslJmp`WUcjdia-0 zl2Y}&L~XfA`uYQboAJ1;J{XLhYjH){cObH3FDva+^8ioOQy%Z=xyjGLmWMrzfFoH; zEi3AG`_v+%)&lDJE;iJWJDI@-X9K5O)LD~j*PBe(wu+|%ar~C+LK1+-+lK=t# z+Xc+J7qp~5q=B~rD!x78)?1+KUIbYr^5rcl&tB-cTtj+e%{gpZZ4G~6r15+d|J(ky zjg@@UzMW0k9@S#W(1H{u;Nq(7llJbq;;4t$awM;l&(2s+$l!Ay9^Ge|34CVhr7|BG z?dAR83smef^frq9V(OH+a+ki#q&-7TkWfFM=5bsGbU(8mC;>QTCWL5ydz9s6k@?+V zcjiH`VI=59P-(-DWXZ~5DH>B^_H~;4$)KUhnmGo*G!Tq8^LjfUDO)lASN*=#AY_yS zqW9UX(VOCO&p@kHdUUgsBO0KhXxn1sprK5h8}+>IhX(nSXZKwlNsjk^M|RAaqmCZB zHBolOHYBas@&{PT=R+?d8pZu zUHfyucQ`(umXSW7o?HQ3H21M`ZJal+%*)SH1B1j6rxTlG3hx1IGJN^M7{$j(9V;MZ zRKybgVuxKo#XVM+?*yTy{W+XHaU5Jbt-UG33x{u(N-2wmw;zzPH&4DE103HV@ER86 z|FZEmQb|&1s5#`$4!Cm}&`^{(4V}OP$bk`}v6q6rm;P!H)W|2i^e{7lTk2W@jo_9q z*aw|U7#+g59Fv(5qI`#O-qPj#@_P>PC#I(GSp3DLv7x-dmYK=C7lPF8a)bxb=@)B1 zUZ`EqpXV2dR}B&r`uM}N(TS99ZT0UB%IN|0H%DcVO#T%L_chrgn#m6%x4KE*IMfjX zJ%4veCEqbXZ`H`F_+fELMC@wuy_ch%t*+Z+1I}wN#C+dRrf2X{1C8=yZ_%Pt6wL_~ zZ2NN-hXOT4P4n$QFO7yYHS-4wF1Xfr-meG9Pn;uK51?hfel`d38k{W)F*|gJLT2#T z<~>spMu4(mul-8Q3*pf=N4DcI)zzjqAgbE2eOT7~&f1W3VsdD44Ffe;3mJp-V@8UC z)|qnPc12o~$X-+U@L_lWqv-RtvB~%hLF($%Ew5w>^NR82qC_0FB z)=hP1-OEx?lLi#jnLzH}a;Nvr@JDO-zQWd}#k^an$Kwml;MrD&)sC5b`s0ZkVyPkb zt}-jOq^%_9>YZe7Y}PhW{a)c39G`kg(P4@kxjcYfgB4XOOcmezdUI7j-!gs7oAo2o zx(Ph{G+YZ`a%~kzK!HTAA5NXE-7vOFRr5oqY$rH>WI6SFvWmahFav!CfRMM3%8J&c z*p+%|-fNS_@QrFr(at!JY9jCg9F-%5{nb5Bo~z@Y9m&SHYV`49GAJjA5h~h4(G!Se zZmK{Bo7ivCfvl}@A-ptkFGcWXAzj3xfl{evi-OG(TaCn1FAHxRc{}B|x+Ua1D=I6M z!C^ZIvK6aS_c&(=OQDZfm>O`Nxsw{ta&yiYPA~@e#c%N>>#rq)k6Aru-qD4(D^v)y z*>Rs;YUbD1S8^D(ps6Jbj0K3wJw>L4m)0e(6Pee3Y?gy9i0^bZO?$*sv+xKV?WBlh zAp*;v6w!a8;A7sLB*g-^<$Z4L7|5jXxxP1}hQZ<55f9<^KJ>^mKlWSGaLcO0=$jem zWyZkRwe~u{{tU63DlCaS9$Y4CP4f?+wwa(&1ou)b>72ydrFvm`Rj-0`kBJgK@nd(*Eh!(NC{F-@=FnF&Y!q`7){YsLLHf0_B6aHc# z>WIuHTyJwIH{BJ4)2RtEauC7Yq7Cytc|S)4^*t8Va3HR zg=~sN^tp9re@w=GTx$;zOWMjcg-7X3Wk^N$n;&Kf1RgVG2}2L-(0o)54C509C&77i zrjSi{X*WV=%C17((N^6R4Ya*4#6s_L99RtQ>m(%#nQ#wrRC8Y%yxkH;d!MdY+Tw@r zjpSnK`;C-U{ATcgaxoEpP0Gf+tx);buOMlK=01D|J+ROu37qc*rD(w`#O=3*O*w9?biwNoq3WN1`&Wp8TvKj3C z3HR9ssH7a&Vr<6waJrU zdLg!ieYz%U^bmpn%;(V%%ugMk92&?_XX1K@mwnVSE6!&%P%Wdi7_h`CpScvspMx?N zQUR>oadnG17#hNc$pkTp+9lW+MBKHRZ~74XWUryd)4yd zj98$%XmIL4(9OnoeO5Fnyn&fpQ9b0h4e6EHHw*l68j;>(ya`g^S&y2{O8U>1*>4zR zq*WSI_2o$CHQ?x0!wl9bpx|Cm2+kFMR)oMud1%n2=qn5nE&t@Fgr#=Zv2?}wtEz^T z9rrj=?IH*qI5{G@Rn&}^Z{+TW}mQeb9=8b<_a`&Cm#n%n~ zU47MvCBsdXFB1+adOO)03+nczfWa#vwk#r{o{dF)QWya9v2nv43Zp3%Ps}($lA02*_g25t;|T{A5snSY?3A zrRQ~(Ygh_ebltHo1VCbJb*eOAr;4cnlXLvI>*$-#AVsGg6B1r7@;g^L zFlJ_th0vxO7;-opU@WAFe;<}?!2q?RBrFK5U{*ai@NLKZ^};Ul}beukveh?TQn;$%9=R+DX07m82gP$=}Uo_%&ngV`}Hyv8g{u z3SWzTGV|cwQuFIs7ZDOqO_fGf8Q`8MwL}eUp>q?4eqCmOTcwQuXtQckPy|4F1on8l zP*h>d+cH#XQf|+6c|S{7SF(Lg>bR~l(0uY?O{OEVlaxa5@e%T&xju=o1`=OD#qc16 zSvyH*my(dcp6~VqR;o(#@m44Lug@~_qw+HA=mS#Z^4reBy8iV?H~I;{LQWk3aKK8$bLRyt$g?- { + const notifier = require('node-notifier') + + return (severity, errors) => { + if (severity !== 'error') return + + const error = errors[0] + const filename = error.file && error.file.split('!').pop() + + notifier.notify({ + title: packageConfig.name, + message: severity + ': ' + error.name, + subtitle: filename || '', + icon: path.join(__dirname, 'logo.png') + }) + } +} diff --git a/client/build/vue-loader.conf.js b/client/build/vue-loader.conf.js new file mode 100644 index 00000000..33ed58bc --- /dev/null +++ b/client/build/vue-loader.conf.js @@ -0,0 +1,22 @@ +'use strict' +const utils = require('./utils') +const config = require('../config') +const isProduction = process.env.NODE_ENV === 'production' +const sourceMapEnabled = isProduction + ? config.build.productionSourceMap + : config.dev.cssSourceMap + +module.exports = { + loaders: utils.cssLoaders({ + sourceMap: sourceMapEnabled, + extract: isProduction + }), + cssSourceMap: sourceMapEnabled, + cacheBusting: config.dev.cacheBusting, + transformToRequire: { + video: ['src', 'poster'], + source: 'src', + img: 'src', + image: 'xlink:href' + } +} diff --git a/client/build/webpack.base.conf.js b/client/build/webpack.base.conf.js new file mode 100644 index 00000000..1f4f47e4 --- /dev/null +++ b/client/build/webpack.base.conf.js @@ -0,0 +1,92 @@ +'use strict' +const path = require('path') +const utils = require('./utils') +const config = require('../config') +const vueLoaderConfig = require('./vue-loader.conf') + +function resolve (dir) { + return path.join(__dirname, '..', dir) +} + +const createLintingRule = () => ({ + test: /\.(js|vue)$/, + loader: 'eslint-loader', + enforce: 'pre', + include: [resolve('src'), resolve('test')], + options: { + formatter: require('eslint-friendly-formatter'), + emitWarning: !config.dev.showEslintErrorsInOverlay + } +}) + +module.exports = { + context: path.resolve(__dirname, '../'), + entry: { + app: './src/main.js' + }, + output: { + path: config.build.assetsRoot, + filename: '[name].js', + publicPath: process.env.NODE_ENV === 'production' + ? config.build.assetsPublicPath + : config.dev.assetsPublicPath + }, + resolve: { + extensions: ['.js', '.vue', '.json'], + alias: { + 'vue$': 'vue/dist/vue.esm.js', + '@': resolve('src'), + } + }, + module: { + rules: [ + ...(config.dev.useEslint ? [createLintingRule()] : []), + { + test: /\.vue$/, + loader: 'vue-loader', + options: vueLoaderConfig + }, + { + test: /\.js$/, + loader: 'babel-loader', + include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] + }, + { + test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, + loader: 'url-loader', + options: { + limit: 10000, + name: utils.assetsPath('img/[name].[hash:7].[ext]') + } + }, + { + test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, + loader: 'url-loader', + options: { + limit: 10000, + name: utils.assetsPath('media/[name].[hash:7].[ext]') + } + }, + { + test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, + loader: 'url-loader', + options: { + limit: 10000, + name: utils.assetsPath('fonts/[name].[hash:7].[ext]') + } + } + ] + }, + node: { + // prevent webpack from injecting useless setImmediate polyfill because Vue + // source contains it (although only uses it if it's native). + setImmediate: false, + // prevent webpack from injecting mocks to Node native modules + // that does not make sense for the client + dgram: 'empty', + fs: 'empty', + net: 'empty', + tls: 'empty', + child_process: 'empty' + } +} diff --git a/client/build/webpack.dev.conf.js b/client/build/webpack.dev.conf.js new file mode 100755 index 00000000..070ae221 --- /dev/null +++ b/client/build/webpack.dev.conf.js @@ -0,0 +1,95 @@ +'use strict' +const utils = require('./utils') +const webpack = require('webpack') +const config = require('../config') +const merge = require('webpack-merge') +const path = require('path') +const baseWebpackConfig = require('./webpack.base.conf') +const CopyWebpackPlugin = require('copy-webpack-plugin') +const HtmlWebpackPlugin = require('html-webpack-plugin') +const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') +const portfinder = require('portfinder') + +const HOST = process.env.HOST +const PORT = process.env.PORT && Number(process.env.PORT) + +const devWebpackConfig = merge(baseWebpackConfig, { + module: { + rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) + }, + // cheap-module-eval-source-map is faster for development + devtool: config.dev.devtool, + + // these devServer options should be customized in /config/index.js + devServer: { + clientLogLevel: 'warning', + historyApiFallback: { + rewrites: [ + { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, + ], + }, + hot: true, + contentBase: false, // since we use CopyWebpackPlugin. + compress: true, + host: HOST || config.dev.host, + port: PORT || config.dev.port, + open: config.dev.autoOpenBrowser, + overlay: config.dev.errorOverlay + ? { warnings: false, errors: true } + : false, + publicPath: config.dev.assetsPublicPath, + proxy: config.dev.proxyTable, + quiet: true, // necessary for FriendlyErrorsPlugin + watchOptions: { + poll: config.dev.poll, + } + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': require('../config/dev.env') + }), + new webpack.HotModuleReplacementPlugin(), + new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. + new webpack.NoEmitOnErrorsPlugin(), + // https://github.com/ampedandwired/html-webpack-plugin + new HtmlWebpackPlugin({ + filename: 'index.html', + template: 'index.html', + inject: true + }), + // copy custom static assets + new CopyWebpackPlugin([ + { + from: path.resolve(__dirname, '../static'), + to: config.dev.assetsSubDirectory, + ignore: ['.*'] + } + ]) + ] +}) + +module.exports = new Promise((resolve, reject) => { + portfinder.basePort = process.env.PORT || config.dev.port + portfinder.getPort((err, port) => { + if (err) { + reject(err) + } else { + // publish the new Port, necessary for e2e tests + process.env.PORT = port + // add port to devServer config + devWebpackConfig.devServer.port = port + + // Add FriendlyErrorsPlugin + devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ + compilationSuccessInfo: { + messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], + }, + onErrors: config.dev.notifyOnErrors + ? utils.createNotifierCallback() + : undefined + })) + + resolve(devWebpackConfig) + } + }) +}) diff --git a/client/build/webpack.prod.conf.js b/client/build/webpack.prod.conf.js new file mode 100644 index 00000000..2f172596 --- /dev/null +++ b/client/build/webpack.prod.conf.js @@ -0,0 +1,149 @@ +'use strict' +const path = require('path') +const utils = require('./utils') +const webpack = require('webpack') +const config = require('../config') +const merge = require('webpack-merge') +const baseWebpackConfig = require('./webpack.base.conf') +const CopyWebpackPlugin = require('copy-webpack-plugin') +const HtmlWebpackPlugin = require('html-webpack-plugin') +const ExtractTextPlugin = require('extract-text-webpack-plugin') +const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') +const UglifyJsPlugin = require('uglifyjs-webpack-plugin') + +const env = process.env.NODE_ENV === 'testing' + ? require('../config/test.env') + : require('../config/prod.env') + +const webpackConfig = merge(baseWebpackConfig, { + module: { + rules: utils.styleLoaders({ + sourceMap: config.build.productionSourceMap, + extract: true, + usePostCSS: true + }) + }, + devtool: config.build.productionSourceMap ? config.build.devtool : false, + output: { + path: config.build.assetsRoot, + filename: utils.assetsPath('js/[name].[chunkhash].js'), + chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') + }, + plugins: [ + // http://vuejs.github.io/vue-loader/en/workflow/production.html + new webpack.DefinePlugin({ + 'process.env': env + }), + new UglifyJsPlugin({ + uglifyOptions: { + compress: { + warnings: false + } + }, + sourceMap: config.build.productionSourceMap, + parallel: true + }), + // extract css into its own file + new ExtractTextPlugin({ + filename: utils.assetsPath('css/[name].[contenthash].css'), + // Setting the following option to `false` will not extract CSS from codesplit chunks. + // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. + // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, + // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 + allChunks: true, + }), + // Compress extracted CSS. We are using this plugin so that possible + // duplicated CSS from different components can be deduped. + new OptimizeCSSPlugin({ + cssProcessorOptions: config.build.productionSourceMap + ? { safe: true, map: { inline: false } } + : { safe: true } + }), + // generate dist index.html with correct asset hash for caching. + // you can customize output by editing /index.html + // see https://github.com/ampedandwired/html-webpack-plugin + new HtmlWebpackPlugin({ + filename: process.env.NODE_ENV === 'testing' + ? 'index.html' + : config.build.index, + template: 'index.html', + inject: true, + minify: { + removeComments: true, + collapseWhitespace: true, + removeAttributeQuotes: true + // more options: + // https://github.com/kangax/html-minifier#options-quick-reference + }, + // necessary to consistently work with multiple chunks via CommonsChunkPlugin + chunksSortMode: 'dependency' + }), + // keep module.id stable when vendor modules does not change + new webpack.HashedModuleIdsPlugin(), + // enable scope hoisting + new webpack.optimize.ModuleConcatenationPlugin(), + // split vendor js into its own file + new webpack.optimize.CommonsChunkPlugin({ + name: 'vendor', + minChunks (module) { + // any required modules inside node_modules are extracted to vendor + return ( + module.resource && + /\.js$/.test(module.resource) && + module.resource.indexOf( + path.join(__dirname, '../node_modules') + ) === 0 + ) + } + }), + // extract webpack runtime and module manifest to its own file in order to + // prevent vendor hash from being updated whenever app bundle is updated + new webpack.optimize.CommonsChunkPlugin({ + name: 'manifest', + minChunks: Infinity + }), + // This instance extracts shared chunks from code splitted chunks and bundles them + // in a separate chunk, similar to the vendor chunk + // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk + new webpack.optimize.CommonsChunkPlugin({ + name: 'app', + async: 'vendor-async', + children: true, + minChunks: 3 + }), + + // copy custom static assets + new CopyWebpackPlugin([ + { + from: path.resolve(__dirname, '../static'), + to: config.build.assetsSubDirectory, + ignore: ['.*'] + } + ]) + ] +}) + +if (config.build.productionGzip) { + const CompressionWebpackPlugin = require('compression-webpack-plugin') + + webpackConfig.plugins.push( + new CompressionWebpackPlugin({ + asset: '[path].gz[query]', + algorithm: 'gzip', + test: new RegExp( + '\\.(' + + config.build.productionGzipExtensions.join('|') + + ')$' + ), + threshold: 10240, + minRatio: 0.8 + }) + ) +} + +if (config.build.bundleAnalyzerReport) { + const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin + webpackConfig.plugins.push(new BundleAnalyzerPlugin()) +} + +module.exports = webpackConfig From fad79197440dd144aada05a05b66951b2ef72caf Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 14 Aug 2018 14:00:10 +0200 Subject: [PATCH 044/115] files are loaded and displayed via absolut url --- client/package-lock.json | 28 +- docs/api/api.ipynb | 494 +++++++++++++++++- pkdb_app/behaviours.py | 6 +- pkdb_app/comments/migrations/0001_initial.py | 2 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/data_management/fill_database.py | 53 +- pkdb_app/interventions/models.py | 14 +- pkdb_app/interventions/serializers.py | 28 +- pkdb_app/interventions/views.py | 9 +- pkdb_app/serializers.py | 18 +- pkdb_app/studies/models.py | 2 +- pkdb_app/studies/serializers.py | 18 +- pkdb_app/subjects/models.py | 16 + pkdb_app/subjects/serializers.py | 16 +- pkdb_app/subjects/views.py | 7 + pkdb_app/urls.py | 3 +- pkdb_app/utils.py | 3 +- 17 files changed, 654 insertions(+), 67 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index d4fb01f8..fea0d5f8 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -5066,12 +5066,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5086,17 +5088,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5213,7 +5218,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5225,6 +5231,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5239,6 +5246,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5246,12 +5254,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5270,6 +5280,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5350,7 +5361,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5362,6 +5374,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5483,6 +5496,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", diff --git a/docs/api/api.ipynb b/docs/api/api.ipynb index 7b9cd1a8..c3f83761 100644 --- a/docs/api/api.ipynb +++ b/docs/api/api.ipynb @@ -720,7 +720,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 6, "metadata": { "collapsed": true }, @@ -821,6 +821,188 @@ "}" ] }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def recursive_iter(obj):\n", + " if isinstance(obj, dict):\n", + " for item in obj.values():\n", + " yield from recursive_iter(item)\n", + " elif any(isinstance(obj, t) for t in (list, tuple)):\n", + " for item in obj:\n", + " yield from recursive_iter(item)\n", + " else:\n", + " yield obj\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('sid',) 16198659\n", + "('name',) Granfors2005\n", + "('reference',) 16198659\n", + "('groups', 0, 'count') 15\n", + "('groups', 0, 'name') Granfors2005-S1\n", + "('groups', 0, 'description') This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\n", + "There were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.\n", + "('groups', 0, 'characteristic_values', 0, 'category') sex\n", + "('groups', 0, 'characteristic_values', 0, 'choice') F\n", + "('groups', 0, 'characteristic_values', 1, 'category') oral_contraceptives\n", + "('groups', 0, 'characteristic_values', 1, 'choice') N\n", + "('groups', 0, 'characteristic_values', 2, 'category') species\n", + "('groups', 0, 'characteristic_values', 2, 'choice') homo sapiens\n", + "('groups', 0, 'characteristic_values', 3, 'category') body_weight\n", + "('groups', 0, 'characteristic_values', 3, 'mean') 62.0\n", + "('groups', 0, 'characteristic_values', 3, 'min') 52.0\n", + "('groups', 0, 'characteristic_values', 3, 'max') 74.0\n", + "('groups', 0, 'characteristic_values', 3, 'sd') 10.0\n", + "('groups', 0, 'characteristic_values', 3, 'unit') kg\n", + "('groups', 0, 'characteristic_values', 4, 'category') smoking\n", + "('groups', 0, 'characteristic_values', 4, 'choice') N\n", + "('groups', 0, 'characteristic_values', 5, 'category') healthy\n", + "('groups', 0, 'characteristic_values', 5, 'choice') Y\n", + "('groups', 0, 'characteristic_values', 6, 'category') age\n", + "('groups', 0, 'characteristic_values', 6, 'mean') 22.0\n", + "('groups', 0, 'characteristic_values', 6, 'min') 19.0\n", + "('groups', 0, 'characteristic_values', 6, 'max') 26.0\n", + "('groups', 0, 'characteristic_values', 6, 'sd') 2.0\n", + "('groups', 0, 'characteristic_values', 6, 'unit') yr\n", + "('groups', 1, 'count') 15\n", + "('groups', 1, 'name') Granfors2005-S2\n", + "('groups', 1, 'description') This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\n", + "There were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.\n", + "('groups', 1, 'characteristic_values', 0, 'category') sex\n", + "('groups', 1, 'characteristic_values', 0, 'choice') F\n", + "('groups', 1, 'characteristic_values', 1, 'category') oral_contraceptives\n", + "('groups', 1, 'characteristic_values', 1, 'choice') Y\n", + "('groups', 1, 'characteristic_values', 2, 'category') species\n", + "('groups', 1, 'characteristic_values', 2, 'choice') homo sapiens\n", + "('groups', 1, 'characteristic_values', 3, 'category') body_weight\n", + "('groups', 1, 'characteristic_values', 3, 'mean') 57.0\n", + "('groups', 1, 'characteristic_values', 3, 'min') 48.0\n", + "('groups', 1, 'characteristic_values', 3, 'max') 63.0\n", + "('groups', 1, 'characteristic_values', 3, 'sd') 6.0\n", + "('groups', 1, 'characteristic_values', 3, 'unit') kg\n", + "('groups', 1, 'characteristic_values', 4, 'category') smoking\n", + "('groups', 1, 'characteristic_values', 4, 'choice') N\n", + "('groups', 1, 'characteristic_values', 5, 'category') healthy\n", + "('groups', 1, 'characteristic_values', 5, 'choice') Y\n", + "('groups', 1, 'characteristic_values', 6, 'category') age\n", + "('groups', 1, 'characteristic_values', 6, 'mean') 22.0\n", + "('groups', 1, 'characteristic_values', 6, 'min') 18.0\n", + "('groups', 1, 'characteristic_values', 6, 'max') 25.0\n", + "('groups', 1, 'characteristic_values', 6, 'sd') 2.0\n", + "('groups', 1, 'characteristic_values', 6, 'unit') yr\n" + ] + } + ], + "source": [ + "import json\n", + "def recursive_iter(obj, keys=()):\n", + " if isinstance(obj, dict):\n", + " for k, v in obj.items():\n", + " yield from recursive_iter(v, keys + (k,))\n", + " elif any(isinstance(obj, t) for t in (list, tuple)):\n", + " for idx, item in enumerate(obj):\n", + " yield from recursive_iter(item, keys + (idx,))\n", + " else:\n", + " yield keys, obj\n", + "\n", + "for keys, item in recursive_iter(study_dict):\n", + " if item \n", + " print(keys, item)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def set_keys(d, value, *keys):\n", + " for key in keys[:-1]:\n", + " d = d[key]\n", + " d[keys[-1]] = value\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'sid': 16198659,\n", + " 'name': 'Granfors2005',\n", + " 'reference': 16198659,\n", + " 'groups': [{'count': 15,\n", + " 'name': 'Granfors2005-S1',\n", + " 'description': 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.',\n", + " 'characteristic_values': [{'category': 'bla', 'choice': 'F'},\n", + " {'category': 'oral_contraceptives', 'choice': 'N'},\n", + " {'category': 'species', 'choice': 'homo sapiens'},\n", + " {'category': 'body_weight',\n", + " 'mean': 62.0,\n", + " 'min': 52.0,\n", + " 'max': 74.0,\n", + " 'sd': 10.0,\n", + " 'unit': 'kg'},\n", + " {'category': 'smoking', 'choice': 'N'},\n", + " {'category': 'healthy', 'choice': 'Y'},\n", + " {'category': 'age',\n", + " 'mean': 22.0,\n", + " 'min': 19.0,\n", + " 'max': 26.0,\n", + " 'sd': 2.0,\n", + " 'unit': 'yr'}]},\n", + " {'count': 15,\n", + " 'name': 'Granfors2005-S2',\n", + " 'description': 'This was an open, parallel-group study with 15 healthy female volunteers (mean age, 22+-2 years [range, 18-25 years]; mean weight, 57+-6 kg [range, 48-63 kg]) using Ocs and 15 healthy female volunteers (mean age, 22+-2 years [range, 19-26 years]; mean weight, 62+-10 kg [range, 52-74 kg]) without any concomitant medication.\\nThere were no statistically significant differences in age or weight between the groups. The combined OCs used by the women in this study contained 75 g gestodene and either 20 g ethinyl estradiol (Harmonet tablet [Wyeth, Newbridge, Ireland], 7 subjects; Meliane tablet [Schering, Berlin, Germany], 5 subjects) or 30 g ethinyl estradiol (Femoden tablet [Schering], 2 subjects; Minulet tablet [Wyeth], 1 subject). The OC users had been using these OC preparations for at least 1 menstrual cycle before the study. Before entering the study, all subjects provided written informed consent and were ascertained to be healthy by medical history, physical examination, and routine laboratory tests. For safety reasons, subjects with a systolic blood pressure lower than 110 mm Hg were excluded from the study. None of the subjects were tobacco smokers, and none used any continuous medication except OCs.',\n", + " 'characteristic_values': [{'category': 'sex', 'choice': 'F'},\n", + " {'category': 'oral_contraceptives', 'choice': 'Y'},\n", + " {'category': 'species', 'choice': 'homo sapiens'},\n", + " {'category': 'body_weight',\n", + " 'mean': 57.0,\n", + " 'min': 48.0,\n", + " 'max': 63.0,\n", + " 'sd': 6.0,\n", + " 'unit': 'kg'},\n", + " {'category': 'smoking', 'choice': 'N'},\n", + " {'category': 'healthy', 'choice': 'Y'},\n", + " {'category': 'age',\n", + " 'mean': 22.0,\n", + " 'min': 18.0,\n", + " 'max': 25.0,\n", + " 'sd': 2.0,\n", + " 'unit': 'yr'}]}]}" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "keys = ['groups', 0, 'characteristic_values', 0, 'category']\n", + "#study_dict.get('groups', 0, 'characteristic_values', 0, 'category')\n", + "test = set_keys(study_dict,\"bla\",*keys)\n", + "study_dict" + ] + }, { "cell_type": "code", "execution_count": 16, @@ -1503,6 +1685,316 @@ "\"33.7\".replace('.','',1).isdigit()" ] }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import os \n", + "import requests\n", + "master = '/home/janekg89/Develop/Pycharm_Projects/pkdb/data/Master/Studies/'\n", + "data_dict = {}\n", + "for root, dirs, files in os.walk(master, topdown=False):\n", + " files = set(files) - set(['reference.json','study.json'])\n", + " for file in files:\n", + " file_path = os.path.join(root, file)\n", + "\n", + " with open(file_path,'rb') as f:\n", + " response = requests.post(f'http://0.0.0.0:8000/api/v1/datafiles/', files={\"file\": f})\n", + " data_dict[file] = response.json()[\"id\"]\n", + "\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'ZylberKatz1984_Tab1.png': 695,\n", + " 'ZylberKatz1984_Fig1.png': 696,\n", + " 'ZylberKatz1984_Tab1.csv': 697,\n", + " 'ZylberKatz1984_Tab2.png': 698,\n", + " 'ZylberKatz1984.xlsx': 699,\n", + " 'ZylberKatz1984.pdf': 700,\n", + " 'ZylberKatz1984_Tab2.csv': 701,\n", + " 'ZylberKatz1984_Fig2.png': 702,\n", + " 'Blanchard1983a_Fig2.csv': 703,\n", + " 'Blanchard1983a_Fig2.png': 704,\n", + " 'Blanchard1983a.pdf': 705,\n", + " 'Blanchard1983a.xlsx': 706,\n", + " 'Haller2002.xlsx': 707,\n", + " 'Haller2002_Fig1C.csv': 708,\n", + " 'Haller2002_Tab3.csv': 709,\n", + " 'Haller2002_Tab1.png': 710,\n", + " 'Haller2002.pdf': 711,\n", + " 'Haller2002_Fig1.png': 712,\n", + " 'Haller2002_Tab3.png': 713,\n", + " 'Granfors2005.pdf': 714,\n", + " 'Granfors2005_Fig7B.csv': 715,\n", + " 'Granfors2005.xlsx': 716,\n", + " 'Granfors2005_Fig7.png': 717,\n", + " 'Renner1984_Fig4.png': 718,\n", + " 'Renner1984_Tab1.png': 719,\n", + " 'Renner1984.xlsx': 720,\n", + " 'Renner1984_Fig2.png': 721,\n", + " 'Renner1984_Tab2.png': 722,\n", + " 'Renner1984.pdf': 723,\n", + " 'Renner1984_Tab3.png': 724,\n", + " 'Desmond1980_Tab1.png': 725,\n", + " 'Desmond1980_Tab2.png': 726,\n", + " 'Desmond1980_Fig2.png': 727,\n", + " 'Desmond1980.pdf': 728,\n", + " 'Abernethy1985.xlsx': 729,\n", + " 'Abernethy1985.pdf': 730,\n", + " 'Abernethy1985_Tab1.png': 731,\n", + " 'Abernethy1985_Fig2.png': 732,\n", + " 'Abernethy1985_Fig2.csv': 733,\n", + " 'Abernethy1985_Fig1.png': 734,\n", + " 'Prescott1980_Fig6.png': 735,\n", + " 'Prescott1980_Fig1.png': 736,\n", + " 'Prescott1980_Fig7.png': 737,\n", + " 'Prescott1980_Fig4.png': 738,\n", + " 'Prescott1980.xlsx': 739,\n", + " 'Prescott1980.pdf': 740,\n", + " 'Amchin1999_Tab1.png': 741,\n", + " 'Amchin1999_Fig1.png': 742,\n", + " 'Amchin1999_Tab2.png': 743,\n", + " 'Amchin1999_Fig1.csv': 744,\n", + " 'Amchin1999.pdf': 745,\n", + " 'Amchin1999_Tab3.png': 746,\n", + " 'Harder1989_Fig2.png': 747,\n", + " 'Harder1989_Fig1.png': 748,\n", + " 'Harder1989_Tab4.png': 749,\n", + " 'Harder1989_Fig1.csv': 750,\n", + " 'Harder1989.pdf': 751,\n", + " 'Harder1989_Tab5.png': 752,\n", + " 'Harder1989.xlsx': 753,\n", + " 'Harder1989_Tab3.png': 754,\n", + " 'Culm-Merdek2005_Tab1.png': 755,\n", + " 'Culm-Merdek2005_Fig1.png': 756,\n", + " 'Culm-Merdek2005.pdf': 757,\n", + " 'Culm-Merdek2005_Fig2.png': 758,\n", + " 'Culm-Merdek2005_Fig3.png': 759,\n", + " 'Chiew2010_Fig3.csv': 760,\n", + " 'Chiew2010_Fig_py1.png': 761,\n", + " 'Chiew2010_Fig2.csv': 762,\n", + " 'Chiew2010_Fig_py2.png': 763,\n", + " 'Chiew2010_Fig1.png': 764,\n", + " 'Chiew2010_Fig.csv': 765,\n", + " 'Chiew2010_Fig2.png': 766,\n", + " 'Chiew2010_Fig1.csv': 767,\n", + " 'Chiew2010_Fig3.png': 768,\n", + " 'Chiew2010.xlsx': 769,\n", + " 'Chiew2010.pdf': 770,\n", + " 'Chiew2010_Tab3.png': 771,\n", + " 'Joeres1988_Tab4.png': 772,\n", + " 'Joeres1988_Tab2.csv': 773,\n", + " 'Joeres1988_Tab2.png': 774,\n", + " 'Joeres1988.pdf': 775,\n", + " 'Joeres1988_Tab3.png': 776,\n", + " 'Joeres1988_Fig1.png': 777,\n", + " 'Joeres1988_Fig1.csv': 778,\n", + " 'Joeres1988_Fig2.png': 779,\n", + " 'Joeres1988.xlsx': 780,\n", + " 'Chan1997.pdf': 781,\n", + " 'Chan1997_Fig1.csv': 782,\n", + " 'Chan1997_Fig1_py.png': 783,\n", + " 'Chan1997_Fig1.png': 784,\n", + " 'Chan1997_Tab1.png': 785,\n", + " 'Chan1997.xlsx': 786,\n", + " 'Seng2009.pdf': 787,\n", + " 'Seng2009_Fig2.png': 788,\n", + " 'Seng2009_Fig1.png': 789,\n", + " 'Seng2009_Tab1.png': 790,\n", + " 'Campbell1987a_Tab3.png': 791,\n", + " 'Campbell1987a_Fig3.png': 792,\n", + " 'Campbell1987a_Fig2.png': 793,\n", + " 'Campbell1987a_Tab6.png': 794,\n", + " 'Campbell1987a.pdf': 795,\n", + " 'Campbell1987a_Tab2.png': 796,\n", + " 'Albert1974_Fig1.csv': 797,\n", + " 'Albert1974_Fig1.png': 798,\n", + " 'Albert1974_Tab2.png': 799,\n", + " 'Albert1974.pdf': 800,\n", + " 'Albert1974.xlsx': 801,\n", + " 'Kaplan1997.xlsx': 802,\n", + " 'Kaplan1997_Fig1.csv': 803,\n", + " 'Kaplan1997.pdf': 804,\n", + " 'Kaplan1997_Fig2.png': 805,\n", + " 'Kaplan1997_Tab2.png': 806,\n", + " 'Kaplan1997_Fig1.png': 807,\n", + " 'Kaplan1997_Tab1.png': 808,\n", + " 'Kaplan1997_Tab1.csv': 809,\n", + " 'Kaplan1997_Fig2.csv': 810,\n", + " 'Healy1989_Tab1.png': 811,\n", + " 'Healy1989.pdf': 812,\n", + " 'Healy1989_Tab2.png': 813,\n", + " 'Critchley2005.pdf': 814,\n", + " 'Critchley2005_Fig1.csv': 815,\n", + " 'Critchley2005_Fig1_py.png': 816,\n", + " 'Critchley2005_Fig1.png': 817,\n", + " 'Critchley2005_Tab1.png': 818,\n", + " 'Critchley2005.xlsx': 819,\n", + " 'Critchley2005_Tab3.png': 820,\n", + " 'Critchley2005_Tab2.png': 821,\n", + " 'Healy1991_Fig2.png': 822,\n", + " 'Healy1991.xlsx': 823,\n", + " 'Healy1991_Tab1.png': 824,\n", + " 'Healy1991.pdf': 825,\n", + " 'Healy1991_Fig1.png': 826,\n", + " 'Healy1991_Fig.csv': 827,\n", + " 'Baraka1990_Tab1.png': 828,\n", + " 'Baraka1990_Fig1.png': 829,\n", + " 'Baraka1990.pdf': 830,\n", + " 'Baraka1990_Fig1.csv': 831,\n", + " 'Baraka1990.xlsx': 832,\n", + " 'Benowitz2003_Fig3.png': 833,\n", + " 'Benowitz2003_Fig4.png': 834,\n", + " 'Benowitz2003.pdf': 835,\n", + " 'Benowitz2003.xlsx': 836,\n", + " 'Benowitz2003_Tab2.png': 837,\n", + " 'Benowitz2003_Fig4.csv': 838,\n", + " 'Benowitz2003_Fig3.csv': 839,\n", + " 'Akinyinka2000_Fig1.png': 840,\n", + " 'Akinyinka2000_Fig2.png': 841,\n", + " 'Akinyinka2000_Fig3.png': 842,\n", + " 'Akinyinka2000_Fig5.csv': 843,\n", + " 'Akinyinka2000_Fig4.csv': 844,\n", + " 'Akinyinka2000.pdf': 845,\n", + " 'Akinyinka2000_Fig4.png': 846,\n", + " 'Akinyinka2000_Fig3.csv': 847,\n", + " 'Akinyinka2000_Tab1.csv': 848,\n", + " 'Akinyinka2000_Tab1.png': 849,\n", + " 'Akinyinka2000_Fig5.png': 850,\n", + " 'Akinyinka2000_Fig1.csv': 851,\n", + " 'Akinyinka2000.xlsx': 852,\n", + " 'Harder1988_Tab4.png': 853,\n", + " 'Harder1988_Tab3.png': 854,\n", + " 'Harder1988.xlsx': 855,\n", + " 'Harder1988_Fig1.png': 856,\n", + " 'Harder1988.pdf': 857,\n", + " 'Harder1988_Fig1.csv': 858,\n", + " 'Parsons1978.pdf': 859,\n", + " 'Parsons1978_Tab2.csv': 860,\n", + " 'Parsons1978_Tab1.png': 861,\n", + " 'Parsons1978_Fig1.png': 862,\n", + " 'Parsons1978_Fig2.png': 863,\n", + " 'Parsons1978_Tab2.png': 864,\n", + " 'Parsons1978.xlsx': 865,\n", + " 'Bonati1982.pdf': 866,\n", + " 'Bonati1982_Tab5.csv': 867,\n", + " 'Bonati1982_Tab3.png': 868,\n", + " 'Bonati1982_Tab1.png': 869,\n", + " 'Bonati1982_Fig3.png': 870,\n", + " 'Bonati1982_Tab3.csv': 871,\n", + " 'Bonati1982_Fig1.png': 872,\n", + " 'Bonati1982_Fig1.csv': 873,\n", + " 'Bonati1982_Tab5.png': 874,\n", + " 'Bonati1982_Tab4.png': 875,\n", + " 'Bonati1982.xlsx': 876,\n", + " 'Rawlins1977_Fig1_py.png': 877,\n", + " 'Rawlins1977.pdf': 878,\n", + " 'Rawlins1977_Fig1.csv': 879,\n", + " 'Rawlins1977_Tab2.png': 880,\n", + " 'Rawlins1977_Fig2.csv': 881,\n", + " 'Rawlins1977_Fig2_py.png': 882,\n", + " 'Rawlins1977_Fig1.png': 883,\n", + " 'Rawlins1977_Tab1.png': 884,\n", + " 'Rawlins1977_Fig2.png': 885,\n", + " 'Rawlins1977.xlsx': 886,\n", + " 'Balogh1995_Tab2.png': 887,\n", + " 'Balogh1995_Tab1.png': 888,\n", + " 'Balogh1995.pdf': 889,\n", + " 'Ameer1981_Fig3.csv': 890,\n", + " 'Ameer1981.pdf': 891,\n", + " 'Ameer1981_Fig3.png': 892,\n", + " 'Ameer1981.xlsx': 893,\n", + " 'Balogh1992_Tab1b.png': 894,\n", + " 'Balogh1992.pdf': 895,\n", + " 'Balogh1992_Tab1a.png': 896,\n", + " 'Fuhr1993a.xlsx': 897,\n", + " 'Fuhr1993a.pdf': 898,\n", + " 'Fuhr1993a_Tab1.png': 899,\n", + " 'Fuhr1993a_Tab2.png': 900,\n", + " 'Fuhr1993a_Tab1.csv': 901,\n", + " 'Fuhr1993a_Tab3.csv': 902,\n", + " 'Fuhr1993a_Tab3.png': 903,\n", + " 'Fuhr1993a_Fig2.png': 904,\n", + " 'Cheng1990_Fig2.png': 905,\n", + " 'Cheng1990.pdf': 906,\n", + " 'Cheng1990_Tab3.png': 907,\n", + " 'Cheng1990_Tab2.png': 908,\n", + " 'Ghassabian2009.xlsx': 909,\n", + " 'Ghassabian2009.pdf': 910,\n", + " 'Ghassabian2009_Tab5.png': 911,\n", + " 'Ghassabian2009_Tab5.csv': 912}" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_dict" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import os \n", + "file_path = os.path.dirname('/home/janekg89/Develop/Pycharm_Projects/pkdb/data/Master/Studies/Prescott1980/Prescott1980_Fig6.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "head, sid = os.path.split(file_path)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/janekg89/Develop/Pycharm_Projects/pkdb/data/Master/Studies\n", + "Prescott1980\n" + ] + }, + { + "data": { + "text/plain": [ + "(None, None)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(head), print(sid)" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index 3da52ecf..a4d083de 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -4,6 +4,7 @@ from django.db import models from django.core.exceptions import ValidationError + from pkdb_app.utils import CHAR_MAX_LENGTH from .categoricals import UNITS_CHOICES @@ -74,9 +75,10 @@ class Hashable(models.Model): class Meta: abstract = True + class Sourceable(models.Model): - source = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) # todo: to file_filed - figure = models.CharField(max_length=CHAR_MAX_LENGTH*5,null=True, blank=True) # todo: to file_filed + #source = models.ForeignKey(DataFile, on_delete=False) # todo: to file_filed + #figure = models.CharField(max_length=CHAR_MAX_LENGTH*5,null=True, blank=True) # todo: to file_filed format = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) class Meta: diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index d09b2ad7..f864b043 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-13 14:04 +# Generated by Django 2.0.6 on 2018-08-14 10:50 from django.db import migrations, models diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index 6c37627b..a782c0fd 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-13 14:04 +# Generated by Django 2.0.6 on 2018-08-14 10:50 from django.conf import settings from django.db import migrations, models @@ -9,7 +9,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('comments', '0002_auto_20180813_1404'), + ('comments', '0002_auto_20180814_1050'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 66665262..ac376b82 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -26,9 +26,8 @@ USERS = [Jan_G_U, Matthias_K] - def get_reference_json_path(): - #fill_user_and_substances() + fill_user_and_substances() for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "reference.json" in files: json_file = os.path.join(root, 'reference.json') @@ -36,22 +35,25 @@ def get_reference_json_path(): yield {"json":json_file , "pdf": pdf_file} + def get_study_json_path(): for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "study.json" in files: yield os.path.join(root, 'study.json') -def open_reference(d): +def open_reference(d): with open(d["json"]) as f: json_dict = json.loads(f.read()) return {"json":json_dict,"pdf":d["pdf"], "reference_path":d["json"]} + def open_study(d): with open(d) as f: json_dict = json.loads(f.read()) return {"json":json_dict, "study_path":d} + def upload_reference(json_reference): validate(json_reference["json"],reference_schema) client.action(document, ["references", "create"], params=json_reference["json"]) @@ -61,7 +63,6 @@ def upload_reference(json_reference): requests.patch(f'http://0.0.0.0:8000/api/v1/references/{json_reference["json"]["sid"]}/', files={"pdf":f}) - def fill_user_and_substances(): for substance in SUBSTANCES_DATA: @@ -70,8 +71,44 @@ def fill_user_and_substances(): client.action(document, ["users", "create"], params=user) +def fill_files(file_path): + data_dict = {} + head, sid = os.path.split(file_path) + study_dir = os.path.join(head,sid) + for root, dirs, files in os.walk(study_dir, topdown=False): + files = set(files) - set(['reference.json', 'study.json', f'{sid}.pdf']) + for file in files: + file_path = os.path.join(root, file) + with open(file_path,'rb') as f: + response = requests.post(f'http://0.0.0.0:8000/api/v1/datafiles/', files={"file": f}) + data_dict[file] = response.json()["id"] + return data_dict + +def recursive_iter(obj, keys=()): + if isinstance(obj, dict): + for k, v in obj.items(): + yield from recursive_iter(v, keys + (k,)) + elif any(isinstance(obj, t) for t in (list, tuple)): + for idx, item in enumerate(obj): + yield from recursive_iter(item, keys + (idx,)) + else: + yield keys, obj + +def set_keys(d, value, *keys): + for key in keys[:-1]: + d = d[key] + d[keys[-1]] = value + def upload_study(json_study): + study_dir = os.path.dirname(json_study["study_path"]) + file_dict = fill_files(study_dir) + + for keys, item in recursive_iter(json_study): + if item in file_dict.keys(): + set_keys(json_study, file_dict[item], *keys) + study_partial = {} + study_partial["sid"] = json_study["json"]["sid"] study_partial["name"] = json_study["json"]["name"] study_partial["pkdb_version"] = json_study["json"]["pkdb_version"] @@ -80,6 +117,8 @@ def upload_study(json_study): study_partial["reference"] = json_study["json"]["reference"] study_partial["curators"] = json_study["json"]["curators"] study_partial["creator"] = json_study["json"]["creator"] + study_partial["files"] = list(file_dict.values()) + @@ -89,15 +128,15 @@ def upload_study(json_study): if response.status_code == 400: print(json_study["json"]["name"],response.text) - #for file in json_study["json"].get("files",[]): - # with open(file, 'rb') as f: - # requests.patch(f'http://0.0.0.0:8000/api/v1/references/{json_reference["json"]["sid"]}/', files={"pdf": f}) + + study_partial2 = {} study_partial2["groupset"] = json_study["json"]["groupset"] study_partial2["interventionset"] = json_study["json"]["interventionset"] study_partial2["individualset"] = json_study["json"].get("individualset", None) + response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = study_partial2) if response.status_code == 400: print(json_study["json"]["name"], response.text) diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 4619ded3..afd75ad9 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -11,7 +11,7 @@ from ..categoricals import INTERVENTION_CHOICES, TIME_UNITS_CHOICES, \ INTERVENTION_ROUTE_CHOICES, INTERVENTION_FORM_CHOICES, INTERVENTION_APPLICATION_CHOICES, PK_DATA_CHOICES, \ SUBSTANCES_DATA_CHOICES, OUTPUT_TISSUE_DATA_CHOICES -from ..subjects.models import Group, Individual, Set +from ..subjects.models import Group, Individual, Set, DataFile from ..utils import CHAR_MAX_LENGTH # ------------------------------------------------- @@ -34,14 +34,8 @@ ##################################### #new -class DataFile(models.Model): - """ Table or figure from where the data comes from (png). - This should be in a separate class, so that they can be easily displayed/filtered/... - """ - file = models.FileField(upload_to="data", null=True, blank=True) # table or figure - filetype = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # XLSX, PNG, CSV class Substance(models.Model): @@ -152,6 +146,8 @@ class Output(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseOutpu """ Storage of data sets. """ + source = models.ForeignKey(DataFile, related_name="output_sources",on_delete=False) + figure = models.ForeignKey(DataFile, related_name="output_figures",on_delete=False) pktype = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES, null=True, blank=True) time = models.FloatField(null=True,blank=True) @@ -167,8 +163,10 @@ class Timecourse(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseO """ #substance #tissue - outputset = models.ForeignKey(OutputSet, related_name="timecourse", on_delete=models.CASCADE,null=True, blank=True) + source = models.ForeignKey(DataFile, related_name="timecourse_sources",on_delete=False) + figure = models.ForeignKey(DataFile, related_name="timecourse_figures",on_delete=False) + outputset = models.ForeignKey(OutputSet, related_name="timecourse", on_delete=models.CASCADE,null=True, blank=True) pktype = models.CharField(max_length=CHAR_MAX_LENGTH, choices=PK_DATA_CHOICES, null=True, blank=True) time = models.DecimalField(max_digits=40, decimal_places=20, null=True, blank=True) #data = models.ForeignKey(DataFile, on_delete=True) # link to the CSV diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 98f14051..69471fcb 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -1,17 +1,14 @@ +from django.contrib.sites.shortcuts import get_current_site from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db.models import Q from rest_framework import serializers -from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet, Timecourse, \ - DataFile +from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet, Timecourse from pkdb_app.serializers import ParserSerializer -from pkdb_app.subjects.models import Individual, Group +from pkdb_app.subjects.models import Individual, Group, DataFile from pkdb_app.utils import un_map, validate_input -class DataFileSerializer(serializers.ModelSerializer): - class Meta: - model = DataFile - fields = ["file","filetype"] + class SubstanceSerializer(serializers.ModelSerializer): @@ -25,8 +22,7 @@ def create(self, validated_data): class InterventionSerializer(ParserSerializer): - substance = serializers.SlugRelatedField(slug_field="name",queryset=Substance.objects.all(),read_only=False,required=False, allow_null=True) - + substance = serializers.SlugRelatedField(slug_field="name",queryset=Substance.objects.all(),read_only=False, required=False, allow_null=True) class Meta: model = Intervention @@ -69,6 +65,8 @@ class OutputSerializer(ParserSerializer): individual = serializers.PrimaryKeyRelatedField(queryset=Individual.objects.all(), read_only=False, required=False, allow_null=True) interventions = serializers.PrimaryKeyRelatedField(queryset=Intervention.objects.all(),many=True, read_only=False,required=False, allow_null=True) substance = serializers.SlugRelatedField(slug_field="name",queryset=Substance.objects.all(),read_only=False,required=False, allow_null=True) + source = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True) + figure = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True) class Meta: model = Output @@ -110,6 +108,7 @@ def to_internal_value(self, data): raise ValidationError(msg) data["interventions"] = interventions + data = self.strip(data) data = self.drop_blank(data) data = self.drop_empty(data) @@ -122,6 +121,11 @@ def to_representation(self, instance): rep["group"] = instance.group.name if "interventions" in rep: rep["interventions"] = [intervention.name for intervention in instance.interventions.all()] + for file in ["source", "figure"]: + if file in rep: + current_site = f'http://{get_current_site(self.context["request"]).domain}' + rep[file] = current_site+ getattr(instance,file).file.url + return un_map(rep) @@ -138,9 +142,9 @@ class Meta: "interventions_map", "substance", "substance_map", "tissue", "tissue_map"] - def to_representation(self, instance): - rep = super().to_representation(instance) - return un_map(rep) + #def to_representation(self, instance): + # rep = super().to_representation(instance) + # return un_map(rep) class OutputSetSerializer(ParserSerializer): diff --git a/pkdb_app/interventions/views.py b/pkdb_app/interventions/views.py index 64ef402b..327891d5 100644 --- a/pkdb_app/interventions/views.py +++ b/pkdb_app/interventions/views.py @@ -4,9 +4,8 @@ # Create your views here. from rest_framework import viewsets -from pkdb_app.interventions.models import Substance, DataFile -from pkdb_app.interventions.serializers import SubstanceSerializer, DataFileSerializer - +from pkdb_app.interventions.models import Substance +from pkdb_app.interventions.serializers import SubstanceSerializer class SubstancesViewSet(viewsets.ModelViewSet): @@ -14,7 +13,3 @@ class SubstancesViewSet(viewsets.ModelViewSet): serializer_class = SubstanceSerializer -class DataFileViewSet(viewsets.ModelViewSet): - - queryset = DataFile.objects.all() - serializer_class = DataFileSerializer \ No newline at end of file diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 2a4073ae..9e9e8b7a 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -3,10 +3,10 @@ from rest_framework import serializers from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError -from collections import OrderedDict, namedtuple +from collections import OrderedDict import pandas as pd -from pkdb_app.interventions.models import Substance, InterventionSet, OutputSet +from pkdb_app.interventions.models import Substance, InterventionSet, OutputSet, DataFile from pkdb_app.studies.models import Reference from pkdb_app.subjects.models import GroupSet, IndividualSet from pkdb_app.users.models import User @@ -43,14 +43,6 @@ def is_valid(self, raise_exception=False): return super().is_valid(raise_exception) - """ - def to_representation(self, instance): - result = super().to_representation(instance) - return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) - - - """ - @staticmethod def create_relations(study, related): for name,model in RELATED_SETS.items(): @@ -68,6 +60,10 @@ def create_relations(study, related): substance = get_or_val_error(Substance, name=substance_data) study.substances.add(substance) + #study.files.all().delete() + for file_pk in related["files"]: + study.files.add(file_pk) + study.save() return study @@ -77,7 +73,7 @@ def pop_relations(validated_data): related_foreinkeys = RELATED_SETS.copy() related_foreinkeys["reference"] = Reference - related_many2many = {"substances": Substance,"curators": User} + related_many2many = {"substances": Substance,"curators": User,"files": DataFile} related_foreinkeys_dict = {name:validated_data.pop(name, None) for name,_ in related_foreinkeys.items()} related_many2many_dict = {name:validated_data.pop(name, []) for name,_ in related_many2many.items()} related = {**related_foreinkeys_dict,**related_many2many_dict} diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 9b5dfb2c..3343bf49 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -3,7 +3,7 @@ """ from django.db import models -from pkdb_app.interventions.models import OutputSet, Substance, DataFile, InterventionSet +from pkdb_app.interventions.models import OutputSet, Substance, InterventionSet, DataFile from pkdb_app.subjects.models import GroupSet, IndividualSet from ..utils import CHAR_MAX_LENGTH from ..behaviours import Sidable diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 2fd9f67b..0ba6ef98 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -1,8 +1,9 @@ +from django.contrib.sites.shortcuts import get_current_site from rest_framework import serializers from pkdb_app.utils import update_or_create_multiple, get_or_val_error -from ..interventions.models import Substance -from ..interventions.serializers import InterventionSetSerializer, OutputSetSerializer, DataFileSerializer +from ..interventions.models import Substance, DataFile +from ..interventions.serializers import InterventionSetSerializer, OutputSetSerializer from ..subjects.serializers import GroupSetSerializer, IndividualSetSerializer from ..users.models import User from .models import Reference, Author, Study @@ -54,12 +55,12 @@ class StudySerializer(BaseSerializer): interventionset = InterventionSetSerializer(read_only=False, required=False,allow_null=True) individualset = IndividualSetSerializer(read_only=False, required=False, allow_null=True) outputset =OutputSetSerializer(read_only=False, required=False, allow_null=True) - files = DataFileSerializer(read_only=False, required=False, allow_null=True, many=True) + files = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True, many=True) class Meta: model = Study fields = ('sid',"pkdb_version","creator",'name',"design",'reference',"curators","substances", - "groupset","individualset","interventionset","outputset") + "groupset","individualset","interventionset","outputset","files") def create(self, validated_data): related = self.pop_relations(validated_data) @@ -93,3 +94,12 @@ def update(self, instance, validated_data): return instance + def to_representation(self, instance): + rep = super().to_representation(instance) + current_site = f'http://{get_current_site(self.context["request"]).domain}' + + if "files" in rep: + rep["files"] = [current_site + file.file.url for file in instance.files.all()] + return rep + + diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 2c70a9be..6d07220e 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -6,6 +6,7 @@ From the data structure this has to be handled very similar. """ from django.db import models + from ..behaviours import Valueable, Describable, ValueableMap, Sourceable from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, CHARACTERISTICA_CHOICES, GROUP_CRITERIA, \ INCLUSION_CRITERIA, EXCLUSION_CRITERIA @@ -21,6 +22,18 @@ # - Intervention # - DataSets/Output +class DataFile(models.Model): + """ Table or figure from where the data comes from (png). + + This should be in a separate class, so that they can be easily displayed/filtered/... + """ + + file = models.FileField(upload_to="data", null=True, blank=True) # table or figure + filetype = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # XLSX, PNG, CSV + + def __str__(self): + return self.file.name + class Set(Describable, models.Model): """ abstarct class for all set classes @@ -76,6 +89,9 @@ class Individual(IndividualMap,Sourceable,models.Model): Individuals are defined via their characteristics. """ + source = models.ForeignKey(DataFile,related_name="individual_sources", on_delete=False) + figure = models.ForeignKey(DataFile, related_name="individual_figures", on_delete=False) + individualset = models.ForeignKey(IndividualSet,on_delete=models.CASCADE, related_name="individuals") group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name="individuals",null=True, blank=True) name = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 7bc695de..a9390773 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,9 +1,14 @@ +from django.contrib.sites.shortcuts import get_current_site from rest_framework import serializers from pkdb_app.behaviours import Sourceable from pkdb_app.utils import un_map, validate_input -from .models import Group, GroupSet, Individual, IndividualSet, Characteristica +from .models import Group, GroupSet, Individual, IndividualSet, Characteristica, DataFile from ..serializers import ParserSerializer +class DataFileSerializer(serializers.ModelSerializer): + class Meta: + model = DataFile + fields = ["id","file","filetype"] class CharacteristicaSerializer(ParserSerializer): count = serializers.IntegerField(required=False) @@ -64,10 +69,12 @@ def get_queryset(self): class IndividualSerializer(ParserSerializer): characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False, allow_null=True) group = GroupSRField(slug_field='name', read_only=False, required=False, allow_null=True) + source = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True) + figure = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True) class Meta: model = Individual - fields = Sourceable.fields() + ["name", "name_map", "group_map", "characteristica", "group"] + fields = Sourceable.fields() + ["name", "name_map", "group_map", "characteristica", "group","source"] def to_internal_value(self, data): data = self.generic_parser(data, "characteristica") @@ -78,6 +85,11 @@ def to_representation(self, instance): rep = super().to_representation(instance) if "group" in rep: rep["group"] = instance.group.name + + for file in ["source", "figure"]: + if file in rep: + current_site = f'http://{get_current_site(self.context["request"]).domain}' + rep[file] = current_site+ getattr(instance,file).file.url return un_map(rep) ''' diff --git a/pkdb_app/subjects/views.py b/pkdb_app/subjects/views.py index c6f11308..9fc30344 100644 --- a/pkdb_app/subjects/views.py +++ b/pkdb_app/subjects/views.py @@ -4,6 +4,9 @@ import django_filters.rest_framework from rest_framework import filters +from pkdb_app.subjects.models import DataFile +from pkdb_app.subjects.serializers import DataFileSerializer + """ class GroupsViewSet(viewsets.ModelViewSet): @@ -34,3 +37,7 @@ class CharacteristicValuesViewSet(viewsets.ModelViewSet): # filter_fields = ('comment','description','type') # search_fields = filter_fields +class DataFileViewSet(viewsets.ModelViewSet): + + queryset = DataFile.objects.all() + serializer_class = DataFileSerializer \ No newline at end of file diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index bdf590e6..fedf614a 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -8,7 +8,8 @@ from django.conf import settings from django.conf.urls import include, url -from .interventions.views import SubstancesViewSet, DataFileViewSet +from pkdb_app.subjects.views import DataFileViewSet +from .interventions.views import SubstancesViewSet from .users.views import UserViewSet, UserCreateViewSet from .studies.views import AuthorsViewSet, ReferencesViewSet, StudyViewSet #from .subjects.views import GroupsViewSet,CharacteristicValuesViewSet diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index edda7c34..8f5f1879 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -71,4 +71,5 @@ def un_map(data): if v is None: continue cleaned_result[k] = v - return cleaned_result \ No newline at end of file + return cleaned_result + From 7bb38ffee25e412ff4e4bc5a4d675b36ab0d0546 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 14 Aug 2018 14:37:06 +0200 Subject: [PATCH 045/115] working on client --- README.md | 9 + client/package-lock.json | 1063 +++++++++++++++++++-------- client/package.json | 4 + client/src/components/Reference.vue | 33 + client/src/http/APIService.js | 6 +- client/src/main.js | 6 + 6 files changed, 824 insertions(+), 297 deletions(-) diff --git a/README.md b/README.md index bfe47d9d..91c28ad5 100644 --- a/README.md +++ b/README.md @@ -96,5 +96,14 @@ Example: ``` ---- +# Client +check out ./client/README.md. +## Requirements +- node.js +- npm +- vue.js + + + © 2018 Jan Grzegorzewski & Matthias König. \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index fea0d5f8..7692d7b7 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -181,8 +181,7 @@ "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "accepts": { "version": "1.3.5", @@ -265,7 +264,6 @@ "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, "requires": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", @@ -310,8 +308,7 @@ "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" }, "ansi-escapes": { "version": "3.1.0", @@ -328,8 +325,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "3.2.1", @@ -362,8 +358,16 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } }, "argparse": { "version": "1.0.10", @@ -401,8 +405,7 @@ "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" }, "array-flatten": { "version": "1.1.1", @@ -451,7 +454,6 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, "requires": { "safer-buffer": "~2.1.0" } @@ -496,8 +498,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "assertion-error": { "version": "1.0.0", @@ -538,6 +539,11 @@ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "dev": true }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=" + }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -547,8 +553,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { "version": "2.1.1", @@ -573,14 +578,12 @@ "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "axios": { "version": "0.18.0", @@ -1358,6 +1361,23 @@ "esutils": "^2.0.2" } }, + "babel-polyfill": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", + "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", + "requires": { + "babel-runtime": "^6.22.0", + "core-js": "^2.4.0", + "regenerator-runtime": "^0.10.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + } + } + }, "babel-preset-env": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", @@ -1490,7 +1510,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" @@ -1547,8 +1566,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", @@ -1621,7 +1639,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, "optional": true, "requires": { "tweetnacl": "^0.14.3" @@ -1641,8 +1658,7 @@ "big.js": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "dev": true + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" }, "binary-extensions": { "version": "1.11.0", @@ -1650,6 +1666,14 @@ "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", "dev": true }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "~2.0.0" + } + }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", @@ -1760,11 +1784,28 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, + "bootstrap": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.3.tgz", + "integrity": "sha512-rDFIzgXcof0jDyjNosjv4Sno77X4KuPeFxG2XZZv1/Kc8DRVGVADdoQyyOVDwPqL36DDmtCQbrpMCqvpPLJQ0w==" + }, + "bootstrap-vue": { + "version": "2.0.0-rc.11", + "resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-2.0.0-rc.11.tgz", + "integrity": "sha512-LxR+oL8yKr1DVoWUWTX+XhiT0xaTMH6142u2VSFDm4tewTH8HIrzN2YIl7HLZrw2DIuE9bRMIdWJqqn3aQe7Hw==", + "requires": { + "bootstrap": "^4.1.1", + "lodash.get": "^4.4.2", + "lodash.startcase": "^4.4.0", + "opencollective": "^1.0.3", + "popper.js": "^1.12.9", + "vue-functional-data-merge": "^2.0.5" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1956,8 +1997,7 @@ "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, "builtin-status-codes": { "version": "3.0.0", @@ -2044,7 +2084,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, "requires": { "camelcase": "^2.0.0", "map-obj": "^1.0.0" @@ -2053,8 +2092,7 @@ "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" } } }, @@ -2106,8 +2144,7 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "center-align": { "version": "0.1.3", @@ -2143,8 +2180,7 @@ "chardet": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" }, "check-types": { "version": "7.4.0", @@ -2317,7 +2353,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, "requires": { "restore-cursor": "^2.0.0" } @@ -2331,8 +2366,7 @@ "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, "cliui": { "version": "2.1.0", @@ -2359,11 +2393,31 @@ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", "dev": true }, + "clone-deep": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", + "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.0", + "shallow-clone": "^1.0.0" + }, + "dependencies": { + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + } + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "coa": { "version": "1.0.4", @@ -2383,8 +2437,7 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "collection-visit": { "version": "1.0.0", @@ -2452,7 +2505,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -2508,8 +2560,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", @@ -2579,6 +2630,11 @@ "date-now": "^0.1.4" } }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, "consolidate": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz", @@ -2691,14 +2747,12 @@ "core-js": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", - "dev": true + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cosmiconfig": { "version": "4.0.0", @@ -3114,7 +3168,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, "requires": { "array-find-index": "^1.0.1" } @@ -3138,7 +3191,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -3192,8 +3244,7 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "decode-uri-component": { "version": "0.2.0", @@ -3340,8 +3391,12 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, "depd": { "version": "1.1.2", @@ -3569,7 +3624,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, "optional": true, "requires": { "jsbn": "~0.1.0", @@ -3636,8 +3690,7 @@ "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" }, "encodeurl": { "version": "1.0.2", @@ -3645,6 +3698,14 @@ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -3685,7 +3746,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -3803,8 +3863,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "1.11.0", @@ -4467,8 +4526,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -4495,7 +4553,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, "requires": { "chardet": "^0.4.0", "iconv-lite": "^0.4.17", @@ -4594,20 +4651,17 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fast-levenshtein": { "version": "2.0.6", @@ -4652,7 +4706,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, "requires": { "escape-string-regexp": "^1.0.5" } @@ -4903,8 +4956,7 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" }, "for-own": { "version": "0.1.5", @@ -4924,14 +4976,12 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "1.0.6", @@ -5022,8 +5072,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "1.2.4", @@ -5066,14 +5115,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5088,20 +5135,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5218,8 +5262,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5231,7 +5274,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5246,7 +5288,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5254,14 +5295,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5280,7 +5319,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5361,8 +5399,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5374,7 +5411,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5496,7 +5532,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5568,6 +5603,17 @@ } } }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, "ftp": { "version": "0.3.10", "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", @@ -5616,17 +5662,58 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "requires": { + "globule": "^1.0.0" + } + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" }, "get-stream": { "version": "3.0.0", @@ -5658,7 +5745,6 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -5667,7 +5753,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5749,11 +5834,20 @@ "pinkie-promise": "^2.0.0" } }, + "globule": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "graceful-readlink": { "version": "1.0.1", @@ -5863,14 +5957,12 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", - "dev": true, "requires": { "ajv": "^5.3.0", "har-schema": "^2.0.0" @@ -5889,7 +5981,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5900,6 +5991,11 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -5988,8 +6084,7 @@ "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" }, "hpack.js": { "version": "2.1.6", @@ -6292,7 +6387,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -6320,7 +6414,6 @@ "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -6400,11 +6493,15 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=" + }, "indent-string": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, "requires": { "repeating": "^2.0.0" } @@ -6425,7 +6522,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -6434,8 +6530,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -6509,8 +6604,7 @@ "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, "ip": { "version": "1.0.1", @@ -6553,8 +6647,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-binary-path": { "version": "1.0.1", @@ -6574,7 +6667,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, "requires": { "builtin-modules": "^1.0.0" } @@ -6663,8 +6755,7 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" }, "is-extglob": { "version": "2.1.1", @@ -6676,7 +6767,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6684,8 +6774,7 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "is-generator-fn": { "version": "1.0.0", @@ -6756,7 +6845,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, "requires": { "isobject": "^3.0.1" } @@ -6776,8 +6864,7 @@ "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, "is-regex": { "version": "1.0.4", @@ -6797,8 +6884,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-svg": { "version": "2.1.0", @@ -6818,14 +6904,12 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" }, "is-whitespace": { "version": "0.3.0", @@ -6848,26 +6932,22 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-api": { "version": "1.3.1", @@ -7790,8 +7870,7 @@ "js-base64": { "version": "2.4.8", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.8.tgz", - "integrity": "sha512-hm2nYpDrwoO/OzBhdcqs/XGT6XjSuSSCVEpia+Kl2J6x4CYt5hISlVL/AYU1khoDXv0AQVgxtdJySb9gjAn56Q==", - "dev": true + "integrity": "sha512-hm2nYpDrwoO/OzBhdcqs/XGT6XjSuSSCVEpia+Kl2J6x4CYt5hISlVL/AYU1khoDXv0AQVgxtdJySb9gjAn56Q==" }, "js-beautify": { "version": "1.7.5", @@ -7825,7 +7904,6 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, "optional": true }, "jsdom": { @@ -7883,14 +7961,12 @@ "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" }, "json-stable-stringify": { "version": "1.0.1", @@ -7910,8 +7986,7 @@ "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json3": { "version": "3.3.2", @@ -7922,8 +7997,7 @@ "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonify": { "version": "0.0.0", @@ -7935,7 +8009,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -7958,8 +8031,7 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" }, "last-call-webpack-plugin": { "version": "2.1.2", @@ -7981,7 +8053,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, "requires": { "invert-kv": "^1.0.0" } @@ -8012,7 +8083,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", @@ -8082,7 +8152,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "dev": true, "requires": { "big.js": "^3.1.3", "emojis-list": "^2.0.0", @@ -8102,8 +8171,7 @@ "lodash": { "version": "4.17.10", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", - "dev": true + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, "lodash._arraycopy": { "version": "3.0.0", @@ -8183,6 +8251,11 @@ "integrity": "sha1-dRqnbBuWSwR+dtFPxyoJP8teLdA=", "dev": true }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" + }, "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -8200,6 +8273,11 @@ "lodash._isiterateecall": "^3.0.0" } }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, "lodash.create": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", @@ -8239,6 +8317,11 @@ } } }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -8283,8 +8366,7 @@ "lodash.mergewith": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", - "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", - "dev": true + "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==" }, "lodash.rest": { "version": "4.0.5", @@ -8298,6 +8380,16 @@ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, + "lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha1-lDbjTtJgk+1/+uGTYUQ1CRXZrdg=" + }, + "lodash.tail": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", + "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=" + }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -8338,7 +8430,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, "requires": { "currently-unhandled": "^0.4.1", "signal-exit": "^3.0.0" @@ -8354,7 +8445,6 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", - "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -8395,8 +8485,7 @@ "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" }, "map-visit": { "version": "1.0.0", @@ -8458,7 +8547,6 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, "requires": { "camelcase-keys": "^2.0.0", "decamelize": "^1.1.2", @@ -8475,8 +8563,7 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, @@ -8547,14 +8634,12 @@ "mime-db": { "version": "1.35.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", - "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", - "dev": true + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" }, "mime-types": { "version": "2.1.19", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", - "dev": true, "requires": { "mime-db": "~1.35.0" } @@ -8562,8 +8647,7 @@ "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, "minimalistic-assert": { "version": "1.0.1", @@ -8581,7 +8665,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -8589,8 +8672,7 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mississippi": { "version": "2.0.0", @@ -8631,11 +8713,26 @@ } } }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=" + } + } + }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" } @@ -8764,15 +8861,12 @@ "mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" }, "nan": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "dev": true, - "optional": true + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" }, "nanomatch": { "version": "1.2.13", @@ -8808,8 +8902,7 @@ "neo-async": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz", - "integrity": "sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA==", - "dev": true + "integrity": "sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA==" }, "netmask": { "version": "1.0.6", @@ -8885,12 +8978,47 @@ } } }, + "node-fetch": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", + "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-forge": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", "dev": true }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + } + } + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -8940,11 +9068,118 @@ "which": "^1.3.0" } }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, + "node-sass": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.3.tgz", + "integrity": "sha512-XzXyGjO+84wxyH7fV6IwBOTrEBe2f0a6SBze9QWWYR/cL74AcQUks2AsqcCZenl/Fp/JVbuEaLpgrLtocwBUww==", + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash.assign": "^4.2.0", + "lodash.clonedeep": "^4.3.2", + "lodash.mergewith": "^4.6.0", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.10.0", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "2.87.0", + "sass-graph": "^2.2.4", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "^5.1.0", + "har-schema": "^2.0.0" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "request": { + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "requires": { + "punycode": "^1.4.1" + } + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "requires": { "abbrev": "1" } @@ -8953,7 +9188,6 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, "requires": { "hosted-git-info": "^2.1.4", "is-builtin-module": "^1.0.0", @@ -8997,6 +9231,17 @@ "path-key": "^2.0.0" } }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, "nth-check": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", @@ -9015,8 +9260,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nwsapi": { "version": "2.0.8", @@ -9027,14 +9271,12 @@ "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-copy": { "version": "0.1.0", @@ -9142,7 +9384,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -9151,11 +9392,86 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, "requires": { "mimic-fn": "^1.0.0" } }, + "opencollective": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz", + "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=", + "requires": { + "babel-polyfill": "6.23.0", + "chalk": "1.1.3", + "inquirer": "3.0.6", + "minimist": "1.2.0", + "node-fetch": "1.6.3", + "opn": "4.0.2" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "inquirer": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", + "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", + "requires": { + "ansi-escapes": "^1.1.0", + "chalk": "^1.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.1", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx": "^4.1.0", + "string-width": "^2.0.0", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "opn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, "opener": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.0.tgz", @@ -9243,8 +9559,7 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { "version": "2.1.0", @@ -9260,8 +9575,16 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } }, "p-finally": { "version": "1.0.0", @@ -9409,7 +9732,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, "requires": { "error-ex": "^1.2.0" } @@ -9453,8 +9775,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -9484,7 +9805,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, "requires": { "graceful-fs": "^4.1.2", "pify": "^2.0.0", @@ -9513,26 +9833,22 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, "requires": { "pinkie": "^2.0.0" } @@ -9558,6 +9874,11 @@ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "dev": true }, + "popper.js": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.4.tgz", + "integrity": "sha1-juwdj/AqWjoVLdQ0FKFce3n9abY=" + }, "portfinder": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.16.tgz", @@ -11732,8 +12053,7 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "progress": { "version": "2.0.0", @@ -11796,14 +12116,12 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "psl": { "version": "1.1.29", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", - "dev": true + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" }, "public-encrypt": { "version": "4.0.2", @@ -11842,8 +12160,7 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "q": { "version": "1.5.1", @@ -11854,8 +12171,7 @@ "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { "version": "4.3.4", @@ -11954,7 +12270,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, "requires": { "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", @@ -11965,7 +12280,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" @@ -11975,7 +12289,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" @@ -11985,7 +12298,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, "requires": { "pinkie-promise": "^2.0.0" } @@ -11996,7 +12308,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12041,7 +12352,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, "requires": { "indent-string": "^2.1.0", "strip-indent": "^1.0.1" @@ -12092,8 +12402,7 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, "regenerator-transform": { "version": "0.10.1", @@ -12214,7 +12523,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, "requires": { "is-finite": "^1.0.0" } @@ -12223,7 +12531,6 @@ "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -12270,8 +12577,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-from-string": { "version": "2.0.2", @@ -12282,8 +12588,7 @@ "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, "require-uncached": { "version": "1.0.3", @@ -12343,7 +12648,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, "requires": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" @@ -12368,7 +12672,6 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, "requires": { "glob": "^7.0.5" } @@ -12393,7 +12696,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, "requires": { "is-promise": "^2.1.0" } @@ -12407,6 +12709,11 @@ "aproba": "^1.1.1" } }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=" + }, "rx-lite": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", @@ -12425,8 +12732,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -12440,8 +12746,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sane": { "version": "2.5.2", @@ -12468,6 +12773,118 @@ } } }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "requires": { + "camelcase": "^3.0.0" + } + } + } + }, + "sass-loader": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", + "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "requires": { + "clone-deep": "^2.0.1", + "loader-utils": "^1.0.1", + "lodash.tail": "^4.1.1", + "neo-async": "^2.5.0", + "pify": "^3.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -12483,6 +12900,25 @@ "ajv": "^5.0.0" } }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -12507,8 +12943,7 @@ "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" }, "send": { "version": "0.16.2", @@ -12581,8 +13016,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-immediate-shim": { "version": "1.0.1", @@ -12635,6 +13069,23 @@ "safe-buffer": "^5.0.1" } }, + "shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -12676,8 +13127,7 @@ "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "slash": { "version": "1.0.0", @@ -12938,7 +13388,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", - "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -12947,14 +13396,12 @@ "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", - "dev": true + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -12963,8 +13410,7 @@ "spdx-license-ids": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", - "dev": true + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" }, "spdy": { "version": "3.4.7", @@ -13014,7 +13460,6 @@ "version": "1.14.2", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", - "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -13075,6 +13520,14 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, + "stdout-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", + "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "requires": { + "readable-stream": "^2.0.1" + } + }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", @@ -13157,7 +13610,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -13166,14 +13618,12 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, "requires": { "ansi-regex": "^3.0.0" } @@ -13184,7 +13634,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -13193,7 +13642,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -13202,7 +13650,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, "requires": { "is-utf8": "^0.2.0" } @@ -13217,7 +13664,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, "requires": { "get-stdin": "^4.0.1" } @@ -13284,6 +13730,16 @@ "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=", "dev": true }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + }, "test-exclude": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz", @@ -13312,8 +13768,7 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { "version": "2.0.3", @@ -13356,7 +13811,6 @@ "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, "requires": { "os-tmpdir": "~1.0.2" } @@ -13431,7 +13885,6 @@ "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" @@ -13457,8 +13910,7 @@ "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" }, "trim-right": { "version": "1.0.1", @@ -13466,6 +13918,28 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "true-case-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", + "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", + "requires": { + "glob": "^6.0.4" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "tryer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", @@ -13502,7 +13976,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -13511,7 +13984,6 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, "optional": true }, "type-check": { @@ -13846,8 +14318,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { "version": "1.0.0", @@ -13874,14 +14345,12 @@ "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -13903,7 +14372,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -13949,6 +14417,11 @@ } } }, + "vue-functional-data-merge": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-2.0.6.tgz", + "integrity": "sha512-eivElFOJwhXJopKlq71/8onDxOKK4quPwWGFF9yIVjpU2sNzxISRpufu18bh674ivSADuEAPU2OhT+vrH0E9Mg==" + }, "vue-hot-reload-api": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz", @@ -14639,7 +15112,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, "requires": { "isexe": "^2.0.0" } @@ -14650,6 +15122,14 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", @@ -14675,7 +15155,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" @@ -14685,7 +15164,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -14694,7 +15172,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -14706,8 +15183,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { "version": "0.2.1", @@ -14774,8 +15250,7 @@ "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, "yargs": { "version": "10.1.2", diff --git a/client/package.json b/client/package.json index dcee374e..1d6f52a6 100644 --- a/client/package.json +++ b/client/package.json @@ -15,6 +15,10 @@ }, "dependencies": { "axios": "^0.18.0", + "bootstrap": "^4.1.3", + "bootstrap-vue": "^2.0.0-rc.11", + "node-sass": "^4.9.3", + "sass-loader": "^7.1.0", "vue": "^2.5.2" }, "devDependencies": { diff --git a/client/src/components/Reference.vue b/client/src/components/Reference.vue index a3185deb..89c407aa 100644 --- a/client/src/components/Reference.vue +++ b/client/src/components/Reference.vue @@ -1,6 +1,39 @@ diff --git a/client/src/http/APIService.js b/client/src/http/APIService.js index 9ef2752c..6747d7d0 100644 --- a/client/src/http/APIService.js +++ b/client/src/http/APIService.js @@ -14,9 +14,9 @@ export class APIService{ return axios.get(url).then(response => response.data); } - updateReference(product){ - const url = `${API_URL}/api/products/${product.pk}`; - return axios.put(url,product); + updateReference(pk){ + const url = `${API_URL}/api/preferences/${pk}`; + return axios.put(url,pk); } } diff --git a/client/src/main.js b/client/src/main.js index 684ffacc..8270b2d5 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -1,7 +1,13 @@ // The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' +import BootstrapVue from 'bootstrap-vue' import App from './App' +import 'bootstrap/dist/css/bootstrap.css' +import 'bootstrap-vue/dist/bootstrap-vue.css' + +Vue.use(BootstrapVue); + Vue.config.productionTip = false From 90254dbd96a8a7fc19eed2541ae3211d7b174549 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 14 Aug 2018 18:01:10 +0200 Subject: [PATCH 046/115] added a watcher if file is correct --- pkdb_app/comments/migrations/0001_initial.py | 4 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/data_management/fill_database.py | 51 ++++++++++++++++--- pkdb_app/data_management/study_upload.py | 49 ++++++++++++++++++ pkdb_app/data_management/study_watch.py | 44 ++++++++++++++++ requirements.txt | 3 +- 6 files changed, 143 insertions(+), 12 deletions(-) create mode 100644 pkdb_app/data_management/study_upload.py create mode 100644 pkdb_app/data_management/study_watch.py diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index f864b043..547ab0de 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-14 10:50 +# Generated by Django 2.0.6 on 2018-08-14 12:39 from django.db import migrations, models @@ -8,8 +8,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('interventions', '0001_initial'), ('subjects', '0001_initial'), + ('interventions', '0001_initial'), ] operations = [ diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index a782c0fd..e950d5cc 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-14 10:50 +# Generated by Django 2.0.6 on 2018-08-14 12:39 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('comments', '0002_auto_20180814_1050'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('comments', '0002_auto_20180814_1239'), ] operations = [ diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index ac376b82..acb56abc 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -3,6 +3,7 @@ import coreapi import json import requests +from django.core.exceptions import ValidationError BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) @@ -14,10 +15,16 @@ import mondrian from pkdb_app.categoricals import SUBSTANCES_DATA # One line setup (excepthook=True tells mondrian to handle uncaught exceptions) -mondrian.setup(excepthook=True) +#mondrian.setup(excepthook=True) # Use logging, as usual. -logger = logging.getLogger() -logger.setLevel(logging.DEBUG) +#logger = logging.getLogger() +#logger.setLevel(logging.DEBUG) +if hasattr (sys, 'tracebacklimit'): + del sys.tracebacklimit + +class Stop (Exception): + def __init__ (self): + sys.tracebacklimit = 0 PASSWORD = "test" Jan_G_U = {"username":"janekg","first_name":"Jan","last_name":"Grzegorzewski","email":"Janekg89@hotmail.de","password":PASSWORD} @@ -44,23 +51,46 @@ def get_study_json_path(): def open_reference(d): with open(d["json"]) as f: - json_dict = json.loads(f.read()) + try: + json_dict = json.loads(f.read()) + except json.decoder.JSONDecodeError as err: + print(err) + return return {"json":json_dict,"pdf":d["pdf"], "reference_path":d["json"]} def open_study(d): with open(d) as f: - json_dict = json.loads(f.read()) + try: + json_dict = json.loads(f.read()) + except json.decoder.JSONDecodeError as err: + print(err) + return + + + return {"json":json_dict, "study_path":d} def upload_reference(json_reference): + ok = True validate(json_reference["json"],reference_schema) - client.action(document, ["references", "create"], params=json_reference["json"]) + #client.action(document, ["references", "create"], params=json_reference["json"]) + response = requests.post(f'http://0.0.0.0:8000/api/v1/references/', json=json_reference["json"]) + if response.status_code == 400: + print(json_reference["json"]["name"], response.text) + ok = False with open(json_reference["pdf"],'rb') as f: - requests.patch(f'http://0.0.0.0:8000/api/v1/references/{json_reference["json"]["sid"]}/', files={"pdf":f}) + response = requests.patch(f'http://0.0.0.0:8000/api/v1/references/{json_reference["json"]["sid"]}/', files={"pdf":f}) + + if response.status_code == 400: + print(json_reference["json"]["name"], response.text) + ok = False + + return ok + def fill_user_and_substances(): @@ -100,6 +130,7 @@ def set_keys(d, value, *keys): d[keys[-1]] = value def upload_study(json_study): + ok = True study_dir = os.path.dirname(json_study["study_path"]) file_dict = fill_files(study_dir) @@ -127,6 +158,7 @@ def upload_study(json_study): json=study_partial) if response.status_code == 400: print(json_study["json"]["name"],response.text) + ok = False @@ -140,11 +172,16 @@ def upload_study(json_study): response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = study_partial2) if response.status_code == 400: print(json_study["json"]["name"], response.text) + ok = False if "outputset" in json_study["json"].keys(): response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = {"outputset": json_study["json"].get("outputset")}) if response.status_code == 400: print(json_study["json"]["name"],response.text) + ok = False + + return ok + #study_partial["outputset"] = json_study["json"].get("outputset",None) diff --git a/pkdb_app/data_management/study_upload.py b/pkdb_app/data_management/study_upload.py new file mode 100644 index 00000000..f5116e52 --- /dev/null +++ b/pkdb_app/data_management/study_upload.py @@ -0,0 +1,49 @@ +#! /usr/bin/env python +import os, sys +import argparse + +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) +from pkdb_app.data_management.fill_database import open_reference, open_study, upload_reference,upload_study + + + +def run(args): + ok = True + study_path = os.path.join(args.study, "study.json") + _ , study_name = os.path.split(args.study) + + reference_path = os.path.join(args.study, "reference.json") + reference_pdf = os.path.join(args.study, f"{study_name}.pdf") + + if os.path.isfile(reference_path): + reference_dict = {"json": reference_path, "pdf": reference_pdf} + if open_reference(reference_dict): + ok_ref = upload_reference(open_reference(reference_dict)) + if not ok_ref: + ok = ok_ref + else: + ok = False + + if os.path.isfile(study_path): + if open_study(study_path): + ok_study = upload_study(open_study(study_path)) + if not ok_study: + ok = ok_study + else: + ok = False + + + if ok: + print("everthing is fine") + +def main(): + parser = argparse.ArgumentParser(description="Upload a file to PKDB") + parser.add_argument("-s", help="directory of a study", dest="study", type=str, required=True) + parser.set_defaults(func=run) + args = parser.parse_args() + args.func(args) + + +if __name__=="__main__": + main() \ No newline at end of file diff --git a/pkdb_app/data_management/study_watch.py b/pkdb_app/data_management/study_watch.py new file mode 100644 index 00000000..3af2d484 --- /dev/null +++ b/pkdb_app/data_management/study_watch.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +import time +import argparse +import os, sys +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) +from pkdb_app.data_management.study_upload import run as upload_study + + + +class MyHandler(FileSystemEventHandler): + def __init__(self, study): + self.study = study + + def on_created(self, event): + #if event.is_directory: + _, study_name = os.path.split(self.study) + + print(f'---------- Study: {study_name} ----------') + upload_study(self) + + +def run(args): + event_handler = MyHandler(study = args.study) + observer = Observer() + observer.schedule(event_handler, path=args.study, recursive=False) + observer.start() + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + observer.stop() + observer.join() + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Upload a file to PKDB") + parser.add_argument("-s", help="directory of a study", dest="study", type=str, required=True) + parser.set_defaults(func=run) + args = parser.parse_args() + args.func(args) + + diff --git a/requirements.txt b/requirements.txt index 638de48d..9739a7c2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -48,4 +48,5 @@ pandas jsonschema django-extra-fields PyPDF2 -lark-parser \ No newline at end of file +lark-parser +watchdog \ No newline at end of file From 7bc4d9d6f3a9e9949575f8fb174eab4f839eae8e Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 16 Aug 2018 14:19:59 +0200 Subject: [PATCH 047/115] files dublicate, comments missing, rest working --- pkdb_app/categoricals.py | 8 +++- pkdb_app/comments/migrations/0001_initial.py | 2 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/config/common.py | 1 - .../create_reference_caffeine.py | 10 ++-- pkdb_app/data_management/fill_database.py | 23 +++++---- pkdb_app/data_management/reference_create.py | 31 ++++++++++++ pkdb_app/data_management/study_upload.py | 13 ++++- pkdb_app/interventions/models.py | 8 ++-- pkdb_app/interventions/serializers.py | 5 +- pkdb_app/serializers.py | 47 ++++++++++++++----- pkdb_app/studies/serializers.py | 6 ++- pkdb_app/subjects/models.py | 26 +++++++--- pkdb_app/subjects/serializers.py | 33 +++++++------ pkdb_app/utils.py | 11 +++-- 15 files changed, 157 insertions(+), 71 deletions(-) create mode 100644 pkdb_app/data_management/reference_create.py diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 03516d42..64f1ede0 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -43,6 +43,8 @@ def create_choices(list): UnitType('m'), UnitType('kg'), UnitType('yr'), + UnitType('week'), + UnitType('day'), UnitType('kg/m^2'), UnitType('1/day'), UnitType('1/h'), @@ -167,7 +169,7 @@ def create_choices(list): "ofloxacin", "fluvoxamine", "alcohol", - + "codeine" ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] @@ -220,11 +222,13 @@ def create_choices(list): # Study protocol CharacteristicType('overnight fast', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('alcohol abstinence', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('abstinence', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, SUBSTANCES_DATA+["alcohol","food"]), + CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA+["alcohol","medication","grapefruit juice"],["-"]), # Medication # Genetics ??? + CharacteristicType('genetics', 'genetics',CATEGORIAL_TYPE, ["CYP2D6 duplication","CYP2D6 wild type","CYP2D6 poor metabolizer"], ["-"]), + # Requires storage of the variants and effects of clearance ] PK_DATA = [ diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index 547ab0de..3e1592a3 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-14 12:39 +# Generated by Django 2.0.6 on 2018-08-16 10:30 from django.db import migrations, models diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index e950d5cc..acecefc2 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-14 12:39 +# Generated by Django 2.0.6 on 2018-08-16 10:30 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('comments', '0002_auto_20180816_1030'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('comments', '0002_auto_20180814_1239'), ] operations = [ diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index d63b538b..f72b69f8 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -53,7 +53,6 @@ class Common(Configuration): DEBUG_TOOLBAR_PATCH_SETTINGS = False CORS_ORIGIN_WHITELIST = ('0.0.0.0:8080','localhost:8080') - INTERNAL_IPS = ('172.18.0.1',) ALLOWED_HOSTS = ["*"] diff --git a/pkdb_app/data_management/create_reference_caffeine.py b/pkdb_app/data_management/create_reference_caffeine.py index c46a2d9d..d7b9e252 100644 --- a/pkdb_app/data_management/create_reference_caffeine.py +++ b/pkdb_app/data_management/create_reference_caffeine.py @@ -15,6 +15,8 @@ sys.path.append(BASEPATH) from pkdb_app.utils import ensure_dir +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pkdb_app.config.local") + CAFFEINE = "caffeine" Master = os.path.join(BASEPATH, "Master") @@ -60,24 +62,24 @@ def add_reference_path(d): def load_from_biopython(d): + Entrez.email = 'janekg89@hotmail.de' handle = Entrez.efetch(db='pubmed', id=d['pmid'], retmode='xml') all_info = handle.read() handle.close() - yield {**d, 'xml': all_info} + return {**d, 'xml': all_info} def xml_to_data(d): - yield {**d, 'data': ET.fromstring(d['xml'])} + return {**d, 'data': ET.fromstring(d['xml'])} def create_json(d): json_dict = {} - #json_dict["groups"] = [] json_dict["pmid"] = d["pmid"] json_dict["name"] = d["name"] - json_dict["sid"] = d["sid"] + json_dict["sid"] = d["pmid"] for date in d["data"].iter("DateCompleted"): year = date.find('Year').text month = date.find('Month').text diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index acb56abc..d0b9ed1b 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -3,22 +3,19 @@ import coreapi import json import requests -from django.core.exceptions import ValidationError BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) - -from pkdb_app.data_management.create_reference_caffeine import REFERENCESMASTERPATH from jsonschema import validate from pkdb_app.data_management.schemas import reference_schema import logging import mondrian -from pkdb_app.categoricals import SUBSTANCES_DATA # One line setup (excepthook=True tells mondrian to handle uncaught exceptions) #mondrian.setup(excepthook=True) # Use logging, as usual. #logger = logging.getLogger() #logger.setLevel(logging.DEBUG) + if hasattr (sys, 'tracebacklimit'): del sys.tracebacklimit @@ -34,7 +31,10 @@ def __init__ (self): def get_reference_json_path(): + fill_user_and_substances() + from pkdb_app.data_management.create_reference_caffeine import REFERENCESMASTERPATH + for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "reference.json" in files: json_file = os.path.join(root, 'reference.json') @@ -44,6 +44,7 @@ def get_reference_json_path(): def get_study_json_path(): + from pkdb_app.data_management.create_reference_caffeine import REFERENCESMASTERPATH for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): if "study.json" in files: yield os.path.join(root, 'study.json') @@ -77,7 +78,7 @@ def upload_reference(json_reference): validate(json_reference["json"],reference_schema) #client.action(document, ["references", "create"], params=json_reference["json"]) response = requests.post(f'http://0.0.0.0:8000/api/v1/references/', json=json_reference["json"]) - if response.status_code == 400: + if not response.status_code == 201: print(json_reference["json"]["name"], response.text) ok = False @@ -85,7 +86,7 @@ def upload_reference(json_reference): with open(json_reference["pdf"],'rb') as f: response = requests.patch(f'http://0.0.0.0:8000/api/v1/references/{json_reference["json"]["sid"]}/', files={"pdf":f}) - if response.status_code == 400: + if not response.status_code == 200: print(json_reference["json"]["name"], response.text) ok = False @@ -94,7 +95,7 @@ def upload_reference(json_reference): def fill_user_and_substances(): - + from pkdb_app.categoricals import SUBSTANCES_DATA for substance in SUBSTANCES_DATA: client.action(document, ["substances", "create"], params={"name":substance}) for user in USERS: @@ -149,6 +150,8 @@ def upload_study(json_study): study_partial["curators"] = json_study["json"]["curators"] study_partial["creator"] = json_study["json"]["creator"] study_partial["files"] = list(file_dict.values()) + #study_partial["bla"] = "bla" + @@ -156,7 +159,7 @@ def upload_study(json_study): #client.action(document, ["studies", "create"], params=study_partial) response = requests.post(f'http://0.0.0.0:8000/api/v1/studies/', json=study_partial) - if response.status_code == 400: + if not response.status_code == 201: print(json_study["json"]["name"],response.text) ok = False @@ -170,13 +173,13 @@ def upload_study(json_study): response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = study_partial2) - if response.status_code == 400: + if not response.status_code == 200: print(json_study["json"]["name"], response.text) ok = False if "outputset" in json_study["json"].keys(): response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = {"outputset": json_study["json"].get("outputset")}) - if response.status_code == 400: + if not response.status_code == 200: print(json_study["json"]["name"],response.text) ok = False diff --git a/pkdb_app/data_management/reference_create.py b/pkdb_app/data_management/reference_create.py new file mode 100644 index 00000000..145648fb --- /dev/null +++ b/pkdb_app/data_management/reference_create.py @@ -0,0 +1,31 @@ +import argparse + +import os +import sys + +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) + +from pkdb_app.data_management.create_reference_caffeine import load_from_biopython, xml_to_data,create_json,add_doi,save_json + +def run(args): + + ref_dict = {"reference_path":args.reference, + "name":args.name, + "pmid":args.pmid} + save_json(add_doi(create_json(xml_to_data(load_from_biopython(ref_dict))))) + +def main(): + parser = argparse.ArgumentParser(description="create reference folder") + parser.add_argument("-s", help="directory of a reference", dest="reference", type=str, required=True) + parser.add_argument("-n", help="name of reference", dest="name", type=str, required=True) + parser.add_argument("-p", help="pmid", dest="pmid", type=str, required=True) + + + parser.set_defaults(func=run) + args = parser.parse_args() + args.func(args) + + +if __name__=="__main__": + main() \ No newline at end of file diff --git a/pkdb_app/data_management/study_upload.py b/pkdb_app/data_management/study_upload.py index f5116e52..1be1c34c 100644 --- a/pkdb_app/data_management/study_upload.py +++ b/pkdb_app/data_management/study_upload.py @@ -1,11 +1,11 @@ #! /usr/bin/env python import os, sys import argparse - +from collections import namedtuple BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) from pkdb_app.data_management.fill_database import open_reference, open_study, upload_reference,upload_study - +from pkdb_app.data_management.reference_create import run as create_reference def run(args): @@ -16,6 +16,13 @@ def run(args): reference_path = os.path.join(args.study, "reference.json") reference_pdf = os.path.join(args.study, f"{study_name}.pdf") + if open_study(study_path) and hasattr(args, 'r'): + study = open_study(study_path) + Reference = namedtuple("Reference",["reference", "name", "pmid"]) + ref = Reference(reference=args.study,name=study_name, pmid=study["json"]["reference"]) + create_reference(ref) + + if os.path.isfile(reference_path): reference_dict = {"json": reference_path, "pdf": reference_pdf} if open_reference(reference_dict): @@ -40,6 +47,8 @@ def run(args): def main(): parser = argparse.ArgumentParser(description="Upload a file to PKDB") parser.add_argument("-s", help="directory of a study", dest="study", type=str, required=True) + parser.add_argument("--r", help="directory of a study", action="store_true") + parser.set_defaults(func=run) args = parser.parse_args() args.func(args) diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index afd75ad9..a200d361 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -146,8 +146,8 @@ class Output(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseOutpu """ Storage of data sets. """ - source = models.ForeignKey(DataFile, related_name="output_sources",on_delete=False) - figure = models.ForeignKey(DataFile, related_name="output_figures",on_delete=False) + source = models.ForeignKey(DataFile, related_name="output_sources",null=True,blank=True, on_delete=models.SET_NULL) + figure = models.ForeignKey(DataFile, related_name="output_figures",null=True,blank=True, on_delete=models.SET_NULL) pktype = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES, null=True, blank=True) time = models.FloatField(null=True,blank=True) @@ -163,8 +163,8 @@ class Timecourse(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseO """ #substance #tissue - source = models.ForeignKey(DataFile, related_name="timecourse_sources",on_delete=False) - figure = models.ForeignKey(DataFile, related_name="timecourse_figures",on_delete=False) + source = models.ForeignKey(DataFile, related_name="timecourse_sources",null=True,blank=True,on_delete=models.SET_NULL) + figure = models.ForeignKey(DataFile, related_name="timecourse_figures",null=True,blank=True, on_delete=models.SET_NULL) outputset = models.ForeignKey(OutputSet, related_name="timecourse", on_delete=models.CASCADE,null=True, blank=True) pktype = models.CharField(max_length=CHAR_MAX_LENGTH, choices=PK_DATA_CHOICES, null=True, blank=True) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 69471fcb..871d363c 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -78,7 +78,6 @@ class Meta: "substance","substance_map","tissue", "tissue_map"] def to_internal_value(self, data): - study_sid = self.context['request'].path.split("/")[-2] data = self.split_to_map(data) @@ -142,9 +141,7 @@ class Meta: "interventions_map", "substance", "substance_map", "tissue", "tissue_map"] - #def to_representation(self, instance): - # rep = super().to_representation(instance) - # return un_map(rep) + class OutputSetSerializer(ParserSerializer): diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 9e9e8b7a..1d772351 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -2,9 +2,11 @@ from lark import UnexpectedCharacters, Lark from rest_framework import serializers -from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError +from rest_framework.exceptions import ValidationError +from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from collections import OrderedDict import pandas as pd +from rest_framework.settings import api_settings from pkdb_app.interventions.models import Substance, InterventionSet, OutputSet, DataFile from pkdb_app.studies.models import Reference @@ -15,13 +17,28 @@ RELATED_SETS = {"groupset":GroupSet ,"individualset": IndividualSet,"interventionset":InterventionSet,"outputset":OutputSet} -class BaseSerializer(serializers.ModelSerializer): +class WrongKeySerializer(serializers.ModelSerializer): + + def validate_wrong_keys(self,data): + serializer_fields = self.Meta.fields + payload_keys = data.keys() + for payload_key in payload_keys: + if payload_key not in serializer_fields: + msg = {payload_key:f"<{payload_key}> is a wrong key"} + raise ValidationError(msg) + + def to_internal_value(self, data): + self.validate_wrong_keys(data) + return super().to_internal_value(data) + +class BaseSerializer(WrongKeySerializer): """ This Serializer is overwriting a the is_valid method. If sid allready exisits. It adds a instance to the class. This triggers the update method instead of the create method of the serializer. """ def is_valid(self, raise_exception=False): + if "sid" in self.initial_data.keys(): sid = self.initial_data.get("sid") self.context["study"] = sid @@ -43,6 +60,10 @@ def is_valid(self, raise_exception=False): return super().is_valid(raise_exception) + + + + @staticmethod def create_relations(study, related): for name,model in RELATED_SETS.items(): @@ -60,7 +81,6 @@ def create_relations(study, related): substance = get_or_val_error(Substance, name=substance_data) study.substances.add(substance) - #study.files.all().delete() for file_pk in related["files"]: study.files.add(file_pk) @@ -80,7 +100,9 @@ def pop_relations(validated_data): return related -class ParserSerializer(serializers.ModelSerializer): +class ParserSerializer(WrongKeySerializer): + + @staticmethod def generic_parser(data,key): @@ -97,7 +119,7 @@ def number_raw(data): return len(values) return 1 - def split_string_count(string): + def split_string_count(string,key): l = Lark('''start: WORD "{{" NUMBER "}}" %import common.NUMBER @@ -111,8 +133,8 @@ def split_string_count(string): # except UnexpectedCharacters as e: # msg = f"{string} is not maching pattern:\{{(.?[0-9]+)\}}" # raise ValidationError(str(e)) - except UnexpectedCharacters as e: - raise ValidationError(f"UnexpectedCharacters in {string}") + except UnexpectedCharacters: + raise ValidationError({key:f"UnexpectedCharacters in {string}"}) return data def list_chara(data): @@ -128,8 +150,8 @@ def list_chara(data): values = [value] if (key == "name" and len(values) != n): - msg = f"names have to be splitted and not left as <{values}>. Otherwise UniqueConstrain is violated." - raise ValidationError(msg) + msg = {f"names have to be splitted and not left as <{values}>. Otherwise UniqueConstrain is violated."} + raise ValidationError({"name": msg}) if len(values) == 1: values = values * n @@ -139,12 +161,12 @@ def list_chara(data): count_n = [] for value in values: if "{{" in value: - splitted_data = split_string_count(value) + splitted_data = split_string_count(value,key) values_n.append(splitted_data.children[0].value) count_n.append(splitted_data.children[1].value) else: values_n.append(value) - count_n.append(data.get("count", "")) + count_n.append(data.get("count", None)) values = values_n data_n["count"] = count_n @@ -224,11 +246,10 @@ def strip(data): v = v.strip() data_stripped[k] = v - return data_stripped - def to_representation(self, instance): result = super().to_representation(instance) return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) + diff --git a/pkdb_app/studies/serializers.py b/pkdb_app/studies/serializers.py index 0ba6ef98..222bab14 100644 --- a/pkdb_app/studies/serializers.py +++ b/pkdb_app/studies/serializers.py @@ -1,4 +1,5 @@ from django.contrib.sites.shortcuts import get_current_site +from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError from rest_framework import serializers from pkdb_app.utils import update_or_create_multiple, get_or_val_error @@ -7,10 +8,10 @@ from ..subjects.serializers import GroupSetSerializer, IndividualSetSerializer from ..users.models import User from .models import Reference, Author, Study -from ..serializers import BaseSerializer +from ..serializers import BaseSerializer, WrongKeySerializer -class AuthorSerializer(serializers.ModelSerializer): +class AuthorSerializer(WrongKeySerializer): id = serializers.ReadOnlyField() class Meta: @@ -76,6 +77,7 @@ def create(self, validated_data): study = self.create_relations(study,related) return study + def update(self, instance, validated_data): related = self.pop_relations(validated_data) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 6d07220e..981f0fdf 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -89,8 +89,8 @@ class Individual(IndividualMap,Sourceable,models.Model): Individuals are defined via their characteristics. """ - source = models.ForeignKey(DataFile,related_name="individual_sources", on_delete=False) - figure = models.ForeignKey(DataFile, related_name="individual_figures", on_delete=False) + source = models.ForeignKey(DataFile,related_name="individual_sources", null=True,blank=True, on_delete=models.SET_NULL) + figure = models.ForeignKey(DataFile, related_name="individual_figures", null=True,blank=True, on_delete=models.SET_NULL) individualset = models.ForeignKey(IndividualSet,on_delete=models.CASCADE, related_name="individuals") group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name="individuals",null=True, blank=True) @@ -119,7 +119,23 @@ def __str__(self): return self.name -class Characteristica(ValueableMap,Valueable, models.Model): +class CharacteristicaBase(models.Model): + + category = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) + choice = models.CharField(max_length=CHAR_MAX_LENGTH * 3, null=True, + blank=True) # check in validation that allowed choice + ctype = models.CharField(choices=CHARACTERISTICA_CHOICES, max_length=CHAR_MAX_LENGTH, + default=GROUP_CRITERIA) # this is for exclusion and inclustion + + category_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + choice_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + ctype_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + + class Meta: + abstract = True + + +class Characteristica(CharacteristicaBase,ValueableMap,Valueable, models.Model): """ Characteristic. Characteristics are used to store information about a group of subjects. @@ -136,13 +152,11 @@ class Characteristica(ValueableMap,Valueable, models.Model): This is the concrete selection/information of the characteristics. This stores the raw information. Derived values can be calculated. """ - category = models.CharField(choices=CHARACTERISTIC_CHOICES, max_length=CHAR_MAX_LENGTH) - choice = models.CharField(max_length=CHAR_MAX_LENGTH*3, null=True,blank=True) # check in validation that allowed choice + groupset = models.ForeignKey(GroupSet, related_name="characteristica", null=True, blank=True,on_delete=models.CASCADE) group = models.ForeignKey(Group, related_name="characteristica", null=True, blank=True,on_delete=models.CASCADE) individual = models.ForeignKey(Individual, related_name="characteristica", null=True,blank=True, on_delete=models.CASCADE) individualset = models.ForeignKey(IndividualSet, related_name="characteristica", null=True,blank=True, on_delete=models.CASCADE) - ctype = models.CharField(choices=CHARACTERISTICA_CHOICES, max_length=CHAR_MAX_LENGTH, default=GROUP_CRITERIA) #this is for exclusion and inclustion @property diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index a9390773..c97009e5 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,21 +1,25 @@ from django.contrib.sites.shortcuts import get_current_site +from django.core.exceptions import ValidationError from rest_framework import serializers from pkdb_app.behaviours import Sourceable from pkdb_app.utils import un_map, validate_input from .models import Group, GroupSet, Individual, IndividualSet, Characteristica, DataFile -from ..serializers import ParserSerializer +from ..serializers import ParserSerializer, WrongKeySerializer -class DataFileSerializer(serializers.ModelSerializer): + +class DataFileSerializer(WrongKeySerializer): class Meta: model = DataFile - fields = ["id","file","filetype"] + fields = ["file","filetype","id"] + extra_kwargs = {'id': {'allow_null': False}} + class CharacteristicaSerializer(ParserSerializer): count = serializers.IntegerField(required=False) class Meta: model = Characteristica - fields = ["category", "choice", "ctype", "count", "value", "mean", "median", "min", "max", "sd", "se", "cv", + fields = ["category", "category_map","choice_map","choice", "ctype","ctype_map", "count", "value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", "count_map", "value_map", "mean_map", "median_map", "min_map", "max_map", "sd_map", "se_map", "cv_map", "unit_map"] @@ -27,11 +31,11 @@ def to_representation(self, instance): def to_internal_value(self, data): data = self.split_to_map(data) - return super(CharacteristicaSerializer, self).to_internal_value(data) + return super().to_internal_value(data) - def validate(self, attrs): - data = super().validate(attrs) - return validate_input(data, "characteristica") + def validate(self,data): + validated_data = super().validate(data) + return validate_input(validated_data,"characteristica") class GroupSerializer(ParserSerializer): @@ -42,6 +46,7 @@ class Meta: fields = ["name", "count", "characteristica"] def to_internal_value(self, data): + self.validate_wrong_keys(data) data = self.generic_parser(data, "characteristica") return super(GroupSerializer, self).to_internal_value(data) @@ -55,20 +60,15 @@ class Meta: fields = ["description", "characteristica", "groups"] def to_internal_value(self, data): + self.validate_wrong_keys(data) data = self.generic_parser(data, "characteristica") return super(GroupSetSerializer, self).to_internal_value(data) -class GroupSRField(serializers.SlugRelatedField): - def get_queryset(self): - study = self.context["study"] - queryset = Group.objects.filter(groupset__study__sid=study) - return queryset - class IndividualSerializer(ParserSerializer): characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False, allow_null=True) - group = GroupSRField(slug_field='name', read_only=False, required=False, allow_null=True) + group =serializers.PrimaryKeyRelatedField(queryset=Group.objects.all(), required=False, allow_null=True) source = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True) figure = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True) @@ -77,6 +77,7 @@ class Meta: fields = Sourceable.fields() + ["name", "name_map", "group_map", "characteristica", "group","source"] def to_internal_value(self, data): + self.validate_wrong_keys(data) data = self.generic_parser(data, "characteristica") data = self.split_to_map(data) return super(IndividualSerializer, self).to_internal_value(data) @@ -121,6 +122,7 @@ def parse_individuals(self,data): class IndividualSetSerializer(ParserSerializer): + characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) individuals = IndividualSerializer(many=True, read_only=False, required=False) @@ -129,6 +131,7 @@ class Meta: fields = ["description", "individuals", "characteristica"] def to_internal_value(self, data): + self.validate_wrong_keys(data) data = self.generic_parser(data, "characteristica") return super(IndividualSetSerializer, self).to_internal_value(data) diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index 8f5f1879..c571cd29 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -1,6 +1,7 @@ import os from django.core.exceptions import ValidationError +#from rest_framework.exceptions import ValidationError from pkdb_app.categoricals import CHARACTERISTIC_DICT, CATEGORIAL_TYPE, BOOLEAN_TYPE, NUMERIC_TYPE, INTERVENTION_DICT @@ -40,11 +41,12 @@ def get_or_val_error(model, *args, **kwargs): return model.objects.get(*args, **kwargs) except model.DoesNotExist: msg = f"{model} instance with args:{args}, kwargs:{kwargs} does not exist" - return ValidationError(msg) + raise ValidationError({model:msg}) def validate_input(data,model_name): model_categoricals = {"characteristica":CHARACTERISTIC_DICT,"intervention":INTERVENTION_DICT} category = data.get("category", None) + if category: model_categorical = model_categoricals[model_name][data.get("category")] choice = data.get("choice",None) @@ -54,13 +56,12 @@ def validate_input(data,model_name): if (model_categorical.dtype == CATEGORIAL_TYPE or model_categorical.dtype == BOOLEAN_TYPE): if not choice in model_categorical.choices: msg = f"{choice} is not part of {model_categorical.choices} for {model_categorical.value}" - raise ValidationError(msg) + raise ValidationError({"choice":msg}) elif model_categorical.dtype == NUMERIC_TYPE: if not unit in model_categorical.units: - msg = f"{unit} is not allowed but required. For {model_categorical.value} allowed units are {model_categorical.units}" - raise ValidationError(msg) - + msg = f"{unit} is not allowed but unit is required. For {model_categorical.value} allowed units are {model_categorical.units}" + raise ValidationError({"unit":msg}) return data def un_map(data): From 5a5a47ba79b55f6608d3fc5568ea74aff94ddee0 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 16 Aug 2018 14:32:43 +0200 Subject: [PATCH 048/115] changed storage overwrite in files --- pkdb_app/storage.py | 8 ++++++++ pkdb_app/studies/models.py | 3 ++- pkdb_app/subjects/models.py | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 pkdb_app/storage.py diff --git a/pkdb_app/storage.py b/pkdb_app/storage.py new file mode 100644 index 00000000..f6d7ac3a --- /dev/null +++ b/pkdb_app/storage.py @@ -0,0 +1,8 @@ +from django.core.files.storage import FileSystemStorage + + +class OverwriteStorage(FileSystemStorage): + + def get_available_name(self, name, max_length=None): + self.delete(name) + return name \ No newline at end of file diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index 3343bf49..e1a27ff2 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -4,6 +4,7 @@ from django.db import models from pkdb_app.interventions.models import OutputSet, Substance, InterventionSet, DataFile +from pkdb_app.storage import OverwriteStorage from pkdb_app.subjects.models import GroupSet, IndividualSet from ..utils import CHAR_MAX_LENGTH from ..behaviours import Sidable @@ -32,7 +33,7 @@ class Reference(models.Model): abstract = models.TextField(blank=True, null=True) journal = models.TextField(blank=True, null=True) date = models.DateField() - pdf = models.FileField(upload_to="study", null=True, blank=True) + pdf = models.FileField(upload_to="study",storage=OverwriteStorage(), null=True, blank=True) authors = models.ManyToManyField(Author, blank=True, related_name='references') def __str__(self): diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 981f0fdf..a96a1b77 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -7,6 +7,7 @@ """ from django.db import models +from pkdb_app.storage import OverwriteStorage from ..behaviours import Valueable, Describable, ValueableMap, Sourceable from ..categoricals import CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES, CHARACTERISTICA_CHOICES, GROUP_CRITERIA, \ INCLUSION_CRITERIA, EXCLUSION_CRITERIA @@ -28,12 +29,11 @@ class DataFile(models.Model): This should be in a separate class, so that they can be easily displayed/filtered/... """ - file = models.FileField(upload_to="data", null=True, blank=True) # table or figure + file = models.FileField(upload_to="data", storage=OverwriteStorage() ,null=True, blank=True) # table or figure filetype = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # XLSX, PNG, CSV def __str__(self): - return self.file.name - + return self.file.nam class Set(Describable, models.Model): """ abstarct class for all set classes From 350686ff1b95ef1b0dc35771230a7f89bb835d42 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 16 Aug 2018 14:55:11 +0200 Subject: [PATCH 049/115] comments are delete during import, has to be fixed later --- pkdb_app/data_management/fill_database.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index d0b9ed1b..bd3dd13a 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -129,15 +129,34 @@ def set_keys(d, value, *keys): for key in keys[:-1]: d = d[key] d[keys[-1]] = value +def pop_comment(d, *keys): + + for key in keys[:-1]: + + if key == "comments": + d.pop("comments") + return + + d = d[key] + + + def upload_study(json_study): ok = True study_dir = os.path.dirname(json_study["study_path"]) file_dict = fill_files(study_dir) - + comments = [] for keys, item in recursive_iter(json_study): if item in file_dict.keys(): set_keys(json_study, file_dict[item], *keys) + if "comments" in keys: + comments.append(keys) + + for comment in comments: + pop_comment(json_study,*comment) + + study_partial = {} From 1717d5beab7e11b36a7fe512ced7414ed1b01bdd Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 16 Aug 2018 15:53:21 +0200 Subject: [PATCH 050/115] refactoring fill_database --- pkdb_app/comments/migrations/0001_initial.py | 2 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/data_management/add_groups.py | 14 +- pkdb_app/data_management/add_intervention.py | 6 +- pkdb_app/data_management/add_output.py | 6 +- pkdb_app/data_management/fill_database.py | 156 ++++++++++++------ pkdb_app/data_management/study_upload.py | 14 +- requirements.txt | 2 + 8 files changed, 127 insertions(+), 77 deletions(-) diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index 3e1592a3..ee3a4692 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-16 10:30 +# Generated by Django 2.0.6 on 2018-08-16 12:58 from django.db import migrations, models diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index acecefc2..f7c3e623 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-16 10:30 +# Generated by Django 2.0.6 on 2018-08-16 12:58 from django.conf import settings from django.db import migrations, models @@ -9,7 +9,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('comments', '0002_auto_20180816_1030'), + ('comments', '0002_auto_20180816_1258'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py index 388961dd..2094eb68 100644 --- a/pkdb_app/data_management/add_groups.py +++ b/pkdb_app/data_management/add_groups.py @@ -7,7 +7,7 @@ BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from pkdb_app.data_management.fill_database import get_study_json_path, open_study +from pkdb_app.data_management.fill_database import get_study_paths, read_study_json from pkdb_app.data_management.initialize_study import save_study, study_filename, SEPERATOR from pkdb_app.categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE from pkdb_app.data_management.create_reference_caffeine import SUBJECTSPATH, INDIVIDUALPATH @@ -167,8 +167,8 @@ def get_graph_study(**options): graph = bonobo.Graph() # add studies graph.add_chain( - get_study_json_path, - open_study, + get_study_paths, + read_study_json, add_groupset_to_study, add_group_to_groupset, save_study, @@ -179,8 +179,8 @@ def get_graph_study(**options): def get_graph_groupset_chara(**options): graph = bonobo.Graph() graph.add_chain( - get_study_json_path, - open_study, + get_study_paths, + read_study_json, add_characteristica_groupset, save_study, ) @@ -189,8 +189,8 @@ def get_graph_groupset_chara(**options): def get_graph_groupset_individual(**options): graph = bonobo.Graph() graph.add_chain( - get_study_json_path, - open_study, + get_study_paths, + read_study_json, add_individual_set, save_study, ) diff --git a/pkdb_app/data_management/add_intervention.py b/pkdb_app/data_management/add_intervention.py index d7b3d2ec..4d11fa0f 100644 --- a/pkdb_app/data_management/add_intervention.py +++ b/pkdb_app/data_management/add_intervention.py @@ -7,7 +7,7 @@ BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from pkdb_app.data_management.fill_database import get_study_json_path, open_study +from pkdb_app.data_management.fill_database import get_study_paths, read_study_json from pkdb_app.data_management.create_reference_caffeine import DOSINGPATH, ensure_dir from pkdb_app.data_management.initialize_study import save_study, SEPERATOR from pkdb_app.utils import create_if_exists, clean_import @@ -55,8 +55,8 @@ def get_graph_study(**options): graph = bonobo.Graph() # add studies graph.add_chain( - get_study_json_path, - open_study, + get_study_paths, + read_study_json, add_intervention_to_study, save_study, ) diff --git a/pkdb_app/data_management/add_output.py b/pkdb_app/data_management/add_output.py index 6188949a..d03e6552 100644 --- a/pkdb_app/data_management/add_output.py +++ b/pkdb_app/data_management/add_output.py @@ -5,7 +5,7 @@ sys.path.append(BASEPATH) -from pkdb_app.data_management.fill_database import get_study_json_path, open_study +from pkdb_app.data_management.fill_database import get_study_paths, read_study_json from pkdb_app.data_management.create_reference_caffeine import PHARMACOKINETICSPATH, TIMECOURSEPATH, OUTPUTINDIVIDUALPATH from pkdb_app.data_management.initialize_study import save_study from pkdb_app.utils import create_if_exists, clean_import @@ -87,8 +87,8 @@ def get_graph_study(**options): graph = bonobo.Graph() # add studies graph.add_chain( - get_study_json_path, - open_study, + get_study_paths, + read_study_json, inizialize_output, add_individualmapping_to_ouput, add_timecourse_to_ouput, diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index bd3dd13a..552022f6 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -1,76 +1,128 @@ -import os, sys +""" +Script to load data into database. + +Needs location of directory with data. +Uses bonobo framework, a lightweight extract-transform-load (ETL) framework, +for data transformation and preparation. + +The upload expects a certain folder structure: +- folder name is STUDYNAME, e.g., Albert1974 +- folder contains pdf as STUDYNAME.pdf, e.g., Albert1974.pdf +- folder contains reference information as `reference.json` +- folder contains study information as `study.json` +- folder contains additional files associated with study, i.e., + - tables, named STUDYNAME_Tab[0-9]*.png, e.g., Albert1974_Tab1.png + - figures, named STUDYNAME_Fig[0-9]*.png, e.g., Albert1974_Fig2.png + - excel file, named STUDYNAME.xlsx, e.g., Albert1974.xlsx + - data files, named STUDYNAME_Tab[0-9]*.csv or STUDYNAME_Fig[0-9]*.csv + +Details about the JSON schema are given elsewhere (JSON schema and REST API). +""" +import os +import sys import bonobo import coreapi import json import requests +from jsonschema import validate BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from jsonschema import validate from pkdb_app.data_management.schemas import reference_schema -import logging -import mondrian -# One line setup (excepthook=True tells mondrian to handle uncaught exceptions) -#mondrian.setup(excepthook=True) -# Use logging, as usual. -#logger = logging.getLogger() -#logger.setLevel(logging.DEBUG) +from pkdb_app.data_management.create_reference_caffeine import REFERENCESMASTERPATH -if hasattr (sys, 'tracebacklimit'): - del sys.tracebacklimit -class Stop (Exception): - def __init__ (self): - sys.tracebacklimit = 0 +# FIXME: implement proper logging +# ----------------------------- +# user information +# ----------------------------- PASSWORD = "test" -Jan_G_U = {"username":"janekg","first_name":"Jan","last_name":"Grzegorzewski","email":"Janekg89@hotmail.de","password":PASSWORD} -Matthias_K = {"username":"mkoenig","first_name":"Matthias","last_name":"König","email":"konigmatt@googlemail.com","password":PASSWORD} +USERS = [ + {"username": "janekg", "first_name": "Jan", "last_name": "Grzegorzewski", "email": "Janekg89@hotmail.de", + "password": PASSWORD}, + {"username": "mkoenig", "first_name": "Matthias", "last_name": "König", "email": "konigmatt@googlemail.com", + "password": PASSWORD} +] + +# ----------------------------- +# master path +# ----------------------------- +MASTER_PATH = REFERENCESMASTERPATH -USERS = [Jan_G_U, Matthias_K] +def setup_database(): + """ Creates core information in database. -def get_reference_json_path(): + This information is independent of study information. E.g., users, substances, + categorials. + + :return: + """ + # FIXME: use requests instead of core api + from pkdb_app.categoricals import SUBSTANCES_DATA + for substance in SUBSTANCES_DATA: + client.action(document, ["substances", "create"], params={"name": substance}) + for user in USERS: + client.action(document, ["users", "create"], params=user) - fill_user_and_substances() - from pkdb_app.data_management.create_reference_caffeine import REFERENCESMASTERPATH - for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): - if "reference.json" in files: - json_file = os.path.join(root, 'reference.json') - pdf_file = os.path.join(root,f"{os.path.basename(root)}.pdf") +# ------------------------------- +# Paths of JSON files +# ------------------------------- +def _get_paths(filename): + """ Finds paths of filename recursively in MASTER_PATH. """ + for root, dirs, files in os.walk(MASTER_PATH, topdown=False): + if filename in files: + yield os.path.join(root, filename) - yield {"json":json_file , "pdf": pdf_file} +def get_reference_paths(): + """ Finds paths of reference JSON files and corresponding PDFs. -def get_study_json_path(): - from pkdb_app.data_management.create_reference_caffeine import REFERENCESMASTERPATH - for root, dirs, files in os.walk(REFERENCESMASTERPATH, topdown=False): - if "study.json" in files: - yield os.path.join(root, 'study.json') + :return: dict + """ + for path in _get_paths("reference.json"): + pdf_path = os.path.join(os.path.dirname(path), f"{os.path.basename(path)}.pdf") + yield {"reference_path": path, "pdf": pdf_path} -def open_reference(d): - with open(d["json"]) as f: - try: - json_dict = json.loads(f.read()) - except json.decoder.JSONDecodeError as err: - print(err) - return - return {"json":json_dict,"pdf":d["pdf"], "reference_path":d["json"]} +def get_study_paths(): + """ Finds paths of study JSON files. """ + _get_paths("study.json") -def open_study(d): - with open(d) as f: +# ------------------------------- +# Read JSON files +# ------------------------------- +def _read_json(path): + """ Reads json. + + :param path: returns json, or None if parsing failed. + :return: + """ + with open(path) as f: try: - json_dict = json.loads(f.read()) + json_data = json.loads(f.read()) except json.decoder.JSONDecodeError as err: print(err) return + return json_data + + +def read_reference_json(d): + """ Reads JSON for reference. """ + path = d["reference_path"] + d2 = d.copy() + d2["json"] = _read_json(path) + return d2 +def read_study_json(path): + return {"json": _read_json(path), + "study_path": path} + - return {"json":json_dict, "study_path":d} def upload_reference(json_reference): @@ -94,14 +146,6 @@ def upload_reference(json_reference): -def fill_user_and_substances(): - from pkdb_app.categoricals import SUBSTANCES_DATA - for substance in SUBSTANCES_DATA: - client.action(document, ["substances", "create"], params={"name":substance}) - for user in USERS: - client.action(document, ["users", "create"], params=user) - - def fill_files(file_path): data_dict = {} head, sid = os.path.split(file_path) @@ -211,8 +255,8 @@ def get_graph_references(**options): graph = bonobo.Graph() # add studies graph.add_chain( - get_reference_json_path, - open_reference, + get_reference_paths, + read_reference_json, upload_reference, ) return graph @@ -221,8 +265,8 @@ def get_graph_study(**options): graph = bonobo.Graph() # add studies graph.add_chain( - get_study_json_path, - open_study, + get_study_paths, + read_study_json, upload_study, ) return graph @@ -236,6 +280,10 @@ def get_services(**options): client = coreapi.Client() document = client.get("http://0.0.0.0:8000/") + # core database setup + setup_database() + + # run the bonobo chain parser = bonobo.get_argument_parser() with bonobo.parse_args(parser) as options: bonobo.run(get_graph_references(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/study_upload.py b/pkdb_app/data_management/study_upload.py index 1be1c34c..03eb1034 100644 --- a/pkdb_app/data_management/study_upload.py +++ b/pkdb_app/data_management/study_upload.py @@ -4,7 +4,7 @@ from collections import namedtuple BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from pkdb_app.data_management.fill_database import open_reference, open_study, upload_reference,upload_study +from pkdb_app.data_management.fill_database import read_reference_json, read_study_json, upload_reference,upload_study from pkdb_app.data_management.reference_create import run as create_reference @@ -16,8 +16,8 @@ def run(args): reference_path = os.path.join(args.study, "reference.json") reference_pdf = os.path.join(args.study, f"{study_name}.pdf") - if open_study(study_path) and hasattr(args, 'r'): - study = open_study(study_path) + if read_study_json(study_path) and hasattr(args, 'r'): + study = read_study_json(study_path) Reference = namedtuple("Reference",["reference", "name", "pmid"]) ref = Reference(reference=args.study,name=study_name, pmid=study["json"]["reference"]) create_reference(ref) @@ -25,16 +25,16 @@ def run(args): if os.path.isfile(reference_path): reference_dict = {"json": reference_path, "pdf": reference_pdf} - if open_reference(reference_dict): - ok_ref = upload_reference(open_reference(reference_dict)) + if read_reference_json(reference_dict): + ok_ref = upload_reference(read_reference_json(reference_dict)) if not ok_ref: ok = ok_ref else: ok = False if os.path.isfile(study_path): - if open_study(study_path): - ok_study = upload_study(open_study(study_path)) + if read_study_json(study_path): + ok_study = upload_study(read_study_json(study_path)) if not ok_study: ok = ok_study else: diff --git a/requirements.txt b/requirements.txt index 9739a7c2..823d2d86 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ +pip==18.0 + # Core pytz==2018.4 Django==2.0.6 From 20b3fddb14fdbade95fe46b2d03d7062293b91fb Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 16 Aug 2018 16:09:13 +0200 Subject: [PATCH 051/115] refactored fill_database --- pkdb_app/data_management/fill_database.py | 146 ++++++++++++---------- 1 file changed, 79 insertions(+), 67 deletions(-) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 552022f6..bf609373 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -40,9 +40,9 @@ PASSWORD = "test" USERS = [ {"username": "janekg", "first_name": "Jan", "last_name": "Grzegorzewski", "email": "Janekg89@hotmail.de", - "password": PASSWORD}, + "password": PASSWORD}, {"username": "mkoenig", "first_name": "Matthias", "last_name": "König", "email": "konigmatt@googlemail.com", - "password": PASSWORD} + "password": PASSWORD} ] # ----------------------------- @@ -123,43 +123,12 @@ def read_study_json(path): "study_path": path} - - -def upload_reference(json_reference): - ok = True - validate(json_reference["json"],reference_schema) - #client.action(document, ["references", "create"], params=json_reference["json"]) - response = requests.post(f'http://0.0.0.0:8000/api/v1/references/', json=json_reference["json"]) - if not response.status_code == 201: - print(json_reference["json"]["name"], response.text) - ok = False - - - with open(json_reference["pdf"],'rb') as f: - response = requests.patch(f'http://0.0.0.0:8000/api/v1/references/{json_reference["json"]["sid"]}/', files={"pdf":f}) - - if not response.status_code == 200: - print(json_reference["json"]["name"], response.text) - ok = False - - return ok - - - -def fill_files(file_path): - data_dict = {} - head, sid = os.path.split(file_path) - study_dir = os.path.join(head,sid) - for root, dirs, files in os.walk(study_dir, topdown=False): - files = set(files) - set(['reference.json', 'study.json', f'{sid}.pdf']) - for file in files: - file_path = os.path.join(root, file) - with open(file_path,'rb') as f: - response = requests.post(f'http://0.0.0.0:8000/api/v1/datafiles/', files={"file": f}) - data_dict[file] = response.json()["id"] - return data_dict +# ------------------------------- +# Helpers +# ------------------------------- def recursive_iter(obj, keys=()): + """ Creates dictionary with key:object from nested JSON data structure. """ if isinstance(obj, dict): for k, v in obj.items(): yield from recursive_iter(v, keys + (k,)) @@ -169,27 +138,77 @@ def recursive_iter(obj, keys=()): else: yield keys, obj + def set_keys(d, value, *keys): + """ Changes keys in nested dictionary. """ for key in keys[:-1]: d = d[key] d[keys[-1]] = value -def pop_comment(d, *keys): + +def pop_comment(d, *keys): + """ Pops comment in nested dictionary. """ for key in keys[:-1]: - if key == "comments": + if key == "comments": d.pop("comments") return d = d[key] +# ------------------------------- +# Upload JSON in database +# ------------------------------- +API_URL = "http://0.0.0.0:8000/api/v1" + + +def upload_files(file_path): + """ Uploads all files in directory of given file. + + :param file_path: + :return: dict with all keys for files + """ + data_dict = {} + head, sid = os.path.split(file_path) + study_dir = os.path.join(head, sid) + for root, dirs, files in os.walk(study_dir, topdown=False): + files = set(files) - set(['reference.json', 'study.json', f'{sid}.pdf']) + for file in files: + file_path = os.path.join(root, file) + with open(file_path, 'rb') as f: + response = requests.post(f'{API_URL}/datafiles/', files={"file": f}) + data_dict[file] = response.json()["id"] + return data_dict + + +def upload_reference(json_reference): + """ Uploads reference JSON. """ + success = True + validate(json_reference["json"], reference_schema) + + # post + response = requests.post(f'{API_URL}/references/', json=json_reference["json"]) + if not response.status_code == 201: + print(json_reference["json"]["name"], response.text) + success = False + + # patch + with open(json_reference["pdf"], 'rb') as f: + response = requests.patch(f'{API_URL}/references/{json_reference["json"]["sid"]}/', files={"pdf": f}) + + if not response.status_code == 200: + print(json_reference["json"]["name"], response.text) + success = False + + return success def upload_study(json_study): - ok = True + """ Uploads study JSON. """ + success = True study_dir = os.path.dirname(json_study["study_path"]) - file_dict = fill_files(study_dir) + file_dict = upload_files(study_dir) comments = [] for keys, item in recursive_iter(json_study): if item in file_dict.keys(): @@ -198,12 +217,9 @@ def upload_study(json_study): comments.append(keys) for comment in comments: - pop_comment(json_study,*comment) - - + pop_comment(json_study, *comment) study_partial = {} - study_partial["sid"] = json_study["json"]["sid"] study_partial["name"] = json_study["json"]["name"] study_partial["pkdb_version"] = json_study["json"]["pkdb_version"] @@ -213,44 +229,38 @@ def upload_study(json_study): study_partial["curators"] = json_study["json"]["curators"] study_partial["creator"] = json_study["json"]["creator"] study_partial["files"] = list(file_dict.values()) - #study_partial["bla"] = "bla" - - - - - #client.action(document, ["studies", "create"], params=study_partial) - response = requests.post(f'http://0.0.0.0:8000/api/v1/studies/', - json=study_partial) + # post + response = requests.post(f'{API_URL}/studies/', json=study_partial) if not response.status_code == 201: - print(json_study["json"]["name"],response.text) - ok = False - - - + print(json_study["json"]["name"], response.text) + success = False study_partial2 = {} study_partial2["groupset"] = json_study["json"]["groupset"] study_partial2["interventionset"] = json_study["json"]["interventionset"] study_partial2["individualset"] = json_study["json"].get("individualset", None) - - response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = study_partial2) + # patch + response = requests.patch(f'{API_URL}/studies/{json_study["json"]["sid"]}/', json=study_partial2) if not response.status_code == 200: print(json_study["json"]["name"], response.text) - ok = False + success = False + # patch if "outputset" in json_study["json"].keys(): - response = requests.patch(f'http://0.0.0.0:8000/api/v1/studies/{json_study["json"]["sid"]}/', json = {"outputset": json_study["json"].get("outputset")}) + response = requests.patch(f'{API_URL}/studies/{json_study["json"]["sid"]}/', + json={"outputset": json_study["json"].get("outputset")}) if not response.status_code == 200: - print(json_study["json"]["name"],response.text) - ok = False + print(json_study["json"]["name"], response.text) + success = False - return ok - - #study_partial["outputset"] = json_study["json"].get("outputset",None) + return success +# ------------------------------- +# Bonobo +# ------------------------------- def get_graph_references(**options): graph = bonobo.Graph() # add studies @@ -261,6 +271,7 @@ def get_graph_references(**options): ) return graph + def get_graph_study(**options): graph = bonobo.Graph() # add studies @@ -276,6 +287,7 @@ def get_services(**options): return {} +# ------------------------------------------------------------------------------- if __name__ == '__main__': client = coreapi.Client() document = client.get("http://0.0.0.0:8000/") From e94e92f16110657fe7d53e8adcf3a1cf7529212c Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 16 Aug 2018 16:44:20 +0200 Subject: [PATCH 052/115] fill database refactored --- pkdb_app/data_management/add_groups.py | 207 ------------------ pkdb_app/data_management/add_intervention.py | 72 ------ pkdb_app/data_management/add_output.py | 109 --------- pkdb_app/data_management/create_reference.py | 112 ++++++++++ .../create_reference_acetaminophen.py | 175 --------------- .../create_reference_caffeine.py | 177 --------------- pkdb_app/data_management/create_study_json.sh | 2 - pkdb_app/data_management/fill_database.py | 37 ++-- pkdb_app/data_management/initialize_study.py | 70 ------ pkdb_app/data_management/reference_create.py | 31 --- pkdb_app/data_management/study_upload.py | 44 ++-- pkdb_app/data_management/study_watch.py | 25 ++- pkdb_app/utils.py | 2 + requirements.txt | 3 +- 14 files changed, 173 insertions(+), 893 deletions(-) delete mode 100644 pkdb_app/data_management/add_groups.py delete mode 100644 pkdb_app/data_management/add_intervention.py delete mode 100644 pkdb_app/data_management/add_output.py create mode 100644 pkdb_app/data_management/create_reference.py delete mode 100644 pkdb_app/data_management/create_reference_acetaminophen.py delete mode 100644 pkdb_app/data_management/create_reference_caffeine.py delete mode 100755 pkdb_app/data_management/create_study_json.sh delete mode 100644 pkdb_app/data_management/initialize_study.py delete mode 100644 pkdb_app/data_management/reference_create.py diff --git a/pkdb_app/data_management/add_groups.py b/pkdb_app/data_management/add_groups.py deleted file mode 100644 index 2094eb68..00000000 --- a/pkdb_app/data_management/add_groups.py +++ /dev/null @@ -1,207 +0,0 @@ -import os -import sys -from pprint import pprint -import pandas as pd -import bonobo - -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) -sys.path.append(BASEPATH) - -from pkdb_app.data_management.fill_database import get_study_paths, read_study_json -from pkdb_app.data_management.initialize_study import save_study, study_filename, SEPERATOR -from pkdb_app.categoricals import CHARACTERISTIC_CATEGORIES,CHARACTERISTIC_DTYPE -from pkdb_app.data_management.create_reference_caffeine import SUBJECTSPATH, INDIVIDUALPATH -from pkdb_app.utils import create_if_exists, clean_import - - -def add_groupset_to_study(study): - study_json = {**study["json"]} - subject_pd = pd.read_csv(SUBJECTSPATH,delimiter='\t',keep_default_na=False) - this_subject = subject_pd[subject_pd["reference"] == study_json["name"]] - this_subject = this_subject.replace({'NA':None}) - #this_subject.columns = [c.replace('_', ' ') for c in this_subject.columns] - study_json["groupset"] = {} - try: - test = this_subject["description"].unique()[0] - study_json["groupset"]["description"] = SEPERATOR.join(this_subject["description"].unique()) - except IndexError: - print( f'{study_json["name"]}: has no group') - - if len(this_subject) > 1: - study_json["groupset"]["characteristica"] = [] - study_json["groupset"]["groups"] = [] - - for group in this_subject.itertuples(): - #print(group.reset_index().to_dict()) - #print(group) - #print(group.to_dict("records")) - yield {"json": study_json,"group": group._asdict(), "study_path": study["study_path"]} - - -def add_group_to_groupset(data): - - data_group = { k.replace('_', ' '):v for k,v in data["group"].items()} - print(data_group) - #add groupsets - ####################################################### - group = {} - - group["count"] = data["group"]["count"] - group["name"] = data["group"]["groups"] - #group["description"] = data["group"]["description"] - group["characteristica"] = add_characteristic_values(data_group) - json = {**data["json"]} - json["groupset"]["groups"].append(group) - return {"json":json, "study_path":data["study_path"]} - -def add_characteristica_groupset(data): - - this_data = {**data} - groups = this_data["json"]["groupset"]["groups"] - number_of_groups = len(groups) - - if number_of_groups > 1: - new_groups =[] - for group in groups: - new_chara = [] - for characteristica in group['characteristica']: - characteristica.pop("count",None) - new_chara.append(tuple(characteristica.items())) - new_groups.append(set(new_chara)) - - groupset_chara_tuples = set.intersection(*new_groups) - groupset_dict = [dict(x) for x in groupset_chara_tuples] - this_data["json"]["groupset"]["characteristica"] = groupset_dict - - new_groups = [group - groupset_chara_tuples for group in new_groups] - groups_dict = [list(map(dict,x)) for x in new_groups] - - for i, group in enumerate(groups_dict): - this_data["json"]["groupset"]["groups"][i]['characteristica'] = group - - return this_data - - -def add_individual_set(data): - this_data = {**data} - individials_pd = pd.read_csv(INDIVIDUALPATH, delimiter='\t', keep_default_na=False) - this_individuals = individials_pd[individials_pd["study"] == this_data["json"]["name"]] - this_individuals.replace({'NA': None}, inplace=True) - - if len(this_individuals) > 0: - this_data["json"]["individualset"] = {} - - this_data["json"]["individualset"]["description"] = "" - this_data["json"]["individualset"]["individuals"] = [] - - for individuals in this_individuals.itertuples(): - individuals_dict_raw = individuals._asdict() - individuals_dict_raw = {k.replace('_', ' '): v for k, v in individuals_dict_raw.items()} - - individuals_dict = {} - individuals_dict["name"] = individuals_dict_raw["name"] - individuals_dict["group"] = individuals_dict_raw["group"] - individuals_dict["source"] = individuals_dict_raw["source"] - individuals_dict["format"] = individuals_dict_raw["format"] - individuals_dict["figure"] = individuals_dict_raw["figure"] - individuals_dict['characteristica'] = add_characteristic_values(individuals_dict_raw) - this_data["json"]["individualset"]["individuals"].append(clean_import(individuals_dict)) - - - return this_data - - - - -def add_characteristic_values(group): - characteristics_values = [] - for category in CHARACTERISTIC_CATEGORIES: - for characteristics_value in process_characteristic_values(group,category): - temp_characteristics_value = {**characteristics_value} - for key in ["category","count"]: - temp_characteristics_value.pop(key,None) - if not temp_characteristics_value == {}: - characteristics_values.append(characteristics_value) - return characteristics_values - - -def process_characteristic_values(group,category): - this_value = str(group.get("category","")) - if this_value.strip().replace('.','',1).isdigit() or CHARACTERISTIC_DTYPE[category] == "numeric": - - numeric_data = {} - numeric_data["category"] = category - group["count"] = group.get("count",1) - if "new_count" in group: - numeric_data["count"] = group["new_count"] - - if group["count"] > 1: - numeric_data = create_if_exists(group,category,numeric_data,"mean") - numeric_data = create_if_exists(group,f"{category} median",numeric_data,"median") - numeric_data = create_if_exists(group,f"{category} min",numeric_data,"min") - numeric_data = create_if_exists(group,f"{category} max",numeric_data,"max") - numeric_data = create_if_exists(group,f"{category} sd",numeric_data,"sd") - numeric_data = create_if_exists(group,f"{category} se",numeric_data,"se") - numeric_data = create_if_exists(group,f"{category} cv",numeric_data,"cv") - - else: - numeric_data = create_if_exists(group,category,numeric_data,"value") - - numeric_data = create_if_exists(group, f"{category} unit", numeric_data, "unit") - - return [clean_import(numeric_data)] - - else: - categorical_data = {} - if "new_count" in group: - categorical_data["count"] = group["new_count"] - - - - categorical_data["category"] = category - categorical_data = create_if_exists(group, category, categorical_data, "choice") - - return [clean_import(categorical_data)] - -def get_graph_study(**options): - graph = bonobo.Graph() - # add studies - graph.add_chain( - get_study_paths, - read_study_json, - add_groupset_to_study, - add_group_to_groupset, - save_study, - ) - return graph - - -def get_graph_groupset_chara(**options): - graph = bonobo.Graph() - graph.add_chain( - get_study_paths, - read_study_json, - add_characteristica_groupset, - save_study, - ) - return graph - -def get_graph_groupset_individual(**options): - graph = bonobo.Graph() - graph.add_chain( - get_study_paths, - read_study_json, - add_individual_set, - save_study, - ) - return graph -def get_services(**options): - return {} - - -if __name__ == '__main__': - parser = bonobo.get_argument_parser() - with bonobo.parse_args(parser) as options: - bonobo.run(get_graph_study(**options), services=get_services(**options)) - bonobo.run(get_graph_groupset_chara(**options), services=get_services(**options)) - bonobo.run(get_graph_groupset_individual(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/add_intervention.py b/pkdb_app/data_management/add_intervention.py deleted file mode 100644 index 4d11fa0f..00000000 --- a/pkdb_app/data_management/add_intervention.py +++ /dev/null @@ -1,72 +0,0 @@ -import bonobo -import pandas as pd -import os -import sys -import json - -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) -sys.path.append(BASEPATH) - -from pkdb_app.data_management.fill_database import get_study_paths, read_study_json -from pkdb_app.data_management.create_reference_caffeine import DOSINGPATH, ensure_dir -from pkdb_app.data_management.initialize_study import save_study, SEPERATOR -from pkdb_app.utils import create_if_exists, clean_import - -def add_intervention_to_study(study): - dosing_pd = pd.read_csv(DOSINGPATH, delimiter='\t') - study_json = {**study["json"]} - study_json["interventionset"] = {} - this_interventions = dosing_pd[dosing_pd["study"] == study_json["name"]] - this_interventions.replace({'NA':None}, inplace=True) - - try: - test = this_interventions["dosing_details"].unique()[0] - study_json["interventionset"]["description"] = SEPERATOR.join(this_interventions["dosing_details"].unique()) - except IndexError: - print( f'{study_json["name"]}:has no Interventions') - - study_json["interventionset"]["interventions"] = [] - - for i, row in this_interventions.iterrows(): - intervention_json = {} - intervention_json["name"] = row["dosing"] - intervention_json["substance"] = row["substance"] - intervention_json["time"] = row["time"] - intervention_json["time_unit"] = row["time_unit"] - intervention_json["route"] = row["route"] - intervention_json["form"] = row["form"] - intervention_json["value"] = row["dose"] - intervention_json["unit"] = row["dose_unit"] - intervention_json["category"] = row["category"] - - study_json["interventionset"]["interventions"].append(clean_import(intervention_json)) - - yield {"json":study_json,"study_path": study["study_path"]} - - - -def save_reference(d): - ensure_dir(d["interventions_file"]) - with open(d["interventions_file"], 'a') as fp: - json.dump(d['json'], fp, indent=4) - - -def get_graph_study(**options): - graph = bonobo.Graph() - # add studies - graph.add_chain( - get_study_paths, - read_study_json, - add_intervention_to_study, - save_study, - ) - return graph - -def get_services(**options): - return {} - - -if __name__ == '__main__': - parser = bonobo.get_argument_parser() - with bonobo.parse_args(parser) as options: - bonobo.run(get_graph_study(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/add_output.py b/pkdb_app/data_management/add_output.py deleted file mode 100644 index d03e6552..00000000 --- a/pkdb_app/data_management/add_output.py +++ /dev/null @@ -1,109 +0,0 @@ -import bonobo -import pandas as pd -import os,sys -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) -sys.path.append(BASEPATH) - - -from pkdb_app.data_management.fill_database import get_study_paths, read_study_json -from pkdb_app.data_management.create_reference_caffeine import PHARMACOKINETICSPATH, TIMECOURSEPATH, OUTPUTINDIVIDUALPATH -from pkdb_app.data_management.initialize_study import save_study -from pkdb_app.utils import create_if_exists, clean_import - -def inizialize_output(study): - study_json = {**study["json"]} - study_json["outputset"] = {} - study_json["outputset"]["description"] = "" - study_json["outputset"]["outputs"] = [] - yield {"json": study_json, "study_path": study["study_path"]} - -def add_outputs_to_study(study): - dosing_pd = pd.read_csv(PHARMACOKINETICSPATH, delimiter='\t') - study_json = {**study["json"]} - - study_output = dosing_pd[dosing_pd["study"] == study_json["name"]] - for name, data in study_output.groupby(["subjects", "dosing","substance"]): - output = {} - output["group"] = name[0] - interventions = name[1].split(",") - output["interventions"] = list(map(str.strip,interventions)) - - - output["substance"] = name[2] - - for i, row in data.iterrows(): - - output["pktype"] = row["pktype"] - output["value"] = row["value"] - output['tissue'] = row["tissue"] - output['sd'] = row["sd"] - output['se'] = row["se"] - output['cv'] = row["cv"] - output['min'] = row["min"] - output['max'] = row["max"] - output['unit'] = row["unit"] - study_json["outputset"]["outputs"].append(clean_import(output)) - - yield {"json":study_json,"study_path": study["study_path"]} - -def add_timecourse_to_ouput(data): - this_data = {**data} - timecourse_pd = pd.read_csv(TIMECOURSEPATH, delimiter='\t', keep_default_na=False, encoding="utf-8") - this_timecourse = timecourse_pd[timecourse_pd["study"] == this_data["json"]["name"]] - this_timecourse.replace({'NA': None}, inplace=True) - - if len(this_timecourse) > 0: - this_data["json"]["outputset"]["timecourse"] = [] - for timecourse in this_timecourse.itertuples(index=False): - timecourse_dict = timecourse._asdict() - timecourse_dict.pop("study") - if ("interventions" in timecourse_dict and timecourse_dict["interventions"]): - timecourse_dict["interventions"] = list( - map(str.strip, timecourse_dict["interventions"].split(","))) - - this_data["json"]["outputset"]["timecourse"].append(clean_import(timecourse_dict)) - - - return this_data - -def add_individualmapping_to_ouput(data): - this_data = {**data} - individuals_output_pd = pd.read_csv(OUTPUTINDIVIDUALPATH, delimiter='\t', keep_default_na=False, encoding="utf-8") - this_individuals_output = individuals_output_pd[individuals_output_pd["study"] == this_data["json"]["name"]] - this_individuals_output.replace({'NA': None}, inplace=True) - - if len(this_individuals_output) > 0: - for individuals_output in this_individuals_output.itertuples(index=False): - individuals_output_dict = individuals_output._asdict() - individuals_output_dict.pop("study") - if ("interventions" in individuals_output_dict and individuals_output_dict["interventions"]): - individuals_output_dict["interventions"] = list(map(str.strip,individuals_output_dict["interventions"].split(","))) - - this_data["json"]["outputset"]["outputs"].append(clean_import(individuals_output_dict)) - return this_data - - -def get_graph_study(**options): - graph = bonobo.Graph() - # add studies - graph.add_chain( - get_study_paths, - read_study_json, - inizialize_output, - add_individualmapping_to_ouput, - add_timecourse_to_ouput, - add_outputs_to_study, - save_study, - ) - return graph - -def get_services(**options): - return {} - - -if __name__ == '__main__': - parser = bonobo.get_argument_parser() - with bonobo.parse_args(parser) as options: - bonobo.run(get_graph_study(**options), services=get_services(**options)) - - diff --git a/pkdb_app/data_management/create_reference.py b/pkdb_app/data_management/create_reference.py new file mode 100644 index 00000000..ca02b1f7 --- /dev/null +++ b/pkdb_app/data_management/create_reference.py @@ -0,0 +1,112 @@ +""" +Creates reference.json from given PMID id. +""" +import argparse +import os +import sys +import xml.etree.ElementTree as ET +from Bio import Entrez +import json +import requests +from pkdb_app.utils import ensure_dir + + +BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) +sys.path.append(BASEPATH) + +# FIXME: get proper email +ENTREZ_EMAIL = 'janekg89@hotmail.de' + + +def run(args): + ref_dict = {"reference_path": args.reference, + "name": args.name, + "pmid": args.pmid} + save_json(add_doi(create_json(xml_to_data(load_from_biopython(ref_dict))))) + + +def load_from_biopython(d): + """ Retrieves pubmed information. + + :param d: + :return: + """ + Entrez.email = ENTREZ_EMAIL + handle = Entrez.efetch(db='pubmed', id=d['pmid'], retmode='xml') + all_info = handle.read() + handle.close() + return {**d, 'xml': all_info} + + +def xml_to_data(d): + return {**d, 'data': ET.fromstring(d['xml'])} + + +def create_json(d): + """ Creates reference.json""" + json_dict = {} + json_dict["pmid"] = d["pmid"] + json_dict["name"] = d["name"] + json_dict["sid"] = d["pmid"] + for date in d["data"].iter("DateCompleted"): + year = date.find('Year').text + month = date.find('Month').text + day = date.find('Day').text + json_dict["date"] = f"{year}-{str(month).zfill(2)}-{str(day).zfill(2)}" + continue + for journal in d["data"].iter("Title"): + json_dict["journal"] = journal.text + continue + for title in d["data"].iter("ArticleTitle"): + json_dict["title"] = title.text + continue + for abstract in d["data"].iter("AbstractText"): + json_dict["abstract"] = abstract.text + continue + + authors = [] + for author in d["data"].iter("Author"): + author_dict = {} + author_dict["first_name"] = author.find("ForeName").text + author_dict["last_name"] = author.find("LastName").text + authors.append(author_dict) + json_dict["authors"] = authors + return {'json': json_dict, 'reference_path': d["reference_path"]} + + +def add_doi(d): + """ Try to get DOI. + + :param d: + :return: + """ + json_dict = d["json"] + response = requests.get(f'https://www.ncbi.nlm.nih.gov/pmc/utils/idconv/v1.0/?tool=my_tool&email=my_email@example.com&ids={json_dict["pmid"]}') + pmcids = ET.fromstring(response.content) + for records in pmcids.iter("record"): + json_dict["doi"] = records.get('doi', "") + + return {"json":json_dict, "reference_path": d["reference_path"]} + + +def save_json(d): + json_file = os.path.join(d["reference_path"],"reference.json") + ensure_dir(json_file) + with open(json_file, 'w') as fp: + json.dump(d['json'], fp, indent=4) + + +def main(): + parser = argparse.ArgumentParser(description="Get Pubmed information as JSON") + parser.add_argument("-s", help="directory of a reference", dest="reference", type=str, required=True) + parser.add_argument("-n", help="name of reference", dest="name", type=str, required=True) + parser.add_argument("-p", help="pmid", dest="pmid", type=str, required=True) + + # call run function + parser.set_defaults(func=run) + args = parser.parse_args() + args.func(args) + + +if __name__=="__main__": + main() diff --git a/pkdb_app/data_management/create_reference_acetaminophen.py b/pkdb_app/data_management/create_reference_acetaminophen.py deleted file mode 100644 index fd36ad9e..00000000 --- a/pkdb_app/data_management/create_reference_acetaminophen.py +++ /dev/null @@ -1,175 +0,0 @@ -""" -Creates json files in master folder -""" -import os -import shutil -import csv -import sys -import bonobo -import xml.etree.ElementTree as ET -from Bio import Entrez -import json -import requests - -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) -sys.path.append(BASEPATH) -from pkdb_app.utils import ensure_dir - -SUBSTANCE = "acetaminophen" - -Master = os.path.join(BASEPATH, "Master") -if BASEPATH not in sys.path: - sys.path.append(BASEPATH) - -# important for this script -DATABASEPATH = os.path.join(BASEPATH, "data") -LITERATUREPATH = os.path.join(DATABASEPATH, SUBSTANCE, "literature") -MASTERPATH = os.path.join(DATABASEPATH, "Master") -REFERENCESMASTERPATH = os.path.join(MASTERPATH, "Studies") -REFERENCESPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Studies.tsv") - - -# important for other scripts -SUBJECTSPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Subjects.tsv") -PHARMACOKINETICSPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Pharmacokinetics.tsv") -INTERVENTIONSPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Interventions.tsv") -DOSINGPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Dosing.tsv") -INDIVIDUALPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Individuals.tsv") -TIMECOURSEPATH = os.path.join(DATABASEPATH, SUBSTANCE, "Timecourse.tsv") -OUTPUTINDIVIDUALPATH = os.path.join(DATABASEPATH, SUBSTANCE, "OutputIndividuals.tsv") - -def extract_references(path): - reader = csv.DictReader(open(path), delimiter='\t') - for line in reader: - yield dict(line) - -def pmid_to_int(d): - d['sid'] = int(d['pmid']) - d['pmid'] = int(d['pmid']) - - yield d - - -def add_reference_sid(d): - sid = str(d["study"]) - yield {**d , 'name': sid} - - -def add_reference_path(d): - reference_path = os.path.join(REFERENCESMASTERPATH, d['name']) - return {**d, "reference_path":reference_path} - - -def load_from_biopython(d): - Entrez.email = 'janekg89@hotmail.de' - handle = Entrez.efetch(db='pubmed', id=d['pmid'], retmode='xml') - all_info = handle.read() - handle.close() - yield {**d, 'xml': all_info} - - -def xml_to_data(d): - yield {**d, 'data': ET.fromstring(d['xml'])} - - - -def create_json(d): - json_dict = {} - json_dict["pmid"] = d["pmid"] - json_dict["name"] = d["name"] - json_dict["sid"] = d["sid"] - for date in d["data"].iter("DateCompleted"): - year = date.find('Year').text - month = date.find('Month').text - day = date.find('Day').text - json_dict["date"] = f"{year}-{str(month).zfill(2)}-{str(day).zfill(2)}" - continue - for journal in d["data"].iter("Title"): - json_dict["journal"] = journal.text - continue - for title in d["data"].iter("ArticleTitle"): - json_dict["title"] = title.text - continue - for abstract in d["data"].iter("AbstractText"): - json_dict["abstract"] = abstract.text - continue - - authors = [] - for author in d["data"].iter("Author"): - author_dict = {} - author_dict["first_name"] = author.find("ForeName").text - author_dict["last_name"] = author.find("LastName").text - authors.append(author_dict) - json_dict["authors"] = authors - return {'json': json_dict, 'reference_path' : d["reference_path"]} - - -def add_doi(d): - json_dict = d["json"] - response = requests.get(f'https://www.ncbi.nlm.nih.gov/pmc/utils/idconv/v1.0/?tool=my_tool&email=my_email@example.com&ids={json_dict["pmid"]}') - pmcids = ET.fromstring(response.content) - for records in pmcids.iter("record"): - json_dict["doi"] = records.get('doi', "") - - - return {"json":json_dict, "reference_path": d["reference_path"]} - -def save_json(d): - json_file = os.path.join(d["reference_path"],"reference.json") - ensure_dir(json_file) - with open(json_file, 'w') as fp: - json.dump(d['json'],fp, indent=4) - -def add_resources(d): - """ - inputs the result of "add_reference_path()" from add reference path - :param d: - :return: - """ - for file in os.listdir(LITERATUREPATH): - if file.startswith(d['name']): - src = os.path.join(LITERATUREPATH,file) - dst = os.path.join(d["reference_path"],file) - ensure_dir(dst) - shutil.copy(src,dst) - - - -collect_reference = [extract_references(REFERENCESPATH), - pmid_to_int, - add_reference_sid, - add_reference_path,] - -def get_graph(**options): - """ Bonobo execution graph. - - :param options: - :return: - """ - graph = bonobo.Graph() - - #adds reference to - graph.add_chain(*collect_reference) - - graph.add_chain( - load_from_biopython, - xml_to_data, - create_json, - add_doi, - save_json, - _input= add_reference_path) - - - graph.add_chain(add_resources, _input= add_reference_path) - - return graph - - -def get_services(**options): - return {} - - -if __name__ == '__main__': - parser = bonobo.get_argument_parser() - with bonobo.parse_args(parser) as options: - bonobo.run(get_graph(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/create_reference_caffeine.py b/pkdb_app/data_management/create_reference_caffeine.py deleted file mode 100644 index d7b9e252..00000000 --- a/pkdb_app/data_management/create_reference_caffeine.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -Creates json files in master folder -""" -import os -import shutil -import csv -import sys -import bonobo -import xml.etree.ElementTree as ET -from Bio import Entrez -import json -import requests - -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) -sys.path.append(BASEPATH) -from pkdb_app.utils import ensure_dir - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pkdb_app.config.local") - -CAFFEINE = "caffeine" - -Master = os.path.join(BASEPATH, "Master") -if BASEPATH not in sys.path: - sys.path.append(BASEPATH) - -DATABASEPATH = os.path.join(BASEPATH, "data") -REFERENCESPATH = os.path.join(DATABASEPATH, CAFFEINE, "Studies.tsv") -SUBJECTSPATH = os.path.join(DATABASEPATH, CAFFEINE, "Subjects.tsv") -LITERATUREPATH = os.path.join(DATABASEPATH, CAFFEINE, "literature") -PHARMACOKINETICSPATH = os.path.join(DATABASEPATH, CAFFEINE, "Pharmacokinetics.tsv") -INTERVENTIONSPATH = os.path.join(DATABASEPATH, CAFFEINE, "Interventions.tsv") -DOSINGPATH = os.path.join(DATABASEPATH, CAFFEINE, "Dosing.tsv") -MASTERPATH = os.path.join(DATABASEPATH, "Master") -REFERENCESMASTERPATH = os.path.join(MASTERPATH, "Studies") -INDIVIDUALPATH = os.path.join(DATABASEPATH, CAFFEINE, "Individuals.tsv") -TIMECOURSEPATH = os.path.join(DATABASEPATH, CAFFEINE, "Timecourse.tsv") -OUTPUTINDIVIDUALPATH = os.path.join(DATABASEPATH, CAFFEINE, "OutputIndividuals.tsv") - - - -def extract_references(path): - reader = csv.DictReader(open(path), delimiter='\t') - for line in reader: - yield dict(line) - - -def pmid_to_int(d): - d['sid'] = int(d['pmid']) - d['pmid'] = int(d['pmid']) - - yield d - - -def add_reference_sid(d): - sid = str(d["study"]) - yield {**d , 'name': sid} - - -def add_reference_path(d): - reference_path = os.path.join(REFERENCESMASTERPATH, d['name']) - return {**d, "reference_path":reference_path} - - -def load_from_biopython(d): - - Entrez.email = 'janekg89@hotmail.de' - handle = Entrez.efetch(db='pubmed', id=d['pmid'], retmode='xml') - all_info = handle.read() - handle.close() - return {**d, 'xml': all_info} - - -def xml_to_data(d): - return {**d, 'data': ET.fromstring(d['xml'])} - - - -def create_json(d): - json_dict = {} - json_dict["pmid"] = d["pmid"] - json_dict["name"] = d["name"] - json_dict["sid"] = d["pmid"] - for date in d["data"].iter("DateCompleted"): - year = date.find('Year').text - month = date.find('Month').text - day = date.find('Day').text - json_dict["date"] = f"{year}-{str(month).zfill(2)}-{str(day).zfill(2)}" - continue - for journal in d["data"].iter("Title"): - json_dict["journal"] = journal.text - continue - for title in d["data"].iter("ArticleTitle"): - json_dict["title"] = title.text - continue - for abstract in d["data"].iter("AbstractText"): - json_dict["abstract"] = abstract.text - continue - - authors = [] - for author in d["data"].iter("Author"): - author_dict = {} - author_dict["first_name"] = author.find("ForeName").text - author_dict["last_name"] = author.find("LastName").text - authors.append(author_dict) - json_dict["authors"] = authors - return {'json': json_dict, 'reference_path' : d["reference_path"]} - - -def add_doi(d): - json_dict = d["json"] - response = requests.get(f'https://www.ncbi.nlm.nih.gov/pmc/utils/idconv/v1.0/?tool=my_tool&email=my_email@example.com&ids={json_dict["pmid"]}') - pmcids = ET.fromstring(response.content) - for records in pmcids.iter("record"): - json_dict["doi"] = records.get('doi', "") - - - return {"json":json_dict, "reference_path": d["reference_path"]} - -def save_json(d): - json_file = os.path.join(d["reference_path"],"reference.json") - ensure_dir(json_file) - with open(json_file, 'w') as fp: - json.dump(d['json'],fp, indent=4) - -def add_resources(d): - """ - inputs the result of "add_reference_path()" from add reference path - :param d: - :return: - """ - for file in os.listdir(LITERATUREPATH): - if file.startswith(d['name']): - src = os.path.join(LITERATUREPATH,file) - dst = os.path.join(d["reference_path"],file) - ensure_dir(dst) - shutil.copy(src,dst) - - - -collect_reference = [extract_references(REFERENCESPATH), - pmid_to_int, - add_reference_sid, - add_reference_path,] - -def get_graph(**options): - """ Bonobo execution graph. - - :param options: - :return: - """ - graph = bonobo.Graph() - - #adds reference to - graph.add_chain(*collect_reference) - - graph.add_chain( - load_from_biopython, - xml_to_data, - create_json, - add_doi, - save_json, - _input= add_reference_path) - - - graph.add_chain(add_resources, _input= add_reference_path) - - return graph - - -def get_services(**options): - return {} - - -if __name__ == '__main__': - parser = bonobo.get_argument_parser() - with bonobo.parse_args(parser) as options: - bonobo.run(get_graph(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/create_study_json.sh b/pkdb_app/data_management/create_study_json.sh deleted file mode 100755 index c0725be2..00000000 --- a/pkdb_app/data_management/create_study_json.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -python initialize_study.py && python add_groups.py && python add_intervention.py && python add_output.py \ No newline at end of file diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index bf609373..4fd041f3 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -21,22 +21,26 @@ import os import sys import bonobo -import coreapi import json import requests from jsonschema import validate +import logging BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) from pkdb_app.data_management.schemas import reference_schema -from pkdb_app.data_management.create_reference_caffeine import REFERENCESMASTERPATH - # FIXME: implement proper logging # ----------------------------- -# user information +# master path +# ----------------------------- +DATA_PATH = os.path.join(BASEPATH, "data", "Master", "Studies") + # ----------------------------- +# setup database +# ----------------------------- +API_URL = "http://0.0.0.0:8000/api/v1" PASSWORD = "test" USERS = [ {"username": "janekg", "first_name": "Jan", "last_name": "Grzegorzewski", "email": "Janekg89@hotmail.de", @@ -45,11 +49,6 @@ "password": PASSWORD} ] -# ----------------------------- -# master path -# ----------------------------- -MASTER_PATH = REFERENCESMASTERPATH - def setup_database(): """ Creates core information in database. @@ -59,12 +58,12 @@ def setup_database(): :return: """ - # FIXME: use requests instead of core api from pkdb_app.categoricals import SUBSTANCES_DATA for substance in SUBSTANCES_DATA: - client.action(document, ["substances", "create"], params={"name": substance}) + requests.post(f'{API_URL}/substances/', json={"name": substance}) + for user in USERS: - client.action(document, ["users", "create"], params=user) + requests.post(f'{API_URL}/users/', json=user) # ------------------------------- @@ -72,7 +71,7 @@ def setup_database(): # ------------------------------- def _get_paths(filename): """ Finds paths of filename recursively in MASTER_PATH. """ - for root, dirs, files in os.walk(MASTER_PATH, topdown=False): + for root, dirs, files in os.walk(DATA_PATH, topdown=False): if filename in files: yield os.path.join(root, filename) @@ -83,13 +82,14 @@ def get_reference_paths(): :return: dict """ for path in _get_paths("reference.json"): - pdf_path = os.path.join(os.path.dirname(path), f"{os.path.basename(path)}.pdf") + study_name = os.path.basename(os.path.dirname(path)) + pdf_path = os.path.join(os.path.dirname(path), f"{study_name}.pdf") yield {"reference_path": path, "pdf": pdf_path} def get_study_paths(): """ Finds paths of study JSON files. """ - _get_paths("study.json") + return _get_paths("study.json") # ------------------------------- @@ -160,9 +160,6 @@ def pop_comment(d, *keys): # ------------------------------- # Upload JSON in database # ------------------------------- -API_URL = "http://0.0.0.0:8000/api/v1" - - def upload_files(file_path): """ Uploads all files in directory of given file. @@ -289,11 +286,9 @@ def get_services(**options): # ------------------------------------------------------------------------------- if __name__ == '__main__': - client = coreapi.Client() - document = client.get("http://0.0.0.0:8000/") # core database setup - setup_database() + # setup_database() # run the bonobo chain parser = bonobo.get_argument_parser() diff --git a/pkdb_app/data_management/initialize_study.py b/pkdb_app/data_management/initialize_study.py deleted file mode 100644 index a8aeaf0b..00000000 --- a/pkdb_app/data_management/initialize_study.py +++ /dev/null @@ -1,70 +0,0 @@ -""" -Creates study.py json files in master folder with group infrmation -""" - - - -import bonobo -import pandas as pd -import numpy as np -import json -import os -import sys - -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) -sys.path.append(BASEPATH) - -from pkdb_app.data_management.create_reference_caffeine import collect_reference, add_reference_path, ensure_dir - -MK = "Matthias König" -MK_u = "mkoenig" -JG_u = "janekg" -JG = "Jan Grzeogrzewski" -SUBSTANCES = ["caffeine",] -pkdb_version = 1.0 -study_filename = "study.json" -SEPERATOR = "||" - -def study_create(reference): - #create json for study - json = {"sid": reference["sid"]} - json["pkdb_version"] = pkdb_version - json["creator"] = MK_u - json["name"] = reference["name"] - json["design"] = "" - json["reference"] = reference["sid"] - json["curators"] = [MK_u, JG_u] - json["substances"] = SUBSTANCES - study_path = os.path.join(reference["reference_path"],study_filename) - return {"json":json, "study_path":study_path} - - -def save_study(d): - json_file = os.path.join(d["study_path"]) - ensure_dir(json_file) - with open(json_file, 'w') as fp: - json.dump(d['json'],fp, indent=4, ensure_ascii=False,) - - -def get_graph(**options): - graph = bonobo.Graph() - - # add reference information - graph.add_chain(*collect_reference) - - #add studies - graph.add_chain( - study_create, - save_study, - _input=add_reference_path, - ) - return graph - - -def get_services(**options): - return {} - -if __name__ == '__main__': - parser = bonobo.get_argument_parser() - with bonobo.parse_args(parser) as options: - bonobo.run(get_graph(**options), services=get_services(**options)) diff --git a/pkdb_app/data_management/reference_create.py b/pkdb_app/data_management/reference_create.py deleted file mode 100644 index 145648fb..00000000 --- a/pkdb_app/data_management/reference_create.py +++ /dev/null @@ -1,31 +0,0 @@ -import argparse - -import os -import sys - -BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) -sys.path.append(BASEPATH) - -from pkdb_app.data_management.create_reference_caffeine import load_from_biopython, xml_to_data,create_json,add_doi,save_json - -def run(args): - - ref_dict = {"reference_path":args.reference, - "name":args.name, - "pmid":args.pmid} - save_json(add_doi(create_json(xml_to_data(load_from_biopython(ref_dict))))) - -def main(): - parser = argparse.ArgumentParser(description="create reference folder") - parser.add_argument("-s", help="directory of a reference", dest="reference", type=str, required=True) - parser.add_argument("-n", help="name of reference", dest="name", type=str, required=True) - parser.add_argument("-p", help="pmid", dest="pmid", type=str, required=True) - - - parser.set_defaults(func=run) - args = parser.parse_args() - args.func(args) - - -if __name__=="__main__": - main() \ No newline at end of file diff --git a/pkdb_app/data_management/study_upload.py b/pkdb_app/data_management/study_upload.py index 03eb1034..0668a71e 100644 --- a/pkdb_app/data_management/study_upload.py +++ b/pkdb_app/data_management/study_upload.py @@ -1,58 +1,64 @@ #! /usr/bin/env python -import os, sys +""" +Script which allows to upload single study from folder. +Is used in watchdog. +""" +import os +import sys import argparse from collections import namedtuple + BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from pkdb_app.data_management.fill_database import read_reference_json, read_study_json, upload_reference,upload_study -from pkdb_app.data_management.reference_create import run as create_reference + +from pkdb_app.data_management.fill_database import read_reference_json, read_study_json, upload_reference, upload_study +from pkdb_app.data_management.create_reference import run as create_reference def run(args): - ok = True + success = True study_path = os.path.join(args.study, "study.json") - _ , study_name = os.path.split(args.study) + _, study_name = os.path.split(args.study) reference_path = os.path.join(args.study, "reference.json") reference_pdf = os.path.join(args.study, f"{study_name}.pdf") if read_study_json(study_path) and hasattr(args, 'r'): study = read_study_json(study_path) - Reference = namedtuple("Reference",["reference", "name", "pmid"]) - ref = Reference(reference=args.study,name=study_name, pmid=study["json"]["reference"]) + Reference = namedtuple("Reference", ["reference", "name", "pmid"]) + ref = Reference(reference=args.study, name=study_name, pmid=study["json"]["reference"]) create_reference(ref) - if os.path.isfile(reference_path): reference_dict = {"json": reference_path, "pdf": reference_pdf} if read_reference_json(reference_dict): ok_ref = upload_reference(read_reference_json(reference_dict)) if not ok_ref: - ok = ok_ref + success = ok_ref else: - ok = False + success = False if os.path.isfile(study_path): if read_study_json(study_path): ok_study = upload_study(read_study_json(study_path)) if not ok_study: - ok = ok_study + success = ok_study else: - ok = False + success = False + if success: + print("--- upload successful ---") - if ok: - print("everthing is fine") def main(): - parser = argparse.ArgumentParser(description="Upload a file to PKDB") - parser.add_argument("-s", help="directory of a study", dest="study", type=str, required=True) - parser.add_argument("--r", help="directory of a study", action="store_true") + parser = argparse.ArgumentParser(description="Upload a study to PKDB") + parser.add_argument("-s", help="directory of study", dest="study", type=str, required=True) + parser.add_argument("--r", help="create reference json", action="store_true") parser.set_defaults(func=run) args = parser.parse_args() args.func(args) -if __name__=="__main__": - main() \ No newline at end of file +if __name__ == "__main__": + main() diff --git a/pkdb_app/data_management/study_watch.py b/pkdb_app/data_management/study_watch.py index 3af2d484..41499435 100644 --- a/pkdb_app/data_management/study_watch.py +++ b/pkdb_app/data_management/study_watch.py @@ -1,21 +1,28 @@ #!/usr/bin/python +""" +Watchdog to observe study folder for changes. +Updates study on changes. +""" + +import os +import sys import time import argparse -import os, sys + from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler + BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from pkdb_app.data_management.study_upload import run as upload_study +from pkdb_app.data_management.study_upload import run as upload_study -class MyHandler(FileSystemEventHandler): +class StudyHandler(FileSystemEventHandler): def __init__(self, study): self.study = study def on_created(self, event): - #if event.is_directory: _, study_name = os.path.split(self.study) print(f'---------- Study: {study_name} ----------') @@ -23,7 +30,8 @@ def on_created(self, event): def run(args): - event_handler = MyHandler(study = args.study) + """ Run observer. """ + event_handler = StudyHandler(study = args.study) observer = Observer() observer.schedule(event_handler, path=args.study, recursive=False) observer.start() @@ -34,11 +42,10 @@ def run(args): observer.stop() observer.join() + if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Upload a file to PKDB") - parser.add_argument("-s", help="directory of a study", dest="study", type=str, required=True) + parser = argparse.ArgumentParser(description="Watch a study folder for changes") + parser.add_argument("-s", help="directory of study", dest="study", type=str, required=True) parser.set_defaults(func=run) args = parser.parse_args() args.func(args) - - diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index c571cd29..58ca8eb3 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -25,7 +25,9 @@ def clean_import(data): return clean_dict + def ensure_dir(file_path): + """ Checks for directory and creates if non-existant.""" directory = os.path.dirname(file_path) if not os.path.exists(directory): os.makedirs(directory) diff --git a/requirements.txt b/requirements.txt index 823d2d86..efeab3e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -51,4 +51,5 @@ jsonschema django-extra-fields PyPDF2 lark-parser -watchdog \ No newline at end of file +watchdog +requests \ No newline at end of file From 4e3294c864580a462d8b1485e47fa4fb2c1d513f Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 16 Aug 2018 17:19:47 +0200 Subject: [PATCH 053/115] data deprecated from repository --- pkdb_app/comments/migrations/0001_initial.py | 4 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/data_management/fill_database.py | 73 +++++++++++++++++-- pkdb_app/data_management/study_upload.py | 37 +--------- pkdb_app/data_management/study_watch.py | 4 +- 5 files changed, 74 insertions(+), 48 deletions(-) diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index ee3a4692..68dc26cf 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-16 12:58 +# Generated by Django 2.0.6 on 2018-08-16 15:11 from django.db import migrations, models @@ -8,8 +8,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('subjects', '0001_initial'), ('interventions', '0001_initial'), + ('subjects', '0001_initial'), ] operations = [ diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index f7c3e623..8169b7ca 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-16 12:58 +# Generated by Django 2.0.6 on 2018-08-16 15:11 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('comments', '0002_auto_20180816_1258'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('comments', '0002_auto_20180816_1511'), ] operations = [ diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 4fd041f3..b4e83921 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -20,22 +20,33 @@ """ import os import sys -import bonobo import json import requests +import bonobo from jsonschema import validate import logging +# FIXME: remove bonobo + BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) from pkdb_app.data_management.schemas import reference_schema +from pkdb_app.data_management.create_reference import run as create_reference +from collections import namedtuple + # FIXME: implement proper logging # ----------------------------- # master path # ----------------------------- -DATA_PATH = os.path.join(BASEPATH, "data", "Master", "Studies") +# DATA_PATH = os.path.join(BASEPATH, "data", "Master", "Studies") +DATA_PATH = os.path.abspath(os.path.join(BASEPATH, "..", "pkdb_data", "caffeine")) +print("-" * 80) +print("DATA_PATH:", DATA_PATH) +print("-" * 80) +if not os.path.exists(DATA_PATH): + raise FileNotFoundError # ----------------------------- # setup database @@ -179,7 +190,7 @@ def upload_files(file_path): return data_dict -def upload_reference(json_reference): +def upload_reference_json(json_reference): """ Uploads reference JSON. """ success = True validate(json_reference["json"], reference_schema) @@ -201,7 +212,7 @@ def upload_reference(json_reference): return success -def upload_study(json_study): +def upload_study_json(json_study): """ Uploads study JSON. """ success = True study_dir = os.path.dirname(json_study["study_path"]) @@ -255,6 +266,52 @@ def upload_study(json_study): return success +def upload_study_from_dir(study_dir): + """ Upload a complete study directory. + + Includes + - study.json + - reference.json + - files + + :param study_dir: + :return: + """ + + success = True + study_path = os.path.join(study_dir, "study.json") + _, study_name = os.path.split(study_dir) + + reference_path = os.path.join(study_dir, "reference.json") + reference_pdf = os.path.join(study_dir, f"{study_name}.pdf") + + if not os.path.exists(reference_path): + study = read_study_json(study_path) + Reference = namedtuple("Reference", ["reference", "name", "pmid"]) + ref = Reference(reference=study_dir, name=study_name, pmid=study["json"]["reference"]) + create_reference(ref) + + if os.path.isfile(reference_path): + reference_dict = {"json": reference_path, "pdf": reference_pdf} + if read_reference_json(reference_dict): + ok_ref = upload_reference_json(read_reference_json(reference_dict)) + if not ok_ref: + success = ok_ref + else: + success = False + + if os.path.isfile(study_path): + if read_study_json(study_path): + ok_study = upload_study_json(read_study_json(study_path)) + if not ok_study: + success = ok_study + else: + success = False + + if success: + print("--- upload successful ---") + + # ------------------------------- # Bonobo # ------------------------------- @@ -264,7 +321,7 @@ def get_graph_references(**options): graph.add_chain( get_reference_paths, read_reference_json, - upload_reference, + upload_reference_json, ) return graph @@ -275,7 +332,7 @@ def get_graph_study(**options): graph.add_chain( get_study_paths, read_study_json, - upload_study, + upload_study_json, ) return graph @@ -288,7 +345,8 @@ def get_services(**options): if __name__ == '__main__': # core database setup - # setup_database() + setup_database() + # run the bonobo chain parser = bonobo.get_argument_parser() @@ -296,3 +354,4 @@ def get_services(**options): bonobo.run(get_graph_references(**options), services=get_services(**options)) bonobo.run(get_graph_study(**options), services=get_services(**options)) + print("--- done ---") \ No newline at end of file diff --git a/pkdb_app/data_management/study_upload.py b/pkdb_app/data_management/study_upload.py index 0668a71e..e7ed0491 100644 --- a/pkdb_app/data_management/study_upload.py +++ b/pkdb_app/data_management/study_upload.py @@ -6,48 +6,15 @@ import os import sys import argparse -from collections import namedtuple BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from pkdb_app.data_management.fill_database import read_reference_json, read_study_json, upload_reference, upload_study -from pkdb_app.data_management.create_reference import run as create_reference +from pkdb_app.data_management.fill_database import upload_study_from_dir def run(args): - success = True - study_path = os.path.join(args.study, "study.json") - _, study_name = os.path.split(args.study) - - reference_path = os.path.join(args.study, "reference.json") - reference_pdf = os.path.join(args.study, f"{study_name}.pdf") - - if read_study_json(study_path) and hasattr(args, 'r'): - study = read_study_json(study_path) - Reference = namedtuple("Reference", ["reference", "name", "pmid"]) - ref = Reference(reference=args.study, name=study_name, pmid=study["json"]["reference"]) - create_reference(ref) - - if os.path.isfile(reference_path): - reference_dict = {"json": reference_path, "pdf": reference_pdf} - if read_reference_json(reference_dict): - ok_ref = upload_reference(read_reference_json(reference_dict)) - if not ok_ref: - success = ok_ref - else: - success = False - - if os.path.isfile(study_path): - if read_study_json(study_path): - ok_study = upload_study(read_study_json(study_path)) - if not ok_study: - success = ok_study - else: - success = False - - if success: - print("--- upload successful ---") + upload_study_from_dir(args.study) def main(): diff --git a/pkdb_app/data_management/study_watch.py b/pkdb_app/data_management/study_watch.py index 41499435..50b97308 100644 --- a/pkdb_app/data_management/study_watch.py +++ b/pkdb_app/data_management/study_watch.py @@ -15,7 +15,7 @@ BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) -from pkdb_app.data_management.study_upload import run as upload_study +from pkdb_app.data_management.fill_database import upload_study_from_dir class StudyHandler(FileSystemEventHandler): @@ -26,7 +26,7 @@ def on_created(self, event): _, study_name = os.path.split(self.study) print(f'---------- Study: {study_name} ----------') - upload_study(self) + upload_study_from_dir(self.study) def run(args): From fb386c65a669feffa4c6370bae9a23b533673858 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 16 Aug 2018 18:52:57 +0200 Subject: [PATCH 054/115] improved fill_database with logging --- CURATION.md | 26 +-- pkdb_app/data_management/fill_database.py | 149 +++++++++++------- .../{study_upload.py => upload_study.py} | 0 .../{study_watch.py => watch_study.py} | 17 +- 4 files changed, 116 insertions(+), 76 deletions(-) rename pkdb_app/data_management/{study_upload.py => upload_study.py} (100%) rename pkdb_app/data_management/{study_watch.py => watch_study.py} (76%) mode change 100644 => 100755 diff --git a/CURATION.md b/CURATION.md index b5b52ee4..16212d12 100644 --- a/CURATION.md +++ b/CURATION.md @@ -1,10 +1,9 @@ # Curation information -Collection of resources and infromation on how experimental data +Collection of resources and information on how experimental data should be curated from manuscripts for upload/inclusion in PKDB. -Most important point is to create valid JSON which can be accepted -by the model serializers, i.e. serializers which are defined -in +In the curation JSON files for the study and reference are created which are parsed + by the model serializers ``` serializers.py studies/serializers.py @@ -12,15 +11,20 @@ interventions/serializers.py subjects/serializers.py ``` -Additionally, the JSON files have to be conform to the JSON schema, -defined in - ## 1. PDF, Reference, Figures & Tables -* Create folder for study, name folder AuthorYear{a,b,c, ...} from hereon referred to as StudyName +For upload a certain folder structure is expected +- folder name is STUDYNAME, e.g., Albert1974 +- folder contains pdf as STUDYNAME.pdf, e.g., Albert1974.pdf +- folder contains reference information as `reference.json` +- folder contains study information as `study.json` +- folder contains additional files associated with study, i.e., + - tables, named STUDYNAME_Tab[0-9]*.png, e.g., Albert1974_Tab1.png + - figures, named STUDYNAME_Fig[0-9]*.png, e.g., Albert1974_Fig2.png + - excel file, named STUDYNAME.xlsx, e.g., Albert1974.xlsx + - data files, named STUDYNAME_Tab[0-9]*.csv or STUDYNAME_Fig[0-9]*.csv +* Start watchdog `watch_study.py` via pycharm with `-s PATH_TO_DIRECTORY` argument + * Get `PMID` (Pubmed id) for publication from https://www.ncbi.nlm.nih.gov/pubmed/ -* Download PDF in folder as StudyName.pdf -* Extract Figures with graphics program and save as StudyName_Fig[0-9]* or StudyName_Tab[0-9]* -* Digitized data should be stored in StudyName.xlsx ## 2. Initial study information (`study.json`) Fill in basic information for study, use the `PMID` for `sid` and `reference` field, use StudyName for `name` field. diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index b4e83921..15955d1c 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -42,10 +42,10 @@ # ----------------------------- # DATA_PATH = os.path.join(BASEPATH, "data", "Master", "Studies") DATA_PATH = os.path.abspath(os.path.join(BASEPATH, "..", "pkdb_data", "caffeine")) -print("-" * 80) -print("DATA_PATH:", DATA_PATH) -print("-" * 80) if not os.path.exists(DATA_PATH): + print("-" * 80) + print("DATA_PATH:", DATA_PATH) + print("-" * 80) raise FileNotFoundError # ----------------------------- @@ -116,7 +116,7 @@ def _read_json(path): try: json_data = json.loads(f.read()) except json.decoder.JSONDecodeError as err: - print(err) + logging.warning(f'{err}\nin {path}') return return json_data @@ -186,7 +186,12 @@ def upload_files(file_path): file_path = os.path.join(root, file) with open(file_path, 'rb') as f: response = requests.post(f'{API_URL}/datafiles/', files={"file": f}) - data_dict[file] = response.json()["id"] + if response.status_code == 201: + data_dict[file] = response.json()["id"] + else: + logging.warning(f"File upload failed: {file}") + print(response.json()) + return data_dict @@ -198,7 +203,7 @@ def upload_reference_json(json_reference): # post response = requests.post(f'{API_URL}/references/', json=json_reference["json"]) if not response.status_code == 201: - print(json_reference["json"]["name"], response.text) + logging.info(json_reference["json"]["name"], response.text) success = False # patch @@ -206,61 +211,76 @@ def upload_reference_json(json_reference): response = requests.patch(f'{API_URL}/references/{json_reference["json"]["sid"]}/', files={"pdf": f}) if not response.status_code == 200: - print(json_reference["json"]["name"], response.text) + logging.info(json_reference["json"]["name"], response.text) success = False return success -def upload_study_json(json_study): - """ Uploads study JSON. """ +def upload_study_json(json_study_dict): + """ Uploads study JSON. + + :returns success code + """ success = True - study_dir = os.path.dirname(json_study["study_path"]) + json_study = json_study_dict["json"] + if not json_study: + logging.warning("No study information in `study.json`") + return False + + # upload files (and get dict for file ids) + study_dir = os.path.dirname(json_study_dict["study_path"]) file_dict = upload_files(study_dir) + + comments = [] - for keys, item in recursive_iter(json_study): + for keys, item in recursive_iter(json_study_dict): if item in file_dict.keys(): - set_keys(json_study, file_dict[item], *keys) + set_keys(json_study_dict, file_dict[item], *keys) if "comments" in keys: comments.append(keys) for comment in comments: - pop_comment(json_study, *comment) - - study_partial = {} - study_partial["sid"] = json_study["json"]["sid"] - study_partial["name"] = json_study["json"]["name"] - study_partial["pkdb_version"] = json_study["json"]["pkdb_version"] - study_partial["design"] = json_study["json"]["design"] - study_partial["substances"] = json_study["json"]["substances"] - study_partial["reference"] = json_study["json"]["reference"] - study_partial["curators"] = json_study["json"]["curators"] - study_partial["creator"] = json_study["json"]["creator"] - study_partial["files"] = list(file_dict.values()) - - # post - response = requests.post(f'{API_URL}/studies/', json=study_partial) + pop_comment(json_study_dict, *comment) + + # --------------------------- + # post study core + # --------------------------- + study_core = {} + study_core["sid"] = json_study.get("sid") + study_core["name"] = json_study.get("name") + study_core["pkdb_version"] = json_study.get("pkdb_version") + study_core["design"] = json_study.get("design") + study_core["substances"] = json_study.get("substances") + study_core["reference"] = json_study.get("reference") + study_core["curators"] = json_study.get("curators") + study_core["creator"] = json_study.get("creator") + study_core["files"] = list(file_dict.values()) + + response = requests.post(f'{API_URL}/studies/', json=study_core) if not response.status_code == 201: - print(json_study["json"]["name"], response.text) + logging.warning(f'{study_core["name"]} {response.text}') success = False - study_partial2 = {} - study_partial2["groupset"] = json_study["json"]["groupset"] - study_partial2["interventionset"] = json_study["json"]["interventionset"] - study_partial2["individualset"] = json_study["json"].get("individualset", None) + # --------------------------- + # post study sets + # --------------------------- + study_sets = {} + study_sets["groupset"] = json_study.get("groupset") + study_sets["interventionset"] = json_study.get("interventionset") + study_sets["individualset"] = json_study.get("individualset") - # patch - response = requests.patch(f'{API_URL}/studies/{json_study["json"]["sid"]}/', json=study_partial2) + response = requests.patch(f'{API_URL}/studies/{json_study["sid"]}/', json=study_sets) if not response.status_code == 200: - print(json_study["json"]["name"], response.text) + logging.warning(f'{study_core["name"]} {response.text}') success = False # patch - if "outputset" in json_study["json"].keys(): - response = requests.patch(f'{API_URL}/studies/{json_study["json"]["sid"]}/', - json={"outputset": json_study["json"].get("outputset")}) + if "outputset" in json_study.keys(): + response = requests.patch(f'{API_URL}/studies/{json_study["sid"]}/', + json={"outputset": json_study.get("outputset")}) if not response.status_code == 200: - print(json_study["json"]["name"], response.text) + logging.warning(f'{study_core["name"]} {response.text}') success = False return success @@ -278,37 +298,44 @@ def upload_study_from_dir(study_dir): :return: """ - success = True + # handle study.json study_path = os.path.join(study_dir, "study.json") _, study_name = os.path.split(study_dir) + if not os.path.exists(study_path): + logging.warning("`study.json` missing.") + return False - reference_path = os.path.join(study_dir, "reference.json") - reference_pdf = os.path.join(study_dir, f"{study_name}.pdf") + study_dict = read_study_json(study_path) + if not study_dict: + logging.warning("`study.json` is empty.") + return False - if not os.path.exists(reference_path): - study = read_study_json(study_path) - Reference = namedtuple("Reference", ["reference", "name", "pmid"]) - ref = Reference(reference=study_dir, name=study_name, pmid=study["json"]["reference"]) - create_reference(ref) + study_json = study_dict.get("json", None) - if os.path.isfile(reference_path): + # try to create missing reference.json + reference_path = os.path.join(study_dir, "reference.json") + reference_pdf = os.path.join(study_dir, f"{study_name}.pdf") + if study_json and not os.path.exists(reference_path): + if study_json: + pmid = json.get("reference", None) + if pmid is not None: + Reference = namedtuple("Reference", ["reference", "name", "pmid"]) + ref = Reference(reference=study_dir, name=study_name, pmid=pmid) + create_reference(ref) + else: + logging.warning("`reference.json` missing, and no pmid in `study.json`") + + # upload reference.json + success_ref = True + if os.path.exists(reference_path): reference_dict = {"json": reference_path, "pdf": reference_pdf} if read_reference_json(reference_dict): - ok_ref = upload_reference_json(read_reference_json(reference_dict)) - if not ok_ref: - success = ok_ref - else: - success = False + success_ref = upload_reference_json(read_reference_json(reference_dict)) - if os.path.isfile(study_path): - if read_study_json(study_path): - ok_study = upload_study_json(read_study_json(study_path)) - if not ok_study: - success = ok_study - else: - success = False + # upload study.json + success_study = upload_study_json(study_dict) - if success: + if success_ref and success_study: print("--- upload successful ---") diff --git a/pkdb_app/data_management/study_upload.py b/pkdb_app/data_management/upload_study.py similarity index 100% rename from pkdb_app/data_management/study_upload.py rename to pkdb_app/data_management/upload_study.py diff --git a/pkdb_app/data_management/study_watch.py b/pkdb_app/data_management/watch_study.py old mode 100644 new mode 100755 similarity index 76% rename from pkdb_app/data_management/study_watch.py rename to pkdb_app/data_management/watch_study.py index 50b97308..6c9167d4 --- a/pkdb_app/data_management/study_watch.py +++ b/pkdb_app/data_management/watch_study.py @@ -2,12 +2,18 @@ """ Watchdog to observe study folder for changes. Updates study on changes. + +(pkdb) python ~/git/pkdb/pkdb_app/data_management/watch_study.py -s PATH_TO_DIRECTORY + """ import os import sys import time import argparse +import logging + +logging.getLogger().setLevel(logging.INFO) from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler @@ -21,17 +27,20 @@ class StudyHandler(FileSystemEventHandler): def __init__(self, study): self.study = study - - def on_created(self, event): _, study_name = os.path.split(self.study) + logging.info('-' * 80) + logging.info(f'Watching [{study_name}]') + logging.info(f'\t{self.study}') + logging.info('-' * 80) + upload_study_from_dir(self.study) - print(f'---------- Study: {study_name} ----------') + def on_created(self, event): upload_study_from_dir(self.study) def run(args): """ Run observer. """ - event_handler = StudyHandler(study = args.study) + event_handler = StudyHandler(study=args.study) observer = Observer() observer.schedule(event_handler, path=args.study, recursive=False) observer.start() From 93c8e9d47f6ead7bf01781fd9bec29baf0430422 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 16 Aug 2018 19:19:29 +0200 Subject: [PATCH 055/115] bugfixes watchdog and fill_database --- .gitignore | 2 +- CURATION.md | 3 +-- README.md | 7 +++++++ pkdb_app/data_management/fill_database.py | 11 ++++++++--- pkdb_app/data_management/watch_study.py | 3 +++ pkdb_app/subjects/models.py | 7 +++++-- 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index ed6984b4..7ac499b5 100644 --- a/.gitignore +++ b/.gitignore @@ -61,7 +61,7 @@ coverage.xml # Django stuff: *.log .static_storage/ -.media/ +media/ local_settings.py # Flask stuff: diff --git a/CURATION.md b/CURATION.md index 16212d12..51fc3350 100644 --- a/CURATION.md +++ b/CURATION.md @@ -24,7 +24,6 @@ For upload a certain folder structure is expected - data files, named STUDYNAME_Tab[0-9]*.csv or STUDYNAME_Fig[0-9]*.csv * Start watchdog `watch_study.py` via pycharm with `-s PATH_TO_DIRECTORY` argument -* Get `PMID` (Pubmed id) for publication from https://www.ncbi.nlm.nih.gov/pubmed/ ## 2. Initial study information (`study.json`) Fill in basic information for study, use the `PMID` for `sid` and `reference` field, use StudyName for `name` field. @@ -35,7 +34,7 @@ Fill in basic information for study, use the `PMID` for `sid` and `reference` fi "pkdb_version": 1.0, "creator": "mkoenig", "name": "Akinyinka2000", - "design":"parallel group", + "design": "parallel group", "reference": 10877011, "curators": [ "mkoenig", diff --git a/README.md b/README.md index 91c28ad5..7ba1fe63 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,13 @@ Database and web interface for storing pharmacokinetics information including Figure 1: Overview over data extraction. +## Access +http://localhost:8000/api/v1/ +http://localhost:8000/api/v1/studies/17955229/ + + + + ## Data model Pharmacokinetics data is a special type of experimental data. Pharmacokinetics data like clearance, halflife, ... (with units and error measurements) are either directly reported in publications diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 15955d1c..d94d34c6 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -283,6 +283,9 @@ def upload_study_json(json_study_dict): logging.warning(f'{study_core["name"]} {response.text}') success = False + if success: + logging.info(f'{API_URL}/studies/{json_study["sid"]}/') + return success @@ -317,7 +320,7 @@ def upload_study_from_dir(study_dir): reference_pdf = os.path.join(study_dir, f"{study_name}.pdf") if study_json and not os.path.exists(reference_path): if study_json: - pmid = json.get("reference", None) + pmid = study_json.get("reference", None) if pmid is not None: Reference = namedtuple("Reference", ["reference", "name", "pmid"]) ref = Reference(reference=study_dir, name=study_name, pmid=pmid) @@ -328,7 +331,7 @@ def upload_study_from_dir(study_dir): # upload reference.json success_ref = True if os.path.exists(reference_path): - reference_dict = {"json": reference_path, "pdf": reference_pdf} + reference_dict = {"reference_path": reference_path, "pdf": reference_pdf} if read_reference_json(reference_dict): success_ref = upload_reference_json(read_reference_json(reference_dict)) @@ -336,7 +339,9 @@ def upload_study_from_dir(study_dir): success_study = upload_study_json(study_dict) if success_ref and success_study: - print("--- upload successful ---") + logging.info("--- upload successful ---") + + return {} # ------------------------------- diff --git a/pkdb_app/data_management/watch_study.py b/pkdb_app/data_management/watch_study.py index 6c9167d4..74cae4eb 100755 --- a/pkdb_app/data_management/watch_study.py +++ b/pkdb_app/data_management/watch_study.py @@ -23,6 +23,8 @@ from pkdb_app.data_management.fill_database import upload_study_from_dir +# FIXME: make sure that removed files are removed from the study (on delete?) + class StudyHandler(FileSystemEventHandler): def __init__(self, study): @@ -35,6 +37,7 @@ def __init__(self, study): upload_study_from_dir(self.study) def on_created(self, event): + print('\n') upload_study_from_dir(self.study) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index a96a1b77..811ce210 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -33,10 +33,12 @@ class DataFile(models.Model): filetype = models.CharField(null=True, blank=True, max_length=CHAR_MAX_LENGTH) # XLSX, PNG, CSV def __str__(self): - return self.file.nam + return self.file.name + + class Set(Describable, models.Model): """ - abstarct class for all set classes + abstract class for all set classes """ @property @@ -46,6 +48,7 @@ def reference(self): class Meta: abstract = True + class GroupSet(Set): objects = GroupSetManager() From 0b3d93c1170c3effa949db8651fff0314c81420a Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 10:34:37 +0200 Subject: [PATCH 056/115] Fiexes #20 --- pkdb_app/serializers.py | 8 +++++--- pkdb_app/studies/models.py | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 1d772351..19caeb3c 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -81,8 +81,11 @@ def create_relations(study, related): substance = get_or_val_error(Substance, name=substance_data) study.substances.add(substance) - for file_pk in related["files"]: - study.files.add(file_pk) + if related["files"] : + print(related["files"]) + study.files.all().delete() + for file_pk in related["files"]: + study.files.add(file_pk) study.save() @@ -102,7 +105,6 @@ def pop_relations(validated_data): class ParserSerializer(WrongKeySerializer): - @staticmethod def generic_parser(data,key): diff --git a/pkdb_app/studies/models.py b/pkdb_app/studies/models.py index e1a27ff2..57fbb741 100644 --- a/pkdb_app/studies/models.py +++ b/pkdb_app/studies/models.py @@ -52,7 +52,6 @@ class Study(Sidable, models.Model): reference = models.ForeignKey(Reference, on_delete=True, to_field="sid", db_column="reference_sid", related_name='studies', null=True, blank=True) curators = models.ManyToManyField(User) # any curator needs an account. substances = models.ManyToManyField(Substance) - #raw_data = models.ManyToManyField(DataFile) # FIXME: is this the right name? groupset = models.OneToOneField(GroupSet, on_delete=models.CASCADE,null=True, blank=True) interventionset = models.OneToOneField(InterventionSet, on_delete=models.CASCADE,null=True, blank=True) individualset = models.OneToOneField(IndividualSet, on_delete=models.CASCADE,null=True, blank=True) From ead888111ee184c82127c38ce70d8d2711a932d2 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 10:49:43 +0200 Subject: [PATCH 057/115] updating categorials --- client/README.md | 7 ++++++- pkdb_app/categoricals.py | 35 +++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/client/README.md b/client/README.md index c6fd5fc3..9865ce3a 100644 --- a/client/README.md +++ b/client/README.md @@ -1,6 +1,6 @@ # frontend -> pkdb +> pkdb ## Build Setup @@ -28,3 +28,8 @@ npm test ``` For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). + + +``` +sudo apt-get install npm +``` diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 64f1ede0..69838866 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -57,6 +57,7 @@ def create_choices(list): UnitType("µg/ml"), UnitType("µg/ml"), UnitType("mg"), + UnitType("mmHg"), UnitType("ml/min/1.73m^2"), UnitType("µg/ml*h/kg"), UnitType("l"), @@ -68,7 +69,6 @@ def create_choices(list): UnitType("mg/l*h"), UnitType("mg/kg"), UnitType("mg/day") - ] @@ -93,8 +93,8 @@ def create_choices(list): BOOLEAN_CHOICES = [YES, NO, MIX,NAN] INTERVENTION_ROUTE = [ -"oral", -"iv", + "oral", + "iv", ] INTERVENTION_ROUTE_CHOICES = create_choices(INTERVENTION_ROUTE) INTERVENTION_APPLICATION = [ @@ -132,8 +132,8 @@ def create_choices(list): FileFormat = namedtuple("FileFormat", ["name", "delimiter"]) -FORMAT_MAPPING = {"TSV":FileFormat("TSV",'\t'), - "CSV":FileFormat("CSV",",")} +FORMAT_MAPPING = {"TSV": FileFormat("TSV",'\t'), + "CSV": FileFormat("CSV",",")} STUDY_DESIGN_DATA = [ "single group", # (interventional study) @@ -180,7 +180,10 @@ def create_choices(list): # Medication CharacteristicType('oral contraceptives', 'contraceptives', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('oral contraceptives amount', 'contraceptives', NUMERIC_TYPE, None, ["-"]), - CharacteristicType('medication', 'medication', CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"], ["-"]), # ? dosing + + CharacteristicType('medication', 'medication', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('medication type', 'medication', CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"], ["-"]), + CharacteristicType('medication amount', 'medication', NUMERIC_TYPE, None, ["-"]), # Lifestyle CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), @@ -198,18 +201,26 @@ def create_choices(list): CharacteristicType('kidney weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), CharacteristicType('age', DEMOGRAPHICS, NUMERIC_TYPE, None, ["yr"]), - CharacteristicType('sex', DEMOGRAPHICS, CATEGORIAL_TYPE, ["M", "F", MIX,NAN], ["-"]), + CharacteristicType('sex', DEMOGRAPHICS, CATEGORIAL_TYPE, ["M", "F", MIX, NAN], ["-"]), CharacteristicType('ethnicity', DEMOGRAPHICS, CATEGORIAL_TYPE, ["african", "afroamerican", "asian", "caucasian",NAN], ["-"]), # Disease (status) CharacteristicType('healthy', "health status", BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('disease', "disease", CATEGORIAL_TYPE, [NAN,"cirrhosis","plasmodium falciparum","alcoholic liver cirrhosis","cirrhotic liver disease","PBC","miscellaneous liver disease","schizophrenia"], ["-"]), + CharacteristicType('disease', "disease", CATEGORIAL_TYPE, [NAN, "cirrhosis", "plasmodium falciparum","alcoholic liver cirrhosis","cirrhotic liver disease","PBC","miscellaneous liver disease","schizophrenia"], ["-"]), - # Lifestyle + CharacteristicType('blood pressure', "health status", NUMERIC_TYPE, None, ["mmHg"]), + + # ------------ + # smoking + # ------------ CharacteristicType('smoking', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('smoking amount', 'lifestyle', NUMERIC_TYPE, None, ["1/day"]), + CharacteristicType('smoking amount (cigarettes)', 'lifestyle', NUMERIC_TYPE, None, ["1/day"]), + CharacteristicType('smoking amount (packyears)', 'lifestyle', NUMERIC_TYPE, None, ["yr"]), + CharacteristicType('smoking duration (years)', 'lifestyle', NUMERIC_TYPE, None, ["yr"]), + + CharacteristicType('alcohol', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('alcohol amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), @@ -222,12 +233,12 @@ def create_choices(list): # Study protocol CharacteristicType('overnight fast', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('alcohol abstinence', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA+["alcohol","medication","grapefruit juice"],["-"]), + CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA+["alcohol", "medication", "grapefruit juice"],["-"]), # Medication # Genetics ??? - CharacteristicType('genetics', 'genetics',CATEGORIAL_TYPE, ["CYP2D6 duplication","CYP2D6 wild type","CYP2D6 poor metabolizer"], ["-"]), + CharacteristicType('genetics', 'genetics', CATEGORIAL_TYPE, ["CYP2D6 duplication","CYP2D6 wild type", "CYP2D6 poor metabolizer"], ["-"]), # Requires storage of the variants and effects of clearance ] From b16e75a8c7d4f796e33f16dd10a41282832c4d5e Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 10:58:34 +0200 Subject: [PATCH 058/115] Fixes #19 --- pkdb_app/data_management/fill_database.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index d94d34c6..0da61b3e 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -181,7 +181,13 @@ def upload_files(file_path): head, sid = os.path.split(file_path) study_dir = os.path.join(head, sid) for root, dirs, files in os.walk(study_dir, topdown=False): + #exclude files files = set(files) - set(['reference.json', 'study.json', f'{sid}.pdf']) + #exclude files + forbidden_suffix = (".log",".xlsx#",".idea") + files = [file for file in files if not file.endswith(forbidden_suffix)] + + for file in files: file_path = os.path.join(root, file) with open(file_path, 'rb') as f: From 2b61900388ced6d8bd85708fd0dbc039727ca58c Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 11:37:58 +0200 Subject: [PATCH 059/115] categorials cleaned --- pkdb_app/categoricals.py | 145 ++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 70 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 69838866..ad378515 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -45,9 +45,19 @@ def create_choices(list): UnitType('yr'), UnitType('week'), UnitType('day'), - UnitType('kg/m^2'), + UnitType('h'), + UnitType('min'), + UnitType('s'), + + UnitType('1/week'), UnitType('1/day'), UnitType('1/h'), + UnitType('1/min'), + UnitType('1/s'), + + UnitType('kg/m^2'), + + UnitType('IU/I'), UnitType('mg/dl'), UnitType('g/dl'), @@ -89,7 +99,7 @@ def create_choices(list): YES = "Y" NO = 'N' MIX = "Mixed" -NAN = "NAN" +NAN = "NaN" BOOLEAN_CHOICES = [YES, NO, MIX,NAN] INTERVENTION_ROUTE = [ @@ -100,27 +110,28 @@ def create_choices(list): INTERVENTION_APPLICATION = [ "single dose", "multiple dose", - "continous injection", + "continuous injection", ] INTERVENTION_APPLICATION_CHOICES = create_choices(INTERVENTION_APPLICATION) INTERVENTION_FORM = [ "tablete", "capsule", - "2 100mg NO-DOZ tablets", - "capsules", - "2 capsules", NAN, - ] INTERVENTION_FORM_CHOICES = create_choices(INTERVENTION_FORM) # categories -DEMOGRAPHICS = "demographics" # age, sex, ethnicity -ANTHROPOMETRY = "anthropometry" # height, weight, waist bmi SPECIES = "species" +DEMOGRAPHICS = "demographics" +ANTHROPOMETRY = "anthropometry" +PHYSIOLOGY = "physiology" +PATIENT_STATUS = "patient status" +MEDICATION = "medication" +LIFESTYLE = "lifestyle" BIOCHEMICAL_DATA = "biochemical data" HEMATOLOGY_DATA = "hematology data" +GENETIC_VARIANTS = "genetic variants" INCLUSION_CRITERIA = "inclusion" @@ -145,103 +156,108 @@ def create_choices(list): STUDY_DESIGN_CHOICES = [(t, t) for t in STUDY_DESIGN_DATA] SUBSTANCES_DATA = [ - "ibuprofen", - "paracetamol", - "aspirin", - "caffeine", + # acetaminophen "acetaminophen", + + # caffeine + "caffeine", "paraxanthine", "paraxanthine/caffeine", "theobromine", "theophylline", - "chlorozoxazone", - "lomefloxacin", "AAMU", "1U", "17X", "17U", "37X", "1X", + + # codeine + "codeine", + + # misc + "ibuprofen", + "aspirin", "enoxacin", "ciprofloxacin", "pipemidic acid", "norfloxacin", "ofloxacin", "fluvoxamine", - "alcohol", - "codeine" + "ethanol", + "chlorozoxazone", + "lomefloxacin", ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] - - -COMMON_DATA = [ - # Medication - CharacteristicType('oral contraceptives', 'contraceptives', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('oral contraceptives amount', 'contraceptives', NUMERIC_TYPE, None, ["-"]), - - CharacteristicType('medication', 'medication', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('medication type', 'medication', CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"], ["-"]), - CharacteristicType('medication amount', 'medication', NUMERIC_TYPE, None, ["-"]), - - # Lifestyle - CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('caffeine amount', 'lifestyle', NUMERIC_TYPE, None, ["mg/day"]), -] - -CHARACTERISTIC_DATA = COMMON_DATA + [ - # Antropmetrical information +CHARACTERISTIC_DATA = [ + # -------------- Species -------------- CharacteristicType('species', SPECIES, CATEGORIAL_TYPE, ["homo sapiens"], ["-"]), + + # -------------- Anthropometry -------------- CharacteristicType('height', ANTHROPOMETRY, NUMERIC_TYPE, None, ["cm", 'm']), CharacteristicType('weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["kg"]), CharacteristicType('bmi', ANTHROPOMETRY, NUMERIC_TYPE, None, ["kg/m^2"]), CharacteristicType('waist circumference', ANTHROPOMETRY, NUMERIC_TYPE, None, ["cm"]), - CharacteristicType('liver weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), - CharacteristicType('kidney weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), + # -------------- Demography -------------- CharacteristicType('age', DEMOGRAPHICS, NUMERIC_TYPE, None, ["yr"]), CharacteristicType('sex', DEMOGRAPHICS, CATEGORIAL_TYPE, ["M", "F", MIX, NAN], ["-"]), - CharacteristicType('ethnicity', DEMOGRAPHICS, CATEGORIAL_TYPE, ["african", "afroamerican", "asian", "caucasian",NAN], ["-"]), + CharacteristicType('ethnicity', DEMOGRAPHICS, CATEGORIAL_TYPE, ["african", "afroamerican", "asian", "caucasian", NAN], ["-"]), + # -------------- Physiology -------------- + CharacteristicType('blood pressure', PHYSIOLOGY, NUMERIC_TYPE, None, ["mmHg"]), + CharacteristicType('heart rate', PHYSIOLOGY, NUMERIC_TYPE, None, ["1/s"]), - # Disease (status) - CharacteristicType('healthy', "health status", BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('disease', "disease", CATEGORIAL_TYPE, [NAN, "cirrhosis", "plasmodium falciparum","alcoholic liver cirrhosis","cirrhotic liver disease","PBC","miscellaneous liver disease","schizophrenia"], ["-"]), + # -------------- Organ weights -------------- + CharacteristicType('liver weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), + CharacteristicType('kidney weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["g", "kg"]), + + # -------------- Patient status -------------- + CharacteristicType('overnight fast', PATIENT_STATUS, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('healthy', PATIENT_STATUS, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('disease', PATIENT_STATUS, CATEGORIAL_TYPE, [NAN, "cirrhosis", "plasmodium falciparum", + "alcoholic liver cirrhosis", "cirrhotic liver disease", "PBC", + "miscellaneous liver disease", "schizophrenia"], ["-"]), + # -------------- Medication -------------- + CharacteristicType('medication', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('medication type', MEDICATION, CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"], ["-"]), + CharacteristicType('medication amount', MEDICATION, NUMERIC_TYPE, None, ["-"]), - CharacteristicType('blood pressure', "health status", NUMERIC_TYPE, None, ["mmHg"]), + CharacteristicType('oral contraceptives', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + # CharacteristicType('oral contraceptives amount', MEDICATION, NUMERIC_TYPE, None, ["-"]), + + CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA + ["grapefruit juice"], + ["year", "weak", "day"]), + + # -------------- Caffeine -------------- + CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('caffeine amount', 'lifestyle', NUMERIC_TYPE, None, ["mg/day"]), - # ------------ - # smoking - # ------------ + # -------------- Smoking -------------- CharacteristicType('smoking', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('smoking amount (cigarettes)', 'lifestyle', NUMERIC_TYPE, None, ["1/day"]), CharacteristicType('smoking amount (packyears)', 'lifestyle', NUMERIC_TYPE, None, ["yr"]), CharacteristicType('smoking duration (years)', 'lifestyle', NUMERIC_TYPE, None, ["yr"]), - + # -------------- Alcohol -------------- CharacteristicType('alcohol', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('alcohol amount', 'lifestyle', NUMERIC_TYPE, None, ["-"]), + CharacteristicType('alcohol abstinence', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - - # Biochemical data + # -------------- Biochemical data -------------- CharacteristicType('ALT', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["IU/I"]), CharacteristicType('AST', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["IU/I"]), CharacteristicType('albumin', BIOCHEMICAL_DATA, NUMERIC_TYPE, None, ["g/dl"]), - # Study protocol - CharacteristicType('overnight fast', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('alcohol abstinence', 'study protocol', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA+["alcohol", "medication", "grapefruit juice"],["-"]), - - # Medication - # Genetics ??? - CharacteristicType('genetics', 'genetics', CATEGORIAL_TYPE, ["CYP2D6 duplication","CYP2D6 wild type", "CYP2D6 poor metabolizer"], ["-"]), + # --------------Genetic variants -------------- + CharacteristicType('genetics', GENETIC_VARIANTS, CATEGORIAL_TYPE, ["CYP2D6 duplication","CYP2D6 wild type", "CYP2D6 poor metabolizer"], ["-"]), - # Requires storage of the variants and effects of clearance ] + PK_DATA = [ "auc", "concentration", @@ -260,12 +276,14 @@ def create_choices(list): "caf_px_6h", "auc24h", ] + OUTPUT_TISSUE_DATA = [ "saliva", "plasma", "urine", "urine (24h)", ] + OUTPUT_TISSUE_DATA_CHOICES = create_choices(OUTPUT_TISSUE_DATA) PK_DATA_CHOICES = create_choices(PK_DATA) @@ -287,16 +305,3 @@ def dict_and_choices(data): CHARACTERISTIC_DICT, CHARACTERISTIC_CHOICES = dict_and_choices(CHARACTERISTIC_DATA) INTERVENTION_DICT, INTERVENTION_CHOICES = dict_and_choices(INTERVENTION_DATA) - -''' -DATA_CHOICES = ( - (1, "Other"), - (2, "Dynamic Individual"), - (3, "Dynamic Group"), - (4, "Static Individual"), - (5, "Static Group"), - ) -''' - - - From a32f0a9bea134daefa14602b431d30d27ce1fbec Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 11:45:38 +0200 Subject: [PATCH 060/115] categorials updated --- pkdb_app/categoricals.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index ad378515..ed461262 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -29,25 +29,20 @@ def create_choices(list): # TODO: lookup units package and proper units handling (units conversion, default units, ...) UNIT_TIME = [ - UnitType('sec'), - UnitType('min'), + UnitType('yr'), + UnitType('week'), + UnitType('day'), UnitType('h'), - UnitType('days'), + UnitType('min'), + UnitType('s'), ] TIME_UNITS_CHOICES = [(utype.name, utype.name) for utype in UNIT_TIME] - UNIT_DATA = UNIT_TIME + [ UnitType('-'), UnitType('cm'), UnitType('m'), UnitType('kg'), - UnitType('yr'), - UnitType('week'), - UnitType('day'), - UnitType('h'), - UnitType('min'), - UnitType('s'), UnitType('1/week'), UnitType('1/day'), @@ -229,8 +224,8 @@ def create_choices(list): CharacteristicType('oral contraceptives', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), # CharacteristicType('oral contraceptives amount', MEDICATION, NUMERIC_TYPE, None, ["-"]), - CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA + ["grapefruit juice"], - ["year", "weak", "day"]), + CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, ["alcohol", "caffeine", "grapefruit juice"], + ["year", "week", "day"]), # -------------- Caffeine -------------- CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), From 9bb3c41b5f1e02e52daca24204f31746751020e3 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 12:25:58 +0200 Subject: [PATCH 061/115] categorials updated --- pkdb_app/categoricals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index ed461262..362e109d 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -158,6 +158,7 @@ def create_choices(list): "caffeine", "paraxanthine", "paraxanthine/caffeine", + "caffeine/paraxanthine", "theobromine", "theophylline", "AAMU", From 86c406d19a2f71e0107b0b4fd104eb8e82e5fb5c Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 12:32:27 +0200 Subject: [PATCH 062/115] tizanidine added --- pkdb_app/categoricals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 362e109d..5aa031a9 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -172,6 +172,7 @@ def create_choices(list): "codeine", # misc + "tizanidine", "ibuprofen", "aspirin", "enoxacin", From e13e46bfa240690724978969238e396f2863d4fa Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 13:06:58 +0200 Subject: [PATCH 063/115] fixes #21 --- pkdb_app/comments/migrations/0001_initial.py | 2 +- .../comments/migrations/0003_comment_user.py | 4 +- pkdb_app/data_management/fill_database.py | 20 ++++-- pkdb_app/studies/views.py | 63 +++++++++++++++++++ pkdb_app/subjects/models.py | 2 + 5 files changed, 83 insertions(+), 8 deletions(-) diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index 68dc26cf..0f77b1be 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-16 15:11 +# Generated by Django 2.0.6 on 2018-08-17 08:02 from django.db import migrations, models diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index 8169b7ca..2cc68661 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-16 15:11 +# Generated by Django 2.0.6 on 2018-08-17 08:02 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('comments', '0002_auto_20180817_0802'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('comments', '0002_auto_20180816_1511'), ] operations = [ diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 0da61b3e..ea58e9b7 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -156,8 +156,13 @@ def set_keys(d, value, *keys): d = d[key] d[keys[-1]] = value +def remove_keys(d, value, *keys): + """ Changes keys in nested dictionary. """ + for key in keys[:-1]: + d = d[key] + d[keys[-1]] = value -def pop_comment(d, *keys): +def pop_comments(d, *keys): """ Pops comment in nested dictionary. """ for key in keys[:-1]: @@ -244,10 +249,15 @@ def upload_study_json(json_study_dict): if item in file_dict.keys(): set_keys(json_study_dict, file_dict[item], *keys) if "comments" in keys: - comments.append(keys) - - for comment in comments: - pop_comment(json_study_dict, *comment) + n_keys = [] + for key in keys: + n_keys.append(key) + if key == "comments": + break + comments.append(tuple(n_keys)) + + for comment in set(comments): + pop_comments(json_study_dict, *comment) # --------------------------- # post study core diff --git a/pkdb_app/studies/views.py b/pkdb_app/studies/views.py index 221327a9..faef8d6b 100644 --- a/pkdb_app/studies/views.py +++ b/pkdb_app/studies/views.py @@ -1,3 +1,6 @@ +from rest_framework.exceptions import ValidationError + +from pkdb_app.subjects.serializers import GroupSerializer from .models import Author, Reference, Study from .serializers import AuthorSerializer, ReferenceSerializer, StudySerializer from rest_framework import viewsets, generics @@ -57,6 +60,66 @@ class StudyViewSet(viewsets.ModelViewSet): search_fields = filter_fields + @staticmethod + def group_validation(request): + if "groupset" in request.data: + groupset = request.data["groupset"] + groups = groupset.get("groups", []) + parents = set([group.get("parent") for group in groups]) + groups = set([group.get("name") for group in groups]) + missing_groups = parents - groups + if not missing_groups: + msg = {"groups": f"<{missing_groups}> have been used but not defined"} + raise ValidationError(msg) + + def partial_update(self, request, *args, **kwargs): + self.group_validation(request) + return super().partial_update(request, *args, **kwargs) + + + def update(self, request, *args, **kwargs): + self.group_validation(request) + return super().update(request, *args, **kwargs) + + + def create(self, request, *args, **kwargs): + self.group_validation(request) + return super().create(request, *args, **kwargs) + + ''' + study_request = request.copy() + study_data = study_request.data + basic_keys = ["sid","name","pkdb_version","design","substances","reference","curators","files"] + study_core_data = [study_data.pop(basic_keys) for key in basic_keys] + request.data = study_core_data + response = super().create(request, *args, **kwargs) + + if "groupset" in study_data: + groupset = study_data["groupset"] + groups = groupset.get("groups", []) + for group in groups: + serializer = GroupSerializer(data=group,) + + if "individualset" in study_data: + indivdualset = study_data["individualset"] + individuals = indivdualset.get("individuals", []) + #upload individuals + + if "interventionset" in study_data: + interventionset = study_data["interventionset"] + interventions = interventionset.get("interventions", []) + #upload interventions + + + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + ''' + + + #class InterventionsViewSet(viewsets.ModelViewSet): diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 811ce210..9cf2eda8 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -61,8 +61,10 @@ class Group(models.Model): groupset = models.ForeignKey(GroupSet,on_delete=models.SET_NULL,null=True,related_name="groups") name = models.CharField(max_length=CHAR_MAX_LENGTH) count = models.IntegerField() # number of people/animals/objects in group + parent = models.ForeignKey("Group",null=True,blank=True,on_delete=models.CASCADE) objects = GroupManager() + @property def reference(self): return self.groupset.reference From ef1c68f213a8d7284a2ea3e16941cca223690aac Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 13:29:08 +0200 Subject: [PATCH 064/115] added parent to groups --- pkdb_app/serializers.py | 1 - pkdb_app/subjects/managers.py | 13 +++++++++++-- pkdb_app/subjects/serializers.py | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 19caeb3c..0d53f7a8 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -41,7 +41,6 @@ def is_valid(self, raise_exception=False): if "sid" in self.initial_data.keys(): sid = self.initial_data.get("sid") - self.context["study"] = sid try: # Try to get the object in question obj = self.Meta.model.objects.get(sid = sid) diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 43c0f28e..48f2e3ca 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -19,6 +19,8 @@ def create(self, *args, **kwargs): class GroupSetManager(models.Manager): def create(self, *args, **kwargs): characteristica = kwargs.pop("characteristica", []) + + groups = kwargs.pop("groups", []) groupset = super(GroupSetManager, self).create(*args, **kwargs) @@ -27,9 +29,16 @@ def create(self, *args, **kwargs): for characteristica_single in characteristica: groupset.characteristica.create(**characteristica_single) - + study_groups = [] for group in groups: - groupset.groups.create(**group) + if "parent" in group: + for n_group in study_groups: + if n_group.name == group["parent"]: + group["parent"] = n_group + + + n_group = groupset.groups.create(**group) + study_groups.append(n_group) groupset.save() diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index c97009e5..4d95eb80 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -40,10 +40,11 @@ def validate(self,data): class GroupSerializer(ParserSerializer): characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) + parent = serializers.CharField() class Meta: model = Group - fields = ["name", "count", "characteristica"] + fields = ["name", "count", "characteristica","parent"] def to_internal_value(self, data): self.validate_wrong_keys(data) From 7d38703ee20f91761e46bbf223e396517ae873f3 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 13:31:30 +0200 Subject: [PATCH 065/115] additional substances --- pkdb_app/categoricals.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 5aa031a9..91ba3dbb 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -168,11 +168,22 @@ def create_choices(list): "37X", "1X", + # quinolones + "quinolone", + "pipemidic acid", + "norfloxacin", + "enoxacin", + "ciprofloxacin", + "ofloxacin", + # codeine "codeine", + + # misc "tizanidine", + "ibuprofen", "aspirin", "enoxacin", From cbb0b60179b8f9280d483fc396809bec00ae761f Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 14:44:32 +0200 Subject: [PATCH 066/115] bug in groups --- pkdb_app/studies/views.py | 2 +- pkdb_app/subjects/serializers.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkdb_app/studies/views.py b/pkdb_app/studies/views.py index faef8d6b..99659847 100644 --- a/pkdb_app/studies/views.py +++ b/pkdb_app/studies/views.py @@ -68,7 +68,7 @@ def group_validation(request): parents = set([group.get("parent") for group in groups]) groups = set([group.get("name") for group in groups]) missing_groups = parents - groups - if not missing_groups: + if missing_groups: msg = {"groups": f"<{missing_groups}> have been used but not defined"} raise ValidationError(msg) diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 4d95eb80..0e00c472 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -44,13 +44,19 @@ class GroupSerializer(ParserSerializer): class Meta: model = Group - fields = ["name", "count", "characteristica","parent"] + fields = ["name","parent", "count", "characteristica",] def to_internal_value(self, data): self.validate_wrong_keys(data) data = self.generic_parser(data, "characteristica") return super(GroupSerializer, self).to_internal_value(data) + def to_representation(self, instance): + rep = super().to_representation(instance) + if "parent" in rep: + rep["parent"] = instance.parent.name + return rep + class GroupSetSerializer(ParserSerializer): characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) From ab85d70a9082583250613d18abe4b64848590831 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 15:06:48 +0200 Subject: [PATCH 067/115] descriptions replace description --- pkdb_app/comments/models.py | 29 +++++++++++++++++---------- pkdb_app/interventions/managers.py | 10 ++++++++- pkdb_app/interventions/serializers.py | 8 ++++++-- pkdb_app/subjects/managers.py | 10 +++++++++ pkdb_app/subjects/models.py | 2 +- pkdb_app/subjects/serializers.py | 7 +++++-- 6 files changed, 49 insertions(+), 17 deletions(-) diff --git a/pkdb_app/comments/models.py b/pkdb_app/comments/models.py index 5110f9e0..247fc569 100644 --- a/pkdb_app/comments/models.py +++ b/pkdb_app/comments/models.py @@ -14,22 +14,29 @@ class Comment(models.Model): time = models.DateTimeField(auto_created=True) #### - individual = models.ForeignKey(Individual,related_name="comments",blank=True, null=True, on_delete=False) + individual = models.ForeignKey(Individual,related_name="comments",blank=True, null=True, on_delete=False) individualset = models.ForeignKey(IndividualSet,related_name="comments",blank=True, null=True, on_delete=False) - group = models.ForeignKey(Group,related_name="comments", blank=True, null=True,on_delete=False) - groupset = models.ForeignKey(GroupSet,related_name="comments",blank=True, null=True, on_delete=False) - characteristica = models.ForeignKey(Characteristica,related_name="comments",blank=True, null=True, on_delete=False) + group = models.ForeignKey(Group,related_name="comments", blank=True, null=True,on_delete=False) + groupset = models.ForeignKey(GroupSet,related_name="comments",blank=True, null=True, on_delete=False) + characteristica = models.ForeignKey(Characteristica,related_name="comments",blank=True, null=True, on_delete=False) - output = models.ForeignKey(Output,related_name="comments",blank=True, null=True, on_delete=False) - outputset = models.ForeignKey(OutputSet,related_name="comments",blank=True, null=True, on_delete=False) - timecourse = models.ForeignKey(Timecourse,related_name="comments", blank=True, null=True,on_delete=False) + output = models.ForeignKey(Output,related_name="comments",blank=True, null=True, on_delete=False) + outputset = models.ForeignKey(OutputSet,related_name="comments",blank=True, null=True, on_delete=False) + timecourse = models.ForeignKey(Timecourse,related_name="comments", blank=True, null=True,on_delete=False) - intervention = models.ForeignKey(Intervention,related_name="comments",blank=True, null=True, on_delete=False) - interventionset = models.ForeignKey(InterventionSet,related_name="comments", blank=True, null=True,on_delete=False) + intervention = models.ForeignKey(Intervention,related_name="comments",blank=True, null=True, on_delete=False) + interventionset = models.ForeignKey(InterventionSet,related_name="comments", blank=True, null=True,on_delete=False) - reference = models.ForeignKey(Reference,related_name="comments",blank=True, null=True, on_delete=False) - study = models.ForeignKey(Study, related_name="comments",blank=True, null=True,on_delete=False) + reference = models.ForeignKey(Reference,related_name="comments",blank=True, null=True, on_delete=False) + study = models.ForeignKey(Study, related_name="comments",blank=True, null=True,on_delete=False) +class Description(models.Model): + text = models.TextField(blank=True, null=True) + + groupset = models.ForeignKey(GroupSet,related_name="descriptions",blank=True, null=True, on_delete=False) + interventionset = models.ForeignKey(InterventionSet,related_name="descriptions", blank=True, null=True,on_delete=False) + outputset = models.ForeignKey(OutputSet,related_name="descriptions",blank=True, null=True, on_delete=False) + individualset = models.ForeignKey(IndividualSet,related_name="descriptions",blank=True, null=True, on_delete=False) diff --git a/pkdb_app/interventions/managers.py b/pkdb_app/interventions/managers.py index f055942b..0754d7b9 100644 --- a/pkdb_app/interventions/managers.py +++ b/pkdb_app/interventions/managers.py @@ -9,10 +9,15 @@ class InterventionSetManager(models.Manager): def create(self, *args, **kwargs): interventions = kwargs.pop("interventions", []) + descriptions = kwargs.pop("descriptions", []) + interventionset = super().create(*args, **kwargs) interventionset.interventions.all().delete() + for description in descriptions: + interventionset.descriptions.create(**description) + for intervention in interventions: interventionset.interventions.create(**intervention) interventionset.save() @@ -25,10 +30,13 @@ class OutputSetManager(models.Manager): def create(self, *args, **kwargs): outputs = kwargs.pop("outputs", []) timecourses = kwargs.pop("timecourse", []) - + descriptions = kwargs.pop("descriptions", []) outputset = super().create(*args, **kwargs) outputset.outputs.all().delete() + for description in descriptions: + outputset.descriptions.create(**description) + for output in outputs: intervention_ids = output.pop("interventions", []) output_instance = outputset.outputs.create(**output) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 871d363c..a7a0f29a 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -2,6 +2,8 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db.models import Q from rest_framework import serializers + +from pkdb_app.comments.serializers import DescriptionsSerializer from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet, Timecourse from pkdb_app.serializers import ParserSerializer from pkdb_app.subjects.models import Individual, Group, DataFile @@ -46,9 +48,10 @@ def to_representation(self, instance): class InterventionSetSerializer(ParserSerializer): interventions = InterventionSerializer(many=True , read_only=False,required=False, allow_null=True) + descriptions = DescriptionsSerializer(many=True,read_only=False,required=False, allow_null=True ) class Meta: model = InterventionSet - fields = ["description","interventions"] + fields = ["descriptions","interventions"] def to_internal_value(self, data): """ @@ -147,10 +150,11 @@ class Meta: class OutputSetSerializer(ParserSerializer): outputs = OutputSerializer(many=True, read_only=False, required=False, allow_null=True) timecourse = TimecourseSerializer(many=True, read_only=False, required=False, allow_null=True) + descriptions = DescriptionsSerializer(many=True,read_only=False,required=False, allow_null=True ) class Meta: model = OutputSet - fields = ["description","outputs","timecourse"] + fields = ["descriptions","outputs","timecourse"] def to_internal_value(self, data): """ diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 48f2e3ca..4708f376 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -19,6 +19,7 @@ def create(self, *args, **kwargs): class GroupSetManager(models.Manager): def create(self, *args, **kwargs): characteristica = kwargs.pop("characteristica", []) + descriptions = kwargs.pop("descriptions", []) groups = kwargs.pop("groups", []) @@ -29,6 +30,10 @@ def create(self, *args, **kwargs): for characteristica_single in characteristica: groupset.characteristica.create(**characteristica_single) + + for description in descriptions: + groupset.descriptions.create(**description) + study_groups = [] for group in groups: if "parent" in group: @@ -60,11 +65,16 @@ class IndividualSetManager(models.Manager): def create(self, *args, **kwargs): characteristica = kwargs.pop("characteristica", []) individuals = kwargs.pop("individuals", []) + descriptions = kwargs.pop("descriptions", []) + individualset = super(IndividualSetManager, self).create(*args, **kwargs) individualset.characteristica.all().delete() individualset.individuals.all().delete() + for description in descriptions: + individualset.descriptions.create(**description) + for characteristica_single in characteristica: individualset.characteristica.create(**characteristica_single) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 9cf2eda8..fd421e8c 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -36,7 +36,7 @@ def __str__(self): return self.file.name -class Set(Describable, models.Model): +class Set(models.Model): """ abstract class for all set classes """ diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 0e00c472..166c2262 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -2,6 +2,7 @@ from django.core.exceptions import ValidationError from rest_framework import serializers from pkdb_app.behaviours import Sourceable +from pkdb_app.comments.serializers import DescriptionsSerializer from pkdb_app.utils import un_map, validate_input from .models import Group, GroupSet, Individual, IndividualSet, Characteristica, DataFile from ..serializers import ParserSerializer, WrongKeySerializer @@ -61,10 +62,11 @@ def to_representation(self, instance): class GroupSetSerializer(ParserSerializer): characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) groups = GroupSerializer(many=True, read_only=False) + descriptions = DescriptionsSerializer(many=True,read_only=False,required=False, allow_null=True ) class Meta: model = GroupSet - fields = ["description", "characteristica", "groups"] + fields = ["descriptions", "characteristica", "groups"] def to_internal_value(self, data): self.validate_wrong_keys(data) @@ -132,10 +134,11 @@ class IndividualSetSerializer(ParserSerializer): characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) individuals = IndividualSerializer(many=True, read_only=False, required=False) + descriptions = DescriptionsSerializer(many=True,read_only=False,required=False, allow_null=True ) class Meta: model = IndividualSet - fields = ["description", "individuals", "characteristica"] + fields = ["descriptions", "individuals", "characteristica"] def to_internal_value(self, data): self.validate_wrong_keys(data) From dff9086d409f4aebd01c2b6e827b9cb9d6fe4e6e Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 15:07:15 +0200 Subject: [PATCH 068/115] serializer added --- pkdb_app/comments/serializers.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 pkdb_app/comments/serializers.py diff --git a/pkdb_app/comments/serializers.py b/pkdb_app/comments/serializers.py new file mode 100644 index 00000000..69aba6c8 --- /dev/null +++ b/pkdb_app/comments/serializers.py @@ -0,0 +1,16 @@ +from rest_framework import serializers + +from pkdb_app.comments.models import Description + + +class DescriptionsSerializer(serializers.ModelSerializer): + + class Meta: + fields = ["text"] + model = Description + + def to_internal_value(self, data): + return {"text": data} + + def to_representation(self, instance): + return instance.text From 82696f82f0a29b53c5b62c83fe92d64bf1604b94 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 15:26:12 +0200 Subject: [PATCH 069/115] updated categorials --- pkdb_app/categoricals.py | 5 ++--- pkdb_app/comments/migrations/0001_initial.py | 4 ++-- pkdb_app/comments/migrations/0003_comment_user.py | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 91ba3dbb..d7282949 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -167,7 +167,7 @@ def create_choices(list): "17U", "37X", "1X", - + "methylxanthine", # quinolones "quinolone", "pipemidic acid", @@ -179,8 +179,6 @@ def create_choices(list): # codeine "codeine", - - # misc "tizanidine", @@ -224,6 +222,7 @@ def create_choices(list): # -------------- Patient status -------------- CharacteristicType('overnight fast', PATIENT_STATUS, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), + CharacteristicType('fasted', PATIENT_STATUS, NUMERIC_TYPE, None, ["h"]), CharacteristicType('healthy', PATIENT_STATUS, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('disease', PATIENT_STATUS, CATEGORIAL_TYPE, [NAN, "cirrhosis", "plasmodium falciparum", "alcoholic liver cirrhosis", "cirrhotic liver disease", "PBC", diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py index 0f77b1be..af1cafb0 100644 --- a/pkdb_app/comments/migrations/0001_initial.py +++ b/pkdb_app/comments/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-17 08:02 +# Generated by Django 2.0.6 on 2018-08-17 12:38 from django.db import migrations, models @@ -8,8 +8,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('interventions', '0001_initial'), ('subjects', '0001_initial'), + ('interventions', '0001_initial'), ] operations = [ diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py index 2cc68661..7edafa5c 100644 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ b/pkdb_app/comments/migrations/0003_comment_user.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2018-08-17 08:02 +# Generated by Django 2.0.6 on 2018-08-17 12:38 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('comments', '0002_auto_20180817_0802'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('comments', '0002_auto_20180817_1238'), ] operations = [ From 8d6a98b7c1013c269b849fd0b1f7692e945b98cf Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 15:26:20 +0200 Subject: [PATCH 070/115] colered logging, debug characteristca not allowed on groupset --- pkdb_app/data_management/upload_study.py | 4 ++++ pkdb_app/data_management/watch_study.py | 6 ++++-- pkdb_app/subjects/managers.py | 6 +++--- pkdb_app/subjects/serializers.py | 5 ++--- requirements.txt | 3 ++- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/pkdb_app/data_management/upload_study.py b/pkdb_app/data_management/upload_study.py index e7ed0491..7108aa50 100644 --- a/pkdb_app/data_management/upload_study.py +++ b/pkdb_app/data_management/upload_study.py @@ -6,6 +6,10 @@ import os import sys import argparse +import coloredlogs, logging + +logger = logging.getLogger(__name__) +coloredlogs.install(level='INFO') BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) diff --git a/pkdb_app/data_management/watch_study.py b/pkdb_app/data_management/watch_study.py index 74cae4eb..79465fb6 100755 --- a/pkdb_app/data_management/watch_study.py +++ b/pkdb_app/data_management/watch_study.py @@ -11,9 +11,11 @@ import sys import time import argparse -import logging +import coloredlogs, logging + +logger = logging.getLogger(__name__) +coloredlogs.install(level='INFO') -logging.getLogger().setLevel(logging.INFO) from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 4708f376..5d79d357 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -18,7 +18,7 @@ def create(self, *args, **kwargs): class GroupSetManager(models.Manager): def create(self, *args, **kwargs): - characteristica = kwargs.pop("characteristica", []) + #characteristica = kwargs.pop("characteristica", []) descriptions = kwargs.pop("descriptions", []) @@ -28,8 +28,8 @@ def create(self, *args, **kwargs): groupset.characteristica.all().delete() groupset.groups.all().delete() - for characteristica_single in characteristica: - groupset.characteristica.create(**characteristica_single) + #for characteristica_single in characteristica: + # groupset.characteristica.create(**characteristica_single) for description in descriptions: groupset.descriptions.create(**description) diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 166c2262..4bf8bed7 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -60,17 +60,16 @@ def to_representation(self, instance): class GroupSetSerializer(ParserSerializer): - characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) + #characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) groups = GroupSerializer(many=True, read_only=False) descriptions = DescriptionsSerializer(many=True,read_only=False,required=False, allow_null=True ) class Meta: model = GroupSet - fields = ["descriptions", "characteristica", "groups"] + fields = ["descriptions","groups"] def to_internal_value(self, data): self.validate_wrong_keys(data) - data = self.generic_parser(data, "characteristica") return super(GroupSetSerializer, self).to_internal_value(data) diff --git a/requirements.txt b/requirements.txt index efeab3e2..7490a8a4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -52,4 +52,5 @@ django-extra-fields PyPDF2 lark-parser watchdog -requests \ No newline at end of file +requests +coloredlogs \ No newline at end of file From 3c0a7c7b0acb26290ba6dc576070bd7b159f93e4 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 15:33:32 +0200 Subject: [PATCH 071/115] removed migration files --- pkdb_app/comments/migrations/0001_initial.py | 33 ------------------- .../comments/migrations/0003_comment_user.py | 22 ------------- 2 files changed, 55 deletions(-) delete mode 100644 pkdb_app/comments/migrations/0001_initial.py delete mode 100644 pkdb_app/comments/migrations/0003_comment_user.py diff --git a/pkdb_app/comments/migrations/0001_initial.py b/pkdb_app/comments/migrations/0001_initial.py deleted file mode 100644 index af1cafb0..00000000 --- a/pkdb_app/comments/migrations/0001_initial.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 2.0.6 on 2018-08-17 12:38 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('subjects', '0001_initial'), - ('interventions', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='Comment', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('time', models.DateTimeField(auto_created=True)), - ('text', models.TextField(blank=True, null=True)), - ('characteristica', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.Characteristica')), - ('group', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.Group')), - ('groupset', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.GroupSet')), - ('individual', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.Individual')), - ('individualset', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='subjects.IndividualSet')), - ('intervention', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.Intervention')), - ('interventionset', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.InterventionSet')), - ('output', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.Output')), - ('outputset', models.ForeignKey(blank=True, null=True, on_delete=False, related_name='comments', to='interventions.OutputSet')), - ], - ), - ] diff --git a/pkdb_app/comments/migrations/0003_comment_user.py b/pkdb_app/comments/migrations/0003_comment_user.py deleted file mode 100644 index 7edafa5c..00000000 --- a/pkdb_app/comments/migrations/0003_comment_user.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 2.0.6 on 2018-08-17 12:38 - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('comments', '0002_auto_20180817_1238'), - ] - - operations = [ - migrations.AddField( - model_name='comment', - name='user', - field=models.ForeignKey(on_delete=False, related_name='comments', to=settings.AUTH_USER_MODEL), - ), - ] From 459d5625bf85d82bc0fc4d4354fcf8a355d52a00 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 16:28:32 +0200 Subject: [PATCH 072/115] updated categorials --- pkdb_app/categoricals.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index d7282949..091d1259 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -157,8 +157,6 @@ def create_choices(list): # caffeine "caffeine", "paraxanthine", - "paraxanthine/caffeine", - "caffeine/paraxanthine", "theobromine", "theophylline", "AAMU", @@ -168,6 +166,14 @@ def create_choices(list): "37X", "1X", "methylxanthine", + "paraxanthine/caffeine", + "caffeine/paraxanthine", + "theobromine/caffeine", + "theophylline/caffeine", + "1X/caffeine", + "1X/paraxanthine", + "1X/theophylline", + # quinolones "quinolone", "pipemidic acid", From 63fa9ba089d1cb7f84eab1fc7dc983b6d76dab07 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 16:33:33 +0200 Subject: [PATCH 073/115] debug group validation --- pkdb_app/studies/views.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pkdb_app/studies/views.py b/pkdb_app/studies/views.py index 99659847..35a63a46 100644 --- a/pkdb_app/studies/views.py +++ b/pkdb_app/studies/views.py @@ -63,14 +63,18 @@ class StudyViewSet(viewsets.ModelViewSet): @staticmethod def group_validation(request): if "groupset" in request.data: - groupset = request.data["groupset"] - groups = groupset.get("groups", []) - parents = set([group.get("parent") for group in groups]) - groups = set([group.get("name") for group in groups]) - missing_groups = parents - groups - if missing_groups: - msg = {"groups": f"<{missing_groups}> have been used but not defined"} - raise ValidationError(msg) + if request.data["groupset"]: + groupset = request.data["groupset"] + if "groups" in groupset: + groups = groupset.get("groups", []) + parents = set([group.get("parent") for group in groups if group.get("parent")] ) + groups = set([group.get("name") for group in groups if group.get("name")]) + missing_groups = parents - groups + if missing_groups: + print(missing_groups) + if missing_groups is not None: + msg = {"groups": f"<{missing_groups}> have been used but not defined"} + raise ValidationError(msg) def partial_update(self, request, *args, **kwargs): self.group_validation(request) From 6badd11aee7824be0bc96db06cc5cebdabb39bf0 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 17:49:04 +0200 Subject: [PATCH 074/115] updated categorials --- pkdb_app/categoricals.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 091d1259..781b312b 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -272,29 +272,29 @@ def create_choices(list): ] PK_DATA = [ - "auc", + "auc_inf", # Area under the curve, extrapolated until infinity + "auc_end", # Area under the curve, until end time point (time has to be given as time attribute) + + "amount", "concentration", + "ratio", + "clearance", - "vd", - "thalf", - "tmax", - "cmax", - "amount", - "kel", - "kabs", + "clearance_renal", + "vd", # Volume of distribution + "thalf", # halflife + "tmax", # time of maximum + "cmax", # maximum concentration + + "kel", # elimination rate + "kabs", # absorption rate "plasma_binding", - "clearance_unbound", - "ratio", - "clearance_tbc", - "caf_px_6h", - "auc24h", ] OUTPUT_TISSUE_DATA = [ "saliva", "plasma", "urine", - "urine (24h)", ] OUTPUT_TISSUE_DATA_CHOICES = create_choices(OUTPUT_TISSUE_DATA) From 1321daa429dc9385f8740deff4f0f166df5c3cc1 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 17:50:53 +0200 Subject: [PATCH 075/115] cleaning --- pkdb_app/categoricals.py | 5 ++--- pkdb_app/data_management/fill_database.py | 8 +++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 091d1259..e4bf2119 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -198,8 +198,7 @@ def create_choices(list): "fluvoxamine", "ethanol", "chlorozoxazone", - "lomefloxacin", -] + "lomefloxacin",] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] @@ -242,7 +241,7 @@ def create_choices(list): CharacteristicType('oral contraceptives', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), # CharacteristicType('oral contraceptives amount', MEDICATION, NUMERIC_TYPE, None, ["-"]), - CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, ["alcohol", "caffeine", "grapefruit juice"], + CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA+["alcohol", "grapefruit juice"], ["year", "week", "day"]), # -------------- Caffeine -------------- diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index ea58e9b7..586d5c5e 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -164,12 +164,11 @@ def remove_keys(d, value, *keys): def pop_comments(d, *keys): """ Pops comment in nested dictionary. """ - for key in keys[:-1]: + for key in keys: if key == "comments": d.pop("comments") return - d = d[key] @@ -255,9 +254,12 @@ def upload_study_json(json_study_dict): if key == "comments": break comments.append(tuple(n_keys)) - + #print(comments) for comment in set(comments): pop_comments(json_study_dict, *comment) + #from pprint import pprint + #pprint(json_study_dict) + # --------------------------- # post study core From 70c2f621052623de9c6683e51f3623c2d8a6ebeb Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 17 Aug 2018 18:07:03 +0200 Subject: [PATCH 076/115] changed length max --- pkdb_app/categoricals.py | 2 ++ pkdb_app/interventions/models.py | 6 ++++++ pkdb_app/interventions/serializers.py | 6 ++++-- pkdb_app/utils.py | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index cab5d271..92aed8bc 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -65,6 +65,8 @@ def create_choices(list): UnitType("mmHg"), UnitType("ml/min/1.73m^2"), UnitType("µg/ml*h/kg"), + UnitType("mg*h/l"), + UnitType("l/h"), UnitType("l"), UnitType("µmol/l*h"), UnitType("ml/min"), diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index a200d361..844d3729 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -136,6 +136,8 @@ class Meta: class OutputMap(models.Model): pktype_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) time_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + time_unit_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + class Meta: abstract = True @@ -151,6 +153,8 @@ class Output(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseOutpu pktype = models.CharField(max_length=CHAR_MAX_LENGTH,choices=PK_DATA_CHOICES, null=True, blank=True) time = models.FloatField(null=True,blank=True) + time_unit = models.CharField(max_length=CHAR_MAX_LENGTH,null=True,blank=True, choices=TIME_UNITS_CHOICES) + # files from which the data was extracted, these have to be linked to the study already should be PNG or NONE #files = models.ForeignKey(DataFile, on_delete=True) @@ -169,6 +173,8 @@ class Timecourse(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseO outputset = models.ForeignKey(OutputSet, related_name="timecourse", on_delete=models.CASCADE,null=True, blank=True) pktype = models.CharField(max_length=CHAR_MAX_LENGTH, choices=PK_DATA_CHOICES, null=True, blank=True) time = models.DecimalField(max_digits=40, decimal_places=20, null=True, blank=True) + time_unit = models.CharField(max_length=CHAR_MAX_LENGTH,null=True,blank=True, choices=TIME_UNITS_CHOICES) + #data = models.ForeignKey(DataFile, on_delete=True) # link to the CSV diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index a7a0f29a..200a5252 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -76,7 +76,8 @@ class Meta: fields = ["source","figure","format"] + \ ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", ] \ +["value_map", "mean_map", "median_map", "min_map", "max_map","sd_map", "se_map", "cv_map", "unit_map" ]\ - + ["pktype", "pktype_map", "time", + + ["pktype", "pktype_map", "time", "time_unit", + "time_unit_map", "time_map","group","group_map", "individual", "individual_map", "interventions", "interventions_map", "substance","substance_map","tissue", "tissue_map"] @@ -140,7 +141,8 @@ class Meta: + ["value_map", "mean_map", "median_map", "min_map", "max_map", "sd_map", "se_map", "cv_map", "unit_map"] \ + ["pktype", "pktype_map", "time", - "time_map", "group", "group_map", "individual", "individual_map", "interventions", + "time_map", "time_unit", + "time_unit_map", "group", "group_map", "individual", "individual_map", "interventions", "interventions_map", "substance", "substance_map", "tissue", "tissue_map"] diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index 58ca8eb3..b0327aed 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -5,7 +5,7 @@ from pkdb_app.categoricals import CHARACTERISTIC_DICT, CATEGORIAL_TYPE, BOOLEAN_TYPE, NUMERIC_TYPE, INTERVENTION_DICT -CHAR_MAX_LENGTH = 30 +CHAR_MAX_LENGTH = 100 def create_if_exists(src,src_key,dest,dest_key): if src_key in src.keys(): From d1d76db3a6dcd88cfb027e5218c0308ee2325166 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 19:19:00 +0200 Subject: [PATCH 077/115] make watchdog work with atom --- pkdb_app/categoricals.py | 1 + pkdb_app/data_management/watch_study.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 92aed8bc..cdff2d4e 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -114,6 +114,7 @@ def create_choices(list): INTERVENTION_FORM = [ "tablete", "capsule", + "solution", NAN, ] INTERVENTION_FORM_CHOICES = create_choices(INTERVENTION_FORM) diff --git a/pkdb_app/data_management/watch_study.py b/pkdb_app/data_management/watch_study.py index 79465fb6..62ce716e 100755 --- a/pkdb_app/data_management/watch_study.py +++ b/pkdb_app/data_management/watch_study.py @@ -38,7 +38,7 @@ def __init__(self, study): logging.info('-' * 80) upload_study_from_dir(self.study) - def on_created(self, event): + def on_modified(self, event): print('\n') upload_study_from_dir(self.study) From 819eb9e916106936618a443852fc18bb40221527 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Fri, 17 Aug 2018 20:06:09 +0200 Subject: [PATCH 078/115] improved path handling of watcher --- pkdb_app/data_management/watch_study.py | 49 ++++++++++++++++--------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/pkdb_app/data_management/watch_study.py b/pkdb_app/data_management/watch_study.py index 62ce716e..b9dab11e 100755 --- a/pkdb_app/data_management/watch_study.py +++ b/pkdb_app/data_management/watch_study.py @@ -11,15 +11,14 @@ import sys import time import argparse -import coloredlogs, logging +import coloredlogs +import logging +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler logger = logging.getLogger(__name__) coloredlogs.install(level='INFO') - -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler - BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) @@ -29,25 +28,41 @@ class StudyHandler(FileSystemEventHandler): - def __init__(self, study): - self.study = study - _, study_name = os.path.split(self.study) + """ Handler for study folder. """ + def __init__(self, path): + + self.path = path + _, study_name = os.path.split(self.path) logging.info('-' * 80) logging.info(f'Watching [{study_name}]') - logging.info(f'\t{self.study}') + logging.info(f'\t{self.path}') logging.info('-' * 80) - upload_study_from_dir(self.study) + upload_study_from_dir(self.path) def on_modified(self, event): + """ Executed on modified event. + :param event: + :return: + """ print('\n') - upload_study_from_dir(self.study) + upload_study_from_dir(self.path) -def run(args): +def start_observer(args): """ Run observer. """ - event_handler = StudyHandler(study=args.study) + + # normalize path + path = os.path.abspath(args.path) + if path.endswith("/"): + path = path[:-1] + if not os.path.exists(path) or not os.path.isdir(path): + print(path) + raise FileNotFoundError + + # start event handling + event_handler = StudyHandler(path=path) observer = Observer() - observer.schedule(event_handler, path=args.study, recursive=False) + observer.schedule(event_handler, path=path, recursive=False) observer.start() try: while True: @@ -58,8 +73,8 @@ def run(args): if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Watch a study folder for changes") - parser.add_argument("-s", help="directory of study", dest="study", type=str, required=True) - parser.set_defaults(func=run) + parser = argparse.ArgumentParser(description="Watch a study directory for changes") + parser.add_argument("-s", help="path to study directory", dest="path", type=str, required=True) + parser.set_defaults(func=start_observer) args = parser.parse_args() args.func(args) From 778c24b2729b880a0556c06439b80c588796c695 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Sat, 18 Aug 2018 18:01:46 +0200 Subject: [PATCH 079/115] categorials for oral contraceptives --- pkdb_app/categoricals.py | 5 +++++ pkdb_app/interventions/models.py | 7 ++----- pkdb_app/subjects/models.py | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index cdff2d4e..a8b039aa 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -185,6 +185,11 @@ def create_choices(list): "ciprofloxacin", "ofloxacin", + # oral contraceptives + "levonorgestrel", + "gestodene", + "EE2", + # codeine "codeine", diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 844d3729..2b084ff0 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -36,8 +36,6 @@ #new - - class Substance(models.Model): """ Substances have to be in a different table, so that than be uniquely defined. @@ -53,12 +51,12 @@ class Substance(models.Model): def __str__(self): return self.name + class InterventionSet(Set): objects = InterventionSetManager() -class Intervention(Valueable,models.Model): - +class Intervention(Valueable, models.Model): """ A concrete step/thing which is done to the group. In case of dosing/medication the actual dosing is stored in the Valueable. @@ -70,7 +68,6 @@ class Intervention(Valueable,models.Model): substance = models.ForeignKey(Substance, null=True,blank=False, on_delete=False)#substance: # what was given [' route = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_ROUTE_CHOICES)# route: # where ['oral', 'iv'] form = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_FORM_CHOICES) - application = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True,null=True, choices=INTERVENTION_APPLICATION_CHOICES) # application: # how timing ['single dose', 'multiple doses', 'continuous injection'] time = models.FloatField(null=True,blank=False) #application_time: # when exactly [h] (for multiple times create multiple MedicationSteps) time_unit = models.CharField(max_length=CHAR_MAX_LENGTH,null=True,blank=True, choices=TIME_UNITS_CHOICES) diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index fd421e8c..89993031 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -140,7 +140,7 @@ class Meta: abstract = True -class Characteristica(CharacteristicaBase,ValueableMap,Valueable, models.Model): +class Characteristica(CharacteristicaBase, ValueableMap, Valueable, models.Model): """ Characteristic. Characteristics are used to store information about a group of subjects. From b8c510095d3b625be609bec364ec6a92d2da8ac7 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Sat, 18 Aug 2018 18:57:49 +0200 Subject: [PATCH 080/115] additional caffeine ratios added --- pkdb_app/categoricals.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index a8b039aa..1a12f15b 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -162,6 +162,7 @@ def create_choices(list): "paraxanthine", "theobromine", "theophylline", + "AFMU", "AAMU", "1U", "17X", @@ -176,6 +177,10 @@ def create_choices(list): "1X/caffeine", "1X/paraxanthine", "1X/theophylline", + "(AFMU+1U+1X)/17U", + "17U/17X", + "1U/(1U+1X)", + "AFMU/(AFMU+1U+1X)", # quinolones "quinolone", From 89b49395e327a2e0736bde542982835d87f31139 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 18 Aug 2018 19:46:49 +0200 Subject: [PATCH 081/115] fixes #27 --- pkdb_app/data_management/fill_database.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 586d5c5e..15f7e606 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -146,6 +146,10 @@ def recursive_iter(obj, keys=()): elif any(isinstance(obj, t) for t in (list, tuple)): for idx, item in enumerate(obj): yield from recursive_iter(item, keys + (idx,)) + + if len(obj) == 0: + yield keys, None + else: yield keys, obj @@ -248,17 +252,18 @@ def upload_study_json(json_study_dict): if item in file_dict.keys(): set_keys(json_study_dict, file_dict[item], *keys) if "comments" in keys: + print(keys) n_keys = [] for key in keys: n_keys.append(key) if key == "comments": break comments.append(tuple(n_keys)) - #print(comments) + print(comments) for comment in set(comments): pop_comments(json_study_dict, *comment) - #from pprint import pprint - #pprint(json_study_dict) + from pprint import pprint + pprint(list(recursive_iter(json_study_dict))) # --------------------------- From 8b50c059ab0e0077e948d21b456b61c2436f2930 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 18 Aug 2018 19:47:56 +0200 Subject: [PATCH 082/115] removed prints for debuging --- pkdb_app/data_management/fill_database.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 15f7e606..7a2f8e5a 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -259,11 +259,10 @@ def upload_study_json(json_study_dict): if key == "comments": break comments.append(tuple(n_keys)) - print(comments) for comment in set(comments): pop_comments(json_study_dict, *comment) - from pprint import pprint - pprint(list(recursive_iter(json_study_dict))) + #from pprint import pprint + #pprint(list(recursive_iter(json_study_dict))) # --------------------------- From 54a5c3f8b195ce733bb56009e8f71187c048783d Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 18 Aug 2018 19:49:18 +0200 Subject: [PATCH 083/115] cleaning --- pkdb_app/data_management/fill_database.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 7a2f8e5a..879024a0 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -252,7 +252,6 @@ def upload_study_json(json_study_dict): if item in file_dict.keys(): set_keys(json_study_dict, file_dict[item], *keys) if "comments" in keys: - print(keys) n_keys = [] for key in keys: n_keys.append(key) From 93aba6dd0b8efbcdbeeaecfa8a5f9ac914995c5d Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 18 Aug 2018 19:52:20 +0200 Subject: [PATCH 084/115] added subset_map --- pkdb_app/interventions/models.py | 1 + pkdb_app/interventions/serializers.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index 2b084ff0..feed05c1 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -126,6 +126,7 @@ class BaseOutputMap(models.Model): interventions_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) substance_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) tissue_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + subset_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) class Meta: abstract = True diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 200a5252..56c17ff5 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -79,7 +79,7 @@ class Meta: + ["pktype", "pktype_map", "time", "time_unit", "time_unit_map", "time_map","group","group_map", "individual", "individual_map", "interventions", "interventions_map", - "substance","substance_map","tissue", "tissue_map"] + "substance","substance_map","tissue", "tissue_map","subset_map"] def to_internal_value(self, data): study_sid = self.context['request'].path.split("/")[-2] @@ -141,7 +141,7 @@ class Meta: + ["value_map", "mean_map", "median_map", "min_map", "max_map", "sd_map", "se_map", "cv_map", "unit_map"] \ + ["pktype", "pktype_map", "time", - "time_map", "time_unit", + "time_map", "time_unit","subset_map", "time_unit_map", "group", "group_map", "individual", "individual_map", "interventions", "interventions_map", "substance", "substance_map", "tissue", "tissue_map"] From fe546a3b68420d137f6d8236e3369b079cb49764 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Sun, 19 Aug 2018 16:43:45 +0200 Subject: [PATCH 085/115] updated categorials, Fix #26, prettify json --- pkdb_app/categoricals.py | 16 +++++---- pkdb_app/data_management/fill_database.py | 40 ++++++++++++++++------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 1a12f15b..3dbee713 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -112,7 +112,7 @@ def create_choices(list): INTERVENTION_APPLICATION_CHOICES = create_choices(INTERVENTION_APPLICATION) INTERVENTION_FORM = [ - "tablete", + "tablet", "capsule", "solution", NAN, @@ -141,8 +141,8 @@ def create_choices(list): FileFormat = namedtuple("FileFormat", ["name", "delimiter"]) -FORMAT_MAPPING = {"TSV": FileFormat("TSV",'\t'), - "CSV": FileFormat("CSV",",")} +FORMAT_MAPPING = {"TSV": FileFormat("TSV", '\t'), + "CSV": FileFormat("CSV", ",")} STUDY_DESIGN_DATA = [ "single group", # (interventional study) @@ -178,6 +178,7 @@ def create_choices(list): "1X/paraxanthine", "1X/theophylline", "(AFMU+1U+1X)/17U", + "(AAMU+1X+1U)/17U", "17U/17X", "1U/(1U+1X)", "AFMU/(AFMU+1U+1X)", @@ -200,6 +201,7 @@ def create_choices(list): # misc "tizanidine", + "venlafaxine", "ibuprofen", "aspirin", @@ -211,7 +213,8 @@ def create_choices(list): "fluvoxamine", "ethanol", "chlorozoxazone", - "lomefloxacin",] + "lomefloxacin", +] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] @@ -294,12 +297,13 @@ def create_choices(list): "clearance", "clearance_renal", "vd", # Volume of distribution - "thalf", # halflife + "thalf", # half-life "tmax", # time of maximum "cmax", # maximum concentration - "kel", # elimination rate + "kel", # elimination rate (often beta) "kabs", # absorption rate + "fraction_absorbed", # "often also absolute bioavailability "plasma_binding", ] diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 586d5c5e..82da1df9 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -227,6 +227,26 @@ def upload_reference_json(json_reference): return success +def check_json_response(response): + """ Check response and create warning if not valid + + :param response: + :return: + """ + if response.status_code not in [200, 201]: + try: + json_data = json.loads(response.text) + + msg = json.dumps(json_data, sort_keys=True, indent=2) + logging.warning(f'\n{msg}') + + except json.decoder.JSONDecodeError as err: + logging.warning(err) + + return False + return True + + def upload_study_json(json_study_dict): """ Uploads study JSON. @@ -242,7 +262,6 @@ def upload_study_json(json_study_dict): study_dir = os.path.dirname(json_study_dict["study_path"]) file_dict = upload_files(study_dir) - comments = [] for keys, item in recursive_iter(json_study_dict): if item in file_dict.keys(): @@ -260,7 +279,6 @@ def upload_study_json(json_study_dict): #from pprint import pprint #pprint(json_study_dict) - # --------------------------- # post study core # --------------------------- @@ -288,21 +306,19 @@ def upload_study_json(json_study_dict): study_sets["interventionset"] = json_study.get("interventionset") study_sets["individualset"] = json_study.get("individualset") - response = requests.patch(f'{API_URL}/studies/{json_study["sid"]}/', json=study_sets) - if not response.status_code == 200: - logging.warning(f'{study_core["name"]} {response.text}') - success = False + # post + sid = json_study["sid"] + response = requests.patch(f'{API_URL}/studies/{sid}/', json=study_sets) + success = success and check_json_response(response) - # patch if "outputset" in json_study.keys(): - response = requests.patch(f'{API_URL}/studies/{json_study["sid"]}/', + response = requests.patch(f'{API_URL}/studies/{sid}/', json={"outputset": json_study.get("outputset")}) - if not response.status_code == 200: - logging.warning(f'{study_core["name"]} {response.text}') - success = False + success = success and check_json_response(response) if success: - logging.info(f'{API_URL}/studies/{json_study["sid"]}/') + # print access URL + logging.info(f'{API_URL}/studies/{sid}/') return success From 1a4c46fa7321f164467eb6831852f3bd759f822d Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Sun, 19 Aug 2018 17:44:32 +0200 Subject: [PATCH 086/115] updating categorials --- pkdb_app/categoricals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 3dbee713..aed1995c 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -202,6 +202,7 @@ def create_choices(list): # misc "tizanidine", "venlafaxine", + "lomefloxacin", "ibuprofen", "aspirin", From 93f5b820c33e4396fe30c2f607b997354fd0d818 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Sun, 19 Aug 2018 18:06:20 +0200 Subject: [PATCH 087/115] comments about groupset, fixed warnings --- pkdb_app/data_management/fill_database.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index e32eabd5..f2d852b0 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -297,17 +297,17 @@ def upload_study_json(json_study_dict): study_core["files"] = list(file_dict.values()) response = requests.post(f'{API_URL}/studies/', json=study_core) - if not response.status_code == 201: - logging.warning(f'{study_core["name"]} {response.text}') - success = False + success = check_json_response(response) # --------------------------- # post study sets # --------------------------- study_sets = {} study_sets["groupset"] = json_study.get("groupset") - study_sets["interventionset"] = json_study.get("interventionset") study_sets["individualset"] = json_study.get("individualset") + study_sets["interventionset"] = json_study.get("interventionset") + + # FIXME: Where are groupset, individualset and interventionset uploaded? # post sid = json_study["sid"] From 9228403ca39559850ced9557ecadd61eda99d8e4 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Sun, 19 Aug 2018 18:20:11 +0200 Subject: [PATCH 088/115] logging modules and line levels --- pkdb_app/data_management/watch_study.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkdb_app/data_management/watch_study.py b/pkdb_app/data_management/watch_study.py index b9dab11e..5f9d09a2 100755 --- a/pkdb_app/data_management/watch_study.py +++ b/pkdb_app/data_management/watch_study.py @@ -16,8 +16,15 @@ from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler +coloredlogs.install( + level='INFO', + fmt="%(module)s:%(lineno)s %(funcName)s %(levelname) -10s %(message)s" + # fmt="%(levelname) -10s %(asctime)s %(module)s:%(lineno)s %(funcName)s %(message)s" +) logger = logging.getLogger(__name__) -coloredlogs.install(level='INFO') + + + BASEPATH = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../')) sys.path.append(BASEPATH) From bc90c4710510713bae3ac6bce40ad85885eeb806 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Sun, 19 Aug 2018 18:49:20 +0200 Subject: [PATCH 089/115] cleaning up serializers --- pkdb_app/data_management/fill_database.py | 4 +- pkdb_app/interventions/serializers.py | 72 ++++++++++++----------- pkdb_app/serializers.py | 60 +++++++++++-------- 3 files changed, 77 insertions(+), 59 deletions(-) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index f2d852b0..ba980b40 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -245,7 +245,9 @@ def check_json_response(response): logging.warning(f'\n{msg}') except json.decoder.JSONDecodeError as err: - logging.warning(err) + # something went wrong on the django serializer side + logging.error(err) + logging.warning(response.text) return False return True diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 56c17ff5..c0f749c7 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -1,3 +1,6 @@ +""" +Serializers for interventions. +""" from django.contrib.sites.shortcuts import get_current_site from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db.models import Q @@ -10,10 +13,8 @@ from pkdb_app.utils import un_map, validate_input - - class SubstanceSerializer(serializers.ModelSerializer): - + """ Substance. """ class Meta: model = Substance fields = ["name"] @@ -24,11 +25,12 @@ def create(self, validated_data): class InterventionSerializer(ParserSerializer): + """ Intervention.""" substance = serializers.SlugRelatedField(slug_field="name",queryset=Substance.objects.all(),read_only=False, required=False, allow_null=True) class Meta: model = Intervention - fields = ["category","name","route","form","application","time","time_unit","value","unit","substance"] + fields = ["category", "name", "route", "form", "application", "time", "time_unit", "value", "unit", "substance"] def to_internal_value(self, data): data = self.split_to_map(data) @@ -36,22 +38,23 @@ def to_internal_value(self, data): data = self.strip(data) return super().to_internal_value(data) - def validate(self,data): + def validate(self, data): validated_data = super().validate(data) - return validate_input(validated_data,"intervention") + return validate_input(validated_data, "intervention") def to_representation(self, instance): - rep = super().to_representation(instance) + rep = super().to_representation(instance) return un_map(rep) class InterventionSetSerializer(ParserSerializer): + """ InterventionSet. """ + interventions = InterventionSerializer(many=True, read_only=False, required=False, allow_null=True) + descriptions = DescriptionsSerializer(many=True, read_only=False, required=False, allow_null=True) - interventions = InterventionSerializer(many=True , read_only=False,required=False, allow_null=True) - descriptions = DescriptionsSerializer(many=True,read_only=False,required=False, allow_null=True ) class Meta: model = InterventionSet - fields = ["descriptions","interventions"] + fields = ["descriptions", "interventions"] def to_internal_value(self, data): """ @@ -59,33 +62,38 @@ def to_internal_value(self, data): :param data: :return: """ - data = self.generic_parser(data,"interventions") + data = self.generic_parser(data, "interventions") return super(InterventionSetSerializer, self).to_internal_value(data) class OutputSerializer(ParserSerializer): - group = serializers.PrimaryKeyRelatedField(queryset=Group.objects.all(), read_only=False,required=False, allow_null=True) - individual = serializers.PrimaryKeyRelatedField(queryset=Individual.objects.all(), read_only=False, required=False, allow_null=True) - interventions = serializers.PrimaryKeyRelatedField(queryset=Intervention.objects.all(),many=True, read_only=False,required=False, allow_null=True) - substance = serializers.SlugRelatedField(slug_field="name",queryset=Substance.objects.all(),read_only=False,required=False, allow_null=True) + """ + Output + """ + group = serializers.PrimaryKeyRelatedField(queryset=Group.objects.all(), + read_only=False, required=False, allow_null=True) + individual = serializers.PrimaryKeyRelatedField(queryset=Individual.objects.all(), + read_only=False, required=False, allow_null=True) + interventions = serializers.PrimaryKeyRelatedField(queryset=Intervention.objects.all(), many=True, + read_only=False, required=False, allow_null=True) + substance = serializers.SlugRelatedField(slug_field="name", queryset=Substance.objects.all(), + read_only=False, required=False, allow_null=True) source = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True) figure = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True) class Meta: model = Output - fields = ["source","figure","format"] + \ - ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit", ] \ - +["value_map", "mean_map", "median_map", "min_map", "max_map","sd_map", "se_map", "cv_map", "unit_map" ]\ - + ["pktype", "pktype_map", "time", "time_unit", - "time_unit_map", - "time_map","group","group_map", "individual", "individual_map", "interventions", "interventions_map", - "substance","substance_map","tissue", "tissue_map","subset_map"] + fields = ["source", "figure", "format"] + \ + ["value", "mean", "median", "min", "max", "sd", "se", "cv", "unit"] + \ + ["value_map", "mean_map", "median_map", "min_map", "max_map", "sd_map", "se_map", "cv_map", "unit_map"] + \ + ["pktype", "pktype_map", "time", "time_unit", "time_unit_map", + "time_map", "group", "group_map", "individual", "individual_map", "interventions", "interventions_map", + "substance", "substance_map", "tissue", "tissue_map", "subset_map"] def to_internal_value(self, data): study_sid = self.context['request'].path.split("/")[-2] data = self.split_to_map(data) - if "group" in data : if data["group"]: try: @@ -93,6 +101,7 @@ def to_internal_value(self, data): except ObjectDoesNotExist: msg = f'group: {data.get("group")} in study: {study_sid} does not exist' raise ValidationError(msg) + if "individual" in data: if data["individual"]: try: @@ -100,6 +109,7 @@ def to_internal_value(self, data): except ObjectDoesNotExist: msg = f'individual: {data.get("individual")} in study: {study_sid} does not exist' raise ValidationError(msg) + if "interventions" in data: if data["interventions"]: interventions = [] @@ -111,7 +121,6 @@ def to_internal_value(self, data): raise ValidationError(msg) data["interventions"] = interventions - data = self.strip(data) data = self.drop_blank(data) data = self.drop_empty(data) @@ -119,7 +128,7 @@ def to_internal_value(self, data): return super().to_internal_value(data) def to_representation(self, instance): - rep = super().to_representation(instance) + rep = super().to_representation(instance) if "group" in rep: rep["group"] = instance.group.name if "interventions" in rep: @@ -127,13 +136,13 @@ def to_representation(self, instance): for file in ["source", "figure"]: if file in rep: current_site = f'http://{get_current_site(self.context["request"]).domain}' - rep[file] = current_site+ getattr(instance,file).file.url + rep[file] = current_site + getattr(instance, file).file.url return un_map(rep) class TimecourseSerializer(OutputSerializer): - + """ Timecourse. """ class Meta: model = Timecourse fields = ["source", "figure", "format"] + \ @@ -147,9 +156,10 @@ class Meta: "substance", "substance_map", "tissue", "tissue_map"] - - class OutputSetSerializer(ParserSerializer): + """ + Outputset + """ outputs = OutputSerializer(many=True, read_only=False, required=False, allow_null=True) timecourse = TimecourseSerializer(many=True, read_only=False, required=False, allow_null=True) descriptions = DescriptionsSerializer(many=True,read_only=False,required=False, allow_null=True ) @@ -167,7 +177,3 @@ def to_internal_value(self, data): data = self.split_to_map(data) return super().to_internal_value(data) - - - - diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 0d53f7a8..c57a70bf 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -14,26 +14,33 @@ from pkdb_app.users.models import User from pkdb_app.utils import get_or_val_error +ITEM_SEPARATOR = '||' +RELATED_SETS = { + "groupset": GroupSet, + "individualset": IndividualSet, + "interventionset": InterventionSet, + "outputset": OutputSet +} -RELATED_SETS = {"groupset":GroupSet ,"individualset": IndividualSet,"interventionset":InterventionSet,"outputset":OutputSet} class WrongKeySerializer(serializers.ModelSerializer): - def validate_wrong_keys(self,data): + def validate_wrong_keys(self, data): serializer_fields = self.Meta.fields payload_keys = data.keys() for payload_key in payload_keys: if payload_key not in serializer_fields: - msg = {payload_key:f"<{payload_key}> is a wrong key"} + msg = {payload_key: f"<{payload_key}> is a wrong key"} raise ValidationError(msg) def to_internal_value(self, data): self.validate_wrong_keys(data) return super().to_internal_value(data) + class BaseSerializer(WrongKeySerializer): """ - This Serializer is overwriting a the is_valid method. If sid allready exisits. It adds a instance to the class. + This Serializer is overwriting a the is_valid method. If sid already exists. It adds a instance to the class. This triggers the update method instead of the create method of the serializer. """ @@ -59,17 +66,13 @@ def is_valid(self, raise_exception=False): return super().is_valid(raise_exception) - - - - @staticmethod def create_relations(study, related): - for name,model in RELATED_SETS.items(): + for name, model in RELATED_SETS.items(): if related[name] is not None: instance = model.objects.create(**related[name]) instance.save() - setattr(study,name,instance) + setattr(study, name, instance) for curator_data in related["curators"]: curator = get_or_val_error(User, username=curator_data) @@ -80,7 +83,7 @@ def create_relations(study, related): substance = get_or_val_error(Substance, name=substance_data) study.substances.add(substance) - if related["files"] : + if related["files"]: print(related["files"]) study.files.all().delete() for file_pk in related["files"]: @@ -104,15 +107,19 @@ def pop_relations(validated_data): class ParserSerializer(WrongKeySerializer): + @staticmethod - def generic_parser(data,key): + def generic_parser(data, key): - raw = data.get(key,[]) + # FIXME: This is overkill and looks very complicated! + # TODO: code review def number_raw(data): + """ Splits the data to get number of entries. """ + for key, value in data.items(): try: - values = value.split('||') + values = value.split(ITEM_SEPARATOR) except AttributeError: values = [value] @@ -120,7 +127,8 @@ def number_raw(data): return len(values) return 1 - def split_string_count(string,key): + + def split_string_count(string, key): l = Lark('''start: WORD "{{" NUMBER "}}" %import common.NUMBER @@ -135,16 +143,21 @@ def split_string_count(string,key): # msg = f"{string} is not maching pattern:\{{(.?[0-9]+)\}}" # raise ValidationError(str(e)) except UnexpectedCharacters: - raise ValidationError({key:f"UnexpectedCharacters in {string}"}) + raise ValidationError({key: f"UnexpectedCharacters in {string}"}) return data def list_chara(data): + """ Splits data items based on item separator. + + :param data: + :return: + """ n = number_raw(data) data_n = {} for key, value in data.items(): try: - values = value.split('||') + values = value.split(ITEM_SEPARATOR) values = list(map(str.strip, values)) except AttributeError: @@ -179,6 +192,7 @@ def list_chara(data): return data_n + raw = data.get(key, []) cleaned = [] for raw_single in raw: raw_single = {k: v for k, v in raw_single.items() if v is not None} @@ -188,9 +202,8 @@ def list_chara(data): return data - @staticmethod - def mapping_parser(mapping,table): + def mapping_parser(mapping, table): resulting_keys = [] for key, value in mapping.items(): @@ -200,7 +213,6 @@ def mapping_parser(mapping,table): raise Exception(f"Value provided does not match pattern 'col==', with key:{key} and value:{values}") resulting_keys.append(values[1].strip()) - else: table[key] = value resulting_keys.append(key) @@ -212,14 +224,14 @@ def mapping_parser(mapping,table): @staticmethod def split_to_map(data): splitted_data = {} - for key,value in data.items(): + for key, value in data.items(): try: if "==" in value: splitted_data[f"{key}_map"] = data.get(key) else: splitted_data[key] = data.get(key) - except : - splitted_data[key] = data.get(key) + except: + splitted_data[key] = data.get(key) return splitted_data @@ -252,5 +264,3 @@ def strip(data): def to_representation(self, instance): result = super().to_representation(instance) return OrderedDict([(key, result[key]) for key in result if result[key] is not None]) - - From d1499b4fbaa1eb10d51968805727246c20603937 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Sun, 19 Aug 2018 19:39:31 +0200 Subject: [PATCH 090/115] ValidationError for failed splitting of data --- pkdb_app/serializers.py | 30 ++++++++++++++++++------------ pkdb_app/urls.py | 23 +++++++++++------------ 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index c57a70bf..fd011149 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -2,7 +2,6 @@ from lark import UnexpectedCharacters, Lark from rest_framework import serializers -from rest_framework.exceptions import ValidationError from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from collections import OrderedDict import pandas as pd @@ -14,6 +13,9 @@ from pkdb_app.users.models import User from pkdb_app.utils import get_or_val_error +import traceback +import logging + ITEM_SEPARATOR = '||' RELATED_SETS = { "groupset": GroupSet, @@ -31,7 +33,7 @@ def validate_wrong_keys(self, data): for payload_key in payload_keys: if payload_key not in serializer_fields: msg = {payload_key: f"<{payload_key}> is a wrong key"} - raise ValidationError(msg) + raise serializers.ValidationError(msg) def to_internal_value(self, data): self.validate_wrong_keys(data) @@ -50,7 +52,7 @@ def is_valid(self, raise_exception=False): sid = self.initial_data.get("sid") try: # Try to get the object in question - obj = self.Meta.model.objects.get(sid = sid) + obj = self.Meta.model.objects.get(sid=sid) except (ObjectDoesNotExist, MultipleObjectsReturned): # Except not finding the object or the data being ambiguous # for defining it. Then validate the data as usual @@ -65,7 +67,6 @@ def is_valid(self, raise_exception=False): # data={something} proceed as usual return super().is_valid(raise_exception) - @staticmethod def create_relations(study, related): for name, model in RELATED_SETS.items(): @@ -107,7 +108,6 @@ def pop_relations(validated_data): class ParserSerializer(WrongKeySerializer): - @staticmethod def generic_parser(data, key): @@ -127,9 +127,7 @@ def number_raw(data): return len(values) return 1 - def split_string_count(string, key): - l = Lark('''start: WORD "{{" NUMBER "}}" %import common.NUMBER %import common.WORD @@ -143,7 +141,7 @@ def split_string_count(string, key): # msg = f"{string} is not maching pattern:\{{(.?[0-9]+)\}}" # raise ValidationError(str(e)) except UnexpectedCharacters: - raise ValidationError({key: f"UnexpectedCharacters in {string}"}) + raise serializers.ValidationError({key: f"UnexpectedCharacters in {string}"}) return data def list_chara(data): @@ -196,7 +194,15 @@ def list_chara(data): cleaned = [] for raw_single in raw: raw_single = {k: v for k, v in raw_single.items() if v is not None} - cleaned += pd.DataFrame(list_chara(raw_single)).to_dict('records') + + try: + cleaned += pd.DataFrame(list_chara(raw_single)).to_dict('records') + except ValueError as err: + print(err) + raise serializers.ValidationError([ + f"ValueError in splitting entries", + raw_single, + traceback.format_exc()]) from err data[key] = cleaned @@ -210,7 +216,7 @@ def mapping_parser(mapping, table): if "==" in value: values = value.split("==") if not values[0].strip() == "col": - raise Exception(f"Value provided does not match pattern 'col==', with key:{key} and value:{values}") + raise serializers.ValidationError(f"Value provided does not match pattern 'col==', with key:{key} and value:{values}") resulting_keys.append(values[1].strip()) else: @@ -242,8 +248,8 @@ def drop_blank(data): @staticmethod def drop_empty(data): dropped_empty = {} - for k,v in data.items(): - if isinstance(v,str): + for k, v in data.items(): + if isinstance(v, str): if not v: continue dropped_empty[k] = v diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index fedf614a..a80e636f 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -1,3 +1,6 @@ +""" +Django URLs +""" from django.conf import settings from django.urls import path, include from django.conf.urls import url @@ -23,36 +26,32 @@ router.register('datafiles', DataFileViewSet, base_name="datafiles") # views in studies -router.register('authors',AuthorsViewSet,base_name="authors") +router.register('authors', AuthorsViewSet, base_name="authors") router.register('references', ReferencesViewSet, base_name="references") -router.register('studies',StudyViewSet, base_name="studies") +router.register('studies', StudyViewSet, base_name="studies") -#router.register('groups', GroupsViewSet, base_name="groups") -#router.register('characteristic_values', CharacteristicValuesViewSet, base_name="characteristic_values") - -#router.register('intervention',InterventionsViewSet,base_name="intervention") +# router.register('groups', GroupsViewSet, base_name="groups") +# router.register('characteristic_values', CharacteristicValuesViewSet, base_name="characteristic_values") +# router.register('intervention',InterventionsViewSet,base_name="intervention") schema_view = get_swagger_view(title='PKDB API') - - - urlpatterns = [ path('admin/', admin.site.urls), url(r'^$', schema_view), path('api/v1/', include(router.urls)), - #path('api-token-auth/', views.obtain_auth_token), + # path('api-token-auth/', views.obtain_auth_token), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), # the 'api-root' from django rest-frameworks default router # http://www.django-rest-framework.org/api-guide/routers/#defaultrouter #re_path(r'^$', RedirectView.as_view(url=reverse_lazy('api-root'), permanent=False)), - ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) +] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) if settings.DEBUG: import debug_toolbar urlpatterns = [ url(r'^__debug__/', include(debug_toolbar.urls)), - ] + urlpatterns \ No newline at end of file + ] + urlpatterns From fa215537fa6d5caa915fb70424c587be665a3cb7 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Sun, 19 Aug 2018 19:52:11 +0200 Subject: [PATCH 091/115] units updated --- pkdb_app/categoricals.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index aed1995c..dde92dd1 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -58,22 +58,29 @@ def create_choices(list): UnitType('g/dl'), UnitType('l/kg'), UnitType("ml/min/kg"), - UnitType("µg/ml*h"), + UnitType("µg/ml"), UnitType("µg/ml"), UnitType("mg"), UnitType("mmHg"), UnitType("ml/min/1.73m^2"), + UnitType("µg/ml*h/kg"), + + # AUC UnitType("mg*h/l"), + UnitType("µg*h/ml"), # -> mg*h/l + UnitType("mg*min/l"), # -> mg*h/l + UnitType("µmol*h/l"), + UnitType("l/h"), UnitType("l"), - UnitType("µmol/l*h"), + UnitType("ml/min"), - UnitType("mg/l*min"), + UnitType("ml/h/kg"), UnitType("mg/l"), - UnitType("mg/l*h"), + UnitType("mg/kg"), UnitType("mg/day") ] From 0b6ffad23bac1fda464fdc8b1680451f40013bfe Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 20 Aug 2018 09:05:32 +0200 Subject: [PATCH 092/115] cleanup code --- pkdb_app/behaviours.py | 56 +++++++++++++++++-------------------- pkdb_app/categoricals.py | 2 +- pkdb_app/subjects/models.py | 41 +++++++++++++-------------- 3 files changed, 47 insertions(+), 52 deletions(-) diff --git a/pkdb_app/behaviours.py b/pkdb_app/behaviours.py index a4d083de..2b2cbb1b 100644 --- a/pkdb_app/behaviours.py +++ b/pkdb_app/behaviours.py @@ -9,7 +9,6 @@ from .categoricals import UNITS_CHOICES - class Sidable(models.Model): """ Model has an sid. """ sid = models.CharField(max_length=CHAR_MAX_LENGTH, primary_key=True) @@ -32,9 +31,6 @@ class Meta: ''' - - - class Blankable(models.Model): # when creating the BlankAble class object it will add a __blank_together__ # attribute corresponding to the same in {YourModel}.MyMeta.blank_together @@ -70,7 +66,7 @@ class Meta: class Hashable(models.Model): """ Add hash key field. """ - hash = models.CharField(max_length=CHAR_MAX_LENGTH,blank=True, null=True) + hash = models.CharField(max_length=CHAR_MAX_LENGTH, blank=True, null=True) class Meta: abstract = True @@ -86,24 +82,23 @@ class Meta: @staticmethod def fields(): - return ["source","figure","format"] + return ["source", "figure", "format"] + class Valueable(models.Model): - """ Add fields to store values. + """ Valuable. - In addition all the statistical values are stored. + Adds fields to store values with their statistics. """ count = models.IntegerField(null=True, blank=True) # how many participants in characteristics - value = models.FloatField( null=True, blank=True) - mean = models.FloatField( null=True, blank=True) - median = models.FloatField( null=True, blank=True) - min = models.FloatField( null=True, blank=True) - max = models.FloatField( null=True, blank=True) - sd = models.FloatField( null=True, blank=True) - se = models.FloatField( null=True, blank=True) - cv = models.FloatField( null=True, blank=True) - - + value = models.FloatField(null=True, blank=True) + mean = models.FloatField(null=True, blank=True) + median = models.FloatField(null=True, blank=True) + min = models.FloatField(null=True, blank=True) + max = models.FloatField(null=True, blank=True) + sd = models.FloatField(null=True, blank=True) + se = models.FloatField(null=True, blank=True) + cv = models.FloatField(null=True, blank=True) unit = models.CharField(choices=UNITS_CHOICES, max_length=CHAR_MAX_LENGTH, null=True, blank=True) class Meta: @@ -115,18 +110,19 @@ class Meta: class ValueableMap(models.Model): - count_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) # how many participants in characteristics - value_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - - mean_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - median_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - min_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - max_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - sd_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - se_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - cv_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - - unit_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + """ ValuableMap. """ + count_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) # how many participants in characteristics + value_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + + mean_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + median_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + min_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + max_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + sd_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + se_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + cv_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + + unit_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) class Meta: abstract = True diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index dde92dd1..3dc857d1 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -265,7 +265,7 @@ def create_choices(list): CharacteristicType('oral contraceptives', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), # CharacteristicType('oral contraceptives amount', MEDICATION, NUMERIC_TYPE, None, ["-"]), - CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA+["alcohol", "grapefruit juice"], + CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA+["alcohol", "smoking", "grapefruit juice"], ["year", "week", "day"]), # -------------- Caffeine -------------- diff --git a/pkdb_app/subjects/models.py b/pkdb_app/subjects/models.py index 89993031..191c4a8d 100644 --- a/pkdb_app/subjects/models.py +++ b/pkdb_app/subjects/models.py @@ -54,16 +54,18 @@ class GroupSet(Set): class Group(models.Model): - """ Individual or group of people. + """ Group of people. - Groups are defined via their characteristics. + Groups are defined via their characteristica. + A group can be a subgroup of another group via the parent field. + All characteristica of the parent group are also in the child group. """ - groupset = models.ForeignKey(GroupSet,on_delete=models.SET_NULL,null=True,related_name="groups") + groupset = models.ForeignKey(GroupSet, on_delete=models.SET_NULL, null=True, related_name="groups") name = models.CharField(max_length=CHAR_MAX_LENGTH) count = models.IntegerField() # number of people/animals/objects in group - parent = models.ForeignKey("Group",null=True,blank=True,on_delete=models.CASCADE) - objects = GroupManager() + parent = models.ForeignKey("Group", null=True, blank=True, on_delete=models.CASCADE) + objects = GroupManager() @property def reference(self): @@ -82,30 +84,27 @@ class IndividualSet(Set): class IndividualMap(models.Model): - group_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - name_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + group_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + name_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) class Meta: abstract = True -class Individual(IndividualMap,Sourceable,models.Model): - """ Individual or group of people. +class Individual(IndividualMap, Sourceable, models.Model): + """ Individual. - Individuals are defined via their characteristics. + Individuals are defined via their characteristics, analogue to groups. """ source = models.ForeignKey(DataFile,related_name="individual_sources", null=True,blank=True, on_delete=models.SET_NULL) figure = models.ForeignKey(DataFile, related_name="individual_figures", null=True,blank=True, on_delete=models.SET_NULL) - individualset = models.ForeignKey(IndividualSet,on_delete=models.CASCADE, related_name="individuals") - group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name="individuals",null=True, blank=True) - name = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - ############### + individualset = models.ForeignKey(IndividualSet, on_delete=models.CASCADE, related_name="individuals") + group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name="individuals", null=True, blank=True) + name = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) objects = IndividualManager() - - @property def reference(self): return self.individualset.reference @@ -118,7 +117,7 @@ def groups_in_study(self): return self.study.groupset.groups class Meta: - unique_together = ('individualset','name','name_map','source') + unique_together = ('individualset', 'name', 'name_map', 'source') def __str__(self): return self.name @@ -130,11 +129,11 @@ class CharacteristicaBase(models.Model): choice = models.CharField(max_length=CHAR_MAX_LENGTH * 3, null=True, blank=True) # check in validation that allowed choice ctype = models.CharField(choices=CHARACTERISTICA_CHOICES, max_length=CHAR_MAX_LENGTH, - default=GROUP_CRITERIA) # this is for exclusion and inclustion + default=GROUP_CRITERIA) # this is for exclusion and inclusion - category_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - choice_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) - ctype_map = models.CharField(max_length=CHAR_MAX_LENGTH,null=True, blank=True) + category_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + choice_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) + ctype_map = models.CharField(max_length=CHAR_MAX_LENGTH, null=True, blank=True) class Meta: abstract = True From 05093048f4b43c6619f7d7546060952687008410 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 20 Aug 2018 09:54:54 +0200 Subject: [PATCH 093/115] categorials updated --- pkdb_app/categoricals.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 3dc857d1..f59d7528 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -52,7 +52,6 @@ def create_choices(list): UnitType('kg/m^2'), - UnitType('IU/I'), UnitType('mg/dl'), UnitType('g/dl'), @@ -75,12 +74,14 @@ def create_choices(list): UnitType("l/h"), UnitType("l"), + UnitType('l/kg'), + UnitType('ml/kg'), + # clearance UnitType("ml/min"), - UnitType("ml/h/kg"), - UnitType("mg/l"), + UnitType("mg/l"), UnitType("mg/kg"), UnitType("mg/day") ] @@ -266,7 +267,7 @@ def create_choices(list): # CharacteristicType('oral contraceptives amount', MEDICATION, NUMERIC_TYPE, None, ["-"]), CharacteristicType('abstinence', 'study protocol', CATEGORIAL_TYPE, SUBSTANCES_DATA+["alcohol", "smoking", "grapefruit juice"], - ["year", "week", "day"]), + ["year", "week", "day", "h"]), # -------------- Caffeine -------------- CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), @@ -326,7 +327,7 @@ def create_choices(list): # class, value, dtype (numeric, boolean, categorial), choices INTERVENTION_DATA = [ - CharacteristicType('dosing', 'dosing', NUMERIC_TYPE, None, ["mg","mg/kg"]), + CharacteristicType('dosing', 'dosing', NUMERIC_TYPE, None, ["mg", "mg/kg"]), CharacteristicType('smoking cessation', 'lifestyle', NUMERIC_TYPE, None, ["-"]), CharacteristicType('female cycle', 'cycle', STRING_TYPE, None, ["-"]), ] From 349a99c569b1479e8f8c974a18fd1cc5cafadd8e Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 20 Aug 2018 10:19:45 +0200 Subject: [PATCH 094/115] Fix #11, missing substances added --- pkdb_app/categoricals.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index f59d7528..83574b6e 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -40,6 +40,7 @@ def create_choices(list): UNIT_DATA = UNIT_TIME + [ UnitType('-'), + UnitType('%'), # dimensionless * 100 UnitType('cm'), UnitType('m'), UnitType('kg'), @@ -223,6 +224,15 @@ def create_choices(list): "ethanol", "chlorozoxazone", "lomefloxacin", + + "aminopyrine", + "antipyrine", + "bromsulpthalein", + "midazolam", + "phenylalanine", + "omeprazole", + "indocyanine green", + "morphine", ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] @@ -236,6 +246,8 @@ def create_choices(list): CharacteristicType('weight', ANTHROPOMETRY, NUMERIC_TYPE, None, ["kg"]), CharacteristicType('bmi', ANTHROPOMETRY, NUMERIC_TYPE, None, ["kg/m^2"]), CharacteristicType('waist circumference', ANTHROPOMETRY, NUMERIC_TYPE, None, ["cm"]), + CharacteristicType('lean body mass', ANTHROPOMETRY, NUMERIC_TYPE, None, ["kg"]), + CharacteristicType('percent fat', ANTHROPOMETRY, NUMERIC_TYPE, None, ["%"]), # -------------- Demography -------------- CharacteristicType('age', DEMOGRAPHICS, NUMERIC_TYPE, None, ["yr"]), From a1431b22ef21a800c94de713b95dceb50bd843b1 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 20 Aug 2018 10:47:30 +0200 Subject: [PATCH 095/115] debuging --- pkdb_app/data_management/fill_database.py | 9 ++++++++- pkdb_app/interventions/managers.py | 2 +- pkdb_app/interventions/models.py | 2 +- pkdb_app/interventions/serializers.py | 11 +++++++---- pkdb_app/serializers.py | 7 ++++--- pkdb_app/subjects/serializers.py | 12 +++++++++++- 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index ba980b40..138c52e7 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -306,7 +306,6 @@ def upload_study_json(json_study_dict): # --------------------------- study_sets = {} study_sets["groupset"] = json_study.get("groupset") - study_sets["individualset"] = json_study.get("individualset") study_sets["interventionset"] = json_study.get("interventionset") # FIXME: Where are groupset, individualset and interventionset uploaded? @@ -316,6 +315,14 @@ def upload_study_json(json_study_dict): response = requests.patch(f'{API_URL}/studies/{sid}/', json=study_sets) success = success and check_json_response(response) + # is using group, has to be uploaded separately from the groupset + if "individualset" in json_study.keys(): + response = requests.patch(f'{API_URL}/studies/{sid}/', + json = {"individualset": json_study.get("individualset")}) + + success = success and check_json_response(response) + + if "outputset" in json_study.keys(): response = requests.patch(f'{API_URL}/studies/{sid}/', json={"outputset": json_study.get("outputset")}) diff --git a/pkdb_app/interventions/managers.py b/pkdb_app/interventions/managers.py index 0754d7b9..58c8d2b5 100644 --- a/pkdb_app/interventions/managers.py +++ b/pkdb_app/interventions/managers.py @@ -29,7 +29,7 @@ class OutputSetManager(models.Manager): def create(self, *args, **kwargs): outputs = kwargs.pop("outputs", []) - timecourses = kwargs.pop("timecourse", []) + timecourses = kwargs.pop("timecourses", []) descriptions = kwargs.pop("descriptions", []) outputset = super().create(*args, **kwargs) outputset.outputs.all().delete() diff --git a/pkdb_app/interventions/models.py b/pkdb_app/interventions/models.py index feed05c1..4c22a398 100644 --- a/pkdb_app/interventions/models.py +++ b/pkdb_app/interventions/models.py @@ -168,7 +168,7 @@ class Timecourse(OutputMap,Sourceable,ValueableMap,Valueable,BaseOutputMap,BaseO source = models.ForeignKey(DataFile, related_name="timecourse_sources",null=True,blank=True,on_delete=models.SET_NULL) figure = models.ForeignKey(DataFile, related_name="timecourse_figures",null=True,blank=True, on_delete=models.SET_NULL) - outputset = models.ForeignKey(OutputSet, related_name="timecourse", on_delete=models.CASCADE,null=True, blank=True) + outputset = models.ForeignKey(OutputSet, related_name="timecourses", on_delete=models.CASCADE,null=True, blank=True) pktype = models.CharField(max_length=CHAR_MAX_LENGTH, choices=PK_DATA_CHOICES, null=True, blank=True) time = models.DecimalField(max_digits=40, decimal_places=20, null=True, blank=True) time_unit = models.CharField(max_length=CHAR_MAX_LENGTH,null=True,blank=True, choices=TIME_UNITS_CHOICES) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index c0f749c7..d2a1a4b4 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -124,6 +124,7 @@ def to_internal_value(self, data): data = self.strip(data) data = self.drop_blank(data) data = self.drop_empty(data) + #data = self.split_to_map(data) return super().to_internal_value(data) @@ -161,19 +162,21 @@ class OutputSetSerializer(ParserSerializer): Outputset """ outputs = OutputSerializer(many=True, read_only=False, required=False, allow_null=True) - timecourse = TimecourseSerializer(many=True, read_only=False, required=False, allow_null=True) + timecourses = TimecourseSerializer(many=True, read_only=False, required=False, allow_null=True) descriptions = DescriptionsSerializer(many=True,read_only=False,required=False, allow_null=True ) class Meta: model = OutputSet - fields = ["descriptions","outputs","timecourse"] + fields = ["descriptions","outputs","timecourses"] def to_internal_value(self, data): """ :param data: :return: """ - data = self.generic_parser(data, "outputs") - data = self.split_to_map(data) + #data = self.generic_parser(data, "outputs") + #data = self.generic_parser(data, "timecourses") + + #data = self.split_to_map(data) return super().to_internal_value(data) diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index fd011149..53946012 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -190,6 +190,10 @@ def list_chara(data): return data_n + + + + raw = data.get(key, []) cleaned = [] for raw_single in raw: @@ -198,7 +202,6 @@ def list_chara(data): try: cleaned += pd.DataFrame(list_chara(raw_single)).to_dict('records') except ValueError as err: - print(err) raise serializers.ValidationError([ f"ValueError in splitting entries", raw_single, @@ -223,8 +226,6 @@ def mapping_parser(mapping, table): table[key] = value resulting_keys.append(key) - #resulting_data = table[resulting_keys].to_dict("records") - #return resulting_data return table[resulting_keys] @staticmethod diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 4bf8bed7..eb54a09f 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -1,5 +1,6 @@ from django.contrib.sites.shortcuts import get_current_site -from django.core.exceptions import ValidationError +from django.core.exceptions import ValidationError, ObjectDoesNotExist +from django.db.models import Q from rest_framework import serializers from pkdb_app.behaviours import Sourceable from pkdb_app.comments.serializers import DescriptionsSerializer @@ -88,6 +89,15 @@ def to_internal_value(self, data): self.validate_wrong_keys(data) data = self.generic_parser(data, "characteristica") data = self.split_to_map(data) + study_sid = self.context['request'].path.split("/")[-2] + if "group" in data : + if data["group"]: + try: + data["group"] = Group.objects.get(Q(groupset__study__sid=study_sid) & Q(name=data.get("group"))).pk + except ObjectDoesNotExist: + msg = f'group: {data.get("group")} in study: {study_sid} does not exist' + raise ValidationError(msg) + return super(IndividualSerializer, self).to_internal_value(data) def to_representation(self, instance): From 314cf6199fb69e9aceb1b2d81d4600b01675612b Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 20 Aug 2018 10:48:15 +0200 Subject: [PATCH 096/115] carbamazepine added --- pkdb_app/categoricals.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 83574b6e..1bb8be5c 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -233,6 +233,11 @@ def create_choices(list): "omeprazole", "indocyanine green", "morphine", + + "glycerol", + "FFA", + + "carbamazepine" ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] From 88278791bfb66ac8616ac8257e49b537dcb8ecf3 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 20 Aug 2018 12:16:06 +0200 Subject: [PATCH 097/115] fixing some validation issues --- pkdb_app/interventions/serializers.py | 40 ++++--- pkdb_app/serializers.py | 149 ++++++++++++++------------ pkdb_app/subjects/serializers.py | 32 ++++-- pkdb_app/utils.py | 15 ++- 4 files changed, 142 insertions(+), 94 deletions(-) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index d2a1a4b4..52611d88 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -2,7 +2,7 @@ Serializers for interventions. """ from django.contrib.sites.shortcuts import get_current_site -from django.core.exceptions import ObjectDoesNotExist, ValidationError +from django.core.exceptions import ObjectDoesNotExist from django.db.models import Q from rest_framework import serializers @@ -10,7 +10,7 @@ from pkdb_app.interventions.models import Substance, InterventionSet, Intervention, Output, OutputSet, Timecourse from pkdb_app.serializers import ParserSerializer from pkdb_app.subjects.models import Individual, Group, DataFile -from pkdb_app.utils import un_map, validate_input +from pkdb_app.utils import un_map, validate_categorials class SubstanceSerializer(serializers.ModelSerializer): @@ -40,7 +40,7 @@ def to_internal_value(self, data): def validate(self, data): validated_data = super().validate(data) - return validate_input(validated_data, "intervention") + return validate_categorials(validated_data, "intervention") def to_representation(self, instance): rep = super().to_representation(instance) @@ -62,7 +62,7 @@ def to_internal_value(self, data): :param data: :return: """ - data = self.generic_parser(data, "interventions") + data = self.split_entries_for_key(data, "interventions") return super(InterventionSetSerializer, self).to_internal_value(data) @@ -100,7 +100,7 @@ def to_internal_value(self, data): data["group"] = Group.objects.get(Q(groupset__study__sid=study_sid) & Q(name=data.get("group"))).pk except ObjectDoesNotExist: msg = f'group: {data.get("group")} in study: {study_sid} does not exist' - raise ValidationError(msg) + raise serializers.ValidationError(msg) if "individual" in data: if data["individual"]: @@ -108,7 +108,7 @@ def to_internal_value(self, data): data["individual"] = Individual.objects.get(Q(individualset__study__sid=study_sid) & Q(name=data.get("individual"))).pk except ObjectDoesNotExist: msg = f'individual: {data.get("individual")} in study: {study_sid} does not exist' - raise ValidationError(msg) + raise serializers.ValidationError(msg) if "interventions" in data: if data["interventions"]: @@ -118,13 +118,12 @@ def to_internal_value(self, data): interventions.append(Intervention.objects.get(Q(interventionset__study__sid=study_sid) & Q(name=internvention)).pk) except ObjectDoesNotExist: msg = f'intervention: {internvention} in study: {study_sid} does not exist' - raise ValidationError(msg) + raise serializers.ValidationError(msg) data["interventions"] = interventions data = self.strip(data) data = self.drop_blank(data) data = self.drop_empty(data) - #data = self.split_to_map(data) return super().to_internal_value(data) @@ -141,6 +140,23 @@ def to_representation(self, instance): return un_map(rep) + def validate(self, data): + validated_data = super().validate(data) + + # either group or individual set + if validated_data.get("individual") and validated_data.get("group"): + raise serializers.ValidationError( + ["individual and group cannot be set together on output.", + validated_data + ]) + if not validated_data.get("individual") and not validated_data.get("group"): + raise serializers.ValidationError( + ["either individual or group must be set together on output.", + validated_data + ]) + + return validated_data + class TimecourseSerializer(OutputSerializer): """ Timecourse. """ @@ -159,7 +175,7 @@ class Meta: class OutputSetSerializer(ParserSerializer): """ - Outputset + OutputSet """ outputs = OutputSerializer(many=True, read_only=False, required=False, allow_null=True) timecourses = TimecourseSerializer(many=True, read_only=False, required=False, allow_null=True) @@ -174,9 +190,7 @@ def to_internal_value(self, data): :param data: :return: """ - #data = self.generic_parser(data, "outputs") - #data = self.generic_parser(data, "timecourses") - - #data = self.split_to_map(data) + data = self.split_entries_for_key(data, "outputs") + data = self.split_entries_for_key(data, "timecourses") return super().to_internal_value(data) diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index 53946012..cb3930cd 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -1,10 +1,7 @@ -import re -from lark import UnexpectedCharacters, Lark from rest_framework import serializers from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from collections import OrderedDict -import pandas as pd from rest_framework.settings import api_settings from pkdb_app.interventions.models import Substance, InterventionSet, OutputSet, DataFile @@ -109,104 +106,114 @@ def pop_relations(validated_data): class ParserSerializer(WrongKeySerializer): @staticmethod - def generic_parser(data, key): + def split_entries_for_key(data, key): + """ Splits entries in multiple if separators found. - # FIXME: This is overkill and looks very complicated! - # TODO: code review + Gets the subset of data for the key, splits the entries in multiple + and overwrites the data in the original data dict! - def number_raw(data): + :param data: + :param key: + :return: + """ + + def number_of_entries(entry): """ Splits the data to get number of entries. """ - for key, value in data.items(): + n_values = [] + for field, value in entry.items(): + n = 1 try: values = value.split(ITEM_SEPARATOR) + n = len(values) except AttributeError: - values = [value] + pass - if len(values) > 1: - return len(values) - return 1 + n_values.append(n) - def split_string_count(string, key): - l = Lark('''start: WORD "{{" NUMBER "}}" - %import common.NUMBER - %import common.WORD + # validation (either 1 or max length) + n_set = set(n_values) + if len(n_set) not in [1, 2]: + serializers.ValidationError( + f"Fields have different length, check || separators", + entry, + ) - %ignore " " // Disregard spaces in text - ''') + return max(n_values) - try: - data = l.parse(string) - # except UnexpectedCharacters as e: - # msg = f"{string} is not maching pattern:\{{(.?[0-9]+)\}}" - # raise ValidationError(str(e)) - except UnexpectedCharacters: - raise serializers.ValidationError({key: f"UnexpectedCharacters in {string}"}) - return data - - def list_chara(data): - """ Splits data items based on item separator. - - :param data: - :return: + def split_entry(entry): + """ Splits entry fields based on separator. + + :param entry: + :return: list of entries """ - n = number_raw(data) - data_n = {} - for key, value in data.items(): + n = number_of_entries(entry) + if n == 1: + return [entry] + + # create entries by splitting separators + entries = [dict() for k in range(n)] + + for field in entry.keys(): + value = entry[field] + print(field, value) try: values = value.split(ITEM_SEPARATOR) - values = list(map(str.strip, values)) - except AttributeError: values = [value] - - if (key == "name" and len(values) != n): - msg = {f"names have to be splitted and not left as <{values}>. Otherwise UniqueConstrain is violated."} - raise ValidationError({"name": msg}) - + for k, value in enumerate(values): + if isinstance(value, str): + values[k] = value.strip() + + print(field, values) + + # --- validation --- + # names must be split in a split entry + if field == "name" and len(values) != n: + raise serializers.ValidationError(f"names have to be splitted and not left as <{values}>. Otherwise UniqueConstrain is violated.") + # check for old syntax + for value in values: + if isinstance(value, str): + if "{{" in value or "}}" in value: + raise serializers.ValidationError( + f"Splitting via '{{ }}' syntax not allowed, use '||' in count.") + # ------------------ + + # extend entries if len(values) == 1: values = values * n - else: - values_n = [] - count_n = [] - for value in values: - if "{{" in value: - splitted_data = split_string_count(value,key) - values_n.append(splitted_data.children[0].value) - count_n.append(splitted_data.children[1].value) - else: - values_n.append(value) - count_n.append(data.get("count", None)) - values = values_n - data_n["count"] = count_n - - # if key == "name" and n > 1: - # ialpha = iter(string.ascii_uppercase) - # values = [f"{value}_{next(ialpha)}" for value in values] - - data_n[key] = values + if len(values) is not n: + raise serializers.ValidationError( + ["Values do not have correct length", + field, values, entry] + ) - return data_n + for k in range(n): + entries[k][field] = values[k] + return entries + # get data for key + raw = data.get(key, []) # outputs - - - raw = data.get(key, []) cleaned = [] - for raw_single in raw: - raw_single = {k: v for k, v in raw_single.items() if v is not None} - + for entry in raw: # output + entries = split_entry(entry) + cleaned.extend(entries) + ''' try: - cleaned += pd.DataFrame(list_chara(raw_single)).to_dict('records') - except ValueError as err: + entries = split_entry(entry) + cleaned.extend(entries) + except Exception as err: raise serializers.ValidationError([ f"ValueError in splitting entries", - raw_single, + entry, traceback.format_exc()]) from err + ''' + # overwrite data data[key] = cleaned return data diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index eb54a09f..9da8d0b6 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -4,7 +4,7 @@ from rest_framework import serializers from pkdb_app.behaviours import Sourceable from pkdb_app.comments.serializers import DescriptionsSerializer -from pkdb_app.utils import un_map, validate_input +from pkdb_app.utils import un_map, validate_categorials from .models import Group, GroupSet, Individual, IndividualSet, Characteristica, DataFile from ..serializers import ParserSerializer, WrongKeySerializer @@ -35,12 +35,15 @@ def to_internal_value(self, data): data = self.split_to_map(data) return super().to_internal_value(data) - def validate(self,data): + def validate(self, data): validated_data = super().validate(data) - return validate_input(validated_data,"characteristica") + validated_data = validate_categorials(validated_data, "characteristica") + + return validated_data class GroupSerializer(ParserSerializer): + """ Group.""" characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) parent = serializers.CharField() @@ -49,8 +52,7 @@ class Meta: fields = ["name","parent", "count", "characteristica",] def to_internal_value(self, data): - self.validate_wrong_keys(data) - data = self.generic_parser(data, "characteristica") + data = self.split_entries_for_key(data, "characteristica") return super(GroupSerializer, self).to_internal_value(data) def to_representation(self, instance): @@ -59,6 +61,10 @@ def to_representation(self, instance): rep["parent"] = instance.parent.name return rep + def validate(self, data): + validated_data = super().validate(data) + return validated_data + class GroupSetSerializer(ParserSerializer): #characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False) @@ -74,8 +80,8 @@ def to_internal_value(self, data): return super(GroupSetSerializer, self).to_internal_value(data) - class IndividualSerializer(ParserSerializer): + """ Individual """ characteristica = CharacteristicaSerializer(many=True, read_only=False, required=False, allow_null=True) group =serializers.PrimaryKeyRelatedField(queryset=Group.objects.all(), required=False, allow_null=True) source = serializers.PrimaryKeyRelatedField(queryset=DataFile.objects.all(), required=False, allow_null=True) @@ -87,7 +93,7 @@ class Meta: def to_internal_value(self, data): self.validate_wrong_keys(data) - data = self.generic_parser(data, "characteristica") + data = self.split_entries_for_key(data, "characteristica") data = self.split_to_map(data) study_sid = self.context['request'].path.split("/")[-2] if "group" in data : @@ -111,6 +117,16 @@ def to_representation(self, instance): rep[file] = current_site+ getattr(instance,file).file.url return un_map(rep) + def validate(self, data): + validated_data = super().validate(data) + + # individuals require group + if not validated_data.get("group"): + raise serializers.ValidationError( + ["individuals require group.", + validated_data + ]) + ''' def parse_individuals(self,data): """ @@ -151,7 +167,7 @@ class Meta: def to_internal_value(self, data): self.validate_wrong_keys(data) - data = self.generic_parser(data, "characteristica") + data = self.split_entries_for_key(data, "characteristica") return super(IndividualSetSerializer, self).to_internal_value(data) def to_representation(self, instance): diff --git a/pkdb_app/utils.py b/pkdb_app/utils.py index b0327aed..80c4a12e 100644 --- a/pkdb_app/utils.py +++ b/pkdb_app/utils.py @@ -45,8 +45,19 @@ def get_or_val_error(model, *args, **kwargs): msg = f"{model} instance with args:{args}, kwargs:{kwargs} does not exist" raise ValidationError({model:msg}) -def validate_input(data,model_name): - model_categoricals = {"characteristica":CHARACTERISTIC_DICT,"intervention":INTERVENTION_DICT} + +def validate_categorials(data, model_name): + """ + + :param data: + :param model_name: + :return: + """ + + model_categoricals = { + "characteristica": CHARACTERISTIC_DICT, + "intervention": INTERVENTION_DICT + } category = data.get("category", None) if category: From bd61a8b207cbf63353bca76d3474b5d1965e9374 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 20 Aug 2018 12:34:56 +0200 Subject: [PATCH 098/115] validation errors on groups and individuals --- pkdb_app/interventions/serializers.py | 4 ++-- pkdb_app/subjects/serializers.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 52611d88..f5057d5c 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -144,12 +144,12 @@ def validate(self, data): validated_data = super().validate(data) # either group or individual set - if validated_data.get("individual") and validated_data.get("group"): + if validated_data.get("individual") and (validated_data.get("group") or validated_data.get("group_map")): raise serializers.ValidationError( ["individual and group cannot be set together on output.", validated_data ]) - if not validated_data.get("individual") and not validated_data.get("group"): + if not validated_data.get("individual") and not (validated_data.get("group") or validated_data.get("group_map")): raise serializers.ValidationError( ["either individual or group must be set together on output.", validated_data diff --git a/pkdb_app/subjects/serializers.py b/pkdb_app/subjects/serializers.py index 9da8d0b6..b58a3f25 100644 --- a/pkdb_app/subjects/serializers.py +++ b/pkdb_app/subjects/serializers.py @@ -121,11 +121,12 @@ def validate(self, data): validated_data = super().validate(data) # individuals require group - if not validated_data.get("group"): + if not validated_data.get("group") and not validated_data.get("group_map"): raise serializers.ValidationError( ["individuals require group.", validated_data ]) + return validated_data ''' def parse_individuals(self,data): From 5d987fb0c067435177f9085e1cba375344e32135 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 20 Aug 2018 13:18:52 +0200 Subject: [PATCH 099/115] latest changes --- pkdb_app/interventions/serializers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index f5057d5c..136efd80 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -144,14 +144,14 @@ def validate(self, data): validated_data = super().validate(data) # either group or individual set - if validated_data.get("individual") and (validated_data.get("group") or validated_data.get("group_map")): + if (validated_data.get("individual") and validated_data.get("individual_map")) and (validated_data.get("group") or validated_data.get("group_map")): raise serializers.ValidationError( ["individual and group cannot be set together on output.", validated_data ]) - if not validated_data.get("individual") and not (validated_data.get("group") or validated_data.get("group_map")): + if not (validated_data.get("individual") or validated_data.get("individual_map")) and not (validated_data.get("group") or validated_data.get("group_map")): raise serializers.ValidationError( - ["either individual or group must be set together on output.", + ["either individual or group must be set on output.", validated_data ]) From e78a46cded4a68100f6ccd1fd0954b10a1fbd8a9 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 20 Aug 2018 13:51:23 +0200 Subject: [PATCH 100/115] fixes #23 ,fixes #35 --- pkdb_app/data_management/fill_database.py | 16 ++++++++++++++-- pkdb_app/interventions/managers.py | 2 +- pkdb_app/interventions/serializers.py | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 138c52e7..87a11b80 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -270,8 +270,20 @@ def upload_study_json(json_study_dict): comments = [] for keys, item in recursive_iter(json_study_dict): - if item in file_dict.keys(): - set_keys(json_study_dict, file_dict[item], *keys) + + + + #set_keys(json_study_dict,item.replace(item,file_dict[item]),*keys) + if isinstance(item,str): + for file, file_pk in file_dict.items(): + item = item.replace(file,str(file_pk)) + + + set_keys(json_study_dict, item, *keys) + + + + if "comments" in keys: n_keys = [] for key in keys: diff --git a/pkdb_app/interventions/managers.py b/pkdb_app/interventions/managers.py index 58c8d2b5..13e16e16 100644 --- a/pkdb_app/interventions/managers.py +++ b/pkdb_app/interventions/managers.py @@ -46,7 +46,7 @@ def create(self, *args, **kwargs): for timecourse in timecourses: intervention_ids = timecourse.pop("interventions", []) - timecourse_instance = outputset.timecourse.create(**timecourse) + timecourse_instance = outputset.timecourses.create(**timecourse) timecourse_instance.interventions.add(*intervention_ids) timecourse_instance.save() outputset.save() diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 136efd80..5e72a02a 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -124,6 +124,7 @@ def to_internal_value(self, data): data = self.strip(data) data = self.drop_blank(data) data = self.drop_empty(data) + print(data.get("figure")) return super().to_internal_value(data) From c0598084d753c6be4dc1f81fa65143114b81131e Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 20 Aug 2018 13:57:34 +0200 Subject: [PATCH 101/115] midazolam and digoxin added to substances --- pkdb_app/categoricals.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 1bb8be5c..8de836e6 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -237,7 +237,9 @@ def create_choices(list): "glycerol", "FFA", - "carbamazepine" + "carbamazepine", + "midazolam", + "digoxin" ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] From f5f255c5ba7d247fb3407683ad728f906dcedaca Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 20 Aug 2018 15:23:21 +0200 Subject: [PATCH 102/115] cleaned useless prints --- pkdb_app/config/common.py | 3 ++- pkdb_app/interventions/serializers.py | 1 - pkdb_app/serializers.py | 24 +++++++++++++++++------- pkdb_app/studies/views.py | 1 - 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index f72b69f8..a9556e0e 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -198,7 +198,8 @@ class Common(Configuration): # Custom user app AUTH_USER_MODEL = 'users.User' - + #STRICT_JSON = False + #UNICODE_JSON = True # Django Rest Framework REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', diff --git a/pkdb_app/interventions/serializers.py b/pkdb_app/interventions/serializers.py index 5e72a02a..136efd80 100644 --- a/pkdb_app/interventions/serializers.py +++ b/pkdb_app/interventions/serializers.py @@ -124,7 +124,6 @@ def to_internal_value(self, data): data = self.strip(data) data = self.drop_blank(data) data = self.drop_empty(data) - print(data.get("figure")) return super().to_internal_value(data) diff --git a/pkdb_app/serializers.py b/pkdb_app/serializers.py index cb3930cd..1f0cc096 100644 --- a/pkdb_app/serializers.py +++ b/pkdb_app/serializers.py @@ -1,4 +1,4 @@ - +import numpy as np from rest_framework import serializers from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from collections import OrderedDict @@ -22,8 +22,16 @@ } + class WrongKeySerializer(serializers.ModelSerializer): + + def replace_NA(self,dict): + for key, value in dict.items(): + if isinstance(value,str): + dict[key].replace("NA","nan") + + def validate_wrong_keys(self, data): serializer_fields = self.Meta.fields payload_keys = data.keys() @@ -32,9 +40,14 @@ def validate_wrong_keys(self, data): msg = {payload_key: f"<{payload_key}> is a wrong key"} raise serializers.ValidationError(msg) - def to_internal_value(self, data): - self.validate_wrong_keys(data) - return super().to_internal_value(data) + # def to_internal_value(self, data): + # self.validate_wrong_keys(data) + # return super().to_internal_value(data) + + def validate(self, attrs): + self.validate_wrong_keys(attrs) + return super().validate(attrs) + class BaseSerializer(WrongKeySerializer): @@ -82,7 +95,6 @@ def create_relations(study, related): study.substances.add(substance) if related["files"]: - print(related["files"]) study.files.all().delete() for file_pk in related["files"]: study.files.add(file_pk) @@ -157,7 +169,6 @@ def split_entry(entry): for field in entry.keys(): value = entry[field] - print(field, value) try: values = value.split(ITEM_SEPARATOR) except AttributeError: @@ -166,7 +177,6 @@ def split_entry(entry): if isinstance(value, str): values[k] = value.strip() - print(field, values) # --- validation --- # names must be split in a split entry diff --git a/pkdb_app/studies/views.py b/pkdb_app/studies/views.py index 35a63a46..97c0f4f2 100644 --- a/pkdb_app/studies/views.py +++ b/pkdb_app/studies/views.py @@ -71,7 +71,6 @@ def group_validation(request): groups = set([group.get("name") for group in groups if group.get("name")]) missing_groups = parents - groups if missing_groups: - print(missing_groups) if missing_groups is not None: msg = {"groups": f"<{missing_groups}> have been used but not defined"} raise ValidationError(msg) From cd8e0b7a8ccee7e3702a88147e5ac131e3826581 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 20 Aug 2018 15:58:50 +0200 Subject: [PATCH 103/115] updated to django 2.1. fixes #14 --- pkdb_app/subjects/managers.py | 6 +++++- requirements.txt | 7 +++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pkdb_app/subjects/managers.py b/pkdb_app/subjects/managers.py index 5d79d357..7be9bb05 100644 --- a/pkdb_app/subjects/managers.py +++ b/pkdb_app/subjects/managers.py @@ -61,6 +61,8 @@ def create(self, *args, **kwargs): return individual + + class IndividualSetManager(models.Manager): def create(self, *args, **kwargs): characteristica = kwargs.pop("characteristica", []) @@ -81,6 +83,8 @@ def create(self, *args, **kwargs): for individual in individuals: individualset.individuals.create(**individual) + individualset.save() - return individualset \ No newline at end of file + return individualset + diff --git a/requirements.txt b/requirements.txt index 7490a8a4..336a242f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,8 @@ pip==18.0 # Core pytz==2018.4 -Django==2.0.6 -django-configurations==2.0 +Django==2.1 +django-configurations==2.1 gunicorn==19.8.1 newrelic==3.2.2.94 @@ -18,7 +18,7 @@ django_unique_upload==0.2.1 # Rest apis djangorestframework==3.8.2 Markdown==2.6.11 -django-filter==1.1.0 +django-filter==2.0 coreapi django-rest-swagger django-cors-headers==2.4.0 @@ -50,7 +50,6 @@ pandas jsonschema django-extra-fields PyPDF2 -lark-parser watchdog requests coloredlogs \ No newline at end of file From 04ba4ae1fff43a66073fbc762a7d6f935b8cf6fa Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 20 Aug 2018 18:11:38 +0200 Subject: [PATCH 104/115] categorials updated --- README.md | 3 +-- pkdb_app/categoricals.py | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7ba1fe63..dc608ce3 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,7 @@ docker-compose run --rm web ./manage.py createsuperuser # Update after code change ``` # reset migrations -sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete -sudo rm -r media/study/ +sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete && sudo rm -r media/study/ # rebuild container docker-compose down diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 8de836e6..3697d7d7 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -59,8 +59,10 @@ def create_choices(list): UnitType('l/kg'), UnitType("ml/min/kg"), - UnitType("µg/ml"), UnitType("µg/ml"), + UnitType("µmol/l"), + + UnitType("ng/ml"), UnitType("mg"), UnitType("mmHg"), UnitType("ml/min/1.73m^2"), @@ -192,6 +194,9 @@ def create_choices(list): "1U/(1U+1X)", "AFMU/(AFMU+1U+1X)", + # caffeine interaction + "fluvoxamine", + # quinolones "quinolone", "pipemidic acid", @@ -239,7 +244,17 @@ def create_choices(list): "carbamazepine", "midazolam", - "digoxin" + "1-hydroxymidazolam", + "digoxin", + "losartan", + "exp3174", + # omeprazole + "omeprazole", + "5-hydroxyomeprazole", + + "dextromethorphan", + "dextrorphan", + ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] @@ -291,6 +306,7 @@ def create_choices(list): # -------------- Caffeine -------------- CharacteristicType('caffeine', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), CharacteristicType('caffeine amount', 'lifestyle', NUMERIC_TYPE, None, ["mg/day"]), + CharacteristicType('caffeine amount (beverages)', 'lifestyle', NUMERIC_TYPE, None, ["1/day"]), # -------------- Smoking -------------- CharacteristicType('smoking', 'lifestyle', BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), @@ -311,7 +327,6 @@ def create_choices(list): # --------------Genetic variants -------------- CharacteristicType('genetics', GENETIC_VARIANTS, CATEGORIAL_TYPE, ["CYP2D6 duplication","CYP2D6 wild type", "CYP2D6 poor metabolizer"], ["-"]), - ] PK_DATA = [ From 4997c9bb746ff559ee577205d8111784a932ec20 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Tue, 21 Aug 2018 11:25:49 +0200 Subject: [PATCH 105/115] categorials updated --- pkdb_app/categoricals.py | 67 +++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index 3697d7d7..b35656c8 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -39,54 +39,57 @@ def create_choices(list): TIME_UNITS_CHOICES = [(utype.name, utype.name) for utype in UNIT_TIME] UNIT_DATA = UNIT_TIME + [ + # base units UnitType('-'), UnitType('%'), # dimensionless * 100 UnitType('cm'), UnitType('m'), UnitType('kg'), + UnitType("mg"), + UnitType("mmHg"), + # reverse time units UnitType('1/week'), UnitType('1/day'), UnitType('1/h'), UnitType('1/min'), UnitType('1/s'), + # misc units + UnitType("mg/kg"), + UnitType("mg/day"), UnitType('kg/m^2'), - UnitType('IU/I'), - UnitType('mg/dl'), - UnitType('g/dl'), - UnitType('l/kg'), - UnitType("ml/min/kg"), + UnitType("l/h"), + # concentration UnitType("µg/ml"), - UnitType("µmol/l"), - - UnitType("ng/ml"), - UnitType("mg"), - UnitType("mmHg"), - UnitType("ml/min/1.73m^2"), - - UnitType("µg/ml*h/kg"), + UnitType('mg/dl'), # -> µg/ml + UnitType("mg/l"), # -> µg/ml + UnitType("µmol/l"), # -> µg/ml (with molar weight) + UnitType("nmol/l"), # -> µg/ml (with molar weight) + UnitType('g/dl'), # -> µg/dl + UnitType("ng/ml"), # -> µg/ml # AUC UnitType("mg*h/l"), UnitType("µg*h/ml"), # -> mg*h/l UnitType("mg*min/l"), # -> mg*h/l - UnitType("µmol*h/l"), + UnitType("µmol*h/l"), # -> mg*h/l (with molar weight) + UnitType("µmol/l*h"), # -> mg*h/l (with molar weight) + UnitType("µg/ml*h/kg"), # -> mg*h/l/kg - UnitType("l/h"), + # Volume of distribution (vd) UnitType("l"), UnitType('l/kg'), - UnitType('ml/kg'), + UnitType('ml/kg'), # -> l/kg # clearance UnitType("ml/min"), + UnitType("ml/h"), # -> ml/min UnitType("ml/h/kg"), - - UnitType("mg/l"), - UnitType("mg/kg"), - UnitType("mg/day") + UnitType("ml/min/kg"), # -> ml/h/kg + UnitType("ml/min/1.73m^2"), ] @@ -168,7 +171,7 @@ def create_choices(list): # acetaminophen "acetaminophen", - # caffeine + # caffeine (CYP2A1) "caffeine", "paraxanthine", "theobromine", @@ -193,11 +196,10 @@ def create_choices(list): "17U/17X", "1U/(1U+1X)", "AFMU/(AFMU+1U+1X)", - # caffeine interaction "fluvoxamine", - - # quinolones + "naringenin", + "grapefruit juice", "quinolone", "pipemidic acid", "norfloxacin", @@ -233,9 +235,7 @@ def create_choices(list): "aminopyrine", "antipyrine", "bromsulpthalein", - "midazolam", "phenylalanine", - "omeprazole", "indocyanine green", "morphine", @@ -243,18 +243,27 @@ def create_choices(list): "FFA", "carbamazepine", + + # midazolam "midazolam", "1-hydroxymidazolam", - "digoxin", + + # losartan "losartan", "exp3174", - # omeprazole + + # omeprazole (CYP2C19) "omeprazole", "5-hydroxyomeprazole", + "5-hydroxyomeprazole/omeprazole", + # dextromethorphan "dextromethorphan", "dextrorphan", + "digoxin", + "clozapine", + ] SUBSTANCES_DATA_CHOICES = [(t, t) for t in SUBSTANCES_DATA] @@ -294,7 +303,7 @@ def create_choices(list): # -------------- Medication -------------- CharacteristicType('medication', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), - CharacteristicType('medication type', MEDICATION, CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin"], ["-"]), + CharacteristicType('medication type', MEDICATION, CATEGORIAL_TYPE, ["ibuprofen", "paracetamol", "aspirin", "clozapine"], ["-"]), CharacteristicType('medication amount', MEDICATION, NUMERIC_TYPE, None, ["-"]), CharacteristicType('oral contraceptives', MEDICATION, BOOLEAN_TYPE, BOOLEAN_CHOICES, ["-"]), From 33a9f5c14745e4f2949e818bdf8a6bbb8fa7c0ae Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Tue, 21 Aug 2018 12:49:41 +0200 Subject: [PATCH 106/115] categorials updated --- pkdb_app/categoricals.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index b35656c8..b730f5ee 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -74,6 +74,7 @@ def create_choices(list): # AUC UnitType("mg*h/l"), UnitType("µg*h/ml"), # -> mg*h/l + UnitType("µg/ml*h"), # -> mg*h/l UnitType("mg*min/l"), # -> mg*h/l UnitType("µmol*h/l"), # -> mg*h/l (with molar weight) UnitType("µmol/l*h"), # -> mg*h/l (with molar weight) @@ -219,6 +220,8 @@ def create_choices(list): "tizanidine", "venlafaxine", "lomefloxacin", + "ephedrine", + "pseudoephedrine", "ibuprofen", "aspirin", From 7384836481d95625d2bda84e45b9d992e13aca1d Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Tue, 21 Aug 2018 19:27:19 +0200 Subject: [PATCH 107/115] categorials updated --- pkdb_app/categoricals.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkdb_app/categoricals.py b/pkdb_app/categoricals.py index b730f5ee..87bd60c1 100644 --- a/pkdb_app/categoricals.py +++ b/pkdb_app/categoricals.py @@ -47,6 +47,7 @@ def create_choices(list): UnitType('kg'), UnitType("mg"), UnitType("mmHg"), + UnitType("µmol"), # reverse time units UnitType('1/week'), @@ -87,9 +88,10 @@ def create_choices(list): # clearance UnitType("ml/min"), - UnitType("ml/h"), # -> ml/min - UnitType("ml/h/kg"), - UnitType("ml/min/kg"), # -> ml/h/kg + UnitType("ml/h"), # -> ml/min + UnitType("l/h/kg"), + UnitType("ml/h/kg"), # -> l/h/kg + UnitType("ml/min/kg"), # -> l/h/kg UnitType("ml/min/1.73m^2"), ] @@ -346,6 +348,7 @@ def create_choices(list): "auc_end", # Area under the curve, until end time point (time has to be given as time attribute) "amount", + "cum_amount", # cumulative amount "concentration", "ratio", @@ -377,7 +380,6 @@ def create_choices(list): CharacteristicType('smoking cessation', 'lifestyle', NUMERIC_TYPE, None, ["-"]), CharacteristicType('female cycle', 'cycle', STRING_TYPE, None, ["-"]), ] - def dict_and_choices(data): data_dict = {item.value: item for item in data} data_choices = [(ctype.value, ctype.value) for ctype in data] From b97fcb6874a43c7e5fd3b12e0201da5983ca04b8 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Wed, 22 Aug 2018 15:44:23 +0200 Subject: [PATCH 108/115] working on deployment settings --- docker-compose.yml | 3 ++- CURATION.md => docs/CURATION.md | 0 gunicorn_start.sh | 30 +++++++++++++++++++++++ pkdb_app/config/common.py | 16 +++--------- pkdb_app/config/local.py | 13 +++++++--- pkdb_app/config/production.py | 18 +++++++++++++- pkdb_app/data_management/fill_database.py | 3 ++- remove_migrations.sh | 4 +++ 8 files changed, 68 insertions(+), 19 deletions(-) rename CURATION.md => docs/CURATION.md (100%) create mode 100755 gunicorn_start.sh create mode 100755 remove_migrations.sh diff --git a/docker-compose.yml b/docker-compose.yml index 7ac5164b..c1768e1a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,8 @@ services: web: restart: always environment: - - DJANGO_SECRET_KEY=local + - PKPD_SECRET_KEY="cgasj6yjpkag" + - PKPD_DEFAULT_PASSWORD="pkdb" image: web build: ./ diff --git a/CURATION.md b/docs/CURATION.md similarity index 100% rename from CURATION.md rename to docs/CURATION.md diff --git a/gunicorn_start.sh b/gunicorn_start.sh new file mode 100755 index 00000000..87b482b9 --- /dev/null +++ b/gunicorn_start.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +NAME="pkpd" # Name of the application (*) +DJANGODIR=/var/git/pkpd # Django project directory (*) +SOCKFILE=/var/git/pkpd/run/gunicorn.sock # we will communicate using this unix socket (*) +USER=mkoenig # the user to run as (*) +GROUP=mkoenig # the group to run as (*) +NUM_WORKERS=1 # how many worker processes should Gunicorn spawn (*) +DJANGO_SETTINGS_MODULE=pkpd_app.config.local # which settings file should Django use (*) +DJANGO_WSGI_MODULE=pkpd_app.wsgi # WSGI module name (*) + +echo "Starting $NAME as `whoami`" + +# Activate the virtual environment +cd $DJANGODIR +source /var/www/test/venv/bin/activate +export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE +export PYTHONPATH=$DJANGODIR:$PYTHONPATH + +# Create the run directory if it doesn't exist +RUNDIR=$(dirname $SOCKFILE) +test -d $RUNDIR || mkdir -p $RUNDIR + +# Start your Django Unicorn +# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon) +exec /home/mkoenig/envs/flutype_webapp/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \ + --name $NAME \ + --workers $NUM_WORKERS \ + --user $USER \ + --bind=unix:$SOCKFILE diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index a9556e0e..4a69b944 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -4,11 +4,8 @@ import os from os.path import join from distutils.util import strtobool -import dj_database_url from configurations import Configuration BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -POSTGRES_PORT = 5432 - class Common(Configuration): @@ -35,7 +32,6 @@ class Common(Configuration): 'pkdb_app.subjects', 'pkdb_app.interventions', 'pkdb_app.comments', - ) # https://docs.djangoproject.com/en/2.0/topics/http/middleware/ @@ -52,12 +48,12 @@ class Common(Configuration): ) DEBUG_TOOLBAR_PATCH_SETTINGS = False - CORS_ORIGIN_WHITELIST = ('0.0.0.0:8080','localhost:8080') + CORS_ORIGIN_WHITELIST = ('0.0.0.0:8080', 'localhost:8080') INTERNAL_IPS = ('172.18.0.1',) ALLOWED_HOSTS = ["*"] ROOT_URLCONF = 'pkdb_app.urls' - SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') + SECRET_KEY = os.getenv('PKPD_SECRET_KEY') WSGI_APPLICATION = 'pkdb_app.wsgi.application' # Email @@ -67,13 +63,7 @@ class Common(Configuration): ('Author', 'janekg89@hotmail.de'), ) - # Postgres - DATABASES = { - 'default': dj_database_url.config( - default=f'postgres://postgres:pass@postgres:{POSTGRES_PORT}/postgres', - conn_max_age=int(os.getenv('POSTGRES_CONN_MAX_AGE', 600)) - ) - } + # General APPEND_SLASH = False diff --git a/pkdb_app/config/local.py b/pkdb_app/config/local.py index 6b9b2ac6..4e347014 100755 --- a/pkdb_app/config/local.py +++ b/pkdb_app/config/local.py @@ -4,11 +4,9 @@ import os from .common import Common BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - +import dj_database_url class Local(Common): - - DEBUG = True # Testing @@ -24,6 +22,15 @@ class Local(Common): '--cover-package=pkdb' ] + # Postgres + DATABASES = { + 'default': dj_database_url.config( + # postgres://USER:PASSWORD@HOST:PORT/NAME + default=f'postgres://postgres:pass@postgres:5432/postgres', + conn_max_age=int(os.getenv('POSTGRES_CONN_MAX_AGE', 600)) + ) + } + # Mail EMAIL_HOST = 'localhost' EMAIL_PORT = 1025 diff --git a/pkdb_app/config/production.py b/pkdb_app/config/production.py index 0b1f801d..e6857dea 100755 --- a/pkdb_app/config/production.py +++ b/pkdb_app/config/production.py @@ -6,8 +6,24 @@ class Production(Common): + DEBUG = False + INSTALLED_APPS = Common.INSTALLED_APPS - SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') + SECRET_KEY = os.getenv('PKDB_SECRET_KEY') + POSTGRES_PASSWORD = os.getenv('PKDB_POSTGRES_PASSWORD') + + # Postgres + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'pkpd', + 'USER': 'pkpd_user', + 'HOST': 'localhost', + 'PASSWORD': POSTGRES_PASSWORD, + 'PORT': 5432, + } + } + # Site # https://docs.djangoproject.com/en/2.0/ref/settings/#allowed-hosts ALLOWED_HOSTS = ["*"] diff --git a/pkdb_app/data_management/fill_database.py b/pkdb_app/data_management/fill_database.py index 87a11b80..1b107305 100644 --- a/pkdb_app/data_management/fill_database.py +++ b/pkdb_app/data_management/fill_database.py @@ -52,7 +52,8 @@ # setup database # ----------------------------- API_URL = "http://0.0.0.0:8000/api/v1" -PASSWORD = "test" + +PASSWORD = os.getenv("PKPD_DEFAULT_PASSWORD") USERS = [ {"username": "janekg", "first_name": "Jan", "last_name": "Grzegorzewski", "email": "Janekg89@hotmail.de", "password": PASSWORD}, diff --git a/remove_migrations.sh b/remove_migrations.sh new file mode 100755 index 00000000..8a51d254 --- /dev/null +++ b/remove_migrations.sh @@ -0,0 +1,4 @@ +################################ +# script to remove migrations +################################ +sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete && sudo rm -r media/study/ From 69f43200b8fb7222247e7af44990a19db62d7489 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Wed, 22 Aug 2018 17:49:10 +0200 Subject: [PATCH 109/115] updated remove_migrations --- remove_migrations.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/remove_migrations.sh b/remove_migrations.sh index 8a51d254..6f627cf4 100755 --- a/remove_migrations.sh +++ b/remove_migrations.sh @@ -1,4 +1,6 @@ ################################ # script to remove migrations ################################ -sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete && sudo rm -r media/study/ +sudo find . -path "*/migrations/*.py" -not -name "__init__.py" -delete && sudo find . -path "*/migrations/*.pyc" -delete +sudo rm -r media/study/ +sudo rm -r media/data/ From f8ca5eb135b95256971345bf6af03d2ad29a4070 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 23 Aug 2018 16:58:29 +0200 Subject: [PATCH 110/115] changes for deployment --- create_db.sh | 14 ++++++++ db_backup.sh | 30 ++++++++++++++++ docker-compose.yml | 2 +- manage.py | 3 +- pkdb_app/_version.py | 4 +++ pkdb_app/config/common.py | 9 +++-- pkdb_app/config/local.py | 16 +++++++++ pkdb_app/config/production.py | 7 ++-- pkdb_app/static/pkdb/images/favicon.ico | Bin 0 -> 2966 bytes pkdb_app/static/pkdb/images/swagger.png | Bin 0 -> 9271 bytes pkdb_app/templates/pkdb/about.html | 10 ++++++ pkdb_app/templates/pkdb/base.html | 45 ++++++++++++++++++++++++ pkdb_app/urls.py | 9 +++-- pkdb_app/views.py | 10 +++++- 14 files changed, 148 insertions(+), 11 deletions(-) create mode 100755 create_db.sh create mode 100755 db_backup.sh create mode 100644 pkdb_app/_version.py create mode 100644 pkdb_app/static/pkdb/images/favicon.ico create mode 100644 pkdb_app/static/pkdb/images/swagger.png create mode 100644 pkdb_app/templates/pkdb/about.html create mode 100644 pkdb_app/templates/pkdb/base.html diff --git a/create_db.sh b/create_db.sh new file mode 100755 index 00000000..e60d2c0c --- /dev/null +++ b/create_db.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +######################################################## +# Setup the database +# +# Deletes old database and recreates all data. +######################################################## +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# delete old migrations +./remove_migrations.sh + +# clean setup +python manage.py makemigrations +python manage.py migrate diff --git a/db_backup.sh b/db_backup.sh new file mode 100755 index 00000000..05276d3a --- /dev/null +++ b/db_backup.sh @@ -0,0 +1,30 @@ +################################## +# Backup of FluTypeDB +# +# TODO: compress backup +# TODO: run via cron job +# TODO: differential backup +# TODO: check that backup can be restored +# +# usage: +# ./db_backup.sh +################################## +echo "-------------------------------" +echo "PKDB database backup" +echo "-------------------------------" +cd /var/git/pkdb + +# create directory for backup +DIR=/var/backups/pkdb/$(date '+%F') +sudo mkdir -p $DIR +sudo chown -R mkoenig:mkoenig $DIR +echo "Backup to" $DIR + +# backup media +sudo cp -R /var/git/pkdb/media $DIR + +# backup database +echo "---------------" +echo "Dump database" +echo "---------------" +sudo -u postgres pg_dump pkdb > $DIR/pddb_dump.psql diff --git a/docker-compose.yml b/docker-compose.yml index c1768e1a..89f8e5d4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: web: restart: always environment: - - PKPD_SECRET_KEY="cgasj6yjpkag" + - PKPD_SECRET_KEY="cgasj6yjpkagcgasj6yjpkagcgasj6yjpkag" - PKPD_DEFAULT_PASSWORD="pkdb" image: web diff --git a/manage.py b/manage.py index b61c80fb..b64594a9 100755 --- a/manage.py +++ b/manage.py @@ -4,7 +4,8 @@ if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pkdb_app.config") - os.environ.setdefault("DJANGO_CONFIGURATION", "Local") + PKDB_DJANGO_CONFIGURATION = os.getenv("PKDB_DJANGO_CONFIGURATION", "Local") + os.environ.setdefault("DJANGO_CONFIGURATION", PKDB_DJANGO_CONFIGURATION) try: from configurations.management import execute_from_command_line diff --git a/pkdb_app/_version.py b/pkdb_app/_version.py new file mode 100644 index 00000000..0c49a88b --- /dev/null +++ b/pkdb_app/_version.py @@ -0,0 +1,4 @@ +""" +Definition of version string. +""" +__version__ = "0.1.0" diff --git a/pkdb_app/config/common.py b/pkdb_app/config/common.py index 4a69b944..1387bea6 100755 --- a/pkdb_app/config/common.py +++ b/pkdb_app/config/common.py @@ -6,6 +6,7 @@ from distutils.util import strtobool from configurations import Configuration BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +print("TEMPLATE_DIR", os.path.join(BASE_DIR, 'templates')) class Common(Configuration): @@ -53,7 +54,7 @@ class Common(Configuration): ALLOWED_HOSTS = ["*"] ROOT_URLCONF = 'pkdb_app.urls' - SECRET_KEY = os.getenv('PKPD_SECRET_KEY') + SECRET_KEY = os.getenv('PKDB_SECRET_KEY') WSGI_APPLICATION = 'pkdb_app.wsgi.application' # Email @@ -79,7 +80,9 @@ class Common(Configuration): # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.0/howto/static-files/ STATIC_ROOT = os.path.normpath(join(os.path.dirname(BASE_DIR), 'static')) - STATICFILES_DIRS = [] + STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "static"), + ] STATIC_URL = '/static/' STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', @@ -93,7 +96,7 @@ class Common(Configuration): TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': STATICFILES_DIRS, + 'DIRS': STATICFILES_DIRS + [os.path.join(BASE_DIR, "templates")], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/pkdb_app/config/local.py b/pkdb_app/config/local.py index 4e347014..601dd1b4 100755 --- a/pkdb_app/config/local.py +++ b/pkdb_app/config/local.py @@ -6,6 +6,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) import dj_database_url +POSTGRES_PASSWORD = os.getenv('PKDB_POSTGRES_PASSWORD') + class Local(Common): DEBUG = True @@ -23,6 +25,7 @@ class Local(Common): ] # Postgres + DATABASES = { 'default': dj_database_url.config( # postgres://USER:PASSWORD@HOST:PORT/NAME @@ -30,6 +33,19 @@ class Local(Common): conn_max_age=int(os.getenv('POSTGRES_CONN_MAX_AGE', 600)) ) } + ''' + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'pkdb', + 'USER': 'pkdb_user', + 'HOST': 'localhost', + 'PASSWORD': POSTGRES_PASSWORD, + 'PORT': 5432, + } + } + ''' + # Mail EMAIL_HOST = 'localhost' diff --git a/pkdb_app/config/production.py b/pkdb_app/config/production.py index e6857dea..7fcfd2ae 100755 --- a/pkdb_app/config/production.py +++ b/pkdb_app/config/production.py @@ -9,15 +9,14 @@ class Production(Common): DEBUG = False INSTALLED_APPS = Common.INSTALLED_APPS - SECRET_KEY = os.getenv('PKDB_SECRET_KEY') POSTGRES_PASSWORD = os.getenv('PKDB_POSTGRES_PASSWORD') # Postgres DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'pkpd', - 'USER': 'pkpd_user', + 'NAME': 'pkdb', + 'USER': 'pkdb_user', 'HOST': 'localhost', 'PASSWORD': POSTGRES_PASSWORD, 'PORT': 5432, @@ -29,6 +28,7 @@ class Production(Common): ALLOWED_HOSTS = ["*"] INSTALLED_APPS += ("gunicorn", ) + ''' # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.0/howto/static-files/ # http://django-storages.readthedocs.org/en/latest/index.html @@ -49,3 +49,4 @@ class Production(Common): AWS_HEADERS = { 'Cache-Control': 'max-age=86400, s-maxage=86400, must-revalidate', } + ''' diff --git a/pkdb_app/static/pkdb/images/favicon.ico b/pkdb_app/static/pkdb/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..75bcef67971ac3c9574fa519b45e7c3e56460d95 GIT binary patch literal 2966 zcmcJR2~<;89>!lgJu__)lVDhq5VA-X_T4~KLJ}bCn-CE~5E38>1URfx_mQ4ytzAZ) z>2anVi%Tm^&#A45RJ*9Pa@0;+t5cMzOYumiSRuSDFK^487tY{uW)7!L$9eDk?)|@e z-@V`W?z{KC2SHCzCqD@CrO-A%2%j)Dh39j7tfuJ(J9+5B;foA9sDe z;tnH*sk#;Mk>K(tR@9?#S9nXKk+y<7VFE>@S$H>*3fXIZ~$d9bFmOc3eH+8 z2a!V6pKB`CaeVDGiFu1P|DVf^RqqBBsfKbg!2ZS{LnvvP*#(dO<#%BA8U73?lvMh$`WL?v``E|QBN*BY}_)- zLI}mu3LnHjCuq=*lq==O06+9i4~O*{&I$Pq&I&9?BSf8evgX%_B=RK>KhOl02WSSx zzl5Gl3N%q(ASj+zAK1o)<~>C$E&n;v^KA?@quVpHE`Tu3o*8!Vi(Yo{OMt?|W$*Ly z*aKdE=l~kV+Jo^!`cVE7_4AV8Eq@7p#$XjJF<+GU>pza6D`I>dMKChv`}=Q`_0^;A zWadr)sbti}VeRsUvR)>99>UnaM+MvgOu#)vd3Y1$vR+3svJN8Wpg(k?(xFe#5fsl8Q z8^Ch^vL0D*?2-l1Ncy9#nTGn) z_g1BUi`I8f!JGFWXjRJ`n!R=o&(}H0+$uYnvhoVDoIgm)44lE#sA<#ixiaRkXJA465eb`YO+^i+^^oifVA`TGli~Q)QZXc#ZHxG9Q^i(iySzGB84?`sH$`p*EYdKnE^)C zMK&yP#e{d2;u~rUw<}$97ZdZ(0g2!{3)LS5kvVOKAJ6`SLGFtgEht(Y;6ln)NODe3fA?L%4`PLX=fq z!8Y{Yz!D<&qEW1VR2oowTS`w)`S$_Xykml4FpXbXYqVi`IvC#gs@vPS(~T4xU~gW{ zoQKl(%5rDP=oL0ZD*781MBjuYs$n8UGlNQEZDhRCfhVe_$&AA5&dBKVq(pSuD-nJ~ zW@#>gH{QqagCAmOrS1eG3fe+QXw4vkUbHugQ4r|!LFEttN1^8C3x>LuNsrbt=k9pX z<$hs50_!^+q`bh6C#hyZf^vqG#7+T`_?DX&@-`ugI*&%nrZI8E9T1atkI2ze@2$s0 zWa}s|>ic+H+9WQc=1W!GIB7J0hpnrbbKrQ`ZwL+h<+z4?1!?)?EY^-P1NE*mJVx(#wmZvjog zS0Fw4FvwFM2i3J-f=25&Fj%gE2J3gIxoZ+Ob=$l;<4urTa0RH8mq5Dw98j+M2xt@^ zfZU9uQ-#XGlX><9JA>htE2aFNY};*wx#7uiPbu$w_45^ zElr;`S{qJiYu6s<)K$J0Xwe^fuuqQx0CxP7?Nm-pNC0i6;88q9L0v$Qf`UfzD+dQ@0+Qek%> zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3;umK?W|rT=3Uy#&k#EC=H`y@OhQe-{y?NIpqj z-KR)VNoGd4!)>^O0pZSn{qO7k7r&Y>(dA;T_F6r^a?d>u{?h#C*XL{S`ThU>O7Z)% z@cZ}O&mTm-mGsKbKkNCve(?SB*BdNzzQQ~7&& z|Nq43Z(`?u{`HUG{ruY>vGe2m{q%b%oUh*()IVbM{eCEad_VoXP5f;|;jcUY_Jgv+ z@xT81C3g4jcJKK--N=#tSE*Oz&-#-^QQ9-|hYG{BAtrB4e9uPJS;J zdWb~(h8%Vn;fC|RuCQ2Qjwc#lV_Y%4@3myH$Muqu^*h{Xsi*D8PE3oeCB7Yht|h$t z_IJM(8h74-SH{4_0`K^b-|p|e`Tz6#=Y{T7>4xCj&sedpsH$NZ%AEest4K(=-baRWobWZM4*KE3Gzbt@So~>@fG z_1?$erh`il-aUB57&Fc^^DMJYn{DaIEI0hj-Cvpe*Sxus|DW;} z|0#1$sr#SEoKxz)nfuSY{Y}>Pc#M)>g4BhIsZSSR<3%Gj{sWKy@oVRAygscHyQSP) z*gU!#ysZWUB^UD1Yr~xR@QTTI59n9n(P|xI-9hh_IlT3H>pqm21@c+4U-!gHj$=CmdYNuTNkX%gWLvKq?h=L=TZ{) z)I9shMkXn_ZU@51GurOSZm*R4O(`gFrxz#%+6k9xnoidYaj?d8shgmGQ&$#>g>k7( zn&9-rL!1Kd)NsmRC8?hkS$dCi&9={Wgg+nt)yL+)QgtD#XWvNhPQ4>+9(?7tch}Ea z&rsKUB;A#J@~;!Bi*|R8`oWF$y$^beH$p zFx_%O=(-^fe)C@s={p5LYoyi*;a!1Xc>_C82Lv^e!8wW1iKVoq`Yq?jiZ*Q>?`piEQR2lPMMZo>k3pm9zgNkQaE zt)2HkViwz(vTN1crLc^^b5o(g$*J0>WX#T?Wc=y7QZmLW&YD^Zjm8yv1NBF*`=a7N z$k}(WzUKwSSQ>S^sPeLt7D^InxRUZZbTMnEc360vjW~yL_N4dyNwK>)dg$=}E`t&t zzH^UNP{9vEdQ+3tDhzp$@=srr+fNsF-b*IBFz4Hcqa7Y^b;Q&(a43z<6YX2(p1>{T zzsJhd`pmQsz(%Ju)j8KqbL@0drYB2enb1IsVvtNAz0Dgo&$B>kz&3&`XP-e!724Td ziaBJvYR0JMO+*EiRu|>b&dC(nEc9$0Q#EsT0stCKIH?z^3wa{Xv?nrJP`h%0D^Xv|NzDg8q8O{4ptjHMr)7L?#mljs7 z9~j>}$XuB^+8zGdp0BpnUWXf>S`(fHBB8LFjZ6U3rG%);Ku_Jy)B0JB*Iy$&B*@KW z03YkQ)}a=7@f@S1+X_$zY)u*pwHapeqr#nd4LZci1gk?JYs_Co=w6v2vITZRo-CB+i6;HLHCE`^hkETxUTTJkNe zF^&Hw#kR?Mp}1&YzWZpQ#=VywfI5XZd%UsWE-JDncmVDQ*=*Mtp=7HWr9R@UCtg4I zSp({u5e)UVslU63fn5lW{y!UlCu<#4Uo{A3OP#l{8ot1Wz%$|OG)}Ft6Z*Pp3FsZ5 z3(Ym38vjYd?k687!o9dHs|V)h^O`Xhcb_eK&Uj>>#~XDd66*NQ;ldTHW{&)(EcwdXQtQXn!~mK3l+-=&xPG3lZ&?hRn)`LowhbB<_K$ zNt>;U$!|CYR!8+C^$?BSv%*o3{g53_#Ym}k6d+A z|6m)^N|5$=B)7jBwRDKflR*?{430YtE<=2d9$j~!+es2P*n@kMbptQEQVO|C@E{3` z$fI238EOkDaoj>o-jz1kK-$4Vds;c+w!*-3_=Gh;M1tGM>q*xmol(m`7&t~T(D5!!NzC;akp#Mon1glu+jFlVh?9hZf8$5?ZrX6>K z%lrvjQtVDhr&6+&I>4s@pr?IR#{^Dbc`OWRCw4BGM`n_Pg;XFR&@uf8tu};UE4+t4 z@l(qOE^ag6bY})jD1bGdEy07zufaCaBeE8lb6%?0$nF2%&$(BfbXM<4fA;Lg3o$cGsa`T@rO`lp3XtdAU<5*YZ!&)ynF8Cvr*U#X{Fhh9 z&%<TGw2*~8bxRBgq0JXFNU9gbA?Qn2NN{T^4CGLj) zy7#mQ*wAEKA}LPpfb7Gq(Ohss)8KuTB#lI93X*rbJ?PGph@1=z2o|J>Lk4~$*hQXL z?8NJc#F41vG=&>QR|pm=I7(<@j`3XBzz6$u9KH$}hgSh#y$F`FO-QDlLy{LGRb-#a zKQl!dh)fTWk=2JsfWqFITO#h`+#$lK8o1=m<03V-knMSFbjnpZT{vA%4p@~O?Y_)PUI+hpPmblO`7dP#bT6kpfo# z6OGo|Ke}QWeclvwOBWH|NCwkA_q!*06l)skzX^Oaq@{i48`!!D_oHIMFI^>p;Zgo3 zy}0(}c|sZ?hgX~(iT7#DA~%6LF`PfrL<1DGDisO$MzF~~5$z7{4hpFSgBT5wj@*Dy zk$E6>!`gt1GoeZ%x%C;}LT9P5!1{5&iQ&=mOALU+MKINMpr02W6Y@Zr(eqyw5=PJ{ z31M+&@L6*y6%K@2tzoTQ*ytC~8kN&D5fhk$mbLR7OLMNJL9OOyKrN}ozpO;EV7-jj zt(x0`GsE!{nuVHwIAdpG%f^88`GpX9bD7R#tE>-hKtqcN;?*8{0&09+UWDaRmd~TC zc9W~jLcsEwBk^JbrAXU}IUNKuOU$o%%R@{tp_f0jl^yld+Y1?f9)L%+VbE!VMI|G_ zrJWH0jRyE3i(8MU=q`}?4&ePpy*T(pYH=#sxEb685o_W$WD(`2Ni#42>dI2^;=c6< zo_#ALz(>Y^03%CGNMB0kL3=D

@!PG+=ZiZPKK;HGik!=nY8CAGBGQjex(Xy+UPg zur6=3y+|z<3P#eILPZcqT^FQkxl|hk_)Q=TRbfO}8*zs3PlsZ2vH|D`&|C@bGzJWc zI^2bNZs^;S+8gG3L_rK^h8ZS zDPRj0Y^B|x8iD!tytl(N7s=p+DYzwAW_t7rLaXkoa3H%=)F?x;TTqU93Ku$;!GYy# z#>%L--rN-nvC9$pp)tYEipY5~iB3pR0(w2tk>~<`68Ii{3ZZFm1O=c+7nDtQi#bfA z>~R4S(1RFMniC&{QznV5_G%LHbZpY3T3oLIQNz&UQupl}nR7axHj4&XPDgeQq6MR3 zP5?jcu@Y@ltyHu(5c{pavE}3WiYP2WgL6|s?tqa>Q-I~E%?wu9roxAH5C&N3g=_G} zhMXaQh!9e}a_GnqWd6{a33jNYIKq%X6%;^iYU0_bo!xT=gc`AJB(t`ph)cckPJGhP zKt-FT&=VE{aDuD_UGx!|&=A%eR{MEU=t9UidgTcLRziSv>oi_LKg8ibjbaUgl(nE2 zFb@mFMqOo;d)55=WPHJ%1X0$i)1kld7<{N2H>1L;rBqYR!)t|*uwOGQNm zO`GMUZkC@&c{Jrbg7)>C*O5(@s`~349$C=qKjFdE9F=Z`uFj^XUV>o^Pykqxm50Y` zhX3#rKpZ?k>vho)qF>sTINXfR0zWi@MsJwr{#c81G!+7S6fy7#n&L5%l{aUhf4W4E zLy`fdnhU`%D`K?@9n8-m@D&SvkJhK}XN>fH_E_!N{Y&f)2SL=SkuC9GzeR+@QO zt!a;LY3l$AC1;MKHU?08C^Tb;&|G^&03Hbw1v znl`*|0Yt%jTr$8&{jyqlV!;;akyE`Df_x;nL23lff`wS%Q%Ps_LQz53SH~v4azQ0W zUcU^Oe=?x^2MSEcW!CWMLm|BKGcSboNn8zkG`Kr8Kv~4!MbKIaK=BRG5JifD1J>XI zc;uoyG#@32T?86Ht({E_k*BuD=o2DH${h^aTJErC&^`+cx~Z>gly}#b5_T>UOsElx z1mh6%h&D}c1dsSKLV}^fi_oOFLPKa#0e(qJWEmmYsb*xZ~&RF z%if%C4R@(K0)eZ7M==vHG)930(p49fqCX0uSoCOv5+Pa)J$4?hq5dJ}{3dqEfsM(3 znm9Ckg2~+g(z=tTTTu=<$aDj08znUG5QLecg-5|jDwOCb{e&UIrzMG3GZ`0RepqO0VwHMAmBZrm+~bh1i$KBWFeT_o!1r6mLCB%k?4Tr9Ln79pz`3MIc%&J8=nn<$}C>s<*A_Ne84N0v6oYVMZ zFgA2m#UuSqRi+j-4u)a4Y@rSuV#|Zn+Uw(Inu}40O^3^f&v$S;FRFcHlv>e#WYcc4 z^p3|nw}P`CB{-;klL+Ik=qIG|WAz1pJXY7f-Dq?;k)b(b2Aa0kl2KHmLJ%CM8>SQE zllZrTzzF{e~lY&uQ>wG$muD;0MJD)Ong zH2u%vX_eO0L5GRW()e><8buZuep|qyHa=3`%@@TlEMzGdcPwI!mL}*`Dosg@h)QBb zjEEIPBVndDZGZqfDI6FYlH>>{L`spERWC+Fl%Ym|9Sy~`<$nM%-v&&Z5ow7^$y5>w z+xPU~k8GNFjJDWw%!ckGSPd%!C%#Dmm#!^W%18*wQ?6a(0O;^F`)Tx)IgQ7P2Q7d?N=u? zGU-((_;z-6;Jimpv@=w+Wm$)q_NNR8S1FWo(cNQbbxYD2>9}FSr!7`=qUVf zwZ(9>>zB%iyA&x<{WM9F)>G}*8O@u?G|jq~^dXWQPzpNkK?i}4Hp^G)%GT5Ic&a{R z3p99ndnOvY03UBgu(-*(KgTY?VYYqL+~U-wD9z955c?be5o808DA3QW4`%Ax&r^P- z>^5ZrWUZ84)fp15Y7MHGXaz&`-(aF2?)b)_{AWmP_~uP;{2vpX8+nhr*eMM96{g=G zD&qHj%HO|o`GzAUac>IKHAS+U-q2Tr7)oFB_sWuy9SgkyHTBQD3X!X!n2qhrsXyj4 zaX|lhdKW_ z38nTCr5c4|4=XT!&_*=1Fbm$kRbxR4RYy`fB~+5^Sk*r4!HSX#N(rIS6L1~AldOnf zCVELNWRw%op^=I=^%*6?jnXNf=@AABoef@-HL+2P!H|YSV<17HY@bMB*a<3ZK=y5O zh=|M7AX4@_kVmfMc-=wx;=cH0I*9;F@T6FrtPuoKz%(7zxv>iEgBc}#Pe^3$1^`1E zeL6Z27Do%gSKJ@niH$dmijP5OfOsDkfxBf5y|D*Y5~O6&RCuGaiI-{wYvlkh6hp>yN7_3_tJ;uQ|2hTz zZG)jB$Y^pm244@sla2$R^u;phC$CLhfWEL z3q~J3djNlcU{>gJaEqGAeQCd*G zg0hbqU0gCptDI3TagKC<`XS%nJPo-Z`Ad0gzWH`h*CO+87gc+`8=eRc z_dQq;XVTWnt3sbU@XfN(A3CdFOYtKIjsNI7v{KOl$(z91s47SO7Hn3=>C!UyvwgfU zP33JL_fvo~B^tuXDtDR#b&H2M^lDJ~$}{h*u~BsjC7yYvj5?k8daTW=^l(i&dMmod zAx6!&b=*RyEWY7zF5vm$WRKI` z>zxvK8<7?iggf5`K0K=}3mvjZwW9nnq~yDgNI95nI%W@>S4!AXb02ymXQryU?lhE)qhJg8s|kpPlLnIVkUI9#rO7o;_?#0!WtomT#|Gbd4R;NJpko5` z>Y)1*$X54(+=5OyL^>?#l!JyT1XJ^{&%ug{h%g~Z+bu~UXu!Gf)FQy){yJLl_LP$R ze;C^7Fp8xITZlm3nstN*fTn%$If3rE?+gNM>vc}bX)BI)>}2A527!kX^}I6(SI3w8 zJA=^E*2Jv|_Aj6K_=>Y?-Yfb{IupzL>uZqOX2 zP4{<8E8*0GF7P7_;}qvz(bZaUnT zgge@9K<7l%dT3<(u|CFwPVZSGEKq77v@j`lHHy$4A+}FDydF5y0l{S3FLH$MeTR?6 zR7)eW06oY{bC;_FYI`~z&x7ono*x-~<=wD)OS1t=dr|o`yGHlG6eVwxpns!$-TO;| zh0r9_1R@KkQ2uaq^gBL>HRU#1IE)mu z_3_Kn;=<0TM@TfW)WQ0olOQ9#>1A3vRX<*2CQrLRJE_{SMijj>f~0%sm;|c{TqwYP zpXx?>Dg(qE?THL-4yZ#fkdVD|(MGM;6q|xgnHHoOi1N^mx)h>5;h^(HNt*+jnQ3?p z4O69#)fFA{MZ#zB3hb7<5wynw;VIsgVACGC*w0GVclTk)i*=b#%8 zYFaZHk9&b$-ChLkjRTjC0TIG?7#YX9g=!Q{(C#a;KO`~P_e?a>9Vo8*dnOvDO`gz0 z>YwA^(4;84{kJ~!F~*Bq(oTDJgIY((AeWYMjr+*_FhV>)EJlj9;YlPOFFKwAs-KOZ zNv<_4S#S8F-7Ksnpm_cKo;!fQ@$2iI8%I%?FivH!_v=u!(7b>F^K&RV?v4m+@Y+kD zi~!1igiro_*N&{zEBVtO#2xw5r-s1MSvsjnq0&VO4Ua5r*O3#5O$UFq4e&m{(WyJr z_Wet6U=c;1LV^KkZJ-;xF>Uv}($qeP0_XlUqQ9P9pm2F~BAkWnc*LPKaqWH*wV%7XxK5d_<3$P3OOchZ6xDLM9ipUy}D=+>t* zC`K5JZirQ9NN^Y%XXTaYJ&%T|ce<)fBf=%(-$y!h3v~z-^0Lpc+GT@(=f^&4%I_Q|Q-mr8y^gZOz;e-R!ym5k;K0iS7z5Vk+7+qQ) zg{h{G$6&&P<{D88lR`0lAjW@G{pWrDD*sYi_2hmVEsEvO%&g zpue#gXNUg%u*(Z4)Q$#%5Oj7kcBj#&jy+6`s?hU_jmCQ~Hu@~mU$Lq8Ni;c{oHWPK z4kaK>VAs&@dVixJicm+@H9Mny@hYu?-=k~e2g8kal)vAgmyXu0`A*4PZ4C?{?BM&+ z9kdNL9ZJ{}=F_RWlYjYWR)%iF*G@e*)!$iJoe;~wJzn4z#|nDj-d*DmNOTPdd+6js zy$G(v^Jjgg&ECfo@6$T;uSBrvBSGQ==p?${XrO=lw9LPJ1w=ldQ^4mqdJ!~h-;d?J z7v-qqP9DFio%%qIa3k8GL6T5{kpT1DNdWLZ9^nB4xc^?PfVQ`zP5};$!u9i{GDq#` zBVS3U_p{!JdDUn3FojESpicy@&u4lhM$7-@6Nm3Bg+L|phW`T;u{1416$KCg004MU zOjJc}ngIX*|NH#-{{Q{>`t$qz`K`uq@%84X!e#UK>$S{&_4w|Zxlj4~_3!lKtj2ER z?9bfi!RheXvB`IbtS*kRI=9V%l(j^jyjG&VUCZ00y3dD>usM066~WY#fv6+i=*H0B zuGZqW#@L+B-mAaUkml~x+~>lGoptyC000SaNLh0L04^f{04^f|c%?sf00007bV*G` z2jU194mbnu?(~HK00GBIL_t(Y$DNjqZiFBVfLj^rWzj62i3yo<>f*is8x9n)0_P81 z;xXyhmV%{#zA&!-l<1$pG`KI6@(ySG7-1}6)-ke2>>ST3B^h_$yNH=!(^!L%x|^5> z0r9V&iLm;H63GJj$Q%S0EqKxjZWSmpznB^bN;6SEK!^c8%0T?U7U&2EGH!mr=Hrl{ z46LI8PGq2n9!zE;??g@&b1|;}Pev7%u=tXz_D8+yDbj0mOXeHC=)yvZML}Q)p|ciA z%nnwFPr2L8R;Gxh85ag2PJrRJzwQTOOWn)}Gv`WLgH%dHY37+l)^wdAI%x{gadlUb zPDcj%;M5yZ`AD@>K(4)TyKlimpz@rq$Y=!+-Y^(@e2_$f;A6+rWn$RW3+TnywY4ed!y$(wF+BFQ&j=DEwv@*`3Rx zb1sXRE6EtRb@9bqud9(l$UPuM;avQoR-v<$JZ=@}L{jR8q%6)Fl22_9J8FAknyX7K Z+&^0SA;O5ld3*o>002ovPDHLkV1mF}=nwz^ literal 0 HcmV?d00001 diff --git a/pkdb_app/templates/pkdb/about.html b/pkdb_app/templates/pkdb/about.html new file mode 100644 index 00000000..097be6ab --- /dev/null +++ b/pkdb_app/templates/pkdb/about.html @@ -0,0 +1,10 @@ +{% extends "pkdb/base.html" %} +{% load static %} +{% block content %} +

About PK-DB

+

+ Pharmacokinetics database
+ Version: {{ version }}
+ REST API +

+{% endblock %} \ No newline at end of file diff --git a/pkdb_app/templates/pkdb/base.html b/pkdb_app/templates/pkdb/base.html new file mode 100644 index 00000000..7df27a67 --- /dev/null +++ b/pkdb_app/templates/pkdb/base.html @@ -0,0 +1,45 @@ +{% load static %} + + + + + + + + + PK-DB + + + + + {% block head %}{% endblock %} + + + + +
+
+ +
+ + {% block content %}{% endblock %} + +
+ + +
+
+
+

© 2017-2018 PK-DB

+
+ +
+ +
+ +
+ + +{% block javascript %}{% endblock %} + + diff --git a/pkdb_app/urls.py b/pkdb_app/urls.py index a80e636f..ab3075cf 100755 --- a/pkdb_app/urls.py +++ b/pkdb_app/urls.py @@ -17,6 +17,8 @@ from .studies.views import AuthorsViewSet, ReferencesViewSet, StudyViewSet #from .subjects.views import GroupsViewSet,CharacteristicValuesViewSet +from . import views + # views in User router = DefaultRouter() router.register(r'users', UserViewSet) @@ -40,14 +42,17 @@ urlpatterns = [ path('admin/', admin.site.urls), - url(r'^$', schema_view), - path('api/v1/', include(router.urls)), + url(r'^$', views.about_view, name='index'), + url(r'api', schema_view, name='api'), + path(r'^api/v1/', include(router.urls)), # path('api-token-auth/', views.obtain_auth_token), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), # the 'api-root' from django rest-frameworks default router # http://www.django-rest-framework.org/api-guide/routers/#defaultrouter #re_path(r'^$', RedirectView.as_view(url=reverse_lazy('api-root'), permanent=False)), + + ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) if settings.DEBUG: diff --git a/pkdb_app/views.py b/pkdb_app/views.py index 3061544f..0ae56546 100644 --- a/pkdb_app/views.py +++ b/pkdb_app/views.py @@ -1,10 +1,11 @@ """ Views """ +from pkdb_app._version import __version__ from django.shortcuts import render from rest_framework_swagger.renderers import SwaggerUIRenderer,OpenAPIRenderer -from rest_framework.decorators import api_view,renderer_classes,authentication_classes,permission_classes +from rest_framework.decorators import api_view, renderer_classes,authentication_classes, permission_classes from rest_framework.renderers import CoreJSONRenderer from rest_framework.schemas import SchemaGenerator from rest_framework.authentication import SessionAuthentication, TokenAuthentication, BasicAuthentication @@ -20,3 +21,10 @@ def schema_view(request): generator = SchemaGenerator( title='PKDB Web API') return Response(generator.get_schema(request=request)) + + +def about_view(request): + return render(request, "pkdb/about.html", + { + "version": __version__, + }) From 8625601e76c555e0b524f33c25df7f12f595ab16 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 23 Aug 2018 17:03:09 +0200 Subject: [PATCH 111/115] gunicorn start script updated --- gunicorn_start.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gunicorn_start.sh b/gunicorn_start.sh index 87b482b9..dbdca61f 100755 --- a/gunicorn_start.sh +++ b/gunicorn_start.sh @@ -1,13 +1,13 @@ #!/bin/bash -NAME="pkpd" # Name of the application (*) -DJANGODIR=/var/git/pkpd # Django project directory (*) -SOCKFILE=/var/git/pkpd/run/gunicorn.sock # we will communicate using this unix socket (*) +NAME="pkdb" # Name of the application (*) +DJANGODIR=/var/git/pkdb # Django project directory (*) +SOCKFILE=/var/git/pkdb/run/gunicorn.sock # we will communicate using this unix socket (*) USER=mkoenig # the user to run as (*) GROUP=mkoenig # the group to run as (*) NUM_WORKERS=1 # how many worker processes should Gunicorn spawn (*) -DJANGO_SETTINGS_MODULE=pkpd_app.config.local # which settings file should Django use (*) -DJANGO_WSGI_MODULE=pkpd_app.wsgi # WSGI module name (*) +DJANGO_SETTINGS_MODULE=pkdb_app.config.local # which settings file should Django use (*) +DJANGO_WSGI_MODULE=pkdb_app.wsgi # WSGI module name (*) echo "Starting $NAME as `whoami`" From bba9ffe5cf3f35e10a4fa1829f34a54912f711a0 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 23 Aug 2018 17:25:36 +0200 Subject: [PATCH 112/115] latest local changes --- pkdb_app/config/local.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pkdb_app/config/local.py b/pkdb_app/config/local.py index 601dd1b4..0ed77932 100755 --- a/pkdb_app/config/local.py +++ b/pkdb_app/config/local.py @@ -46,7 +46,6 @@ class Local(Common): } ''' - # Mail EMAIL_HOST = 'localhost' EMAIL_PORT = 1025 From 3cc69e62d641534a5bc6acdb8c3116d59457a636 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 23 Aug 2018 17:27:13 +0200 Subject: [PATCH 113/115] updated manage.py for production --- manage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/manage.py b/manage.py index b64594a9..2bc37704 100755 --- a/manage.py +++ b/manage.py @@ -5,6 +5,7 @@ if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pkdb_app.config") PKDB_DJANGO_CONFIGURATION = os.getenv("PKDB_DJANGO_CONFIGURATION", "Local") + print("DJANGO_CONFIGURATION:", PKDB_DJANGO_CONFIGURATION) os.environ.setdefault("DJANGO_CONFIGURATION", PKDB_DJANGO_CONFIGURATION) try: From 0fc65bd8337aa2c8702d2b4a7fa0cee133ecbf24 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 23 Aug 2018 17:52:51 +0200 Subject: [PATCH 114/115] fixing start scripts --- gunicorn_start.sh | 2 +- pkdb_app/config/local.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gunicorn_start.sh b/gunicorn_start.sh index dbdca61f..da72ec3b 100755 --- a/gunicorn_start.sh +++ b/gunicorn_start.sh @@ -23,7 +23,7 @@ test -d $RUNDIR || mkdir -p $RUNDIR # Start your Django Unicorn # Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon) -exec /home/mkoenig/envs/flutype_webapp/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \ +exec /home/mkoenig/envs/pkdb/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \ --name $NAME \ --workers $NUM_WORKERS \ --user $USER \ diff --git a/pkdb_app/config/local.py b/pkdb_app/config/local.py index 0ed77932..f565747a 100755 --- a/pkdb_app/config/local.py +++ b/pkdb_app/config/local.py @@ -25,13 +25,12 @@ class Local(Common): ] # Postgres - DATABASES = { 'default': dj_database_url.config( # postgres://USER:PASSWORD@HOST:PORT/NAME default=f'postgres://postgres:pass@postgres:5432/postgres', conn_max_age=int(os.getenv('POSTGRES_CONN_MAX_AGE', 600)) - ) + ), } ''' DATABASES = { From 38c74edcd444c0419c85379a4bf47badb0dc7130 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 23 Aug 2018 18:21:39 +0200 Subject: [PATCH 115/115] gunicorn_start.sh fixed --- gunicorn_start.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gunicorn_start.sh b/gunicorn_start.sh index da72ec3b..279cc9e0 100755 --- a/gunicorn_start.sh +++ b/gunicorn_start.sh @@ -1,19 +1,18 @@ #!/bin/bash - NAME="pkdb" # Name of the application (*) DJANGODIR=/var/git/pkdb # Django project directory (*) SOCKFILE=/var/git/pkdb/run/gunicorn.sock # we will communicate using this unix socket (*) USER=mkoenig # the user to run as (*) GROUP=mkoenig # the group to run as (*) NUM_WORKERS=1 # how many worker processes should Gunicorn spawn (*) -DJANGO_SETTINGS_MODULE=pkdb_app.config.local # which settings file should Django use (*) +DJANGO_SETTINGS_MODULE=pkdb_app.config.production # which settings file should Django use (*) DJANGO_WSGI_MODULE=pkdb_app.wsgi # WSGI module name (*) echo "Starting $NAME as `whoami`" # Activate the virtual environment cd $DJANGODIR -source /var/www/test/venv/bin/activate +source /home/mkoenig/envs/pkdb/bin/activate export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE export PYTHONPATH=$DJANGODIR:$PYTHONPATH